kimi-plugin-cc 2.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/.claude-plugin/marketplace.json +16 -0
  3. package/.claude-plugin/plugin.json +32 -0
  4. package/CHANGELOG.md +1096 -0
  5. package/LICENSE +201 -0
  6. package/README.md +772 -0
  7. package/agents/kimi-ask.md +82 -0
  8. package/agents/kimi-challenge.md +82 -0
  9. package/agents/kimi-pursue.md +91 -0
  10. package/agents/kimi-rescue.md +85 -0
  11. package/agents/kimi-review.md +82 -0
  12. package/agents/kimi-swarm-write.md +92 -0
  13. package/agents/kimi-swarm.md +83 -0
  14. package/commands/README.md +16 -0
  15. package/commands/ask.md +32 -0
  16. package/commands/cancel.md +17 -0
  17. package/commands/challenge.md +29 -0
  18. package/commands/pursue.md +37 -0
  19. package/commands/replay.md +13 -0
  20. package/commands/rescue.md +32 -0
  21. package/commands/result.md +13 -0
  22. package/commands/review.md +29 -0
  23. package/commands/setup.md +23 -0
  24. package/commands/status.md +13 -0
  25. package/commands/swarm.md +38 -0
  26. package/dist/background-spawn.js +224 -0
  27. package/dist/cli-cancellation.js +43 -0
  28. package/dist/cli-client.js +845 -0
  29. package/dist/commands/ask.js +327 -0
  30. package/dist/commands/cancel.js +178 -0
  31. package/dist/commands/cli-helpers.js +112 -0
  32. package/dist/commands/models.js +140 -0
  33. package/dist/commands/not-implemented.js +4 -0
  34. package/dist/commands/pursue.js +311 -0
  35. package/dist/commands/registry.js +87 -0
  36. package/dist/commands/repair-sessions.js +159 -0
  37. package/dist/commands/replay.js +123 -0
  38. package/dist/commands/rescue.js +333 -0
  39. package/dist/commands/result.js +58 -0
  40. package/dist/commands/review-gate.js +393 -0
  41. package/dist/commands/review.js +218 -0
  42. package/dist/commands/setup.js +1132 -0
  43. package/dist/commands/status.js +27 -0
  44. package/dist/commands/swarm.js +576 -0
  45. package/dist/commands/worker.js +31 -0
  46. package/dist/companion.js +114 -0
  47. package/dist/config.js +22 -0
  48. package/dist/errors.js +40 -0
  49. package/dist/git.js +215 -0
  50. package/dist/hooks/approval-hook.js +112 -0
  51. package/dist/hooks/approval-policy.js +254 -0
  52. package/dist/hooks/config-safety.js +637 -0
  53. package/dist/hooks/install-paths.js +504 -0
  54. package/dist/hooks/install.js +281 -0
  55. package/dist/hooks/managed-block.js +745 -0
  56. package/dist/hooks/review-gate-stop.js +19 -0
  57. package/dist/job-store.js +559 -0
  58. package/dist/jobs.js +202 -0
  59. package/dist/kimi-command.js +72 -0
  60. package/dist/kimi-engine.js +624 -0
  61. package/dist/kimi-errors.js +220 -0
  62. package/dist/kimi-home.js +9 -0
  63. package/dist/kimi-timeouts.js +68 -0
  64. package/dist/kimi-version-probe.js +1410 -0
  65. package/dist/logging.js +22 -0
  66. package/dist/native-v2-preflight.js +417 -0
  67. package/dist/package.json +1 -0
  68. package/dist/parsing.js +553 -0
  69. package/dist/paths.js +27 -0
  70. package/dist/plugin-data.js +98 -0
  71. package/dist/process-tree.js +448 -0
  72. package/dist/render.js +159 -0
  73. package/dist/rescue-approval.js +951 -0
  74. package/dist/schemas/review-gate-output.js +43 -0
  75. package/dist/session-title.js +293 -0
  76. package/dist/stream-json.js +498 -0
  77. package/dist/types.js +1 -0
  78. package/dist/vendor/shell-quote/LICENSE +24 -0
  79. package/dist/vendor/shell-quote/index.js +1 -0
  80. package/dist/vendor/shell-quote/parse.js +229 -0
  81. package/dist/vendor/smol-toml/LICENSE +24 -0
  82. package/dist/vendor/smol-toml/date.js +127 -0
  83. package/dist/vendor/smol-toml/error.js +63 -0
  84. package/dist/vendor/smol-toml/extract.js +100 -0
  85. package/dist/vendor/smol-toml/parse.js +148 -0
  86. package/dist/vendor/smol-toml/primitive.js +179 -0
  87. package/dist/vendor/smol-toml/struct.js +184 -0
  88. package/dist/vendor/smol-toml/util.js +113 -0
  89. package/dist/version.js +7 -0
  90. package/docs/migration.md +215 -0
  91. package/docs/models.md +82 -0
  92. package/docs/registry-releases.md +70 -0
  93. package/docs/safety.md +318 -0
  94. package/docs/session-visibility.md +32 -0
  95. package/hooks/README.md +9 -0
  96. package/hooks/hooks.json +16 -0
  97. package/package.json +67 -0
  98. package/plugins/kimi-codex/.codex-plugin/plugin.json +39 -0
  99. package/plugins/kimi-codex/dist/background-spawn.js +224 -0
  100. package/plugins/kimi-codex/dist/cli-cancellation.js +43 -0
  101. package/plugins/kimi-codex/dist/cli-client.js +845 -0
  102. package/plugins/kimi-codex/dist/commands/ask.js +327 -0
  103. package/plugins/kimi-codex/dist/commands/cancel.js +178 -0
  104. package/plugins/kimi-codex/dist/commands/cli-helpers.js +112 -0
  105. package/plugins/kimi-codex/dist/commands/models.js +140 -0
  106. package/plugins/kimi-codex/dist/commands/not-implemented.js +4 -0
  107. package/plugins/kimi-codex/dist/commands/pursue.js +311 -0
  108. package/plugins/kimi-codex/dist/commands/registry.js +87 -0
  109. package/plugins/kimi-codex/dist/commands/repair-sessions.js +159 -0
  110. package/plugins/kimi-codex/dist/commands/replay.js +123 -0
  111. package/plugins/kimi-codex/dist/commands/rescue.js +333 -0
  112. package/plugins/kimi-codex/dist/commands/result.js +58 -0
  113. package/plugins/kimi-codex/dist/commands/review-gate.js +393 -0
  114. package/plugins/kimi-codex/dist/commands/review.js +218 -0
  115. package/plugins/kimi-codex/dist/commands/setup.js +1132 -0
  116. package/plugins/kimi-codex/dist/commands/status.js +27 -0
  117. package/plugins/kimi-codex/dist/commands/swarm.js +576 -0
  118. package/plugins/kimi-codex/dist/commands/worker.js +31 -0
  119. package/plugins/kimi-codex/dist/companion.js +114 -0
  120. package/plugins/kimi-codex/dist/config.js +22 -0
  121. package/plugins/kimi-codex/dist/errors.js +40 -0
  122. package/plugins/kimi-codex/dist/git.js +215 -0
  123. package/plugins/kimi-codex/dist/hooks/approval-hook.js +112 -0
  124. package/plugins/kimi-codex/dist/hooks/approval-policy.js +254 -0
  125. package/plugins/kimi-codex/dist/hooks/config-safety.js +637 -0
  126. package/plugins/kimi-codex/dist/hooks/install-paths.js +504 -0
  127. package/plugins/kimi-codex/dist/hooks/install.js +281 -0
  128. package/plugins/kimi-codex/dist/hooks/managed-block.js +745 -0
  129. package/plugins/kimi-codex/dist/hooks/review-gate-stop.js +19 -0
  130. package/plugins/kimi-codex/dist/job-store.js +559 -0
  131. package/plugins/kimi-codex/dist/jobs.js +202 -0
  132. package/plugins/kimi-codex/dist/kimi-command.js +72 -0
  133. package/plugins/kimi-codex/dist/kimi-engine.js +624 -0
  134. package/plugins/kimi-codex/dist/kimi-errors.js +220 -0
  135. package/plugins/kimi-codex/dist/kimi-home.js +9 -0
  136. package/plugins/kimi-codex/dist/kimi-timeouts.js +68 -0
  137. package/plugins/kimi-codex/dist/kimi-version-probe.js +1410 -0
  138. package/plugins/kimi-codex/dist/logging.js +22 -0
  139. package/plugins/kimi-codex/dist/native-v2-preflight.js +417 -0
  140. package/plugins/kimi-codex/dist/package.json +1 -0
  141. package/plugins/kimi-codex/dist/parsing.js +553 -0
  142. package/plugins/kimi-codex/dist/paths.js +27 -0
  143. package/plugins/kimi-codex/dist/plugin-data.js +98 -0
  144. package/plugins/kimi-codex/dist/process-tree.js +448 -0
  145. package/plugins/kimi-codex/dist/render.js +159 -0
  146. package/plugins/kimi-codex/dist/rescue-approval.js +951 -0
  147. package/plugins/kimi-codex/dist/schemas/review-gate-output.js +43 -0
  148. package/plugins/kimi-codex/dist/session-title.js +293 -0
  149. package/plugins/kimi-codex/dist/stream-json.js +498 -0
  150. package/plugins/kimi-codex/dist/types.js +1 -0
  151. package/plugins/kimi-codex/dist/vendor/shell-quote/LICENSE +24 -0
  152. package/plugins/kimi-codex/dist/vendor/shell-quote/index.js +1 -0
  153. package/plugins/kimi-codex/dist/vendor/shell-quote/parse.js +229 -0
  154. package/plugins/kimi-codex/dist/vendor/smol-toml/LICENSE +24 -0
  155. package/plugins/kimi-codex/dist/vendor/smol-toml/date.js +127 -0
  156. package/plugins/kimi-codex/dist/vendor/smol-toml/error.js +63 -0
  157. package/plugins/kimi-codex/dist/vendor/smol-toml/extract.js +100 -0
  158. package/plugins/kimi-codex/dist/vendor/smol-toml/parse.js +148 -0
  159. package/plugins/kimi-codex/dist/vendor/smol-toml/primitive.js +179 -0
  160. package/plugins/kimi-codex/dist/vendor/smol-toml/struct.js +184 -0
  161. package/plugins/kimi-codex/dist/vendor/smol-toml/util.js +113 -0
  162. package/plugins/kimi-codex/dist/version.js +7 -0
  163. package/plugins/kimi-codex/scripts/companion.sh +37 -0
  164. package/plugins/kimi-codex/scripts/review-gate-hook.sh +32 -0
  165. package/plugins/kimi-codex/skills/kimi-ask/SKILL.md +31 -0
  166. package/plugins/kimi-codex/skills/kimi-ask/agents/openai.yaml +6 -0
  167. package/plugins/kimi-codex/skills/kimi-cancel/SKILL.md +25 -0
  168. package/plugins/kimi-codex/skills/kimi-cancel/agents/openai.yaml +6 -0
  169. package/plugins/kimi-codex/skills/kimi-challenge/SKILL.md +31 -0
  170. package/plugins/kimi-codex/skills/kimi-challenge/agents/openai.yaml +6 -0
  171. package/plugins/kimi-codex/skills/kimi-pursue/SKILL.md +30 -0
  172. package/plugins/kimi-codex/skills/kimi-pursue/agents/openai.yaml +6 -0
  173. package/plugins/kimi-codex/skills/kimi-replay/SKILL.md +25 -0
  174. package/plugins/kimi-codex/skills/kimi-replay/agents/openai.yaml +6 -0
  175. package/plugins/kimi-codex/skills/kimi-rescue/SKILL.md +30 -0
  176. package/plugins/kimi-codex/skills/kimi-rescue/agents/openai.yaml +6 -0
  177. package/plugins/kimi-codex/skills/kimi-result/SKILL.md +25 -0
  178. package/plugins/kimi-codex/skills/kimi-result/agents/openai.yaml +6 -0
  179. package/plugins/kimi-codex/skills/kimi-review/SKILL.md +31 -0
  180. package/plugins/kimi-codex/skills/kimi-review/agents/openai.yaml +6 -0
  181. package/plugins/kimi-codex/skills/kimi-setup/SKILL.md +32 -0
  182. package/plugins/kimi-codex/skills/kimi-setup/agents/openai.yaml +6 -0
  183. package/plugins/kimi-codex/skills/kimi-status/SKILL.md +25 -0
  184. package/plugins/kimi-codex/skills/kimi-status/agents/openai.yaml +6 -0
  185. package/plugins/kimi-codex/skills/kimi-swarm/SKILL.md +31 -0
  186. package/plugins/kimi-codex/skills/kimi-swarm/agents/openai.yaml +6 -0
  187. package/plugins/kimi-codex/skills/kimi-swarm-write/SKILL.md +32 -0
  188. package/plugins/kimi-codex/skills/kimi-swarm-write/agents/openai.yaml +6 -0
  189. package/scripts/companion.sh +37 -0
  190. package/scripts/review-gate-hook.sh +32 -0
