kimi-plugin-cc 2.2.2 → 2.4.0

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 (123) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +5 -3
  3. package/.mcp.json +13 -0
  4. package/CHANGELOG.md +18 -0
  5. package/README.md +57 -5
  6. package/agents/kimi-challenge.md +3 -3
  7. package/agents/kimi-pursue.md +1 -1
  8. package/agents/kimi-rescue.md +2 -2
  9. package/agents/kimi-review.md +3 -3
  10. package/commands/README.md +2 -2
  11. package/commands/challenge.md +1 -1
  12. package/commands/pursue.md +1 -1
  13. package/commands/review.md +1 -1
  14. package/dist/background-spawn.js +9 -17
  15. package/dist/cli-client.js +24 -63
  16. package/dist/commands/ask.js +28 -31
  17. package/dist/commands/cancel.js +50 -23
  18. package/dist/commands/cli-helpers.js +7 -16
  19. package/dist/commands/pursue.js +24 -33
  20. package/dist/commands/registry.js +6 -19
  21. package/dist/commands/rescue.js +23 -22
  22. package/dist/commands/review-gate.js +18 -28
  23. package/dist/commands/review.js +41 -45
  24. package/dist/commands/setup.js +85 -171
  25. package/dist/commands/swarm.js +107 -91
  26. package/dist/commands/worker.js +0 -6
  27. package/dist/companion.js +13 -40
  28. package/dist/git.js +14 -7
  29. package/dist/help.js +2 -0
  30. package/dist/hooks/approval-hook.js +9 -20
  31. package/dist/hooks/approval-policy.js +36 -69
  32. package/dist/hooks/config-safety.js +6 -4
  33. package/dist/hooks/install-paths.js +62 -138
  34. package/dist/hooks/install.js +37 -108
  35. package/dist/hooks/managed-block.js +88 -214
  36. package/dist/job-id.js +12 -0
  37. package/dist/job-store.js +65 -28
  38. package/dist/jobs.js +9 -1
  39. package/dist/kimi-command.js +1 -3
  40. package/dist/kimi-engine.js +1 -1
  41. package/dist/kimi-timeouts.js +9 -21
  42. package/dist/kimi-version-probe.js +16 -1210
  43. package/dist/mcp/binding.js +58 -0
  44. package/dist/mcp/job-control.js +345 -0
  45. package/dist/mcp/launcher.js +257 -0
  46. package/dist/mcp/operations.js +301 -0
  47. package/dist/mcp/protocol.js +275 -0
  48. package/dist/mcp/server.js +8 -0
  49. package/dist/mcp/stdio.js +78 -0
  50. package/dist/mcp/supervised-child.js +15 -0
  51. package/dist/mcp/tool-result.js +7 -0
  52. package/dist/mcp/workspace.js +34 -0
  53. package/dist/model-command.js +32 -0
  54. package/dist/native-v2-preflight.js +1 -1
  55. package/dist/parsing.js +4 -18
  56. package/dist/rescue-approval.js +78 -164
  57. package/dist/session-recovery.js +7 -10
  58. package/dist/stream-json.js +6 -174
  59. package/dist/version.js +1 -1
  60. package/docs/migration.md +2 -6
  61. package/docs/registry-releases.md +23 -7
  62. package/docs/safety.md +30 -14
  63. package/package.json +7 -3
  64. package/plugins/kimi-codex/.codex-plugin/plugin.json +8 -5
  65. package/plugins/kimi-codex/.mcp.json +28 -0
  66. package/plugins/kimi-codex/dist/background-spawn.js +9 -17
  67. package/plugins/kimi-codex/dist/cli-client.js +24 -63
  68. package/plugins/kimi-codex/dist/commands/ask.js +28 -31
  69. package/plugins/kimi-codex/dist/commands/cancel.js +50 -23
  70. package/plugins/kimi-codex/dist/commands/cli-helpers.js +7 -16
  71. package/plugins/kimi-codex/dist/commands/pursue.js +24 -33
  72. package/plugins/kimi-codex/dist/commands/registry.js +6 -19
  73. package/plugins/kimi-codex/dist/commands/rescue.js +23 -22
  74. package/plugins/kimi-codex/dist/commands/review-gate.js +18 -28
  75. package/plugins/kimi-codex/dist/commands/review.js +41 -45
  76. package/plugins/kimi-codex/dist/commands/setup.js +85 -171
  77. package/plugins/kimi-codex/dist/commands/swarm.js +107 -91
  78. package/plugins/kimi-codex/dist/commands/worker.js +0 -6
  79. package/plugins/kimi-codex/dist/companion.js +13 -40
  80. package/plugins/kimi-codex/dist/git.js +14 -7
  81. package/plugins/kimi-codex/dist/help.js +2 -0
  82. package/plugins/kimi-codex/dist/hooks/approval-hook.js +9 -20
  83. package/plugins/kimi-codex/dist/hooks/approval-policy.js +36 -69
  84. package/plugins/kimi-codex/dist/hooks/config-safety.js +6 -4
  85. package/plugins/kimi-codex/dist/hooks/install-paths.js +62 -138
  86. package/plugins/kimi-codex/dist/hooks/install.js +37 -108
  87. package/plugins/kimi-codex/dist/hooks/managed-block.js +88 -214
  88. package/plugins/kimi-codex/dist/job-id.js +12 -0
  89. package/plugins/kimi-codex/dist/job-store.js +65 -28
  90. package/plugins/kimi-codex/dist/jobs.js +9 -1
  91. package/plugins/kimi-codex/dist/kimi-command.js +1 -3
  92. package/plugins/kimi-codex/dist/kimi-engine.js +1 -1
  93. package/plugins/kimi-codex/dist/kimi-timeouts.js +9 -21
  94. package/plugins/kimi-codex/dist/kimi-version-probe.js +16 -1210
  95. package/plugins/kimi-codex/dist/mcp/binding.js +58 -0
  96. package/plugins/kimi-codex/dist/mcp/job-control.js +345 -0
  97. package/plugins/kimi-codex/dist/mcp/launcher.js +257 -0
  98. package/plugins/kimi-codex/dist/mcp/operations.js +301 -0
  99. package/plugins/kimi-codex/dist/mcp/protocol.js +275 -0
  100. package/plugins/kimi-codex/dist/mcp/server.js +8 -0
  101. package/plugins/kimi-codex/dist/mcp/stdio.js +78 -0
  102. package/plugins/kimi-codex/dist/mcp/supervised-child.js +15 -0
  103. package/plugins/kimi-codex/dist/mcp/tool-result.js +7 -0
  104. package/plugins/kimi-codex/dist/mcp/workspace.js +34 -0
  105. package/plugins/kimi-codex/dist/model-command.js +32 -0
  106. package/plugins/kimi-codex/dist/native-v2-preflight.js +1 -1
  107. package/plugins/kimi-codex/dist/parsing.js +4 -18
  108. package/plugins/kimi-codex/dist/rescue-approval.js +78 -164
  109. package/plugins/kimi-codex/dist/session-recovery.js +7 -10
  110. package/plugins/kimi-codex/dist/stream-json.js +6 -174
  111. package/plugins/kimi-codex/dist/version.js +1 -1
  112. package/plugins/kimi-codex/skills/kimi-ask/SKILL.md +2 -2
  113. package/plugins/kimi-codex/skills/kimi-cancel/SKILL.md +1 -1
  114. package/plugins/kimi-codex/skills/kimi-challenge/SKILL.md +1 -1
  115. package/plugins/kimi-codex/skills/kimi-pursue/SKILL.md +1 -1
  116. package/plugins/kimi-codex/skills/kimi-replay/SKILL.md +1 -1
  117. package/plugins/kimi-codex/skills/kimi-rescue/SKILL.md +1 -1
  118. package/plugins/kimi-codex/skills/kimi-result/SKILL.md +1 -1
  119. package/plugins/kimi-codex/skills/kimi-review/SKILL.md +3 -3
  120. package/plugins/kimi-codex/skills/kimi-setup/SKILL.md +1 -1
  121. package/plugins/kimi-codex/skills/kimi-status/SKILL.md +1 -1
  122. package/plugins/kimi-codex/skills/kimi-swarm/SKILL.md +1 -1
  123. package/plugins/kimi-codex/skills/kimi-swarm-write/SKILL.md +1 -1
