kimi-plugin-cc 2.2.1 → 2.3.1

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 (91) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/CHANGELOG.md +22 -0
  4. package/README.md +5 -5
  5. package/agents/kimi-challenge.md +3 -3
  6. package/agents/kimi-pursue.md +1 -1
  7. package/agents/kimi-rescue.md +2 -2
  8. package/agents/kimi-review.md +3 -3
  9. package/commands/README.md +2 -2
  10. package/commands/challenge.md +1 -1
  11. package/commands/pursue.md +1 -1
  12. package/commands/review.md +1 -1
  13. package/dist/background-spawn.js +9 -17
  14. package/dist/cli-client.js +22 -62
  15. package/dist/commands/ask.js +24 -29
  16. package/dist/commands/cancel.js +7 -19
  17. package/dist/commands/cli-helpers.js +9 -17
  18. package/dist/commands/pursue.js +21 -31
  19. package/dist/commands/registry.js +6 -19
  20. package/dist/commands/rescue.js +20 -20
  21. package/dist/commands/review-gate.js +16 -24
  22. package/dist/commands/review.js +37 -43
  23. package/dist/commands/setup.js +85 -171
  24. package/dist/commands/swarm.js +103 -88
  25. package/dist/commands/worker.js +0 -6
  26. package/dist/git.js +14 -7
  27. package/dist/hooks/approval-hook.js +9 -20
  28. package/dist/hooks/approval-policy.js +36 -69
  29. package/dist/hooks/config-safety.js +7 -4
  30. package/dist/hooks/install-paths.js +62 -138
  31. package/dist/hooks/install.js +37 -108
  32. package/dist/hooks/managed-block.js +88 -214
  33. package/dist/job-store.js +6 -28
  34. package/dist/kimi-command.js +1 -3
  35. package/dist/kimi-engine.js +2 -1
  36. package/dist/kimi-timeouts.js +9 -21
  37. package/dist/kimi-version-probe.js +16 -1210
  38. package/dist/native-v2-preflight.js +1 -1
  39. package/dist/parsing.js +4 -18
  40. package/dist/rescue-approval.js +78 -164
  41. package/dist/session-recovery.js +7 -10
  42. package/dist/stream-json.js +22 -174
  43. package/dist/version.js +1 -1
  44. package/docs/migration.md +2 -6
  45. package/docs/registry-releases.md +25 -5
  46. package/docs/safety.md +16 -12
  47. package/package.json +2 -2
  48. package/plugins/kimi-codex/.codex-plugin/plugin.json +4 -4
  49. package/plugins/kimi-codex/dist/background-spawn.js +9 -17
  50. package/plugins/kimi-codex/dist/cli-client.js +22 -62
  51. package/plugins/kimi-codex/dist/commands/ask.js +24 -29
  52. package/plugins/kimi-codex/dist/commands/cancel.js +7 -19
  53. package/plugins/kimi-codex/dist/commands/cli-helpers.js +9 -17
  54. package/plugins/kimi-codex/dist/commands/pursue.js +21 -31
  55. package/plugins/kimi-codex/dist/commands/registry.js +6 -19
  56. package/plugins/kimi-codex/dist/commands/rescue.js +20 -20
  57. package/plugins/kimi-codex/dist/commands/review-gate.js +16 -24
  58. package/plugins/kimi-codex/dist/commands/review.js +37 -43
  59. package/plugins/kimi-codex/dist/commands/setup.js +85 -171
  60. package/plugins/kimi-codex/dist/commands/swarm.js +103 -88
  61. package/plugins/kimi-codex/dist/commands/worker.js +0 -6
  62. package/plugins/kimi-codex/dist/git.js +14 -7
  63. package/plugins/kimi-codex/dist/hooks/approval-hook.js +9 -20
  64. package/plugins/kimi-codex/dist/hooks/approval-policy.js +36 -69
  65. package/plugins/kimi-codex/dist/hooks/config-safety.js +7 -4
  66. package/plugins/kimi-codex/dist/hooks/install-paths.js +62 -138
  67. package/plugins/kimi-codex/dist/hooks/install.js +37 -108
  68. package/plugins/kimi-codex/dist/hooks/managed-block.js +88 -214
  69. package/plugins/kimi-codex/dist/job-store.js +6 -28
  70. package/plugins/kimi-codex/dist/kimi-command.js +1 -3
  71. package/plugins/kimi-codex/dist/kimi-engine.js +2 -1
  72. package/plugins/kimi-codex/dist/kimi-timeouts.js +9 -21
  73. package/plugins/kimi-codex/dist/kimi-version-probe.js +16 -1210
  74. package/plugins/kimi-codex/dist/native-v2-preflight.js +1 -1
  75. package/plugins/kimi-codex/dist/parsing.js +4 -18
  76. package/plugins/kimi-codex/dist/rescue-approval.js +78 -164
  77. package/plugins/kimi-codex/dist/session-recovery.js +7 -10
  78. package/plugins/kimi-codex/dist/stream-json.js +22 -174
  79. package/plugins/kimi-codex/dist/version.js +1 -1
  80. package/plugins/kimi-codex/skills/kimi-ask/SKILL.md +2 -2
  81. package/plugins/kimi-codex/skills/kimi-cancel/SKILL.md +1 -1
  82. package/plugins/kimi-codex/skills/kimi-challenge/SKILL.md +1 -1
  83. package/plugins/kimi-codex/skills/kimi-pursue/SKILL.md +1 -1
  84. package/plugins/kimi-codex/skills/kimi-replay/SKILL.md +1 -1
  85. package/plugins/kimi-codex/skills/kimi-rescue/SKILL.md +1 -1
  86. package/plugins/kimi-codex/skills/kimi-result/SKILL.md +1 -1
  87. package/plugins/kimi-codex/skills/kimi-review/SKILL.md +3 -3
  88. package/plugins/kimi-codex/skills/kimi-setup/SKILL.md +1 -1
  89. package/plugins/kimi-codex/skills/kimi-status/SKILL.md +1 -1
  90. package/plugins/kimi-codex/skills/kimi-swarm/SKILL.md +1 -1
  91. package/plugins/kimi-codex/skills/kimi-swarm-write/SKILL.md +1 -1
@@ -5,7 +5,7 @@
5
5
  },
