refactor: drop 12 runtimes, keep Claude, Codex, OpenCode, Cursor, ZCode, Antigravity
Removes kilo, kimi, kimi-code, copilot, windsurf, augment, trae, qwen, hermes, cline, codebuddy and pi end to end: capability descriptors, installer branches and converters (bin/install.js 14.9k -> 11.2k lines), TypeScript converters, hook surfaces and runtime homes, review lanes qwen/kimi-code, the two pi migrations, Kimi payload normalization in the hook guards, dead hostBehaviors vocabulary, launcher home probes, fixtures, runtime-specific tests and the prose that presented them as supported. Installer output for the six kept runtimes is byte-identical to before the prune. The Kimi tool-vocabulary tests in workflow-guard, read-guard and read-injection-scanner are left in place pending a decision.
This commit is contained in:
@@ -25,7 +25,6 @@ const crypto = require('node:crypto');
|
||||
|
||||
const { resolveRuntimeArtifactLayout, findInstallSourceRoot } = require('../msd-core/bin/lib/runtime-artifact-layout.cjs');
|
||||
const capabilityRegistry = require('../msd-core/bin/lib/capability-registry.cjs');
|
||||
const installProfiles = require('../msd-core/bin/lib/install-profiles.cjs');
|
||||
const { withInstallFs } = require('../msd-core/bin/lib/install-fs-adapter.cjs');
|
||||
const { install } = require('../bin/install.js');
|
||||
const { createTempDir, cleanup, scrubConfigLocationEnv, writePackageSourceMarkerFixture } = require('./helpers.cjs');
|
||||
@@ -156,24 +155,6 @@ test('keeps every built-in local artifact layout project-scoped (#2777)', () =>
|
||||
}
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — copilot', () => {
|
||||
test('returns correct layout for copilot', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('copilot', FAKE_DIR);
|
||||
assert.strictEqual(layout.runtime, 'copilot');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
// #1575: agents kind added (copilot cutover)
|
||||
assert.strictEqual(layout.kinds.length, 2);
|
||||
assert.strictEqual(layout.kinds[0].kind, 'skills');
|
||||
assert.strictEqual(layout.kinds[0].destSubpath, 'skills');
|
||||
assert.strictEqual(layout.kinds[0].prefix, 'msd-');
|
||||
assert.strictEqual(typeof layout.kinds[0].stage, 'function');
|
||||
assert.strictEqual(layout.kinds[1].kind, 'agents');
|
||||
assert.strictEqual(layout.kinds[1].destSubpath, 'agents');
|
||||
assert.strictEqual(layout.kinds[1].prefix, 'msd-');
|
||||
assert.strictEqual(typeof layout.kinds[1].stage, 'function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — antigravity', () => {
|
||||
test('returns correct layout for antigravity', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('antigravity', FAKE_DIR);
|
||||
@@ -192,209 +173,8 @@ describe('resolveRuntimeArtifactLayout — antigravity', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — windsurf', () => {
|
||||
test('returns local workflow + agents layout for windsurf (ADR-1235)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('windsurf', FAKE_DIR, 'local');
|
||||
assert.strictEqual(layout.runtime, 'windsurf');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(layout.kinds.length, 2);
|
||||
|
||||
const commandsKind = layout.kinds.find(k => k.kind === 'commands');
|
||||
assert.ok(commandsKind, 'must have a commands/workflows kind');
|
||||
assert.strictEqual(commandsKind.destSubpath, 'workflows');
|
||||
assert.strictEqual(commandsKind.prefix, 'msd-');
|
||||
assert.strictEqual(typeof commandsKind.stage, 'function');
|
||||
|
||||
const agentsKind = layout.kinds.find(k => k.kind === 'agents');
|
||||
assert.ok(agentsKind, 'must have an agents kind (ADR-1235 §1 descriptor cutover)');
|
||||
assert.strictEqual(agentsKind.destSubpath, 'agents');
|
||||
assert.strictEqual(agentsKind.prefix, 'msd-');
|
||||
assert.strictEqual(typeof agentsKind.stage, 'function');
|
||||
});
|
||||
|
||||
test('returns agents-only global layout for windsurf (ADR-1235)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('windsurf', FAKE_DIR, 'global');
|
||||
assert.strictEqual(layout.runtime, 'windsurf');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(layout.kinds.length, 1);
|
||||
|
||||
const agentsKind = layout.kinds.find(k => k.kind === 'agents');
|
||||
assert.ok(agentsKind, 'global windsurf must have agents kind (ADR-1235 §1)');
|
||||
assert.strictEqual(agentsKind.destSubpath, 'agents');
|
||||
assert.strictEqual(agentsKind.prefix, 'msd-');
|
||||
assert.strictEqual(typeof agentsKind.stage, 'function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — augment', () => {
|
||||
test('returns correct layout for augment (commands + skills + agents — ADR-1235)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('augment', FAKE_DIR);
|
||||
assert.strictEqual(layout.runtime, 'augment');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(layout.kinds.length, 3);
|
||||
|
||||
const commandsKind = layout.kinds.find(k => k.kind === 'commands');
|
||||
assert.ok(commandsKind, 'must have a commands kind');
|
||||
assert.strictEqual(commandsKind.destSubpath, 'commands');
|
||||
assert.strictEqual(commandsKind.prefix, 'msd-');
|
||||
assert.strictEqual(typeof commandsKind.stage, 'function');
|
||||
|
||||
const skillsKind = layout.kinds.find(k => k.kind === 'skills');
|
||||
assert.ok(skillsKind, 'must have a skills kind');
|
||||
assert.strictEqual(skillsKind.destSubpath, 'skills');
|
||||
assert.strictEqual(skillsKind.prefix, 'msd-');
|
||||
assert.strictEqual(typeof skillsKind.stage, 'function');
|
||||
|
||||
const agentsKind = layout.kinds.find(k => k.kind === 'agents');
|
||||
assert.ok(agentsKind, 'must have an agents kind (ADR-1235 §1 descriptor cutover)');
|
||||
assert.strictEqual(agentsKind.destSubpath, 'agents');
|
||||
assert.strictEqual(agentsKind.prefix, 'msd-');
|
||||
assert.strictEqual(typeof agentsKind.stage, 'function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — trae', () => {
|
||||
test('returns correct layout for trae (skills + agents — ADR-1235)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('trae', FAKE_DIR);
|
||||
assert.strictEqual(layout.runtime, 'trae');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(layout.kinds.length, 2);
|
||||
|
||||
const skillsKind = layout.kinds.find(k => k.kind === 'skills');
|
||||
assert.ok(skillsKind, 'must have a skills kind');
|
||||
assert.strictEqual(skillsKind.destSubpath, 'skills');
|
||||
assert.strictEqual(skillsKind.prefix, 'msd-');
|
||||
assert.strictEqual(typeof skillsKind.stage, 'function');
|
||||
|
||||
const agentsKind = layout.kinds.find(k => k.kind === 'agents');
|
||||
assert.ok(agentsKind, 'must have an agents kind (ADR-1235 §1 descriptor cutover)');
|
||||
assert.strictEqual(agentsKind.destSubpath, 'agents');
|
||||
assert.strictEqual(agentsKind.prefix, 'msd-');
|
||||
assert.strictEqual(typeof agentsKind.stage, 'function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — qwen', () => {
|
||||
test('returns correct layout for qwen (skills + agents — #2092 Phase B Upgrade 1)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('qwen', FAKE_DIR);
|
||||
assert.strictEqual(layout.runtime, 'qwen');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(layout.kinds.length, 2);
|
||||
|
||||
const skillsKind = layout.kinds.find(k => k.kind === 'skills');
|
||||
assert.ok(skillsKind, 'must have a skills kind');
|
||||
assert.strictEqual(skillsKind.destSubpath, 'skills');
|
||||
assert.strictEqual(skillsKind.prefix, 'msd-');
|
||||
assert.strictEqual(typeof skillsKind.stage, 'function');
|
||||
|
||||
const agentsKind = layout.kinds.find(k => k.kind === 'agents');
|
||||
assert.ok(agentsKind, 'must have an agents kind (#2092 Phase B Upgrade 1 — native .qwen/agents/*.md subagent projection)');
|
||||
assert.strictEqual(agentsKind.destSubpath, 'agents');
|
||||
assert.strictEqual(agentsKind.prefix, 'msd-');
|
||||
assert.strictEqual(typeof agentsKind.stage, 'function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — kimi', () => {
|
||||
test('returns global skills layout and guarded empty local layout for kimi', () => {
|
||||
const globalLayout = resolveRuntimeArtifactLayout('kimi', FAKE_DIR, 'global');
|
||||
assert.strictEqual(globalLayout.runtime, 'kimi');
|
||||
assert.strictEqual(globalLayout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(globalLayout.kinds.length, 2);
|
||||
assert.strictEqual(globalLayout.kinds[0].kind, 'skills');
|
||||
assert.strictEqual(globalLayout.kinds[0].destSubpath, 'skills');
|
||||
assert.strictEqual(globalLayout.kinds[0].prefix, 'msd-');
|
||||
assert.strictEqual(typeof globalLayout.kinds[0].stage, 'function');
|
||||
assert.strictEqual(globalLayout.kinds[1].kind, 'kimi-agents');
|
||||
assert.strictEqual(globalLayout.kinds[1].destSubpath, 'agents');
|
||||
assert.strictEqual(globalLayout.kinds[1].prefix, 'msd');
|
||||
assert.strictEqual(typeof globalLayout.kinds[1].stage, 'function');
|
||||
|
||||
const localLayout = resolveRuntimeArtifactLayout('kimi', FAKE_DIR, 'local');
|
||||
assert.strictEqual(localLayout.runtime, 'kimi');
|
||||
assert.strictEqual(localLayout.configDir, FAKE_DIR);
|
||||
assert.deepStrictEqual(localLayout.kinds, []);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — hermes', () => {
|
||||
// #2875 Part 2: agents kind added — hermes was never in the deleted
|
||||
// `_DESCRIPTOR_AGENTS_RUNTIMES` set, so the inline loop wrote hermes agents
|
||||
// too (brand-swapped via the new named converter convertClaudeAgentToHermesAgent,
|
||||
// whose rewrite data was already declared on hostBehaviors.brandingRewrites).
|
||||
test('returns correct layout for hermes', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('hermes', FAKE_DIR);
|
||||
assert.strictEqual(layout.runtime, 'hermes');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(layout.kinds.length, 2);
|
||||
assert.strictEqual(layout.kinds[0].kind, 'skills');
|
||||
assert.strictEqual(layout.kinds[0].destSubpath, 'skills/msd');
|
||||
assert.strictEqual(layout.kinds[0].prefix, 'msd-'); // #947: restored canonical prefix
|
||||
assert.strictEqual(typeof layout.kinds[0].stage, 'function');
|
||||
assert.strictEqual(layout.kinds[1].kind, 'agents');
|
||||
assert.strictEqual(layout.kinds[1].destSubpath, 'agents');
|
||||
assert.strictEqual(layout.kinds[1].prefix, 'msd-');
|
||||
assert.strictEqual(typeof layout.kinds[1].stage, 'function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — codebuddy', () => {
|
||||
test('returns correct layout for codebuddy (commands + skills + agents — #789, ADR-1235)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('codebuddy', FAKE_DIR);
|
||||
assert.strictEqual(layout.runtime, 'codebuddy');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(layout.kinds.length, 3);
|
||||
|
||||
const commandsKind = layout.kinds.find(k => k.kind === 'commands');
|
||||
assert.ok(commandsKind, 'must have a commands kind');
|
||||
assert.strictEqual(commandsKind.destSubpath, 'commands');
|
||||
assert.strictEqual(commandsKind.prefix, 'msd-');
|
||||
assert.strictEqual(typeof commandsKind.stage, 'function');
|
||||
|
||||
const skillsKind = layout.kinds.find(k => k.kind === 'skills');
|
||||
assert.ok(skillsKind, 'must have a skills kind');
|
||||
assert.strictEqual(skillsKind.destSubpath, 'skills');
|
||||
assert.strictEqual(skillsKind.prefix, 'msd-');
|
||||
assert.strictEqual(typeof skillsKind.stage, 'function');
|
||||
|
||||
const agentsKind = layout.kinds.find(k => k.kind === 'agents');
|
||||
assert.ok(agentsKind, 'must have an agents kind (ADR-1235 §1 descriptor cutover)');
|
||||
assert.strictEqual(agentsKind.destSubpath, 'agents');
|
||||
assert.strictEqual(agentsKind.prefix, 'msd-');
|
||||
assert.strictEqual(typeof agentsKind.stage, 'function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — cline', () => {
|
||||
// #2875 Part 2: agents kind added to cline/global — cline was never in the
|
||||
// deleted `_DESCRIPTOR_AGENTS_RUNTIMES` set, so the inline loop wrote cline
|
||||
// agents too, via convertClaudeAgentToClineAgent.
|
||||
test('returns correct layout for cline global (skills-capable since v3.48.0 — #782)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('cline', FAKE_DIR, 'global');
|
||||
assert.strictEqual(layout.runtime, 'cline');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(layout.kinds.length, 2);
|
||||
assert.strictEqual(layout.kinds[0].kind, 'skills');
|
||||
assert.strictEqual(layout.kinds[0].destSubpath, 'skills');
|
||||
assert.strictEqual(layout.kinds[0].prefix, 'msd-');
|
||||
assert.strictEqual(typeof layout.kinds[0].stage, 'function');
|
||||
assert.strictEqual(layout.kinds[1].kind, 'agents');
|
||||
assert.strictEqual(layout.kinds[1].destSubpath, 'agents');
|
||||
assert.strictEqual(layout.kinds[1].prefix, 'msd-');
|
||||
assert.strictEqual(typeof layout.kinds[1].stage, 'function');
|
||||
});
|
||||
|
||||
test('cline local: no skills kind (skills are global-only, #782); agents kind present (#2875 Part 2 defect fix, cline-local agents-drop regression)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('cline', FAKE_DIR, 'local');
|
||||
assert.strictEqual(layout.runtime, 'cline');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
const kindNames = layout.kinds.map((k) => k.kind).sort();
|
||||
assert.deepStrictEqual(kindNames, ['agents'], 'cline local must declare only the agents kind — no skills kind');
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — opencode', () => {
|
||||
// #2875 Part 2: agents kind added — opencode/kilo's agents were previously
|
||||
// #2875 Part 2: agents kind added — opencode's agents were previously
|
||||
// written by a code path entirely separate from this layout
|
||||
// (installOpencodeFamilyArtifacts's bespoke writers never called
|
||||
// resolveRuntimeArtifactLayout for agents); installAgentsKindStandalone now
|
||||
@@ -427,44 +207,9 @@ describe('resolveRuntimeArtifactLayout — opencode', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveRuntimeArtifactLayout — kilo', () => {
|
||||
// #2875 Part 2: agents kind added — same reason as opencode above (kilo
|
||||
// shares the combined-family install shape).
|
||||
test('returns commands + skills + agents layout for kilo (#784)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('kilo', FAKE_DIR);
|
||||
assert.strictEqual(layout.runtime, 'kilo');
|
||||
assert.strictEqual(layout.configDir, FAKE_DIR);
|
||||
assert.strictEqual(layout.kinds.length, 3);
|
||||
|
||||
const commands = layout.kinds.find((k) => k.kind === 'commands');
|
||||
assert.ok(commands, 'should have a commands kind');
|
||||
assert.strictEqual(commands.destSubpath, 'command');
|
||||
assert.strictEqual(commands.prefix, 'msd-');
|
||||
assert.strictEqual(typeof commands.stage, 'function');
|
||||
|
||||
const skills = layout.kinds.find((k) => k.kind === 'skills');
|
||||
assert.ok(skills, 'should have a skills kind');
|
||||
assert.strictEqual(skills.destSubpath, 'skills');
|
||||
assert.strictEqual(skills.prefix, 'msd-');
|
||||
assert.strictEqual(typeof skills.stage, 'function');
|
||||
|
||||
const agents = layout.kinds.find((k) => k.kind === 'agents');
|
||||
assert.ok(agents, 'should have an agents kind');
|
||||
assert.strictEqual(agents.destSubpath, 'agents');
|
||||
assert.strictEqual(agents.prefix, 'msd-');
|
||||
assert.strictEqual(typeof agents.stage, 'function');
|
||||
});
|
||||
});
|
||||
|
||||
// ─── resolveRuntimeArtifactLayout — edge-cases ──────────────────────────────
|
||||
|
||||
describe('resolveRuntimeArtifactLayout edge-cases', () => {
|
||||
test('hermes has destSubpath skills/msd and msd- prefix (#947: restored from bare-stem)', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('hermes', '/tmp/x');
|
||||
assert.strictEqual(layout.kinds[0].destSubpath, 'skills/msd');
|
||||
assert.strictEqual(layout.kinds[0].prefix, 'msd-'); // #947: bare-stem prefix='' reversed
|
||||
});
|
||||
|
||||
test('claude local has both commands and agents kinds', () => {
|
||||
const layout = resolveRuntimeArtifactLayout('claude', '/tmp/x', 'local');
|
||||
const kindNames = layout.kinds.map(k => k.kind);
|
||||
@@ -630,87 +375,6 @@ describe('stage — skills kind (claude global)', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('stage — skills kind (kimi global)', () => {
|
||||
test('stage returns Kimi SKILL.md dirs and agent YAML/prompt artifacts', (t) => {
|
||||
const layout = resolveRuntimeArtifactLayout('kimi', createStageConfigDir(t), 'global');
|
||||
const skillsKind = layout.kinds.find(k => k.kind === 'skills');
|
||||
assert.ok(skillsKind, 'should have a skills kind');
|
||||
|
||||
const stagedDir = skillsKind.stage(PROFILE_CORE);
|
||||
assert.ok(fs.existsSync(stagedDir), 'stagedDir must exist');
|
||||
const skillMd = path.join(stagedDir, 'msd-new-project', 'SKILL.md');
|
||||
assert.ok(fs.existsSync(skillMd), 'msd-new-project/SKILL.md must exist');
|
||||
const content = fs.readFileSync(skillMd, 'utf8');
|
||||
assert.match(content, /^name: msd-new-project$/m);
|
||||
assert.match(content, /\/skill:msd-new-project/);
|
||||
assert.doesNotMatch(content, /kimi_cli\.tools|system_prompt_path|^version: 1$/m);
|
||||
|
||||
const agentsKind = layout.kinds.find(k => k.kind === 'kimi-agents');
|
||||
assert.ok(agentsKind, 'should have a kimi-agents kind');
|
||||
|
||||
const stagedAgentsDir = agentsKind.stage(PROFILE_FULL);
|
||||
const rootYamlPath = path.join(stagedAgentsDir, 'msd.yaml');
|
||||
const rootPromptPath = path.join(stagedAgentsDir, 'msd.md');
|
||||
const executorYamlPath = path.join(stagedAgentsDir, 'subagents', 'msd-executor.yaml');
|
||||
const executorPromptPath = path.join(stagedAgentsDir, 'subagents', 'msd-executor.md');
|
||||
assert.ok(fs.existsSync(rootYamlPath), 'agents/msd.yaml must be staged');
|
||||
assert.ok(fs.existsSync(rootPromptPath), 'agents/msd.md must be staged');
|
||||
assert.ok(fs.existsSync(executorYamlPath), 'agents/subagents/msd-executor.yaml must be staged');
|
||||
assert.ok(fs.existsSync(executorPromptPath), 'agents/subagents/msd-executor.md must be staged');
|
||||
|
||||
const rootYaml = fs.readFileSync(rootYamlPath, 'utf8');
|
||||
assert.match(rootYaml, /^version: 1$/m);
|
||||
assert.match(rootYaml, /^agent:$/m);
|
||||
assert.match(rootYaml, /extend: default/);
|
||||
assert.match(rootYaml, /system_prompt_path: \.\/msd\.md/);
|
||||
assert.match(rootYaml, /tools:/);
|
||||
assert.match(rootYaml, /subagents:/);
|
||||
assert.match(rootYaml, /kimi_cli\.tools\./);
|
||||
assert.doesNotMatch(rootYaml, /mcp__/);
|
||||
|
||||
const executorYaml = fs.readFileSync(executorYamlPath, 'utf8');
|
||||
assert.match(executorYaml, /system_prompt_path: \.\/msd-executor\.md/);
|
||||
assert.match(executorYaml, /kimi_cli\.tools\./);
|
||||
assert.doesNotMatch(executorYaml, /mcp__/);
|
||||
});
|
||||
|
||||
test('tracks Kimi agent staging dir before writing artifacts', (t) => {
|
||||
const layout = resolveRuntimeArtifactLayout('kimi', createStageConfigDir(t), 'global');
|
||||
const agentsKind = layout.kinds.find(k => k.kind === 'kimi-agents');
|
||||
assert.ok(agentsKind, 'should have a kimi-agents kind');
|
||||
|
||||
const originalWriteFileSync = fs.writeFileSync;
|
||||
const before = new Set(installProfiles.STAGED_DIRS);
|
||||
let added = [];
|
||||
|
||||
try {
|
||||
fs.writeFileSync = function writeFileSyncWithInjectedFailure(file, ...args) {
|
||||
const filePath = String(file);
|
||||
if (filePath.includes('msd-kimi-agents-') && path.basename(filePath) === 'msd.yaml') {
|
||||
throw new Error('forced Kimi stage write failure');
|
||||
}
|
||||
return originalWriteFileSync.call(this, file, ...args);
|
||||
};
|
||||
|
||||
assert.throws(
|
||||
() => agentsKind.stage(PROFILE_FULL),
|
||||
/forced Kimi stage write failure/
|
||||
);
|
||||
|
||||
added = [...installProfiles.STAGED_DIRS]
|
||||
.filter(dir => !before.has(dir) && path.basename(dir).startsWith('msd-kimi-agents-'));
|
||||
assert.strictEqual(added.length, 1, 'partially written Kimi stage dir must be tracked for cleanup');
|
||||
assert.ok(fs.existsSync(added[0]), 'tracked partial Kimi stage dir should exist');
|
||||
} finally {
|
||||
fs.writeFileSync = originalWriteFileSync;
|
||||
for (const dir of added) {
|
||||
cleanup(dir);
|
||||
installProfiles.STAGED_DIRS.delete(dir);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('stage — opencode commands kind', () => {
|
||||
test('opencode stage returns directory with .md files for selected skills', (t) => {
|
||||
const layout = resolveRuntimeArtifactLayout('opencode', createStageConfigDir(t));
|
||||
@@ -727,8 +391,8 @@ describe('stage — opencode commands kind', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('stage — opencode/kilo skills kind (#784)', () => {
|
||||
for (const runtime of ['opencode', 'kilo']) {
|
||||
describe('stage — opencode skills kind (#784)', () => {
|
||||
for (const runtime of ['opencode']) {
|
||||
test(`${runtime} skills stage writes msd-<stem>/SKILL.md with name + description`, (t) => {
|
||||
const layout = resolveRuntimeArtifactLayout(runtime, createStageConfigDir(t));
|
||||
const skillsKind = layout.kinds.find(k => k.kind === 'skills');
|
||||
|
||||
Reference in New Issue
Block a user