@@ -50,13 +50,9 @@ export async function verifyHookInstalled(env) {
50
50
  configPath,
51
51
  };
52
52
  }
53
- // Pass `nodeExists` so a command MISMATCH is classified into an actionable
54
- // H4 diagnosis (Node upgrade / version-manager switch vs. plugin path drift)
55
- // instead of a raw expected-vs-got dump. Classification only refines the
56
- // reason; it never changes the installed=false decision.
57
- //
58
- // `hostId` selects THIS host's block in the shared config so Claude Code and
59
- // Codex verify their own managed block independently (v1.7.0 host scoping).
53
+ // Classify command mismatches into actionable drift reasons without changing
54
+ // the installed=false decision. hostId isolates this host's block in the
55
+ // shared config.
60
56
  const check = evaluateInstalled(raw, expected.command, {
61
57
  hostId: resolveHostId(env, expected.hookScriptPath),
62
58
  nodeExists: (binPath) => existsSync(binPath),
@@ -73,9 +69,8 @@ export async function verifyHookInstalled(env) {
73
69
  ...(check.drift !== undefined ? { drift: check.drift } : {}),
74
70
  };
75
71
  }
76
- // The command matched byte-for-byte, but that alone doesn't prove the
77
- // hook can run — confirm the script it points at still exists and is
78
- // readable (see point 3 above). Fail closed on any stat/access error.
72
+ // A byte-exact command does not prove the hook can run. Confirm the script
73
+ // remains readable and fail closed on every access error.
79
74
  try {
80
75
  await access(expected.hookScriptPath, fsConstants.R_OK);
81
76
  }
@@ -86,61 +81,28 @@ export async function verifyHookInstalled(env) {
86
81
  configPath,
87
82
  };
88
83
  }
