kimi-plugin-cc 2.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/.claude-plugin/marketplace.json +16 -0
  3. package/.claude-plugin/plugin.json +32 -0
  4. package/CHANGELOG.md +1096 -0
  5. package/LICENSE +201 -0
  6. package/README.md +772 -0
  7. package/agents/kimi-ask.md +82 -0
  8. package/agents/kimi-challenge.md +82 -0
  9. package/agents/kimi-pursue.md +91 -0
  10. package/agents/kimi-rescue.md +85 -0
  11. package/agents/kimi-review.md +82 -0
  12. package/agents/kimi-swarm-write.md +92 -0
  13. package/agents/kimi-swarm.md +83 -0
  14. package/commands/README.md +16 -0
  15. package/commands/ask.md +32 -0
  16. package/commands/cancel.md +17 -0
  17. package/commands/challenge.md +29 -0
  18. package/commands/pursue.md +37 -0
  19. package/commands/replay.md +13 -0
  20. package/commands/rescue.md +32 -0
  21. package/commands/result.md +13 -0
  22. package/commands/review.md +29 -0
  23. package/commands/setup.md +23 -0
  24. package/commands/status.md +13 -0
  25. package/commands/swarm.md +38 -0
  26. package/dist/background-spawn.js +224 -0
  27. package/dist/cli-cancellation.js +43 -0
  28. package/dist/cli-client.js +845 -0
  29. package/dist/commands/ask.js +327 -0
  30. package/dist/commands/cancel.js +178 -0
  31. package/dist/commands/cli-helpers.js +112 -0
  32. package/dist/commands/models.js +140 -0
  33. package/dist/commands/not-implemented.js +4 -0
  34. package/dist/commands/pursue.js +311 -0
  35. package/dist/commands/registry.js +87 -0
  36. package/dist/commands/repair-sessions.js +159 -0
  37. package/dist/commands/replay.js +123 -0
  38. package/dist/commands/rescue.js +333 -0
  39. package/dist/commands/result.js +58 -0
  40. package/dist/commands/review-gate.js +393 -0
  41. package/dist/commands/review.js +218 -0
  42. package/dist/commands/setup.js +1132 -0
  43. package/dist/commands/status.js +27 -0
  44. package/dist/commands/swarm.js +576 -0
  45. package/dist/commands/worker.js +31 -0
  46. package/dist/companion.js +114 -0
  47. package/dist/config.js +22 -0
  48. package/dist/errors.js +40 -0
  49. package/dist/git.js +215 -0
  50. package/dist/hooks/approval-hook.js +112 -0
  51. package/dist/hooks/approval-policy.js +254 -0
  52. package/dist/hooks/config-safety.js +637 -0
  53. package/dist/hooks/install-paths.js +504 -0
  54. package/dist/hooks/install.js +281 -0
  55. package/dist/hooks/managed-block.js +745 -0
  56. package/dist/hooks/review-gate-stop.js +19 -0
  57. package/dist/job-store.js +559 -0
  58. package/dist/jobs.js +202 -0
  59. package/dist/kimi-command.js +72 -0
  60. package/dist/kimi-engine.js +624 -0
  61. package/dist/kimi-errors.js +220 -0
  62. package/dist/kimi-home.js +9 -0
  63. package/dist/kimi-timeouts.js +68 -0
  64. package/dist/kimi-version-probe.js +1410 -0
  65. package/dist/logging.js +22 -0
  66. package/dist/native-v2-preflight.js +417 -0
  67. package/dist/package.json +1 -0
  68. package/dist/parsing.js +553 -0
  69. package/dist/paths.js +27 -0
  70. package/dist/plugin-data.js +98 -0
  71. package/dist/process-tree.js +448 -0
  72. package/dist/render.js +159 -0
  73. package/dist/rescue-approval.js +951 -0
  74. package/dist/schemas/review-gate-output.js +43 -0
  75. package/dist/session-title.js +293 -0
  76. package/dist/stream-json.js +498 -0
  77. package/dist/types.js +1 -0
  78. package/dist/vendor/shell-quote/LICENSE +24 -0
  79. package/dist/vendor/shell-quote/index.js +1 -0
  80. package/dist/vendor/shell-quote/parse.js +229 -0
  81. package/dist/vendor/smol-toml/LICENSE +24 -0
  82. package/dist/vendor/smol-toml/date.js +127 -0
  83. package/dist/vendor/smol-toml/error.js +63 -0
  84. package/dist/vendor/smol-toml/extract.js +100 -0
  85. package/dist/vendor/smol-toml/parse.js +148 -0
  86. package/dist/vendor/smol-toml/primitive.js +179 -0
  87. package/dist/vendor/smol-toml/struct.js +184 -0
  88. package/dist/vendor/smol-toml/util.js +113 -0
  89. package/dist/version.js +7 -0
  90. package/docs/migration.md +215 -0
  91. package/docs/models.md +82 -0
  92. package/docs/registry-releases.md +70 -0
  93. package/docs/safety.md +318 -0
  94. package/docs/session-visibility.md +32 -0
  95. package/hooks/README.md +9 -0
  96. package/hooks/hooks.json +16 -0
  97. package/package.json +67 -0
  98. package/plugins/kimi-codex/.codex-plugin/plugin.json +39 -0
  99. package/plugins/kimi-codex/dist/background-spawn.js +224 -0
  100. package/plugins/kimi-codex/dist/cli-cancellation.js +43 -0
  101. package/plugins/kimi-codex/dist/cli-client.js +845 -0
  102. package/plugins/kimi-codex/dist/commands/ask.js +327 -0
  103. package/plugins/kimi-codex/dist/commands/cancel.js +178 -0
  104. package/plugins/kimi-codex/dist/commands/cli-helpers.js +112 -0
  105. package/plugins/kimi-codex/dist/commands/models.js +140 -0
  106. package/plugins/kimi-codex/dist/commands/not-implemented.js +4 -0
  107. package/plugins/kimi-codex/dist/commands/pursue.js +311 -0
  108. package/plugins/kimi-codex/dist/commands/registry.js +87 -0
  109. package/plugins/kimi-codex/dist/commands/repair-sessions.js +159 -0
  110. package/plugins/kimi-codex/dist/commands/replay.js +123 -0
  111. package/plugins/kimi-codex/dist/commands/rescue.js +333 -0
  112. package/plugins/kimi-codex/dist/commands/result.js +58 -0
  113. package/plugins/kimi-codex/dist/commands/review-gate.js +393 -0
  114. package/plugins/kimi-codex/dist/commands/review.js +218 -0
  115. package/plugins/kimi-codex/dist/commands/setup.js +1132 -0
  116. package/plugins/kimi-codex/dist/commands/status.js +27 -0
  117. package/plugins/kimi-codex/dist/commands/swarm.js +576 -0
  118. package/plugins/kimi-codex/dist/commands/worker.js +31 -0
  119. package/plugins/kimi-codex/dist/companion.js +114 -0
  120. package/plugins/kimi-codex/dist/config.js +22 -0
  121. package/plugins/kimi-codex/dist/errors.js +40 -0
  122. package/plugins/kimi-codex/dist/git.js +215 -0
  123. package/plugins/kimi-codex/dist/hooks/approval-hook.js +112 -0
  124. package/plugins/kimi-codex/dist/hooks/approval-policy.js +254 -0
  125. package/plugins/kimi-codex/dist/hooks/config-safety.js +637 -0
  126. package/plugins/kimi-codex/dist/hooks/install-paths.js +504 -0
  127. package/plugins/kimi-codex/dist/hooks/install.js +281 -0
  128. package/plugins/kimi-codex/dist/hooks/managed-block.js +745 -0
  129. package/plugins/kimi-codex/dist/hooks/review-gate-stop.js +19 -0
  130. package/plugins/kimi-codex/dist/job-store.js +559 -0
  131. package/plugins/kimi-codex/dist/jobs.js +202 -0
  132. package/plugins/kimi-codex/dist/kimi-command.js +72 -0
  133. package/plugins/kimi-codex/dist/kimi-engine.js +624 -0
  134. package/plugins/kimi-codex/dist/kimi-errors.js +220 -0
  135. package/plugins/kimi-codex/dist/kimi-home.js +9 -0
  136. package/plugins/kimi-codex/dist/kimi-timeouts.js +68 -0
  137. package/plugins/kimi-codex/dist/kimi-version-probe.js +1410 -0
  138. package/plugins/kimi-codex/dist/logging.js +22 -0
  139. package/plugins/kimi-codex/dist/native-v2-preflight.js +417 -0
  140. package/plugins/kimi-codex/dist/package.json +1 -0
  141. package/plugins/kimi-codex/dist/parsing.js +553 -0
  142. package/plugins/kimi-codex/dist/paths.js +27 -0
  143. package/plugins/kimi-codex/dist/plugin-data.js +98 -0
  144. package/plugins/kimi-codex/dist/process-tree.js +448 -0
  145. package/plugins/kimi-codex/dist/render.js +159 -0
  146. package/plugins/kimi-codex/dist/rescue-approval.js +951 -0
  147. package/plugins/kimi-codex/dist/schemas/review-gate-output.js +43 -0
  148. package/plugins/kimi-codex/dist/session-title.js +293 -0
  149. package/plugins/kimi-codex/dist/stream-json.js +498 -0
  150. package/plugins/kimi-codex/dist/types.js +1 -0
  151. package/plugins/kimi-codex/dist/vendor/shell-quote/LICENSE +24 -0
  152. package/plugins/kimi-codex/dist/vendor/shell-quote/index.js +1 -0
  153. package/plugins/kimi-codex/dist/vendor/shell-quote/parse.js +229 -0
  154. package/plugins/kimi-codex/dist/vendor/smol-toml/LICENSE +24 -0
  155. package/plugins/kimi-codex/dist/vendor/smol-toml/date.js +127 -0
  156. package/plugins/kimi-codex/dist/vendor/smol-toml/error.js +63 -0
  157. package/plugins/kimi-codex/dist/vendor/smol-toml/extract.js +100 -0
  158. package/plugins/kimi-codex/dist/vendor/smol-toml/parse.js +148 -0
  159. package/plugins/kimi-codex/dist/vendor/smol-toml/primitive.js +179 -0
  160. package/plugins/kimi-codex/dist/vendor/smol-toml/struct.js +184 -0
  161. package/plugins/kimi-codex/dist/vendor/smol-toml/util.js +113 -0
  162. package/plugins/kimi-codex/dist/version.js +7 -0
  163. package/plugins/kimi-codex/scripts/companion.sh +37 -0
  164. package/plugins/kimi-codex/scripts/review-gate-hook.sh +32 -0
  165. package/plugins/kimi-codex/skills/kimi-ask/SKILL.md +31 -0
  166. package/plugins/kimi-codex/skills/kimi-ask/agents/openai.yaml +6 -0
  167. package/plugins/kimi-codex/skills/kimi-cancel/SKILL.md +25 -0
  168. package/plugins/kimi-codex/skills/kimi-cancel/agents/openai.yaml +6 -0
  169. package/plugins/kimi-codex/skills/kimi-challenge/SKILL.md +31 -0
  170. package/plugins/kimi-codex/skills/kimi-challenge/agents/openai.yaml +6 -0
  171. package/plugins/kimi-codex/skills/kimi-pursue/SKILL.md +30 -0
  172. package/plugins/kimi-codex/skills/kimi-pursue/agents/openai.yaml +6 -0
  173. package/plugins/kimi-codex/skills/kimi-replay/SKILL.md +25 -0
  174. package/plugins/kimi-codex/skills/kimi-replay/agents/openai.yaml +6 -0
  175. package/plugins/kimi-codex/skills/kimi-rescue/SKILL.md +30 -0
  176. package/plugins/kimi-codex/skills/kimi-rescue/agents/openai.yaml +6 -0
  177. package/plugins/kimi-codex/skills/kimi-result/SKILL.md +25 -0
  178. package/plugins/kimi-codex/skills/kimi-result/agents/openai.yaml +6 -0
  179. package/plugins/kimi-codex/skills/kimi-review/SKILL.md +31 -0
  180. package/plugins/kimi-codex/skills/kimi-review/agents/openai.yaml +6 -0
  181. package/plugins/kimi-codex/skills/kimi-setup/SKILL.md +32 -0
  182. package/plugins/kimi-codex/skills/kimi-setup/agents/openai.yaml +6 -0
  183. package/plugins/kimi-codex/skills/kimi-status/SKILL.md +25 -0
  184. package/plugins/kimi-codex/skills/kimi-status/agents/openai.yaml +6 -0
  185. package/plugins/kimi-codex/skills/kimi-swarm/SKILL.md +31 -0
  186. package/plugins/kimi-codex/skills/kimi-swarm/agents/openai.yaml +6 -0
  187. package/plugins/kimi-codex/skills/kimi-swarm-write/SKILL.md +32 -0
  188. package/plugins/kimi-codex/skills/kimi-swarm-write/agents/openai.yaml +6 -0
  189. package/scripts/companion.sh +37 -0
  190. package/scripts/review-gate-hook.sh +32 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,1096 @@
