From c6ce4d1d9aabfb167d14a6762d50c56f67a785d1 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Mon, 3 Aug 2026 18:56:42 -0400 Subject: [PATCH] fix(#2755): resolve the kimi hooks-TOML root per runtime (#3032) * test(#2755): failing-first coverage for per-runtime kimi hooks root Install/uninstall filesystem-shape rows over a sandbox HOME (no permission tricks) plus resolver unit rows. Covers both uninstall directions, which is where a fix applied only to the install call site would drift. Co-Authored-By: Claude Opus 5 * fix(#2755): resolve the kimi hooks-TOML root per runtime resolveKimiHooksTomlDir took no runtime argument and hardcoded ~/.kimi, but both kimi and kimi-code route through the single hooksSurface=kimi-hooks-toml branch. A --kimi-code install therefore wrote its [[hooks]] block, hook bundle and CommonJS marker into Kimi CLI's config file, and a --kimi-code uninstall stripped Kimi CLI's block. Adds a runtime selector to the resolver -- kimi keeps ~/.kimi + KIMI_SHARE_DIR, kimi-code gets ~/.kimi-code + KIMI_CODE_HOME, per Kimi Code's own upstream data-locations and hooks docs -- and passes the runtime at both the install and uninstall call sites. An omitted or unrecognized runtime still resolves ~/.kimi, so the exported no-arg contract is unchanged. Co-Authored-By: Claude Opus 5 * test(#2755): use centralized helpers and add a divergence guard Review findings, all fixed in-PR: - The new test block reimplemented runMinimalInstall, createTempDir and toPosixPath. Extends runMinimalInstall with optional root/extraEnv instead (back-compat: every existing caller passes neither) and uses the centralized helpers, per CONTRIBUTING's Use Centralized Test Helpers rule. - Adds a parity assertion between the capability registry and the resolver: a third runtime declaring hooksSurface kimi-hooks-toml would silently inherit ~/.kimi, re-creating this very defect. The guard fires the moment those two surfaces drift. - Adds an installer-level test proving KIMI_SHARE_DIR and KIMI_CODE_HOME do not interfere when both are set, which only the resolver unit covered before. Co-Authored-By: Claude Opus 5 * test(#2755): track the kimi-code hooks root in the emitted-artifact gates The remote runner caught a real ripple: moving kimi-code hooks to ~/.kimi-code made 31 emitted paths unattributable and 58 emitted hashes unexplained, because three parallel surfaces keyed on the literal .kimi path. - HOOK_CONFIG_RELATIVE_PATHS excluded only .kimi/config.toml, so kimi-code's config.toml became manifest-visible; it embeds a platform-varying node-runner command and must stay out for both products. - HOOKS_ROOTS, the package.json-marker branch and the synthesized-install-metadata pattern each named .kimi only. - tests/fixtures/install-tree/kimi-code.json still recorded the old paths; regenerated via gen:install-tree. Adds the per-PR drift acknowledgment for the 58 paths whose bytes are unchanged but whose destination moved - a ripple no source diff can show, since no hook script was edited. Co-Authored-By: Claude Opus 5 * fix(#2755): clear production-tree security advisories The remote runner's npm-integrity gate reported 2 high advisories in the production dependency tree. My diff touches neither package.json nor package-lock.json, so these come from the base -- but a red gate is not something to wave off as pre-existing, so it is fixed here rather than deferred. Lockfile-only, semver-in-range, via npm audit fix: fast-uri 3.1.4 -> 3.1.5 (host confusion via backslash authority introducer) ip-address 10.2.0 -> 10.4.0 (three SSRF / trust-boundary bypasses) hono 4.12.31 -> 4.13.0 (moderate; reverting it traded a high for a moderate, so the full remedy is taken) npm audit now reports 0 vulnerabilities at every severity, npm ci installs clean from the updated lockfile, and the build and the kimi behavior both re-verified afterwards. Co-Authored-By: Claude Opus 5 * chore(#2755): backfill changeset pr numbers Co-Authored-By: Claude Opus 5 --------- Co-authored-by: Claude Opus 5 --- .changeset/mellow-pandas-rally.md | 5 + .changeset/sturdy-zebras-purr.md | 5 + bin/install.js | 12 +- .../host-integration-capability-matrix.md | 2 + package-lock.json | 18 +- src/runtime-homes.cts | 63 +++++-- .../2755-kimi-code-hooks-root.json | 63 +++++++ tests/fixtures/install-tree/kimi-code.json | 60 +++---- tests/helpers/emitted-provenance.cjs | 17 +- tests/helpers/install-shared.cjs | 22 ++- tests/kimi-upgrades.test.cjs | 165 +++++++++++++++++- tests/runtime-homes-descriptor-drive.test.cjs | 93 ++++++++++ 12 files changed, 451 insertions(+), 74 deletions(-) create mode 100644 .changeset/mellow-pandas-rally.md create mode 100644 .changeset/sturdy-zebras-purr.md create mode 100644 tests/emitted-drift-acks/2755-kimi-code-hooks-root.json diff --git a/.changeset/mellow-pandas-rally.md b/.changeset/mellow-pandas-rally.md new file mode 100644 index 000000000..303932cce --- /dev/null +++ b/.changeset/mellow-pandas-rally.md @@ -0,0 +1,5 @@ +--- +type: Security +pr: 3032 +--- +**Production dependency tree is clear of known advisories** — three transitive packages reached by `@anthropic-ai/claude-agent-sdk` carried published advisories: `fast-uri` (host confusion via a backslash authority introducer), `ip-address` (three SSRF / trust-boundary bypasses via leading-zero octets, CIDR-suffix suppression, and IPv4-mapped address misclassification), and `hono`. All three are lockfile-only, semver-in-range updates. (#2755) diff --git a/.changeset/sturdy-zebras-purr.md b/.changeset/sturdy-zebras-purr.md new file mode 100644 index 000000000..0c51a0155 --- /dev/null +++ b/.changeset/sturdy-zebras-purr.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 3032 +--- +**A `--kimi-code` install now configures hooks in Kimi Code, not Kimi CLI** — installing GSD for Kimi Code wrote its lifecycle hooks, hook bundle and CommonJS marker into Kimi CLI's `~/.kimi/config.toml`, so Kimi Code itself received no hooks at all and a machine with only Kimi Code got a config file no product reads. Each Kimi product now uses its own root and its own environment override (`KIMI_SHARE_DIR` for Kimi CLI, `KIMI_CODE_HOME` for Kimi Code), and uninstalling one no longer removes the other's hooks. (#2755) diff --git a/bin/install.js b/bin/install.js index eaee3797c..652672ef1 100755 --- a/bin/install.js +++ b/bin/install.js @@ -8082,11 +8082,12 @@ function uninstall(isGlobal, runtime = DEFAULT_RUNTIME) { // 1a-kimi. Non-layout Kimi side-effect (#2095 EoS/kimi Upgrade 1): kimi's // native config.toml lives outside targetDir entirely (resolveKimiHooksTomlDir - // resolves ~/.kimi, a sibling of targetDir's ~/.config/agents), so its + // resolves ~/.kimi for kimi and ~/.kimi-code for kimi-code (#2755), a sibling + // of targetDir's ~/.config/agents), so its // cleanup can't be driven by anything under targetDir the way every other // hook surface above is. if (resolveInstallPlan(runtime).hooksSurface === 'kimi-hooks-toml') { - const kimiHooksRoot = resolveKimiHooksTomlDir(); + const kimiHooksRoot = resolveKimiHooksTomlDir({ runtime }); const kimiHooksTomlPath = path.join(kimiHooksRoot, 'config.toml'); const kimiHooksCleanup = removeKimiHooksToml(kimiHooksTomlPath); if (kimiHooksCleanup.changed) { @@ -11924,7 +11925,8 @@ function install(isGlobal, runtime = DEFAULT_RUNTIME, options = {}) { // hooks needed. Kimi is also artifact-only for its INSTALL surface (skills + // kimi-agents, no settings.json) but #2095 Upgrade 1 gives it its own // independent hooksSurface: kimi's native config.toml [[hooks]] array, which - // lives outside targetDir entirely (resolveKimiHooksTomlDir resolves ~/.kimi, + // lives outside targetDir entirely (resolveKimiHooksTomlDir resolves the + // per-runtime root — ~/.kimi for kimi, ~/.kimi-code for kimi-code, #2755 — // a sibling of targetDir's ~/.config/agents) — hence writing it here, inside // this early-return, rather than requiring installSurface to change. // @@ -11945,7 +11947,7 @@ function install(isGlobal, runtime = DEFAULT_RUNTIME, options = {}) { // ~/.kimi/hooks/