6
6
  "metadata": {
7
7
  "description": "Kimi for Claude Code: code questions, reviews, fixes, and parallel tasks through the local Kimi Code CLI.",
8
- "version": "2.2.1"
8
+ "version": "2.3.1"
9
9
  },
10
10
  "plugins": [
11
11
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kimi",
3
- "description": "Claude Code plugin that delegates read-only review, challenge, free-form ask, and write-capable rescue work to the local kimi-code CLI. Includes an opt-in stop-time review gate and a PreToolUse hook that enforces per-command safety.",
4
- "version": "2.2.1",
3
+ "description": "Kimi for Claude Code: ask, review, challenge, rescue, pursue, and swarm through the local Kimi Code CLI, with per-command PreToolUse safety hooks and an optional Stop-hook review gate.",
4
+ "version": "2.3.1",
5
5
  "homepage": "https://github.com/linxule/kimi-plugin-cc",
6
6
  "repository": "https://github.com/linxule/kimi-plugin-cc",
7
7
  "license": "Apache-2.0",
package/CHANGELOG.md CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
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
4
 
5
+ ## 2.3.1 — 2026-10-23
6
+
7
+ - Certify exact kimi-code 2.3.1 for all eight native-v2 operations after the source scan, plan-ON/OFF controls and full 15-test candidate smoke. Preserve the no-plan construction and document the new session-lock, internal-`ps`/PATH and legacy-trust-migration residuals. See [evidence](docs/upstream-2.3.1-certification.md).
8
+ - Give Kimi clearer operation-specific contracts: evidence-backed ask/review/challenge responses, complete rescue implementation and verification, honest pursue budgets, and a host-neutral, evidence-only review gate. Keep raw task text in job summaries and fallback titles while the full prompt drives execution and recovery.
9
+ - Include untracked files in working-tree reviews, keep `--base` snapshots isolated from dirty files, and make truncated-diff coverage explicit. Pursue now uses `/goal --` and enforces the 4000-character objective budget including injected guidance; swarm prompts distinguish soft total counts, hard concurrency and prompt-only coordination.
10
+ - Remove roughly 2,300 lines of stale or duplicated release archaeology from production comments while retaining current safety invariants. Capture the durable prompt, scope, comment-hygiene and release rules in `AGENTS.md`, `CONTRIBUTING.md` and the compatibility docs.
11
+ - Make missing-session-ID warnings distinguish resume from replay, and fail write-swarm patch capture explicitly when intent-to-add fails instead of silently omitting new files. Capture failures now fail the job and retain the worktree for recovery; successful runs preserve the `[swarm-write]` summary prefix.
12
+
13
+ ## 2.2.2 — 2026-10-22
14
+
15
+ - Certify exact kimi-code 2.3.0 for all eight native-v2 operations after its
16
+ source scan, plan-ON/OFF controls and full candidate smoke; legacy support
17
+ remains capped at 0.41.x. See [evidence](docs/upstream-2.3.0-certification.md).
18
+
19
+ - Preserve CLI 2.3.0's stdout-only occupied-session refusal as bounded structured
20
+ diagnostics, without treating it as prose, session lineage or an exit-status
21
+ override. Marker-first provenance checks are unchanged.
22
+ - Audit and pin the new stale-session reload path. Concurrent edits to trusted
23
+ operator journals remain an explicit residual; no new hook bypass within the
24
+ existing trust boundary was demonstrated. Clarify the no-plan certification
25
+ gates and remove stale ordering-gate instructions.
26
+
5
27
  ## 2.2.1 — 2026-10-15
6
28
 
7
29
  - Request per-run thinking effort with `--thinking <effort>` through the upstream environment binding; persist requested effort and replay it in detached workers without changing saved defaults. The review gate requests `off` by default; provider/model no-op cases remain explicit.
package/README.md CHANGED
@@ -40,7 +40,7 @@ You need:
40
40
  - macOS or Linux
41
41
  - Claude Code or Codex with plugin support
42
42
  - Node.js 22.5 or newer
43
- - Kimi Code CLI 2.2.0 (2.1.1 also certified), the recommended version for plugin 2.2.0
43
+ - Kimi Code CLI 2.3.1 (2.3.0 also certified), the recommended version for plugin 2.3.1
44
44
 
45
45
  Windows is not currently supported. Check your versions in a terminal:
46
46
 
@@ -108,7 +108,7 @@ needed to use the package. Kimi Code CLI and Node are still prerequisites.
108
108
  For an explicitly versioned local Claude Code plugin:
109
109
 
110
110
  ```sh
111
- npm install --prefix ~/.local/share/kimi-plugin-cc kimi-plugin-cc@2.2.1
111
+ npm install --prefix ~/.local/share/kimi-plugin-cc kimi-plugin-cc@2.3.1
112
112
  claude --plugin-dir ~/.local/share/kimi-plugin-cc/node_modules/kimi-plugin-cc
113
113
  ```
114
114
 
@@ -249,7 +249,7 @@ Contributors need Bun to run `bun run check`. The detailed engineering documents
249
249
  - macOS 或 Linux
250
250
  - 支持插件的 Claude Code 或 Codex
251
251
  - Node.js 22.5 或更高版本
252
- - Kimi Code CLI 2.2.0(2.1.1 亦已认证),这是插件 2.2.0 的推荐版本
252
+ - Kimi Code CLI 2.3.1(2.3.0 亦已认证),这是插件 2.3.1 的推荐版本
253
253
 
254
254
  目前不支持 Windows。在终端检查版本:
255
255
 
@@ -433,7 +433,7 @@ Il vous faut :
433
433
  - macOS ou Linux
434
434
  - une version de Claude Code ou de Codex prenant en charge les plugins
435
435
  - Node.js 22.5 ou une version ultérieure
436
- - Kimi Code CLI 2.2.0 (2.1.1 également certifiée), la version recommandée pour le plugin 2.2.0
436
+ - Kimi Code CLI 2.3.1 (2.3.0 également certifiée), la version recommandée pour le plugin 2.3.1
437
437
 
438
438
  Windows n'est pas pris en charge actuellement. Vérifiez les versions dans un terminal :
439
439
 
@@ -617,7 +617,7 @@ Les contributeurs ont besoin de Bun pour exécuter `bun run check`. La documenta
617
617
  - macOS または Linux
618
618
  - プラグインに対応した Claude Code または Codex
619
619
  - Node.js 22.5 以降
620
- - Kimi Code CLI 2.2.0(2.1.1 も認証済み。プラグイン 2.2.0 の推奨バージョン)
620
+ - Kimi Code CLI 2.3.1(2.3.0 も認証済み。プラグイン 2.3.1 の推奨バージョン)
621
621
 
622
622
  現在、Windows には対応していません。ターミナルでバージョンを確認します。
623
623
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: kimi-challenge
3
- description: Use this agent when Claude wants Kimi to run an adversarial review that challenges the implementation approach, design choices, tradeoffs, and assumptions rather than just flagging defects. Choose this agent when the user wants pushback on whether the chosen approach is the right one, not a tighter pass over implementation defects (see kimi-review for that).
3
+ description: Use this agent when the user or main thread wants Kimi to run an adversarial review that challenges the implementation approach, design choices, tradeoffs, and assumptions rather than just flagging defects. Choose this agent when the user wants pushback on whether the chosen approach is the right one, not a tighter pass over implementation defects (see kimi-review for that).
4
4
  model: sonnet
5
5
  tools: Bash
6
6
  color: yellow
@@ -21,7 +21,7 @@ Why this triggers: The user is asking for the alternative-perspective framing, n
21
21
  </example>
22
22
 
23
23
  <example>
24
- Context: The main Claude thread has just made a non-obvious design choice and the user says, "Stress test this."
24
+ Context: The main thread has just made a non-obvious design choice and the user says, "Stress test this."
25
25
  Why this triggers: Design-level stress testing is the canonical kimi-challenge target.
26
26
  </example>
27
27
 
@@ -46,7 +46,7 @@ When invoked:
46
46
  - call the shared companion runtime with one Bash invocation after any model-discovery step: `${CLAUDE_PLUGIN_ROOT}/scripts/companion.sh task challenge <args>`
47
47
  - if the companion reports `CHALLENGE_HOOK_NOT_INSTALLED`, surface the refusal and tell the user to run `/kimi:setup`; do not reach for `KIMI_PLUGIN_CC_SKIP_HOOK_CHECK`
48
48
  - the companion accepts a **strict allowlist** of flags: `--thinking <off|low|medium|high>` (requested per run), `--base <ref>`, `-m`/`--model <name>`, `--budget <dur>`. Everything else is trailing focus text — adversarial framing, not a content channel. Reasoning behavior follows the selected model and Kimi configuration unless `--thinking <effort>` requests one for this run (honoured by Kimi's own providers on models that can turn thinking off; other providers ignore it silently; the plugin cannot verify it). `--no-thinking` is rejected; use `--thinking off`
49
- - do not invent flags (`--file`, `--context`, `--path`, etc.). The runtime hard-fails with `INVALID_ARGS` on unknown flag-shaped tokens. If you need to attach file content or extended context, switch to `kimi-ask` or paste a brief summary into the focus text — challenge's payload is the git diff, not arbitrary file content
49
+ - do not invent flags (`--file`, `--context`, `--path`, etc.). The runtime hard-fails with `INVALID_ARGS` on unknown flag-shaped tokens. If you need to attach file content or extended context, switch to `kimi-ask` or paste a brief summary into the focus text — challenge's payload is the git diff plus untracked files listed by `git status` for working-tree challenges, or only the branch/commit diff with `--base` — not arbitrary file content
50
50
  - do not pass `--background` or `--wait` to the companion — the runtime rejects both with `INVALID_FLAGS` for review and challenge
51
51
  - if the user wants fire-and-forget behavior on a broad challenge, detach the Bash call itself with `run_in_background: true` instead of reaching for a companion flag; after launching, tell the user to check `/kimi:status` for progress
52
52
  - `/kimi:result <jobId> --json` returns a structured envelope with metadata plus the artifact body.
@@ -47,7 +47,7 @@ When invoked:
47
47
  - decide whether the task is genuinely AUTONOMOUS multi-turn pursuit rather than a single bounded delegated task (kimi-rescue) or read-only work (kimi-ask / kimi-review / kimi-swarm); when in doubt, prefer kimi-rescue — pursue is only for explicit hands-off autonomy
48
48
  - preserve the user's objective and explicit constraints with minimal reframing
49
49
  - call the shared companion runtime with one Bash invocation after any model-discovery step: `${CLAUDE_PLUGIN_ROOT}/scripts/companion.sh task pursue <args>`
50
- - the companion accepts a **strict allowlist** of flags: `--thinking <off|low|medium|high>` (requested per run), `--budget <duration>` (HARD wall-clock ceiling; e.g. `30m`, `1h`, `90s`; bare number = minutes; default 45m — the ONLY guaranteed bound on an autonomous run), `--turns <N>` (SOFT hint injected into the objective so Kimi calls `SetGoalBudget` itself; advisory, NOT enforced headless), and `-m`/`--model <name>`. Everything else is trailing objective text. Reasoning behavior follows the selected model and Kimi configuration unless `--thinking <effort>` requests one for this run (honoured by Kimi's own providers on models that can turn thinking off; other providers ignore it silently; the plugin cannot verify it). `--no-thinking` is rejected; use `--thinking off`
50
+ - the companion accepts a **strict allowlist** of flags: `--thinking <off|low|medium|high>` (requested per run), `--budget <duration>` (HARD wall-clock ceiling; e.g. `30m`, `1h`, `90s`; bare number = minutes; default 45m — the ONLY guaranteed bound on an autonomous run), `--turns <N>` (SOFT instruction injected into the objective to stop after at most N turns, NEVER a request to call the denied `SetGoalBudget` tool; advisory, NOT enforced headless, and a soft stop is NOT proof of completion), and `-m`/`--model <name>`. Everything else is trailing objective text. Reasoning behavior follows the selected model and Kimi configuration unless `--thinking <effort>` requests one for this run (honoured by Kimi's own providers on models that can turn thinking off; other providers ignore it silently; the plugin cannot verify it). `--no-thinking` is rejected; use `--thinking off`
51
51
  - do not invent flags. The runtime hard-fails with `INVALID_ARGS` on unknown flag-shaped tokens — pass `--` before flag-shaped objective text to forward it as objective text rather than a flag
52
52
  - **this is the plugin's highest blast radius: write-capable AND autonomous.** Only dispatch on explicit user intent for hands-off multi-turn pursuit. Writes are confined to the workspace by the rescue allowlist, and the index-0 PreToolUse hook fires on EVERY continuation turn — proven by a real-binary smoke that runs goal mode under a read-only label and asserts zero files land across the whole multi-turn run (no continuation turn slips past the hook; pursue itself writes via the rescue allowlist). pursue cannot mutate git state (the main thread owns branch/commit). The autonomy is bounded ONLY by `--budget`, so always pass an explicit one sized to the task and keep it WELL UNDER the 45m default unless the user named a larger window — a model-launched, possibly unwatched write loop should get the smallest budget that can plausibly finish, and never more than the user asked for; never try to remove it
53
53
  - pursue is foreground-only **at the runtime level** — `--background`, `--wait`, `--fresh`, and `--resume` are rejected with `INVALID_ARGS` (`--resume` intentionally: goal mode's `goalId` differs from the resume `sessionId`). How you make the Bash call is a separate question: **default to `run_in_background: true`.** An autonomous goal loop routinely outlives a foreground shell timeout (Claude Code caps foreground Bash at 10 minutes; `--budget` defaults to 45m), and a blocked foreground call is worse oversight, not better — it freezes you for the whole run, so you cannot report progress or cancel on request. What bounds this surface is the managed PreToolUse hook, the workspace allowlist, the no-git-mutation rule, and the mandatory finite `--budget` — none of which depend on anyone watching. Keep `--budget` finite and never remove it: it is the sole hard bound on the loop
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: kimi-rescue
3
- description: Use this agent proactively when the user wants to delegate a substantial investigation or implementation task to Kimi, especially multi-step bug hunts, cross-file refactors, or work the main Claude thread would rather offload than context-switch through. Choose this agent when the work is too large for an inline response but the user clearly wants it handed off, not just reviewed.
3
+ description: Use this agent proactively when the user wants to delegate a substantial investigation or implementation task to Kimi, especially multi-step bug hunts, cross-file refactors, or work the main thread would rather offload than context-switch through. Choose this agent when the work is too large for an inline response but the user clearly wants it handed off, not just reviewed.
4
4
  model: sonnet
5
5
  tools: Bash
6
6
  color: magenta
@@ -26,7 +26,7 @@ Why this triggers: The user is clearly asking to resume a prior Kimi rescue work
26
26
  </example>
27
27
 
28
28
  <example>
29
- Context: The main Claude thread has been debugging a multi-file runtime error for several turns, the investigation has grown beyond inline reasoning, and the user has not yet explicitly asked for delegation.
29
+ Context: The main thread has been debugging a multi-file runtime error for several turns, the investigation has grown beyond inline reasoning, and the user has not yet explicitly asked for delegation.
30
30
  Why this triggers: The task has outgrown the main thread's context; proactive rescue handoff preserves the user's attention and offloads the deep search into an isolated Kimi session. Proactive rescue is for a SINGLE bounded handoff of in-flight work — if the user wants Kimi to keep driving toward an objective on its own across many turns, that is autonomous goal mode and needs explicit intent (see kimi-pursue), not rescue's proactive path.
31
31
  </example>
32
32
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: kimi-review
3
- description: Use this agent when Claude wants an independent second-pair-of-eyes review from Kimi over a working-tree diff or branch diff. Choose this agent for read-only diff review — multi-file changes, design-risk changes, or when the user explicitly asks for another reviewer. Not for implementation work (see kimi-rescue) or free-form Q&A (see kimi-ask).
3
+ description: Use this agent when the user or main thread wants an independent second-pair-of-eyes review from Kimi over working-tree changes, including untracked files listed by `git status`, or a branch diff. Choose this agent for read-only change review — multi-file changes, design-risk changes, or when the user explicitly asks for another reviewer. Not for implementation work (see kimi-rescue) or free-form Q&A (see kimi-ask).
4
4
  model: sonnet
5
5
  tools: Bash
6
6
  color: cyan
@@ -16,7 +16,7 @@ Why this triggers: The user is explicitly asking for a second reviewer from Kimi
16
16
  </example>
17
17
 
18
18
  <example>
19
- Context: The main Claude thread just finished a multi-file refactor and the user says, "Does this hold up?"
19
+ Context: The main thread just finished a multi-file refactor and the user says, "Does this hold up?"
20
20
  Why this triggers: Multi-file, risk-bearing change where a cross-model reviewer adds value over another pass from the same thread.
21
21
  </example>
22
22
 
@@ -46,7 +46,7 @@ When invoked:
46
46
  - call the shared companion runtime with one Bash invocation after any model-discovery step: `${CLAUDE_PLUGIN_ROOT}/scripts/companion.sh review <args>`
47
47
  - if the companion reports `REVIEW_HOOK_NOT_INSTALLED`, surface the refusal and tell the user to run `/kimi:setup`; do not reach for `KIMI_PLUGIN_CC_SKIP_HOOK_CHECK`
48
48
  - the companion accepts a **strict allowlist** of flags: `--thinking <off|low|medium|high>` (requested per run), `--base <ref>`, `-m`/`--model <name>`, `--budget <dur>`. Everything else is trailing focus text — a short scope hint, not a content channel. Reasoning behavior follows the selected model and Kimi configuration unless `--thinking <effort>` requests one for this run (honoured by Kimi's own providers on models that can turn thinking off; other providers ignore it silently; the plugin cannot verify it). `--no-thinking` is rejected; use `--thinking off`
49
- - do not invent flags (`--file`, `--context`, `--path`, etc.). The runtime hard-fails with `INVALID_ARGS` on unknown flag-shaped tokens. If you need to attach file content or extended context, switch to `kimi-ask` or paste a brief summary into the focus text — review's payload is the git diff, not arbitrary file content
49
+ - do not invent flags (`--file`, `--context`, `--path`, etc.). The runtime hard-fails with `INVALID_ARGS` on unknown flag-shaped tokens. If you need to attach file content or extended context, switch to `kimi-ask` or paste a brief summary into the focus text — review's payload is the git diff plus untracked files listed by `git status` for working-tree reviews, or only the branch/commit diff with `--base` — not arbitrary file content
50
50
  - do not pass `--background` or `--wait` to the companion — the runtime rejects both with `INVALID_FLAGS` for review and challenge
51
51
  - if the user wants fire-and-forget behavior on a long review (multi-file diff, unclear scope), detach the Bash call itself with `run_in_background: true` instead of reaching for a companion flag; after launching, tell the user to check `/kimi:status` for progress
52
52
  - `/kimi:result <jobId> --json` returns a structured envelope with metadata plus the artifact body.
@@ -1,6 +1,6 @@
1
- # Claude Code commands
1
+ # Kimi task commands
2
2
 
3
- These Markdown files route Claude Code commands through `scripts/companion.sh` to the Node runtime. They also describe supported flags and model-selection rules. Codex uses the generated skills in `plugins/kimi-codex/skills/`.
3
+ These Markdown files expose Kimi's ask, review, challenge, rescue, pursue, and swarm capabilities as Claude Code commands, routed through `scripts/companion.sh` to the Node runtime and local Kimi Code CLI. They also describe supported flags and model-selection rules. Codex uses the generated skills in `plugins/kimi-codex/skills/`.
4
4
 
5
5
  | File | Purpose |
6
6
  | --- | --- |
@@ -14,7 +14,7 @@ Supported flags:
14
14
 
15
15
  - `--budget <dur>` — wall-clock ceiling (default 30m; `30m`, `1h`, `90s`, or bare minutes; maximum 24h)
16
16
 
17
- - `--base <ref>` — challenge against a branch/commit diff instead of the working tree
17
+ - `--base <ref>` — challenge against a branch/commit diff instead of the working tree. Working-tree challenges also include untracked files listed by `git status`; `--base` remains branch/commit-diff only.
18
18
  - `-m`, `--model <name>`
19
19
  - trailing text — adversarial focus or framing to steer the challenge
20
20
 
@@ -15,7 +15,7 @@ Supported flags:
15
15
  - `--thinking <off|low|medium|high>` (also `--thinking=<effort>`) — request effort for this process; other model-supported effort tokens pass through. `--no-thinking` is rejected; use `--thinking off`.
16
16
 
17
17
  - `--budget <duration>` — HARD wall-clock ceiling (e.g. `30m`, `1h`, `90s`; bare number = minutes). Default 45m. This is the only guaranteed bound on an autonomous run.
18
- - `--turns <N>` — SOFT cap: injected into the objective as a model instruction to call `SetGoalBudget`. Advisory, not enforced.
18
+ - `--turns <N>` — SOFT instruction injected into the objective to stop after at most N turns; it never requests the denied `SetGoalBudget` tool. Advisory, not enforced; a soft stop is not proof the objective is complete. The plugin's `--budget` wall-clock ceiling remains the hard bound.
19
19
  - `-m`, `--model <name>`
20
20
 
21
21
  Prototype limitations (experimental):
@@ -14,7 +14,7 @@ Supported flags:
14
14
 
15
15
  - `--budget <dur>` — wall-clock ceiling (default 30m; `30m`, `1h`, `90s`, or bare minutes; maximum 24h)
16
16
 
17
- - `--base <ref>` — review against a branch/commit diff instead of the working tree
17
+ - `--base <ref>` — review against a branch/commit diff instead of the working tree. Working-tree reviews also include untracked files listed by `git status`; `--base` remains branch/commit-diff only.
18
18
  - `-m`, `--model <name>`
19
19
  - trailing text — optional focus hint for the review
20
20
 
@@ -15,24 +15,16 @@ const companionEntrypoint = fileURLToPath(new URL(isCompiledRuntime ? "./compani
15
15
  const companionProjectRoot = path.resolve(path.dirname(companionEntrypoint), "..");
16
16
  const FAILURE_PERSIST_RETRY_DELAYS_MS = [100, 200, 400];
17
17
  export async function startBackgroundJob(job, prompt, context, paths, options) {
18
- // MUST be the same resolution the hook verifier uses. The worker re-verifies
19
- // the hook (rescue.ts / ask.ts, deliberately, so a background job cannot
20
- // outlive or bypass the check), and the verifier rebuilds the canonical
21
- // command from ITS OWN `process.argv0`. Spawning with a different spelling of
22
- // node than setup pinned makes the worker compute a different expected
23
- // command than the config holds → byte-exact mismatch → every background
24
- // rescue/ask refuses forever, with `/kimi:setup` unable to converge the two
25
- // sides (setup runs via companion.sh, whose argv0 is the stable symlink).
18
+ // Background spawn and hook verification must resolve the same stable Node
19
+ // path: the worker re-verifies the byte-exact hook command from its own
20
+ // runtime path, so a different spelling than setup pinned fails closed. For
21
+ // example, spawn(process.execPath) can resolve …/Cellar/node/<ver>/bin/node
22
+ // while setup pinned /opt/homebrew/bin/node.
26
23
  //
27
- // Concretely: `spawn(process.execPath)` gives the child an argv0 equal to the
28
- // fully symlink-resolved path (…/Cellar/node/<ver>/bin/node), whereas setup
29
- // pins /opt/homebrew/bin/node. Caught by Kimi's pre-release review of v1.9.0.
30
- // NOTE: this is deliberately NOT `resolveNodeBinary`, which additionally
31
- // REQUIRES an absolute override because the hook command runs under
32
- // `/bin/sh -c` with a possibly sanitized PATH. Spawning has no such
33
- // constraint — a bare name is resolved by spawn() via PATH — so the override
34
- // is honored verbatim here. Only the no-override default needs to change:
35
- // it must match what the verifier computes, hence `preferStableNodePath`.
24
+ // An explicit spawn override need not be absolute because spawn() resolves
25
+ // bare names through PATH. The hook command separately requires an absolute
26
+ // override because /bin/sh -c may have a sanitized PATH. Only the no-override
27
+ // default uses preferStableNodePath to match the verifier.
36
28
  const override = context.env.KIMI_PLUGIN_CC_NODE_BIN;
37
29
  const nodeBinary = override !== undefined && override.length > 0
38
30
  ? override
@@ -1,17 +1,5 @@
1
1
  // Subprocess client for `kimi -p --output-format stream-json`.
2
2
  //
3
- // Replaces runtime/wire/client.ts for v1.0. Both modules coexist during the
4
- // PR 1-3 transition; PR 4 deletes wire/. The contract is intentionally
5
- // narrower than the v0.4 wire client — one process per prompt, no in-band
6
- // approvals (PreToolUse hook handles those), no resumable JSON-RPC channel.
7
- //
8
- // Where v0.4 streamed turn events to a TurnCapture state machine,
9
- // stream-json gives us flattened OpenAI-shaped records that callers
10
- // reassemble at their own seam. The buffered result is the primary return
11
- // shape; callers needing incremental visibility (e.g., updating SQLite
12
- // phase as tools run) can pass `onRecord` to observe records as they arrive
13
- // without paying for a separate event-stream API.
14
- //
15
3
  // Per-job env (`KIMI_PLUGIN_CC_CMD`) is set on this spawn so the
16
4
  // PreToolUse hook can branch per command (review vs rescue vs ask). It is
17
5
  // passed via the spawn `env` option, not exported to a shell, so concurrent
@@ -32,12 +20,7 @@ import { collectDescendantIdentities, revalidateProcessIdentities, waitForProces
32
20
  const STDERR_TAIL_BYTES = 8192;
33
21
  /** Hard cap on awaiting diagnostics log drain before resolving the result. */
34
22
  const LOG_DRAIN_TIMEOUT_MS = 250;
35
- /**
36
- * Default delay between SIGTERM and SIGKILL when an abort fires.
37
- * Matches v0.4's `cancellation.ts` escalation timing for wire clients,
38
- * so rescue/ask/review continue to feel identical to a stuck-kimi user
39
- * after the v1.0 cutover.
40
- */
23
+ /** Default 1500 ms delay between SIGTERM and SIGKILL after an abort. */
41
24
  const DEFAULT_ESCALATION_MS = 1_500;
42
25
  /** Maximum time spent confirming POSIX tree exit after SIGKILL dispatch. */
43
26
  const POST_KILL_QUIESCENCE_MS = 500;
@@ -126,6 +109,7 @@ export async function runCliPrompt(opts) {
126
109
  let stderrTail = "";
127
110
  let announcedSessionId;
128
111
  let announcedGoalSummary;
112
+ let announcedCliError;
129
113
  let announcedSystemVersion;
130
114
  const hookMonitor = createHookEscapeMonitor({ commandLabel: opts.commandLabel,
131
115
  operationKind: opts.executionPlan.operationKind, trustedWorkspaceRoot: opts.trustedWorkspaceRoot, cwd: opts.cwd });
@@ -190,12 +174,16 @@ export async function runCliPrompt(opts) {
190
174
  for (const outcome of outcomes) {
191
175
  if (engineMismatchDetected)
192
176
  return;
177
+ if (outcome.cliError !== undefined) {
178
+ if (requireMarkerBeforeOutput("a CLI error record"))
179
+ return;
180
+ announcedCliError ??= outcome.cliError;
181
+ appendLogLine({ event: "cli_error", ...outcome.cliError });
182
+ continue;
183
+ }
193
184
  if (outcome.unknownRecord !== undefined) {
194
- // H3 forward-compat: a stream-json line with a role we don't model
195
- // (a future kimi-code role). Log it for diagnostics but keep it OUT of
196
- // records[] and out of onRecord — consumers iterate records[] expecting
197
- // assistant/tool only. Tolerated, not treated as malformed/error —
198
- // EXCEPT that on a native-v2 plan nothing may precede the marker.
185
+ // Unknown roles are diagnostic-only and excluded from consumer records;
186
+ // native-v2 still refuses any output before its marker.
199
187
  if (requireMarkerBeforeOutput(`an unknown-role (${outcome.unknownRecord.role}) record`)) {
200
188
  return;
201
189
  }
@@ -208,9 +196,7 @@ export async function runCliPrompt(opts) {
208
196
  if (outcome.goalSummary !== undefined) {
209
197
  if (requireMarkerBeforeOutput("goal.summary"))
210
198
  return;
211
- // Goal-mode summary is out-of-band metadata for our wrapper, not a
212
- // consumer-facing record. First-announce wins (a run emits exactly one,
213
- // at session end); capture and skip so records[] stays assistant/tool.
199
+ // Out-of-band metadata; first-announce-wins, excluded from consumer records.
214
200
  if (announcedGoalSummary === undefined) {
215
201
  announcedGoalSummary = outcome.goalSummary;
216
202
  appendLogLine({
@@ -544,21 +530,12 @@ export async function runCliPrompt(opts) {
544
530
  });
545
531
  };
546
532
  opts.signal?.addEventListener("abort", onAbort, { once: true });
547
- // Re-check `aborted` AFTER attaching the listener. `await mkdir` above
548
- // is the first synchronous yield point after the pre-spawn aborted
549
- // check — if abort fired during that await, the signal is already in
550
- // an aborted state by the time we reach addEventListener, which does
551
- // NOT re-fire for already-aborted signals (per the AbortSignal spec).
552
- // Without this re-check the spawned child is orphaned: SIGTERM/SIGKILL
553
- // is never sent and the process keeps holding the SQLite row + model
554
- // tokens. Audit report 28 (Codex H1) tracked this fix.
533
+ // Abort may occur during any pre-spawn await, and addEventListener does not
534
+ // replay an already-aborted signal. Re-check after attaching the listener so
535
+ // the spawned child cannot escape cancellation teardown.
555
536
  if (opts.signal?.aborted === true) {
556
537
  onAbort();
557
538
  }
558
- // Swap the pre-attached early listener for the real handler. These two
559
- // statements are synchronous and execute as one unit; no event can
560
- // interleave between marking earlyErrorHandled and attaching the new
561
- // listener.
562
539
  earlyErrorHandled = true;
563
540
  child.on("error", (err) => {
564
541
  appendLogLine({ event: "process_error", message: formatError(err) });
@@ -606,9 +583,10 @@ export async function runCliPrompt(opts) {
606
583
  await raceWithTimeout(logChain, LOG_DRAIN_TIMEOUT_MS);
607
584
  settle("resolve", {
608
585
  spawnedAt,
609
- settledAt: 0, // Filled at settlement, after the teardown barrier.
586
+ settledAt: 0,
610
587
  sessionId,
611
588
  goalSummary: announcedGoalSummary,
589
+ cliError: announcedCliError,
612
590
  systemVersion: announcedSystemVersion,
613
591
  observedEngine: announcedSystemVersion !== undefined
614
592
  ? "native-v2"
@@ -713,14 +691,6 @@ export class ResponseTimeoutError extends RuntimeError {
713
691
  *
714
692
  * The generic `withTimeout` (runtime/kimi-timeouts.ts) only rejects
715
693
  * the outer Promise — it has no handle on the kimi child process.
716
- * review/ask/review-gate previously wrapped `runCliPrompt` with
717
- * `withTimeout` and let the orphaned subprocess keep running until
718
- * it crashed or finished on its own. The reviewers (reports 17 +
719
- * 18) flagged this as critical for review_gate in particular: the
720
- * 8 s budget fires inside Claude Code's Stop hook, the parent
721
- * returns "allow stop", and a runaway kimi keeps holding the
722
- * SQLite row + model tokens. Subsequent `/kimi:cancel` can't reach
723
- * it because `kimi_pid` is null.
724
694
  *
725
695
  * Behavior:
726
696
  *
@@ -802,11 +772,6 @@ function buildArgs(opts) {
802
772
  args.push("--skills-dir", dir);
803
773
  }
804
774
  }
805
- // NOTE: thinking effort is requested through the env binding, never CLI argv.
806
- // Non-trait-driven providers or a base level already off ignore it silently;
807
- // an alwaysThinking model receives off unnormalized. stream-json carries no
808
- // thinking deltas (writeThinkingDelta() {} in the JSON writer), so the plugin
809
- // cannot observe whether the request was honoured.
810
775
  // -p accepts the prompt as the option value. We pass it as a separate argv
811
776
  // entry so prompts with leading dashes or whitespace are not interpreted as
812
777
  // additional flags.
@@ -817,15 +782,12 @@ function buildEnv(opts) {
817
782
  const env = { ...opts.env };
818
783
  if (opts.thinkingEffort !== undefined)
819
784
  env.KIMI_MODEL_THINKING_EFFORT = opts.thinkingEffort;
820
- // 2.2.0 audit: ambient trust starts project MCP stdio servers outside PreToolUse.
785
+ // Ambient workspace trust starts project MCP stdio servers outside PreToolUse.
821
786
  delete env.KIMI_CODE_TRUST_WORKSPACE;
822
- // kimi-code 0.33.0 inverted its CLI engine default: an unflagged `kimi -p`
823
- // now selects native agent-core-v2, while this upstream-documented flag pins
824
- // the legacy-v1 path. Native v2 still has a final-allow plan-file path that
825
- // can skip our later external PreToolUse hook, so the engine choice must be a
826
- // plugin-owned spawn invariant rather than ambient operator state. Older
827
- // kimi-code releases ignore the unknown flag. Always overwrite ambient false
828
- // values; accepting one would silently reopen v2 on 0.33+.
787
+ // Legacy-v1 plans use this flag on releases whose unflagged -p default can
788
+ // route to native-v2. Always overwrite ambient false values; older releases
789
+ // ignore it. The engine choice stays plugin-owned, while certified native-v2
790
+ // plans use the no-plan construction rather than a legacy pin.
829
791
  if (opts.executionPlan.intendedEngine === "legacy-v1") {
830
792
  env[KIMI_LEGACY_ENV] = KIMI_LEGACY_FORCED_VALUE;
831
793
  }
@@ -841,8 +803,6 @@ function buildEnv(opts) {
841
803
  env.KIMI_PLUGIN_CC_CMD = opts.commandLabel;
842
804
  }
843
805
  if (opts.swarmMaxConcurrency !== undefined) {
844
- // kimi-code 0.18.0+ caps AgentSwarm's normal-phase concurrency at this
845
- // value; older binaries ignore it. See the field doc on CliClientOptions.
846
806
  env.KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY = String(opts.swarmMaxConcurrency);
847
807
  }
848
808
  if (opts.trustedWorkspaceRoot !== undefined) {
@@ -19,32 +19,28 @@ import { startBackgroundJob } from "../background-spawn.js";
19
19
  import { hookRefusalDetails, hookRefusalRetryProtocol, maybeWarnHookMissing, verifyHookInstalled, } from "../hooks/install.js";
20
20
  import { warnInheritedBudget, captureTimeoutPartialOutput, assertCliResultSuccess, reassembleProseFromRecords, warnIfSessionIdMissing, warnHookEscapes } from "./cli-helpers.js";
21
21
  import { buildKimiSessionTitle, syncKimiSessionTitle } from "../session-title.js";
22
- // v1.0 cutover note (PR 2):
23
- //
24
- // The v0.4 wire client/initialize/prompt sequence is replaced with a
25
- // single `runCliPrompt` against `kimi -p --output-format stream-json`.
26
- // The PreToolUse hook reads `KIMI_PLUGIN_CC_CMD=ask` and applies the
27
- // same read-only tool policy as review/challenge/review_gate.
28
- //
29
- // Session id handling differs from v0.4:
30
- //
31
- // - v0.4 the client assigned the kimi session id upfront (passed via
32
- // `--session <uuid>` on the wire command line).
33
- // - v1.0 kimi-code assigns the session id and announces it via stderr
34
- // ("To resume this session: kimi -r <uuid>"). We capture that id
35
- // after the call and update the JobStore row.
36
- // - For `--resume`, we pass the prior session id via `-r`; kimi-code
37
- // keeps it across resumes.
38
22
  const ASK_SUMMARY_MAX = 120;
39
23
  const ASK_AGENT_PROFILE_PLACEHOLDER = "<cli-client>";
40
- const ASK_PROMPT_PREFIX = [
41
- "Answer the user's question directly in free-form prose.",
42
- "Stay read-only.",
24
+ const ASK_PROMPT_CONTRACT = [
25
+ "Answer directly in free-form prose.",
26
+ "For repository-dependent questions, inspect the relevant code with the allowed read tools and cite file:line for concrete code claims where useful.",
27
+ "Distinguish evidence from inference and state unknowns explicitly.",
28
+ "Do not use shell/Bash, writes, background tasks, or delegated operations.",
43
29
  "Do not emit JSON unless the user explicitly asks for it.",
30
+ "Do not narrate tool progress; make the final response self-contained.",
31
+ ];
32
+ const ASK_PROMPT_PREFIX = [
33
+ ...ASK_PROMPT_CONTRACT,
44
34
  "",
45
35
  "User question:",
46
36
  "",
47
37
  ].join("\n");
38
+ const ASK_CONTINUE_TASK = "Continue the previous ask conversation and answer any outstanding question.";
39
+ const ASK_RESUME_PROMPT = [
40
+ ...ASK_PROMPT_CONTRACT,
41
+ "",
42
+ ASK_CONTINUE_TASK,
43
+ ].join("\n");
48
44
  export async function runAsk(argv, context) {
49
45
  const parsed = parseAskArgs(argv);
50
46
  if (parsed.help)
@@ -91,7 +87,7 @@ export async function runAsk(argv, context) {
91
87
  ...persistedExecutionPlanFields(executionPlan),
92
88
  agent_profile: ASK_AGENT_PROFILE_PLACEHOLDER,
93
89
  prompt_digest: digestPrompt(askPrompt),
94
- summary: shorten(parsed.prompt ?? askPrompt, ASK_SUMMARY_MAX),
90
+ summary: shorten(askPromptSubject(askPrompt), ASK_SUMMARY_MAX),
95
91
  phase: parsed.background ? "queued" : "starting",
96
92
  final_output_path: null,
97
93
  stream_log_path: logPath,
@@ -192,9 +188,7 @@ export async function executeAskJob(jobId, prompt, context, options) {
192
188
  // kimi-code mints a new id on each turn.
193
189
  if (result.sessionId !== undefined &&
194
190
  result.sessionId.length > 0) {
195
- // length>0 guard: empty-string capture would poison the row. The
196
- // warning helper's null-ish check would also fire but only after
197
- // the bad write. (Kimi alpha.4 challenge finding #3.)
191
+ // Never persist an empty ID because NULL represents a missing session ID.
198
192
  store.updateRunningJob(job.job_id, { kimi_session_id_source: "announced", kimi_session_id: result.sessionId });
199
193
  }
200
194
  await syncKimiSessionTitle({
@@ -202,7 +196,7 @@ export async function executeAskJob(jobId, prompt, context, options) {
202
196
  env: context.env,
203
197
  cwd: job.cwd,
204
198
  sessionId: result.sessionId ?? job.kimi_session_id,
205
- title: buildKimiSessionTitle("ask", prompt.startsWith(ASK_PROMPT_PREFIX) ? prompt.slice(ASK_PROMPT_PREFIX.length) : prompt),
199
+ title: buildKimiSessionTitle("ask", askPromptSubject(prompt)),
206
200
  stderr: context.stderr,
207
201
  });
208
202
  // For ask, missing session id breaks both -r (latest-resume) and
@@ -322,14 +316,15 @@ function buildAskPrompt(question, reusedSession) {
322
316
  return ASK_PROMPT_PREFIX + question.trim();
323
317
  }
324
318
  if (reusedSession) {
325
- return [
326
- "Continue the previous ask conversation in free-form prose.",
327
- "Stay read-only.",
328
- "Do not emit JSON unless the user explicitly asks for it.",
329
- ].join("\n");
319
+ return ASK_RESUME_PROMPT;
330
320
  }
331
321
  throw new RuntimeError("INVALID_ARGS", "ask requires a question after the flags.", "ask.parse");
332
322
  }
323
+ function askPromptSubject(prompt) {
324
+ if (prompt.startsWith(ASK_PROMPT_PREFIX))
325
+ return prompt.slice(ASK_PROMPT_PREFIX.length);
326
+ return prompt === ASK_RESUME_PROMPT ? ASK_CONTINUE_TASK : prompt;
327
+ }
333
328
  function shorten(text, max) {
334
329
  const normalized = text.replace(/\s+/g, " ").trim();
335
330
  if (normalized.length <= max) {
@@ -34,27 +34,15 @@ export async function runCancel(argv, context) {
34
34
  if (job.pid === null && job.kimi_pid === null) {
35
35
  throw new RuntimeError("CANCEL_NOT_SUPPORTED", `Job ${job.job_id} does not have a recorded process id to cancel.`, "cancel.runtime");
36
36
  }
37
- // review_gate runs in a Stop hook; SIGTERMing kimi_pid causes the wire
38
- // process to exit with WIRE_PROCESS_EXITED, which the hook's catch path
39
- // would persist as `failed`. Pre-mark the row as `cancelled` here so the
40
- // user's intent is recorded canonically — the subsequent wire exit is a
41
- // no-op against an already-terminal row (markFailed has a WHERE
42
- // status='running' guard).
37
+ // review_gate runs in a Stop hook. Pre-mark the row as cancelled before
38
+ // signaling so the subprocess close/result path cannot persist a failure
39
+ // over the user's intent; later updates are no-ops on a terminal row.
43
40
  //
44
- // Because the row is now terminal, waitForCancellation returns
45
- // immediately on the status check and never escalates to SIGKILL. Run
46
- // an unconditional SIGTERM→1s→SIGKILL sequence on the recorded pids
47
- // here and return early so the lower-level wait/escalation path does
48
- // not skip cleanup. (v0.2.4)
41
+ // The terminal row also makes waitForCancellation return before its own
42
+ // escalation, so this path always attempts SIGTERM after the pre-mark
43
+ // attempt, waits 1s, and sends SIGKILL only if a recorded process remains
44
+ // live. A pre-mark failure is rethrown only after termination is attempted.
49
45
  if (job.command_type === "review_gate") {
50
- // Pre-mark before signaling so the row persists as `cancelled` rather
51
- // than the `failed` the hook's catch path would write on WIRE_PROCESS_EXITED.
52
- //
53
- // If the pre-mark itself fails (disk I/O, SQLite contention), we must
54
- // STILL signal the Kimi child — otherwise the user's cancel command
55
- // produces an alive-but-marked-cancelled stuck state. Capture the
56
- // pre-mark failure, run the SIGTERM→SIGKILL escalation unconditionally,
57
- // and rethrow at the end so the user sees the underlying error.
58
46
  let preMarkError;
59
47
  try {
60
48
  await withJobStore(paths, async (preMarkStore) => {