1
+ # Changelog
2
+
3
+ > **Post-1.0 release history (v1.0.1 -> present) lives in [ROADMAP-TO-GA.md § Post-GA audit log](./ROADMAP-TO-GA.md#post-ga-audit-log)** and the "Version" / "Upstream compat" lines of [AGENTS.md](./AGENTS.md). Docs-only kimi-code compat checkups that don't bump the plugin version (e.g. the 0.14.2 / 0.14.3 patches) are recorded there, not here. Notable releases are summarized below; the GA entry and full pre-GA detail follow.
4
+
5
+ ## 2.0.7 — 2026-09-26
6
+
7
+ - Add npm distribution as `kimi-plugin-cc`, with an explicit file allowlist and
8
+ compiled runtime for both Claude Code and Codex. No install scripts or build
9
+ tools run on the user's machine; the existing GitHub marketplaces still work.
10
+ - Verify the actual tarball after extraction: both host setup/check probes must
11
+ enforce the hook in isolated homes, and both distributions must refuse an
12
+ unsupported CLI version. No credentials or model calls are used by this check.
13
+ - Add tag-verified GitHub Actions publishing with npm Trusted Publishing and
14
+ document the first-publish bootstrap and registry installation path.
15
+ - Runtime behavior and exact upstream certification remain unchanged from 2.0.6.
16
+
17
+ ## 2.0.6 — 2026-09-24
18
+
19
+ - Certify exact Kimi Code CLI 2.1.0 and 2.1.1 for all eight native-v2 operations under the no-plan construction. Previous certified versions remain supported; legacy-v1 stays capped at 0.41.x.
20
+ - Review both exact hook schemas and pin their source hashes. Unreviewed versions, prereleases and build suffixes remain refused. Update the recommended CLI and manual smoke default to 2.1.1.
21
+ - Verify each candidate independently with a 15-test tag scan, plan-ON/OFF controls and the complete sequential live smoke. The active-plan bypass remains, so managed sessions continue to refuse plan mode.
22
+ - Document trusted repository Git configuration: internal explorer Git commands can execute helpers outside tool hooks, including read-only swarm. 2.1.1 rolls back much of 2.1.0's path/Git hardening to the certified 2.0.2 baseline.
23
+ - See [certification evidence and validation](docs/upstream-2.1-certification.md). Publication does not update installed hosts or the operator CLI.
24
+
25
+ ## 2.0.5 — 2026-09-20
26
+
27
+ - Fix lockfile-clean TypeScript 7.0.2 emission for `repair-sessions` by binding SQLite constructors before `new`. Preserve read-only database access and preview behavior.
28
+ - Add four compiled-runtime regressions: root and Codex distributions each run under Node and Bun against a real fixture database. All four failed before the fix and passed afterward; all 14 repair-session tests pass.
29
+ - Frozen-dependency full check: 902 passed, 28 opt-in skips, zero failures, 3,015 assertions. Dependency audit and both final reviews passed.
30
+ - Rebuild both hosts with frozen dependencies. Require a successful CI check before tagging and publishing future releases. v2.0.4's local check used stale TypeScript 6.0.2 dependencies and missed the emitted-code failure; its published tag remains unchanged.
31
+ - Exact CLI certification stays through 2.0.2. No hook, plan-mode, permission, swarm or installed-host changes. See [build-fix evidence](docs/release-2.0.5-build-fix.md).
32
+
33
+ ## 2.0.4 — 2026-09-20
34
+
35
+ - Certify exact Kimi Code CLI 2.0.2 for all eight native-v2 operations under the unchanged no-plan safety construction. Previous certified versions remain supported; legacy-v1 stays capped at 0.41.x.
36
+ - Accept only the reviewed exact 2.0.2 hook schema and pin its source hashes. Future versions, prereleases and build suffixes remain refused.
37
+ - Verification: four source reviews, exact tag scan 15/15, plan-ON/OFF controls and sequential live smoke 15/15 (84 assertions), with no retries. The known upstream plan-file bypass persists; managed sessions still refuse plan mode. See [certification evidence and limitations](docs/upstream-2.0.2-certification.md).
38
+ - Final `bun run check`: 898 passed, 28 opt-in skips, zero failures, 2,987 assertions on an identical staged-tree snapshot in a clean temporary worktree. The original checkout hit filesystem-copy timeouts; no test limits or assertions were relaxed.
39
+ - Plugin 2.0.4 and upstream CLI 2.0.2 are independent version numbers. This release does not update installed hosts or re-pin their hooks.
40
+
41
+ ## 2.0.3 — 2026-09-19
42
+
43
+ - Certify exact Kimi Code CLI 2.0.1 for all eight native-v2 operations. Review and pin its same-wire restore-chain API and unchanged hook schema; future patches remain fail-closed. Exact tag scan 15/15, plan-on/off controls passed, live smoke 15/15 with no retries. See [certification evidence](docs/upstream-2.0.1-certification.md).
44
+ - Fix repeated pursue goal-tool denials: trusted per-spawn operation metadata permits only current-goal reads and terminal complete/blocked updates. Rescue workspace restrictions, plan refusal and wall-clock limits remain unchanged. Remove the misleading SetGoalBudget prompt hint; turn counts remain soft.
45
+ - Validation: `bun run check` passed (898 passed, 28 opt-in skips, zero failures, 2,965 assertions).
46
+ - Keep plugin versions independent of upstream using ordinary SemVer. Plugin 2.0.3 certifies CLI 2.0.1; published versions are never reused.
47
+ - Older coexisting host hooks can still veto goal tools. Updating and re-pinning each host requires its own authorization; no installed Claude Code hook was changed in this slice.
48
+
49
+
50
+ ## 2.0.2 — 2026-09-18
51
+
52
+ Plugin-only maintenance release. Kimi Code CLI certification remains unchanged through exact 2.0.0; this does not certify upstream 2.0.1 or 2.0.2.
53
+
54
+ - Restore visibility of completed native-v2 plugin sessions in Kimi Code Desktop and Web by filling missing redacted prompt previews and notifying the shared session index.
55
+ - Keep new fallback titles replaceable by Kimi's native generation. Preserve manual and already-generated titles. The plugin does not call the native title endpoint automatically because it resumes an agent; use Desktop's Gen Title action or continue an eligible session there.
56
+ - Add `repair-sessions [--apply] [--all]`: preview existing-session repairs by default, recover prompts from bounded invocation logs with digest and provenance checks, and preserve titles, existing previews and session journals.
57
+ - Redact fallback-title source text before truncation and detect changed state before atomic publication. Report index-notification failures separately so an idempotent repair can retry them.
58
+ - Validation: full `bun run check` passes with 881 tests, 26 opt-in skips, and no failures. Ten local sessions were repaired and became visible after Desktop refresh. One native generated title and its transcript were verified after refresh. Separate Web browser rendering was not exercised.
59
+
60
+ See [session visibility and titles](./docs/session-visibility.md). Update Codex or Claude Code independently, then run that host's setup command to re-pin its versioned hook.
61
+
62
+ ## 2.0.1 — 2026-09-17
63
+
64
+ Plugin-only maintenance release. The recommended certified Kimi Code CLI remains 2.0.0; the exact certification table is unchanged.
65
+
66
+ - Harden plugin data-root selection against shared host environment pollution (#13). Standard cache installs verify ownership, custom locations can use `KIMI_PLUGIN_CC_DATA`, and conflicts fail before store access. Existing state is not moved. Background workers keep the selected root; the Stop hook reports a visible skip on conflicts.
67
+ - Handle first-run symlinked homes before data directories exist, and require an explicit data root for fully sanitized launches without a home instead of using a shared `/tmp` fallback.
68
+ - Refresh the README with English, Chinese, French, and Japanese onboarding and screenshots from both hosts. Update safety, migration, contributor, test, and CI documentation. Correct reasoning-setting guidance and default the manual smoke workflow to CLI 2.0.0.
69
+ - Validation: `bun run check` passes with 861 tests, 26 opt-in skips, and no failures. No real-provider calls are needed for this data-routing change.
70
+
71
+ After updating, run the setup command from each updated host to re-pin its hook. If `PLUGIN_DATA_CONFLICT` is reported, follow its expected-directory remedy or deliberately set the absolute `KIMI_PLUGIN_CC_DATA` parent for your existing custom store. No data is migrated automatically.
72
+
73
+ ## 2.0.0 — 2026-09-17
74
+
75
+ **Certifies exact kimi-code 2.0.0 for native agent-core-v2 across all eight
76
+ operations.** Starting here, plugin certification releases use the same
77
+ version number as the upstream release they certify. Previous exact native-v2
78
+ versions remain supported; the legacy table stays capped at 0.41.x.
79
+
80
+ Setup now accepts PermissionRequest, PermissionResult and Interrupt on the
81
+ reviewed exact 2.0.0 schema. Future patches/minors, prereleases and other
82
+ nonzero versions remain refused for those events. Hook policy, workspace
83
+ allowlist and no-plan preflight behavior are unchanged.
84
+
85
+ Model selection now includes a credential-safe offline inventory through
86
+ `setup --models [--json]`, native subscription/API-provider setup guidance, and
87
+ model-choice instructions for both Claude and Codex. Fresh tasks use the default;
88
+ named requests resolve configured aliases without a silent fallback. The review
89
+ gate now follows the default unless its model override is set. See
90
+ [models and provider setup](./docs/models.md).
91
+
92
+ Evidence:
93
+
94
+ - Exact source `1b89e4b0`: tag scan 15/15, including new hook-schema pins.
95
+ The wire flush now drains the same agent journal directly; swarm eviction
96
+ and rebuild retain normal lifecycle creation and eager child hooks.
97
+ - Plan-ON reproduced the known bypass (769-byte plan, hook saw Glob only);
98
+ plan-OFF denied both Write and EnterPlanMode without creating files.
99
+ - Full candidate smoke: 12 passed, one failed its fan-out precondition (no
100
+ AgentSwarm call, no escape files). After clarifying that the paths are
101
+ authorized disposable negative-test fixtures, a targeted retry passed with
102
+ the original assertions and a surfaced hook-denial reason. All 13 cases
103
+ are covered by the full run plus that retry; this was not a clean single run.
104
+ - Goal mode: five turns over the two-minute budget, zero writes. Write-swarm:
105
+ 278-byte patch, user tree clean, worktree removed. Resume/taint lanes passed.
106
+ - Final `bun run check` after model-selection additions: 847 pass / 26 skip / 0 fail; build, typecheck,
107
+ generated surfaces and drift gate passed. Fake-credential fixtures cover
108
+ secret-free inventory/errors, no writes, environment defaults, explicit
109
+ aliases and resume, and default/override review-gate argv. Both compiled
110
+ host entrypoints passed an offline fixture without provider calls.
111
+ - An authorized live Moonshot K3 API test completed through an explicit
112
+ configured alias; the saved subscription default remained unchanged.
113
+
114
+ The smoke harness can select an exact audited v2 candidate before production
115
+ certification, with an exact-binary mismatch refusal and a test-process-only
116
+ write-swarm capability row. Temporary config/OAuth copies were explicitly
117
+ authorized for this run and removed afterward. After upgrading either host,
118
+ run its setup command to refresh the version-stamped hook path.
119
+
120
+ ## 1.10.3 — 2026-09-15
121
+
122
+ **Certifies kimi-code 0.43.0 and 0.43.1 for native agent-core-v2 (all eight
123
+ operations).** kimi-code published 0.43.0 on 2026-09-14 and 0.43.1 on
124
+ 2026-09-15; the operator's binary auto-upgraded to 0.43.1 the same morning, so
125
+ every model-spawning command on an auto-updating host had started refusing with
126
+ `KIMI_CAPABILITY_NOT_CERTIFIED`. `NATIVE_V2_CERTIFIED_VERSIONS` is now
127
+ `0.42.0, 0.43.0, 0.43.1`. No approval-policy, allowlist, hook, preflight or
128
+ engine-selection change.
129
+
130
+ Certification evidence (per docs/upstream-compat-audit.md, all three gates, per
131
+ exact version):
132
+
133
+ - **Tag scan** (`tests/audit/v2-tag-scan.test.ts`): 15/15 on the exact 0.43.0
134
+ and 0.43.1 source trees (and still 15/15 on 0.42.0). New hash rows for both
135
+ versions; the seven load-bearing files are byte-identical between 0.43.0 and
136
+ 0.43.1, and five of them are byte-identical to 0.42.0. The two that changed
137
+ are upstream's restore refactor (`state/eventDispatcherService.ts`,
138
+ `state/state.ts`): patch-history undo replaced by in-memory state snapshots,
139
+ and `restore()` now folds `wire.readRestorable()` before `wire.readJournal()`.
140
+ `readRestorable()` is `readStableEntries()` over the same `wire.jsonl`
141
+ append-log filtered by the pure `restorableChain()` (`wire/tree/fork.ts`) —
142
+ no second on-disk restore source — so the resume taint scan's premise holds.
143
+ The "restore folds only the wire journal" check now also asserts that every
144
+ `this.wire.read*()` call in the dispatcher is `readJournal`/`readRestorable`,
145
+ that every append-log read in the wire service names `AGENT_WIRE_RECORD_KEY`
146
+ (`'wire.jsonl'`), and that `restorableChain` takes only the entries it is
147
+ handed.
148
+ - **Live controls on both exact binaries**: plan-ON (`default_plan_mode = true`,
149
+ deny-all hook) still shows the upstream bypass — one `system.version`, plan
150
+ file written, the hook saw `Glob` only — so the plugin's refusal remains
151
+ load-bearing (#3431 unchanged). Plan-OFF (new `repro-clean.ts`): an ordinary
152
+ `Write` and an `EnterPlanMode` attempt both reached the hook and were denied;
153
+ no file, no plan file.
154
+ - **Real-binary smoke** (`bun run smoke:real`): 13 pass / 0 fail / 0 skip on the operator's installed **0.43.1** (312 s) and on a temp-installed exact **0.43.0** via `KIMI_PLUGIN_CC_KIMI_BIN` (285 s) — every native-v2 lane: all read-only labels hook-denied, the goal-mode run wrote zero files across the budget (0.43.1: `turnsUsed:8`, paused on the plugin abort; 0.43.0: `turnsUsed:10`), default-plan preflight and resume/taint lanes, swarm subagent write denied, and write-swarm confined to its worktree with a captured patch (0.43.1: `patchBytes=278 userTreeClean=true worktreeCleaned=true`; 0.43.0: `patchBytes=278 userTreeClean=true worktreeCleaned=true`).
155
+
156
+ Also read for this release: the 0.42.0→0.43.1 diffs of `run-v2-print.ts`
157
+ (prompt submission moved from `IAgentPromptService.enqueue()` to
158
+ `IAgentLoopService.submit()`; no argv or provenance change), the before-execute
159
+ subscriber set (unchanged eight; sole `.allow()` still `planService.ts:110`),
160
+ the experimental flag set (`KIMI_CODE_EXPERIMENTAL_AUTO_SESSION_TITLE` removed,
161
+ nothing added; `tower`/`subagent_fork` refusals unchanged), and the
162
+ `[secondary_model]` subagent validation added in 0.43.1 (config diagnostics
163
+ only), and the 0.43.0→0.43.1 `_base/di/**` diff (`cascadeEngine`,
164
+ `dependencyGraph`, `instantiationService`, `scopeUnits`): disposal-path cleanup
165
+ only (`dropScope`/`removeScope`/`deleteScope`, ledger release on retract,
166
+ `.sort()`→`.toSorted()`) — no change to service resolution, child-scope
167
+ creation or singleton-vs-scoped wiring, so the "every `AgentSwarm` subagent has
168
+ its own eager external-hooks service" claim stands (Codex release review).
169
+ Upstream removed its 24-hour goal limit; the plugin's mandatory finite
170
+ `--budget` is unaffected.
171
+
172
+ Test fix: `tests/runtime/shell-quote-linear.test.ts` (1.10.2) asserted an empty
173
+ stderr from a `node --import tsx` subprocess; Node 26.8 prints a `DEP0205`
174
+ deprecation warning for tsx's `module.register()`, failing all three lanes on
175
+ an unmodified checkout. The test now strips only that warning pair from stderr
176
+ before asserting it is empty, so any other stderr output still trips it.
177
+
178
+ Docs: `AGENTS.md` trimmed from 43.6 KB to 23.6 KB (Kimi flagged it above the
179
+ 32 KB instruction-file guidance; every host loads it each turn). It is now the
180
+ contract sheet — one present-tense statement per invariant plus a pointer —
181
+ and the full mechanics/rationale moved verbatim to the new `docs/invariants.md`.
182
+ `CLAUDE.md` stays an `@AGENTS.md` import (single source, nothing to mirror).
183
+
184
+ Release reviews (Codex via its plugin; Kimi via the 1.10.3 runtime against the
185
+ installed hook pin): both approve. Kimi's two low findings are closed in this
186
+ release — the tag scan now (a) pins `wire/wireService.ts`, `wire/record.ts` and
187
+ `wire/tree/fork.ts` so the `readRestorable` regex assertions cannot degrade
188
+ silently, with an explicit body-delimiter check, and (b) asserts that no
189
+ `wire/migration/*` source references the plan domain, because migrations run on
190
+ each journal line BEFORE restore folds by type while the plugin's taint scan
191
+ reads the raw line (no such migration exists at 0.42.0–0.43.1; this closes the
192
+ vector for future tags).
193
+
194
+ Operational notes: run live controls and smokes sequentially — two isolated
195
+ homes refreshing a copy of the managed OAuth grant concurrently invalidated the
196
+ operator's token (remedy `kimi login`). Update the plugin through its
197
+ marketplace and run `/kimi:setup` (Claude Code) or `$kimi-setup` (Codex) to
198
+ activate; publishing does not update existing host caches or hook pins.
199
+
200
+ ## 1.10.2 — 2026-09-14
201
+
202
+ **Security patch: bounded parser work during hook validation.** Vendored TOML
203
+ parsing now rejects unfinished arrays or inline tables ending in a comment
204
+ without a newline, instead of looping indefinitely (GHSA-7w5x-hrqm-74c2).
205
+ Vendored shell parsing finalizes tokens in linear time, including callback
206
+ environments, instead of repeatedly copying growing arrays
207
+ (GHSA-395f-4hp3-45gv). Both complete upstream fixes are backported into the
208
+ existing parser versions and included in the Claude and Codex distributions;
209
+ provenance is recorded beside each vendored parser.
210
+
211
+ Development dependencies, Bun, and GitHub Actions are current. Grouped weekly
212
+ Dependabot checks and CI dependency auditing cover the manifest and lockfile;
213
+ vendor-specific regression tests cover the shipped source that package audits
214
+ cannot inspect. A swarm test fixture now supplies its own executable stub so
215
+ CI does not require an installed Kimi binary.
216
+
217
+ No UI, approval-policy, engine-selection, or certification changes. Exact
218
+ native-v2 certification remains kimi-code **0.42.0**. Validation: frozen install,
219
+ zero dependency audit findings, generated-surface/distribution checks, and the
220
+ full local suite (832 pass, 25 intentional source-audit/provider-smoke skips).
221
+ Paid live-provider smoke was not run for this maintenance release. Update the
222
+ plugin through its marketplace and run the appropriate host's setup command
223
+ (`/kimi:setup` in Claude Code or `$kimi-setup` in Codex) to activate the new
224
+ version; publishing does not update existing host caches or hook pins.
225
+
226
+ ## 1.10.1 — 2026-09-09
227
+
228
+ **Patch: every plugin refusal now states its setup-retryability explicitly.** The 1.10.0
229
+ refusal-code contract (`docs/safety.md § Refusal codes`) says agents key on
230
+ `details.retryable_after_setup`; three pre-1.10 refusal shapes omitted the field —
231
+ `CLI_V2_HOOK_ORDER_UNSAFE`, `INVALID_ENV` (all three `KIMI_PLUGIN_CC_KIMI_PREFIX_ARGS` paths)
232
+ and the legacy-v1 branch of `KIMI_CAPABILITY_NOT_CERTIFIED` (which also gains
233
+ `refusal_kind: "v1-version-not-certified"`). Behaviour was already fail-safe (the retry gate
234
+ retries only on literal `true`), so this is a contract-exactness fix: no policy, allowlist,
235
+ engine-selection or certification change; kimi-code 0.42.0 remains the exact certified version.
236
+ Found by Kimi's post-publish release review of 1.10.0. Wrappers must still treat an absent
237
+ field as non-retryable.
238
+
239
+ ## 1.10.0 — 2026-09-09
240
+
241
+ **Full migration to native agent-core-v2, certified at exact kimi-code 0.42.0.**
242
+ kimi-code 0.42.0 deleted the legacy agent-core-v1 package and `KIMI_CODE_LEGACY_FLAG`
243
+ (#3542, not in its changelog), making `kimi -p` native-v2 unconditionally and rendering
244
+ the plugin's forced-v1 pin inert. All eight operations (ask, review, challenge,
245
+ review_gate, rescue, pursue, swarm, swarm-write) now run on unmodified native v2.
246
+
247
+ ### ⚠️ Breaking changes and upgrade notes
248
+
249
+ This release changes behaviour that earlier 1.x users may depend on. Strictly by semver it is a major; it ships as 1.10.0 because the plugin is upgraded in place through the marketplace and its 1.x line has always advanced compat by minor releases.
250
+
251
+ - **Certification is now per EXACT kimi-code version, not per minor.** Native v2 is certified at `0.42.0` only. When kimi-code publishes `0.42.1` (or newer), every model-spawning command refuses with `KIMI_CAPABILITY_NOT_CERTIFIED` until a plugin release certifies it — before 1.10, a patch release inside a tested minor kept working. kimi-code self-upgrades in the background, so expect this on the next upstream patch; pin `KIMI_PLUGIN_CC_KIMI_BIN` to a certified binary if you need continuity, and watch for the next plugin release.
252
+ - **Sessions created before 1.10 cannot be resumed on 0.42.0.** `ask --resume`, `ask -r`, `rescue --resume` and rescue's implicit latest-session reuse refuse (`KIMI_SESSION_LINEAGE_UNKNOWN` / `KIMI_SESSION_ENGINE_MISMATCH`) — the v1 engine no longer exists in the binary, so nothing could replay those sessions. Nothing is deleted; `/kimi:status`, `/kimi:result` and `/kimi:replay` still work on the old jobs. Start fresh sessions.
253
+ - **`default_plan_mode = true` (any spelling) in `~/.kimi-code/config.toml` now blocks every command** (`CLI_V2_PLAN_MODE_CONFIGURED`). On the old forced-v1 path that setting was harmless; on native v2 it would arm the one code path that bypasses the safety hook. Set it to `false` or remove it. `/kimi:setup` cannot fix this one.
254
+ - **`KIMI_PLUGIN_CC_KIMI_PREFIX_ARGS` may no longer contain kimi flags** (`-r`, `-c`/`-C`, `-S`, `-p`, `-m`, `--plan`, `--yolo`, `--agent`, `--add-dir`, …) — `INVALID_ENV`. The prefix is a launcher shim only (e.g. `["--import","tsx",…]`).
255
+ - **`[experimental] tower` / `subagent_fork` and `KIMI_CODE_EXPERIMENTAL_FLAG` refuse before spawn** (`CLI_V2_EXPERIMENTAL_UNSAFE` / `CLI_V2_HOOK_ORDER_UNSAFE`). Unset them for plugin-managed runs.
256
+ - **Still on kimi-code ≤ 0.41.x?** Nothing changes for you: those versions route to the legacy-v1 engine exactly as before. But the plugin certifies them only for an explicitly pinned binary — kimi-code's auto-update will move you to 0.42.x, at which point the notes above apply.
257
+
258
+ No action for the job store (one additive nullable column, migrated automatically) or the hook policy (unchanged allowlists). As with every release, run `/kimi:setup` (or `$kimi-setup`) after updating so the hook is re-pinned to the new install path — a `kimi login` also strips the managed-block markers, and setup restores them.
259
+
260
+ None of these refusals is repaired by `/kimi:setup` (the native-v2 ones carry `retryable_after_setup: false` explicitly; a few pre-1.10 codes omit the field in 1.10.0 and an absent field must be treated as `false`). They are catalogued with remedies in [docs/safety.md § Refusal codes](./docs/safety.md#refusal-codes-of-the-native-v2-contract-v1100).
261
+
262
+ - **Certification basis changed (docs/native-v2-certification-provenance.md §2).** Upstream
263
+ still registers the plan feature before external hooks and provides no ordering guarantee
264
+ (confirmed in the shipped 0.42.0 bundle). Native v2 is instead certified on a construction:
265
+ the plan-file guard is the engine's ONLY chain-breaking final allow, it fires only while
266
+ plan mode is ACTIVE, and the plugin proves plan mode is never armed in a plugin-managed
267
+ session. `event.allow` count and the before-execute subscriber set are re-verified per tag
268
+ by `tests/audit/v2-tag-scan.test.ts`, backed by a live plan-mode-ON control.
269
+ - **New pre-spawn preflight (`runtime/native-v2-preflight.ts`).** Refuses `default_plan_mode`
270
+ unless absent/`false` (`CLI_V2_PLAN_MODE_CONFIGURED`), refuses `[experimental]`
271
+ tower/subagent_fork from config or per-flag env (`CLI_V2_EXPERIMENTAL_UNSAFE`), and refuses
272
+ resuming a session whose wire journal holds any `plan_mode.*`/`plan.*` record
273
+ (`KIMI_SESSION_PLAN_TAINTED`). Fail-closed on unreadable/oversized/symlinked inputs. Run
274
+ before spawn and re-run at the cli-client spawn boundary (config and journals are mutable).
275
+ - **Resume proven live on the real layout.** The real-binary smoke gains a native-v2 resume
276
+ lane: a fresh run's real `agents/*/wire.jsonl` is found where the preflight scans, the `-r`
277
+ resume re-emits `system.version` first with the same session id and the hook still denying
278
+ writes, and a `plan_mode.enter` record appended to that journal makes the next resume refuse
279
+ before any process is created. The tag scan additionally pins `features/plan/planOps.ts` and
280
+ asserts the durable plan event types are exactly `plan_mode.enter|cancel|exit` +
281
+ `plan.revision` (the prefixes the taint scan keys on) and that `restore()` folds by literal
282
+ `record.type`; `permission.set_mode` (`manual|yolo|auto`) is verified to be a separate state.
283
+ - **Second-round adversarial review (Codex) — seven findings, all closed with regression tests.**
284
+ (P1) upstream's config loader camelCases every top-level TOML key before the plan section
285
+ reads `defaultPlanMode`, so `defaultPlanMode = true` (or any mixed spelling) walked past a
286
+ literal `default_plan_mode` check — the preflight now mirrors upstream's `snakeToCamel`
287
+ verbatim (`app/config/toml.ts` is hash-pinned by the tag scan; the `[experimental]` table
288
+ is verified to keep raw keys and is not normalized). (P1) the hidden `-C` alias of
289
+ `--continue` resumed the latest cwd session with no journal scan — the reserved-prefix-flag
290
+ set now covers every kimi root flag incl. `-C`, `-y/--yes/--auto-approve/--manual`, `-V/-h`.
291
+ (P1) the Stop hook verified the hook under `<plugin-root>/<relative KIMI_CODE_HOME>` while the
292
+ child read `<payload.cwd>/<…>` — `runReviewGateStopHook` now resolves the home once against
293
+ the payload cwd for verification, plan and spawn. (P2) a persisted row carrying a session id
294
+ but no source job is refused (`KIMI_SESSION_LINEAGE_UNKNOWN`) instead of exempted. (P2)
295
+ unknown-role and malformed stream lines before the `system.version` marker now trip the
296
+ marker-first rule. (P2) the stderr resume-hint channel (kimi 0.1.x) is consulted only on
297
+ legacy-v1 plans — a native-v2 plan pins a session id from the stdout meta record alone.
298
+ (P2) the marker's `version` must be a single well-formed semver token; a multi-line value
299
+ is no longer first-line-normalized into the certified version.
300
+ - **Second-round review (Kimi) — three findings, all closed.** (1) the v2 resume path had no
301
+ repeatable proof of the session-store keying → smoke lane 3b (above) plus a tag-scan pin of
302
+ upstream's own layout scanner (`app/sessionExport/wire-scan.ts`) and the `session_<uuid>` /
303
+ `sessions/` / `agents/` builders. (2) a goal-terminal pursue exit (3/6) skipped the success
304
+ assertion, so a native-v2 plan could resolve with no `system.version` marker and an empty
305
+ artifact — `assertGoalRunProvenance` now refuses that (`CLI_ENGINE_PROVENANCE_MISMATCH`).
306
+ (3) a readdir failure other than ENOENT/ENOTDIR (e.g. `EACCES`) during the journal scan
307
+ escaped as an untyped error instead of the classified `KIMI_SESSION_JOURNAL_UNAVAILABLE`.
308
+ - **Engine selection is plugin-owned (`selectIntendedEngine`).** Exact version in
309
+ `NATIVE_V2_CERTIFIED` → native-v2; a minor in `KIMI_TESTED_MINORS` (≤ 0.41) → legacy-v1 with
310
+ the child-only legacy pin; otherwise refuse. Certification is per exact version and per
311
+ operation. `KIMI_TESTED_MINORS` is unchanged and never gains 0.42.
312
+ - **Provenance.** A native-v2 plan requires the `system.version` marker as the first
313
+ stream-json line and requires it to equal the probed version; a legacy plan still refuses
314
+ it. Either mismatch tears down the process tree before any record reaches the caller.
315
+ Jobs persist a `safety_profile` column (`native-v2-no-plan/1` for v2, null for v1); forged
316
+ or unknown-profile plans refuse at the spawn boundary. Resume refuses unknown lineage
317
+ (`KIMI_SESSION_LINEAGE_UNKNOWN`) and cross-engine sources.
318
+ - **Bash cwd confinement (`runtime/rescue-approval.ts`).** v2's `Bash` tool accepts a separate
319
+ `cwd`; the allowlist now validates `tool_input.cwd` against the trusted root (realpath,
320
+ symlink, `.git`, existence) before the command-string policy. Closes the 0.40.0
321
+ out-of-workspace-cwd gap for write-capable operations.
322
+ - **Hook policy.** `EnterPlanMode` and `ExitPlanMode` denied for every label. Every spawn
323
+ exports `KIMI_CODE_NO_AUTO_UPDATE=1` and an absolute `KIMI_CODE_HOME`. The master
324
+ `KIMI_CODE_EXPERIMENTAL_FLAG` still refuses before spawn.
325
+ - **Continuation cost:** sessions created before this release (v1 or unknown provenance) are
326
+ no longer resumable — the v1 engine no longer exists in the binary. `ask --resume` /
327
+ `rescue --resume` on such jobs refuse with a fresh-session remedy; nothing is deleted;
328
+ status/result/replay stay inspectable.
329
+ - **Out of scope / refused:** native plan mode, tower mode, subagent fork, Remote Control,
330
+ `--add-dir`, and the singular `Agent` tool. #3431 stays open as the preferred end state (a
331
+ released ordering guarantee would let native plan mode return).
332
+
333
+ ## 1.9.14 — 2026-09-06
334
+
335
+ **Certifies kimi-code 0.41.0 on forced legacy-v1.** Model jobs on 0.41.x now
336
+ pass the tested-minor gate. Native v2 remains disabled for every operation.
337
+
338
+ - **Source audit: COMPAT-PRESERVED.** Four independent reviewers compared
339
+ exact 0.40.0 and 0.41.0. The v1 core, CLI prompt driver/shared writer, hooks,
340
+ permissions, session bootstrap/config, and kaos are unchanged. The SDK adds
341
+ `suggestFiles` (v1 returns `undefined`) and changes a comment.
342
+ - **Runtime evidence:** the September 6 monitor's exact 0.41.0 smoke passed
343
+ **12 tests / 0 failures / 55 assertions in 383.88s**. This boundary/version
344
+ and documentation release reuses that same-day smoke; it changes no model
345
+ execution behavior. The known-minor assertion advances to 0.41; unknown-minor
346
+ refusal fixtures continue deriving the next boundary automatically.
347
+ - **V2 evidence refreshed:** the exact 0.41.0 fresh-plan reproduction still
348
+ bypasses the hook on plan-file Write; v1 blocks it. `staleGuard` and the old
349
+ upstream `Permission.md` are removed in this release, so the docs distinguish
350
+ historical design evidence from current source. Auto-mode dangerous-command
351
+ checks are skipped, while their nonInteractive exclusion predates 0.41.0.
352
+ The [v2 brief](docs/native-v2-status.md) separates released changes from open
353
+ proposals and retains #3431 as the ordering blocker.
354
+ - Claude/Codex version metadata and bundled runtime are regenerated. Release
355
+ gates: independent post-edit review and `bun run check`.
356
+
357
+ ## 1.9.13 — 2026-09-02
358
+
359
+ **Certifies kimi-code 0.40.0 on the forced legacy-v1 path.** Native agent-core-v2 remains fail-closed disabled; no hook, permission, concurrency, budget, confinement, or allowlist policy changed.
360
+
361
+ - **Scoped source audit preserved the supported contract.** The 0.39.1→0.40.0 diffs (48 commits) are 0 bytes for v1 permission policies, v1 hooks, and wire/session. CLI prompt mode changes only `--yolo`/`--auto` help text and adds top-level `fork`/`session` subcommands, which are off the `-p` path (the plugin passes the prompt as the value of `-p`, never a bare positional). Session bootstrap/config is one additive line — `ModelAliasBaseSchema.protocol` widens to `'anthropic' | 'openai_responses'` — and that line is the entire `packages/agent-core` source change. v1 tools/SDK is additive telemetry, session-list, and tower plumbing; Write/Edit `path`, Bash `command`, kaos path guards, and the v1 `createKimiHarness` entry point are unchanged (the `KimiHarness` class gains one optional telemetry field that entry point does not wire). `KIMI_CODE_LEGACY_FLAG=1` still forces v1 for fresh and resumed `-p` at the top of `runPrompt()`; engine selection reads only that env var, so no `config.toml` key — including `[experimental]` tables, which can enable registered v1 flags (`tool-select`, `secondary-model` only) without the env master switch — can defeat the pin. #3427's config-over-env flag precedence and #3434's removal of the legacy acp-adapter package (touches `KIMI_CODE_LEGACY_FLAG` only inside the `acp` subcommand) are v2-only / off the `-p` transport; the secondary-model pool stays opt-in on v1.
362
+ - **Native-v2 containment remains load-bearing, and 0.40.0 adds a reason.** The plan feature (`index.ts:330`) still registers before external hooks (`:338`), `planService.ts:112` is still the sole `event.allow()`, and `toolExecutor/` is a 0-byte diff; MoonshotAI/kimi-code#3431 is open with no maintainer response. The 2026-09-01 live repro, re-run on 2026-09-02 against the 0.40.0 binary, still bypasses the hook (v2: hook denies `Glob`, plan-file `Write` executes with zero hook payloads; v1 control blocks it). New this release: #3444 removed `RuntimeWorkspaceView.resolve()`'s root assertion, so native-v2 Bash can run with an out-of-workspace `cwd` — confined to agent-core-v2 with no shared code in v1 or kaos, unreachable on the pinned path, and one more reason the refusal stays. The new v2 dangerous-command ask policy is skipped under `nonInteractive` and is not an ordering fix.
363
+ - **Operator notes, not contract.** v2 config writeback (#3392) now preserves `config.toml` formatting per domain, so managed-block markers may survive login/settings writes more often — the marker-less fallback fires less, never incorrectly. `kimi doctor` now validates config against the v2 schema, whose hook schema is field-for-field identical to v1's, so the managed block passes. The new `kimi migrate --run` is a headless entry point that can rewrite `config.toml`, but its merge mode keeps the target's `hooks` entry and writes atomically at mode 0600 — though, like any kimi-code re-serialize, it drops comments and therefore the managed-block markers, the already-documented marker-loss class the parser-based fallback covers (pre-existing logic; if it ever did alter the entry, the per-spawn byte-exact verification refuses as drift).
364
+ - **Certification evidence is green.** The exact-0.40.0 temporary binary passed `bun run smoke:real` with **12 pass / 0 fail / 55 assertions in 383.45s** (the daily monitor's earlier 3/9 red was the documented operator-auth false alarm — `auth.login_required`, `records=[]` — cleared once operator auth was valid again: an isolated-home `kimi -p` probe answered `OK` before the re-run), covering forced-write denials, v2 pre-spawn refusal, fresh/resumed default-plan v1 pinning, pursue's every-turn hook gate, real read-swarm child denial, write-swarm confinement (`patchBytes=306`, user tree clean, worktree removed), and non-vacuous out-of-root denial. `KIMI_TESTED_MINORS` gains `{0,40}`. Tags: `v1.9.13` and `compat-verified-kimi-code-0.40.0`. Reports 117-120; continuity report `.claude/kimi-code-research/daily-monitor/2026-09-02-upstream-monitor.md`.
365
+ - **Release gate.** `bun run check` passed with **706 pass / 10 intentional real-binary skips / 0 fail / 2,209 assertions** across 38 files; the two untested-version test fixtures moved from 0.40.0 to 0.41.0 as the boundary advanced.
366
+
367
+ ## 1.9.12 — 2026-08-29
368
+
369
+ **Makes forced-legacy engine provenance durable and certifies the exact kimi-code 0.39.1 patch.** Native agent-core-v2 remains fail-closed unavailable; no hook-verification, permission, allowlist, concurrency, budget, or worktree-confinement rule is relaxed.
370
+
371
+ - **Every model job now carries an immutable execution plan.** Before a job row exists, the runtime resolves the exact executable, probes the same command/prefix/cwd tuple, checks the operation's certified legacy-v1 version range, and persists the real operation, intended/observed engine, kimi version, command tuple, certification source, and resume lineage. Detached ask/rescue workers reload that persisted tuple instead of consulting ambient PATH/config again; the final spawn boundary rejects command drift, corrupt certification, stale test-bypass rows, every native-v2 plan, and untested minors. Setup now says this plainly: it may complete on an out-of-range binary, but model commands refuse until the plugin certifies the minor or `KIMI_PLUGIN_CC_KIMI_BIN` selects a certified binary; the skip-version flag is tests/smoke only.
372
+ - **Observed-engine mismatches tear down before tool output can escape.** A native-v2-only `system.version` marker under a forced-v1 plan stops record delivery, reaps the owned process tree, and raises `CLI_ENGINE_PROVENANCE_MISMATCH`. New SQLite columns are additive and nullable; old rows remain unknown unless bounded saved-log evidence proves an engine. Conflicting evidence stays unknown, historical `rescue` labels no longer guess between rescue and pursue, cross-engine resume refuses only on a proven mismatch, and forensic backfill does not reorder jobs.
373
+ - **Write-capable trust roots are plugin-owned.** Rescue and pursue now export the persisted job cwd, while write-swarm exports its throwaway worktree, through `KIMI_PLUGIN_CC_WORKSPACE_ROOT`; the hook never trusts upstream payload `cwd` and denies write tools when the root is missing. Write-swarm certifies wrappers from the actual spawn worktree cwd, preventing relative prefix arguments from resolving one target during probe and another at execution.
374
+ - **Independent review findings were closed before release.** The Kimi release-blocker pass confirmed no native-v2 containment hole, then caught the stale warn-only operator contract and plan-deserialization calls outside rescue/pursue/swarm cleanup. The warning/recovery policy is now consistent and corrupt/pre-slice plans transition jobs to failed rather than stranding them as running. The review also recorded two bounded costs without weakening the gate: review-gate performs its exact version probe before the 8-second model budget, and permanently unknown historical rows may re-read at most 32 MiB of saved log on inspection.
375
+ - **0.39.1 patch certification is exact and v2 remains blocked.** All six 0.39.0→0.39.1 playbook scopes are 0 bytes. Exact 0.39.1 and live upstream `main` (`9d2304c`) retain the plan service's final `event.allow()` before ordinary external-hook listeners; no upstream issue/PR or released ordering contract exists yet, so `NATIVE_V2_CERTIFIED_OPERATIONS` stays empty. The exact temporary binary passed `bun run smoke:real` with **12 pass / 0 fail / 55 assertions in 400.68s**, including fresh/resumed default-plan legacy pinning, pursue every-turn enforcement, real swarm-child denial, write-swarm confinement (`patchBytes=278`, user tree clean, worktree removed), and out-of-root denial. `KIMI_TESTED_MINORS` is unchanged at `{0,39}`. Tags: `v1.9.12` and `compat-verified-kimi-code-0.39.1`.
376
+ - **Release gate.** `bun run check` passed with **706 pass / 10 intentional real-binary skips / 0 fail / 2,203 assertions** across 38 files after regenerated Claude/Codex surfaces were staged.
377
+
378
+ ## 1.9.11 — 2026-08-27
379
+
380
+ **Certifies kimi-code 0.39.0 on the forced legacy-v1 path.** Native agent-core-v2 remains fail-closed disabled; no hook, permission, concurrency, budget, confinement, or allowlist policy changed.
381
+
382
+ - **Scoped source audit preserved the supported contract.** The 0.38.0→0.39.0 diffs were 0 bytes for CLI prompt mode (including the engine selector and all of its call sites), v1 permission policies, v1 hooks, and the wire/session scope; the only non-empty scoped surface (9,060 bytes) is MCP-registry `cwd`/OAuth-verify plumbing that leaves create/resume session bootstrap and the `config/` dir byte-unchanged. The v1 tool-layer files outside the scoped diffs (`path-access.ts`, `bash.ts`) are a win32-only shell-path-bridge refactor, provably identity on POSIX. The audit playbook gains a `06-v1-tools-sdk.diff` scope after the adversarial reviewer showed `packages/node-sdk` (source of `createKimiHarness`) and `packages/kaos` were on the `-p` path but never scoped.
383
+ - **0.39.0's experimental tower mode and subagent fork are v2-only and inert on the pinned path.** Zero v1 flag-registry presence; the v1 `AgentSwarm` schema is `.strict()` so a model-supplied `fork` argument is rejected; both flags are subsumed by the already-refused `KIMI_CODE_EXPERIMENTAL_FLAG`; `[experimental] subagent_fork = true` in the shared config.toml is inert under v1 and does not trip the plugin's hooks-scoped validation. A dedicated v2 veto-ordering re-audit over the release's agent-core-v2 churn (diffstat: 337 changed files under `packages/agent-core-v2/src`, recorded in synthesis report 116) confirmed the plan-file final-allow defect is unchanged — and upstream's own Permission.md documents the bypass as intended with listener ordering an open design question — so both features (and native v2) stay gated on a released ordering contract.
384
+ - **Remote Control (experimental) is contained by existing verification.** A tunneled config patch can remove the managed hook out-of-band; the per-spawn byte-exact `verifyHookInstalled` catches that fail-closed (an altered entry refuses as drift, a removed one as not-installed — same `/kimi:setup` remedy). Operator notes on the relay's refresh-token forwarding and permissive loopback branch are recorded in the Post-GA audit log.
385
+ - **Certification evidence is green.** The exact-0.39.0 temporary binary passed `bun run smoke:real` with **12 pass / 0 fail / 55 assertions in 554.49s**, covering forced-write denials, v2 pre-spawn refusal, fresh/resumed default-plan v1 pinning, pursue's every-turn hook gate, read-swarm child denial, write-swarm confinement (`patchBytes=278`, user tree clean, worktree removed), and non-vacuous out-of-root denial. `KIMI_TESTED_MINORS` gains `{0,39}`. Tags: `v1.9.11` and `compat-verified-kimi-code-0.39.0`. Reports 111-116; continuity report `.claude/kimi-code-research/daily-monitor/2026-08-27-upstream-monitor.md`.
386
+
387
+ ## 1.9.10 — 2026-08-24
388
+
389
+ **Certifies kimi-code 0.37.x and 0.38.0 on the forced legacy-v1 path.** Native agent-core-v2 remains fail-closed disabled; no hook, permission, concurrency, budget, confinement, or allowlist policy changed.
390
+
391
+ - **Scoped source audit preserved the supported contract.** Intermediate 0.37.0→0.37.1 and 0.37.1→0.37.2 diffs were 0 bytes across all five audit surfaces. The cumulative 0.36.1→0.38.0 audit found 1,805 bytes in CLI prompt mode (only the off-path hidden `__update_download` command), 0 bytes in permission, 0 bytes in hooks, 8,525 bytes in wire/session (MCP OAuth/session plumbing plus a 0.38 background-write drain), and 47,360 bytes in session bootstrap/config (MCP registry/OAuth plus create/resume wiring). Hook merge, cwd, policy order, matching, tool-input keys, and standard swarm-child permission inheritance remain unchanged. The 0.38.0 `WaitFor` tool is v2-only and outside the plugin read-only allowlist.
392
+ - **Native-v2 containment remains load-bearing.** Exact 0.38.0 still permits plan-file final approval before the external hook in native v2. Accepted children therefore overwrite `KIMI_CODE_LEGACY_FLAG=1`, while truthy `KIMI_CODE_EXPERIMENTAL_FLAG` values refuse before spawn. KAP indexing and MoonshotAI/kimi-code#2376 remain upstream follow-ups; v2 is not re-enabled.
393
+ - **Certification evidence is green.** The exact-0.38.0 temporary binary passed `bun run smoke:real` with **12 pass / 0 fail / 55 assertions in 381.64s**, covering forced-write denials, v2 refusal, fresh/resumed default-plan v1 pinning, pursue's every-turn hook gate, real read-swarm child denial, write-swarm confinement (`patchBytes=278`, user tree clean, worktree removed), and non-vacuous out-of-root denial. `KIMI_TESTED_MINORS` gains `{0,37}` and `{0,38}`.
394
+ - **Release scope.** v1.9.10 publishes the verified compatibility boundary and regenerated Claude/Codex surfaces without changing safety defaults. Tags: `v1.9.10` and `compat-verified-kimi-code-0.38.0`. Continuity report: `.claude/kimi-code-research/daily-monitor/2026-08-24-upstream-monitor.md`.
395
+
396
+ ## 1.9.9 — 2026-08-13
397
+
398
+ **Certifies kimi-code 0.36.0 on the forced legacy-v1 path.** Native agent-core-v2 remains fail-closed disabled; no hook, permission, concurrency, budget, confinement, or allowlist policy changed.
399
+
400
+ - **Scoped source audit preserved the supported contract.** The immutable 0.35.0→0.36.0 diffs for CLI prompt mode, v1 permission policies, and v1 hooks were all 0 bytes. The 5,056-byte wire/session diff adds MCP OAuth credential coordination; the 22,703-byte bootstrap/config diff adds MCP OAuth inspection/coordinator APIs and v2 secondary-model pool config round-tripping. Neither changes the `-p` stream, create/resume hook merge, permission context, cwd, or workspace-local config loading.
401
+ - **Native-v2 containment remains load-bearing.** Exact 0.36.0 still permits the plan listener to final-allow exact plan-file writes before later external hooks. Accepted children therefore overwrite `KIMI_CODE_LEGACY_FLAG=1`, while truthy `KIMI_CODE_EXPERIMENTAL_FLAG` values still refuse before spawn. The new v2 secondary-model keys are excluded from the v1 derived-model patch recipe.
402
+ - **Certification evidence is green.** The exact-0.36.0 temporary binary passed `bun run smoke:real` with **12 pass / 0 fail / 55 assertions in 534.57s**, including forced-write denials, v2 pre-spawn refusal, fresh/resumed default-plan v1 pinning, pursue's every-turn hook gate, real read-swarm child denial, write-swarm confinement/cleanup, and out-of-root denial. `KIMI_TESTED_MINORS` gains `{0,36}`. Tags: `v1.9.9` and `compat-verified-kimi-code-0.36.0`.
403
+
404
+ ## 1.9.8 — 2026-08-12
405
+
406
+ **Certifies kimi-code 0.35.0 on the forced legacy-v1 path.** Native agent-core-v2 remains fail-closed disabled; no hook, permission, concurrency, budget, confinement, or allowlist policy changed.
407
+
408
+ - **Scoped source audit preserved the supported contract.** The immutable 0.34.0→0.35.0 diffs for CLI prompt mode, v1 permission policies, v1 hooks, and consumed wire/session records were all 0 bytes. The only canonical bootstrap diff (3,347 bytes) adds global MCP OAuth-status RPC/helper code and does not change `-p` session construction, hook merging, permission context, cwd, or workspace-local config loading.
409
+ - **Adjacent upstream changes narrow, rather than widen, child capability.** The builtin `coder` profile no longer exposes nested `Agent`/`AgentSwarm` by default, and builtin profiles are cloned per session. The coordinator `AgentSwarm` path remains available and hook-gated.
410
+ - **Native-v2 containment remains load-bearing.** Exact 0.35.0 still permits the plan listener to final-allow exact plan-file writes before later external hooks. Accepted children therefore overwrite `KIMI_CODE_LEGACY_FLAG=1`, while truthy `KIMI_CODE_EXPERIMENTAL_FLAG` values still refuse before spawn.
411
+ - **Certification evidence is green.** The exact-0.35.0 temporary binary passed `bun run smoke:real` with **12 pass / 0 fail / 55 assertions in 525.01s**, including fresh/resumed default-plan v1 pinning, forced-write denials, pursue's finite budget, real read-swarm child denial, write-swarm confinement/cleanup, and out-of-root denial. `KIMI_TESTED_MINORS` gains `{0,35}`. Tags: `v1.9.8` and `compat-verified-kimi-code-0.35.0`.
412
+
413
+ ## 1.9.7 — 2026-08-08
414
+
415
+ **Makes hook refusals self-healing for every caller and startup failures self-diagnosing.** No safety-policy, permission, concurrency, budget, allowlist, or `KIMI_TESTED_MINORS` change; experimental-v2 remains fail-closed refused.
416
+
417
+ - **The re-pin protocol rides the refusal message.** Every `*_HOOK_NOT_INSTALLED` refusal now appends a single-source caller protocol (`hookRefusalRetryProtocol`, `runtime/hooks/install.ts`, consumed at all five model-spawning refusal sites): on `retryable_after_setup: true`, run the embedded resolved `companion.sh setup` and retry the refused command once only on exit 0; anything else — or a second refusal — surfaces. Slash-command callers now self-heal after a plugin update exactly like the agents (whose `agents/*.md` contract is unchanged), completing step 3 of the hook-pin durability spec's recommended path for all surfaces with zero duplication in the 13 surface files — an earlier draft that pasted the paragraph into each command was reverted for exactly that bloat.
418
+ - **`auth.login_required` is classified as auth, not startup.** kimi-code's logged-out OAuth store (`auth.login_required: OAuth provider "managed:kimi-code" requires login…`) reaches the classifier inside the `CLI_NONZERO_EXIT` message (cli-helpers embeds the stderr tail); a new branch ahead of the generic nonzero-exit case maps it to `*_KIMI_AUTH_UNAVAILABLE` with a "Run `kimi login`… `/kimi:setup` does not repair auth" remedy. Trigger incident: 2026-08-08, an out-of-band kimi background auto-upgrade (0.31.1→0.34.0) invalidated the token and the plugin's startup-failed advice misdirected to setup.
419
+ - **Wrapped startup failures keep their cause.** `classifyManagedCommandFailure` threads `availability`, `cause_code`, and a tail-truncated (2 KB) `cause_message` into `RuntimeError.details`, so the underlying stderr survives on the foreground `details:` JSON line and in the SQLite job row. Previously the cause lived only on the unserialized `cause` chain — invisible to LLM callers on every channel (LLM-caller discipline).
420
+ - Tests: login classification, details threading, tail truncation, and the review-gate warning path; full `bun run check` green (692 pass / 0 fail).
421
+
422
+ ## 1.9.6 — 2026-08-08
423
+
424
+ - **Fix-first engine pin.** kimi-code 0.33.0 inverted unflagged `kimi -p` from v1 to native v2 (unchanged in 0.34.0), while v1.9.5's refusal still recognized only the old `KIMI_CODE_EXPERIMENTAL_FLAG` selector. Every accepted child spawn now overwrites `KIMI_CODE_LEGACY_FLAG=1`, including resumed sessions and ambient false-value cases; older binaries ignore the unknown flag. Truthy experimental values remain an independent pre-spawn `CLI_V2_HOOK_ORDER_UNSAFE` refusal.
425
+ - **Why the pin is load-bearing.** Exact 0.34.0 source still lets the plan service final-allow its exact KIMI_CODE_HOME plan-file Write/Edit before the later external PreToolUse listener. The path is outside the user worktree but violates the every-tool managed-hook contract. Native v2 remains uncertified; this candidate does not relax hook, permission, concurrency, budget, confinement, or allowlist policy.
426
+ - **Certification evidence is green.** Unit tests prove the forced legacy flag reaches fresh and resumed children even when ambient state says `0`/`false`; the exact-0.34.0 temp binary passed `bun run smoke:real` with **11 pass / 0 fail / 54 assertions in 460.09s**. The non-vacuous `default_plan_mode=true` fresh+resume lane stayed on v1 (no `system.version`) and both writes reached the managed hook and were denied. `KIMI_TESTED_MINORS` gains `{0,32}`, `{0,33}`, and `{0,34}`. Release tags: `v1.9.6` and `compat-verified-kimi-code-0.34.0`.
427
+
428
+ ## 1.9.5 — 2026-08-01
429
+
430
+ **Publishes the already-verified kimi-code 0.31.1 patch boundary as an installable plugin release.** There is no runtime safety-policy, permission, concurrency, budget, allowlist, or `KIMI_TESTED_MINORS` change; experimental-v2 remains fail-closed refused.
431
+
432
+ - **Default-v1 compatibility remains intact.** The scoped 0.31.0→0.31.1 audit found 0-byte CLI, permission, hook, and bootstrap/config diffs. The only canonical wire/session delta removes the disabled no-op `model` parameter from Agent/AgentSwarm schemas; the AgentSwarm tool name/executor and all load-bearing hook invariants are unchanged.
433
+ - **Exact released-binary evidence is green.** A temp-installed `@moonshot-ai/kimi-code@0.31.1` binary passed the final release-candidate `bun run smoke:real` with **10 pass / 0 fail / 42 assertions in 305.60s**, covering forced-write denials, pre-spawn v2 refusal, pursue's finite budget, read-swarm child denial, write-swarm confinement/cleanup, and out-of-root denial.
434
+ - **Release scope is distribution-only.** The prior `compat-verified-kimi-code-0.31.1` marker already recorded the audit at immutable upstream commit `6b56c11697771fe596099b38bafae539820309a4`. v1.9.5 refreshes plugin/cache version metadata and generated mirrors without changing executable policy.
435
+
436
+ ## 1.9.4 — 2026-07-31
437
+
438
+ **Certifies kimi-code 0.31.0 for the default-v1 engine and fail-closes experimental-v2 after correcting an inherited hook-order overclaim.** `KIMI_TESTED_MINORS` gains `{0,31}`; the setup warning stops firing for 0.31.x. This is a patch release because the safe outcome requires runtime refusal, not only documentation.
439
+
440
+ - **The v2 issue is an actual managed-hook bypass, confined outside the worktree.** Production v2 listener order is permission gate → plan → swarm → external hooks. With plan mode active, `AgentPlanService` final-allows a `Write`/`Edit` targeting only the exact plan file under `KIMI_CODE_HOME`; final allow stops later listeners, so PreToolUse never runs. Fresh sessions can reach it through user `default_plan_mode=true`, and resumes restore plan state. The path cannot write the user tree, but "every model tool reaches the managed hook" is load-bearing and cannot tolerate the exception.
441
+ - **Fail-closed mitigation.** `cli-client.ts` now refuses before spawn when `KIMI_CODE_EXPERIMENTAL_FLAG` matches upstream's truthy values (`1|true|yes|on`, trimmed/case-insensitive), returning `CLI_V2_HOOK_ORDER_UNSAFE` with `refusal_kind:"v2-hook-order-unsafe"`. It does not silently force v1 and `/kimi:setup` is not the remedy; unset the flag. False/unset values preserve default-v1 fresh and resume behavior. `EnterPlanMode` is explicitly denied for every managed label as defense in depth.
442
+ - **Correction, not a 0.31 regression.** The ordering is byte-identical in 0.30.0 and 0.31.0. Earlier audits correctly proved ordinary v2 hook vetoes but overgeneralized them into "before plan approval." v2 stays disabled until an exact release guarantees external-hook veto before every final allow and both fresh-default-plan and restored-plan tests pass.
443
+ - **0.31 custom-agent boundary documented.** Default-v1 now discovers project/user/plugin agent profiles and plugin system-prompt contributions. `override: true` can replace builtin `agent`/`coder` instructions and tool availability, and the chosen profile persists with the session. Profile fields and system-prompt text can redirect task intent but cannot themselves set hooks/permission/cwd, widen the local allowlist, or escape swarm-write confinement; enabled plugins are a separate source of hooks, still governed by any-block-wins aggregation.
444
+ - **Source/wire and smoke evidence.** V1 permission and hook trees are 0-byte diffs; consumed argv, hook aggregation, tool-input keys, swarm inheritance, PromptJsonWriter/session/goal shapes remain compatible. Parser/client verification passed 98/0/247. Exact-0.31.0 pre-mitigation smoke passed 11/0/49 in 944.47s across the forced-write labels, pursue budget, read swarm, write-swarm confinement, out-of-root denial, populated-home KAP observation, and an ordinary fresh-v2 denial. It proves confinement for that matrix, not fidelity under a hostile custom profile/prompt; the v2 lane is explicitly not certification because it did not cover `default_plan_mode`. The post-mitigation smoke lane asserts pre-spawn v2 refusal.
445
+ - **KAP caveat retained as released-source history.** 0.31.0 still contains experimental-v2 eager cross-session indexing and upstream PR #2376 remains unmerged, but the side effect is unreachable from plugin flows while v2 is refused.
446
+
447
+ ## 1.9.3 — 2026-07-29
448
+
449
+ **Certifies kimi-code 0.30.0, and fixes the smoke test that would otherwise have certified it for the wrong reason.** `KIMI_TESTED_MINORS` gains `{0,30}`; the H9 out-of-range warning stops firing. The substantive change is not the certification — it is the discovery that the evidence backing it was vacuous.
450
+
451
+ - **The smoke was green because it never ran the code it was believed to cover.** An exact-0.30.0 `smoke:real` had already passed `10 / 0 / 43`. It was worthless for the one behaviour in question: every isolated `KIMI_CODE_HOME` is created empty, kimi-code's cross-session indexer short-circuits when it finds zero sessions, so the path exited before doing anything. Nothing in the harness checked that its own premise held. **A green test whose precondition never held is worse than a red one — it reads as evidence.** The new populated-home case asserts its precondition (`wire.jsonl` count > 0) and fails loudly rather than passing quietly. This is now a standing rule in AGENTS.md, because the failure mode is generic: any smoke whose behaviour depends on host state can pass for the wrong reason.
452
+ - **What the test asserts, and deliberately does not.** It pins the INVARIANT — writes stay denied under a populated home, agent-core-v2 genuinely served the run (`systemVersion` defined), and no search index ever appears in the WORKSPACE — while only RECORDING whether `<KIMI_CODE_HOME>/search-index` materialized. Asserting its absence would encode an upstream bug as a plugin failure; asserting its presence would break the day the upstream fix ships. Recording keeps the test correct on both sides of that release.
453
+ - **Exact-0.30.0 `smoke:real` GREEN: 11 pass / 0 fail, 49 assertions in 348.05s** — and non-vacuous this time (`index PRESENT, wire files=1`). Read-only forced writes denied across all four labels; the asserted `KIMI_CODE_EXPERIMENTAL_FLAG=1` lane denied and emitted the v2 signal; pursue reached its finite budget with zero writes; read swarm denied a spawned subagent write; write-swarm stayed confined (`patchBytes=334`, `userTreeClean=true`, `worktreeCleaned=true`); the out-of-root absolute write was denied.
454
+ - **Source audit re-verified every load-bearing contract against 0.30.0** rather than inheriting the daily monitor's verdict (monitor reports are continuity-only and do not certify a version). Policy queue keeps the hook at index 0 with indices 1-4 all pure denies before the first approve at 5; hook engine keeps first-block-wins, empty-matcher-means-all, exit-2 denial, fail-open on internal error; `Bash`/`command` and `Write`/`Edit`/`path` unchanged with no new write-shaped builtin; `-p` still defaults to v1 with `permission: 'auto'`; goal mode still triggers on the `/goal` prefix alone; `HookDefSchema` still `.strict()`. The deepest check: `agent.hooks` is OPTIONAL, so an unwired subagent would silently fail open through index 0 — it is wired unconditionally by `createAgent`'s `config.hookEngine ?? this.hookEngine` fallback, and no production call site supplies `config.hookEngine`.
455
+ - **Scope correction worth recording.** The audit clone's `package.json` reads `0.30.0`, but `origin/main` is **eight commits ahead of the released tag** — v1 custom agent files, plugin-contributed agents, plugin `systemPrompt`, and the `secondary-model` flag are all queued for 0.31.0 and are NOT in the shipped binary. Auditing the wrong tree would have certified behaviour users do not have. Contracts were verified at both states and hold in both.
456
+ - **The 0.30.0 caveat, characterized rather than waved through.** Experimental-v2 App bootstraps eagerly activate the KAP global-search service, so a `kimi -p` run under `KIMI_CODE_EXPERIMENTAL_FLAG` performs an unasked-for cross-session index pass and creates `<KIMI_CODE_HOME>/search-index`. It is engine-internal (never a tool call), confined to KIMI_CODE_HOME, and the DEFAULT v1 engine is unaffected — not a hook bypass, not a user-worktree write, not a credential read. Root-caused with an upstream fix proposed in still-unmerged **MoonshotAI/kimi-code#2376**, which flips the registration to App-scope `OnDemand` and includes a behavioral DI regression test.
457
+ - **Residual, stated rather than buried.** Write-swarm still runs against a session-less home, so "an un-awaited index sync cannot race the patch capture" is COMPOSED from two tests (index confined to KIMI_CODE_HOME; patch capture reads the ephemeral worktree) rather than observed end to end in one.
458
+ - **Before certifying 0.31.0.** v1 custom agent files will auto-scan project roots (`<git-root>/.kimi-code/agents`, `<git-root>/.agents/agents`) with NO flag gating, and an `override: true` file can replace the default `agent` profile. `AgentFileDefinition` carries no permission/hook/cwd field, so it reshapes the system prompt and tool list only — every call still hits policy index 0 and our label allowlist fails closed on an unknown tool. It is a prompt-injection surface for repo-scoped rescue/swarm-write, not a hook bypass, and it needs a `docs/safety.md` paragraph before 0.31 lands.
459
+
460
+ ## 1.9.2 — 2026-07-25
461
+
462
+ **Agent-facing docs release. No runtime change.** Detaching the caller's shell call is now the documented default for the two write-capable surfaces, the cancel path is corrected to the form that can actually execute, and the harness interrupt contract is measured rather than assumed.
463
+
464
+ - **The bug this fixes is a doc bug with real consequences.** A dispatching agent refused `/kimi:swarm --write` outright, reasoning that the agent doc forbade `run_in_background: true`, `--budget` defaults to 30m, and Claude Code caps a foreground Bash call at 10 minutes. Every premise was true; the conclusion was not. The docs had conflated the runtime's rejection of `--background`/`--wait`/`--fresh`/`--resume` (real, unchanged) with a doc-level rule against the *caller* detaching its own shell call — a rule motivated by watchability, not enforced by anything. `swarm-write` and `pursue` now document caller-level detaching as the default. Read-only swarm's foreground default is unchanged and deliberate.
465
+ - **What actually bounds these surfaces** is the index-0 PreToolUse hook, the workspace allowlist, no-git-mutation, patch-only worktree confinement (swarm-write), and the mandatory finite `--budget` — all runtime-enforced, none dependent on a human watching. A blocked foreground call is *worse* oversight: it freezes the dispatching agent for the whole run, so it cannot report progress or cancel on request.
466
+ - **The first draft of the cancel path was falsified by review, and is corrected.** It told agents to "keep the `job_id` from the launch output and run `companion.sh cancel <job-id>`". That flow cannot execute: `pursue.ts`/`swarm.ts` mint the id with `randomUUID()` and emit nothing at launch, so a detached caller holds a host task id and the plugin id first appears in the final report. The working path is the **no-id** form — `companion.sh cancel` resolves `findLatestJob({runningOnly:true})` for the repo — which also removes the UUID from the human path entirely. Documented limit: with several runs in flight it takes the most recent, so a multi-run session confirms first.
467
+ - **Interrupt signal contract measured** (macOS, Claude Code): foreground Esc and `TaskStop` on a detached call both deliver a trappable SIGTERM **process-group-wide**, then SIGKILL after **~1.35s** (samples 1.34s / 1.36s). Two consequences. Group delivery reaps detached Kimi descendants along with the companion, so the "surviving child keeps writing to the real tree" risk raised against backgrounding `pursue` does not exist. But ~1.35s is shorter than `cli-client.ts`'s 1500ms child escalation *alone*, before quiescence and `git diff --binary` capture begin — so a hard interrupt can kill the companion mid-teardown and **lose the write-swarm patch**. `companion.sh cancel` signals from a separate process not racing that deadline and is the work-preserving stop. The margin is thin; re-measure on harness changes.
468
+ - **`pursue` is not `swarm-write`.** An adversarial review caught the first pass flattening a real asymmetry: swarm-write's edits are worktree-confined and return as a discardable patch, while pursue's land in the user's real tree and a cancel stops further work **without rolling back** what is already done. Both now default to detached callers; only pursue carries the non-rollback warning.
469
+ - **Seven surfaces, one contract — and they had already drifted.** The cancel correction initially landed in AGENTS.md and both Claude agent files but missed `scripts/surface-registry.ts`, so the repo told Codex to do the thing the same commit called impossible. Also fixed: `agents/kimi-pursue.md` contradicting itself four lines apart, `commands/{pursue,swarm}.md` routing a stop through an unobtainable id, `commands/cancel.md` documenting only the id-shaped form, `commands/swarm.md` flattening read and write swarm into one detach rule, and `docs/safety.md` claiming unqualified patch-capture-on-cancel that does not hold under a harness interrupt.
470
+ - **Doc hygiene: version archaeology moved out of the reference docs.** `AGENTS.md` § Releasing requires one current headline with per-version history in CHANGELOG/ROADMAP; the reference docs had drifted from that, and this session's own edits made it worse. Audited by three parallel read-only agents, applied by hand, with the rule that no fragment could be dropped until it was proven recorded elsewhere. One was not — pre-1.0 `v0.2.3` — and was added to "Older releases" below before the trim. Regression-preventing rationale was kept and sharpened into prohibitions ("never re-merge the two flags", "never collapse back to one shared block", "never regress this to a line scanner"). Also drops a stale "verified byte-identical through 0.12.0" that under-reported the tested range by 17 minors.
471
+ - **The Releasing instruction itself was ambiguous** about what a headline is, which is how the accretion kept happening. It now says the Version headline states a present-tense contract an agent must not regress — not what the release did — with an example of each. The 1.9.1 hook-pin durability contract is retained as the headline deliberately: it is still standing, and it is the only place that contract is written down.
472
+ - **No upstream-compat change.** `KIMI_TESTED_MINORS` unchanged through `{0,29}`; no kimi-code re-certification, no runtime code touched.
473
+
474
+ ## 1.9.1 — 2026-07-25
475
+
476
+ **Closes the background hook-enforcement test gap that let the v1.9.0 regression reach pre-release review, and adds a narrow verification-time probe that the pinned Node interpreter is still executable. Deliberately scoped: this is NOT a fix for a silent bypass — the wider rationale it was first written with was refuted by review and is recorded here so it is not revived.**
477
+
478
+ - **Test gap closed (the substantive change).** Every background test set `KIMI_PLUGIN_CC_SKIP_HOOK_CHECK=1`, and the one worker-refusal test drove `executeAskJob` **in-process** — so no test had ever run a real detached worker with enforcement on. That is precisely why v1.9.0's `spawn(process.execPath)` regression, which would have made every background rescue/ask refuse forever, was caught by a model review instead of by CI. New `tests/runtime/background-hook-enforcement.test.ts` runs the companion CLI as a real node subprocess invoked **through a symlink**, with **no** `KIMI_PLUGIN_CC_NODE_BIN` override, and asserts the spawned worker's own hook check agrees with the parent's pin. Confirmed to catch the original bug by reverting it: the job fails with `drift_axis: "node-bin"`, expected `…/Cellar/node/26.5.0/bin/node` vs. installed stable symlink. This could not live in the existing suite — with an override, spawner and verifier agree *by construction* (the buggy code honored the override too), and reproducing the no-override path needs a real node parent, impossible under `bun test` where `process.execPath` is bun.
479
+ - **The argv0 premise is now measured, not assumed.** v1.9.0's regression test fed the expected value in as the child's `argv0` rather than observing one, so it assumed the OS behavior the whole fix rests on. A real child now reports its own `argv0`/`execPath` (via `tests/helpers/print-node-pin.mjs`, which imports the **compiled** `dist/` a worker actually loads) and proves `spawn()` passes argv[0] verbatim without resolving symlinks.
480
+ - **Interpreter executability probe (`access(nodeBin, X_OK)`), honestly scoped.** `verifyHookInstalled` already confirmed the hook *script* was readable; it never confirmed the *interpreter* was runnable. The predicate it covers is narrow and exact: **config and expected command still match byte-for-byte, yet the Node token embedded in that command fails `X_OK` at verification time.** Reachable three ways — an absolute `KIMI_PLUGIN_CC_NODE_BIN` naming an already-dead binary that is not the running interpreter (e.g. an `nvm uninstall`ed version, via a direct `node dist/companion.js` that bypasses `companion.sh`'s exec+version gate); or **post-launch mutation on the default path**, where the interpreter is valid at launch and is then `chmod -x`'d (`realpath` still resolves, argv0 is retained, bytes unchanged) or removed (fallback to `execPath`, identical spelling in `argv0 === execPath` layouts). In each, the old behavior was `installed: true` → `/bin/sh -c` exits 127 → kimi-code reads any non-2 exit as ALLOW. Setup's stronger *execution* probe is not a substitute: it runs at install/`--check`, whereas this reruns before every model spawn and so catches degradation since the last probe.
481
+ - **What it explicitly does NOT do** (recorded because the first draft claimed otherwise, and a wrong comment about the threat model is worse here than wrong code). It does **not** catch a dangling Homebrew symlink: a dangling symlink cannot be exec'd and `command -v node` skips it, so `companion.sh` resolves a *different* node, the expected command is recomputed from the live process and changes, and plain byte-exact equality refuses first — with a **recoverable** drift that `/kimi:setup` converges. It likewise does not catch the 2026-07-25 dead-node zombie (a config pinning `~/.hermes/node`), which is a byte mismatch. And it proves the exec bit only — not a working Node, not the right arch, not >= 22.5. The bypass is **narrowed, not closed**.
482
+ - **`nodeBin` is derived by parsing the built command back, never by re-resolving.** `tryBuildExpectedHookCommand` now returns the interpreter token, obtained via `parseHookShellCommand(command)` — the exact inverse of how it was built — so it is byte-identical to what the config is compared against **by construction**. Re-calling `resolveNodeBinary` would have been a latent reintroduction of the very bypass being fixed: its no-override path runs `preferStableNodePath`, which does `realpath` I/O and is therefore **not** a pure function of `env`. Had the pinned symlink been unlinked between the two calls (what `brew upgrade node` does), the command would pin the symlink while the probe checked the stale realpath — which may still exist — blessing a hook whose real interpreter was gone. Caught in review before shipping; `tryBuildExpectedHookCommand`, previously untested, now pins this identity.
483
+ - **Machine-readable refusal discriminator.** This is the one refusal whose remedy is *not* "run /kimi:setup" — setup cannot repair a broken Node — yet it emitted a `{config_path}` payload byte-identical to four other refusals. It now carries `refusal_kind: "node-bin-not-executable"` plus `node_bin`, per LLM-caller discipline. It can never co-occur with `drift`: drift requires the equality check to **fail**, this requires it to **pass**, so the new refusal cannot displace a recoverable path. Fail-closed on **any** errno, deliberately diverging from `background-spawn.ts` (which ignores errnos outside `ENOENT`/`EACCES`/`EPERM`) — spawning can afford to try and see; a security verifier cannot.
484
+ - **Review round (Opus code-review + independent Opus skeptic + Codex, three passes).** The skeptic **refuted the change's original premise** and I confirmed it empirically before acting. The code-review pass found the re-resolve defect above, plus three test comments that claimed guarantees the tests did not provide: an assertion captioned "the regression assertion" that read `stderr` (the worker is spawned `stdio: "ignore"`, so it can never fail) and an exit-code assertion that is equally inert (`runAsk` *returns* the failure artifact rather than throwing); and two negative tests captioned as covering the **worker's** re-verify when `runAsk` refuses at the entry gate before any child is spawned. All corrected. The same pass cleared every false-refusal path: root (`X_OK` requires a real exec bit), Windows (`X_OK` degrades to `F_OK`, and win32 is already excluded), NFS/`noexec`/containers (false negatives, never false refusals). Codex supplied the post-launch-mutation cases the other two passes missed.
485
+ - **Real-binary smoke GREEN** (run 2026-07-25 against kimi-code **0.29.1** once the managed OAuth session was restored): `bun run smoke:real` passed **10 / 0 / 43 in 401.36s** — read-only forced writes denied, goal mode reached its finite budget with zero writes (`aborted=true`, the expected steady state), read swarm denied a subagent write, and write swarm stayed confined (`patchBytes=278`, `userTreeClean=true`, `worktreeCleaned=true`). An earlier attempt during the release itself was **auth-blocked** (`auth.login_required`, `records: []` on all 10 cases before any prompt reached the model) and was published as NOT-RUN rather than as a pass; that note is superseded by this run. Both hosts re-pinned to 1.9.1 and verified enforcing (direct + shell probe, deny reason captured, interpreter `/opt/homebrew/bin/node` — the stable symlink v1.9.0 introduced).
486
+ - **No upstream-compat change.** `KIMI_TESTED_MINORS` unchanged; no kimi-code re-certification.
487
+
488
+ ## 1.9.0 — 2026-07-25
489
+
490
+ **Stops the recurring "run /kimi:setup" nag at its source: the canonical hook command no longer embeds the Node *version*, and a refusal caused by a moved hook path now carries a machine-readable drift axis so an agent caller can re-pin and retry once. No self-writing verifier — that design was proposed, adversarially reviewed twice, and rejected.**
491
+
492
+ - **Root cause.** "Installed" is byte-exact equality between the config's `command` and a freshly rebuilt canonical command — the strictness that killed the old `true # …approval-hook.js` substring bypass, and it is not negotiable. But that command embedded **two independently version-stamped paths**: the Node binary (`process.execPath` resolves the Homebrew symlink to `…/Cellar/node/<version>/bin/node`) and the version-stamped plugin install dir. `brew upgrade node` invalidated **both hosts at once**; a plugin update invalidated one. Routine maintenance therefore read as "the plugin keeps breaking." Diagnosed live 2026-07-25: Codex auto-updated 1.8.7→1.8.8 and deleted the old dir while the config still named 1.8.7. A June config backup holding `node/26.0.0` and `node/26.3.0` side by side shows the Node axis had already fired before.
493
+ - **Node axis fixed at the source (`preferStableNodePath`).** `resolveNodeBinary` now prefers `process.argv0` — the path the interpreter was actually invoked with, which `companion.sh` resolves through the stable `/opt/homebrew/bin/node` symlink — but **only when it is absolute AND `realpath`-identical to `process.execPath`**. That guard is the whole safety argument: the substitution provably cannot select a *different* binary, only a more stable *name* for the one already running. Any doubt (relative argv0, `realpath` throw, different target) falls back to `execPath`. Byte-exactness, absoluteness, and the shell probe are untouched. Side benefit: hook and companion now ride the same interpreter by construction — previously the companion could run a new Node while the hook stayed pinned to a Cellar path `brew` had already deleted, which spawns nothing and (exit 127) **reads as ALLOW**. nvm/asdf/mise expose version-stamped paths directly, so `argv0 === execPath` there and behavior is unchanged, not worse.
494
+ - **Structured drift signal.** `InstalledCheck.drift` / `HookInstallStatus.drift` (`{axis: "hook-script" | "node-bin" | "both", installedCommand, expectedCommand}`) is populated **only** when a structurally sound block's command names different paths, and is forwarded into every refusal's `RuntimeError.details` via the shared `hookRefusalDetails`. Strictly advisory: derived *after* byte-exact equality has already failed, it can never influence `installed` — the same contract `nodeExists` classification has always had. Refusals that are *not* re-pin-recoverable (unresolvable command, unreadable config, invalid hook set, duplicate/orphan markers, missing script) carry **no** drift, so a caller cannot mistake them for retryable. The `absent` + stale-bare-table case is classified too — that is the **common** real-world shape, since kimi-code strips markers on every login write and a plugin update then moves the path (both at once is exactly the 2026-07-25 incident).
495
+ - **The caller heals it, not the callee.** All seven model-spawning agents now read `drift_axis`: on `"hook-script"` (`retryable_after_setup: true`) they run `/kimi:setup` for that host and retry **once**; on anything else they surface the refusal and stop. Repair stays a **visible, permission-gated action in the transcript**, taken by the host model — not a silent mutation of a security surface. `"node-bin"`/`"both"` are deliberately never auto-retried: a moved interpreter may be *gone*, and that is a real enforcement gap, not a moved file.
496
+ - **Auto-repin REJECTED (recorded so it is not re-proposed).** An in-verifier self-repair was fully specified, then rejected by two independent adversarial reviews. Four defects were mechanically confirmed: (1) **self-deadlock** — the repin path takes `withKimiConfigLock`, then the install transaction takes it again, and the lock has no reentrancy check (staleness is `!isProcessAlive(owner.pid)`, and the owner is us), so every attempt spins 10s and throws; (2) the "target cannot be steered" premise is **false** — `KIMI_PLUGIN_CC_HOOK_SCRIPT`/`NODE_BIN`/`HOST_ID` override resolution, and every gate reads the same env, so they are self-consistent by construction and supply no independent evidence; (3) **no version-monotonicity bound**, so a surviving old session could pin the *global* block to a pre-1.0.3 hook carrying the CRITICAL exec-delegation bypass — the exact outcome that argument was built to prevent; (4) a **write→spawn TOCTOU** in which a stale session repins to a deleted path inside another session's spawn window, yielding exit 127 → ALLOW → an unenforced `rescue` run. The v1.8.0-lock rebuttal was also rationalization: v1.2.1's objection was *authorization* + *detection*; a lock provides *atomicity*, making an unauthorized write correctly serialized. Full analysis, including why **content/hash verification also fails** (the proposal hashes `approval-hook.js` — 4,325 of 55,661 bytes, 7.8% of enforcement code — while the v1.0.3 CRITICAL fix lives in `rescue-approval.ts`; and hook/companion are two halves of one wire protocol a global version floor cannot express) is preserved in `.claude/hook-pin-durability-spec-2026-07-25.md`.
497
+ - **Migration.** The canonical command changes, so **every existing install drifts once** on upgrade and needs one `/kimi:setup` per host. Enforcement is not lost meanwhile — the old block keeps firing; the plugin refuses to *spawn* until re-pinned. The drift is classified as the benign case (see below) and the agents self-repair it.
498
+ - **Migration message is honest about the cause.** `describeHookCommandDrift` now recognizes when two node paths name the **same file** (`realpath`-compared) and says so — *"Node path spelling changed … these are the SAME interpreter reached by different paths … your Node did not move"* — instead of the pre-existing wording that blamed "a Node version-manager switch between runs", which would have misled every upgrading user. A **gone** interpreter still takes precedence and still reports "no longer exists": that is the unambiguous danger signal and must never be softened into a benign re-pin.
499
+ - **Pre-release review round (Kimi + Opus, converging independently).** Three defects were found and fixed before tagging:
500
+ - **CRITICAL — background rescue/ask would have refused permanently.** `startBackgroundJob` spawned the worker with `process.execPath`, so the child's `argv0` was the fully symlink-resolved (version-stamped) path, while setup — running through `companion.sh`, which execs `$(command -v node)` — pinned the stable symlink. The worker re-verifies the hook (deliberately, so a background job cannot outlive or bypass the check), rebuilt a *different* expected command, and `/kimi:setup` could never converge the two sides. Foreground commands were unaffected, which is exactly why it would have shipped. Now uses `preferStableNodePath` for the no-override default — deliberately **not** `resolveNodeBinary`, whose absolute-path requirement is the *hook-pin* contract, not the *spawn* contract (spawn resolves a bare name via PATH). Regression test added.
501
+ - **The signal never reached the caller.** Agents were told to branch on `drift_axis`, but `formatError` dropped `details` entirely and the failure artifact rendered only code/stage/message — so the field existed only in the SQLite row, reachable via `result --json` for background jobs and *lost outright* for foreground ones. `formatError` now serializes details as one deterministic JSON line (non-serializable values can never suppress the error itself), and the artifact renders a sorted `### Details` section.
502
+ - **The retry could walk past a proven-dead hook.** `/kimi:setup` **install** exited 0 even when its probe *failed*, and only `check` exited nonzero. Since an agent now keys its retry on that exit code, a hook that is byte-exact and readable but cannot deny — a truncated `approval-hook.js` (iCloud sync has done this in this repo), or a half-extracted plugin cache — would pass `verifyHookInstalled` and the command would run unenforced. Any failed probe now exits nonzero, and the agents retry only on a clean exit. `probe: "skipped"` (uninstall) is untouched.
503
+ - Also fixed: agents were told to run `/kimi:setup`, a slash command a `tools: Bash` subagent cannot invoke — they now call `${CLAUDE_PLUGIN_ROOT}/scripts/companion.sh setup`, the same surface the command wrappers use; and `retryable_after_setup` contradicted the new same-file finding (prose said "benign, expected" while the field said "do not retry") for the single most common refusal this release creates. Retryability is now "every differing token is benign": a moved script, or a node token whose spelling changed but still names the same file. A node token naming a **different** file is still never retryable.
504
+ - **No upstream-compat change.** `KIMI_TESTED_MINORS` and all kimi-code surface reasoning are unchanged; this is a plugin-side durability fix, not a kimi-code certification.
505
+
506
+ ## 1.8.8 — 2026-07-25
507
+
508
+ **Certifies kimi-code 0.29.0 + 0.29.1.** Verdict **COMPAT-PRESERVED**; `KIMI_TESTED_MINORS` extended with `{0,29}`.
509
+
510
+ - **V1 safety chain unchanged.** Across 0.28.1→0.29.1, `02-permission` and `03-hooks` are 0-byte diffs. The index-0 hook, first-approve ordering, any-block-wins aggregation, exit-2 denial, empty-matcher behavior, `Bash.command` / `Write.path` / `Edit.path`, `-p` auto/headless behavior, configured+plugin hook merge, swarm subagent stack, and hard concurrency gate remain intact.
511
+ - **Scoped non-empty changes are compatible.** 0.29.0 adds opt-in v2 custom-agent flags the plugin does not pass plus session/provider/model-capability and replay plumbing. 0.29.1 adds MCP timeout defaults and web endpoint/env configuration. None changes PromptJsonWriter output, `session.resume_hint`, permission-context construction, or workspace-write policy.
512
+ - **Experimental v2 refactor preserved the ordinary deny seam, but the original order claim was later corrected.** 0.29.1 replaces ordered pre-execution hook slots with an awaited veto event; ordinary external PreToolUse blocks and the exact smoke below were real. A 2026-07-31 production-registration trace found plan service actually precedes external hooks and can final-allow its exact plan-file write first. v1.9.4 therefore disables experimental-v2 across the tested range; see its entry for the inherited gap and mitigation.
513
+ - **Exact-binary smoke GREEN on latest.** The temp-installed exact-0.29.1 `bun run smoke:real` passed **10 / 0 / 43 in 339.80s**: all read-only forced writes denied, asserted-v2 denial passed through the new veto path, pursue reached its finite budget with zero writes, read swarm denied a subagent write, write swarm stayed confined (`patchBytes=306`, `userTreeClean=true`, `worktreeCleaned=true`), and the non-vacuous out-of-root absolute write was denied. Exact 0.29.0 had already passed the same 10/0/43 matrix.
514
+ - **Headless pursue resume remains upstream-blocked.** Both print drivers still use create-only goal parsing; `resumeGoal()` remains TUI/RPC-only.
515
+ - Edits: `runtime/kimi-version-probe.ts` (`{0,29}` + audit proof), `runtime/stream-json.ts` (verified-through range), version/docs/tests, re-pinned Claude hashes, and regenerated `dist/` + `plugins/kimi-codex/`. Tags: `v1.8.8` and `compat-verified-kimi-code-0.29.1`. Evidence: daily-monitor reports 2026-07-23 and 2026-07-24.
516
+
517
+ ## 1.8.7 — 2026-07-21
518
+
519
+ **Certifies kimi-code 0.27.0 + 0.28.1** — a chained two-minor catch-up (the minors shipped since the v1.8.4-certified 0.26.0). Verdict **COMPAT-PRESERVED** on both; `KIMI_TESTED_MINORS` extended with `{0,27}` and `{0,28}`.
520
+
521
+ - **The two load-bearing safety surfaces are 0-byte diffs across the whole span.** `02-permission` and `03-hooks` are byte-identical 0.26.0→0.28.1 — policy queue (PreToolCallHook index 0, AgentSwarmExclusiveDeny index 1, AutoModeApprove first approve at index 5, only denies between), the hook engine (exit-2 deny, empty matcher = all tools, any-block-wins aggregation), and the full invariant set (Bash.command / Write.path / Edit.path, `-p` auto + headless handlers + resume-hint emission) reconfirmed by direct checks on the released tags.
522
+ - **`01-cli-prompt-mode` (1.7 KB) is commands.ts-only**: the top-level `server` registration is replaced by `web` and the YOLO-vs-Auto help text is corrected; `run-prompt.ts`/`options.ts` are byte-identical and the plugin passes its prompt as the VALUE of `-p`, so consumed argv and `-p` routing are unchanged.
523
+ - **`04-wire-records` is entirely the 0.27.0 session-storage work** (workspace-id registry reuse with safe-id fallback; timestamped debug-export filenames) — session-directory bookkeeping, not `-p` stdout shapes; **0-byte past it**.
524
+ - **`05-session-bootstrap`**: 0.27.0 wires an optional `resolveWorkspaceId` callback into SessionStore; 0.28.1 adds a one-shot `thinking.effort "max"→"high"` migration that strictly re-parses + reserializes `config.toml` — validated `hooks[]` entries survive as data but **all comments are stripped**, exactly the markerless-hook condition the plugin has handled since v1.8.2. A new marker-strip regression simulates that parse→mutate→stringify shape and asserts the host still verifies installed.
525
+ - **The 0.28.1 v2 change** (broadcasting session-level permission-mode switches to already-running subagents) is a propagation fix, not a hook bypass — the v2 external-hook runner is byte-identical across the delta.
526
+ - **Exact-binary smokes GREEN on both releases** (temp-installed exact binaries via `KIMI_PLUGIN_CC_KIMI_BIN`; `bun run smoke:real`): 0.27.0 — 10 pass / 0 fail / 43 assertions; 0.28.1 — 10 / 0 / 43. Full matrix on each: read-only forced-write denials, the `KIMI_CODE_EXPERIMENTAL_FLAG=1` v2 denial lane, pursue budget-abort with zero writes, read-swarm subagent denial, write-swarm confinement (`patchBytes=278`, `userTreeClean=true`, `worktreeCleaned=true`), and the out-of-root absolute-write denial.
527
+ - **Test-only fix:** a Node ≥25 environment failure — the tsx loader's DEP0205 `module.register()` deprecation warning leaked into a spawned companion's stderr assertion in `tests/runtime/setup-command.test.ts`; the assertion now strips Node deprecation warnings before comparing.
528
+ - Edits: `runtime/kimi-version-probe.ts` (`{0,27}`/`{0,28}` + chained audit comments), `runtime/stream-json.ts` (verified-through range), AGENTS.md, CHANGELOG.md, ROADMAP audit log, `tests/runtime/{kimi-version-probe,marker-strip,setup-command}.test.ts`, 4-file version bump 1.8.6 → 1.8.7 + re-pinned surface hashes, regenerated `dist/` + `plugins/kimi-codex/`. Tags: `v1.8.7`, `compat-verified-kimi-code-0.27.0`, `compat-verified-kimi-code-0.28.1`. Evidence: daily-monitor reports 2026-07-18 (0.27.0) and 2026-07-21 (0.28.1).
529
+
530
+ ## 1.8.6 — 2026-07-17
531
+
532
+ **Rescue write-allowlist + verifier hardening, from a k3 (kimi-code 0.26.0) whole-repo self-audit.** A parallel kimi swarm on the new k3 model, cross-checked against the code, surfaced a confirmed parser-divergence write-allowlist bypass, two RCE-class exec-delegating gaps, a batch of per-tool write-flag holes, and two verifier fail-open paths. Every CRITICAL/HIGH was re-verified against the source before fixing; each fix ships with regression tests. No compat change — `KIMI_TESTED_MINORS` still `{…,0,26}`.
533
+
534
+ - **Keystone syntax gate (`hasUnsafeShellSyntax`) — now quote-aware.** The vendored `shell-quote` parser diverges from bash, and a smuggled single-word flag rides that gap past every per-flag check. First cut used word-boundary regexes; a Fable adversarial review then found those both **under-** and **over-**matched, so the gate was rebuilt on two quote-aware passes:
535
+ - a **throwing-env parse** (`parse(cmd, k => { throw on non-empty key })`) that rejects any real `$VAR`/`${…}` reference — including the CONFIRMED CRITICAL **`$IFS`-gluing** (`rg x$IFS--pre$IFS'sh'` → bash splits into `rg x --pre sh`, an RCE, while the parser glues it into one token so the regex — anchored to a word boundary — missed the letter-preceded `$`), the double-quoted `"$VAR"` form, and `${VAR:-flag}`. It leverages the parser's own quote tracking, so it fires only where bash actually expands.
536
+ - a **quote-aware scanner** for the constructs the parser doesn't surface as an expansion: backticks, command/process substitution, the `$'…'`/`$"…"` quoting openers (bash decodes `\xNN` into flag bytes), and **brace expansion** (`find . {-delete,}` → `find . -delete`; `sort {-o,}/tmp/x` → a write — both smuggled a token past the flag checks).
537
+ This also REMOVES the false positives the first-cut regexes introduced: single-quoted literals bash never expands — `grep 'foo $'`, `grep '$(x)'`, `find -name '*.{js,ts}'`, `awk '{print $NF}'` — are now allowed. Verified against a bypass + false-positive battery.
538
+ - **argparse-abbreviation-proof mypy/pytest report flags.** mypy/pytest parse argv with argparse `allow_abbrev`, so `--jun`→`--junit-xml`, `--html-rep`→`--html-report`, `--cache-di`→`--cache-dir`, `--junitx`→`--junitxml` all resolved past the old exact-and-`=` matching (mypy runs no repo code but writes reports/cache to arbitrary paths and can pip-install). Both now match abbreviation-aware (any unambiguous prefix of a dangerous flag), while legit read flags that merely share a prefix region (`--ignore-missing-imports`, `--incremental`, `-rA`) stay allowed.
539
+ - **Second review round (Fable + Opus over the *fixes*) — a CRITICAL, a HIGH, and five MEDIUMs closed.** **(CRITICAL)** the quote-aware keystone rebuild treated a DOUBLE-quoted span as inert, but bash keeps command substitution ACTIVE inside double quotes — `grep "$(id)" file`, `` ls "`whoami`" `` executed (RCE in every write-capable mode; `$VAR` was still caught, only `$(…)`/backtick leaked). The double-quote scan now looks for non-escaped `$(`/backtick while `"\$(x)"`/`` "\`x`" `` stay literal. Then: **(HIGH)** `evaluateInstalled` now runs a whole-file smol-toml parse (`foundHookEntryIsClean`) on the marked-block success path — a `matcher = "*"` (or stray key) placed AFTER the `# === END … ===` comment is still part of the same `[[hooks]]` TOML table, so kimi-code loaded it and disabled the hook while the line-scanned *body* looked clean (fail-open `installed:true`); **(MED)** `sort` bundled short-flag clusters (`sort -rT /tmp`, `-ro file`) that the plain `-o` check missed, now scanned with getopt semantics; **(MED)** `tsc` option names are case-insensitive, so `--outdir`/`--tsbuildinfofile` are matched lowercased (`--outdir` == `--outDir`); **(MED)** `eslint --parser`/`--rulesdir`/`--resolve-plugins-relative-to` load+execute a module from an arbitrary path (code-exec escape); **(MED)** `mypy --config-file` (a config can set `plugins=` → imports Python); **(MED)** `ruff --config` (inline `fix=true` override flips write mode). All verified live against on-disk code before and after. (The same round confirmed the quote-aware keystone already closes `$IFS`-glue, `$'…'` mid-word, and brace `{,}` — a fresh adversarial pass reproduced those only against the pre-rewrite regex version.)
540
+ - **Exec-delegating flags (RCE) rejected for every tool.** `rg --pre <cmd>` (per-file preprocessor), `rg --hostname-bin <cmd>`, and `sort --compress-program <cmd>` (GNU sort spill (de)compressor) all run their VALUE as a command; added to `EXEC_DELEGATING_FLAGS_EXACT`/`_PREFIXES` alongside the existing `--open-files-in-pager`/`-vettool`/`-toolexec`/`-exec` set.
541
+ - **Per-tool write-flag gaps closed.** New per-tool checks reject writes that survive a tool's read/check mode: `tsc --generateCpuProfile/--generateTrace/--tsBuildInfoFile/--outFile/--outDir/--out/--declarationDir` (survive `--noEmit`); `biome check --apply*/--write*/--fix*` (the `-unsafe`/`-only` suffixes dodged the global exact/prefix set); `ruff check --add-noqa/--fix-only/--cache-dir/--output-file` (`--fix-only` dodged the global `--fix`); `cargo --target-dir/--out-dir`; `go test -coverprofile/-cpuprofile/-memprofile/-blockprofile/-mutexprofile/-trace/-outputdir`; joined `eslint -o<path>` + `--cache-location`; `mypy --junit*`/`--*-report`/`--cache-dir`/`--install-types` (argparse `allow_abbrev`-proof by prefix); and pipeline `sort -T`/`--temporary-directory`.
542
+ - **HIGH — `verifyHookInstalled` script-existence check.** A byte-exact `command` match no longer blesses an install on its own: the verifier now confirms the hook SCRIPT file exists and is readable (`access(…, R_OK)`, fail-closed). A pruned versioned-dist directory left the config matching while kimi-code's `/bin/sh -c '<node>' '<script>'` failed to spawn — and kimi-code treats any non-2 exit (including a spawn failure) as ALLOW, silently degrading every refusal gate to auto-approve.
543
+ - **HIGH — marked-block matcher rejection is now parser-based.** The primary present-state path (`validateBlockBody`) validated the managed block with a line scanner (`/^matcher\s*=/`) that a quoted `"matcher"` or literal `'matcher'` key slips past, while kimi-code's real parser honors it and disables the hook (`new RegExp("*")` throws). The body is now also parsed with the vendored `smol-toml` and rejected if any hook entry carries a `matcher` key in any spelling — the same immunity the absent-state fallback (`hasCleanEnforcingHookEntry`) already had. Fail-closed on parse error.
544
+ - **MEDIUM/LOW.** stderr session-id capture is now first-announce-wins across BOTH channels (a later stderr line can no longer overwrite the stdout-meta-pinned id); `writeConfigAtomic` creates the temp config at 0o600 via `O_WRONLY|O_CREAT|O_EXCL|O_NOFOLLOW` (mode passed to `open()`), closing the brief create-then-`chmod` umask window on a credential-bearing file.
545
+ - **Two write-swarm MEDIUMs (memo-continuity gap-check).** A follow-up review of the transcript surfaced two `swarm.ts` findings the main remediation hadn't folded in: **(MED, fail-open version gate)** `assertSwarmSupported` returned without blocking whenever the `kimi --version` probe failed — fine for READ mode (a too-old binary is only degraded, the read-only hook still holds), but UNSAFE for `--write`, whose safe concurrency depends on the hard `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY` cap that only exists on kimi-code ≥0.18.0. On a flaky probe against a 0.12–0.17 binary the env var is ignored, the default `--max-concurrency 1` serialization is enforced nowhere, and racing `coder` subagents corrupt the shared-worktree patch. The gate now **fails CLOSED for write mode** (`throw SWARM_UNSUPPORTED` with the probe reason) while read mode keeps failing open. **(MED, orphan-sweep reaps a live worktree)** `WORKTREE_ORPHAN_TTL_MS` was a flat 6h while `--budget` accepts up to `MAX_DURATION_MS` (24h); the sweep's only liveness signal is the worktree dir's mtime, which is frozen at `git worktree add` time when a run edits only existing files. A long write run (`--budget 12h`) could thus be seen as "idle >6h" and `git worktree remove --force`d by a concurrent run's startup sweep → ENOENT writes, lost patch. The TTL is now derived as `MAX_DURATION_MS + 2h`, so it always exceeds the longest a run can live; orphans (hard-kill leftovers) are still reaped, just after a provably-safe delay. Both are covered by new `swarm.test.ts` regressions (write refuses on a broken probe; read still reaches the hook check; TTL > max budget).
546
+ - **Read-only swarm prompt slimmed (k3 anti-hang).** The kimi-code 0.26.0 coordinator hung when over-prescribed (it emitted a non-sole-tool-call response and never launched, timing out to budget with 0 records) and stalled on a denied preliminary `Bash` size-check. `buildSwarmPrompt` now states the read-only goal + report shape, names the tool constraint (Read/Grep/Glob only, Bash denied), and steers the fan-out to be the first action — without prescribing the `AgentSwarm`/`subagent_type`/`prompt_template` mechanics. Safety is unchanged: the PreToolUse hook (swarm label, policy index 0) denies every write/edit/shell for the coordinator and every subagent regardless of prose.
547
+ - **Process.** The findings came from a kimi k3 `/kimi:swarm` self-audit; every CRITICAL/HIGH was re-verified against the source (the `$IFS`-glue RCE and the parser divergences were reproduced directly against the vendored parser). A follow-up Fable adversarial review of the *fixes* found the `$IFS`-glue hole in the first-cut regex gate and drove the quote-aware rebuild; an Opus correctness pass checked for false positives. (The k3 swarm coordinator itself repeatedly hung — a known upstream k3 limitation — so the reliable internal reviews carried the gap-check.)
548
+ - Edits: `runtime/rescue-approval.ts`, `runtime/hooks/managed-block.ts`, `runtime/hooks/install.ts`, `runtime/cli-client.ts`, `runtime/commands/setup.ts`, `runtime/commands/swarm.ts`; regression tests in `tests/runtime/{rescue-approval,marker-strip,hook-install,cli-client,setup,swarm}.test.ts`; 4-file version bump 1.8.5 → 1.8.6 + re-pinned surface hashes; regenerated `dist/` + `plugins/kimi-codex/`.
549
+
550
+ ## 1.8.5 — 2026-07-16
551
+
552
+ **agent-core-v2 readiness hardening.** Explicitly models kimi-code's experimental-v2 `system.version` stream-json record and adds a persistent real-binary v2 smoke lane, so an eventual v2 default-flip is a non-event instead of a scramble. No behavior change on the default v1 path; v2 remains opt-in.
553
+
554
+ - **`system.version` is now a modeled `SystemVersionRecord`.** agent-core-v2 (selected by a truthy ambient `KIMI_CODE_EXPERIMENTAL_FLAG`, which the plugin inherits) emits `{"role":"meta","type":"system.version","version":"<semver>"}` once before the assistant/tool stream; v1 emits none. Previously this routed to the malformed/diagnostic channel as an unknown meta type (non-fatal — `records[]` and the terminal `session.resume_hint` were never affected). It is now parsed into the `StreamJsonRecord` union, validated (non-empty string `version`), and filtered from consumer `records[]`/`onRecord` exactly like `session.resume_hint` and `turn.step.retrying`. This keeps a benign, expected v2 line out of diagnostics.
555
+ - **Observable out-of-band on `CliClientResult.systemVersion`.** Captured first-announce-wins and surfaced on the result (mirroring `goalSummary`/`sessionId`), so a caller can tell which engine served a run — `undefined` on v1, the kimi-code semver on v2. Diagnostic/observability only; not load-bearing.
556
+ - **New opt-in v2 smoke lane** (`tests/runtime/real-binary-smoke.test.ts`). Runs the forced-write denial under `KIMI_CODE_EXPERIMENTAL_FLAG=1` and asserts (1) no file written + the hook deny marker (the index-0 hook still denies under the native engine) and (2) `result.systemVersion` is defined — proving the flag actually engaged v2 rather than silently falling back to v1. Verified GREEN against the installed 0.25.0 binary (1 pass / 0 fail). Skipped under `bun run check` like the rest of the smoke.
557
+ - Regression: 4 new `stream-json` unit tests (valid parse, resume-hint-not-pre-empted, malformed-version rejection cases). Edits: `runtime/stream-json.ts` (`SystemVersionRecord` + parse), `runtime/cli-client.ts` (`systemVersion` field + capture), the two test files, 4-file version bump 1.8.4 → 1.8.5 + re-pinned surface hashes.
558
+
559
+ ## 1.8.4 — 2026-07-16
560
+
561
+ **Certifies kimi-code 0.26.0.** Extends `KIMI_TESTED_MINORS` to include `{0,26}` after a scoped source audit (COMPAT-PRESERVED) backed by a GREEN exact-`0.26.0` real-binary smoke. Tags `compat-verified-kimi-code-0.26.0`. No runtime behavior change. (Shipped the same day as v1.8.3's 0.25.0 certification — npm `latest` had moved to 0.26.0 mid-audit.)
562
+
563
+ - **Source audit (`0.25.0 → 0.26.0`, scoped).** All **three** primary safety surfaces are **0-byte diffs**: `01-cli-prompt-mode`, `02-permission`, AND `03-hooks` are byte-identical, so argv, default-v1 routing, `permission: 'auto'`, headless handlers, the whole policy queue (`PreToolCallHook` index 0), the hook engine, exit-2 denial, matcher behavior, and any-block-wins aggregation are unchanged from certified 0.25.0. The two non-empty surfaces are compat-benign:
564
+ - `04-wire-records` (32 KB): session-store `workDir` normalization (Windows case-insensitive drive paths); session **forking** (a persisted `forked` `AgentRecord` + a new internal `context.update_token_count` record — neither is a `-p` stdout record the parser consumes, and an unknown type fails safe to the diagnostic channel); provider-manager thinking plumbing; and a `subagent-host.ts` `drainChildBackgroundTasks` addition that holds a subagent open until its background tasks settle and suppresses their terminal notifications — a **lifecycle/settlement change, not a permission-stack change** (drained tasks still fire the index-0 hook; it aligns with the plugin's own settlement-barrier cancellation).
565
+ - `05-session-bootstrap` (16 KB): `config/model.ts` thinking-profile plumbing; an optional `auth: 'oauth'` field added to the MCP HTTP/SSE schemas (**not** `HookDefSchema`, which stays `.strict()`); additive `rpc/core-impl.ts` Global-MCP management + OAuth flows + `deleteSession`/`importContext` (all RPC/host methods off the `-p` path); a `setAdditionalDirs → setBaseAdditionalDirs` rename; and an `includeSubagents` resume flag the plugin never passes. The create/resume hook merge is unchanged.
566
+ - **Direct invariant checks on the 0.26.0 tag.** `tools/builtin/file/` is a 0-byte diff (`Write.path`/`Edit.path` byte-identical); the `deny-all` unshift is still `startBtw()`-only (inside `startBtw()` in `subagent-host.ts`, never the swarm spawn path); `installHeadlessHandlers` and the v1 default persist.
567
+ - **Exact-`0.26.0` real-binary smoke — GREEN.** `bun run smoke:real` against a temp-installed `0.26.0` binary (via the `KIMI_PLUGIN_CC_KIMI_BIN` override): **9 pass / 0 fail, 39 assertions in 376.06s**. Read-only labels denied the forced write; pursue wrote no file through its full budget (aborted at the ceiling); read-only swarm denied a spawned subagent write; write-swarm stayed confined (`patchBytes=278`, `userTreeClean=true`, `worktreeCleaned=true`); the out-of-root absolute write was denied.
568
+ - **pursue `--resume` re-checked (still upstream-blocked).** A read-only investigation of kimi-code 0.26.0 confirmed the headless CLI (`kimi -p`, both v1 and experimental-v2 drivers) has no argv/prompt/session-resume path that calls `resumeGoal()` — per upstream's own docs, goal management is TUI-only; PR #552 restores the goal *snapshot* on `-r` but nothing acts on it. `/kimi:pursue` stays foreground-only and `experimental`; `docs/safety.md` § "Autonomous goal mode" updated to cite the 0.26.0 evidence.
569
+ - Edits: `runtime/kimi-version-probe.ts` (`{0,26}` + full audit comment), AGENTS.md (Version headline + Upstream-compat range), ROADMAP-TO-GA.md (Post-GA audit log entry), `docs/safety.md` (pursue-resume 0.26.0 note), 4-file version bump 1.8.3 → 1.8.4 + re-pinned surface hashes.
570
+
571
+ ## 1.8.3 — 2026-07-16
572
+
573
+ **Certifies kimi-code 0.25.0.** Extends `KIMI_TESTED_MINORS` to include `{0,25}` after a scoped source audit (COMPAT-PRESERVED) backed by a GREEN exact-`0.25.0` real-binary smoke on the clean tree. Tags `compat-verified-kimi-code-0.25.0`. No runtime behavior change — this is a compatibility certification, and it carries v1.8.2's config-rewrite survival unchanged.
574
+
575
+ - **Source audit (`0.24.2 → 0.25.0`, scoped to the six consumed surfaces).** The two primary safety surfaces are **0-byte diffs**: `01-cli-prompt-mode` and `03-hooks` are byte-identical, so argv, default-v1 routing, `permission: 'auto'`, headless handlers, the hook payload, exit-2 denial, matcher behavior, and any-block-wins aggregation are unchanged. The rest are compat-benign: `02-permission` (943 B) only adds `trace_id` to two permission telemetry events; `04-wire-records` (2 KB) forwards Anthropic `supportEfforts`/adaptive-thinking capability data in `session/provider-manager.ts` with no new stream-json record, role/meta type, session-id field, or goal-summary shape; `05-session-bootstrap` (3.9 KB) resolves thinking efforts from the provider profile while still loading workspace dirs, building the permission context, and merging configured + plugin hooks on create and resume.
576
+ - **Invariants re-verified on the released 0.25.0 tag.** `PreToolCallHook` index 0, `AgentSwarmExclusiveDeny` index 1, `AutoModeApprove` the first approve at index 5 (every intervening policy a deny); any-block-wins; empty matcher = all tools; exit 2 blocks; `Bash.command` / `Write.path` / `Edit.path`; `kimi -p` default v1 unless a truthy ambient `KIMI_CODE_EXPERIMENTAL_FLAG` selects agent-core-v2 (still opt-in, still safety-preserving); AgentSwarm subagents on the standard permission stack (`deny-all` remains `startBtw()`-only); `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY` the hard concurrent-subagent ceiling.
577
+ - **Exact-`0.25.0` real-binary smoke — GREEN on the clean tree.** `bun run smoke:real` against the installed `0.25.0` binary: **9 pass / 0 fail, 39 assertions in 419.12s**. Read-only labels (review/challenge/ask/review_gate) denied the forced write; pursue wrote no file through its full wall-clock budget (aborted at the ceiling); read-only swarm denied a spawned subagent's write; write-swarm stayed confined to the throwaway worktree (`patchBytes=278`, `userTreeClean=true`, `worktreeCleaned=true`); the out-of-root absolute write was denied after a real swarm-write dispatch. A supplementary `KIMI_CODE_EXPERIMENTAL_FLAG=1` targeted v2 review-denial also passed. (An earlier rerun hit `auth.login_required` from an expired operator OAuth token — machine state, not a regression; re-login then produced the green run above. An auth-failed smoke is not a passed smoke; the green run is the one that counts.)
578
+ - **Credentials note (carried from v1.8.2).** The managed OAuth token lives in `~/.kimi-code/credentials/kimi-code.json` (mode 0600) and has since the earliest kimi-code — not a per-version migration; `config.toml` never held it. `config.toml` stays credential-bearing (a BYO-provider `apiKey` can live there) and mode 0600.
579
+ - **Note on 0.26.0.** npm `latest` advanced to `0.26.0` after this audit began; it is certified separately (it needs its own install + source audit + smoke) and is not covered by this release.
580
+ - Edits: `runtime/kimi-version-probe.ts` (`KIMI_TESTED_MINORS` += `{0,25}` with the full audit comment), AGENTS.md (Version headline + Upstream-compat range), ROADMAP-TO-GA.md (Post-GA audit log entry), 4-file version bump 1.8.2 → 1.8.3 + re-pinned surface hashes. Daily monitor: `2026-07-16`.
581
+
582
+ ## 1.8.2 — 2026-07-16
583
+
584
+ **Survive kimi-code config rewrites: markers are comments, and kimi-code deletes every comment on every config write. Verification now falls back to byte-exact content identity, and orphan pruning is host-scoped — ending the cross-host setup "seesaw" and the false "not installed" after every kimi login.**
585
+
586
+ - **Root cause (live-captured during diagnosis, 2026-07-16).** kimi-code persists `config.toml` via `stringifyToml(configToTomlData(...))` (`packages/agent-core/src/config/toml.ts`; login flows call it via `managedAuth.ts`) — smol-toml's stringify cannot represent comments, so **every login/settings write deleted both hosts' `# === BEGIN/END kimi-plugin-cc-managed ===` markers** while the `[[hooks]]` tables (data) survived and kept enforcing. Each host then reported "managed block is NOT installed" right after every kimi login (enforcement was never actually lost), and the next `/kimi:setup` on either host **pruned the other host's marker-less live hook as an "orphan"** — the cross-host seesaw that v1.7.0's host-scoped blocks were meant to end, reintroduced through the host-blind prune.
587
+ - **Content-based installed fallback.** When this host's marked block is absent, `evaluateInstalled` now accepts a marker-less `[[hooks]]` table whose decoded `command` is **byte-identical** to the canonical expected command, with the same strict grammar as the managed block (`event = "PreToolUse"`, no matcher, no keys beyond event/command/timeout). Markers were never the security boundary — the exact command equality is — so this weakens nothing: drifted paths, matcher-bearing tables, and foreign-key tables still refuse. The fallback applies ONLY from the absent state; duplicate/orphan/invalid-marked states still demand repair. `setup --check` stays green after a kimi login and surfaces an advisory "re-adorn" note instead of a false failure.
588
+ - **Host-scoped orphan pruning.** `findUnmanagedApprovalHookBlocks` takes an `ownedBy` host id (derived per table via `hostIdFromHookCommand`); install and scoped uninstall now prune only THIS host's marker-less tables. Another host's marker-less table — its live hook after a comment strip — is reported informationally and left byte-untouched. `/kimi:setup --uninstall --all` remains the explicit every-host sweep. Hand-rolled user hooks are still never touched (the `isOurApprovalHookCommand` strictness is unchanged).
589
+ - **Clearer setup output.** `runCheck` now triages marker-less tables three ways: this host's live-but-unmarked hook (advisory note), this host's stale tables (prunable), and other hosts' tables (informational, untouched). `runInstall` distinguishes "re-adorned this host's markers after a kimi-code config rewrite" from "pruned stale cruft".
590
+ - **Safety contract unchanged.** Byte-exact canonical-command equality, strict whole-file TOML validation, fail-closed refusal, and the serialized-locking transaction are all untouched. The one-setup-per-host-per-plugin-update requirement from version-stamped install paths also remains (a candidate for a future auto-repin).
591
+ - **Multi-model review round (Opus + Sonnet + kimi-on-0.25.0).** A HIGH bypass in the first bare-table *line scanner* was caught and fixed: a blank line does not end a TOML table, so a `matcher = "*"` placed after a blank line still belongs to the `[[hooks]]` table — kimi-code loads it (a matcher is a schema-valid string, so whole-file validation passes) then throws at `new RegExp("*")` at execution time and silently disables the hook. All three reviewers converged on the same conclusion: a line scanner cannot see TOML table structure — the panel further showed the matcher could hide behind a **quoted `"matcher"` key** (never matches a `matcher =` regex) or past a **multiline array value** — so the installed decision now uses the **real vendored `smol-toml` parser** (`hasCleanEnforcingHookEntry`): it strips managed-block lines (host isolation), parses the remainder, and accepts only a `hooks[]` entry with `event="PreToolUse"`, byte-exact `command`, **no `matcher` in any spelling**, and no keys beyond `{event,command,timeout}`. Immune to all three blind spots; fail-closed on parse error. `findBareApprovalHookTables` remains ONLY the conservative line-based PRUNE scanner. Also fixed: `--check` now recommends re-adorning markers instead of a contradictory "No action needed" when installed via a bare table, and a `KIMI_PLUGIN_CC_HOST_ID`-override edge that could append a duplicate block (a table whose command byte-equals this host's expected command is now recognized as ours regardless of host-id derivation).
592
+ - **kimi-code 0.25.0 observation (uncertified).** A source audit of 0.25.0 found the v1 safety contract intact (policy index-0 hook, any-block-wins, `Bash.command`/`Write.path`/`Edit.path`, `-p` auto permission) and agent-core-v2 still opt-in behind `KIMI_CODE_EXPERIMENTAL_FLAG` (and safety-preserving if it flips). 0.25.x remains outside `KIMI_TESTED_MINORS` pending the normal source-audit + real-binary smoke gate. **Correction to an earlier working assumption:** the OAuth token is stored in `~/.kimi-code/credentials/kimi-code.json` (mode 0600) and has been since the earliest kimi-code — this is NOT a 0.25.0 migration, and `config.toml` never held the managed token. The plugin still treats `config.toml` as credential-bearing and preserves mode 0600 because a user-configured custom (BYO-key) provider's `apiKey` can still live there, and upstream itself writes the file at 0600.
593
+ - `smol-toml@1.6.1` (the exact version kimi-code vendors) added as a **devDependency** for the new round-trip regression suite (`tests/runtime/marker-strip.test.ts`), which installs both hosts, replays kimi-code's real `stringify(parse(...))` rewrite, and proves verification survives, cross-host pruning is gone, and hand-rolled hooks are preserved.
594
+
595
+ ## 1.8.1 — 2026-07-15
596
+
597
+ **kimi-code 0.24.2 compatibility: extend `KIMI_TESTED_MINORS` with `{0,24}` after a four-lane source audit and green exact-binary smoke.** This patch release clears the H9 newer-than-tested warning for operators whose upstream binary auto-upgraded into 0.24.x.
598
+
599
+ - **Default v1 safety chain unchanged.** Across 0.23.6→0.24.2, permission and live `session/hooks/` diffs are 0 bytes. The PreToolUse hook remains policy index 0, auto-mode approve remains the first approve at index 5, any block still wins across configured/plugin hooks, and `Bash.command` / `Write.path` / `Edit.path` remain intact.
600
+ - **Prompt-mode refactor remains compatible.** The v1 driver still forces auto permission, preserves the plugin's argv, emits the same assistant/tool, retry, goal-summary, and terminal resume-hint shapes, and stays inside the plugin's mandatory budgets and identity-safe cancellation barrier despite upstream's new default background steering and unbounded task waits.
601
+ - **Experimental v2 seam audited.** A truthy ambient `KIMI_CODE_EXPERIMENTAL_FLAG` now selects native agent-core-v2. Its strict hook config, configured+plugin hook merge, snake_case payload, awaited pre-execution deny, and per-agent hook service preserve the effective safety contract; a targeted exact-v2 review smoke denied a forced write. V2's extra `meta/system.version` line is safely diagnostic-only today: it never enters consumer records/prose and does not disrupt terminal session pinning. Explicit modeling remains optional polish.
602
+ - **Exact 0.24.2 smoke GREEN.** The temp-binary v1 suite ran 9 pass / 0 fail, 39 assertions in 261.33s: all read-only forced writes were denied; pursue wrote no file through its full budget; read swarm denied a subagent write; write-swarm remained confined (`patchBytes=278`, `userTreeClean=true`, `worktreeCleaned=true`); and the out-of-root write was denied. The targeted v2 lane ran 1 pass / 8 skip / 0 fail in 11.60s.
603
+ - **Audit-doc correction.** The live v1 hook engine is `session/hooks/`; the historical `agent/hooks/` tree was removed by the relocation commit. Audit commands keep both paths only for cross-version coverage.
604
+ - Reports: `.claude/kimi-code-research/reports/97-upstream-0242-hook-contract.md` through `101-upstream-0242-synthesis.md`. Tags: `v1.8.1` and `compat-verified-kimi-code-0.24.2`.
605
+
606
+ ## 1.8.0 — 2026-07-11
607
+
608
+ **Safety stabilization: fail closed before Kimi starts, protect the shared config as a complete document, and do not resume callers while cancellation teardown is still running.**
609
+
610
+ - **Every model-spawning command now requires a verified hook.** Ask, review, and challenge join rescue, pursue, and swarm in refusing before a Kimi subprocess starts when the current host's PreToolUse block is missing or invalid. The stop-time review gate skips visibly instead of launching an unenforced turn. Background ask re-verifies inside the detached worker so a block removed between enqueue and execution cannot bypass the gate. `KIMI_PLUGIN_CC_SKIP_HOOK_CHECK=1` remains an explicit tests/diagnostics escape hatch and now clearly means bypass every refusal gate.
611
+ - **Setup validates the complete kimi-code config.** The installer vendors the same `smol-toml@1.6.1` parser used by kimi-code, parses the whole `config.toml`, and strictly validates every configured hook before accepting or writing the candidate. A valid plugin block can no longer conceal malformed unrelated TOML, unknown hook fields, invalid event/version combinations, or out-of-range values. `/kimi:setup --check` now exits nonzero on failure while preserving actionable stdout.
612
+ - **Setup mutations are serialized, private, and identity-bound.** Install/uninstall hold `config.toml.kimi-plugin-cc.lock` across the complete read-modify-write transaction, wait for live owners, recover stale locks through an ABA-safe recovery lease, and time out rather than clobbering concurrent host setup. Lock publication is atomic; reads are no-follow, regular-file-only, nonblocking, and capped; ownership is rechecked by inode/token before mutation or removal. A newly-created kimi-code home is mode `0700`; config, temporary config, and lock files are mode `0600`. Existing inline `hooks = [...]` assignments are normalized to canonical `[[hooks]]` tables with an explicit formatting/comment-loss warning before the host block is inserted.
613
+ - **Cancellation is a teardown barrier, not just a signal request.** POSIX cancellation captures ancestry and process identity together, revalidates PID/PGID/start-time before positive or group signals, starts the escalation grace after SIGTERM dispatch, and performs a bounded post-SIGKILL quiescence check. Results and budget errors do not settle until that teardown finishes, closing the normal close-before-escalation race where write-swarm could capture/remove its worktree while a detached descendant was still writing. Snapshot/probe failure and the unavoidable identity-check-to-signal syscall window remain conservative residuals; post-kill non-confirmation is logged after 500ms rather than hanging the host indefinitely, and Windows remains direct-child-only.
614
+ - **kimi-code 0.23.5 retry metadata is first-class.** `role:"meta", type:"turn.step.retrying"` is validated against its exact upstream shape, normalized, and kept out of consumer `records[]`/`onRecord`, like `session.resume_hint`; malformed variants still fail closed into parser diagnostics. Compatibility remains inside the already-certified `{0,23}` minor.
615
+ - **Exact 0.23.5 field proof is green after the parser change.** The full real-binary smoke ran 9 pass / 0 fail in 229.56s: every read-only label denied forced writes, pursue wrote no file across its full budget, read-only swarm subagent writes were denied, write-swarm stayed worktree-confined (`patchBytes=334`, `userTreeClean=true`, `worktreeCleaned=true`), and an out-of-root absolute write was denied.
616
+ - Vendored `smol-toml` retains its upstream BSD-3-Clause license. New regression coverage exercises whole-file parser differentials, hook-schema failures, concurrent/stale setup locks, detached ask re-verification, retry-record filtering, PID-reuse defenses, grace timing, teardown settlement, quiescence, and bounded post-kill observation.
617
+
618
+ ## 1.7.2 — 2026-07-08
619
+
620
+ **Silence the `MODULE_TYPELESS_PACKAGE_JSON` warning in the Codex bundle.** Cosmetic packaging fix; no runtime behavior change.
621
+
622
+ - The root `package.json` declares `"type": "module"`, which covers root `dist/` on the Claude side (Claude Code copies the repo root, package.json included, into its cache). But the self-contained Codex bundle `plugins/kimi-codex/` carried no `package.json`, so when Codex ran the bundled `dist/companion.js` from its cache Node walked up to `~/package.json` (no `type`), emitted `MODULE_TYPELESS_PACKAGE_JSON`, and reparsed as ESM (perf overhead; the warning also leaked into the setup probe's captured deny-reason preview).
623
+ - Fix: `bun run build` now emits `dist/package.json` (`{"type":"module"}`), which the existing runtime mirror copies into `plugins/kimi-codex/dist/`, so the bundled companion resolves its module type locally. Verified in an isolated `$HOME` location: **1 → 0** warnings. `bun run check` green.
624
+
625
+ ## 1.7.1 — 2026-07-08
626
+
627
+ **Post-release hardening of the v1.7.0 host-scoping edges, from a second Codex + Kimi review.** All three were rare-input edge cases on the config-mutating path; no behavior change on the normal path.
628
+
629
+ - **Conservative prune (Codex, Medium).** `findUnmanagedApprovalHookBlocks` now prunes a marker-less table ONLY when its body is exactly our grammar (`event`/`command`/`timeout` + comments). A table that reuses `approval-hook.js` but carries any other key — notably a multi-line `metadata = [ … ]` array whose continuation lines fooled the `[`-boundary check — is left fully intact instead of being partially cut (which had left dangling TOML).
630
+ - **Ambiguous legacy blocks are not clobbered on scoped uninstall (Codex, Medium).** A legacy un-suffixed block whose command isn't the canonical two-single-quoted-token shape can't be attributed to a host, so `hostIdFromHookCommand` returns null. `/kimi:setup --uninstall` now LEAVES such a block (only `--uninstall --all` removes it), so a scoped uninstall can't destroy another host's non-canonical block. Install still adopts/refreshes it (it's being replaced anyway).
631
+ - **64-bit fallback host id (Codex, Low).** The dev-checkout fallback id widened from `host-<sha1[:8]>` (32 bits, a concrete collision was demonstrated) to `host-<sha1[:16]>` (64 bits), so two unrecognized install roots no longer collide and clobber.
632
+ - **Transitional-window guidance (Kimi).** `docs/migration.md` now carries a loud caution: upgrade BOTH hosts to v1.7.0+ before re-running setup (running the old ≤1.6.5 installer after one host migrated can re-clobber), with `/kimi:setup --uninstall --all` as the clean-slate escape hatch.
633
+ - New tests cover the multi-line-array prune, the ambiguous-legacy uninstall/`--all` split, and the widened host id. `bun run check` green.
634
+
635
+ ## 1.7.0 — 2026-07-08
636
+
637
+ **Host-scoped managed blocks: Claude Code and Codex stop clobbering each other's PreToolUse hook in the shared `~/.kimi-code/config.toml`.** A behavior release fixing the cross-host setup collision.
638
+
639
+ - **The bug.** Claude Code and Codex install this plugin to *different, version-stamped* paths (`~/.claude/plugins/cache/…` vs `~/.codex/plugins/cache/…`) but read the **same** `~/.kimi-code/config.toml`. The managed hook block was a **single** block whose `command` was exact-matched to the *running host's* path, so `/kimi:setup` (Claude) and `$kimi-setup` (Codex) **overwrote each other**. Whichever host ran setup last won; the other host's strict verifier then reported "hook path drift" and its write-commands (`/kimi:rescue`, `/kimi:swarm`, `/kimi:pursue`) **refused** while read-only commands only warned. Switching hosts appeared to "need setup redone" every time.
640
+ - **The fix — host scoping.** The managed block marker now carries a `:<host-id>` suffix (`# === BEGIN kimi-plugin-cc-managed:claude-code (vX) ===`). Each host owns, verifies, and uninstalls only its **own** block; setup in one host leaves the other's byte-identical. Host id (`runtime/hooks/install-paths.ts::resolveHostId`) is derived **version-independently** from the hook path (`.claude`→`claude-code`, `.codex`→`codex`, else `host-<sha1[:8]>`; `KIMI_PLUGIN_CC_HOST_ID` overrides), so a plugin upgrade *refreshes* the same host's block instead of accumulating one per version.
641
+ - **Safety contract preserved.** `evaluateInstalled` still does **exact** command equality (no substring bypass like `true # …approval-hook.js`), now keyed per host. Enforcement stays correct under coexistence because kimi-code fires every `[[hooks]]` and aggregates **any-block-wins** — the current host's live hook always denies; another host's stale path fails open harmlessly; a drifted *own* block is caught at the per-command verify gate (prompts a re-setup for that host only).
642
+ - **Migration + cleanup.** A pre-1.7.0 un-suffixed block is **adopted and converted in place** by the current host on its next `/kimi:setup`. Orphaned, marker-less `[[hooks]]` entries that are unambiguously our approval hook (canonical two-single-quoted-token command, `approval-hook.js` under a kimi-marketplace/kimi-plugin-cc tree) are **pruned** — the predicate is strict, so a hand-rolled hook is never removed.
643
+ - **New `--uninstall --all`.** `/kimi:setup --uninstall` now removes only the current host's block (plus legacy + our orphans); `/kimi:setup --uninstall --all` removes **every** host's block from the shared config.
644
+ - **Files:** `runtime/hooks/install-paths.ts` (`resolveHostId`/`hostIdFromHookScript`/`slugifyHostId`/`isOurApprovalHookCommand`), `runtime/hooks/managed-block.ts` (host-aware marker grammar, `parseManagedBlock(contents, hostId)`, `findUnmanagedApprovalHookBlocks`), `runtime/hooks/install.ts`, `runtime/commands/setup.ts` (host-suffixed block, prune, host-scoped uninstall, `--all`). New tests cover two-host coexistence, legacy migration, orphan prune, host-scoped uninstall, `--all`, and host-id derivation. Docs: `docs/safety.md` (§ Host scoping), `docs/migration.md`, `README.md`, `AGENTS.md`.
645
+ - **Adversarial review (Codex + Kimi) before ship.** Fixes folded in: reject a `command` smuggled under a non-`[[hooks]]` table (would falsely verify); prune boundary stops at comment-trailed table headers and only removes tables matching our exact grammar (approval-hook command + `event="PreToolUse"` + no matcher); the orphan predicate requires a real `/kimi-plugin-cc/`|`/kimi-marketplace/` path segment (not a bare substring); marker host ids are case-normalized; and a legacy un-suffixed block is attributed to the host its **command path** derives to (`effectiveHost`) so one host's setup/uninstall never adopts, clobbers, or removes another host's block during migration.
646
+ - **No upstream-compat change.** Tested-minors set and kimi-code surface reasoning are unchanged; this is a plugin-side host-coexistence fix, not a kimi-code certification.
647
+
648
+ ## 1.6.5 — 2026-07-07
649
+
650
+ **kimi-code 0.23.1 compat: extend `KIMI_TESTED_MINORS` with `{0,23}` after a GREEN real-binary smoke.** A patch release that certifies the 0.22.3→0.23.1 minor and clears the H9 "newer than tested max" setup warning for operators on 0.23.x.
651
+
652
+ - **Probe extension** (`runtime/kimi-version-probe.ts`): added `{ major: 0, minor: 23 }` with the per-version audit comment.
653
+ - **Verdict: COMPAT-PRESERVED.** Report 96 found the hook engine unchanged, policy order still hook-first (`PreToolCallHookPermissionPolicy` index 0, `AutoModeApprovePermissionPolicy` index 5), `kimi -p` still compatible with the stream-json parser, write-path field names intact (`path` / `command`), plugin hooks still any-block-wins, and `runShellCommand` plus plugin slash commands still host/RPC-only and off the `kimi -p` path.
654
+ - **New 0.23.x surfaces are benign for this plugin:** upstream added `select_tools` as a default-approved MCP schema-disclosure tool, but the plugin hook still denies unknown tools before upstream default approval and no `READ_ONLY_TOOLS` expansion was needed; persisted observability records, session workDir/index repair, thinking-keep defaults, and workspace-skill listing do not alter the plugin hook or stdout contract.
655
+ - **Smoke GREEN on a temp-installed `kimi --version` 0.23.1:** `bun run smoke:real` ran 9 pass / 0 fail on 2026-07-07. Read-only labels denied forced writes; pursue wrote zero files and parsed `goal.summary`; read-only swarm denied a spawned subagent write; write-swarm kept coder edits in the throwaway worktree (`userTreeClean=true`, `patchBytes=334`, `worktreeCleaned=true`) and denied an out-of-root absolute write.
656
+ - **No safety-surface change:** no hook allowlist broadening, no permission relaxation, no swarm concurrency/default change, and no auto-setup path.
657
+ - **Docs:** `AGENTS.md` (Version line + Upstream-compat "through 0.23.1"), `ROADMAP-TO-GA.md` (audit-log entry), and `runtime/stream-json.ts` (verified-through comment). Surface report: `.claude/kimi-code-research/reports/96-upstream-0231-surface.md`. Tags: `v1.6.5` and `compat-verified-kimi-code-0.23.1`.
658
+
659
+ ## 1.6.4 — 2026-07-05
660
+
661
+ **kimi-code 0.22.3 compat: extend `KIMI_TESTED_MINORS` with `{0,22}` after a GREEN real-binary smoke.** A patch release that certifies the 0.21.1→0.22.3 minor and clears the H9 "newer than tested max" setup warning for operators on 0.22.x.
662
+
663
+ - **Probe extension** (`runtime/kimi-version-probe.ts`): added `{ major: 0, minor: 22 }` with the per-version audit comment.
664
+ - **Verdict: COMPAT-PRESERVED.** Reports 94 and 95 found the hook engine unchanged, policy order still hook-first (`PreToolCallHookPermissionPolicy` index 0, `AutoModeApprovePermissionPolicy` index 5), write-path field names intact (`path` / `command`), and plugin slash commands plus `runShellCommand` still host/RPC-only and off the `kimi -p` path.
665
+ - **New 0.22.x surfaces are benign for this plugin:** prompt-mode background drain happens after assistant-output flush and remains bounded by the plugin's AbortController budgets; shell output caps affect huge tool-result content only; image originals are stored under Kimi session state, not the user worktree; model/thinking/provider config changes do not alter permissions; server auth-bypass flags are a separate subcommand stack.
666
+ - **Smoke GREEN on a temp-installed `kimi --version` 0.22.3:** `bun run smoke:real` ran 9 pass / 0 fail on 2026-07-05. Read-only labels denied forced writes; pursue wrote zero files and parsed `goal.summary`; read-only swarm denied a spawned subagent write; write-swarm kept coder edits in the throwaway worktree (`userTreeClean=true`, `patchBytes=334`, `worktreeCleaned=true`) and denied an out-of-root absolute write.
667
+ - **Hook-missing UX:** swarm still refuses without the PreToolUse hook, but the refusal now names both repair commands: Claude Code `/kimi:setup` and Codex `$kimi-setup`. Codex swarm skill guidance surfaces the same repair path and no longer suggests the skip env.
668
+ - **Docs:** `AGENTS.md` (Version line + Upstream-compat "through 0.22.3"), `ROADMAP-TO-GA.md` (audit-log entry), and `runtime/stream-json.ts` (verified-through comment). Surface reports: `.claude/kimi-code-research/reports/94-upstream-0220-surface.md` and `95-upstream-0223-surface.md`. Tags: `v1.6.4` and `compat-verified-kimi-code-0.22.3`.
669
+
670
+ ## 1.6.3 — 2026-07-01
671
+
672
+ **Deterministic post-run Kimi Code title sync for plugin-created sessions.** A patch release that restores human-readable session names in Kimi Code without reintroducing the old v0.4 Wire/web title-assignment path.
673
+
674
+ - **Automatic deterministic titles.** After a successful `kimi -p` run returns or resumes a usable session id, the runtime computes titles from plugin-owned command metadata (`Kimi <Command>: <summary>`) and updates Kimi Code session state best-effort. The model never writes titles.
675
+ - **Scoped to user-facing commands.** Title sync covers ask, review, challenge, rescue, pursue, swarm, and `swarm --write`; `review_gate` remains intentionally excluded to avoid noisy Stop-hook sessions.
676
+ - **Manual titles preserved.** Sessions with `isCustomTitle: true` are skipped, matching Kimi Code's manual-title behavior. The sync preserves other state fields and does not update `updatedAt`.
677
+ - **Metadata hardening.** The helper resolves `KIMI_CODE_HOME` consistently, validates `session_index.jsonl` entries under `<kimiHome>/sessions`, rejects unsafe symlink paths, caps metadata reads, skips oversized index lines, writes `state.json` atomically, preserves file mode, and logs only short best-effort warnings.
678
+ - **Docs/tests.** README and migration docs now describe post-run title sync and the loss of v0.4 pre-run Wire/web title assignment. Tests cover helper safety cases plus ask/review command-level sync and `review_gate` exclusion. `bun run check` green. Tag: `v1.6.3`.
679
+
680
+ ## 1.6.2 — 2026-07-01
681
+
682
+ **kimi-code 0.21.1 compat: extend `KIMI_TESTED_MINORS` with `{0,21}` after a GREEN real-binary smoke.** A patch release that certifies the 0.20.x→0.21.1 minor and clears the H9 "newer than tested max" setup warning for operators whose binary auto-upgraded to 0.21.x.
683
+
684
+ - **Probe extension** (`runtime/kimi-version-probe.ts`): added `{ major: 0, minor: 21 }` with the per-version audit comment.
685
+ - **Verdict: COMPAT-PRESERVED.** Source audit report 93 found `02-permission.diff` and `03-hooks.diff` both 0 bytes across 0.20.2→0.21.1; `options.ts`, `agent/records/`, `workspace-local.ts`, and `tools/builtin/file/{write,edit}.ts` are also unchanged on the load-bearing axes. `run-prompt.ts` still hard-codes `permission:'auto'`; the only scoped `run-prompt.ts` change is a cleanup timeout after the writer flush.
686
+ - **New 0.21.0 surfaces are off-path or benign:** plugin slash commands are RPC/host-initiated and absent from `kimi -p`; the thinking-effort/model-catalog refactor is provider plumbing the plugin does not consume; compaction and record migrations are replay/history internals, not live stdout record-shape changes. The `runShellCommand`/`cancelShellCommand` RPC watch remains discharged: still RPC/TUI-only.
687
+ - **Smoke GREEN on `kimi --version` 0.21.1:** `bun run smoke:real` ran 9 pass / 0 fail on 2026-07-01. Read-only labels denied forced writes; pursue wrote zero files and parsed `goal.summary`; read-only swarm denied a subagent write; write-swarm kept coder edits in the throwaway worktree (`userTreeClean=true`, `patchBytes=334`) and denied an out-of-root absolute write.
688
+ - **Docs:** `AGENTS.md` (Version line + Upstream-compat "through 0.21.1"), `ROADMAP-TO-GA.md` (audit-log entry), `runtime/stream-json.ts` (verified-through comment), and `docs/upstream-compat-audit.md` (plugin-command watch surface). Surface reports: `.claude/kimi-code-research/reports/93-upstream-021-surface.md` and `93-upstream-021-adversarial.md`. `bun run check` green. Tags: `v1.6.2` and `compat-verified-kimi-code-0.21.1`.
689
+
690
+ ## 1.6.1 — 2026-06-26
691
+
692
+ **kimi-code 0.20.0 compat: extend `KIMI_TESTED_MINORS` with `{0,20}` (source-audit certified; the real-binary smoke was quota-blocked).** A patch release that certifies the 0.19.x→0.20.0 minor. The only runtime change is the probe-array extension; there is no behavior change. Operators whose binary auto-upgraded past the `{0,19}` tested max (PR #334 background auto-upgrade; npm went straight 0.19.2→0.20.0, no 0.19.3) were tripping the H9 "newer than tested max" warning at `/kimi:setup`; this clears it for 0.20.x.
693
+
694
+ - **Probe extension** (`runtime/kimi-version-probe.ts`): added `{ major: 0, minor: 20 }` with the full per-version audit comment.
695
+ - **Verdict: COMPAT-PRESERVED**, by a byte-level source audit (not a green smoke — see below). `02-permission.diff` is 0 bytes AND `03-hooks.diff` is 0 bytes (both `agent/hooks/` and `session/hooks/`); `policies/index.ts`, `pre-tool-call-hook.ts`, `run-prompt.ts`, `options.ts`, and `agent/records/` are **all 0-byte** 0.19.1→0.20.0. `PreToolCallHookPermissionPolicy` is still index 0, `AgentSwarmExclusiveDeny` index 1, `AutoModeApprove` the first approve at index 5. A **broad-sweep risk scan over every file changed OUTSIDE the five scoped diffs** found ZERO new permission/approval decisions anywhere outside the (0-byte) permission+hooks dirs, and no swarm-subagent spawn/permission change — so read/write-swarm `coder` subagents are still gated solely by the index-0 hook. (Diffed against the 0.19.1 tag, the array's last narrative anchor; 0.19.1→0.19.2 was already 0-byte on every load-bearing surface — report 86 — so no signal is lost.)
696
+ - **The 0.20.0 changes are all compat-benign for a `kimi -p` wrapper:**
697
+ - **#1040** AGENTS.md-oversized `warning` agent event: **swallowed on `-p`** (`run-prompt.ts:495 case 'warning': return;` — no `stdout.write`, shared with `subagent.*`/`compaction.*`/`goal.updated`). Invisible to the role-keyed `runtime/stream-json.ts` parser; reaches only the RPC `getSessionWarnings` accessor (TUI/kimi-web) + the logger.
698
+ - **#1065** `Write` auto-creates missing parent dirs (`ensureParentDirectory` recursive `mkdir` on ENOENT). The `path` field name is **intact** (`WriteInputSchema = z.object({ path, content })`; `Bash` still `command`), so `rescue-approval.ts::extractFilePath` is unaffected (the v1.4.1 lesson). The `mkdir` runs on the parent of an **already-hook-approved** path → can only create dirs INSIDE a path the index-0 hook approved; no workspace escape.
699
+ - **#1062** tool-result budget: adds a `truncated` flag to tool-result **content** (`loop/tool-call.ts` `normalizeToolResult`), NOT the serialized record **shape** (`records/` + `run-prompt.ts` 0-byte). It also persists tool results >50,000 chars to `<agent.homedir>/tool-results/<stem>-<uuid>.txt` (`agent/turn/tool-result-budget.ts`; `homedir = this.agent.homedir` = the **kimi home, not the workspace cwd**) — a kimi-internal artifact off the user's tree, same class as `~/.kimi-code/logs/`. Does NOT violate "read-only commands write zero files in the repo".
700
+ - **`-C`→`-c` continue rename** (`commands.ts`, + hidden `-C` alias): off our flag set (`-p`/`-r`/`--output-format`/`-m`/`--skills-dir`); `run-prompt.ts`/`options.ts` 0-byte.
701
+ - **New `runShellCommand`/`cancelShellCommand` RPC** (CoreAPI/SessionAPI): a **HOST-initiated** shell exec (TUI `!command` / kimi-web) that calls `bash.resolveExecution().execute()` directly, **bypassing the permission stack + PreToolUse hook** — but **not model-reachable** (not a model tool; absent from `installHeadlessHandlers` and the whole `apps/kimi-code/src/cli/` `-p` path), and the plugin never opens an RPC channel. Unreachable for the plugin today. **WATCH (next audit):** re-confirm it stays RPC/TUI-only — it is the first permission-bypassing shell-exec in agent-core.
702
+ - **`forcePluginSessionStartReminder`** resume override (`rpc/core-impl.ts`): set ONLY via `reloadSession` (the `/reload` RPC flow); the plugin's `-p -r` resume uses plain `harness.resumeSession` → never set. `config/` is 0-byte (the 0.19.0/#812 workspace-local `additional_dir` auto-load is unchanged; `GitCwdWriteApprove`, its sole consumer at index 17, stays dead below auto-approve on `-p`).
703
+ - **`kimi server`/`web` daemon stack** (`cli/sub/server/*`): a separate transport, never invoked; its new `stdout.write`s are off the `-p` path.
704
+ - **Smoke NOT run for this certification.** `bun run smoke:real` against the operator's 0.20.0 binary went **RED on a provider `403 "usage limit for this billing cycle"`** — `records:[]` on every label, the model never issued a single tool call (**0 hook-bypasses observed**). This is the **operator-billing-state false-alarm class** (cf. the `auth.login_required` note in `docs/upstream-compat-audit.md`), **not** a compat break — a true break shows the model *attempting* a write and the hook *not* denying. The operator elected to certify on the source audit (manual byte-level + multi-agent re-audit) and skip the quota-blocked smoke; **re-run `bun run smoke:real` once quota refreshes** to earn the end-to-end proof.
705
+ - **Docs:** `AGENTS.md` (Version line + Upstream-compat "through 0.20.0"), `runtime/stream-json.ts` (verified-through comment), surface report `.claude/kimi-code-research/reports/88-upstream-0200-surface.md`. `bun run check` green. Tags: `v1.6.1` and `compat-verified-kimi-code-0.20.0`.
706
+
707
+ ## 1.6.0 — 2026-06-23
708
+
709
+ **Repackage the Codex plugin as a self-contained `plugins/kimi-codex/` subfolder to end Claude Code/Codex surface crossover.** The Codex sidecars added under v1.5.x placed `skills/` at the repo root — which is also the Claude Code plugin root — and Claude Code auto-discovers a top-level `skills/` directory by convention. So the 12 Codex skills were also loading as Claude Code skills, producing a triple commands+agents+skills surface and a safety asymmetry. This release isolates the Codex package without breaking the Claude Code surface or duplicating maintenance.
710
+
711
+ - **New self-contained Codex plugin root: `plugins/kimi-codex/`** — contains `.codex-plugin/plugin.json` (`skills: "./skills/"`), the 12 `skills/`, and a **byte-mirror of the runtime** (`scripts/companion.sh`, `scripts/review-gate-hook.sh`, `dist/**`). Codex copies a plugin root to `~/.codex/plugins/cache/$MARKETPLACE/$PLUGIN/$VERSION/` on install and forbids `../` escapes, so the package must bundle everything it needs. The repo root no longer has `skills/` or `.codex-plugin/`, so Claude Code is back to its intended **commands + agents** surface. `.agents/plugins/marketplace.json` stays at the repo root with `source.path → "./plugins/kimi-codex"`.
712
+ - **Closes a safety asymmetry.** The write-capable Codex skills (`kimi-rescue`, `kimi-pursue`, `kimi-swarm-write`, `kimi-setup`, `kimi-cancel`) declare `allow_implicit_invocation: false` only in `agents/openai.yaml`, which Claude Code ignores — so while they leaked into Claude Code they were model-invocable there, whereas the equivalent slash commands are deliberately human-only. Moving the skills out of the Claude Code scan root removes that exposure entirely.
713
+ - **Single-sourced version.** `scripts/surface-registry.ts` `PLUGIN_VERSION` now imports `KIMI_PLUGIN_CC_VERSION` from `runtime/version.ts` (it was a 7th hard-coded version source). A new test asserts `PLUGIN_VERSION === KIMI_PLUGIN_CC_VERSION === package.json` version.
714
+ - **Generator + gate hardening** (`scripts/generate-surfaces.ts`): write mode now mirrors the runtime payload into the subfolder (0755 on shell scripts) and prunes stale skill dirs + stale mirrored files; `--check` byte-compares the mirror against the freshly built root and detects orphaned generated files. `bun run check` now builds **before** the surface check, and the drift gate covers `dist` **and** `plugins/kimi-codex`.
715
+ - **New tests**: repo-root `skills/` absence (Claude Code skill-leakage guard) + subfolder presence; bundled `companion.sh` is a byte copy of root; `resolvePluginPaths` precedence (`CLAUDE_PLUGIN_DATA` wins over `PLUGIN_DATA` when both set).
716
+ - **Claude Code regression audit: none.** The v1.5.x shared-file edits (shell env-var alias dance in `companion.sh`/`review-gate-hook.sh`, the `paths.ts` `?? PLUGIN_DATA` fallback, the `review-gate.ts` inline-payload preference with transcript fallback) all short-circuit to the original behavior whenever the Claude environment variables are set, and the load-bearing PreToolUse approval hook + its strict-exact verifier are untouched.
717
+ - **Verified out-of-band by Codex** (not by `bun run check`): a live Codex install loading skills from `plugins/kimi-codex/skills/` and the manifest passing Codex's real schema — reinstall the marketplace + run the `$kimi-ask` product smoke. `bun run check` green locally.
718
+
719
+ ## 1.5.1 — 2026-06-23
720
+
721
+ **kimi-code 0.19.1 compat: extend `KIMI_TESTED_MINORS` with `{0,19}` after a GREEN real-binary smoke.** A patch release that certifies the 0.18.0→0.19.1 jump. The only runtime change is the probe-array extension; there is no behavior change. Operators whose binary auto-upgraded past the 0.18 tested max (PR #334 background auto-upgrade) were tripping the H9 "newer than tested max" warning at `/kimi:setup`; this clears it for 0.19.x.
722
+
723
+ - **Probe extension** (`runtime/kimi-version-probe.ts`): added `{ major: 0, minor: 19 }` with the full per-version audit comment. Backed by a **GREEN `bun run smoke:real` (9 pass / 0 fail)** on the operator's 0.19.1 binary: review/challenge/ask/review_gate forced writes hook-denied; pursue multi-turn goal wrote zero files (`goal.summary` parsed cleanly, turnsUsed:2 tokensUsed:73631); a read-only swarm subagent's forced write hook-denied; and **both write-swarm assertions held on 0.19.1** — a `coder` subagent's edits landed only in the throwaway worktree (patchBytes=306, `userTreeClean=true`) and an out-of-trusted-root absolute write was hook-denied. "Tested" is earned end-to-end on 0.19.1, not source-reading-only.
724
+ - **The 0.18→0.19 minor (#812 `add-dir` support) is compat-benign.** It added a `--add-dir <dir>` flag, plumbed `additionalDirs` through `Session`, and widened `GitCwdWriteApprovePermissionPolicy` to approve writes within cwd OR any additional dir. It is a no-op for the plugin — **not** because `additionalDirs` is empty (#812 also wired an unconditional auto-load of project-local `.kimi-code/local.toml` `additional_dir` into the `-p` create+resume bootstraps via `rpc/core-impl.ts:238,363`, so it is **not** guaranteed empty even without `--add-dir`), but because: `GitCwdWriteApprovePermissionPolicy` is the **only** permission consumer of `additionalDirs` and it sits at **index 17**, below `AutoModeApprovePermissionPolicy` (index 5), so on the `-p` auto path it is structurally unreachable; read-only commands deny all writes at the index-0 hook; and our write commands confine to a single root via `rescue-approval.ts`, which never reads `additionalDirs`. The 0.19.1 smoke proves confinement empirically (write-swarm `userTreeClean=true`, out-of-root write hook-denied). (`isWithinWorkspace` with an empty list is byte-for-byte the old `isWithinDirectory(cwd)` for the non-`-p` modes where the policy actually runs.)
725
+ - **Safety chain re-verified intact.** `03-hooks.diff` is 0 bytes (both `agent/hooks/` and `session/hooks/` byte-identical 0.18.0→0.19.1); `policies/index.ts` is byte-identical (`PreToolCallHookPermissionPolicy` still index 0, `AutoModeApprovePermissionPolicy` still the first approve at index 5); `permission:'auto'` still hard-coded in `run-prompt.ts`.
726
+ - **Off-path / cosmetic only.** #963 adds a new `turn.ended` terminal `reason:'filtered'` (provider content filter) surfaced as a human string — a new failure *reason*, not a new stdout record *shape*, so the role-keyed stream-json parser is unaffected. 0.19.1 over 0.19.0 is `ci:`/`fix(acp)`/`fix(web)` only (0-byte load-bearing diff). #821 (detach-to-background) was already triaged in the forward-scans.
727
+ - **Next-audit note (no action):** #812 (0.19.0) — **not** #992 — wired `.kimi-code/local.toml` `additional_dir` auto-load into the `-p` create AND resume bootstraps for all transports (#992 only re-routed that read's kaos handle to fix an ACP bug). Persisted additional-dirs are upstream-auto-approvable via `GitCwdWriteApprove` but stay hook-bound for us; the "plugin never passes `--add-dir` ⟹ `additionalDirs` empty" assumption is now broken upstream. Re-confirm each audit that the index-0 hook still pre-empts `GitCwdWriteApprove`.
728
+ - **Docs:** `AGENTS.md` (Version line + Upstream-compat "through 0.19.1"), `runtime/stream-json.ts` (verified-through comment), `ROADMAP-TO-GA.md` (audit-log entry). Surface report: `.claude/kimi-code-research/reports/85-upstream-0191-surface.md`. `bun run check` green. Tags: `v1.5.1` and `compat-verified-kimi-code-0.19.1`.
729
+
730
+ ## 1.5.0 — 2026-06-20
731
+
732
+ **Open-thread sweep: model-invocable `kimi-swarm-write` agent, a `--budget` safety ceiling, hardened write-swarm smoke, and a local-first CI decision.** A batch closing the threads left open after v1.4.1, each resolved to a concrete state.
733
+
734
+ - **New: `agents/kimi-swarm-write.md`** (write-capable, `color: red`; auto-discovered, no `plugin.json` change) — the v1.4 "human-only" deferral is **lifted**. The main Claude thread can now dispatch a write fan-out on its own judgement. This is a safe extension because auto-dispatch widens **no** write surface and removes **no** bound: the agent runs the identical `runSwarm --write` code, so edits still land only in the ephemeral throwaway worktree, the index-0 PreToolUse hook still gates every `coder` subagent (the `swarm-write` label's rescue allowlist scoped to the forge-proof trusted root), the result is still a **patch the user reviews and applies — the plugin never applies or commits**, and `--budget` + default `--max-concurrency` 1 + the hook requirement all still hold. It is in fact a *less* dangerous agent than the already-shipped write-capable `kimi-pursue`, which writes directly into the workspace; write-swarm's output is a patch that never reaches a real tree without a human merge. The field-proof gating this was the v1.4.1 real-binary write-swarm smoke (GREEN against 0.18.0). Strict triggering: the description demands BOTH signals — many disjoint write targets AND explicit fan-out intent — and steers single edits to `kimi-rescue`, read-only fan-outs to `kimi-swarm`, and autonomous loops to `kimi-pursue`. Default `--max-concurrency` stays **1**. The `/kimi:swarm --write` slash command stays human-only (`disable-model-invocation: true`). The plugin now ships **seven** subagents.
735
+ - **`--budget` gains a 24h ceiling** (`runtime/parsing.ts::MAX_DURATION_MS`). The budget is the SOLE hard wall-clock bound on pursue/swarm, so a typo'd or absurd value (`999999h`, a pasted nanosecond count) would effectively *disable* the one guarantee those modes rest on. `parseDurationMs` now hard-fails `INVALID_ARGS` above 24h rather than silently clamping (a wrapper LLM should see the rejection). 24h is far above any legitimate budget (pursue defaults to 45m, swarm to 30m) yet finite, so the AbortController always fires. Tests cover the boundary (24h / 1440m / 86400s accepted; 25h / 1441m / 86401s / 999999h rejected).
736
+ - **Hardened the write-swarm escape smoke (Test B).** The out-of-root deny assertion depended on a subagent quoting the rescue denial verbatim through the `agent_swarm_result` aggregation — a paraphrase made it absent even when the safety invariant held (flaky). Split into a deterministic, model-phrasing-independent structure: the **hard** non-vacuous guard is now "the coordinator emitted an `AgentSwarm` tool call" (`"name":"AgentSwarm"` in the records — a structural fact, not prose), proving the no-escape-file result reflects DENIAL rather than a swarm that never launched; the deny-reason string is downgraded to a **soft** `console.warn` diagnostic. The PRIMARY safety invariant (not one escape file landed outside the trusted root) is unchanged.
737
+ - **CI smoke: local-first, deliberately no schedule.** Resolved the "wire the smoke to CI" thread by deciding *against* a recurring CI run. The real-binary smoke's natural cadence is "before release", best run **locally against your own kimi-code subscription** — no secret, no recurring token bill (`docs/ci.md` now makes the local path the documented primary route, and clarifies that any CI API key lives in GitHub's *encrypted secret store*, never in the repo — the YAML references only the secret name). `smoke.yml` stays manual-dispatch and inert-until-configured; its default `kimi_version` bumped `0.15.0 → 0.18.0` (so a manual run exercises the write-swarm smoke) and the job timeout `20 → 30` min (the two real write-swarm fan-outs).
738
+ - **Deferred with rationale (not code).** **H1** (runtime-side allowlist post-validation as defense-in-depth behind the hook) stays a dedicated future effort — it is an explicitly ~2-3 day architectural change, and it sits *behind* a primary gate that is now field-proven by the real-binary smokes; rushing a safety mechanism into a batch is worse than a clean deferral. **H5** (per-spawn thinking control) remains upstream-blocked — kimi-code exposes no `--thinking`/`--no-thinking` CLI flag (only a read-only `alwaysThinking` capability flag), so there is nothing to wire.
739
+ - **Docs:** README (six → seven subagents), AGENTS.md (Version line + the v1.4 "human-only" clause lifted), `docs/safety.md` (the write-swarm agent rationale: patch-only, less dangerous than pursue), `commands/swarm.md`, `docs/ci.md` (local-first + encrypted-secret clarification). `bun run check` green.
740
+
741
+ ## 1.4.1 — 2026-06-20
742
+
743
+ **Critical write-path fix (caught by the new write-swarm real-binary smoke): the rescue allowlist read the wrong path field, so `Write`/`Edit` were denied on every real run.** `runtime/rescue-approval.ts::extractFilePath` read `toolInput.file_path` (the Anthropic/Claude Code convention), but **kimi-code's `Write` and `Edit` tools name the field `path`** (`packages/agent-core/src/tools/builtin/file/{write,edit}.ts`: `z.object({ path })`; there is no `MultiEdit` and `file_path` appears nowhere as a tool param). So for **every** write-capable command — `/kimi:rescue`, `/kimi:pursue`, and the new `/kimi:swarm --write` — a real `Write`/`Edit` was denied with "rescue cannot evaluate … input with no path field" (fail-CLOSED — safe, but the file-edit tools simply never worked against kimi-code; only allowlisted Bash could mutate, and most write-shaped shell is rejected too). This was invisible to the unit suite, which mocks `file_path` everywhere — it only surfaced once the **first real-binary write test** ran. Fix: `extractFilePath` now reads `path` (preferred) and falls back to `file_path` (forward/backward compat). With the fix, in-workspace `Write`/`Edit` are allowed and out-of-workspace ones denied — the allowlist finally behaves as designed.
744
+
745
+ - **New: real-binary write-swarm smoke** (`tests/runtime/real-binary-smoke.test.ts`, gated by `KIMI_PLUGIN_CC_SMOKE=1`). The first POSITIVE real-binary proof (every prior smoke only asserted denial): **Test A** runs the real `runSwarm --write` and asserts a `coder` subagent's edits LAND in the throwaway worktree (captured `.patch` contains the sentinel, AgentSwarm actually fanned out), the **user's real tree is byte-identical + git-clean**, and the worktree is cleaned up; **Test B** asserts a subagent's absolute-path write OUTSIDE the trusted root is hook-denied with the rescue out-of-workspace reason. Both **GREEN against kimi-code 0.18.0** (patch=334 bytes, user tree untouched, worktree cleaned). This is the field-proof the v1.4.0 entry flagged as outstanding; it immediately paid for itself by catching the path-field bug.
746
+ - **Tests:** `rescue-approval.test.ts` adds a regression test that the kimi-code `path` field is evaluated (in-workspace `path` → allow; out-of-workspace `path` → deny) and that a missing path field denies with "no path field"; the existing `file_path` tests still pass (fallback). `bun run check` green.
747
+ - **Process note:** the bug also exposed that the PreToolUse hook runs from compiled `dist/` (the installed managed-block command), so a `runtime/*.ts` fix is inert in a real run until `bun run build` recompiles `dist/` — the first re-run after the source fix still failed for this reason. Documented for future write-path debugging.
748
+
749
+ ## 1.4.0 — 2026-06-20
750
+
751
+ **Write-capable swarm (`/kimi:swarm --write`): parallel code-editing in a throwaway worktree → reviewable patch.** Adds the first WRITE mode to swarm. Where read-only swarm fans `explore` subagents out for review, `--write` runs the coordinator and `coder` (write-capable) subagents inside an **ephemeral detached git worktree off the user's HEAD**, lets them edit disjoint targets there, captures the result as an applyable `.patch` artifact, and removes the worktree. **The user's real working tree is never touched, and the plugin never applies or commits — the main Claude thread owns the merge** (the load-bearing "main thread owns git" invariant). Design A (one worktree for the whole swarm) — kimi-code's `AgentSwarm` spawns subagents in-process sharing the coordinator's cwd (`subagent-host.ts:362`), so per-subagent worktrees are impossible without abandoning `AgentSwarm`; the single throwaway worktree IS the blast radius. Human-only (`disable-model-invocation: true`); there is no `kimi-swarm-write` agent yet.
752
+
753
+ This shipped after a **3-way adversarial spec review** (safety / kimi-contract / convention lenses). Two reviewer blockers were resolved by direct verification against the vendored kimi-code 0.18.0 source: (1) the hook-payload `cwd` for an in-process subagent equals the coordinator spawn cwd (one `HookEngine` per session, `cwd: kaos.getcwd()`, `session/index.ts:178`), and (2) **swarm subagents use the standard permission stack — no deny-all** (the lone `DenyAllPermissionPolicy.unshift` is inside `startBtw()`, the side-question path, NOT the swarm spawn path), so a `coder` subagent's writes actually land and are gated solely by our hook. (Fixed a stale `kimi-version-probe.ts` comment that had mis-cited swarm subagents as inheriting deny-all.)
754
+
755
+ - **New hook label `swarm-write`** (`runtime/hooks/approval-policy.ts`): allows `AgentSwarm` + the read-only set; routes write/edit/shell through the **rescue allowlist verbatim** — but scoped to a **forge-proof trusted worktree root** (`KIMI_PLUGIN_CC_WORKSPACE_ROOT`, exported by the same plugin spawn that sets `KIMI_PLUGIN_CC_CMD`), NOT the hook payload `cwd`. The model inside kimi cannot set an env var on its own process, so confinement does not depend on upstream payload-cwd semantics. **Fail-closed**: a missing trusted root denies all writes. git mutation and the singular `Agent` tool stay denied.
756
+ - **Worktree lifecycle** (`runtime/git.ts`): `createEphemeralWorktree` (off HEAD, under the plugin's own `worktreesDir` — never inside the user repo), `captureWorktreePatch` (`git add -N` intent-to-add + `git diff --binary`, **untruncated**, so new files are captured WITHOUT writing loose objects into the shared object DB — keeping "plugin never mutates git state" literally true), `removeWorktree` (force, with prune + on-disk fallback), `pruneWorktrees`, `hasBornHead`, `isWorkingTreeDirty`. Patch captured on **every** terminal path (success/cancel/budget/failure) BEFORE the worktree is removed; a startup sweep reaps orphans left by a hard kill.
757
+ - **Bounds & gates.** `--write` requires kimi-code **≥ 0.18.0** (the hard `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY` cap — below it a write fan-out has no peak bound), a git repo with a committed HEAD (clean `WRITE_SWARM_NOT_A_REPO` / `WRITE_SWARM_NO_HEAD` refusals), and the PreToolUse hook (refuses without it). Default `--max-concurrency` is **1 for write** (serialize — disjoint-target partitioning is prompt-only) vs 4 for read. Bases on HEAD: a **loud warning** fires when the working tree is dirty (uncommitted work is not in the worktree). The coordinator prompt forbids git mutation and nested `AgentSwarm`.
758
+ - **Lineage:** reuses `command_type:"rescue"` (write-capable, like pursue), `agent_profile "<swarm-write>"`; `/kimi:status` / `/kimi:result` / `/kimi:cancel` work unchanged. The result report prepends a patch-handoff header pointing at the `.patch` file (`git apply <path>`).
759
+ - **Runtime:** `runtime/parsing.ts` (`--write` boolean), `runtime/commands/swarm.ts` (`runWriteSwarm`, `executeSwarmJob` gains a `writeMode` seam threading the worktree spawn cwd + trusted root, `SWARM_WRITE_DEFAULT_MAX_CONCURRENCY` = 1, capture/cleanup/sweep), `runtime/cli-client.ts` (`swarmWriteWorkspaceRoot` → env), `runtime/paths.ts` (`worktreesDir`), `runtime/types.ts` (`swarm-write` log label).
760
+ - **Tests:** `swarm.test.ts` (`--write` parse + composition, write concurrency default = 1, write prompt), `approval-policy.test.ts` (swarm-write allows AgentSwarm/read, confines to the TRUSTED env root not payload cwd, fail-closes on a missing root, forwards deny, denies `Agent`), new `git-worktree.test.ts` (real-repo create → edit → capture-an-applyable-patch incl. new files → remove, main tree untouched). `bun run check` green. A gated real-binary write-swarm smoke (write-lands-in-worktree-only, user-tree-unchanged) is the remaining field-proof before any concurrency raise or write agent.
761
+
762
+ ## 1.3.0 — 2026-06-20
763
+
764
+ **Model-invocable `kimi-swarm` + `kimi-pursue` agents (every command now mirrors to an agent) + enforced swarm concurrency default.** Adds the two remaining Claude Code subagents — `kimi-swarm` (read-only parallel review fan-out) and `kimi-pursue` (experimental autonomous goal mode) — so the main Claude thread can dispatch them autonomously, not only via the human-typed `/kimi:swarm` / `/kimi:pursue` slash commands. This completes the command↔agent mirror that review/challenge/ask/rescue already had (all commands carry `disable-model-invocation: true`; agents are the model-invocable path). **Auto-dispatch widens no safety surface:** the index-0 PreToolUse hook fires on every tool call of every turn for all agents — read-only labels (review/challenge/ask/swarm) deny writes; rescue/pursue apply the workspace allowlist and cannot mutate git state — and the two heavy modes keep their mandatory hard ceilings (swarm `--budget` + default `--max-concurrency`; pursue `--budget`) whoever launches them.
765
+
766
+ - **New: `agents/kimi-swarm.md`** (read-only, `color: green`; auto-discovered, no `plugin.json` change). Its description requires an explicit user breadth-with-parallelism intent plus an anti-trigger ("do not auto-promote a single, unscoped, or diff-shaped review into a per-file swarm — use kimi-review"), so Claude does not over-eagerly fan out. Foreground by default; refuses without the `/kimi:setup` hook.
767
+ - **New: `agents/kimi-pursue.md`** (write-capable autonomous, `color: red` — the highest-caution surface). Reuses the rescue trust boundary (workspace allowlist + index-0 hook on every continuation turn; no git mutation), bounded by the mandatory `--budget` (default 45m). Its description requires an explicit hands-off-autonomy request and steers single bounded tasks to `kimi-rescue`, so Claude never auto-promotes a fix or a question into a goal loop. Foreground-only, no `--resume` (goalId ≠ sessionId); refuses without the hook.
768
+ - **Enforced concurrency default (the real safety change).** Because the fan-out is now auto-dispatchable, an unbounded peak is no longer acceptable. `runtime/commands/swarm.ts` resolves `--max-concurrency` to a default of **4** (`resolveSwarmMaxConcurrency` → `SWARM_DEFAULT_MAX_CONCURRENCY`) when the user passes none, so `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY` is **always** exported and every swarm run — agent-dispatched or human-typed — is peak-bounded by construction on kimi-code 0.18.0+ (older binaries still ignore the env var; the `--budget` wall-clock ceiling remains the always-on hard bound on total cost). Override with an explicit `--max-concurrency N`. This changes the prior behavior, where an unset value fell back to kimi-code's internal concurrency ramp. pursue needs no analogous change — its `--budget` ceiling is already mandatory and defaulted.
769
+ - **Adversarial review drove the hardening.** Each agent went through the same 4-lens review (contract fidelity / convention / auto-invocation safety / doc accuracy). For swarm it confirmed the zero-write-surface claim is load-bearing-correct and surfaced the cost/runaway gap — which produced the concurrency default, the tightened triggering, and restricting the background-detach hint to explicit user requests. pursue was reviewed against the same lenses with the focus on whether a model-invocable write-capable autonomous agent is acceptable given the rescue-allowlist + per-turn-hook + mandatory-budget bounds.
770
+ - **Runtime:** `runtime/commands/swarm.ts` adds `SWARM_DEFAULT_MAX_CONCURRENCY` + `resolveSwarmMaxConcurrency` (applied at the spawn call site; `executeSwarmJob` now takes a non-optional `maxConcurrency`); `runtime/parsing.ts` documents that swarm.ts owns the default. No runtime change for pursue — the addition is the agent file + docs only.
771
+ - **Tests:** `swarm.test.ts` asserts the default is applied when `--max-concurrency` is unset and that an explicit value overrides it. `bun run check` green.
772
+ - **Docs:** README (four → six subagents), AGENTS.md, `docs/safety.md`, and `commands/swarm.md` document both new agents, the uniform command↔agent safety model (auto-dispatch widens no write surface and removes no cost/autonomy bound), and the swarm concurrency default.
773
+
774
+ ## 1.2.7 — 2026-06-19
775
+
776
+ **`/kimi:swarm`: split `--cap` into a soft total-count hint + a hard `--max-concurrency` ceiling.** A fast-follow surface correction to v1.2.6, which had overloaded a single `--cap N` to mean *both* a soft prompt-injected total-subagent-count hint *and* a hard concurrency ceiling (`KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY`). A `/kimi:ask` shape consult flagged the **"cap-as-total-count illusion"**: a user reading `--cap 5` (and the injected prompt's "≤5 subagents") reasonably expects a *total*-cost bound, but the env var only caps *peak concurrency* — a coordinator can still launch many subagents sequentially. Overloading one value onto two different risk levers (lifetime total vs. simultaneous spend) hid the real semantics.
777
+
778
+ - **`--cap N`** is now purely the SOFT total-subagent-count hint injected into `buildSwarmPrompt` (advisory; the hook is stateless and can't count subagents). It no longer touches any env var.
779
+ - **`--max-concurrency N`** (new) is the HARD ceiling on how many subagents run *at once*, exported as `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY` on kimi-code **0.18.0+** (older binaries ignore the unknown env var). The two flags are independent: `--cap 20 --max-concurrency 4` means "aim for ≤20 total, never more than 4 running simultaneously".
780
+ - The always-on hard bound on the whole run remains the `--budget` wall-clock ceiling (default 30m). Concurrency ≠ total count, so `--budget` stays the real bound on total cost; `--max-concurrency` bounds peak parallelism.
781
+ - **Runtime:** `runtime/parsing.ts` adds `SwarmArgs.maxConcurrency` + a `--max-concurrency` case (sharing a `parsePositiveIntFlag` helper with `--cap`, so both apply the same `Number.isInteger && > 0` predicate upstream's `resolveSwarmMaxConcurrency` requires); `runtime/commands/swarm.ts` threads `--max-concurrency` (not `--cap`) into `CliClientOptions.swarmMaxConcurrency`. No compat change, no new write/permission surface — `--max-concurrency` only sets a concurrency-bounding env var; the `swarm` hook label and read-only allowlist are untouched.
782
+ - **Tests:** `swarm.test.ts` asserts the split — `--cap` does NOT set `maxConcurrency`, `--max-concurrency` is validated as a positive integer, and the two are independently parseable. `bun run check` green.
783
+
784
+ ## 1.2.6 — 2026-06-19
785
+
786
+ **kimi-code 0.18.0 compatibility + `/kimi:swarm` hard concurrency cap.** Extends `KIMI_TESTED_MINORS` to `{0,17}` and `{0,18}` (the 0.16.0→0.18.0 jump — 0.17.0/0.17.1/0.18.0 — another out-of-band auto-upgrade past the tested 0.16 max, re-firing the H9 "newer than tested max" warning), and wires kimi-code 0.18.0's new `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY` env var (PR #888) into `/kimi:swarm`.
787
+
788
+ - **Compat (COMPAT-PRESERVED, source-audit-reproduced).** `03-hooks.diff` is **0-byte** (both `agent/hooks/` and `session/hooks/`) and `pre-tool-call-hook.ts` is 0-byte 0.16.0→0.18.0; `PreToolCallHookPermissionPolicy` is **still index 0**, `AgentSwarmExclusiveDenyPermissionPolicy` index 1, `AutoModeApprovePermissionPolicy` index 5 (first approve). The only permission change is a NEW `GoalStartReviewAskPermissionPolicy` (#839, "guided goal authoring") at index ~10, *after* auto-mode-approve — an `ask` gated to a *model-issued* `CreateGoal` in NON-auto mode that returns early when `permission.mode === 'auto'`, so it is triple-dead on the `-p` auto path and (an `ask`) cannot approve a write; it does not affect `/kimi:pursue` (which uses the `/goal` command path under auto, hook-gated every turn). `options.ts` is **byte-identical** (argv intact); `run-prompt.ts` changes only in a telemetry refactor (the `started` event moved into harness `sessionStartedProperties`), with the permission-forcing chain and the stream-json writer (`PromptJsonWriter`/`resume_hint`/`goal.summary`) unchanged.
789
+ - **Off-path additions.** A new `kimi server`/`kimi web` subcommand stack **and** session ARCHIVE (`archived` flag + `archive()`/`includeArchive` in the session store + rpc core-api), both from PR #625 "Kimi web app + daemon gateway" — the **Kimi web** surface. The plugin owns its own SQLite job store, never invokes `kimi server`, and never reads kimi's session list, so this is off the `-p` path. Also: OAuth-error fidelity (provider-manager throws the original error instead of re-wrapping as `loginRequired`), git-context process disposal, a turn-counter restore fix (record-restore path) — all internal.
790
+ - **`/kimi:swarm` `--cap` is now a HARD concurrency ceiling on 0.18.0+.** `--cap N` was a soft prompt-injected subagent-count hint (the hook is stateless and can't count subagents). On kimi-code 0.18.0+, `swarm.ts` now also exports `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY=N` per-spawn (via `CliClientOptions.swarmMaxConcurrency` → `cli-client.ts::buildEnv`), so kimi-code's `SubagentBatch` runs at most N subagents concurrently. Older binaries ignore the unknown env var (the soft hint stays the only count bound there); the `--budget` wall-clock ceiling remains the always-on hard bound. Concurrency ≠ total count, so the cap bounds *peak* parallelism, not lifetime total.
791
+ - **Smoke (GREEN, against installed 0.18.0).** The 0.16.0→0.18.0 audit was *prepared* in a cloud session with no kimi binary, so its Phase 1b smoke was deferred to a pre-merge gate. It was then run locally against the operator's installed **0.18.0** binary before merge: **7 pass / 0 fail** — review/challenge/ask/review_gate forced writes hook-denied; pursue's multi-turn goal wrote **zero files** (`goal.summary` parsed cleanly, `turnsUsed:2`); a spawned swarm subagent's forced write hook-denied. A six-reviewer + independent adversarial re-verification of the 0.16.0→0.18.0 jump **and** the new `--cap` wiring (the one surface report 81's smoke didn't cover) all returned **CONFIRMED-SAFE** — the `--cap` → env value round-trips safely across 19 edge inputs against upstream's identical positive-integer validator, with zero new write surface. Tag `compat-verified-kimi-code-0.18.0`.
792
+
793
+ - **Runtime:** `runtime/kimi-version-probe.ts` adds `{0,17}` + `{0,18}`; `runtime/cli-client.ts` adds the `swarmMaxConcurrency` option (env-overlaid in `buildEnv`, recorded in the spawn diagnostics log); `runtime/commands/swarm.ts` threads `--cap` through `executeSwarmJob`; `runtime/parsing.ts` documents the two-tier `--cap`.
794
+ - **Tests:** `cli-client.test.ts` asserts `swarmMaxConcurrency` reaches the child as `KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY` (and stays unset when omitted), via a new `KIMI_MOCK_ECHO_ENV` capability in the stream mock.
795
+ - **Docs:** slimmed the AGENTS.md "Version" + "Upstream compat" lines to a lean current-state summary, relocating the per-version audit narrative here and to `ROADMAP-TO-GA.md` (the detailed per-version reasoning also lives in `runtime/kimi-version-probe.ts` comments).
796
+
797
+ ## 1.2.5 — 2026-06-17
798
+
799
+ **kimi-code 0.16.0 compatibility.** Extends `KIMI_TESTED_MINORS` to `{0,16}`. The operator's binary auto-upgraded 0.15.0→0.16.0 within a day, re-firing the H9 "newer than tested max" warning. COMPAT-PRESERVED: `permission/`, the hook engine, and `run-prompt.ts` are **0-byte** vs 0.15.0; the only CLI argv change registers a new `kimi vis` subcommand (a visualization server — off the `-p` path; our flags are untouched), and the `records/`/`session/`/`replay/`/`agent/` churn (a compaction refactor, a new `llm-request-logger`, replay-build additions) is internal, off the `-p` stdout stream. Backed by a GREEN `bun run smoke:real` on the 0.16.0 binary (7 pass / 0 fail; read-only labels hook-denied, pursue wrote zero files, swarm subagent write denied). Tag `compat-verified-kimi-code-0.16.0`.
800
+
801
+ - **Runtime:** `runtime/kimi-version-probe.ts` adds `{ major: 0, minor: 16 }`.
802
+
803
+ ## 1.2.4 — 2026-06-16
804
+
805
+ **kimi-code 0.15.0 compatibility.** Extends `KIMI_TESTED_MINORS` to `{0,15}` so the `/kimi:setup` version probe stops firing the H9 "newer than tested max" warning for operators whose kimi binary auto-upgraded to 0.15.0. COMPAT-PRESERVED: the four scoped diffs (0.14.3→0.15.0) leave the permission queue, hook engine, `run-prompt.ts`, and CLI argv **0-byte** (re-confirmed independently by `git diff` byte-count, not just the routine's report); the only scoped change is `records/`+`session/` persistence churn off the `-p` path (PR #786 drops `app_version`/`resumed` from the `.records/` metadata artifact, a `SessionSkillRegistry` rename, a static model-capability lookup) plus an additive `transport:'sse'` MCP config variant the plugin never writes. Backed by a GREEN `bun run smoke:real` on the 0.15.0 binary (7 pass / 0 fail; read-only commands hook-denied, pursue wrote zero files, swarm subagent write denied). A real patch bump (not docs-only) because extending the tested-minors array is a runtime change. Tag `compat-verified-kimi-code-0.15.0`.
806
+
807
+ - **Runtime:** `runtime/kimi-version-probe.ts` adds `{ major: 0, minor: 15 }`.
808
+ - **Docs currency pass:** revived this changelog (pointer banner above); corrected a stale `auto-mode-approve at index 4`→`5` parenthetical in `docs/safety.md` (drifted since kimi-code 0.14.1 inserted a policy at index 1); refreshed `CONTRIBUTING.md` (dead `tests/wire/` live-test reference → `bun run smoke:real`), the `smoke.yml` / `docs/ci.md` example kimi-code pin (0.9.0 → 0.15.0), and the `docs/upstream-compat-audit.md` playbook (hook diff-scope now names the load-bearing `session/hooks/`).
809
+
810
+ ## Post-1.0 releases (summary — full detail in [ROADMAP-TO-GA.md](./ROADMAP-TO-GA.md#post-ga-audit-log))
811
+
812
+ - **1.2.3** — 2026-06-12 — verified kimi-code 0.12.0→0.14.1 compat (4-reviewer audit + adversarial pass + GREEN smoke); extended `KIMI_TESTED_MINORS`.
813
+ - **1.2.2** — 2026-06-09 — H3 closed: an unknown stream-json top-level role is forward-compat (surfaced out-of-band on `StreamJsonOutcome.unknownRecord`, no longer `malformed`).
814
+ - **1.2.1** — 2026-06-09 — hardening: H4 (actionable hook-drift diagnosis), H8 (installed kimi-code plugin notice at setup), H9 (out-of-range version warning flags "newer than tested max").
815
+ - **1.2.0** — 2026-06-09 — read-only `/kimi:swarm` parallel-review fan-out, built on kimi-code 0.12.0's `AgentSwarm` tool.
816
+ - **1.1.1** — 2026-06-09 — verified kimi-code 0.12.0 compat; corrected stale "double-gated goal mode" docs (0.12.0 removed the experimental-flag gate).
817
+ - **1.1.0** — 2026-06-03 — experimental `/kimi:pursue` autonomous goal mode + `goal.summary` stream-json parser.
818
+ - **1.0.5** — 2026-06-03 — verified kimi-code 0.7/0.8/0.9 compat.
819
+ - **1.0.4** — 2026-05-31 — verified kimi-code 0.6.0 compat.
820
+ - **1.0.3** — 2026-05-29 — **rescue allowlist flag hardening (critical RCE fix)** — exec-delegating / report-writer flags rejected.
821
+ - **1.0.2** — 2026-05-29 — kimi-code 0.5.0 compat.
822
+ - **1.0.1** — 2026-05-27 — extended `KIMI_TESTED_MINORS` to 0.3 + 0.4.
823
+
824
+ ## 1.0.0 — 2026-05-26 (GA)
825
+
826
+ > **GA release.** Closes the kimi-code 0.2.0 stream-json session-meta compat gap discovered in alpha.4 production smoke, plus the alpha.4 Round-4 closeout polish items (parser `=value` rejection, safety.md template), plus H6 (kimi-code version probe) per the post-hotfix Codex audit, plus two review-smoke catches (stderr regex tightening, missing challenge test). Two parallel deep audits (Claude opus + Codex via codex-rescue) over the kimi-code 0.1.1→0.2.0 source diff converge: session-id capture is the only break that affects our plugin invariants; hook contract, exit-code semantics, cancellation behavior, config schema, and output framing are all byte-identical between kimi-code 0.1.1 and 0.2.0. Live review-smoke against kimi 0.2.0 (8m 37s) returns clean. **391 tests pass, drift gate clean.**
827
+
828
+ ### Critical fix — kimi-code 0.2.0 compatibility
829
+
830
+ - **Session id capture now reads `role:"meta", type:"session.resume_hint"` from stdout stream-json** (the new transport kimi-code 0.2.0 introduced in [PR #47](https://github.com/MoonshotAI/kimi-code/pull/47)). In kimi 0.2.0 the resume hint moved off stderr — kimi-plugin-cc alpha.4 captured nothing under the new version, so `kimi_session_id` was `null` on every job. Resume/replay broken across the board. The loud `warnIfSessionIdMissing` stderr surface added in alpha.4 G3 caught this in production smoke before the GA tag — exactly the failure mode it was designed to catch.
831
+ - **Session id format widened.** kimi-code 0.2.0 emits `session_<uuid>` instead of bare `<uuid>`. The cli-client stores the token verbatim and round-trips it via `kimi -r <token>` — we treat it as opaque. The stderr-fallback regex accepts both formats so 0.1.x users on text-output mode keep working alongside 0.2.0+ users on stream-json.
832
+ - **Stream-json parser learned `role:"meta"`.** Previously meta records were rejected as "unknown role" malformed. Now `meta.session.resume_hint` produces a structured `SessionResumeHintRecord`; unknown meta types still surface to the malformed channel (forward-compat for 0.3.x — we won't crash on new meta types, just log them for diagnostics).
833
+ - **Meta record filtered from consumer-facing `records[]`.** Commands iterating `result.records` only see assistant/tool roles. The `onRecord` streaming callback also skips meta — wrappers wiring up live UI updates never see plumbing records.
834
+
835
+ ### Review-smoke catches (kimi 0.2.0 review against the GA candidate)
836
+
837
+ - **Stderr fallback regex tightened to anchored full-UUID.** Initial widening to accept `session_<uuid>` used the loose pattern `session_[0-9a-f-]{8,}`, which would have accepted `session_--------` (8 dashes) or any 8+ char hex-dash token. The "anchored full-UUID regex" safety invariant documented in `AGENTS.md` is preserved by requiring both alternations to match a full UUID payload — `session_<uuid>` and bare `<uuid>` are now symmetric. Tests cover five malformed forms (too short, wrong length, missing dashes, non-hex chars) explicitly.
838
+ - **`parseChallengeArgs` `=value` rejection test added.** The `parseKnownFlags` shared helper makes the code correct transitively, but the test gap meant a future refactor could regress the challenge path undetected. All four forms (bare/assignment × thinking/no-thinking) now have explicit assertions under the `"challenge"` command label.
839
+
840
+ ### H6 — kimi-code version probe (Codex post-hotfix audit Area 8, addressed pre-GA)
841
+
842
+ - **New `runtime/kimi-version-probe.ts`.** Spawns `kimi --version`, parses output, compares against a `KIMI_TESTED_MINORS` allow-list of `{major, minor}` pairs (currently `0.1.x`, `0.2.x`). Soft-fails — if the probe itself fails (kimi missing, spawn error, unparseable output), we record nothing because the hook probe will surface a clearer error. Only loud-warns when the version is **demonstrably** out of range.
843
+ - **Wired into `/kimi:setup` (install + check paths).** The warning shows up in setup's warnings array and surfaces on stdout for users. `KIMI_PLUGIN_CC_SKIP_VERSION_PROBE=1` opts out (useful for CI environments without kimi).
844
+ - **Why this matters.** kimi-code 0.2.0 is wire protocol `1.1`; a future 0.3.0 could replay older sessions with an invisible warning and produce flattened output we never capture (per Codex audit reading of `cf2227e` / `2004aed`). The version probe gives users early signal before a silent breakage bites them. Belt-and-suspenders with the alpha.4 `warnIfSessionIdMissing` (which fires *after* a job demonstrates capture failure) — H6 fires *before* any job, on the theory that "you're running an untested kimi" is worth knowing.
845
+ - Tests: parser cases (bare semver, `v` prefix, pre-release, garbage), tested-range membership, formatted warning content, probe behavior under missing-binary / timeout / non-zero-exit paths.
846
+
847
+ ### Parser closeout (Codex Round 4)
848
+
849
+ - **`--thinking=value` / `--no-thinking=value` now produce the canonical removal message.** Previously the assignment form fell through to the generic "Unknown flag" path because the case statements only matched exact tokens. A wrapper agent reading the generic error would have thought the fix is to drop the `=value` rather than the flag itself. New `isRemovedThinkingFlag(token)` helper unifies the exact + assignment forms across all three parsers (ask, rescue, review/challenge).
850
+
851
+ ### Docs
852
+
853
+ - **`docs/safety.md` managed-block template** now uses `vX.Y.Z` placeholder (no more drifting alpha.X strings) and shows the shell-quoted command shape that `runtime/hooks/install-paths.ts::buildHookShellCommand` actually writes, plus a footnote explaining the round-trip.
854
+ - **`AGENTS.md` invariant 1** rewritten for dual-source session capture (stdout meta record for 0.2.0+, stderr fallback for 0.1.x). Captured token semantics — verbatim round-trip — now explicit.
855
+ - **`README.md` Architecture** updated to reflect the stdout meta-record transport.
856
+ - **`ROADMAP-TO-GA.md`** adds H6 (wire-protocol version guard) per Codex post-hotfix audit finding Area 8: kimi-code 0.2.0 is wire protocol `1.1`; future minors may silently replay older sessions without surfacing warnings. Launch-time version-floor probe deferred to v1.0.x or v1.1.
857
+
858
+ ### Tests
859
+
860
+ - `tests/runtime/stream-json.test.ts` — 3 new tests: parse `meta.session.resume_hint`, reject malformed meta with missing session_id, forward-compat reject unknown meta types as malformed (not crash). Stderr regex test extended to cover `session_<uuid>` form.
861
+ - `tests/runtime/cli-client.test.ts` — 3 new integration tests: stdout-only meta capture, both-channels first-announce-wins, onRecord callback skips meta.
862
+ - `tests/runtime/parsing.test.ts` — 3 new tests for `=value` form rejection across all three parsers.
863
+ - `tests/helpers/mock-kimi-stream.ts` — new `KIMI_MOCK_ANNOUNCE_VIA` env var (`stderr` | `stdout-meta` | `both`) so tests can exercise both 0.1.x and 0.2.0+ resume-hint transports without authoring separate fixtures.
864
+
865
+ **391 tests pass, drift gate clean.**
866
+
867
+ ### Roadmap closures incidental to GA
868
+
869
+ - **H2 (session-id stderr format coupling) — closed by upstream + alpha.5 hotfix.** H2 prescribed a machine-readable session record in stream-json. kimi-code 0.2.0 shipped exactly this (`role:"meta", type:"session.resume_hint"`); the alpha.5 hotfix consumes it. The stderr regex remains as a 0.1.x fallback.
870
+ - **H3 (stream-json parser coupling to kimi-code internals) — partially closed.** The forward-compat behavior for unknown meta types (surface to malformed channel, never crash) is now in place. The hard-coded `apps/kimi-code/src/cli/run-prompt.ts:NNN` line references in the parser's doc comments have been replaced with file-only references — drift across kimi-code versions no longer points at stale line numbers. The remaining H3 work (treating unknown top-level roles as forward-compat instead of malformed) deferred to v1.1 — the current "malformed" treatment is conservative-safe and changing it requires a deeper review of consumer assumptions.
871
+ - **H6 (wire-protocol version guard) — closed.** See above section.
872
+
873
+ ### Verified against real kimi 0.2.0
874
+
875
+ Production smoke (working-tree companion against the user's installed kimi 0.2.0):
876
+
877
+ - `/kimi:ask` happy-path → returns prose AND captures `kimi_session_id: "session_<uuid>"` from the stdout meta record.
878
+ - `/kimi:review main "spot any GA blockers"` → completed in **8m 37s** thinking-on (well under the 1800s budget); session id captured; review itself caught two real issues in this candidate (the loose stderr regex and the missing challenge test, both fixed in this commit).
879
+ - `warnIfSessionIdMissing` does NOT fire on successful jobs (no false-positive).
880
+ - `/kimi:cancel` reaps the descendant tree cleanly (alpha.3 invariant preserved).
881
+ - `/kimi:setup --check` strict-equality verifier catches stale hook paths from prior alpha versions (caught in this smoke — alpha.4 install was pointing at alpha.3's hook script). Re-install clean. New version probe surfaces no warning since kimi 0.2.0 is in `KIMI_TESTED_MINORS`.
882
+ - Parser hard-rejection of `--no-thinking foo` and `--no-thinking=true` both surface the canonical removal message.
883
+
884
+ ### Acknowledgments
885
+
886
+ The kimi-code 0.2.0 compat break was found by the alpha.4 production smoke test loop. Two parallel audit agents (Claude opus + Codex via codex-rescue) ran independent change-surface audits against the kimi-code 0.1.1 → 0.2.0 diff and converged: the session-meta gap is the only break in the plugin's invariants. Codex additionally surfaced the wire-protocol-1.1 forward-compat risk now closed by H6. The kimi-driven review-smoke against the GA candidate caught two final issues (the stderr regex over-widening and the missing challenge-path test). Three layers of independent review (kimi, Claude opus, Codex), each catching things the others missed.
887
+
888
+ ## 1.0.0-alpha.4 — 2026-05-26
889
+
890
+ > **Roadmap update**: alpha.4 closes G1 + G3 + L2. G2 deferred to v1.1 as H4 (Node version manager soft-recovery). New H5 added (per-spawn thinking control via kimi-code CLI, pending upstream). See [ROADMAP-TO-GA.md](./ROADMAP-TO-GA.md).
891
+
892
+ ### User directive
893
+
894
+ Thinking is enabled for all user-facing commands (ask, review, challenge, rescue). Previous diagnosis — that review hung at the 10-minute default budget — was a budget-sizing problem, not a flag problem.
895
+
896
+ ### Changed
897
+
898
+ - **Budget constants raised for the thinking-on workflow.** `KIMI_ASK_PROMPT_TIMEOUT_MS` 300s → 900s; `KIMI_REVIEW_PROMPT_TIMEOUT_MS` 600s → 1800s; new `KIMI_RESCUE_PROMPT_TIMEOUT_MS = 1800s` (rescue no longer shares the ask budget — it runs multi-step apply/test/verify loops under thinking-on and needs the full headroom). `KIMI_REVIEW_GATE_TIMEOUT_MS` unchanged at 8s; comment now honest about what it assumes (user has `default_thinking = false` or a non-thinking-capable model selected, since kimi-code 0.1.1 has no per-spawn CLI thinking control).
899
+ - **`--thinking` / `--no-thinking` removed from every user-facing surface.** Stripped from `commands/{ask,challenge,review,rescue}.md` (argument-hint + flag bullets), from `agents/{kimi-review,kimi-challenge}.md` strict allowlists, from `runtime/parsing.ts` `SUPPORTED_FLAGS` strings and error templates, and from `runtime/kimi-errors.ts` nextStep hints. The parser now **hard-rejects** both flags with `INVALID_ARGS` (`THINKING_FLAG_REMOVED_MESSAGE`) — no escape hatch. Multi-agent Round 1-3 review surfaced and closed five contradicting references across docs, agents, and source.
900
+ - **`RESPONSE_TIMEOUT` nextStep hint qualified for review/challenge.** Previous hint suggested `--background` as a universal retry; review and challenge explicitly reject `--background`. Hint now qualifies it as ask/rescue-only.
901
+ - **Hook-missing warning surfaces the nvm/asdf remediation explicitly.** Users who switch Node versions hit a strict-equality verifier rejection by design. The warning now points at re-running `/kimi:setup` after every Node version switch and links to `docs/safety.md`.
902
+
903
+ ### Added
904
+
905
+ - **`warnIfSessionIdMissing` helper in `runtime/commands/cli-helpers.ts`.** When kimi finishes a job but never announces a session id, a loud stderr warning fires so the user learns resume/replay won't work for that job. Wired into review/challenge/ask/rescue end-of-job paths. Full unit coverage in `tests/runtime/cli-helpers.test.ts`.
906
+ - **`CliClientOptions.thinking` (reserved field, currently no-op).** Round 2 Codex review caught that emitting `--no-thinking` in argv crashes kimi-code 0.1.1 (`allowUnknownOption(false)`). The field stays as an intent contract — review-gate sets `thinking: false` to declare its requirement — and `buildArgs` will translate when upstream lands a per-spawn CLI flag (see ROADMAP H5).
907
+ - **Negative test assertions to lock the v1.0 thinking-on contract.** ask, rescue, and review-gate argv assertions now verify `--no-thinking` is NOT emitted; parseRescueArgs has a dedicated rejection test alongside parseAskArgs and parseReviewArgs.
908
+
909
+ ### Fixed
910
+
911
+ - **Empty-string sessionId no longer poisons the SQLite row.** All four sessionId-capturing commands (review/challenge, ask, rescue, review-gate) tightened from `result.sessionId !== undefined` to `result.sessionId.length > 0`. Kimi Round 1 finding #3.
912
+ - **Orphan JSDoc above `warnIfSessionIdMissing` moved back above `assertCliResultSuccess` where it belongs.** Both kimi-review and code-reviewer flagged this in Round 1.
913
+ - **Redundant `RESCUE_PROMPT_TIMEOUT_MS` local alias dropped.** rescue.ts now imports `KIMI_RESCUE_PROMPT_TIMEOUT_MS` directly.
914
+
915
+ ### Process
916
+
917
+ - Multi-agent review across 3 rounds: kimi-review + code-reviewer (Claude opus) + kimi-challenge + codex-rescue. Round 2 surfaced 1 Critical (kimi-code rejects `--no-thinking`) and 2 High (agent files still advertised removed flags). Round 3 found 4 release-blockers (version bump, AGENTS gate text, missing warnIfSessionIdMissing tests, missing alpha.4 CHANGELOG entry) — all addressed in this tag.
918
+
919
+ ### Documentation
920
+
921
+ - `ROADMAP-TO-GA.md` reflects alpha.4 reality: G1+G3+L2 closed, G2→H4, new H5 (kimi-code upstream thinking-flag negotiation). Ship-gate updated.
922
+ - `docs/safety.md` "Known limitation: Node version manager switches" section added.
923
+ - `AGENTS.md` GA gate sentence updated.
924
+
925
+ ---
926
+
927
+ ## 1.0.0-alpha.3 — 2026-05-25
928
+
929
+ > **Roadmap to GA:** see [ROADMAP-TO-GA.md](./ROADMAP-TO-GA.md). The deferred items from the three audit rounds + production smoke testing are triaged into GA blockers (4), high-priority post-GA (3), and polish backlog (3). GA gate ≈ 1 working day of focused work.
930
+
931
+ ### Fixed
932
+
933
+ - **Cancellation: grandchild orphan (CRITICAL, production-observed).** kimi-code 0.1.1's internal `LocalKaos` spawns every Bash tool subprocess with `detached: true` deliberately — so kimi-code can group-kill its own tools during cancellation. This gives bash subprocesses their own PGID (sibling to kimi-code's PGID, not nested). The alpha.2 process-group fix (`process.kill(-kimi_pid, ...)`) therefore only killed kimi-code itself; the bash grandchildren survived as orphans. Reproduced in production smoke testing — `/kimi:cancel` left `bun test` running indefinitely after the cancel completed.
934
+
935
+ **Fix:** On POSIX, enumerate the descendant tree once at abort time (BFS over `/proc/*/status` on Linux, `ps -axo pid=,ppid=` snapshot on macOS, `pgrep -P` recursive as fallback; depth bounded at 8, pid count bounded at 512). The snapshot is reused for both SIGTERM and the SIGKILL escalation 1500ms later — re-enumerating at SIGKILL would miss any grandchildren whose parent (kimi) died from SIGTERM and reparented them to launchd, since the PPID-walk roots at kimi-code's now-dead pid. After per-pid kill, each descendant ALSO gets a negative-pid (process-group) kill as defense-in-depth, because each bash subprocess is itself a session leader and may have its own children that our enumeration missed (e.g. just-spawned pipeline kids). Win32 is unchanged — descendant reaping on Windows is a known limitation, documented in `runtime/cli-client.ts`.
936
+
937
+ **Regression coverage:** New `tests/helpers/process-group-grandchild.ts` spawns its sleep grandchild with `{ detached: true }` to mirror kimi-code's actual production shape. New test in `tests/runtime/cli-client.test.ts` parses the grandchild PID via stdout, aborts the parent, waits for the SIGKILL escalation window, then asserts ESRCH on the grandchild. Confirmed to fail on the alpha.2 process-group-only path. Replaced an older sh-based test that could pass via shell SIGHUP cleanup semantics rather than actual descendant signaling.
938
+
939
+ **Why this is a real safety regression rather than UX polish:** under `/kimi:rescue` an approved long-running tool (e.g. `bun test`, `cargo check`) kept consuming model tokens, file descriptors, and CPU after the user thought the job was cancelled. For build/test commands the workspace impact is bounded by the rescue allowlist's read-only-shape constraints, but the denial-of-cancellation is unacceptable for a write-capable surface. Surfaced by `/kimi:challenge` Finding 4 during smoke testing (challenge mode literally predicted this exact gap) and confirmed empirically.
940
+
941
+ ### Investigation notes
942
+
943
+ - kimi-code 0.1.1's `detached: true` is a deliberate design choice in its `LocalKaos.exec` abstraction, paired with kimi-code-side `process.kill(-pid, ...)` cancellation. The behavior is structural and unlikely to change in the 0.1.x line. There is no env var or flag to disable it (confirmed by binary-strings inspection and source-level grep of the bundled Node binary at `~/.kimi-code/bin/kimi`).
944
+ - Production smoke testing observed a three-level PGID chain: plugin (own PGID from our `detached: true`) → kimi-code (own PGID from kimi-code's spawn shape) → bash (own PGID from kimi-code's `LocalKaos.exec`). All three are siblings, not nested. This is the shape the alpha.3 fix now handles.
945
+
946
+
947
+
948
+ ## 1.0.0-alpha.2 — 2026-05-25
949
+
950
+ ### Highlights
951
+
952
+ Same alpha.1 functionality; the rollback of the marketplace/plugin rename is the only meaningful change. v0.4 installs can now update in place to v1 (`/plugin update kimi`), so long as kimi-code is installed locally first.
953
+
954
+ ### Reverted
955
+
956
+ - **Marketplace and plugin rename.** alpha.1 shipped with the IDs renamed to `kimi-marketplace-v1` / `kimi-v1` as a defensive measure against v0.4 users auto-upgrading into a kimi-code dependency they didn't have. For a plugin at this scale the friction of forcing a fresh marketplace registration + reinstall is more cost than the auto-upgrade risk is worth, so alpha.2 restores the original `kimi-marketplace` / `kimi` ids. The kimi-code prerequisite is now communicated through README + migration docs rather than the install path itself.
957
+
958
+ ### Migration from alpha.1
959
+
960
+ If you installed `kimi-v1@kimi-marketplace-v1` during the brief alpha.1 window:
961
+
962
+ ```
963
+ /plugin uninstall kimi-v1
964
+ /plugin marketplace remove kimi-marketplace-v1
965
+ /plugin marketplace update linxule # or: marketplace add linxule/kimi-plugin-cc
966
+ /plugin install kimi@kimi-marketplace
967
+ ```
968
+
969
+ Then reload Claude Code and re-run `/kimi:setup` (the managed block is keyed by version marker — alpha.1 markers will be detected as stale and refreshed).
970
+
971
+ ## 1.0.0-alpha.1 — 2026-05-25
972
+
973
+ ### Highlights
974
+
975
+ Hard cut from the Python Kimi CLI Wire transport to the kimi-code Node.js subprocess transport. v0.4.x stays available at the [`v0.4.0`](https://github.com/linxule/kimi-plugin-cc/releases/tag/v0.4.0) tag (with a `v0.4-maintenance` branch cut from that tag for ongoing fixes — see the tag if the branch is not yet pushed). alpha.1 briefly renamed the marketplace and plugin ids to `kimi-marketplace-v1` / `kimi-v1`; alpha.2 reverted that. Read the alpha.2 entry above for the upgrade path.
976
+
977
+ The alpha shipped after **two multi-agent audit rounds**: a comprehensive cross-PR pass over the five-commit cutover and a focused re-review of the audit-fix diff. Convergent findings from Claude code-reviewer + Codex closed before tag — exact-command hook verification, abort-race recovery, 0o600 config-mode preservation, an `--output=*` rescue-allowlist gap, and a TOML-decode false-fail for apostrophe-in-path installs. See [docs/safety.md](./docs/safety.md) for the hardened safety story.
978
+
979
+ See [docs/migration.md](./docs/migration.md) for the step-by-step upgrade.
980
+
981
+ ### Architecture changes
982
+
983
+ - **Transport.** Spawns `kimi --output-format stream-json -p "<prompt>"` as a one-process-per-job subprocess; parses OpenAI-shaped NDJSON records (assistant content + tool_calls). Replaces the v0.4 Wire JSON-RPC client. (PRs 1–3)
984
+ - **Safety enforcement.** kimi-code's `kimi -p` mode hard-codes `permission: auto`. v1.0 enforces the read-only contract for review/challenge/review_gate/ask, and the workspace-bound rescue allowlist, via a PreToolUse hook installed in `~/.kimi-code/config.toml`. `/kimi:rescue` REFUSES to run when the hook is missing.
985
+ - **Setup.** `/kimi:setup` rewrites the kimi-code config with a marker-delimited managed block (idempotent), runs a two-layer probe (in-process Node + `/bin/sh -c` shape that mirrors kimi-code's hook runner), and reports failure with actionable detail. `--check` and `--uninstall` subcommands added.
986
+ - **Session id semantics.** kimi-code mints the session id and announces it on stderr; the runtime captures it via regex. Resume passes the captured id via `-r <id>`. The `(repo_id, command_type, kimi_session_id)` SQLite unique index still guards concurrent resumes; concurrent fresh runs are now distinct (NULL session ids until kimi announces).
987
+ - **Replay.** Now reads the v1.0 cli-client NDJSON log format (`{event, record}` lines). v0.4 Wire JSON-RPC logs surface as `REPLAY_LOG_UNREADABLE`. ([PR 4](#))
988
+
989
+ ### Per-command policy (PreToolUse hook)
990
+
991
+ | `KIMI_PLUGIN_CC_CMD` | Allowed tools | Denied tools |
992
+ |---|---|---|
993
+ | `ask`, `review`, `challenge`, `review_gate` | `Read`, `Grep`, `Glob`, `ReadMediaFile`, `TaskList`, `TaskOutput` | everything else |
994
+ | `rescue` | workspace-bound shell + edit allowlist (see [docs/safety.md](./docs/safety.md)) | every shell command, file edit, or write the allowlist rejects |
995
+ | unset / out-of-plugin | everything | nothing — kimi-code is being driven directly |
996
+
997
+ `/kimi:ask` is read-only in v1.0. v0.4 ran ask under Kimi CLI agent profiles that allowed write tools; the hook tightens this to match the documented "narrative answer, not implementation" contract.
998
+
999
+ ### Marketplace + plugin id (reverted in alpha.2)
1000
+
1001
+ alpha.1 renamed the marketplace and plugin ids (`kimi-marketplace` → `kimi-marketplace-v1`, `kimi` → `kimi-v1`) so existing v0.4 installs couldn't auto-pull v1. **alpha.2 reverted that rename**; see the alpha.2 entry above. For posterity the original intent was: kimi-code is a hard dependency in v1, and the rename was a defensive forcing function for users to acknowledge the new prerequisite before upgrading. The revert traded that defense for a much smoother upgrade UX, with the kimi-code prerequisite communicated through README + migration docs instead.
1002
+
1003
+ ### Removed
1004
+
1005
+ - `runtime/wire/` — Wire JSON-RPC client, turn capture, approval dispatcher, think-stall guard. Replaced by `runtime/cli-client.ts` + `runtime/stream-json.ts`.
1006
+ - `runtime/kimi-launch.ts` — Wire-client launch helper. Subsumed by `runtime/cli-client.ts` + `runtime/kimi-command.ts`.
1007
+ - `runtime/kimi-web-client.ts` — Kimi web PATCH endpoint for session titles. kimi-code's vis-server doesn't expose PATCH; the title feature is gone in v1.0.
1008
+ - `runtime/cancellation.ts` — Wire-client SIGTERM/SIGKILL handler. Replaced by `runtime/cli-cancellation.ts` + cli-client's built-in escalation.
1009
+ - `runtime/agents/*.yaml` — Kimi CLI agent profiles. kimi-code doesn't load user profiles; per-command safety lives in the PreToolUse hook now.
1010
+ - `runtime/prompts/*-system.md` — System prompts that were attached via agent profiles. Inlined into command preambles where still needed.
1011
+ - `tests/wire/`, `tests/helpers/mock-kimi-cli.ts` (v0.4), `tests/helpers/mock-wire-server.ts`, and the Wire-client / Kimi-launch / Kimi-web / cancellation test files.
1012
+
1013
+ ### Added
1014
+
1015
+ - `runtime/cli-client.ts` — subprocess wrapper with AbortController cancellation, SIGTERM→SIGKILL escalation (1500ms, matching v0.4), rolling stderr tail, NDJSON diagnostic log, log-drain timeout, pre-aborted signal check.
1016
+ - `runtime/stream-json.ts` — pure parser for kimi-code's `--output-format stream-json` records.
1017
+ - `runtime/cli-cancellation.ts` — AbortController-based cancellation handler.
1018
+ - `runtime/hooks/approval-policy.ts` — pure per-command decision function (the heart of the safety policy).
1019
+ - `runtime/hooks/approval-hook.ts` — entry script (`dist/hooks/approval-hook.js`) installed in `~/.kimi-code/config.toml`.
1020
+ - `runtime/hooks/managed-block.ts` — shared parser for the managed block; used by both the installer and the verifier so the two cannot disagree.
1021
+ - `runtime/hooks/install.ts` — `verifyHookInstalled` + `maybeWarnHookMissing` helpers used by ask/review/challenge/review_gate (warn-once) and rescue (refuse).
1022
+ - `runtime/kimi-command.ts` — `KIMI_PLUGIN_CC_KIMI_BIN` / `KIMI_PLUGIN_CC_KIMI_PREFIX_ARGS` env-var resolver.
1023
+ - `tests/runtime/setup.test.ts` — managed-block install / check / uninstall lifecycle, orphan detection, duplicate detection, CRLF preservation, TOML-safe path enforcement.
1024
+ - `tests/helpers/mock-kimi-cli-v1.ts` — stream-json mock for the cli-client path.
1025
+ - `tests/helpers/sigterm-trap.ts` — child process that traps SIGTERM so SIGKILL escalation paths can be exercised deterministically.
1026
+ - `docs/migration.md`, `docs/safety.md`.
1027
+
1028
+ ### Review-driven hardening
1029
+
1030
+ The five-PR cutover landed with paired Claude code-reviewer + Codex codex-rescue adversarial reviews on every PR. Convergent and divergent findings applied before commit:
1031
+
1032
+ - **PR 2 / hook script compiled but never installed** — added `verifyHookInstalled` + one-time stderr warning so the gap is loud.
1033
+ - **PR 2 / withTimeout left the subprocess running after the budget expired** — added `runCliPromptWithBudget` that ties the timeout to an internal AbortController.
1034
+ - **PR 3 / rescue running write-capable without the hook** — rescue now refuses with `RESCUE_HOOK_NOT_INSTALLED`.
1035
+ - **PR 3 / SIGKILL escalation race** — added `processClosed` flag distinct from `settled` so a timer queued during log-drain can't fire a redundant SIGKILL.
1036
+ - **PR 4 / ask=allow contradicted read-only docs** — ask now shares the read-only allowlist with review/challenge/review_gate.
1037
+ - **PR 4 / verifier was a substring check** — shared the managed-block parser with the installer; both gates reject the same shapes (orphan, duplicate, missing event, missing command, matcher present).
1038
+ - **PR 4 / bare `node` in the managed block could silently fail-open** — installer writes `process.execPath` (absolute Node path).
1039
+ - **PR 4 / TOML escape in the command field** — switched from shell-single-quoting to TOML basic-string escaping; rejects paths with characters that cannot safely round-trip.
1040
+ - **PR 4 / writeConfigAtomic race on a fixed temp file** — unique random tmp filenames.
1041
+ - **PR 4 / stripAllMarkers destroyed user content after an orphan BEGIN** — only marker lines removed; surrounding content preserved.
1042
+ - **PR 4 / locateMarkerBlock only inspected the first BEGIN/END pair** — duplicate-block detection with `SETUP_DUPLICATE_BLOCKS`.
1043
+ - **PR 4 / CRLF line endings mixed on write** — line-ending detection threaded through install/uninstall/splice.
1044
+
1045
+ ### Pre-tag audit hardening
1046
+
1047
+ Two further multi-agent rounds (Claude code-reviewer + Codex codex-rescue, plus plugin-validator and claude-code-guide for spec compliance) found these classes during the pre-tag audit. All closed before tag:
1048
+
1049
+ - **rescue.ts skipped the hook-path drift gate** — the optional `expectedHookPath` parameter let a stale managed block silently re-enable kimi-code's auto-approve. Verifier is now strict-by-default and always reconstructs the canonical command via the shared `runtime/hooks/install-paths.ts` module.
1050
+ - **Verifier substring match → exact equality** — `commandPath.includes(expectedHookPath)` accepted `command = "true # /path/to/approval-hook.js"` (`/bin/sh -c` parsed `#` as a comment, hook exited 0 = ALLOW). Equality on the full canonical shell command closes the bypass.
1051
+ - **`await mkdir` race in cli-client** — if abort fired during the mkdir yield, the listener attached after meant SIGTERM/SIGKILL was never sent. Re-checks `signal.aborted` after attach. Mirrors kimi-code's own runner pattern.
1052
+ - **`writeConfigAtomic` umask** — temp file inherited umask before rename. Now chmods 0o600 before rename so the user's existing API-key/token file mode is preserved.
1053
+ - **`--output=*` workspace escape via Bash** — `git diff --output=/etc/passwd`, `curl --output /tmp/x`, `eslint --output-file=/tmp/x` all wrote outside the workspace through their own report-output mechanism. `--output`/`--output-file`/`--output-directory`/`--output-dir` (exact + `=` prefix) now live in `MUTATING_FLAGS`. `-o` is rejected per-tool where its semantics are write-shape (eslint).
1054
+ - **TOML basic-string capture without decode** — `parseManagedBlock` captured raw, so apostrophe-in-path installs round-tripped through `\\` (TOML escape) → captured `\\` ≠ canonical `\` → false-fail. `decodeTomlBasicString` handles the six standard escapes.
1055
+ - **Relative `KIMI_PLUGIN_CC_HOOK_SCRIPT` override** — kimi-code spawns hooks via `/bin/sh -c` with a cwd that may differ from the companion's. Override is now required to be absolute, matching the `KIMI_PLUGIN_CC_NODE_BIN` contract.
1056
+
1057
+ ### Round 3 audit hardening
1058
+
1059
+ A third multi-agent audit pass (Claude code-reviewer + Codex + plugin-validator + claude-code-guide) found one High, four Medium, two Low, and several polish gaps. All closed before tag:
1060
+
1061
+ - **Process-group cancellation (HIGH)** — `runtime/cli-client.ts` spawned kimi-code with default process-group behavior, so `child.kill(SIGTERM/SIGKILL)` only hit the immediate process. kimi-code's Bash tool subprocesses ran as grandchildren and survived cancel — a denial-of-cancellation issue where long-running approved subprocesses kept consuming workspace state after the plugin reported cancellation. POSIX now spawns with `detached: true` (own process group) and signals the negative pid (`process.kill(-child.pid, ...)`). ESRCH/EPERM fall through to direct `child.kill()`. win32 keeps the original direct-kill path (negative-pid signaling does not exist there; grandchild reaping on Windows is a known gap).
1062
+ - **Session-id capture: incremental + anchored (MEDIUM)** — `runtime/cli-client.ts` only parsed the session id from the final 8192-char `stderrTail` on close; if kimi-code emitted the announce line early and then wrote more than 8192 bytes of stderr, the id was evicted and resume/replay handles silently disappeared. `runtime/stream-json.ts` regex was unanchored and accepted any `[0-9a-f-]{8,}` token, so a hostile Bash command under `/kimi:rescue` could `echo 'To resume this session: kimi -r <fake>' >&2` and poison the captured id. Capture now runs in the stderr `data` handler (first announce wins, pinned), regex tightened to anchored line-bounded full-UUID shape (`/^To resume this session:\s+kimi\s+-r\s+([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\s*$/im`), and `stderrTail` scan remains as a fallback.
1063
+ - **Stream-json line size cap (MEDIUM)** — `StreamJsonParser.push()` appended every chunk into one in-progress buffer until `\n` appeared, with no upper bound; a single 1MB+ unterminated stdout line could land whole in `malformed[]` and the diagnostics log. New `MAX_STREAM_JSON_LINE_BYTES = 1_048_576` guard emits a malformed outcome with a truncated preview, clears the buffer, and continues parsing. `cli-client.ts` also truncates `entry.line` before storing for diagnostics.
1064
+ - **Drift gate untracked-file gap (MEDIUM, convergent with code-reviewer)** — `bun run check`'s `git diff --exit-code -- dist` caught modifications but not untracked files. A new `runtime/foo.ts` whose compiled `dist/foo.js` was forgotten by `git add` would silently pass the gate. The check now additionally fails when `git ls-files --others --exclude-standard -- dist` is non-empty, and prints the offending files so the developer knows what to stage.
1065
+ - **`buildManagedBlock` env divergence** — the installer's managed-block writer called `buildHookShellCommand(hookScriptPath, process.env)` while the verifier and `--check` path resolved the canonical command from a parameter `env`. Production masked this (context.env === process.env), but any future caller or test that passed divergent env would produce an unfixable "installed: false" loop. `buildManagedBlock` now takes `env: NodeJS.ProcessEnv` and the install path threads `context.env` through — single source of truth for the canonical command bytes stays in `runtime/hooks/install-paths.ts`.
1066
+ - **Agent color collision** — `kimi-review`, `kimi-challenge`, and `kimi-ask` all declared `color: cyan`, defeating Claude Code's per-agent UI hint. `kimi-challenge` moved to `yellow` (adversarial framing → warning color); the read-only narrative trio (`kimi-review`, `kimi-ask`) keep cyan and `kimi-rescue` keeps magenta as the only write-capable surface.
1067
+ - **Missing `argument-hint` on lifecycle commands** — `replay`, `result`, `status`, `cancel` accepted positional or flag arguments but exposed no hint in the slash-command palette. Added hints matching the actual parsers (`<job-id>` for replay; `[<job-id>] [--type <kind>] [--json]` for result; `[<job-id>] [--type <kind>]` for status; `[<job-id>]` for cancel).
1068
+ - **Explicit `commands` array in plugin manifest** — `.claude-plugin/plugin.json` relied on auto-discovery from `commands/*.md`. Adding an explicit `commands` array (belt-and-suspenders) prevents the README.md in that directory from being mistakenly registered as a slash command and documents the surface in the manifest itself.
1069
+ - **Setup side-effect doc note** — `commands/setup.md` description didn't mention that `/kimi:setup` writes to `~/.kimi-code/config.toml` (outside the plugin's own files). Description now spells out the side effect.
1070
+ - **Docs drift** — `docs/safety.md` said "once per Claude Code session" for the missing-hook warning latch, but the companion is a fresh Node process per slash-command invocation, so the latch is actually per-companion-invocation. Docs corrected. Same file's unknown-label policy row listed only `Read`, `Grep`, `Glob` while `runtime/hooks/approval-policy.ts::READ_ONLY_TOOLS` and the unknown-label branch actually allow six tools (adds `ReadMediaFile`, `TaskList`, `TaskOutput`). Docs widened to match the code — the broader set is intentional and consistent with the named labels.
1071
+
1072
+ ### Test surface
1073
+
1074
+ 358 tests across 28 files. Drift gate (`git diff --exit-code -- dist && test -z "$(git ls-files --others --exclude-standard -- dist)"`) runs as part of `bun run check` to catch forgotten rebuilds and untracked compiled artifacts before commit.
1075
+
1076
+ ### Versions
1077
+
1078
+ Synced version `1.0.0-alpha.1` across:
1079
+
1080
+ - `runtime/version.ts` (`KIMI_PLUGIN_CC_VERSION` — written into the managed-block marker by `/kimi:setup`)
1081
+ - `package.json`
1082
+ - `.claude-plugin/plugin.json`
1083
+ - `.claude-plugin/marketplace.json`
1084
+ - `AGENTS.md`
1085
+
1086
+ ## Older releases
1087
+
1088
+ See the [`v0.4.0` tag](https://github.com/linxule/kimi-plugin-cc/releases/tag/v0.4.0) (and the `v0.4-maintenance` branch cut from it, once published) for the v0.4.x line. Notable releases:
1089
+
1090
+ - **0.4.0** — Eliminated stderr-as-correctness; structured result envelope.
1091
+ - **0.3.7** — Loud failures across review/challenge/ask/rescue.
1092
+ - **0.3.6** — Hard-error unknown flags on review/challenge.
1093
+ - **0.3.5** — ApprovalRouter; outputMode invariant; command registry.
1094
+ - **0.2.3** — Dropped the JSON output schemas from review and challenge; both became prose pass-through. Only the review gate still parses Kimi output (JSON allow/block).
1095
+
1096
+ For pre-1.0 commit-level history see `git log v0.4.0..` on the v0.4-maintenance branch.