89
- // ...and confirm the pinned INTERPRETER is executable.
90
- //
91
- // SCOPE — read this before widening the claim. This is a NARROW BACKSTOP, not
92
- // the thing that catches a dead Node. Two adversarial reviews (2026-07-25)
93
- // rejected the original, wider rationale, and it was verified empirically:
94
- //
95
- // - It does NOT catch a dangling Homebrew symlink. A dangling symlink cannot
96
- // be exec'd at all, and `command -v node` skips it, so companion.sh (which
97
- // `exec`s the binary it resolves, scripts/companion.sh:34,50) lands on a
98
- // DIFFERENT node. The expected command is recomputed from the live process
99
- // on every call, so it changes, and plain byte-exact equality above
100
- // already refuses — with a RECOVERABLE `drift` that /kimi:setup converges.
101
- // - It does NOT catch the 2026-07-25 dead-node zombie (a config pinning
102
- // ~/.hermes/node). That is a byte mismatch, likewise caught above.
103
- // - On the default path it is close to self-evident: `resolveNodeBinary`
104
- // returns the path THIS process was launched through, which therefore
105
- // existed and was executable moments ago.
106
- //
107
- // THE EXACT PREDICATE it covers: config and expected command still match
108
- // byte-for-byte, yet the Node token embedded in that command fails X_OK AT
109
- // VERIFICATION TIME. Three reachable ways to get there:
84
+ // Confirm the pinned interpreter with a NARROW X_OK backstop. Interpreter
85
+ // moves that change the recomputed command are already refused as drift; this
86
+ // check covers only unchanged command bytes whose Node token fails X_OK now:
110
87
  //
111
- // 1. An absolute `KIMI_PLUGIN_CC_NODE_BIN` naming a binary that is NOT the
112
- // running interpreter and is already dead — e.g. a pinned `nvm` version
113
- // later `nvm uninstall`ed — reached by a direct `node dist/companion.js`
114
- // that bypasses companion.sh's exec+version gate. The override is
115
- // returned verbatim, so it is never proven by the running process.
116
- // 2. POST-LAUNCH MUTATION on the DEFAULT path (this one is easy to miss):
117
- // the interpreter is valid at launch, so the process starts, and is then
118
- // `chmod -x`'d. `realpathSync` still resolves it, so `preferStableNodePath`
119
- // keeps argv0 and the bytes are unchanged — equality passes, X_OK fails.
120
- // 3. Same, but the pathname is REMOVED after launch. `realpathSync` throws
121
- // and we fall back to `execPath`, which in argv0===execPath layouts
122
- // (nvm/asdf) is the identical spelling — so equality still passes while
123
- // the path is gone.
88
+ // 1. An absolute KIMI_PLUGIN_CC_NODE_BIN override names a dead interpreter
89
+ // other than the running process, so launch never proved it executable.
90
+ // 2. The interpreter is chmodded after launch. realpathSync still resolves
91
+ // it, the preferred path and command bytes stay unchanged, but X_OK fails.
92
+ // 3. The pathname is removed after launch. realpathSync throws, and the
93
+ // execPath fallback can retain the same spelling, so equality still passes
94
+ // while the pinned path is gone.
124
95
  //