@@ -0,0 +1,498 @@
1
+ // Stream-JSON parser for `kimi -p --output-format stream-json`.
2
+ //
3
+ // Canonical record shapes (verified against kimi-code source at
4
+ // apps/kimi-code/src/cli/prompt-render.ts — `PromptJsonWriter` emits one JSON
5
+ // object per line via `JSON.stringify(message) + '\n'`):
6
+ //
7
+ // {"role":"assistant","content":"..."}
8
+ // {"role":"assistant","content":"...","tool_calls":[{type,id,function:{name,arguments}}]}
9
+ // {"role":"assistant","tool_calls":[...]}
10
+ // {"role":"tool","tool_call_id":"...","content":"..."}
11
+ // {"role":"meta","type":"session.resume_hint","session_id":"session_<uuid>","command":"kimi -r session_<uuid>","content":"To resume this session: kimi -r session_<uuid>"}
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
+ // {"role":"meta","type":"system.version","version":"0.24.2"} // experimental v2 only; modeled since v1.8.5 (SystemVersionRecord), filtered like other meta
14
+ //
15
+ // Notes on what does and does not appear here:
16
+ // - The session.resume_hint meta record is NEW in kimi-code 0.2.0
17
+ // (introduced at run-prompt.ts:477-505 in 0.2.0; the writer region —
18
+ // `PromptJsonResumeMetaMessage` / `writeResumeHint` / `PromptJsonWriter` —
19
+ // sits at apps/kimi-code/src/cli/run-prompt.ts:567-696 as of 0.9.0 and is
20
+ // verified compatible through 0.24.2. 2026-05-27 audit covered 0.4.0,
21
+ // 2026-05-28 audit covered 0.5.0 (run-prompt.ts zero-byte diff across
22
+ // both), 2026-05-31 audit covered 0.6.0, 2026-06-03 audit covered
23
+ // 0.7.0/0.8.0/0.9.0 in one cumulative pass, 2026-06-09 audit covered
24
+ // 0.10.0/0.11.0/0.12.0 in one cumulative 0.9.0→0.12.0 pass, 2026-06-12 audit
25
+ // covered 0.12.1/0.13.0/0.13.1/0.14.0/0.14.1 in one cumulative 0.12.0→0.14.1
26
+ // pass (records/ dir empty diff; the 0.13/0.14 packages/protocol/ REST+WS
27
+ // control API is a separate transport — run-prompt.ts imports none of it,
28
+ // `-p` stdout stays the direct PromptJsonWriter), 2026-06-13 audit covered
29
+ // the 0.14.2 patch (records/ + the PromptJsonWriter/writeResumeHint region
30
+ // both 0-byte; the patch is a repo-wide `.md`→`.md?raw` bundler-import
31
+ // migration plus a Bash-tool stdout/stderr streaming callback, neither
32
+ // touching the writer), and 2026-06-14 covered the 0.14.3 patch (all four
33
+ // scoped diffs 0-byte; the entire patch is a TUI model-picker
34
+ // provider-refresh change — PR #713 — off the `-p` path), and 2026-06-16
35
+ // covered the 0.15.0 minor (permission/hooks/run-prompt/cli all 0-byte by
36
+ // independent `git diff` byte-count; the only scoped change is records/ +
37
+ // session/ persistence churn — PR #786 drops app_version/resumed from the
38
+ // .records/ metadata artifact, a SessionSkillRegistry rename, a static
39
+ // model-capability lookup — none of it on the `-p` stdout stream; plus an
40
+ // additive `transport:'sse'` MCP config variant the plugin never writes),
41
+ // and 2026-06-17 covered the 0.16.0 minor (permission/hooks/run-prompt all
42
+ // 0-byte; the only argv change registers a new `kimi vis` subcommand off
43
+ // the `-p` path, and the records/replay/compaction/logging churn is
44
+ // internal — not on the stdout stream; GREEN smoke 7/0 on the 0.16.0
45
+ // binary), 2026-06-19 covered the 0.16.0→0.18.0 jump (0.17.0/0.17.1/0.18.0;
46
+ // 03-hooks.diff 0-byte, run-prompt.ts only a telemetry refactor outside the
47
+ // writer, the sole permission change a NON-auto-mode GoalStartReviewAsk that
48
+ // is dead on `-p`), and 2026-06-23 covered the 0.18.0→0.19.1 minor (the
49
+ // writer + records/ 0-byte; the bumping feature #812 `--add-dir` touches
50
+ // only an approve policy at the queue tail, structurally dead below the
51
+ // `-p` auto-mode approve and still pre-empted by our index-0 hook even when
52
+ // project-local `.kimi-code/local.toml` makes additionalDirs non-empty;
53
+ // #963's new `turn.ended` reason:'filtered' is a failure REASON not a new
54
+ // stdout record SHAPE;
55
+ // GREEN smoke 9/0 on the operator's 0.19.1 binary —
56
+ // .claude/kimi-code-research/reports/85-upstream-0191-surface.md), and
57
+ // 2026-06-26 covered the 0.19.1→0.20.0 minor (run-prompt.ts + options.ts +
58
+ // records/ all 0-byte; #1040's new `warning` agent event is swallowed on `-p`
59
+ // at run-prompt.ts:495 `case 'warning': return;`, so it never reaches this
60
+ // parser; #1062's tool-result budget adds a `truncated` flag to tool-result
61
+ // CONTENT, not the record SHAPE; the new runShellCommand RPC + kimi server/web
62
+ // stack are off the `-p` path — report 88. Smoke NOT run this cert: the 0.20.0
63
+ // `bun run smoke:real` was quota-blocked, 403 usage-limit, records:[] — an
64
+ // operator-billing false alarm, not a compat break; certified on source audit;
65
+ // the later 0.20.2 smoke ran GREEN 9/0 on 2026-06-29), and 2026-07-01
66
+ // covered the 0.20.3→0.21.1 minor+patch (report 93; agent/records/ 0-byte,
67
+ // run-prompt.ts writer/resume_hint/goal.summary unchanged, #1204 plugin
68
+ // slash commands off the `-p` path, #1233 cleanup timeout after the writer
69
+ // flush; GREEN smoke 9/0 on the operator's 0.21.1 binary), and 2026-07-05
70
+ // covered the 0.21.1→0.22.3 minor+patch (reports 94/95; hook engine
71
+ // unchanged, policy order still hook-first, writer shape compatible; 0.22.3's
72
+ // prompt-mode background-drain happens after assistant-output flush and is
73
+ // bounded by plugin budgets; shell-output caps and session-owned
74
+ // media-originals do not alter the NDJSON record schema; GREEN smoke 9/0 on
75
+ // a temp-installed 0.22.3 binary), and 2026-07-07 covered the
76
+ // 0.22.3→0.23.1 minor (report 96; hook engine unchanged, policy order still
77
+ // hook-first, PromptJsonWriter-compatible scoped `run-prompt.ts` delta only
78
+ // adds telemetry sessionId; `select_tools` is denied by our hook unless
79
+ // deliberately allowlisted; observability records are persisted agent-log
80
+ // records, not new stdout NDJSON shapes; GREEN smoke 9/0 on a temp-installed
81
+ // 0.23.1 binary), and 2026-07-08 covered the 0.23.2 patch (daily checkup;
82
+ // no writer/resume_hint/goal.summary drift, `02-permission.diff` and
83
+ // `05-session-bootstrap.diff` 0-byte; the only scoped `run-prompt.ts`
84
+ // change keeps the cleanup timeout ref'd so failed headless `-p` turns exit
85
+ // non-zero reliably, and the only hook-engine-adjacent change adds
86
+ // `windowsHide:true` to hook child-process spawn options on Windows; GREEN
87
+ // smoke 9/0 on a temp-installed 0.23.2 binary), and 2026-07-09 covered the
88
+ // 0.23.3/0.23.4 patches (daily checkup; permission + both hook-tree diffs
89
+ // 0-byte; #1516 keeps prompt-mode goals alive across continuation turns
90
+ // until terminal without changing PromptJsonWriter, session.resume_hint,
91
+ // or goal.summary shapes; the wire/session delta is internal provider-auth
92
+ // and media-projection plumbing, while the bootstrap delta adds `[image]`
93
+ // limits without changing hook or permission construction; GREEN smoke 9/0
94
+ // on a temp-installed 0.23.4 binary, including two-minute multi-turn goal
95
+ // confinement and both write-swarm worktree-boundary assertions), and
96
+ // 2026-07-11 covered the 0.23.5 patch at tag commit `352a4492`
97
+ // (permission, both hook trees, and session bootstrap all 0-byte; the wire
98
+ // diff only adds the internal `media-stripped` projection type). The one
99
+ // live stdout change is this file's `turn.step.retrying` meta record: it is
100
+ // modeled exactly and filtered from consumer records while malformed shapes
101
+ // remain diagnostic. The post-change exact-binary smoke was GREEN 9/0 in
102
+ // 229.56s, including the full goal budget and both write-swarm boundaries),
103
+ // and 2026-07-12 covered the 0.23.6 patch at tag commit `b5c236d0`
104
+ // (permission and both hook trees 0-byte; no new PromptJsonWriter record;
105
+ // `run-prompt.ts` now keeps print mode alive across active goals, pending
106
+ // cron fires, and opt-in background steering, all still bounded externally
107
+ // by plugin budgets; subagent timeout config and the capability rename to
108
+ // dynamically_loaded_tools do not alter stdout shape). Exact-binary smoke
109
+ // was GREEN 9/0 in 274.55s, including the full goal budget and both
110
+ // write-swarm boundaries), and 2026-07-15 covered the 0.23.6→0.24.2
111
+ // minor (Phase-1 reports 97-100; permission and the live session/hooks
112
+ // surfaces 0-byte; default-v1 writer/resume/retry/goal shapes compatible;
113
+ // GREEN exact-binary v1 smoke 9/0, 39 assertions in 261.33s). A truthy
114
+ // native v2 shares the writer shapes and terminal session.resume_hint but
115
+ // prepends one new
116
+ // role:"meta", type:"system.version" record. Unknown meta is intentionally
117
+ // non-fatal: it becomes diagnostic-only, never enters records[]/onRecord,
118
+ // and cannot affect prose or session pinning. A targeted exact-v2 review
119
+ // smoke denied the forced write (1 pass / 8 skip / 0 fail).
120
+ // 2026-07-16 covered 0.25.0 + 0.26.0 (the 0.25.0 step added only 943 B
121
+ // of permission telemetry; all three primary safety surfaces were 0-byte
122
+ // on the 0.26.0 step; no new PromptJsonWriter record on either),
123
+ // 2026-07-18 covered 0.27.0, 2026-07-21 covered 0.28.1,
124
+ // 2026-07-23/24 covered 0.29.0 + 0.29.1, and 2026-07-27 covered 0.29.2
125
+ // (permission/hooks stayed 0-byte across every step; the 0.29.x
126
+ // wire/bootstrap changes did not alter PromptJsonWriter output; GREEN
127
+ // exact-binary smoke 10/0, 43 assertions, on each of exact 0.27.0,
128
+ // 0.28.1, 0.29.0, 0.29.1, and 0.29.2; the 0.29.1 veto-event refactor
129
+ // and 0.29.2 automatic scope-activation refactor preserved the modeled
130
+ // system.version signal and terminal session pinning), 2026-07-29 covered
131
+ // 0.30.0, 2026-07-31 covered 0.31.0, 2026-08-01 covered 0.31.1, and
132
+ // 2026-08-08 covered 0.32.0 through 0.34.0, 2026-08-12 covered 0.35.0,
133
+ // 2026-08-13 covered 0.36.0, 2026-08-24 covered 0.37.0 through
134
+ // 0.38.0, 2026-08-27 covered 0.39.0 (prompt-render.ts byte-identical;
135
+ // the MCP structured-content and error-code changes shift only prose
136
+ // inside opaque tool content strings), and 2026-09-02 covered 0.40.0
137
+ // (wire/session scope 0 bytes; run-prompt.ts absent from the diff). The
138
+ // 2026-09-06 covered 0.41.0 (v1 core, prompt-render.ts, goal-prompt.ts,
139
+ // and prompt-session.ts unchanged; exact-binary smoke 12/0, 55 assertions).
140
+ // The legacy-v1 writer remains compatible through 0.41.0;
141
+ // custom profiles can change content/tools but
142
+ // not the NDJSON envelope. In 0.33.0 native v2 became the unflagged default,
143
+ // so v1.9.6 forces KIMI_CODE_LEGACY_FLAG=1 in every accepted child while
144
+ // retaining the old experimental-selector refusal. This parser continues
145
+ // to model v2's system.version record for diagnostics and a future safe
146
+ // re-enable; absence of that record is now a legacy-pin smoke assertion.
147
+ // NB: from 0.6.0 run-prompt.ts
148
+ // is no longer a whole-file zero-byte diff — at 0.6.0 it gained a
149
+ // resume-session workDir guard, and at 0.8.0 it gained headless goal
150
+ // mode (`runHeadlessGoal`) — but both changes are OUTSIDE the
151
+ // stream-json writer, which every audit confirmed byte-identical by
152
+ // content/blob SHA. Goal mode also writes a `{"type":"goal.summary",...}`
153
+ // line (no `role` field) before the resume hint when the prompt is
154
+ // `/goal`-prefixed (on 0.8–0.11 the `goal-command` experimental flag must
155
+ // also be on; 0.12.0 removed that gate — PR #569 — so the `/goal` prefix
156
+ // alone triggers it). Read-only commands never trigger it (their trimmed
157
+ // prompt never starts with `/goal`); the v1.1 /kimi:pursue command is
158
+ // the intentional consumer — it is recognized as a first-class record on
159
+ // the dedicated `StreamJsonOutcome.goalSummary` channel (see
160
+ // GoalSummaryRecord below), NOT routed to the malformed channel. See
161
+ // reports 47-65, 72-76).
162
+ // The hint is emitted once per prompt run at session END
163
+ // (after runPromptTurn settles), not at session start. In 0.1.x the
164
+ // resume hint went to stderr only; 0.2.0+ emits a structured
165
+ // stream-json record on stdout when `--output-format stream-json` is
166
+ // selected (text-output mode still writes the stderr line). Our
167
+ // cli-client consumes the meta record's `session_id` for resume/replay
168
+ // routing.
169
+ // - hook.result events arrive as role:"assistant" with the block rendered as
170
+ // plain text (see formatHookResultPlain in run-prompt.ts). Our
171
+ // PreToolUse hook's deny reason therefore surfaces in the assistant
172
+ // stream, not on a separate channel.
173
+ // - thinking.delta events are silently discarded by the CLI's
174
+ // PromptJsonWriter (`writeThinkingDelta(): void {}`).
175
+ // - tool.progress events are written to stderr only, never entering
176
+ // stream-json.
177
+ // - assistant messages are only emitted when content OR tool_calls are
178
+ // non-empty; we still defend against the empty case for resilience.
179
+ export const MAX_STREAM_JSON_LINE_BYTES = 1_048_576;
180
+ /**
181
+ * Stateful line-buffer parser. Hold partial-line bytes across chunk boundaries.
182
+ *
183
+ * Lifecycle:
184
+ * - `push(chunk)` — consume bytes; returns outcomes for any complete lines
185
+ * that finished within this chunk.
186
+ * - `flush()` — at end of stream, force-parse the trailing buffer if any.
187
+ * Stream-json emits a newline after every record (run-prompt.ts:573), so
188
+ * a non-empty flush remainder indicates an unfinished record (likely an
189
+ * interrupted spawn).
190
+ *
191
+ * Outcomes are non-throwing — malformed lines surface via `malformedLine` /
192
+ * `malformedReason` so callers can route them to a diagnostics log without
193
+ * crashing the parser. Blank lines (between records, or trailing whitespace)
194
+ * are skipped silently.
195
+ */
196
+ export class StreamJsonParser {
197
+ buffer = "";
198
+ push(chunk) {
199
+ this.buffer += typeof chunk === "string" ? chunk : chunk.toString("utf8");
200
+ const outcomes = this.drainCompleteLines();
201
+ if (this.buffer.indexOf("\n") === -1 &&
202
+ Buffer.byteLength(this.buffer, "utf8") > MAX_STREAM_JSON_LINE_BYTES) {
203
+ outcomes.push({
204
+ malformedLine: makeOversizePreview(this.buffer),
205
+ malformedReason: `stream-json line exceeded ${MAX_STREAM_JSON_LINE_BYTES} bytes without newline`,
206
+ });
207
+ this.buffer = "";
208
+ }
209
+ return outcomes;
210
+ }
211
+ flush() {
212
+ const remainder = this.buffer;
213
+ this.buffer = "";
214
+ if (remainder.length === 0)
215
+ return [];
216
+ if (remainder.replace(/\r/g, "").length === 0)
217
+ return [];
218
+ return [parseLine(remainder)];
219
+ }
220
+ drainCompleteLines() {
221
+ const out = [];
222
+ let newlineIndex = this.buffer.indexOf("\n");
223
+ while (newlineIndex !== -1) {
224
+ const line = this.buffer.slice(0, newlineIndex);
225
+ this.buffer = this.buffer.slice(newlineIndex + 1);
226
+ // Skip blank lines (the writer doesn't emit them, but tolerate
227
+ // CRLF-doubled or trailing whitespace defensively).
228
+ if (line.replace(/\r/g, "").length > 0) {
229
+ out.push(parseLine(line));
230
+ }
231
+ newlineIndex = this.buffer.indexOf("\n");
232
+ }
233
+ return out;
234
+ }
235
+ }
236
+ function parseLine(line) {
237
+ const cleaned = line.endsWith("\r") ? line.slice(0, -1) : line;
238
+ let parsed;
239
+ try {
240
+ parsed = JSON.parse(cleaned);
241
+ }
242
+ catch (err) {
243
+ return {
244
+ malformedLine: line,
245
+ malformedReason: `json parse: ${err.message}`,
246
+ };
247
+ }
248
+ if (!isRecord(parsed)) {
249
+ return { malformedLine: line, malformedReason: "not a JSON object" };
250
+ }
251
+ const role = parsed["role"];
252
+ if (role === "assistant") {
253
+ return validateAssistant(parsed, line);
254
+ }
255
+ if (role === "tool") {
256
+ return validateToolResult(parsed, line);
257
+ }
258
+ if (role === "meta") {
259
+ return validateMeta(parsed, line);
260
+ }
261
+ // Role-less goal-mode summary (kimi-code 0.8.0+). Keyed by `type`, not
262
+ // `role`, so it's surfaced on the dedicated goalSummary outcome channel.
263
+ if (role === undefined && parsed["type"] === "goal.summary") {
264
+ return validateGoalSummary(parsed, line);
265
+ }
266
+ // H3 forward-compat: a non-empty string role we don't model (a role a future
267
+ // kimi-code adds). Surface it out-of-band on the unknownRecord channel —
268
+ // tolerated, not malformed — so the parser keeps working and the diagnostic
269
+ // log distinguishes "new upstream role" from a genuinely broken line. It
270
+ // never enters records[] (see UnknownRoleRecord + the consumer sweep).
271
+ if (typeof role === "string" && role.length > 0) {
272
+ return { unknownRecord: { role, raw: parsed } };
273
+ }
274
+ // Genuinely malformed: no `role` at all (and not a recognized role-less typed
275
+ // record like goal.summary), or a non-string role. Surface as malformed.
276
+ return {
277
+ malformedLine: line,
278
+ malformedReason: `unknown role: ${JSON.stringify(role)}`,
279
+ };
280
+ }
281
+ function validateGoalSummary(parsed, line) {
282
+ // Each field is `T | null` upstream (null when no goal snapshot exists). A
283
+ // missing field is tolerated as null; a present-but-wrong-typed field is
284
+ // malformed (so a shape change surfaces in diagnostics rather than silently
285
+ // coercing). Mirrors the defensive posture of validateMeta.
286
+ const asStringOrNull = (v) => v === undefined || v === null ? null : typeof v === "string" ? v : undefined;
287
+ const asNumberOrNull = (v) => v === undefined || v === null
288
+ ? null
289
+ : typeof v === "number" && Number.isFinite(v)
290
+ ? v
291
+ : undefined;
292
+ const goalId = asStringOrNull(parsed["goalId"]);
293
+ const status = asStringOrNull(parsed["status"]);
294
+ const reason = asStringOrNull(parsed["reason"]);
295
+ const turnsUsed = asNumberOrNull(parsed["turnsUsed"]);
296
+ const tokensUsed = asNumberOrNull(parsed["tokensUsed"]);
297
+ const wallClockMs = asNumberOrNull(parsed["wallClockMs"]);
298
+ if (goalId === undefined ||
299
+ status === undefined ||
300
+ reason === undefined ||
301
+ turnsUsed === undefined ||
302
+ tokensUsed === undefined ||
303
+ wallClockMs === undefined) {
304
+ return { malformedLine: line, malformedReason: "goal.summary field has unexpected type" };
305
+ }
306
+ const goalSummary = {
307
+ type: "goal.summary",
308
+ goalId,
309
+ status,
310
+ reason,
311
+ turnsUsed,
312
+ tokensUsed,
313
+ wallClockMs,
314
+ };
315
+ return { goalSummary };
316
+ }
317
+ function validateMeta(parsed, line) {
318
+ const type = parsed["type"];
319
+ if (type === "session.resume_hint") {
320
+ const sessionId = parsed["session_id"];
321
+ if (typeof sessionId !== "string" || sessionId.length === 0) {
322
+ return {
323
+ malformedLine: line,
324
+ malformedReason: "meta.session.resume_hint.session_id not non-empty string",
325
+ };
326
+ }
327
+ const record = {
328
+ role: "meta",
329
+ type: "session.resume_hint",
330
+ sessionId,
331
+ };
332
+ return { record };
333
+ }
334
+ if (type === "turn.step.retrying") {
335
+ const failedAttempt = parsed["failed_attempt"];
336
+ const nextAttempt = parsed["next_attempt"];
337
+ const maxAttempts = parsed["max_attempts"];
338
+ const delayMs = parsed["delay_ms"];
339
+ const errorName = parsed["error_name"];
340
+ const errorMessage = parsed["error_message"];
341
+ const statusCode = parsed["status_code"];
342
+ if (typeof failedAttempt !== "number" ||
343
+ !Number.isFinite(failedAttempt) ||
344
+ typeof nextAttempt !== "number" ||
345
+ !Number.isFinite(nextAttempt) ||
346
+ typeof maxAttempts !== "number" ||
347
+ !Number.isFinite(maxAttempts) ||
348
+ typeof delayMs !== "number" ||
349
+ !Number.isFinite(delayMs) ||
350
+ typeof errorName !== "string" ||
351
+ typeof errorMessage !== "string" ||
352
+ (statusCode !== undefined &&
353
+ (typeof statusCode !== "number" || !Number.isFinite(statusCode)))) {
354
+ return {
355
+ malformedLine: line,
356
+ malformedReason: "meta.turn.step.retrying field has unexpected type",
357
+ };
358
+ }
359
+ const record = {
360
+ role: "meta",
361
+ type: "turn.step.retrying",
362
+ failedAttempt,
363
+ nextAttempt,
364
+ maxAttempts,
365
+ delayMs,
366
+ errorName,
367
+ errorMessage,
368
+ ...(typeof statusCode === "number" && { statusCode }),
369
+ };
370
+ return { record };
371
+ }
372
+ if (type === "system.version") {
373
+ const version = parsed["version"];
374
+ if (typeof version !== "string" || version.length === 0) {
375
+ return {
376
+ malformedLine: line,
377
+ malformedReason: "meta.system.version.version not non-empty string",
378
+ };
379
+ }
380
+ const record = {
381
+ role: "meta",
382
+ type: "system.version",
383
+ version,
384
+ };
385
+ return { record };
386
+ }
387
+ // Unknown meta types are forward-compatible — surface them via the
388
+ // malformed channel for diagnostics, but don't crash. kimi-code may add
389
+ // new meta types in 0.3.x and our wrapper should keep working.
390
+ return {
391
+ malformedLine: line,
392
+ malformedReason: `unknown meta.type: ${JSON.stringify(type)}`,
393
+ };
394
+ }
395
+ function validateAssistant(parsed, line) {
396
+ const content = parsed["content"];
397
+ if (content !== undefined && typeof content !== "string") {
398
+ return { malformedLine: line, malformedReason: "assistant.content not string" };
399
+ }
400
+ const toolCallsRaw = parsed["tool_calls"];
401
+ let toolCalls;
402
+ if (toolCallsRaw !== undefined) {
403
+ if (!Array.isArray(toolCallsRaw)) {
404
+ return { malformedLine: line, malformedReason: "assistant.tool_calls not array" };
405
+ }
406
+ toolCalls = [];
407
+ for (const candidate of toolCallsRaw) {
408
+ const validated = validateToolCall(candidate);
409
+ if (validated === undefined) {
410
+ return {
411
+ malformedLine: line,
412
+ malformedReason: "assistant.tool_calls entry invalid",
413
+ };
414
+ }
415
+ toolCalls.push(validated);
416
+ }
417
+ }
418
+ if (content === undefined && (toolCalls === undefined || toolCalls.length === 0)) {
419
+ return {
420
+ malformedLine: line,
421
+ malformedReason: "assistant has neither content nor tool_calls",
422
+ };
423
+ }
424
+ const record = {
425
+ role: "assistant",
426
+ ...(content !== undefined && { content }),
427
+ ...(toolCalls !== undefined && { tool_calls: toolCalls }),
428
+ };
429
+ return { record };
430
+ }
431
+ function validateToolCall(candidate) {
432
+ if (!isRecord(candidate))
433
+ return undefined;
434
+ if (candidate["type"] !== "function")
435
+ return undefined;
436
+ const id = candidate["id"];
437
+ if (typeof id !== "string" || id.length === 0)
438
+ return undefined;
439
+ const fn = candidate["function"];
440
+ if (!isRecord(fn))
441
+ return undefined;
442
+ const name = fn["name"];
443
+ const args = fn["arguments"];
444
+ if (typeof name !== "string" || typeof args !== "string")
445
+ return undefined;
446
+ return { type: "function", id, function: { name, arguments: args } };
447
+ }
448
+ function validateToolResult(parsed, line) {
449
+ const toolCallId = parsed["tool_call_id"];
450
+ if (typeof toolCallId !== "string" || toolCallId.length === 0) {
451
+ return {
452
+ malformedLine: line,
453
+ malformedReason: "tool.tool_call_id not non-empty string",
454
+ };
455
+ }
456
+ const content = parsed["content"];
457
+ if (typeof content !== "string") {
458
+ return { malformedLine: line, malformedReason: "tool.content not string" };
459
+ }
460
+ const record = {
461
+ role: "tool",
462
+ tool_call_id: toolCallId,
463
+ content,
464
+ };
465
+ return { record };
466
+ }
467
+ function isRecord(value) {
468
+ return typeof value === "object" && value !== null && !Array.isArray(value);
469
+ }
470
+ /**
471
+ * Match kimi-code's stderr session announce line. In stream-json mode this
472
+ * is a 0.1.x compatibility fallback only — kimi 0.2.0+ emits the resume
473
+ * hint as a `role: meta, type: session.resume_hint` record on stdout (see
474
+ * SessionResumeHintRecord above and apps/kimi-code/src/cli/run-prompt.ts).
475
+ *
476
+ * The pattern accepts both 0.1.x bare-UUID format and 0.2.0+ `session_<uuid>`
477
+ * format so the fallback survives mixed-version environments. The captured
478
+ * token is whatever appears after `kimi -r ` — we treat it as an opaque
479
+ * session identifier and round-trip it verbatim via `kimi -r <token>`.
480
+ *
481
+ * Returns the captured session id, or undefined if no match.
482
+ */
483
+ export function extractSessionIdFromStderr(stderr) {
484
+ // The accepted shapes are tightly anchored — both alternations require
485
+ // a full UUID payload. The `session_` prefix is the 0.2.0+ form; the
486
+ // bare UUID is the 0.1.x form. Without the anchoring, a malformed or
487
+ // hostile stderr line could pin `session_--------` (8 dashes) or any
488
+ // 8+ char hex-dash token as the captured session id, weakening the
489
+ // "anchored full-UUID regex" safety invariant documented in AGENTS.md.
490
+ // Review-smoke (kimi 0.2.0 on the alpha.5 candidate) flagged the loose
491
+ // form; this is the post-review tightening.
492
+ const uuid = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
493
+ const pattern = new RegExp(`^To resume this session:\\s+kimi\\s+-r\\s+(session_${uuid}|${uuid})\\s*$`, "im");
494
+ return stderr.match(pattern)?.[1];
495
+ }
496
+ function makeOversizePreview(line) {
497
+ return `${line.slice(0, 200)}[truncated]`;
498
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2013 James Halliday (mail@substack.net)
4
+
5
+ Permission is hereby granted, free of charge,
6
+ to any person obtaining a copy of this software and
7
+ associated documentation files (the "Software"), to
8
+ deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify,
10
+ merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom
12
+ the Software is furnished to do so,
13
+ subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice
16
+ shall be included in all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
22
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1 @@
1
+ export { parse } from "./parse.js";