kimi-plugin-cc 2.2.1 → 2.2.2

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.
@@ -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.2.2"
9
9
  },
10
10
  "plugins": [
11
11
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kimi",
3
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",
4
+ "version": "2.2.2",
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,20 @@
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.2.2 — 2026-10-22
6
+
7
+ - Certify exact kimi-code 2.3.0 for all eight native-v2 operations after its
8
+ source scan, plan-ON/OFF controls and full candidate smoke; legacy support
9
+ remains capped at 0.41.x. See [evidence](docs/upstream-2.3.0-certification.md).
10
+
11
+ - Preserve CLI 2.3.0's stdout-only occupied-session refusal as bounded structured
12
+ diagnostics, without treating it as prose, session lineage or an exit-status
13
+ override. Marker-first provenance checks are unchanged.
14
+ - Audit and pin the new stale-session reload path. Concurrent edits to trusted
15
+ operator journals remain an explicit residual; no new hook bypass within the
16
+ existing trust boundary was demonstrated. Clarify the no-plan certification
17
+ gates and remove stale ordering-gate instructions.
18
+
5
19
  ## 2.2.1 — 2026-10-15
6
20
 
7
21
  - 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.0 (2.2.0 also certified), the recommended version for plugin 2.2.2
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.2.2
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.0(2.2.0 亦已认证),这是插件 2.2.2 的推荐版本
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.0 (2.2.0 également certifiée), la version recommandée pour le plugin 2.2.2
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.0(2.2.0 も認証済み。プラグイン 2.2.2 の推奨バージョン)
621
621
 
622
622
  現在、Windows には対応していません。ターミナルでバージョンを確認します。
623
623
 
@@ -126,6 +126,7 @@ export async function runCliPrompt(opts) {
126
126
  let stderrTail = "";
127
127
  let announcedSessionId;
128
128
  let announcedGoalSummary;
129
+ let announcedCliError;
129
130
  let announcedSystemVersion;
130
131
  const hookMonitor = createHookEscapeMonitor({ commandLabel: opts.commandLabel,
131
132
  operationKind: opts.executionPlan.operationKind, trustedWorkspaceRoot: opts.trustedWorkspaceRoot, cwd: opts.cwd });
@@ -190,6 +191,13 @@ export async function runCliPrompt(opts) {
190
191
  for (const outcome of outcomes) {
191
192
  if (engineMismatchDetected)
192
193
  return;
194
+ if (outcome.cliError !== undefined) {
195
+ if (requireMarkerBeforeOutput("a CLI error record"))
196
+ return;
197
+ announcedCliError ??= outcome.cliError;
198
+ appendLogLine({ event: "cli_error", ...outcome.cliError });
199
+ continue;
200
+ }
193
201
  if (outcome.unknownRecord !== undefined) {
194
202
  // H3 forward-compat: a stream-json line with a role we don't model
195
203
  // (a future kimi-code role). Log it for diagnostics but keep it OUT of
@@ -609,6 +617,7 @@ export async function runCliPrompt(opts) {
609
617
  settledAt: 0, // Filled at settlement, after the teardown barrier.
610
618
  sessionId,
611
619
  goalSummary: announcedGoalSummary,
620
+ cliError: announcedCliError,
612
621
  systemVersion: announcedSystemVersion,
613
622
  observedEngine: announcedSystemVersion !== undefined
614
623
  ? "native-v2"
@@ -99,7 +99,7 @@ export function assertCliResultSuccess(result, stage) {
99
99
  });
100
100
  }
101
101
  if (result.exitCode !== 0) {
102
- const tail = result.stderrTail.trim();
102
+ const tail = result.cliError?.message ?? result.stderrTail.trim();
103
103
  throw new RuntimeError("CLI_NONZERO_EXIT", [
104
104
  `kimi subprocess exited with code ${result.exitCode}`,
105
105
  result.signal ? ` (signal ${result.signal})` : "",
@@ -110,6 +110,7 @@ export function assertCliResultSuccess(result, stage) {
110
110
  signal: result.signal,
111
111
  record_count: result.records.length,
112
112
  malformed_count: result.malformed.length,
113
+ ...(result.cliError !== undefined && { cli_error: result.cliError }),
113
114
  stderr_tail_len: result.stderrTail.length,
114
115
  },
115
116
  });
@@ -593,7 +593,7 @@ function validateVersionSensitiveEvents(events, version) {
593
593
  return invalidHookSet(`version-sensitive event ${JSON.stringify(first.event)} requires a verified kimi-code version`, first.entry, first.line);
594
594
  }
595
595
  // Exact schemas reviewed at 2.0.0 (1b89e4b0), 2.0.1 (caf7d4e2),
596
- // 2.0.2 (9d07f634), 2.1.0 (52437299), 2.1.1 (f67e6398) and 2.2.0 (472192c3):
596
+ // 2.0.2 (9d07f634), 2.1.0 (52437299), 2.1.1 (f67e6398), 2.2.0 (472192c3) and 2.3.0 (b5e28fd6):
597
597
  // the additive events and HookDefSchema are unchanged. Require the full
598
598
  // version string AND matching components; no inferred 2.x compatibility.
599
599
  if (version.major === 2 && ((version.minor === 0 && ((version.version === "2.0.0" && version.patch === 0) ||
@@ -601,7 +601,8 @@ function validateVersionSensitiveEvents(events, version) {
601
601
  (version.version === "2.0.2" && version.patch === 2))) ||
602
602
  (version.minor === 1 && ((version.version === "2.1.0" && version.patch === 0) ||
603
603
  (version.version === "2.1.1" && version.patch === 1))) ||
604
- (version.minor === 2 && ((version.version === "2.2.0" && version.patch === 0))))) {
604
+ (version.minor === 2 && ((version.version === "2.2.0" && version.patch === 0))) ||
605
+ (version.minor === 3 && version.version === "2.3.0" && version.patch === 0))) {
605
606
  return { valid: true };
606
607
  }
607
608
  if (version.major !== 0) {
@@ -39,6 +39,7 @@ export const NATIVE_V2_CERTIFIED_VERSIONS = Object.freeze([
39
39
  "2.1.0",
40
40
  "2.1.1",
41
41
  "2.2.0",
42
+ "2.3.0",
42
43
  ]);
43
44
  /** Per-operation native-v2 certification. One green operation never certifies another. */
44
45
  export const NATIVE_V2_CERTIFIED = new Map([
@@ -12,6 +12,8 @@
12
12
  // {"role":"meta","type":"turn.step.retrying","failed_attempt":1,"next_attempt":2,"max_attempts":3,"delay_ms":300,"error_name":"APIProviderRateLimitError","error_message":"...","status_code":429}
13
13
  // {"role":"meta","type":"system.version","version":"0.24.2"} // experimental v2 only; modeled since v1.8.5 (SystemVersionRecord), filtered like other meta
14
14
  //
15
+ // {"type":"error","code":"session.occupied","message":"...","details":{...}} // 2.3.0; stdout-only refusal, exit 4
16
+ //
15
17
  // Notes on what does and does not appear here:
16
18
  // - The session.resume_hint meta record is NEW in kimi-code 0.2.0
17
19
  // (introduced at run-prompt.ts:477-505 in 0.2.0; the writer region —
@@ -263,6 +265,20 @@ function parseLine(line) {
263
265
  if (role === undefined && parsed["type"] === "goal.summary") {
264
266
  return validateGoalSummary(parsed, line);
265
267
  }
268
+ if (role === undefined && parsed["type"] === "error") {
269
+ if (typeof parsed["code"] !== "string" || parsed["code"].length === 0 ||
270
+ typeof parsed["message"] !== "string" || parsed["message"].length === 0 ||
271
+ (parsed["details"] !== undefined && !isRecord(parsed["details"]))) {
272
+ return { malformedLine: line, malformedReason: "error record field has unexpected type" };
273
+ }
274
+ // Keep bounded diagnostic fields only; holder metadata is not needed and
275
+ // must not become a session-id source or be copied into persisted errors.
276
+ return { cliError: {
277
+ type: "error",
278
+ code: parsed["code"].slice(0, 200),
279
+ message: parsed["message"].slice(0, 4000),
280
+ } };
281
+ }
266
282
  // H3 forward-compat: a non-empty string role we don't model (a role a future
267
283
  // kimi-code adds). Surface it out-of-band on the unknownRecord channel —
268
284
  // tolerated, not malformed — so the parser keeps working and the diagnostic
package/dist/version.js CHANGED
@@ -4,4 +4,4 @@
4
4
  // and AGENTS.md on every release. A future improvement would read this from
5
5
  // package.json at build time, but that adds a build-step dependency we
6
6
  // don't want yet.
7
- export const KIMI_PLUGIN_CC_VERSION = "2.2.1";
7
+ export const KIMI_PLUGIN_CC_VERSION = "2.2.2";
@@ -6,10 +6,12 @@ remain available. The package has no install scripts and no separate CLI.
6
6
 
7
7
  ## Publishing status
8
8
 
9
- As of October 15, 2026, [2.2.0 is live on npm](https://www.npmjs.com/package/kimi-plugin-cc/v/2.2.0), published by
10
- the release-event run of `publish.yml` (run 38658918855) through GitHub Actions OIDC with a signed
11
- provenance statement (sigstore log index 3256863983) — the first release where the tag-triggered
12
- path worked end to end without a manual dispatch. 2.0.8 (same day, run 38650044033) was the first
9
+ As of October 15, 2026, [2.2.1 is live on npm](https://www.npmjs.com/package/kimi-plugin-cc/v/2.2.1), published by
10
+ the release-event run of `publish.yml` (run 38720071707) through GitHub Actions OIDC with a signed
11
+ provenance statement (sigstore log index 3263398504; tarball shasum
12
+ `03907c66d440155763a860ab52b5107c0233938b`, registry propagation took a few minutes this time).
13
+ 2.2.0 (same day, run 38658918855, log index 3256863983) was the first release where the tag-triggered
14
+ path worked end to end without a manual dispatch; 2.0.8 (same day, run 38650044033) was the first
13
15
  OIDC publication; 2.0.7 (September 26) was the hand-published bootstrap.
14
16
  The first upload used the validated GitHub Actions artifact and interactive npm
15
17
  authentication. Its public tarball matched that artifact byte-for-byte, and a
@@ -19,7 +21,7 @@ The trusted publisher is configured for `linxule/kimi-plugin-cc`, workflow
19
21
  `publish.yml`, environment `npm`, with direct publishing allowed.
20
22
  `NPM_TRUSTED_PUBLISHING=true` is enabled in GitHub Actions. Future GitHub releases
21
23
  use short-lived OIDC credentials, without a stored npm token or interactive 2FA.
22
- The first npm OIDC publication will be the next release; do not republish 2.0.7.
24
+ OIDC publication is established; never republish an existing version.
23
25
 
24
26
  **2026-10-15 status.** The `v2.0.8` release triggered the first OIDC attempt. It
25
27
  failed twice on the publish step for reasons unrelated to the package: current
package/docs/safety.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Safety
2
2
 
3
- This guide describes the shipped 2.2.0 runtime. Read-only tasks deny file writes and shell commands. Rescue and pursue can edit your workspace. Write-swarm returns a patch from a temporary Git worktree.
3
+ This guide describes the current checkout runtime; 2.3.0 certification is unreleased. Read-only tasks deny file writes and shell commands. Rescue and pursue can edit your workspace. Write-swarm returns a patch from a temporary Git worktree.
4
4
 
5
- Native agent-core-v2 is certified at exact CLI versions `0.42.0`, `0.43.0`, `0.43.1`, `2.0.0`, `2.0.1`, `2.0.2`, `2.1.0`, and `2.1.1`, with plan mode disabled. The [runtime certification table](../runtime/kimi-engine.ts) controls routing. The hook is not an operating-system sandbox.
5
+ Native agent-core-v2 is certified at exact CLI versions `0.42.0`, `0.43.0`, `0.43.1`, `2.0.0`, `2.0.1`, `2.0.2`, `2.1.0`, `2.1.1`, `2.2.0`, and `2.3.0`, with plan mode disabled. The [runtime certification table](../runtime/kimi-engine.ts) controls routing. The hook is not an operating-system sandbox.
6
6
 
7
7
  ## Why the safety story is hook-based
8
8
 
@@ -156,6 +156,8 @@ Provenance: a native-v2 plan requires the `system.version` marker as the first s
156
156
 
157
157
  Residuals, unchanged from v1 and stated plainly: `config.toml` and the session journals are trusted operator state (an actor who can write them could already delete the `[[hooks]]` entry); the upstream hook runner fails open on its own internal errors; the plan-path comparison does not realpath (a symlink there would need a prior hook-allowed write). Native plan mode, tower, subagent fork, Remote Control and `--add-dir` are out of scope.
158
158
 
159
+ In CLI 2.3.0, stale-session retry can reread those same journals. Do not concurrently operate on or edit a plugin-managed session from another client. The upstream session lock is not a security boundary; no parent-side rescan can make that reload atomic.
160
+
159
161
  ## The rescue allowlist
160
162
 
161
163
  For `/kimi:rescue`, the hook delegates to [`evaluateRescueHookRequest`](../runtime/rescue-approval.ts). The allowlist has been extended since the original Wire-transport implementation. Highlights:
@@ -368,7 +370,7 @@ If you find a way to coax /kimi:review, /kimi:challenge, /kimi:review_gate, or /
368
370
 
369
371
  **Hook-escape monitor** (§1): the cli-client replays the pure hook policy on every streamed `tool_calls` entry; a call the policy denies whose tool result is not the hook's denial (byte-exact, or with upstream's repeat-breaker `<system-reminder>` decoration / handoff text) is recorded as `mismatch`, and a denied call still without a result at settlement as `unresolved`. Findings are **detection evidence, never a failure**: logged (`hook_escape`), persisted on the job row (`hook_escapes`, JSON), exposed by `status`/`result --json`, printed as a stderr `safety hook notice`, and carried in timeout details; the run continues, the job's outcome is unchanged, and the review gate stays fail-open and only annotates. The stream has no outcome field, so a mismatch is equally an upstream pre-hook rejection (unknown tool, disabled tool, invalid args, sensitive path, per-tool resolve errors), a coexisting hook or permission policy blocking first, or hook drift — failing the job needs positive execution evidence this stream does not provide. Streamed calls under read-only labels are covered (swarm subagents are in-process, not streamed); write labels only for the pure denials (plan/goal tools).
370
372
 
371
- A denied attempt alone is not a finding: the hook's denial text in the corresponding tool result (byte-exact, or carrying upstream's repeat-breaker decoration) proves enforcement and clears it. Anything else is recorded as `mismatch` with a 200-character excerpt; a denied call with no result at settlement as `unresolved`. **What a finding means:** the model received something other than the managed denial. On certified 2.2.0 that is produced just as readily by calls upstream rejects before the hook runs (`Tool "LS" not found`, `Invalid args for tool …`, the sensitive-path `PathSecurityError` for `.env`, per-tool resolve errors, `Tool skipped because a previous tool call stopped the turn.`), by a coexisting PreToolUse hook ahead of the managed block or an upstream permission policy blocking first, or by a cancel/budget abort landing before the result — none of which executed anything — as by a hook that failed open. Because the stream carries no outcome field, the plugin cannot tell these apart, so it reports and does not fail: the job completes or fails on its own merits, `status`/`result --json` carry `hook_escapes`, stderr prints a `safety hook notice`, and the review gate annotates `systemMessage` without changing its decision. Treat a finding as a prompt to run `/kimi:setup --check` and read the excerpt, not as proof of a breach; treat a *recurring* `mismatch` whose excerpt looks like tool output (`Wrote N bytes to …`) as a drifted hook. Coverage is streamed calls under read-only labels and pure denials under write labels — not filesystem-dependent rescue allowlist decisions, not swarm subagent calls (in-process, never streamed). Non-vacuous live control (CLI 2.2.0, 2026-10-15): with the hook command pointed at a nonexistent script upstream failed open, `Write` created the file, and the finding was `mismatch` with excerpt `Wrote 7 bytes to ESCAPE.txt`; with the hook intact the same prompt produced the byte-exact denial and no finding. Enforcement (stopping the run, failing the job) is deliberately not shipped: it needs positive execution evidence. The parked upstream ask is an `outcome: executed|vetoed|rejected` field on print-mode tool records; a plugin-side alternative is a per-job trace the hook writes before it exits.
373
+ A denied attempt alone is not a finding: the hook's denial text in the corresponding tool result (byte-exact, or carrying upstream's repeat-breaker decoration) proves enforcement and clears it. Anything else is recorded as `mismatch` with a 200-character excerpt; a denied call with no result at settlement as `unresolved`. **What a finding means:** the model received something other than the managed denial. On certified 2.2.0 that is produced just as readily by calls upstream rejects before the hook runs (`Tool "LS" not found`, `Invalid args for tool …`, the sensitive-path `PathSecurityError` for `.env`, per-tool resolve errors, `Tool skipped because a previous tool call stopped the turn.`), by a coexisting PreToolUse hook ahead of the managed block or an upstream permission policy blocking first, or by a cancel/budget abort landing before the result — none of which executed anything — as by a hook that failed open. Because the stream carries no outcome field, the plugin cannot tell these apart, so it reports and does not fail: the job completes or fails on its own merits, `status`/`result --json` carry `hook_escapes`, stderr prints a `safety hook notice`, and the review gate annotates `systemMessage` without changing its decision. Treat a finding as a prompt to run `/kimi:setup --check` and read the excerpt, not as proof of a breach; treat a *recurring* `mismatch` whose excerpt looks like tool output (`Wrote N bytes to …`) as a drifted hook. Coverage is streamed calls under read-only labels and pure denials under write labels — not filesystem-dependent rescue allowlist decisions, not swarm subagent calls (in-process, never streamed). Non-vacuous live control (CLI 2.2.0, 2026-10-15): with the hook command pointed at a nonexistent script upstream failed open, `Write` created the file, and the finding was `mismatch` with excerpt `Wrote 7 bytes to ESCAPE.txt`; with the hook intact the same prompt produced the byte-exact denial and no finding. Enforcement (stopping the run, failing the job) is deliberately not shipped: it needs positive execution evidence. The upstream ask, filed as MoonshotAI/kimi-code#4241, is an `outcome: executed|vetoed|rejected` field on print-mode tool records; a plugin-side alternative is a per-job trace the hook writes before it exits.
372
374
 
373
375
  ## Review-gate thinking request
374
376
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kimi-plugin-cc",
3
- "version": "2.2.1",
3
+ "version": "2.2.2",
4
4
  "description": "Kimi for Claude Code and Codex: code questions, reviews, fixes, and parallel tasks through the local Kimi Code CLI.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kimi",
3
- "version": "2.2.1",
3
+ "version": "2.2.2",
4
4
  "description": "Codex plugin that delegates review, challenge, ask, rescue, pursue, and swarm workflows to the local kimi-code CLI through the kimi-plugin-cc companion runtime.",
5
5
  "author": {
6
6
  "name": "linxule"
@@ -126,6 +126,7 @@ export async function runCliPrompt(opts) {
126
126
  let stderrTail = "";
127
127
  let announcedSessionId;
128
128
  let announcedGoalSummary;
129
+ let announcedCliError;
129
130
  let announcedSystemVersion;
130
131
  const hookMonitor = createHookEscapeMonitor({ commandLabel: opts.commandLabel,
131
132
  operationKind: opts.executionPlan.operationKind, trustedWorkspaceRoot: opts.trustedWorkspaceRoot, cwd: opts.cwd });
@@ -190,6 +191,13 @@ export async function runCliPrompt(opts) {
190
191
  for (const outcome of outcomes) {
191
192
  if (engineMismatchDetected)
192
193
  return;
194
+ if (outcome.cliError !== undefined) {
195
+ if (requireMarkerBeforeOutput("a CLI error record"))
196
+ return;
197
+ announcedCliError ??= outcome.cliError;
198
+ appendLogLine({ event: "cli_error", ...outcome.cliError });
199
+ continue;
200
+ }
193
201
  if (outcome.unknownRecord !== undefined) {
194
202
  // H3 forward-compat: a stream-json line with a role we don't model
195
203
  // (a future kimi-code role). Log it for diagnostics but keep it OUT of
@@ -609,6 +617,7 @@ export async function runCliPrompt(opts) {
609
617
  settledAt: 0, // Filled at settlement, after the teardown barrier.
610
618
  sessionId,
611
619
  goalSummary: announcedGoalSummary,
620
+ cliError: announcedCliError,
612
621
  systemVersion: announcedSystemVersion,
613
622
  observedEngine: announcedSystemVersion !== undefined
614
623
  ? "native-v2"
@@ -99,7 +99,7 @@ export function assertCliResultSuccess(result, stage) {
99
99
  });
100
100
  }
101
101
  if (result.exitCode !== 0) {
102
- const tail = result.stderrTail.trim();
102
+ const tail = result.cliError?.message ?? result.stderrTail.trim();
103
103
  throw new RuntimeError("CLI_NONZERO_EXIT", [
104
104
  `kimi subprocess exited with code ${result.exitCode}`,
105
105
  result.signal ? ` (signal ${result.signal})` : "",
@@ -110,6 +110,7 @@ export function assertCliResultSuccess(result, stage) {
110
110
  signal: result.signal,
111
111
  record_count: result.records.length,
112
112
  malformed_count: result.malformed.length,
113
+ ...(result.cliError !== undefined && { cli_error: result.cliError }),
113
114
  stderr_tail_len: result.stderrTail.length,
114
115
  },
115
116
  });
@@ -593,7 +593,7 @@ function validateVersionSensitiveEvents(events, version) {
593
593
  return invalidHookSet(`version-sensitive event ${JSON.stringify(first.event)} requires a verified kimi-code version`, first.entry, first.line);
594
594
  }
595
595
  // Exact schemas reviewed at 2.0.0 (1b89e4b0), 2.0.1 (caf7d4e2),
596
- // 2.0.2 (9d07f634), 2.1.0 (52437299), 2.1.1 (f67e6398) and 2.2.0 (472192c3):
596
+ // 2.0.2 (9d07f634), 2.1.0 (52437299), 2.1.1 (f67e6398), 2.2.0 (472192c3) and 2.3.0 (b5e28fd6):
597
597
  // the additive events and HookDefSchema are unchanged. Require the full
598
598
  // version string AND matching components; no inferred 2.x compatibility.
599
599
  if (version.major === 2 && ((version.minor === 0 && ((version.version === "2.0.0" && version.patch === 0) ||
@@ -601,7 +601,8 @@ function validateVersionSensitiveEvents(events, version) {
601
601
  (version.version === "2.0.2" && version.patch === 2))) ||
602
602
  (version.minor === 1 && ((version.version === "2.1.0" && version.patch === 0) ||
603
603
  (version.version === "2.1.1" && version.patch === 1))) ||
604
- (version.minor === 2 && ((version.version === "2.2.0" && version.patch === 0))))) {
604
+ (version.minor === 2 && ((version.version === "2.2.0" && version.patch === 0))) ||
605
+ (version.minor === 3 && version.version === "2.3.0" && version.patch === 0))) {
605
606
  return { valid: true };
606
607
  }
607
608
  if (version.major !== 0) {
@@ -39,6 +39,7 @@ export const NATIVE_V2_CERTIFIED_VERSIONS = Object.freeze([
39
39
  "2.1.0",
40
40
  "2.1.1",
41
41
  "2.2.0",
42
+ "2.3.0",
42
43
  ]);
43
44
  /** Per-operation native-v2 certification. One green operation never certifies another. */
44
45
  export const NATIVE_V2_CERTIFIED = new Map([
@@ -12,6 +12,8 @@
12
12
  // {"role":"meta","type":"turn.step.retrying","failed_attempt":1,"next_attempt":2,"max_attempts":3,"delay_ms":300,"error_name":"APIProviderRateLimitError","error_message":"...","status_code":429}
13
13
  // {"role":"meta","type":"system.version","version":"0.24.2"} // experimental v2 only; modeled since v1.8.5 (SystemVersionRecord), filtered like other meta
14
14
  //
15
+ // {"type":"error","code":"session.occupied","message":"...","details":{...}} // 2.3.0; stdout-only refusal, exit 4
16
+ //
15
17
  // Notes on what does and does not appear here:
16
18
  // - The session.resume_hint meta record is NEW in kimi-code 0.2.0
17
19
  // (introduced at run-prompt.ts:477-505 in 0.2.0; the writer region —
@@ -263,6 +265,20 @@ function parseLine(line) {
263
265
  if (role === undefined && parsed["type"] === "goal.summary") {
264
266
  return validateGoalSummary(parsed, line);
265
267
  }
268
+ if (role === undefined && parsed["type"] === "error") {
269
+ if (typeof parsed["code"] !== "string" || parsed["code"].length === 0 ||
270
+ typeof parsed["message"] !== "string" || parsed["message"].length === 0 ||
271
+ (parsed["details"] !== undefined && !isRecord(parsed["details"]))) {
272
+ return { malformedLine: line, malformedReason: "error record field has unexpected type" };
273
+ }
274
+ // Keep bounded diagnostic fields only; holder metadata is not needed and
275
+ // must not become a session-id source or be copied into persisted errors.
276
+ return { cliError: {
277
+ type: "error",
278
+ code: parsed["code"].slice(0, 200),
279
+ message: parsed["message"].slice(0, 4000),
280
+ } };
281
+ }
266
282
  // H3 forward-compat: a non-empty string role we don't model (a role a future
267
283
  // kimi-code adds). Surface it out-of-band on the unknownRecord channel —
268
284
  // tolerated, not malformed — so the parser keeps working and the diagnostic
@@ -4,4 +4,4 @@
4
4
  // and AGENTS.md on every release. A future improvement would read this from
5
5
  // package.json at build time, but that adds a build-step dependency we
6
6
  // don't want yet.
7
- export const KIMI_PLUGIN_CC_VERSION = "2.2.1";
7
+ export const KIMI_PLUGIN_CC_VERSION = "2.2.2";