125
- // In all three the old behavior was installed=true → `/bin/sh -c` exits 127 →
126
- // kimi-code reads any non-2 exit as ALLOW. Converting that to a refusal is
127
- // the whole value. Cases 2 and 3 are also why setup's stronger execution
128
- // probe is not a substitute: it runs at install/--check, whereas this reruns
129
- // before every model spawn and so catches degradation since the last probe.
96
+ // Refusing these cases matters because a failed hook spawn is ALLOW upstream.
97
+ // This per-spawn check also catches degradation since setup's last execution
98
+ // probe. It proves only the exec bit, not a working Node, architecture, or
99
+ // version; setup's shell probe executes the byte-identical command instead.
130
100
  //
131
- // It proves the exec bit ONLY — not a working Node, not the right arch, not
132
- // >=22.5. The real proof is setup's shell probe, which EXECUTES the byte-
133
- // identical command (setup.ts::probeHook) and now fails install nonzero. The
134
- // verifier runs on every spawn and cannot afford a fork, so it approximates.
101
+ // Fail closed on EVERY access error. Do not harmonize this with spawning code
102
+ // that ignores selected errnos: a security verifier cannot "try and see".
135
103
  //
136
- // Fail-closed on ANY errno, deliberately diverging from background-spawn.ts,
137
- // which ignores errnos outside ENOENT/EACCES/EPERM. Spawning can afford to try
138
- // and see; a security verifier cannot. Do not "harmonize" these.
139
- //
140
- // Not re-pin-recoverable: no `drift` is attached (drift only exists when the
141
- // equality check FAILS, so it can never displace a recoverable path), and
142
- // `hookRefusalDetails` therefore omits `retryable_after_setup`, which agent
143
- // callers map to "surface and stop." Setup cannot conjure a working Node.
104
+ // This refusal carries no drift and therefore no retryable_after_setup field:
105
+ // setup cannot repair a broken Node installation.
144
106
  try {
145
107
  await access(expected.nodeBin, fsConstants.X_OK);
146
108
  }
@@ -151,9 +113,6 @@ export async function verifyHookInstalled(env) {
151
113
  `cannot spawn (kimi-code reads a failed hook as ALLOW). Repair the Node install, or set ` +
152
114
  `KIMI_PLUGIN_CC_NODE_BIN to a valid Node >=22.5 executable and run /kimi:setup.`,
153
115
  configPath,
154
- // Machine-readable discriminator: this is the ONE refusal whose remedy is
155
- // NOT "run /kimi:setup" (LLM-caller discipline — an agent cannot read the
156
- // prose above, and every other refusal emits an identical `{config_path}`).
157
116
  refusalKind: "node-bin-not-executable",
158
117
  nodeBin: expected.nodeBin,
159
118
  };
@@ -164,30 +123,10 @@ function resolveKimiCodeConfigPath(env) {
164
123
  return path.join(resolveKimiHome(env), "config.toml");
165
124
  }
