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:
Jakub Zych
2026-10-06 20:02:40 +02:00
parent 12ee75a509
commit 6cfa0c55d2
509 changed files with 1869 additions and 47737 deletions

View File

@@ -2,15 +2,12 @@
/**
* Installer Module — date-stamped regression tests.
*
* Consolidates install-hermes-regressions.test.cjs into a single
* regressions file for the installer module cluster.
* Regressions file for the installer module cluster.
*
* Defects covered:
* #3664 — --config-dir foreign-agent destination warning (warn-and-proceed)
* #3664 Defect #1 — stale skills/msd/msd-<stem>/ dirs on Hermes upgrade
* #3664 Defect #2 — --hermes --profile=core falls through to wrong path
* #2973 M1–M3 — dev-preferences migration at profile=core for hermes/qwen/claude
* #2973 U1–U3 — uninstall preserves dev-preferences via skill migration
* #2973 M3 — dev-preferences migration at profile=core for claude
* #2973 U2 — uninstall preserves dev-preferences via skill migration
*
* Closes #3758
*/
@@ -29,11 +26,6 @@ const { INSTALL_TIMEOUT_MS, FIXTURE_HOOK_TIMEOUT_SECONDS } = require('./helpers/
const SCOPED_INSTALL_TIMEOUT_MS = 60_000;
const { createTempDir, cleanup, mockPartialWriteThenThrow } = require('./helpers.cjs');
const {
loadSkillsManifest,
resolveProfile,
} = require('../msd-core/bin/lib/install-profiles.cjs');
// Load install exports via MSD_TEST_MODE to skip CLI main()
const savedTestMode = process.env.MSD_TEST_MODE;
process.env.MSD_TEST_MODE = '1';
@@ -48,7 +40,6 @@ try {
const { install, mergeClaudePermissions, MSD_CLAUDE_ALLOW_PERMISSIONS, MSD_CLAUDE_LEGACY_ALLOW_PERMISSIONS, MSD_CLAUDE_LEGACY_DENY_PERMISSIONS, copyWithPathReplacement } = installExports || {};
const {
installRuntimeArtifacts,
uninstallRuntimeArtifacts,
} = require('../msd-core/bin/lib/install-engine.cjs');
@@ -61,9 +52,6 @@ const {
const INSTALL_SCRIPT = path.join(__dirname, '..', 'bin', 'install.js');
// #3145: class-norm timeout, not a per-suite value — see helpers/timeouts.cjs.
const HOOKS_SRC = path.join(__dirname, '..', 'hooks');
const REAL_COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'msd');
const MANIFEST = loadSkillsManifest(REAL_COMMANDS_DIR);
const RESOLVED_CORE = resolveProfile({ modes: ['core'], manifest: MANIFEST });
/**
* Stub managed MSD hook files into targetDir/hooks/ so that
@@ -119,171 +107,6 @@ describe('#2429 regression: Codex local skills stay project-scoped', () => {
});
});
// ─── Defect #1 — Hermes upgrade: bare-stem dirs from #3664 era become stale ──
//
// #947 REVERSES #3664: the canonical layout is now skills/msd/msd-<stem>/ again.
// The migration now removes bare-stem dirs (from #3664: prefix='') and writes
// the msd-prefixed layout. Pre-existing msd-prefixed dirs (the "intermediate"
// layout from before #3664) are now the CANONICAL dirs and are kept / updated.
describe('Defect #1 regression (#3664 reversed by #947): bare-stem dirs removed, msd- prefix written', () => {
test('installRuntimeArtifacts removes bare-stem skills/msd/<stem>/ dirs and writes msd- prefixed layout', (t) => {
const configDir = createTempDir('msd-hermes-reg1-');
t.after(() => cleanup(configDir));
assert.strictEqual(typeof installRuntimeArtifacts, 'function',
'installRuntimeArtifacts must be exported from install-engine.cjs');
// Pre-create #3664-era bare-stem Hermes layout (no msd- prefix, now stale).
// Use real MSD command stems (help, quick) that readMsdCommandNames() knows about.
const nestedMsdDir = path.join(configDir, 'skills', 'msd');
fs.mkdirSync(path.join(nestedMsdDir, 'help'), { recursive: true });
fs.writeFileSync(path.join(nestedMsdDir, 'help', 'SKILL.md'), '# legacy bare-stem help\n');
fs.mkdirSync(path.join(nestedMsdDir, 'quick'), { recursive: true });
fs.writeFileSync(path.join(nestedMsdDir, 'quick', 'SKILL.md'), '# legacy bare-stem quick\n');
// Sibling non-msd dir inside skills/msd/ must survive
const userContentDir = path.join(nestedMsdDir, 'user-content');
fs.mkdirSync(userContentDir, { recursive: true });
fs.writeFileSync(path.join(userContentDir, 'SKILL.md'), '# user content\n');
installRuntimeArtifacts('hermes', configDir, 'global', RESOLVED_CORE);
// Bare-stem dirs from #3664 must be cleaned
assert.ok(!fs.existsSync(path.join(nestedMsdDir, 'help')),
'skills/msd/help/ (bare-stem from #3664) must be removed (#947)');
assert.ok(!fs.existsSync(path.join(nestedMsdDir, 'quick')),
'skills/msd/quick/ (bare-stem from #3664) must be removed (#947)');
// Canonical msd- prefixed layout must be written
assert.ok(fs.existsSync(path.join(nestedMsdDir, 'msd-help', 'SKILL.md')),
'skills/msd/msd-help/SKILL.md must exist after install (#947 canonical layout)');
// User content preserved
assert.ok(fs.existsSync(path.join(userContentDir, 'SKILL.md')),
'user-content must be preserved');
});
});
// ─── Defect #2 — --qwen --profile=core falls through to wrong path ────────────
describe('Defect #2 regression (Qwen, #3664): --qwen --profile=core writes skills/msd-*/, not commands/msd/', () => {
test('spawn --qwen --global --profile=core: skills/msd-*/ written, no commands/msd/', (t) => {
const root = createTempDir('msd-qwen-reg2-');
t.after(() => cleanup(root));
const result = runNode(
[INSTALL_SCRIPT, '--qwen', '--global', '--config-dir', root, '--profile=core'],
{ env: { ...process.env, HOME: root, USERPROFILE: root }, timeoutMs: INSTALL_TIMEOUT_MS },
);
assert.strictEqual(result.exitCode, 0,
`installer exited ${result.exitCode}\n${result.stdout}\n${result.stderr}`);
const qwenSkillsDir = path.join(root, 'skills');
assert.ok(fs.existsSync(qwenSkillsDir));
const skillDirs = fs.readdirSync(qwenSkillsDir, { withFileTypes: true })
.filter(e => e.isDirectory() && e.name.startsWith('msd-'));
assert.ok(skillDirs.length >= 1, 'at least one msd-* skill dir must exist');
assert.ok(
skillDirs.some(e => fs.existsSync(path.join(qwenSkillsDir, e.name, 'SKILL.md'))),
'at least one skills/msd-*/SKILL.md must exist'
);
const commandsMsd = path.join(root, 'commands', 'msd');
if (fs.existsSync(commandsMsd)) {
const mdFiles = fs.readdirSync(commandsMsd).filter(f => f.endsWith('.md'));
assert.strictEqual(mdFiles.length, 0, `commands/msd/ must not contain .md files (Defect #2). Found: ${mdFiles.join(', ')}`);
}
});
});
describe('Defect #2 regression (Hermes, #3664): --hermes --profile=core writes skills/msd/, not commands/msd/', () => {
test('spawn --hermes --global --profile=core: skills/msd/ written, no commands/msd/', (t) => {
const root = createTempDir('msd-hermes-reg2-');
t.after(() => cleanup(root));
const result = runNode(
[INSTALL_SCRIPT, '--hermes', '--global', '--config-dir', root, '--profile=core'],
{ env: { ...process.env, HOME: root, USERPROFILE: root }, timeoutMs: INSTALL_TIMEOUT_MS },
);
assert.strictEqual(result.exitCode, 0,
`installer exited ${result.exitCode}\n${result.stdout}\n${result.stderr}`);
const hermesSkillsMsd = path.join(root, 'skills', 'msd');
assert.ok(fs.existsSync(hermesSkillsMsd));
const skillDirs = fs.readdirSync(hermesSkillsMsd, { withFileTypes: true })
.filter(e => e.isDirectory());
assert.ok(skillDirs.length >= 1);
assert.ok(
skillDirs.some(e => fs.existsSync(path.join(hermesSkillsMsd, e.name, 'SKILL.md'))),
);
const commandsMsd = path.join(root, 'commands', 'msd');
if (fs.existsSync(commandsMsd)) {
const mdFiles = fs.readdirSync(commandsMsd).filter(f => f.endsWith('.md'));
assert.strictEqual(mdFiles.length, 0, `commands/msd/ must not contain .md files (Defect #2). Found: ${mdFiles.join(', ')}`);
}
});
});
// ─── M1 — Hermes minimal-mode migrates dev-preferences (#2973) ───────────────
describe('M1 (#2973, #947): --hermes --global --profile=core migrates dev-preferences → skills/msd/msd-dev-preferences/SKILL.md', () => {
test('dev-preferences migrated to nested Hermes location, legacy source removed', (t) => {
const root = createTempDir('msd-hermes-m1-');
t.after(() => cleanup(root));
const legacyDir = path.join(root, 'commands', 'msd');
fs.mkdirSync(legacyDir, { recursive: true });
fs.writeFileSync(path.join(legacyDir, 'dev-preferences.md'), '# my hermes prefs\n');
const result = runNode(
[INSTALL_SCRIPT, '--hermes', '--global', '--config-dir', root, '--profile=core'],
{ env: { ...process.env, HOME: root, USERPROFILE: root }, timeoutMs: INSTALL_TIMEOUT_MS },
);
assert.strictEqual(result.exitCode, 0,
`installer exited ${result.exitCode}\n${result.stdout}\n${result.stderr}`);
// #947: Hermes uses prefix='msd-' so dev-preferences lands at msd-dev-preferences/ (not dev-preferences/)
const skillFile = path.join(root, 'skills', 'msd', 'msd-dev-preferences', 'SKILL.md');
assert.ok(fs.existsSync(skillFile),
'skills/msd/msd-dev-preferences/SKILL.md must exist (M1+#947: msd- prefix, nested)');
assert.strictEqual(fs.readFileSync(skillFile, 'utf8'), '# my hermes prefs\n');
assert.ok(!fs.existsSync(path.join(legacyDir, 'dev-preferences.md')),
'legacy source must be removed');
});
});
// ─── M2 — Qwen minimal-mode migrates dev-preferences (#2973) ────────────────
describe('M2 (#2973): --qwen --global --profile=core migrates dev-preferences → skills/msd-dev-preferences/SKILL.md', () => {
test('dev-preferences migrated to flat Qwen location, legacy source removed', (t) => {
const root = createTempDir('msd-qwen-m2-');
t.after(() => cleanup(root));
const legacyDir = path.join(root, 'commands', 'msd');
fs.mkdirSync(legacyDir, { recursive: true });
fs.writeFileSync(path.join(legacyDir, 'dev-preferences.md'), '# my qwen prefs\n');
const result = runNode(
[INSTALL_SCRIPT, '--qwen', '--global', '--config-dir', root, '--profile=core'],
{ env: { ...process.env, HOME: root, USERPROFILE: root }, timeoutMs: INSTALL_TIMEOUT_MS },
);
assert.strictEqual(result.exitCode, 0,
`installer exited ${result.exitCode}\n${result.stdout}\n${result.stderr}`);
const skillFile = path.join(root, 'skills', 'msd-dev-preferences', 'SKILL.md');
assert.ok(fs.existsSync(skillFile),
'skills/msd-dev-preferences/SKILL.md must exist (M2: flat Qwen layout)');
assert.strictEqual(fs.readFileSync(skillFile, 'utf8'), '# my qwen prefs\n');
assert.ok(!fs.existsSync(path.join(legacyDir, 'dev-preferences.md')));
});
});
// ─── M3 — Claude global minimal-mode migrates dev-preferences (#2973) ────────
describe('M3 (#2973): --claude --global --profile=core migrates dev-preferences → skills/msd-dev-preferences/SKILL.md', () => {
@@ -311,32 +134,6 @@ describe('M3 (#2973): --claude --global --profile=core migrates dev-preferences
});
});
// ─── U1 — Qwen uninstall preserves dev-preferences via migration (#2973) ─────
describe('U1 (#2973): uninstallRuntimeArtifacts qwen migrates dev-preferences → skills/msd-dev-preferences/SKILL.md', () => {
test('commands/msd/ removed, dev-preferences migrated to skills skill', (t) => {
const configDir = createTempDir('msd-qwen-uninstall-u1-');
t.after(() => cleanup(configDir));
assert.strictEqual(typeof uninstallRuntimeArtifacts, 'function',
'uninstallRuntimeArtifacts must be exported from install-engine.cjs');
const legacyDir = path.join(configDir, 'commands', 'msd');
fs.mkdirSync(legacyDir, { recursive: true });
fs.writeFileSync(path.join(legacyDir, 'dev-preferences.md'), '# my qwen prefs\n');
fs.writeFileSync(path.join(legacyDir, 'help.md'), '# help content\n');
uninstallRuntimeArtifacts('qwen', configDir, 'global');
assert.ok(!fs.existsSync(path.join(legacyDir, 'help.md')));
assert.ok(!fs.existsSync(path.join(legacyDir, 'dev-preferences.md')));
const skillFile = path.join(configDir, 'skills', 'msd-dev-preferences', 'SKILL.md');
assert.ok(fs.existsSync(skillFile), 'skills/msd-dev-preferences/SKILL.md must exist (U1)');
assert.strictEqual(fs.readFileSync(skillFile, 'utf8'), '# my qwen prefs\n');
});
});
// ─── U2 — Claude-global uninstall preserves dev-preferences (#2973) ──────────
describe('U2 (#2973): uninstallRuntimeArtifacts claude/global migrates dev-preferences → skills/msd-dev-preferences/SKILL.md', () => {
@@ -360,32 +157,6 @@ describe('U2 (#2973): uninstallRuntimeArtifacts claude/global migrates dev-prefe
});
});
// ─── U3 — Hermes uninstall migrates dev-preferences to NESTED location (#2973) ─
describe('U3 (#2973, #947): uninstallRuntimeArtifacts hermes migrates dev-preferences → skills/msd/msd-dev-preferences/SKILL.md', () => {
test('commands/msd/ NOT recreated, dev-preferences at nested Hermes location with msd- prefix', (t) => {
const configDir = createTempDir('msd-hermes-uninstall-u3-');
t.after(() => cleanup(configDir));
assert.strictEqual(typeof uninstallRuntimeArtifacts, 'function');
const legacyDir = path.join(configDir, 'commands', 'msd');
fs.mkdirSync(legacyDir, { recursive: true });
fs.writeFileSync(path.join(legacyDir, 'dev-preferences.md'), '# my hermes prefs\n');
uninstallRuntimeArtifacts('hermes', configDir, 'global');
assert.ok(!fs.existsSync(path.join(legacyDir, 'dev-preferences.md')),
'commands/msd/dev-preferences.md must not exist after hermes uninstall (U3)');
// #947: Hermes uses prefix='msd-' so dev-preferences lands at msd-dev-preferences/ (not dev-preferences/)
const skillFile = path.join(configDir, 'skills', 'msd', 'msd-dev-preferences', 'SKILL.md');
assert.ok(fs.existsSync(skillFile),
'skills/msd/msd-dev-preferences/SKILL.md must exist at HERMES nested location (U3+#947)');
assert.strictEqual(fs.readFileSync(skillFile, 'utf8'), '# my hermes prefs\n');
});
});
// ─── #768 — mergeClaudePermissions: pre-populate permissions.allow/deny ──────
describe('mergeClaudePermissions (#768): exports and permission constants', () => {
@@ -1723,10 +1494,10 @@ describe('#3329 regression: stale managed .sh hook commands are reconciled on in
const changed = reconcileManagedShellHookCommands(settings, GLOBAL_EXPECTED, {
platform: 'win32',
runtime: 'qwen',
runtime: 'codex',
});
assert.strictEqual(changed, false, 'win32+qwen keeps the bash runner by design');
assert.strictEqual(changed, false, 'win32+codex keeps the bash runner by design');
assert.strictEqual(settings.hooks.SessionStart[0].hooks[0].command, original);
});
@@ -1909,32 +1680,6 @@ describe('#3664 — config-dir foreign-agent destination warning', () => {
assert.ok(!lines.some((l) => l.includes('(#3664)')), `non-agent files are not harness evidence: ${lines.join(' | ')}`);
});
test('warns for the kimi runtime (kimi-agents kind)', (t) => {
const { dest } = makeForeignDest(t, 'kimi-foreign', ['junie-guide.md']);
const { lines } = capturedLogs(t, () =>
installerMod.warnIfForeignAgentDest('kimi', dest, 'global', true),
);
assert.ok(
lines.some((l) => l.includes('(#3664)') && l.includes('kimi')),
`kimi's kimi-agents kind must take the gate: ${lines.join(' | ')}`,
);
});
test('silent on kimi\'s own msd.md in a shared multi-runtime dir', (t) => {
// kimi's root agent is agents/msd.md — a bare stem, no msd- prefix. A
// shared --all dir accumulates it alongside msd-*.md; none of it is
// foreign, so every runtime's install into that dir must stay silent.
const { dest } = makeForeignDest(t, 'shared-kimi', ['msd-executor.md', 'msd.md']);
const { lines } = capturedLogs(t, () => {
installerMod.warnIfForeignAgentDest('kimi', dest, 'global', true);
installerMod.warnIfForeignAgentDest('claude', dest, 'global', true);
});
assert.ok(
!lines.some((l) => l.includes('(#3664)')),
`MSD-owned msd.md must not read as a foreign agent: ${lines.join(' | ')}`,
);
});
test('degrades silently when the layout cannot resolve', (t) => {
const dest = createTempDir('msd-3664-unknown-');
t.after(() => cleanup(dest));