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:
@@ -42,20 +42,18 @@
|
||||
* entries and MISSED a real leak into `<live>/skills/msd-dev-preferences/`.
|
||||
*
|
||||
* KNOWN GAP — a leak into a file MSD does not own (e.g. mutating the host's own
|
||||
* `.claude.json`, `settings.json`, `hooks.json`, `kilo.json`, `opencode.json`) is
|
||||
* `.claude.json`, `settings.json`, `hooks.json`, `opencode.json`) is
|
||||
* outside this guard by construction. Closing it would require watching shared
|
||||
* files, which is the false-positive trap above.
|
||||
*
|
||||
* NAMED RESIDUALS — stated rather than implied, because two successive rounds
|
||||
* asserted this list was complete and both were refuted. Still NOT watched:
|
||||
* - `agents/subagents/**` (kimi stages `subagents/msd-executor.yaml` under an
|
||||
* UNPREFIXED intermediate dir, so no prefix scan of `agents/` reaches it);
|
||||
* - the loose capability generators copied to `<root>/scripts/*.cjs`
|
||||
* (`fix-slash-commands.cjs` is watched by name; the generators are not);
|
||||
* - `extensions/package.json` and `plugins/package.json` — CommonJS markers in
|
||||
* dirs MSD fills but does not own, so they fall under the shared-ground rule
|
||||
* below rather than being watched;
|
||||
* - the shared-hooks bundle in a NON-registry root's `<root>/hooks/` (kimi) —
|
||||
* - the shared-hooks bundle in a NON-registry root's `<root>/hooks/` —
|
||||
* see resolveExtraWatchTargets; closing it is a layout decision.
|
||||
* DELIBERATELY not watched, which is a different thing from missed: `hooks/lib`,
|
||||
* `hooks/package.json`, `scripts/lib` and `scripts/changeset`. The installer
|
||||
@@ -125,7 +123,7 @@ const NON_REGISTRY_ARTIFACT_PARENTS = ['hooks', 'plugins', 'scripts', 'extension
|
||||
/**
|
||||
* Prefixes used for a parent with no registry-declared one. BOTH forms are the
|
||||
* point: MSD writes `msd-`-hyphen artifacts (`hooks/msd-check-update.js`) AND
|
||||
* bare `msd.`-dotted ones (pi's `extensions/msd.js`), and a lone `msd-` sees
|
||||
* bare `msd.`-dotted ones (`plugins/msd.js`), and a lone `msd-` sees
|
||||
* only the first.
|
||||
*/
|
||||
const DEFAULT_ARTIFACT_PREFIXES = ['msd-', 'msd.'];
|
||||
@@ -176,13 +174,13 @@ function deriveArtifactTargets(runtimes) {
|
||||
const dest = layout?.destSubpath;
|
||||
if (typeof dest !== 'string' || !dest) continue;
|
||||
const last = dest.split('/').pop() || '';
|
||||
// A destination whose own final segment is MSD's (hermes' `skills/msd`) is
|
||||
// A destination whose own final segment is MSD's (`skills/msd`) is
|
||||
// owned wholesale — that directory is ours, not shared.
|
||||
if (last.startsWith('msd')) { owned.add(dest); continue; }
|
||||
// The layout declares its OWN prefix, and it varies: kimi's `kimi-agents`
|
||||
// layout declares `msd` (no hyphen) and writes `agents/msd.yaml` +
|
||||
// `agents/msd.md`, invisible to a fixed `msd-` scan. The same destSubpath
|
||||
// also carries different prefixes across runtimes, so a parent maps to a SET.
|
||||
// The layout declares its OWN prefix, and it may vary: a layout declaring
|
||||
// `msd` (no hyphen) would be invisible to a fixed `msd-` scan. The same
|
||||
// destSubpath also carries different prefixes across runtimes, so a
|
||||
// parent maps to a SET.
|
||||
const declared = typeof layout?.prefix === 'string' && layout.prefix
|
||||
? [layout.prefix]
|
||||
: DEFAULT_ARTIFACT_PREFIXES;
|
||||
@@ -214,12 +212,10 @@ function artifactTargets(deps = {}) {
|
||||
/**
|
||||
* The file MSD writes into a NON-REGISTRY config home.
|
||||
*
|
||||
* Both current descriptors are Kimi's — Kimi CLI's `~/.kimi` (KIMI_SHARE_DIR) and
|
||||
* Kimi Code's `~/.kimi-code` (KIMI_CODE_HOME) — and MSD writes its native
|
||||
* `[[hooks]]` block into `config.toml` in each, so the single filename below holds
|
||||
* for both. NAMED RESIDUAL: this assumes every non-registry descriptor is written
|
||||
* the same way. That assumption is now load-bearing rather than vacuous — it is
|
||||
* carrying two descriptors, not one — and a future descriptor whose owned file
|
||||
* NON_REGISTRY_CONFIG_HOME_DESCRIPTORS is empty today (its former entries were
|
||||
* native `config.toml` hook homes of since-retired runtimes), so this filename
|
||||
* is currently unused. NAMED RESIDUAL: this assumes every non-registry
|
||||
* descriptor is written the same way; a future descriptor whose owned file
|
||||
* differs needs a per-descriptor mapping here. The consequence of getting it wrong
|
||||
* is under-watching (a missed leak), not a false positive, so it fails in the quiet
|
||||
* direction and is called out rather than left to be discovered.
|
||||
@@ -339,8 +335,8 @@ function resolveLiveConfigRoots(deps = {}) {
|
||||
* #2665 round 3: resolveLiveConfigRoots enumerates getGlobalConfigDir per registry
|
||||
* runtime plus grok. A live write surface that is not a config ROOT is invisible to
|
||||
* that shape, so a leak on one passed through this guard — the PR's own safety net —
|
||||
* silently. There are THREE today ($MSD_HOME/.msd, plus one config.toml per entry in
|
||||
* NON_REGISTRY_CONFIG_HOME_DESCRIPTORS, which #2755 took from one entry to two):
|
||||
* silently. Today: $MSD_HOME/.msd, plus one config.toml per entry in
|
||||
* NON_REGISTRY_CONFIG_HOME_DESCRIPTORS (currently none):
|
||||
*
|
||||
* $MSD_HOME/.msd — MSD's user-owned store (consent.json, defaults.json, capability
|
||||
* overlays). Watched WHOLESALE: unlike ~/.claude this root is
|
||||
@@ -348,9 +344,8 @@ function resolveLiveConfigRoots(deps = {}) {
|
||||
* SCOPE above does not apply and an ownership filter would only
|
||||
* narrow the guard for nothing.
|
||||
* <non-registry home>/config.toml — the file MSD writes its native [[hooks]] block
|
||||
* into, one per NON_REGISTRY_CONFIG_HOME_DESCRIPTORS entry: Kimi
|
||||
* CLI's ~/.kimi (KIMI_SHARE_DIR) and, since #2755, Kimi Code's
|
||||
* ~/.kimi-code (KIMI_CODE_HOME). The INVERSE case: those roots
|
||||
* into, one per NON_REGISTRY_CONFIG_HOME_DESCRIPTORS entry
|
||||
* (none today). The INVERSE case: those roots
|
||||
* belong to their products, so the root is never watched
|
||||
* wholesale. This is the KNOWN GAP above accepted deliberately
|
||||
* in one direction — MSD demonstrably writes these files
|
||||
@@ -384,19 +379,18 @@ function resolveExtraWatchTargets(deps = {}) {
|
||||
resolveConfigHomeFromDescriptor,
|
||||
} = require(path.join(libDir, 'runtime-homes.cjs'));
|
||||
|
||||
// ITERATE the descriptor array rather than naming one resolver. Calling
|
||||
// resolveKimiHooksTomlDir directly would cover one of today's two entries and
|
||||
// silently miss tomorrow's — the same partial-enumeration defect that put
|
||||
// KIMI_SHARE_DIR outside the scrub set in the first place, reintroduced one
|
||||
// layer over. TEST_ENV_BASE derives its keys from this array; deriving the
|
||||
// guard's paths from it keeps the two halves from drifting apart.
|
||||
// ITERATE the descriptor array rather than naming one resolver — a
|
||||
// partial enumeration would silently miss a future entry. TEST_ENV_BASE
|
||||
// derives its keys from this array; deriving the guard's paths from it
|
||||
// keeps the two halves from drifting apart.
|
||||
//
|
||||
// Thread the SAME injected env/home used above: resolving bare would read
|
||||
// process.env and os.homedir() regardless of `deps`, leaving the seam
|
||||
// untestable and the targets resolved against different worlds.
|
||||
for (const descriptor of NON_REGISTRY_CONFIG_HOME_DESCRIPTORS) {
|
||||
// The fallback leg, per the note above: a child that blanks KIMI_SHARE_DIR /
|
||||
// KIMI_CODE_HOME writes to the HOME-derived root instead of the ambient one.
|
||||
// The fallback leg, per the note above: a child that blanks the
|
||||
// descriptor's env var writes to the HOME-derived root instead of the
|
||||
// ambient one.
|
||||
const fallbackDir = resolveConfigHomeFromDescriptor(descriptor, { env: {}, home: homedir() });
|
||||
if (typeof fallbackDir === 'string' && fallbackDir.length > 0) {
|
||||
targets.push(path.resolve(path.join(fallbackDir, NON_REGISTRY_OWNED_FILE)));
|
||||
@@ -405,12 +399,11 @@ function resolveExtraWatchTargets(deps = {}) {
|
||||
// The root belongs to the runtime, so it is never watched wholesale — only
|
||||
// the named file below.
|
||||
//
|
||||
// NAMED RESIDUAL (#2665, found pre-push while rebasing): config.toml is NOT
|
||||
// the only thing MSD writes here. bin/install.js also calls
|
||||
// installSharedHooksBundle(kimiHooksRoot), which populates <root>/hooks/
|
||||
// with MSD's hook scripts and a CommonJS marker. That subtree is UNWATCHED,
|
||||
// so a suite-produced leak of a hook bundle into a developer's real ~/.kimi
|
||||
// or ~/.kimi-code passes this guard silently. Closing it needs a layout
|
||||
// NAMED RESIDUAL (#2665, found pre-push while rebasing): config.toml may
|
||||
// NOT be the only thing MSD writes here — an installer may also populate
|
||||
// <root>/hooks/ with MSD's hook scripts and a CommonJS marker. That
|
||||
// subtree is UNWATCHED, so a suite-produced leak of a hook bundle into a
|
||||
// developer's real non-registry root passes this guard silently. Closing it needs a layout
|
||||
// decision, not one more path: the same reason getGlobalSkillsBase is a
|
||||
// deliberate non-target above. Under-watching fails quiet, like the
|
||||
// NON_REGISTRY_OWNED_FILE residual it sits beside.
|
||||
@@ -507,8 +500,8 @@ function snapshotLiveConfig(roots, extraTargets = [], limits = {}) {
|
||||
|
||||
for (const root of roots) {
|
||||
for (const entry of MSD_OWNED_ENTRIES) record(path.join(root, entry));
|
||||
// Paths whose own name is MSD's, nested inside a shared root (hermes'
|
||||
// `skills/msd`, `hooks/lib`, `scripts/lib`, …) — no prefix rule sees these.
|
||||
// Paths whose own name is MSD's, nested inside a shared root
|
||||
// (`skills/msd`, `hooks/lib`, `scripts/lib`, …) — no prefix rule sees these.
|
||||
for (const entry of watchOwned) record(path.join(root, ...entry.split('/')));
|
||||
|
||||
// Shared dirs: enumerate only msd-prefixed children. A child that appears
|
||||
|
||||
Reference in New Issue
Block a user