166
125
  /**
167
- * Format a stderr-suitable warning message for the missing-hook case.
168
- * Single source of truth so review.ts / review-gate.ts / ask.ts emit
169
- * identical language.
170
- */
171
- /**
172
- * Structured `details` payload for a hook-refusal `RuntimeError`. Single source
173
- * of truth so all five model-spawning commands emit the same machine-readable
174
- * shape — an LLM caller cannot see stderr, so anything it must act on has to
175
- * ride the error's structured context (LLM-caller discipline, v0.3.6+).
176
- *
177
- * `drift_axis === "hook-script"` is the ONLY value a caller may treat as
178
- * retryable (run /kimi:setup for this host, retry once). Its absence means the
179
- * refusal is not a moved-path problem and re-running setup will not fix it.
180
- */
181
- /**
182
- * Caller-facing self-heal protocol, appended to every hook-refusal message.
183
- *
184
- * The slash-command wrappers are deliberately thin, so the retry protocol
185
- * rides the refusal itself — the LLM caller reads it on stdout at exactly the
186
- * moment it applies, and one source here serves both hosts and all surfaces
187
- * (commands, agents, Codex skills) without duplicating it in each file.
188
- * Mirrors the fuller contract in agents/*.md: re-pin via setup, retry ONCE,
189
- * only on `retryable_after_setup: true` AND a zero setup exit; never the
190
- * skip env. Embeds the resolved plugin root so the command is runnable as-is.
126
+ * Caller-facing repair protocol shared by every hook-refusal surface. Re-pin
127
+ * through the resolved plugin root, retry ONCE only when
128
+ * `retryable_after_setup` is literally true and setup exits zero, and never use
129
+ * the skip-check environment variable as a repair.
191
130
  */
192
131
  export function hookRefusalRetryProtocol(env) {
193
132
  const root = env.CLAUDE_PLUGIN_ROOT ?? env.PLUGIN_ROOT ?? "${CLAUDE_PLUGIN_ROOT}";
@@ -196,6 +135,13 @@ export function hookRefusalRetryProtocol(env) {
196
135
  `if it exits 0, retry the refused command once. Anything else — or a second refusal — ` +
197
136
  `surface the refusal instead of retrying.`);
198
137
  }
138
+ /**
139
+ * Structured details for a hook-refusal RuntimeError. `retryable_after_setup`
140
+ * is present only for drift and is literally true only when setup can re-pin
141
+ * every differing token: hook-script drift, or node-bin/both drift whose Node
142
+ * tokens name the same file. A different interpreter is not automatically
143
+ * repairable. Callers must also require a zero setup exit before one retry.
144
+ */
199
145
  export function hookRefusalDetails(status) {
200
146
  return {
201
147
  config_path: status.configPath,
@@ -210,16 +156,6 @@ export function hookRefusalDetails(status) {
210
156
  drift_axis: status.drift.axis,
211
157
  drift_installed_command: status.drift.installedCommand,
212
158
  drift_expected_command: status.drift.expectedCommand,
213
- // Retryable exactly when EVERY differing token is benign:
214
- // - the hook script moved → the install path is version-stamped, so
215
- // setup re-pins it to the running install.
216
- // - the node token changed spelling but names the SAME file → not
217
- // an interpreter move (this is the v1.9.0 re-pin, which also
218
- // moves the script, hence axis "both").
219
- // A node token naming a DIFFERENT file is never retryable: the pinned
220
- // interpreter may be gone, and a hook that cannot spawn exits 127,
221
- // which kimi-code treats as ALLOW. Re-pinning would paper over a real
222
- // enforcement gap instead of surfacing it.
223
159
  retryable_after_setup: status.drift.axis === "hook-script" || status.drift.nodeInterpreterUnchanged === true,
224
160
  }
225
161
  : {}),
@@ -254,18 +190,11 @@ export function formatHookMissingWarning(status, commandLabel) {
254
190
  "",
255
191
  ].join("\n");
256
192
  }
257
- /**
258
- * Process-lifetime latch so commands don't spam the warning on every
259
- * call inside a single test run.
260
- */
193
+ /** Once-per-process latch for missing-hook warnings. */
261
194
  let warnedThisProcess = false;
262
195
  /**
263
- * Emit the warning to stderr at most once per process.
264
- *
265
- * Why stderr rather than stdout: stdout is reserved for the command's
266
- * load-bearing output (artifact prose, JSON envelopes). LLM-caller
267
- * discipline says stderr is humans-only, and this warning is exactly
268
- * that — a developer-facing nudge to run /kimi:setup before tagging.
196
+ * Emit the warning to stderr at most once per process. Stderr is for humans;
197
+ * stdout remains reserved for load-bearing command output.
269
198
  */
270
199
  export function maybeWarnHookMissing(status, commandLabel, stderr = process.stderr) {
271
200
  if (status.installed)