refactor: hard-fork GSD -> MSD (Make Software Done)
Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD across contents and paths, upstream package/repo coordinates -> @golem15/msd-core and golem15com/msd-core. Deep links into upstream history, sibling upstream packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is. Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line, package/plugin identity, regenerated lockfile, install-tree fixtures, derived registries and benchmark baseline; migration checksum baseline re-locked (MSD keeps its own install state, so no install had applied the old sums); sort-order and regex-escaped expectations in tests adjusted.
This commit is contained in:
@@ -9,13 +9,13 @@ const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const fc = require('fast-check');
|
||||
const { runNode } = require('./helpers/process-seam.cjs');
|
||||
const { createTempDir, cleanup, runGsdTools } = require('./helpers.cjs');
|
||||
const { createTempDir, cleanup, runMsdTools } = require('./helpers.cjs');
|
||||
const { installerEnv, RUNTIME_META } = require('./helpers/install-shared.cjs');
|
||||
const { INSTALL_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
|
||||
|
||||
const REPO_ROOT = path.join(__dirname, '..');
|
||||
const { appendAgentTools, buildKimiAgentArtifacts, convertClaudeAgentToQwenAgent, convertClaudeAgentToZcodeAgent, _decodeToolScalar } = require('../gsd-core/bin/lib/runtime-artifact-conversion.cjs');
|
||||
const { parseFrontmatter } = require('../gsd-core/bin/lib/frontmatter.cjs');
|
||||
const { appendAgentTools, buildKimiAgentArtifacts, convertClaudeAgentToQwenAgent, convertClaudeAgentToZcodeAgent, _decodeToolScalar } = require('../msd-core/bin/lib/runtime-artifact-conversion.cjs');
|
||||
const { parseFrontmatter } = require('../msd-core/bin/lib/frontmatter.cjs');
|
||||
|
||||
function parseTools(content) {
|
||||
const tools = parseFrontmatter(content).tools;
|
||||
@@ -27,11 +27,11 @@ function parseTools(content) {
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function installClaude(t, { defaults, projectConfig, root = createTempDir('gsd-4032-claude-') } = {}) {
|
||||
function installClaude(t, { defaults, projectConfig, root = createTempDir('msd-4032-claude-') } = {}) {
|
||||
t.after(() => cleanup(root));
|
||||
if (defaults !== undefined) {
|
||||
fs.mkdirSync(path.join(root, '.gsd'), { recursive: true });
|
||||
fs.writeFileSync(path.join(root, '.gsd', 'defaults.json'), JSON.stringify(defaults), 'utf8');
|
||||
fs.mkdirSync(path.join(root, '.msd'), { recursive: true });
|
||||
fs.writeFileSync(path.join(root, '.msd', 'defaults.json'), JSON.stringify(defaults), 'utf8');
|
||||
}
|
||||
if (projectConfig !== undefined) {
|
||||
fs.mkdirSync(path.join(root, '.planning'), { recursive: true });
|
||||
@@ -53,15 +53,15 @@ function installClaude(t, { defaults, projectConfig, root = createTempDir('gsd-4
|
||||
}
|
||||
|
||||
function installRuntime(t, runtime, { defaults, projectConfig, repeat = false, scope = 'local' } = {}) {
|
||||
const root = createTempDir(`gsd-4032-${runtime}-project-`);
|
||||
const home = createTempDir(`gsd-4032-${runtime}-home-`);
|
||||
const root = createTempDir(`msd-4032-${runtime}-project-`);
|
||||
const home = createTempDir(`msd-4032-${runtime}-home-`);
|
||||
t.after(() => {
|
||||
cleanup(root);
|
||||
cleanup(home);
|
||||
});
|
||||
if (defaults !== undefined) {
|
||||
fs.mkdirSync(path.join(home, '.gsd'), { recursive: true });
|
||||
fs.writeFileSync(path.join(home, '.gsd', 'defaults.json'), JSON.stringify(defaults), 'utf8');
|
||||
fs.mkdirSync(path.join(home, '.msd'), { recursive: true });
|
||||
fs.writeFileSync(path.join(home, '.msd', 'defaults.json'), JSON.stringify(defaults), 'utf8');
|
||||
}
|
||||
if (projectConfig !== undefined) {
|
||||
fs.mkdirSync(path.join(root, '.planning'), { recursive: true });
|
||||
@@ -109,14 +109,14 @@ test('Claude installer appends wildcard then named grants exactly once (#4032)',
|
||||
defaults: {
|
||||
agent_tools: {
|
||||
'*': ['mcp__global__one', 'mcp__shared__tool'],
|
||||
'gsd-executor': ['mcp__agent__two', 'mcp__shared__tool'],
|
||||
'msd-executor': ['mcp__agent__two', 'mcp__shared__tool'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const tools = parseTools(installed.agent('gsd-executor'));
|
||||
const tools = parseTools(installed.agent('msd-executor'));
|
||||
assert.match(
|
||||
installed.agent('gsd-executor'),
|
||||
installed.agent('msd-executor'),
|
||||
/^tools:.*mcp__global__one, mcp__shared__tool, mcp__agent__two$/m,
|
||||
'Claude inline tools must remain plain comma-separated tool names',
|
||||
);
|
||||
@@ -129,11 +129,11 @@ test('Claude installer appends wildcard then named grants exactly once (#4032)',
|
||||
|
||||
test('project selectors override only their matching global selector (#4032)', (t) => {
|
||||
const installed = installClaude(t, {
|
||||
defaults: { agent_tools: { '*': ['mcp__global__wildcard'], 'gsd-executor': ['mcp__global__executor'] } },
|
||||
projectConfig: { agent_tools: { 'gsd-executor': ['mcp__project__executor'] } },
|
||||
defaults: { agent_tools: { '*': ['mcp__global__wildcard'], 'msd-executor': ['mcp__global__executor'] } },
|
||||
projectConfig: { agent_tools: { 'msd-executor': ['mcp__project__executor'] } },
|
||||
});
|
||||
|
||||
const tools = parseTools(installed.agent('gsd-executor'));
|
||||
const tools = parseTools(installed.agent('msd-executor'));
|
||||
assert.ok(tools.includes('mcp__global__wildcard'));
|
||||
assert.ok(tools.includes('mcp__project__executor'));
|
||||
assert.ok(!tools.includes('mcp__global__executor'));
|
||||
@@ -141,11 +141,11 @@ test('project selectors override only their matching global selector (#4032)', (
|
||||
|
||||
test('an invalid project selector fails closed instead of restoring a global grant (#4032)', (t) => {
|
||||
const installed = installClaude(t, {
|
||||
defaults: { agent_tools: { 'gsd-executor': ['mcp__global__executor'] } },
|
||||
projectConfig: { agent_tools: { 'gsd-executor': 'not-an-array' } },
|
||||
defaults: { agent_tools: { 'msd-executor': ['mcp__global__executor'] } },
|
||||
projectConfig: { agent_tools: { 'msd-executor': 'not-an-array' } },
|
||||
});
|
||||
|
||||
assert.ok(!parseTools(installed.agent('gsd-executor')).includes('mcp__global__executor'));
|
||||
assert.ok(!parseTools(installed.agent('msd-executor')).includes('mcp__global__executor'));
|
||||
});
|
||||
|
||||
test('an invalid project agent_tools container suppresses global grants (#4032)', (t) => {
|
||||
@@ -154,18 +154,18 @@ test('an invalid project agent_tools container suppresses global grants (#4032)'
|
||||
projectConfig: { agent_tools: ['not-an-object'] },
|
||||
});
|
||||
|
||||
assert.ok(!parseTools(installed.agent('gsd-executor')).includes('mcp__global__wildcard'));
|
||||
assert.ok(!parseTools(installed.agent('msd-executor')).includes('mcp__global__wildcard'));
|
||||
});
|
||||
|
||||
test('config-set accepts named and wildcard agent_tools selectors (#4032)', (t) => {
|
||||
const root = createTempDir('gsd-4032-config-');
|
||||
const root = createTempDir('msd-4032-config-');
|
||||
t.after(() => cleanup(root));
|
||||
fs.mkdirSync(path.join(root, '.planning'), { recursive: true });
|
||||
fs.writeFileSync(path.join(root, '.planning', 'config.json'), '{}\n', 'utf8');
|
||||
const env = { HOME: root, USERPROFILE: root };
|
||||
|
||||
for (const selector of ['gsd-executor', '*']) {
|
||||
const result = runGsdTools(
|
||||
for (const selector of ['msd-executor', '*']) {
|
||||
const result = runMsdTools(
|
||||
['config-set', `agent_tools.${selector}`, '["mcp__configured__grant"]'],
|
||||
root,
|
||||
env,
|
||||
@@ -175,7 +175,7 @@ test('config-set accepts named and wildcard agent_tools selectors (#4032)', (t)
|
||||
|
||||
const config = JSON.parse(fs.readFileSync(path.join(root, '.planning', 'config.json'), 'utf8'));
|
||||
assert.deepStrictEqual(config.agent_tools, {
|
||||
'gsd-executor': ['mcp__configured__grant'],
|
||||
'msd-executor': ['mcp__configured__grant'],
|
||||
'*': ['mcp__configured__grant'],
|
||||
});
|
||||
});
|
||||
@@ -185,31 +185,31 @@ test('inline and block tools forms keep their form after installer augmentation
|
||||
defaults: { agent_tools: { '*': ['mcp__form__grant'] } },
|
||||
});
|
||||
|
||||
const inline = installed.agent('gsd-executor');
|
||||
const block = installed.agent('gsd-nyquist-auditor');
|
||||
const inline = installed.agent('msd-executor');
|
||||
const block = installed.agent('msd-nyquist-auditor');
|
||||
assert.match(inline, /^tools:[^\n]+mcp__form__grant/m);
|
||||
assert.match(block, /^tools:\r?\n(?:[ \t]+- [^\n]+\r?\n)*[ \t]+- "mcp__form__grant"$/m);
|
||||
});
|
||||
|
||||
test('missing or invalid agent_tools leave installed agent bytes unchanged (#4032)', (t) => {
|
||||
const baselineInstall = installClaude(t);
|
||||
const baseline = baselineInstall.agent('gsd-executor');
|
||||
const baseline = baselineInstall.agent('msd-executor');
|
||||
const invalidInstall = installClaude(t, {
|
||||
root: baselineInstall.root,
|
||||
defaults: { agent_tools: { '*': [null, '', ' '] } },
|
||||
});
|
||||
const invalid = invalidInstall.agent('gsd-executor');
|
||||
const invalid = invalidInstall.agent('msd-executor');
|
||||
assert.strictEqual(invalid, baseline);
|
||||
});
|
||||
|
||||
test('host converters receive canonical grants without changing their omissions (#4032)', (t) => {
|
||||
const defaults = { agent_tools: { 'gsd-executor': ['mcp__configured__grant', 'mcp__first__*'] } };
|
||||
const defaults = { agent_tools: { 'msd-executor': ['mcp__configured__grant', 'mcp__first__*'] } };
|
||||
for (const runtime of ['claude', 'codex']) {
|
||||
const artifacts = emittedAgentArtifacts(installRuntime(t, runtime, { defaults }), 'gsd-executor');
|
||||
const artifacts = emittedAgentArtifacts(installRuntime(t, runtime, { defaults }), 'msd-executor');
|
||||
assert.ok(artifacts.some((artifact) => artifact.includes('mcp__configured__grant')),
|
||||
`${runtime} must expose the configured canonical grant in its existing host form`);
|
||||
}
|
||||
const kiloArtifacts = emittedAgentArtifacts(installRuntime(t, 'kilo', { defaults }), 'gsd-executor');
|
||||
const kiloArtifacts = emittedAgentArtifacts(installRuntime(t, 'kilo', { defaults }), 'msd-executor');
|
||||
assert.ok(kiloArtifacts.some((artifact) => {
|
||||
const configured = artifact.indexOf(' configured_grant: allow');
|
||||
const wildcard = artifact.indexOf(' first_*: allow');
|
||||
@@ -217,7 +217,7 @@ test('host converters receive canonical grants without changing their omissions
|
||||
}),
|
||||
'Kilo must translate safe canonical MCP grants into native permission keys in first-seen order');
|
||||
for (const runtime of ['zcode', 'opencode']) {
|
||||
const artifacts = emittedAgentArtifacts(installRuntime(t, runtime, { defaults }), 'gsd-executor');
|
||||
const artifacts = emittedAgentArtifacts(installRuntime(t, runtime, { defaults }), 'msd-executor');
|
||||
assert.ok(artifacts.every((artifact) => !artifact.includes('mcp__configured__grant')),
|
||||
`${runtime} must preserve its existing tool omission policy`);
|
||||
}
|
||||
@@ -225,52 +225,52 @@ test('host converters receive canonical grants without changing their omissions
|
||||
|
||||
test('Kimi receives canonical grants before its existing mapper runs (#4032)', (t) => {
|
||||
const install = installRuntime(t, 'kimi', {
|
||||
defaults: { agent_tools: { 'gsd-executor': ['WebFetch'] } },
|
||||
defaults: { agent_tools: { 'msd-executor': ['WebFetch'] } },
|
||||
scope: 'global',
|
||||
});
|
||||
const artifacts = emittedAgentArtifacts(install, 'gsd-executor');
|
||||
const artifacts = emittedAgentArtifacts(install, 'msd-executor');
|
||||
assert.ok(artifacts.some((artifact) => artifact.includes('kimi_cli.tools.web:FetchURL')),
|
||||
'Kimi must map a configured canonical WebFetch tool through its existing converter');
|
||||
});
|
||||
|
||||
test('Kimi project selectors override matching global selectors (#4032)', (t) => {
|
||||
const install = installRuntime(t, 'kimi', {
|
||||
defaults: { agent_tools: { 'gsd-executor': ['WebFetch'] } },
|
||||
projectConfig: { agent_tools: { 'gsd-executor': ['WebSearch'] } },
|
||||
defaults: { agent_tools: { 'msd-executor': ['WebFetch'] } },
|
||||
projectConfig: { agent_tools: { 'msd-executor': ['WebSearch'] } },
|
||||
scope: 'global',
|
||||
});
|
||||
const artifacts = emittedAgentArtifacts(install, 'gsd-executor');
|
||||
const artifacts = emittedAgentArtifacts(install, 'msd-executor');
|
||||
assert.ok(artifacts.some((artifact) => artifact.includes('kimi_cli.tools.web:SearchWeb')),
|
||||
'Kimi must map the project grant through its existing converter');
|
||||
assert.ok(artifacts.every((artifact) => !artifact.includes('kimi_cli.tools.web:FetchURL')),
|
||||
'the matching global selector must not survive the project override');
|
||||
});
|
||||
|
||||
test('Kimi neutralizes ~/.claude/gsd-core references instead of leaking a repointed path (#4032)', (t) => {
|
||||
test('Kimi neutralizes ~/.claude/msd-core references instead of leaking a repointed path (#4032)', (t) => {
|
||||
// Routing Kimi through the ADR-1235 pre-converter pipeline (needed so
|
||||
// project-scoped agent_tools selectors reach it, see the test above) also
|
||||
// runs _applyAgentPathRewrites. Kimi's own neutralizeKimiAgentPrompt expects
|
||||
// to see the ORIGINAL `~/.claude/gsd-core` text; kimi/kimi-code capability.json
|
||||
// to see the ORIGINAL `~/.claude/msd-core` text; kimi/kimi-code capability.json
|
||||
// now opt out via hostBehaviors.noPathRewrite so that still holds.
|
||||
const install = installRuntime(t, 'kimi', { scope: 'global' });
|
||||
// Inspect generated prompts, not the installation-owned raw source corpus.
|
||||
const artifacts = emittedAgentArtifacts(install, 'gsd-executor', path.join(install.configDir, 'agents'));
|
||||
assert.ok(artifacts.some((artifact) => artifact.includes('GSD core')),
|
||||
'a ~/.claude/gsd-core reference must neutralize to prose, not a repointed Kimi path');
|
||||
const artifacts = emittedAgentArtifacts(install, 'msd-executor', path.join(install.configDir, 'agents'));
|
||||
assert.ok(artifacts.some((artifact) => artifact.includes('MSD core')),
|
||||
'a ~/.claude/msd-core reference must neutralize to prose, not a repointed Kimi path');
|
||||
assert.ok(artifacts.every((artifact) =>
|
||||
!artifact.includes('~/.claude/gsd-core') &&
|
||||
!artifact.includes('$HOME/.claude/gsd-core') &&
|
||||
!artifact.includes('config/agents/gsd-core/references')),
|
||||
'no raw Claude- or Kimi-prefixed gsd-core path may leak into the Kimi prompt body');
|
||||
!artifact.includes('~/.claude/msd-core') &&
|
||||
!artifact.includes('$HOME/.claude/msd-core') &&
|
||||
!artifact.includes('config/agents/msd-core/references')),
|
||||
'no raw Claude- or Kimi-prefixed msd-core path may leak into the Kimi prompt body');
|
||||
});
|
||||
|
||||
test('Kilo global install resolves project agent_tools from the working directory (#4032)', (t) => {
|
||||
const install = installRuntime(t, 'kilo', {
|
||||
defaults: { agent_tools: { 'gsd-executor': ['mcp__global__loser'] } },
|
||||
projectConfig: { agent_tools: { 'gsd-executor': ['mcp__project__winner'] } },
|
||||
defaults: { agent_tools: { 'msd-executor': ['mcp__global__loser'] } },
|
||||
projectConfig: { agent_tools: { 'msd-executor': ['mcp__project__winner'] } },
|
||||
scope: 'global',
|
||||
});
|
||||
const artifacts = emittedAgentArtifacts(install, 'gsd-executor');
|
||||
const artifacts = emittedAgentArtifacts(install, 'msd-executor');
|
||||
assert.ok(artifacts.some((artifact) => artifact.includes(' project_winner: allow')),
|
||||
'the combined-family path must discover project config from cwd during a global install');
|
||||
assert.ok(artifacts.every((artifact) => !artifact.includes('global_loser')),
|
||||
@@ -281,9 +281,9 @@ test('Kilo permission-key collision resolves deterministically to first-seen (#4
|
||||
// mcp__a_b__c and mcp__a__b_c both derive Kilo's native "a_b_c" key — the
|
||||
// `{server}_{tool}` format is Kilo's own fixed contract, not ours to widen.
|
||||
const install = installRuntime(t, 'kilo', {
|
||||
defaults: { agent_tools: { 'gsd-executor': ['mcp__a_b__c', 'mcp__a__b_c'] } },
|
||||
defaults: { agent_tools: { 'msd-executor': ['mcp__a_b__c', 'mcp__a__b_c'] } },
|
||||
});
|
||||
const artifacts = emittedAgentArtifacts(install, 'gsd-executor');
|
||||
const artifacts = emittedAgentArtifacts(install, 'msd-executor');
|
||||
assert.ok(artifacts.some((artifact) => (artifact.match(/^ {2}a_b_c: allow$/gm) || []).length === 1),
|
||||
'a colliding pair must still emit exactly one permission line');
|
||||
});
|
||||
@@ -309,11 +309,11 @@ test('every installable runtime accepts a configured MCP grant without crashing
|
||||
for (const runtime of Object.keys(RUNTIME_META)) {
|
||||
if (NO_SUBAGENT_TOOLKIT.has(runtime)) continue;
|
||||
const install = installRuntime(t, runtime, {
|
||||
defaults: { agent_tools: { 'gsd-executor': ['mcp__smoke__probe'] } },
|
||||
defaults: { agent_tools: { 'msd-executor': ['mcp__smoke__probe'] } },
|
||||
scope: 'global',
|
||||
});
|
||||
const artifacts = emittedAgentArtifacts(install, 'gsd-executor', install.home);
|
||||
assert.ok(artifacts.every((artifact) => artifact.length > 0), `${runtime} must emit non-empty gsd-executor artifact(s)`);
|
||||
const artifacts = emittedAgentArtifacts(install, 'msd-executor', install.home);
|
||||
assert.ok(artifacts.every((artifact) => artifact.length > 0), `${runtime} must emit non-empty msd-executor artifact(s)`);
|
||||
if (!GRANT_SURVIVES_RECOGNIZABLY.has(runtime)) continue;
|
||||
assert.ok(artifacts.some((artifact) => artifact.includes('mcp__smoke__probe') || artifact.includes('smoke_probe')),
|
||||
`${runtime} must carry the configured grant (raw or Kilo-style transformed) — this must fail if agent_tools is reverted`);
|
||||
@@ -322,9 +322,9 @@ test('every installable runtime accepts a configured MCP grant without crashing
|
||||
|
||||
test('Codex grants do not widen the generated TOML sandbox (#4032)', (t) => {
|
||||
const install = installRuntime(t, 'codex', {
|
||||
defaults: { agent_tools: { 'gsd-plan-checker': ['Write'] } },
|
||||
defaults: { agent_tools: { 'msd-plan-checker': ['Write'] } },
|
||||
});
|
||||
const toml = fs.readFileSync(path.join(install.configDir, 'agents', 'gsd-plan-checker.toml'), 'utf8');
|
||||
const toml = fs.readFileSync(path.join(install.configDir, 'agents', 'msd-plan-checker.toml'), 'utf8');
|
||||
assert.match(toml, /^sandbox_mode = "read-only"$/m);
|
||||
assert.doesNotMatch(toml, /Write/,
|
||||
'Codex tool availability is inherited from the parent session, not encoded in agent TOML');
|
||||
@@ -337,7 +337,7 @@ test('hostile values fail closed while inline Claude tools remain valid tokens (
|
||||
];
|
||||
const accepted = ['mcp__safe__:terminal', 'Agent(worker)', '\\backslash'];
|
||||
const installed = installClaude(t, { defaults: { agent_tools: { '*': [...rejected, ...accepted] } } });
|
||||
const content = installed.agent('gsd-executor');
|
||||
const content = installed.agent('msd-executor');
|
||||
const frontmatter = content.slice(4, content.indexOf('\n---', 4));
|
||||
const parsed = require('js-yaml').load(frontmatter);
|
||||
assert.strictEqual(typeof parsed.tools, 'string', 'the emitted inline tools scalar must remain valid YAML');
|
||||
@@ -352,7 +352,7 @@ test('reinstall remains idempotent and preserves Claude read-only restrictions (
|
||||
defaults: { agent_tools: { '*': ['mcp__idempotent__grant'] } },
|
||||
repeat: true,
|
||||
});
|
||||
const artifacts = emittedAgentArtifacts(install, 'gsd-plan-checker');
|
||||
const artifacts = emittedAgentArtifacts(install, 'msd-plan-checker');
|
||||
assert.ok(artifacts.every((artifact) => parseTools(artifact).filter((tool) => tool === 'mcp__idempotent__grant').length === 1));
|
||||
assert.ok(artifacts.some((artifact) => artifact.includes('disallowedTools:')),
|
||||
'the existing Claude read-only deny-list must survive augmentation');
|
||||
@@ -368,14 +368,14 @@ test('quoted scalar identity is shared by append, Kimi, and Qwen (#4191)', () =>
|
||||
assert.strictEqual(_decodeToolScalar(raw), expected);
|
||||
}
|
||||
|
||||
const inline = '---\nname: gsd-test\ndescription: test\ntools: "WebFetch", \'WebSearch\', "unterminated\n---\n';
|
||||
const block = '---\nname: gsd-test\ndescription: test\ntools:\n - "WebFetch"\n - \'WebSearch\'\n - "unterminated\n---\n';
|
||||
const inline = '---\nname: msd-test\ndescription: test\ntools: "WebFetch", \'WebSearch\', "unterminated\n---\n';
|
||||
const block = '---\nname: msd-test\ndescription: test\ntools:\n - "WebFetch"\n - \'WebSearch\'\n - "unterminated\n---\n';
|
||||
|
||||
for (const content of [inline, block]) {
|
||||
const once = appendAgentTools(content, ['WebFetch', 'WebSearch']);
|
||||
assert.strictEqual(once, content, 'quoted values must already satisfy append idempotency');
|
||||
|
||||
const kimi = buildKimiAgentArtifacts({ subagents: [{ path: 'agents/gsd-test.md', content }] });
|
||||
const kimi = buildKimiAgentArtifacts({ subagents: [{ path: 'agents/msd-test.md', content }] });
|
||||
assert.ok(kimi.subagents[0].yaml.includes('kimi_cli.tools.web:FetchURL'));
|
||||
assert.ok(kimi.subagents[0].yaml.includes('kimi_cli.tools.web:SearchWeb'));
|
||||
assert.ok(!kimi.subagents[0].yaml.includes('unterminated'));
|
||||
@@ -388,14 +388,14 @@ test('quoted scalar identity is shared by append, Kimi, and Qwen (#4191)', () =>
|
||||
});
|
||||
|
||||
test('appendAgentTools preserves inline YAML comments without swallowing grants (#4032)', () => {
|
||||
const content = '---\nname: gsd-test\ntools: Read # keep this note\n---\n';
|
||||
const content = '---\nname: msd-test\ntools: Read # keep this note\n---\n';
|
||||
const augmented = appendAgentTools(content, ['WebFetch']);
|
||||
assert.match(augmented, /^tools: Read, WebFetch # keep this note$/m);
|
||||
assert.deepStrictEqual(parseTools(augmented), ['Read', 'WebFetch']);
|
||||
});
|
||||
|
||||
test('appendAgentTools leaves agents without a tools key unchanged (#4032)', () => {
|
||||
const content = '---\nname: gsd-test\ndescription: inherits the runtime tool surface\n---\n';
|
||||
const content = '---\nname: msd-test\ndescription: inherits the runtime tool surface\n---\n';
|
||||
assert.strictEqual(appendAgentTools(content, ['WebFetch']), content);
|
||||
});
|
||||
|
||||
@@ -482,7 +482,7 @@ test('parseFrontmatterTools (Qwen conversion) does not silently drop a block lis
|
||||
// truthy content instead of falling through to `collecting = true`) is a
|
||||
// separate parser reached by Kimi and Qwen conversion, downstream of
|
||||
// appendAgentTools's own output.
|
||||
const agent = '---\nname: gsd-executor\ndescription: test\ntools: # note\n - Read\n - Write\n---\nbody\n';
|
||||
const agent = '---\nname: msd-executor\ndescription: test\ntools: # note\n - Read\n - Write\n---\nbody\n';
|
||||
const qwen = convertClaudeAgentToQwenAgent(agent);
|
||||
assert.match(qwen, /- Read/);
|
||||
assert.match(qwen, /- Write/);
|
||||
@@ -490,7 +490,7 @@ test('parseFrontmatterTools (Qwen conversion) does not silently drop a block lis
|
||||
|
||||
test('parseFrontmatterTools (Qwen conversion) does not tear a quoted scalar containing a literal comma (#4032)', () => {
|
||||
const agent = appendAgentTools(
|
||||
'---\nname: gsd-executor\ndescription: test\ntools: Read, "mcp__x, y"\n---\nbody\n',
|
||||
'---\nname: msd-executor\ndescription: test\ntools: Read, "mcp__x, y"\n---\nbody\n',
|
||||
[],
|
||||
);
|
||||
const qwen = convertClaudeAgentToQwenAgent(agent);
|
||||
|
||||
Reference in New Issue
Block a user