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

@@ -6744,167 +6744,15 @@ describe('bug #260: msd-worktree-path-guard.js', () => {
});
});
// 5b. #2547 — a malformed Kimi edit list must not downgrade the block to an allow
describe('#2547: malformed Kimi edit list does not bypass the cross-root block', () => {
// normalizeKimiPayload rebuilt old_string/new_string with `String(e.old ?? '')`.
// `??` guards the value, not the dereference, so a NULLISH entry threw a
// TypeError before any tool dispatch — and the guard's outer
// `catch { process.exit(0) }` turned that crash into a silent ALLOW on the one
// path this guard exists to BLOCK (#260).
//
// The boundary is nullish specifically, not "non-object": `('x').old` and
// `(7).old` are legal property reads that yield undefined, so string/number
// entries never threw. They are kept below as controls proving `e?.old` did
// not change their behaviour; the nullish cases are the actual regression and
// are the ones that exit 0 (bypass) against pre-fix code.
const crossRootTarget = () => path.join(mainRepo, 'src', 'index.ts');
test('well-formed Kimi edit list blocks the cross-root write (positive control)', () => {
const result = runHook(worktreeDir, {
cwd: worktreeDir,
tool_name: 'StrReplaceFile',
tool_input: { path: crossRootTarget(), edit: [{ old: 'orig', new: 'pwned' }] },
});
assert.strictEqual(result.status, 2,
`expected exit 2 (block), got ${result.status}. stderr: ${result.stderr}`);
assert.strictEqual(JSON.parse(result.stdout).decision, 'block');
});
for (const [label, edit] of [
['null entry (the #2547 bypass)', [null]],
['null alongside a well-formed entry (the #2547 bypass)', [{ old: 'a', new: 'b' }, null]],
// `{"toString": null}` is valid JSON whose coercion throws "Cannot
// convert object to primitive value" — the same crash-to-allow reached
// through String() rather than through the property read.
['non-coercible old (the #2547 String() bypass)', [{ old: { toString: null }, new: 'x' }]],
['non-coercible new (the #2547 String() bypass)', [{ old: 'x', new: { toString: null } }]],
['string entry (control — never threw)', ['nope']],
['number entry (control — never threw)', [7]],
]) {
test(`${label} in the edit list still blocks the cross-root write`, () => {
const result = runHook(worktreeDir, {
cwd: worktreeDir,
tool_name: 'StrReplaceFile',
tool_input: { path: crossRootTarget(), edit },
});
assert.strictEqual(result.status, 2,
`a malformed edit list (${label}) must not downgrade the #260 block to a silent ` +
`allow. Got exit ${result.status}. stderr: ${result.stderr}`);
assert.strictEqual(JSON.parse(result.stdout).decision, 'block');
});
}
test('malformed edit list inside the worktree still exits 0 (no over-block)', () => {
const result = runHook(worktreeDir, {
cwd: worktreeDir,
tool_name: 'StrReplaceFile',
tool_input: { path: path.join(worktreeDir, 'src', 'index.ts'), edit: [null] },
});
assert.strictEqual(result.status, 0,
`an in-worktree write must stay allowed. Got exit ${result.status}. stderr: ${result.stderr}`);
assert.strictEqual(result.stdout, '');
});
});
// 5c. #2547 (review BLOCKER) — a model-supplied `file_path` must not shadow
// Kimi's authoritative `path`. This vector needs NO crash: normalizeKimiPayload
// copied `path` into `file_path` only when `file_path === undefined`, so any
// `file_path` the model chose to include won, and this guard's block logic
// reads `file_path` alone. kimi-cli executes on `path`, so the guard inspected
// one file while the write landed on another.
//
// Reachability is not speculative: soul/toolset.py json-parses the model's raw
// tool arguments and passes that dict verbatim as tool_input to PreToolUse,
// performing typed validation only later inside tool.call() — so the model
// controls extra keys in tool_input at the moment the hook decides.
describe('#2547: a spurious file_path does not shadow Kimi\'s authoritative path', () => {
const crossRootTarget = () => path.join(mainRepo, 'src', 'index.ts');
const inWorktreeTarget = () => path.join(worktreeDir, 'src', 'index.ts');
// Each case pairs a cross-root `path` with a `file_path` the model supplied.
// All three exited 0 (bypass) before the fix.
for (const [label, filePath] of [
['empty-string file_path (the #2547 review BLOCKER)', ''],
['in-worktree decoy file_path', null], // resolved below — needs worktreeDir
// A NON-STRING file_path additionally threw inside path.isAbsolute() and
// reached the outer `catch { process.exit(0) }` — crash-to-allow through
// the guard's own read rather than through normalization.
['non-string file_path (array)', []],
['non-string file_path (object)', {}],
]) {
test(`${label} still blocks the cross-root write`, () => {
const result = runHook(worktreeDir, {
cwd: worktreeDir,
tool_name: 'StrReplaceFile',
tool_input: {
path: crossRootTarget(),
file_path: filePath === null ? inWorktreeTarget() : filePath,
edit: [{ old: 'orig', new: 'pwned' }],
},
});
assert.strictEqual(result.status, 2,
`a model-supplied file_path (${label}) must not shadow Kimi's authoritative ` +
`path and downgrade the #260 block to a silent allow. Got exit ${result.status}. ` +
`stderr: ${result.stderr}`);
assert.strictEqual(JSON.parse(result.stdout).decision, 'block');
});
}
// Negative control: the same shadowing shape pointed INSIDE the worktree must
// still be allowed, so the fix narrows what the guard inspects without
// over-blocking.
test('a spurious file_path on an in-worktree write still exits 0 (no over-block)', () => {
const result = runHook(worktreeDir, {
cwd: worktreeDir,
tool_name: 'StrReplaceFile',
tool_input: {
path: inWorktreeTarget(),
file_path: crossRootTarget(),
edit: [{ old: 'orig', new: 'ok' }],
},
});
assert.strictEqual(result.status, 0,
`an in-worktree write must stay allowed even when a decoy file_path points ` +
`cross-root — the guard follows the path kimi-cli executes on. ` +
`Got exit ${result.status}. stderr: ${result.stderr}`);
assert.strictEqual(result.stdout, '');
});
// Control: a NATIVE Claude payload has no `path` field, so the overwrite must
// not fire and file_path must keep governing. Guards against a fix that
// silently changed the non-Kimi contract.
test('native Claude payload (no path field) still blocks on file_path alone', () => {
const result = runHook(worktreeDir, {
cwd: worktreeDir,
tool_name: 'Edit',
tool_input: { file_path: crossRootTarget() },
});
assert.strictEqual(result.status, 2,
`a native Claude Edit must still block on file_path. Got exit ${result.status}. ` +
`stderr: ${result.stderr}`);
assert.strictEqual(JSON.parse(result.stdout).decision, 'block');
});
});
// 5d. #2595 (review Major 3) — the non-string `file_path` crash-to-allow, read
// WITHOUT a string `path` to mask it.
//
// The 5c cases above pair a non-string file_path with a valid cross-root
// `path`, so they pass because the authoritative-path overwrite replaces the
// bad value before the read. That is real coverage of the SHADOWING fix, but
// the review was right that it is not coverage of the crash: drop the `path`
// key and the identical payload took `data.tool_input?.file_path || ''` ->
// `[]` (truthy, survives the `!rawFilePath` early-out) -> `path.isAbsolute([])`
// 5d. #2595 (review Major 3) — a non-string `file_path` must fail open
// explicitly rather than crash: `data.tool_input?.file_path || ''` -> `[]`
// (truthy, survives the `!rawFilePath` early-out) -> `path.isAbsolute([])`
// -> TypeError -> outer `catch { process.exit(0) }`.
//
// READ THE ASSERTION HONESTLY: these expect exit 0, and pre-fix code ALSO
// exits 0 — via the catch instead of via the early-out. There is no black-box
// signature that separates them, so these cases document the fail-open and
// guard against a future change that makes a malformed payload BLOCK; they do
// not detect a revert. The gate that fails on a revert is the source-level
// invariant in tests/kimi-guard-typed-payload-reads.test.cjs. Asserting exit 0
// here and calling it regression coverage would repeat, one level up, exactly
// the false-green the review flagged in 5c.
// These expect exit 0, and a revert ALSO exits 0 (via the catch instead of the
// early-out) — there is no black-box signature that separates them, so these
// cases document the fail-open and guard against a future change that makes a
// malformed payload BLOCK; they do not detect a revert.
describe('#2595: a non-string file_path with no path key fails open explicitly', () => {
for (const [label, filePath] of [
['array', []],
@@ -6924,17 +6772,6 @@ describe('bug #260: msd-worktree-path-guard.js', () => {
assert.strictEqual(result.stdout, '');
});
test(`Kimi payload with a ${label} file_path and no path key exits 0`, () => {
const result = runHook(worktreeDir, {
cwd: worktreeDir,
tool_name: 'StrReplaceFile',
tool_input: { file_path: filePath, edit: [{ old: 'orig', new: 'pwned' }] },
});
assert.strictEqual(result.status, 0,
`with no string path to normalize from, there is nothing to check. ` +
`Got exit ${result.status}. stderr: ${result.stderr}`);
assert.strictEqual(result.stdout, '');
});
}
// Control: the SAME payload shape with a string cross-root file_path must
@@ -7145,83 +6982,6 @@ describe('bug #260: msd-worktree-path-guard.js', () => {
});
// ---------------------------------------------------------------------------
// #2304 — Kimi tool vocabulary engages the guard
// ---------------------------------------------------------------------------
describe('#2304 — Kimi tool vocabulary engages the guard', () => {
// Payload shapes mirror kimi-cli's actual tool schemas
// (src/kimi_cli/tools/file/{write,replace}.py): WriteFile takes
// `path`/`content`, StrReplaceFile takes `path` + `edit: Edit | list[Edit]`
// — NOT Claude's `file_path`/`old_string`/`new_string`.
test('WriteFile targeting the main repo from a worktree is blocked like Write', () => {
const offendingPath = path.join(mainRepo, 'out.txt');
const payload = {
cwd: worktreeDir,
tool_name: 'WriteFile',
tool_input: { path: offendingPath, content: 'leak' },
};
const result = runHook(worktreeDir, payload);
assert.strictEqual(result.status, 2,
`Kimi WriteFile targeting an outside path must be blocked. Got ${result.status}. stderr: ${result.stderr}`);
const parsed = JSON.parse(result.stdout);
assert.strictEqual(parsed.decision, 'block');
// Kimi feeds stderr (not stdout) back to the model on exit 2, so the
// reason must also reach stderr or the model gets a bare denial.
assert.ok(result.stderr.includes(offendingPath),
`block reason must reach stderr for Kimi's exit-2 protocol. Got stderr: ${result.stderr}`);
});
test('StrReplaceFile targeting the main repo from a worktree is blocked like Edit', () => {
const payload = {
cwd: worktreeDir,
tool_name: 'StrReplaceFile',
tool_input: { path: path.join(mainRepo, 'src', 'index.ts'), edit: { old: 'a', new: 'b' } },
};
const result = runHook(worktreeDir, payload);
assert.strictEqual(result.status, 2,
`Kimi StrReplaceFile targeting an outside path must be blocked. Got ${result.status}. stderr: ${result.stderr}`);
const parsed = JSON.parse(result.stdout);
assert.strictEqual(parsed.decision, 'block');
});
test('module-qualified kimi_cli.tools.file:WriteFile is also recognized', () => {
const payload = {
cwd: worktreeDir,
tool_name: 'kimi_cli.tools.file:WriteFile',
tool_input: { path: path.join(mainRepo, 'out.txt'), content: 'leak' },
};
const result = runHook(worktreeDir, payload);
assert.strictEqual(result.status, 2,
`Module-qualified Kimi WriteFile must be blocked. Got ${result.status}. stderr: ${result.stderr}`);
const parsed = JSON.parse(result.stdout);
assert.strictEqual(parsed.decision, 'block');
});
test('StrReplaceFile with a path inside the worktree still passes', () => {
const payload = {
cwd: worktreeDir,
tool_name: 'StrReplaceFile',
tool_input: { path: path.join(worktreeDir, 'src', 'foo.ts'), edit: { old: 'a', new: 'b' } },
};
const result = runHook(worktreeDir, payload);
assert.strictEqual(result.status, 0,
`Kimi StrReplaceFile inside the worktree should pass. Got ${result.status}. stderr: ${result.stderr}`);
});
test('non-file Kimi tools still pass through silently', () => {
const payload = {
cwd: worktreeDir,
tool_name: 'kimi_cli.tools.file:Grep',
tool_input: { path: path.join(mainRepo, 'src', 'index.ts') },
};
const result = runHook(worktreeDir, payload);
assert.strictEqual(result.status, 0);
assert.strictEqual(result.stdout, '');
});
});
// ---------------------------------------------------------------------------
// #1342 — MSD-activity gate + fail-open for no-repo targets
// ---------------------------------------------------------------------------