@zhushanwen/subagent-core 0.2.0 → 0.5.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 (347) hide show
  1. package/README.md +45 -2
  2. package/agents/analyst.md +60 -0
  3. package/agents/coder.md +69 -0
  4. package/agents/debugger.md +66 -0
  5. package/agents/doc-reviewer.md +49 -0
  6. package/agents/explorer.md +63 -0
  7. package/agents/general-purpose.md +32 -0
  8. package/agents/orchestrator.md +61 -0
  9. package/agents/planner.md +53 -0
  10. package/agents/researcher.md +67 -0
  11. package/agents/reviewer.md +73 -0
  12. package/dist/chunk-43ONBFZX.js +240 -0
  13. package/dist/chunk-APZY4IME.js +27 -0
  14. package/dist/chunk-V3VHZ2VX.js +59 -0
  15. package/dist/execution/engine/engines/zcode/constants.cjs +62 -9
  16. package/dist/execution/engine/engines/zcode/constants.d.cts +116 -12
  17. package/dist/execution/engine/engines/zcode/constants.d.ts +116 -12
  18. package/dist/execution/engine/engines/zcode/constants.js +39 -7
  19. package/dist/execution/engine/engines/zcode/reader.d.cts +2 -1
  20. package/dist/execution/engine/engines/zcode/reader.d.ts +2 -1
  21. package/dist/execution/engine/engines/zcode/reader.js +4 -234
  22. package/dist/execution/engine/paths.js +7 -19
  23. package/dist/index.cjs +18234 -1277
  24. package/dist/index.d.cts +5646 -673
  25. package/dist/index.d.ts +5646 -673
  26. package/dist/index.js +17828 -1277
  27. package/dist/{types-BxyAidGf.d.cts → types-Dv4QhSJ_.d.cts} +678 -112
  28. package/dist/{types-BxyAidGf.d.ts → types-Dv4QhSJ_.d.ts} +678 -112
  29. package/package.json +7 -4
  30. package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
  31. package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
  32. package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
  33. package/src/__tests__/m2-append-content-probe.test.ts +0 -1
  34. package/src/__tests__/manifest-store.test.ts +10 -9
  35. package/src/__tests__/record-store-cache.test.ts +0 -2
  36. package/src/__tests__/record-store-index.test.ts +1 -2
  37. package/src/__tests__/review-fix-loop-script.test.ts +93 -3
  38. package/src/__tests__/review-fix-loop-utils.test.ts +31 -10
  39. package/src/__tests__/robustness-low-batch1.test.ts +6 -5
  40. package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
  41. package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
  42. package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
  43. package/src/__tests__/session-runner.test.ts +1 -1
  44. package/src/__tests__/smoke.test.ts +9 -2
  45. package/src/core/__tests__/host-services.test.ts +2 -2
  46. package/src/core/__tests__/logger.test.ts +1 -1
  47. package/src/core/error-message.ts +9 -0
  48. package/src/core/host-services.ts +21 -5
  49. package/src/core/notify-ports.ts +18 -5
  50. package/src/execution/__tests__/agent-profile.test.ts +232 -0
  51. package/src/execution/__tests__/agent-registry.test.ts +370 -0
  52. package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
  53. package/src/execution/__tests__/agents-assembly.test.ts +219 -0
  54. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
  55. package/src/execution/__tests__/chat-engine-routing.test.ts +136 -30
  56. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +5 -4
  57. package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
  58. package/src/execution/__tests__/create-concurrency-pool.test.ts +194 -0
  59. package/src/execution/__tests__/delivery-methods.test.ts +77 -62
  60. package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
  61. package/src/execution/__tests__/descendant-sweep.test.ts +269 -0
  62. package/src/execution/__tests__/dialog-queue.test.ts +199 -1
  63. package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
  64. package/src/execution/__tests__/epipe-fallback.test.ts +31 -24
  65. package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
  66. package/src/execution/__tests__/execute-nesting.test.ts +34 -188
  67. package/src/execution/__tests__/execution-record.test.ts +217 -60
  68. package/src/execution/__tests__/execution-runtime-face.test.ts +272 -0
  69. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +3 -3
  70. package/src/execution/__tests__/finalize-record.test.ts +278 -16
  71. package/src/execution/__tests__/gc-timer.test.ts +57 -2
  72. package/src/execution/__tests__/get-record-for-action-restart.test.ts +14 -12
  73. package/src/execution/__tests__/get-state-handshake.test.ts +127 -0
  74. package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
  75. package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
  76. package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
  77. package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
  78. package/src/execution/__tests__/keep-alive-no-progress.test.ts +280 -0
  79. package/src/execution/__tests__/kill-all-escalation.test.ts +196 -0
  80. package/src/execution/__tests__/lifecycle-manager-idle-timer-identity.test.ts +117 -0
  81. package/src/execution/__tests__/lifecycle-manager.test.ts +39 -0
  82. package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
  83. package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
  84. package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +99 -0
  85. package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +113 -0
  86. package/src/execution/__tests__/model-resolver.test.ts +2 -2
  87. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
  88. package/src/execution/__tests__/nested-visibility.test.ts +2 -0
  89. package/src/execution/__tests__/notify-ledger.test.ts +1249 -0
  90. package/src/execution/__tests__/output-collector.test.ts +117 -6
  91. package/src/execution/__tests__/pi-invocation.test.ts +1 -1
  92. package/src/execution/__tests__/record-store-orphan-revive.test.ts +159 -0
  93. package/src/execution/__tests__/record-store.test.ts +89 -5
  94. package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
  95. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
  96. package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
  97. package/src/execution/__tests__/rpc-mode.test.ts +2 -2
  98. package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
  99. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +19 -9
  100. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +5 -4
  101. package/src/execution/__tests__/run-spawn-edges.test.ts +418 -26
  102. package/src/execution/__tests__/run-spawn-integration.test.ts +3 -3
  103. package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
  104. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
  105. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +16 -8
  106. package/src/execution/__tests__/service-kill-escalation.test.ts +91 -0
  107. package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
  108. package/src/execution/__tests__/session-file-gc.test.ts +35 -0
  109. package/src/execution/__tests__/session-pending.test.ts +471 -0
  110. package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
  111. package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +110 -0
  112. package/src/execution/__tests__/session-runner-close-prune.test.ts +181 -0
  113. package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
  114. package/src/execution/__tests__/session-runner-epipe.test.ts +4 -3
  115. package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +227 -0
  116. package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
  117. package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
  118. package/src/execution/__tests__/settled-watchdog.test.ts +524 -0
  119. package/src/execution/__tests__/spawn-args.test.ts +11 -10
  120. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
  121. package/src/execution/__tests__/spawn-event-adapter.test.ts +1 -1
  122. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
  123. package/src/execution/__tests__/spawned-children.test.ts +155 -11
  124. package/src/execution/__tests__/start-sync-model-guard.test.ts +4 -4
  125. package/src/execution/__tests__/stdin-writer.test.ts +6 -4
  126. package/src/execution/__tests__/stream-sink-retirement.test.ts +6 -6
  127. package/src/execution/__tests__/subagent-actions-core.test.ts +1017 -0
  128. package/src/execution/__tests__/subagent-service-message-close.test.ts +99 -35
  129. package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +174 -0
  130. package/src/execution/__tests__/subagent-service-notify-gate.test.ts +271 -0
  131. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +33 -29
  132. package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +341 -0
  133. package/src/execution/__tests__/subagent-service.test.ts +37 -30
  134. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
  135. package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
  136. package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
  137. package/src/execution/__tests__/temp-prompt.test.ts +1 -1
  138. package/src/execution/__tests__/timeout-integration.test.ts +13 -12
  139. package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
  140. package/src/execution/__tests__/turn-limiter.test.ts +1 -1
  141. package/src/execution/__tests__/ui-request-handler-factory.test.ts +107 -7
  142. package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
  143. package/src/execution/__tests__/ui-request-queue.test.ts +167 -2
  144. package/src/execution/__tests__/worktree-git-ops.test.ts +571 -0
  145. package/src/execution/__tests__/worktree-manager.test.ts +14 -5
  146. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
  147. package/src/execution/__tests__/worktree-reconcile-aging.test.ts +204 -0
  148. package/src/execution/agent-registry.ts +298 -30
  149. package/src/execution/agent-result-mapper.ts +3 -0
  150. package/src/execution/agents-assembly.ts +88 -0
  151. package/src/execution/cold-resurrect.ts +199 -0
  152. package/src/execution/concurrency-pool.ts +71 -9
  153. package/src/execution/dialog-queue.ts +101 -3
  154. package/src/execution/engine/__tests__/common/capability-gate.test.ts +91 -0
  155. package/src/execution/engine/__tests__/common/data-dir.test.ts +1 -1
  156. package/src/execution/engine/__tests__/common/journal-wiring.test.ts +84 -0
  157. package/src/execution/engine/__tests__/common/kill-chain.test.ts +34 -7
  158. package/src/execution/engine/__tests__/common/persona-router.test.ts +4 -5
  159. package/src/execution/engine/__tests__/common/pool-manager.test.ts +211 -51
  160. package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +149 -0
  161. package/src/execution/engine/__tests__/common/session-view-service.test.ts +499 -0
  162. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +56 -99
  163. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +88 -15
  164. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +33 -7
  165. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +1 -1
  166. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +75 -54
  167. package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +128 -0
  168. package/src/execution/engine/__tests__/engine-discovery.test.ts +15 -3
  169. package/src/execution/engine/__tests__/model-prompt.test.ts +15 -3
  170. package/src/execution/engine/__tests__/registry.test.ts +94 -3
  171. package/src/execution/engine/__tests__/routing.test.ts +115 -6
  172. package/src/execution/engine/common/capability-gate.ts +92 -0
  173. package/src/execution/engine/common/journal-wiring.ts +97 -0
  174. package/src/execution/engine/common/kill-chain.ts +42 -10
  175. package/src/execution/engine/common/nesting-guard.ts +66 -0
  176. package/src/execution/engine/common/persona-router.ts +18 -8
  177. package/src/execution/engine/common/pool-manager.ts +332 -78
  178. package/src/execution/engine/common/session-view-service.ts +506 -0
  179. package/src/execution/engine/common/session-view-types.ts +125 -0
  180. package/src/execution/engine/engine-discovery.ts +12 -16
  181. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +174 -28
  182. package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
  183. package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
  184. package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +86 -11
  185. package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
  186. package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
  187. package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
  188. package/src/execution/engine/engines/pi/reader.ts +11 -0
  189. package/src/execution/engine/engines/pi/registration.ts +4 -2
  190. package/src/execution/engine/engines/pi/session-runner.ts +2840 -0
  191. package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
  192. package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
  193. package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
  194. package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
  195. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +301 -0
  196. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json +36 -0
  197. package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
  198. package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +473 -0
  199. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
  200. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
  201. package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
  202. package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
  203. package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +792 -0
  204. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +782 -0
  205. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +168 -0
  206. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
  207. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
  208. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
  209. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
  210. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +65 -47
  211. package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
  212. package/src/execution/engine/engines/zcode/connection.ts +598 -0
  213. package/src/execution/engine/engines/zcode/constants.ts +147 -14
  214. package/src/execution/engine/engines/zcode/golden-sample.ts +42 -34
  215. package/src/execution/engine/engines/zcode/parser.ts +12 -346
  216. package/src/execution/engine/engines/zcode/preparer.ts +22 -150
  217. package/src/execution/engine/engines/zcode/session-channel.ts +968 -0
  218. package/src/execution/engine/engines/zcode/zcode-engine.ts +1023 -250
  219. package/src/execution/engine/host-task-spec.ts +32 -36
  220. package/src/execution/engine/model-validation.ts +177 -0
  221. package/src/execution/engine/port.ts +65 -7
  222. package/src/execution/engine/registry.ts +53 -0
  223. package/src/execution/engine/routing.ts +75 -1
  224. package/src/execution/engine/types.ts +30 -103
  225. package/src/execution/execution-record.ts +222 -144
  226. package/src/execution/finalize-record.ts +181 -85
  227. package/src/execution/idle-gc.ts +28 -0
  228. package/src/execution/lifecycle-manager.ts +27 -3
  229. package/src/execution/lifecycle-predicates.ts +1 -1
  230. package/src/execution/manifest-store.ts +53 -62
  231. package/src/execution/notifier.ts +10 -10
  232. package/src/execution/notify-host.ts +212 -0
  233. package/src/execution/notify-ledger.ts +117 -16
  234. package/src/execution/record-entry.ts +8 -2
  235. package/src/execution/record-store.ts +148 -88
  236. package/src/execution/round-settlement.ts +93 -0
  237. package/src/execution/session-file-gc.ts +96 -62
  238. package/src/execution/session-pending.ts +213 -62
  239. package/src/execution/session-reconstructor.ts +256 -143
  240. package/src/execution/sessions-index.ts +127 -102
  241. package/src/execution/settled-watchdog.ts +311 -0
  242. package/src/execution/subagent-actions-core.ts +686 -0
  243. package/src/execution/subagent-service.ts +1106 -907
  244. package/src/execution/subprocess-agent-runner.ts +144 -97
  245. package/src/execution/types.ts +9 -0
  246. package/src/execution/ui-request-handler-factory.ts +126 -75
  247. package/src/execution/ui-request-queue.ts +50 -19
  248. package/src/execution/worktree-git-ops.ts +397 -0
  249. package/src/execution/worktree-manager.ts +72 -10
  250. package/src/execution/worktree-registry.ts +6 -12
  251. package/src/index.ts +542 -9
  252. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +42 -3
  253. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +3 -5
  254. package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
  255. package/src/orchestration/__tests__/args-meta.test.ts +358 -0
  256. package/src/orchestration/__tests__/args-validator.test.ts +14 -0
  257. package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +312 -0
  258. package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +384 -0
  259. package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
  260. package/src/orchestration/__tests__/file-run-store-prune.test.ts +168 -0
  261. package/src/orchestration/__tests__/file-run-store-throttle.test.ts +168 -0
  262. package/src/orchestration/__tests__/file-run-store.test.ts +390 -0
  263. package/src/orchestration/__tests__/helpers/flush-microtasks.ts +13 -0
  264. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +34 -0
  265. package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +357 -0
  266. package/src/orchestration/__tests__/lifecycle-recover-crashed.test.ts +289 -0
  267. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
  268. package/src/orchestration/__tests__/lifecycle.test.ts +84 -5
  269. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
  270. package/src/orchestration/__tests__/run-snapshot.test.ts +356 -0
  271. package/src/orchestration/__tests__/script-generate.test.ts +314 -0
  272. package/src/orchestration/__tests__/script-lint.test.ts +17 -0
  273. package/src/orchestration/__tests__/test-mocks.ts +2 -0
  274. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +7 -6
  275. package/src/orchestration/__tests__/worker-message-pump-finalize-run.test.ts +229 -0
  276. package/src/orchestration/__tests__/{error-recovery-handlers.test.ts → worker-message-pump-handlers.test.ts} +28 -27
  277. package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
  278. package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
  279. package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
  280. package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +275 -0
  281. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +78 -1
  282. package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
  283. package/src/orchestration/__tests__/workflow-files.test.ts +186 -0
  284. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
  285. package/src/orchestration/__tests__/workflow-run-summary.test.ts +119 -0
  286. package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +124 -0
  287. package/src/orchestration/agent-opts-resolver.ts +8 -8
  288. package/src/orchestration/args-meta.ts +198 -0
  289. package/src/orchestration/args-validator.ts +53 -31
  290. package/src/orchestration/execute-agent-call.ts +25 -79
  291. package/src/orchestration/file-run-store.ts +327 -0
  292. package/src/orchestration/launcher.ts +160 -104
  293. package/src/orchestration/lifecycle.ts +371 -97
  294. package/src/orchestration/models/agent-call.ts +7 -7
  295. package/src/orchestration/models/budget.ts +5 -5
  296. package/src/orchestration/models/ports.ts +4 -4
  297. package/src/orchestration/models/run-runtime.ts +15 -15
  298. package/src/orchestration/models/trace.ts +9 -9
  299. package/src/orchestration/models/types.ts +111 -22
  300. package/src/orchestration/models/workflow-run.ts +28 -28
  301. package/src/orchestration/models/workflow-script.ts +4 -4
  302. package/src/orchestration/run-snapshot.ts +266 -0
  303. package/src/orchestration/script-generate.ts +154 -0
  304. package/src/orchestration/script-lint.ts +123 -90
  305. package/src/orchestration/worker-handle.ts +10 -10
  306. package/src/orchestration/worker-host.ts +10 -10
  307. package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +498 -221
  308. package/src/orchestration/worker-script-builder.ts +401 -346
  309. package/src/orchestration/workflow-files.ts +37 -11
  310. package/src/orchestration/workflow-run-summary.ts +69 -0
  311. package/src/orchestration/workflow-script-registry-impl.ts +31 -9
  312. package/src/shared/__tests__/agent-ref.test.ts +209 -2
  313. package/src/shared/__tests__/atomic-write.test.ts +267 -0
  314. package/src/shared/__tests__/bounded-serialize.test.ts +236 -0
  315. package/src/shared/__tests__/injection-render.test.ts +518 -0
  316. package/src/shared/__tests__/meta-parser.test.ts +151 -0
  317. package/src/shared/__tests__/resource-discovery-host-roots.test.ts +474 -0
  318. package/src/shared/__tests__/resource-discovery.test.ts +261 -217
  319. package/src/shared/agent-ref.ts +143 -2
  320. package/src/shared/atomic-write.ts +323 -0
  321. package/src/shared/bounded-serialize.ts +154 -0
  322. package/src/shared/injection-render.ts +279 -0
  323. package/src/shared/meta-parser.ts +182 -68
  324. package/src/shared/model-ref.ts +15 -2
  325. package/src/shared/resource-discovery.ts +97 -204
  326. package/src/shared/resource-meta.ts +14 -0
  327. package/src/shared/schema-jsonify.ts +1 -1
  328. package/src/shared/xml-injection.ts +9 -9
  329. package/workflows/README.md +9 -9
  330. package/workflows/chain.js +4 -2
  331. package/workflows/map-reduce.js +5 -3
  332. package/workflows/parallel.js +5 -3
  333. package/workflows/review-fix-loop-utils.cjs +165 -92
  334. package/workflows/review-fix-loop-utils.d.cts +287 -0
  335. package/workflows/review-fix-loop.js +18 -7
  336. package/workflows/scatter-gather.js +4 -2
  337. package/dist/chunk-3VOERJPJ.js +0 -22
  338. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  339. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  340. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  341. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  342. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  343. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -580
  344. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  345. package/src/execution/execute-options-mapper.ts +0 -115
  346. package/src/execution/session-runner.ts +0 -1789
  347. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
@@ -12,7 +12,9 @@ import {
12
12
  getFullText,
13
13
  getFullTextFrom,
14
14
  getTotalUsage,
15
+ jsonlToAgentEvent,
15
16
  markReconstructedStatus,
17
+ resurrectClosed,
16
18
  nextRoundBaseTurnIndex,
17
19
  deriveOutcome,
18
20
  projectOutcome,
@@ -38,8 +40,12 @@ function makeRecord(over: Partial<ExecutionRecord> = {}): ExecutionRecord {
38
40
  id: "test-1",
39
41
  agent: "worker",
40
42
  model: "test-model",
43
+ slug: "t",
44
+ rootSessionId: undefined,
45
+ parentRecordId: undefined,
46
+ depth: 0,
41
47
  thinkingLevel: undefined,
42
- mode: "sync",
48
+ mode: "background",
43
49
  task: "test task",
44
50
  startedAt: 1000,
45
51
  status: "running",
@@ -75,6 +81,7 @@ describe("createRecord", () => {
75
81
  model: "m1",
76
82
  thinkingLevel: "high",
77
83
  mode: "background",
84
+ slug: "t",
78
85
  task: "review PR",
79
86
  startedAt: 2000,
80
87
  });
@@ -102,21 +109,21 @@ describe("createRecord", () => {
102
109
  it("stores controller when provided (background)", () => {
103
110
  const controller = new AbortController();
104
111
  const r = createRecord("r1", {
105
- agent: "w", model: "m", mode: "background", task: "t", startedAt: 0, controller,
112
+ agent: "w", model: "m", mode: "background", slug: "t", task: "t", startedAt: 0, controller,
106
113
  });
107
114
  expect(r.controller).toBe(controller);
108
115
  });
109
116
 
110
117
  it("stores rootSessionId when provided", () => {
111
118
  const r = createRecord("r1", {
112
- agent: "w", model: "m", mode: "sync", task: "t", startedAt: 0, rootSessionId: "sess-A",
119
+ agent: "w", model: "m", mode: "background", slug: "t", task: "t", startedAt: 0, rootSessionId: "sess-A",
113
120
  });
114
121
  expect(r.rootSessionId).toBe("sess-A");
115
122
  });
116
123
 
117
124
  it("defaults rootSessionId to undefined when omitted", () => {
118
125
  const r = createRecord("r1", {
119
- agent: "w", model: "m", mode: "sync", task: "t", startedAt: 0,
126
+ agent: "w", model: "m", mode: "background", slug: "t", task: "t", startedAt: 0,
120
127
  });
121
128
  expect(r.rootSessionId).toBeUndefined();
122
129
  });
@@ -478,7 +485,7 @@ describe("getEventLog", () => {
478
485
  // ============================================================
479
486
  describe("getCurrentActivity", () => {
480
487
  it("returns undefined when status is not running", () => {
481
- const r = makeRecord({ status: "done" });
488
+ const r = makeRecord({ status: "closed" });
482
489
  expect(getCurrentActivity(r)).toBeUndefined();
483
490
  });
484
491
 
@@ -673,7 +680,7 @@ describe("nextRoundBaseTurnIndex", () => {
673
680
  agent: "worker",
674
681
  model: "test-model",
675
682
  thinkingLevel: undefined,
676
- mode: "sync",
683
+ mode: "background",
677
684
  task: "t",
678
685
  slug: "t",
679
686
  startedAt: 1000,
@@ -753,8 +760,8 @@ describe("getAllToolCalls", () => {
753
760
  // 导出形状只有 4 个语义字段
754
761
  expect(Object.keys(tc!).sort()).toEqual(["args", "isError", "result", "toolName"]);
755
762
  // 内部字段不存在
756
- expect((tc as Record<string, unknown>)._status).toBeUndefined();
757
- expect((tc as Record<string, unknown>).startedTs).toBeUndefined();
763
+ expect((tc as unknown as Record<string, unknown>)._status).toBeUndefined();
764
+ expect((tc as unknown as Record<string, unknown>).startedTs).toBeUndefined();
758
765
  });
759
766
  });
760
767
 
@@ -797,70 +804,70 @@ describe("getTotalUsage", () => {
797
804
  describe("tryTransition", () => {
798
805
  it("returns true and sets status when transitioning from running", () => {
799
806
  const r = makeRecord({ status: "running" });
800
- expect(tryTransition(r, "done")).toBe(true);
801
- expect(r.status).toBe("done");
807
+ expect(tryTransition(r, "closed")).toBe(true);
808
+ expect(r.status).toBe("closed");
802
809
  });
803
810
 
804
- it("returns false when already terminal (done)", () => {
805
- const r = makeRecord({ status: "done" });
806
- expect(tryTransition(r, "failed")).toBe(false);
807
- expect(r.status).toBe("done");
811
+ it("returns false when already terminal (closed)", () => {
812
+ const r = makeRecord({ status: "closed" });
813
+ expect(tryTransition(r, "closed")).toBe(false);
814
+ expect(r.status).toBe("closed");
808
815
  });
809
816
 
810
- it("returns false when already terminal (cancelled)", () => {
811
- const r = makeRecord({ status: "cancelled" });
812
- expect(tryTransition(r, "done")).toBe(false);
817
+ it("returns false when already terminal (closed, cancelled reason)", () => {
818
+ const r = makeRecord({ status: "closed", closedReason: "cancelled" });
819
+ expect(tryTransition(r, "closed")).toBe(false);
813
820
  });
814
821
 
815
- it("returns false when already terminal (failed)", () => {
816
- const r = makeRecord({ status: "failed" });
817
- expect(tryTransition(r, "done")).toBe(false);
822
+ it("returns false when already terminal (closed, gc reason)", () => {
823
+ const r = makeRecord({ status: "closed", closedReason: "gc" });
824
+ expect(tryTransition(r, "closed")).toBe(false);
818
825
  });
819
826
 
820
- it("first transition wins in concurrent race (running → done beats running → cancelled)", () => {
827
+ it("first transition wins in concurrent race (running → closed is one-way)", () => {
821
828
  const r = makeRecord({ status: "running" });
822
- expect(tryTransition(r, "done")).toBe(true);
823
- expect(tryTransition(r, "cancelled")).toBe(false);
824
- expect(r.status).toBe("done");
829
+ expect(tryTransition(r, "closed")).toBe(true);
830
+ expect(tryTransition(r, "closed")).toBe(false);
831
+ expect(r.status).toBe("closed");
825
832
  });
826
833
 
827
- it("returns false when trying to transition from crashed to done", () => {
828
- const r = makeRecord({ status: "crashed" });
829
- expect(tryTransition(r, "done")).toBe(false);
830
- expect(r.status).toBe("crashed");
834
+ it("running 入态时 resurrectClosed 防御性 no-op(终态回边仅限 closed)", () => {
835
+ const r = makeRecord({ status: "running" });
836
+ expect(resurrectClosed(r)).toBe(false);
837
+ expect(r.status).toBe("running");
831
838
  });
832
839
  });
833
840
 
834
841
  describe("markReconstructedStatus", () => {
835
842
  it("directly sets status without CAS check", () => {
836
843
  const r = makeRecord({ status: "running" });
837
- markReconstructedStatus(r, "crashed");
838
- expect(r.status).toBe("crashed");
844
+ markReconstructedStatus(r, "closed");
845
+ expect(r.status).toBe("closed");
839
846
  });
840
847
 
841
848
  it("can overwrite terminal status (bypass CAS)", () => {
842
849
  // 重建场景:旧 record 可能已有终态,重建时需要直接覆盖
843
- const r = makeRecord({ status: "done" });
844
- markReconstructedStatus(r, "crashed");
845
- expect(r.status).toBe("crashed");
850
+ const r = makeRecord({ status: "closed" });
851
+ markReconstructedStatus(r, "closed");
852
+ expect(r.status).toBe("closed");
846
853
  });
847
854
 
848
855
  it("can overwrite running status", () => {
849
856
  const r = makeRecord({ status: "running" });
850
- markReconstructedStatus(r, "failed");
851
- expect(r.status).toBe("failed");
857
+ markReconstructedStatus(r, "closed");
858
+ expect(r.status).toBe("closed");
852
859
  });
853
860
 
854
- it("can set crashed on running record", () => {
861
+ it("can set closed on running record", () => {
855
862
  const r = makeRecord({ status: "running" });
856
- markReconstructedStatus(r, "crashed");
857
- expect(r.status).toBe("crashed");
863
+ markReconstructedStatus(r, "closed");
864
+ expect(r.status).toBe("closed");
858
865
  });
859
866
 
860
- it("can set crashed on done record (reconstruction override)", () => {
861
- const r = makeRecord({ status: "done" });
862
- markReconstructedStatus(r, "crashed");
863
- expect(r.status).toBe("crashed");
867
+ it("can re-set closed on closed record (reconstruction override)", () => {
868
+ const r = makeRecord({ status: "closed" });
869
+ markReconstructedStatus(r, "closed");
870
+ expect(r.status).toBe("closed");
864
871
  });
865
872
  });
866
873
 
@@ -870,9 +877,9 @@ describe("markReconstructedStatus", () => {
870
877
  describe("completeRecord", () => {
871
878
  it("writes outcome fields without resetting turnCount/totalTokens", () => {
872
879
  const r = makeRecord({ turnCount: 5, totalTokens: 42 });
873
- r.status = "done";
874
- completeRecord(r, SAMPLE_RESULT, "done");
875
- expect(r.status).toBe("done");
880
+ r.status = "closed";
881
+ completeRecord(r, SAMPLE_RESULT, "closed");
882
+ expect(r.status).toBe("closed");
876
883
  expect(r.endedAt).toBeTypeOf("number");
877
884
  expect(r.agentResult).toBe(SAMPLE_RESULT);
878
885
  expect(r.result).toBe("done");
@@ -883,9 +890,9 @@ describe("completeRecord", () => {
883
890
 
884
891
  it("stores error from result", () => {
885
892
  const r = makeRecord();
886
- r.status = "failed";
893
+ r.status = "closed";
887
894
  const failedResult: AgentResult = { ...SAMPLE_RESULT, success: false, error: "oops" };
888
- completeRecord(r, failedResult, "failed");
895
+ completeRecord(r, failedResult, "closed");
889
896
  expect(r.error).toBe("oops");
890
897
  });
891
898
 
@@ -1018,7 +1025,7 @@ describe("projections", () => {
1018
1025
  });
1019
1026
 
1020
1027
  it("currentActivity is undefined when status is not running", () => {
1021
- const r = makeRecord({ status: "done" });
1028
+ const r = makeRecord({ status: "closed" });
1022
1029
  expect(project(r).currentActivity).toBeUndefined();
1023
1030
  });
1024
1031
 
@@ -1073,13 +1080,13 @@ describe("projections", () => {
1073
1080
 
1074
1081
  describe("snapshot", () => {
1075
1082
  it("returns a readonly snapshot with identity + status fields", () => {
1076
- const r = makeRecord({ turnCount: 2, status: "done", endedAt: 5000, result: "ok" });
1083
+ const r = makeRecord({ turnCount: 2, status: "closed", endedAt: 5000, result: "ok" });
1077
1084
  const s = snapshot(r);
1078
1085
  expect(s.id).toBe("test-1");
1079
1086
  expect(s.agent).toBe("worker");
1080
- expect(s.mode).toBe("sync");
1087
+ expect(s.mode).toBe("background");
1081
1088
  expect(s.task).toBe("test task");
1082
- expect(s.status).toBe("done");
1089
+ expect(s.status).toBe("closed");
1083
1090
  expect(s.turns).toBe(2);
1084
1091
  expect(s.endedAt).toBe(5000);
1085
1092
  expect(s.result).toBe("ok");
@@ -1184,7 +1191,7 @@ describe("computeElapsedSeconds", () => {
1184
1191
  describe("projectLiveProgress (T3.21)", () => {
1185
1192
  it("projects live progress snapshot from running record", () => {
1186
1193
  const record = makeRecord({
1187
- mode: "sync",
1194
+ mode: "background",
1188
1195
  task: "test task",
1189
1196
  startedAt: 1000,
1190
1197
  status: "running",
@@ -1209,7 +1216,7 @@ describe("projectLiveProgress (T3.21)", () => {
1209
1216
 
1210
1217
  it("projectLiveProgress returns lastError when set", () => {
1211
1218
  const record = makeRecord({
1212
- mode: "sync", task: "failing", startedAt: 0, status: "running",
1219
+ mode: "background", task: "failing", startedAt: 0, status: "running",
1213
1220
  lastError: "something went wrong",
1214
1221
  });
1215
1222
  const result = projectLiveProgress(record);
@@ -1227,7 +1234,7 @@ describe("tool_end running index [perf]", () => {
1227
1234
  updateFromEvent(record, { type: "tool_start", toolName: name, args });
1228
1235
 
1229
1236
  const end = (record: ExecutionRecord, name: string, result: string) =>
1230
- updateFromEvent(record, { type: "tool_end", toolName: name, result, isError: false });
1237
+ updateFromEvent(record, { type: "tool_end", toolName: name, result: { content: [result] }, isError: false });
1231
1238
 
1232
1239
  it("同名并发两个 toolCall:tool_end LIFO 配对,结果写回各自槽位", () => {
1233
1240
  const record = makeRecord();
@@ -1239,12 +1246,12 @@ describe("tool_end running index [perf]", () => {
1239
1246
  const calls = record.turns[0]!.toolCalls;
1240
1247
  expect(calls).toHaveLength(2);
1241
1248
  expect(calls[0]).toMatchObject({ args: { cmd: "first" }, _status: "running" });
1242
- expect(calls[1]).toMatchObject({ result: "result-for-second", _status: "done" });
1249
+ expect(calls[1]).toMatchObject({ result: { content: ["result-for-second"] }, _status: "done" });
1243
1250
 
1244
1251
  // 第二个 end 配对剩下的 first
1245
1252
  end(record, "bash", "result-for-first");
1246
- expect(calls[0]).toMatchObject({ result: "result-for-first", _status: "done" });
1247
- expect(calls[1]).toMatchObject({ result: "result-for-second", _status: "done" });
1253
+ expect(calls[0]).toMatchObject({ result: { content: ["result-for-first"] }, _status: "done" });
1254
+ expect(calls[1]).toMatchObject({ result: { content: ["result-for-second"] }, _status: "done" });
1248
1255
  });
1249
1256
 
1250
1257
  it("索引 miss(无 tool_start 的外部注入 tool_end)→ fallback 全扫后 push 幽灵条目", () => {
@@ -1252,7 +1259,7 @@ describe("tool_end running index [perf]", () => {
1252
1259
  end(record, "external_tool", "injected");
1253
1260
  const calls = record.turns[0]!.toolCalls;
1254
1261
  expect(calls).toHaveLength(1);
1255
- expect(calls[0]).toMatchObject({ toolName: "external_tool", result: "injected", _status: "done" });
1262
+ expect(calls[0]).toMatchObject({ toolName: "external_tool", result: { content: ["injected"] }, _status: "done" });
1256
1263
  });
1257
1264
 
1258
1265
  it("跨 turn 滞后 tool_end:索引跨 turn 命中(与旧全扫语义一致)", () => {
@@ -1263,8 +1270,8 @@ describe("tool_end running index [perf]", () => {
1263
1270
  end(record, "write", "w-done"); // 正常配对 turn 1
1264
1271
  end(record, "read", "r-done"); // 滞后 end 配对 turn 0(跨 turn 兜底)
1265
1272
 
1266
- expect(record.turns[0]!.toolCalls[0]).toMatchObject({ toolName: "read", result: "r-done", _status: "done" });
1267
- expect(record.turns[1]!.toolCalls[0]).toMatchObject({ toolName: "write", result: "w-done", _status: "done" });
1273
+ expect(record.turns[0]!.toolCalls[0]).toMatchObject({ toolName: "read", result: { content: ["r-done"] }, _status: "done" });
1274
+ expect(record.turns[1]!.toolCalls[0]).toMatchObject({ toolName: "write", result: { content: ["w-done"] }, _status: "done" });
1268
1275
  });
1269
1276
  });
1270
1277
 
@@ -1335,6 +1342,156 @@ describe("createRecord 引擎留痕字段(P4)", () => {
1335
1342
  });
1336
1343
  });
1337
1344
 
1345
+ // ============================================================
1346
+ // jsonlToAgentEvent — subprocess JSONL → AgentEvent 翻译
1347
+ // ============================================================
1348
+ describe("jsonlToAgentEvent(JSONL → AgentEvent 翻译)", () => {
1349
+ it("不映射类型(session/message_start/turn_start/tool_execution_update)→ 空数组", () => {
1350
+ expect(jsonlToAgentEvent({ type: "session" })).toEqual([]);
1351
+ expect(jsonlToAgentEvent({ type: "message_start" })).toEqual([]);
1352
+ expect(jsonlToAgentEvent({ type: "turn_start" })).toEqual([]);
1353
+ expect(jsonlToAgentEvent({ type: "tool_execution_update" })).toEqual([]);
1354
+ });
1355
+
1356
+ it("未知类型 → 空数组(落空语义)", () => {
1357
+ expect(jsonlToAgentEvent({ type: "something_new" })).toEqual([]);
1358
+ });
1359
+
1360
+ it("tool_execution_start → tool_start(toolName/args 透传)", () => {
1361
+ expect(jsonlToAgentEvent({ type: "tool_execution_start", toolName: "read", args: { path: "/x.ts" } })).toEqual([
1362
+ { type: "tool_start", toolName: "read", args: { path: "/x.ts" } },
1363
+ ]);
1364
+ });
1365
+
1366
+ it("tool_execution_start:toolName 非字符串归一空串", () => {
1367
+ expect(jsonlToAgentEvent({ type: "tool_execution_start", toolName: 42 })).toEqual([
1368
+ { type: "tool_start", toolName: "", args: undefined },
1369
+ ]);
1370
+ });
1371
+
1372
+ it("tool_execution_end → tool_end(isError === true 才成立,result 透传)", () => {
1373
+ const result = { content: [{ type: "text", text: "out" }] };
1374
+ expect(
1375
+ jsonlToAgentEvent({ type: "tool_execution_end", toolName: "bash", args: { command: "ls" }, result, isError: true }),
1376
+ ).toEqual([
1377
+ { type: "tool_end", toolName: "bash", args: { command: "ls" }, result, isError: true },
1378
+ ]);
1379
+ // isError 非 true(字符串 "yes" / 缺失)→ false
1380
+ expect(
1381
+ jsonlToAgentEvent({ type: "tool_execution_end", toolName: "bash", isError: "yes" })[0],
1382
+ ).toMatchObject({ isError: false });
1383
+ expect(
1384
+ jsonlToAgentEvent({ type: "tool_execution_end", toolName: "bash" })[0],
1385
+ ).toMatchObject({ isError: false });
1386
+ });
1387
+
1388
+ it("message_update:thinking_delta(delta 字符串透传 / 非字符串归一空串)", () => {
1389
+ expect(
1390
+ jsonlToAgentEvent({ type: "message_update", assistantMessageEvent: { type: "thinking_delta", delta: "hmm" } }),
1391
+ ).toEqual([{ type: "thinking_delta", delta: "hmm" }]);
1392
+ expect(
1393
+ jsonlToAgentEvent({ type: "message_update", assistantMessageEvent: { type: "thinking_delta", delta: 42 } }),
1394
+ ).toEqual([{ type: "thinking_delta", delta: "" }]);
1395
+ });
1396
+
1397
+ it("message_update:text_delta(delta 非字符串 String() 归一)", () => {
1398
+ expect(
1399
+ jsonlToAgentEvent({ type: "message_update", assistantMessageEvent: { delta: "txt" } }),
1400
+ ).toEqual([{ type: "text_delta", delta: "txt" }]);
1401
+ expect(
1402
+ jsonlToAgentEvent({ type: "message_update", assistantMessageEvent: { delta: 42 } }),
1403
+ ).toEqual([{ type: "text_delta", delta: "42" }]);
1404
+ });
1405
+
1406
+ it("message_update:ame 缺失 / delta 缺失 → 不产出", () => {
1407
+ expect(jsonlToAgentEvent({ type: "message_update" })).toEqual([]);
1408
+ expect(jsonlToAgentEvent({ type: "message_update", assistantMessageEvent: undefined })).toEqual([]);
1409
+ expect(jsonlToAgentEvent({ type: "message_update", assistantMessageEvent: { type: "other" } })).toEqual([]);
1410
+ });
1411
+
1412
+ it("turn_end → [{type:'turn_end'}]", () => {
1413
+ expect(jsonlToAgentEvent({ type: "turn_end" })).toEqual([{ type: "turn_end" }]);
1414
+ });
1415
+
1416
+ it("message_end:usage 拍平 + cost.total 提取 + stopReason=error 额外产 error 事件(双事件)", () => {
1417
+ const events = jsonlToAgentEvent({
1418
+ type: "message_end",
1419
+ message: {
1420
+ usage: { input: 10, output: 20, cacheRead: 5, cacheWrite: 3, cost: { total: 0.5 } },
1421
+ stopReason: "error",
1422
+ errorMessage: "boom",
1423
+ },
1424
+ });
1425
+ expect(events).toEqual([
1426
+ { type: "message_end", usage: { input: 10, output: 20, cacheRead: 5, cacheWrite: 3, cost: 0.5 } },
1427
+ { type: "error", message: "boom" },
1428
+ ]);
1429
+ });
1430
+
1431
+ it("message_end:stopReason=aborted 无 errorMessage → raw.reason fallback,再兜底 String(stopReason)", () => {
1432
+ expect(
1433
+ jsonlToAgentEvent({ type: "message_end", message: { stopReason: "aborted" }, reason: "user aborted" }),
1434
+ ).toEqual([
1435
+ { type: "error", message: "user aborted" },
1436
+ ]);
1437
+ expect(
1438
+ jsonlToAgentEvent({ type: "message_end", message: { stopReason: "aborted" } }),
1439
+ ).toEqual([
1440
+ { type: "error", message: "aborted" },
1441
+ ]);
1442
+ });
1443
+
1444
+ it("message_end:usage 缺 cost → cost undefined;stopReason=stop 不产 error 事件", () => {
1445
+ const events = jsonlToAgentEvent({
1446
+ type: "message_end",
1447
+ message: { usage: { input: 1, output: 1 }, stopReason: "stop" },
1448
+ });
1449
+ expect(events).toEqual([
1450
+ { type: "message_end", usage: { input: 1, output: 1, cacheRead: 0, cacheWrite: 0, cost: undefined } },
1451
+ ]);
1452
+ });
1453
+
1454
+ it("message_end:message 缺失 / stopReason 正常 → 空数组或仅 usage", () => {
1455
+ expect(jsonlToAgentEvent({ type: "message_end" })).toEqual([]);
1456
+ expect(jsonlToAgentEvent({ type: "message_end", message: {} })).toEqual([]);
1457
+ });
1458
+
1459
+ it("compaction_start → [{type:'compaction'}]", () => {
1460
+ expect(jsonlToAgentEvent({ type: "compaction_start" })).toEqual([{ type: "compaction" }]);
1461
+ });
1462
+
1463
+ it("翻译产物喂 updateFromEvent 与 live 事件同构(text/tool/turn 收口进 turns[])", () => {
1464
+ const r = makeRecord();
1465
+ for (const event of [
1466
+ ...jsonlToAgentEvent({ type: "tool_execution_start", toolName: "read", args: { path: "/a.ts" } }),
1467
+ ...jsonlToAgentEvent({ type: "message_update", assistantMessageEvent: { delta: "answer" } }),
1468
+ ...jsonlToAgentEvent({ type: "tool_execution_end", toolName: "read", args: { path: "/a.ts" }, result: { content: [] }, isError: false }),
1469
+ ...jsonlToAgentEvent({ type: "message_end", message: { usage: { input: 7, output: 3, cacheRead: 0, cacheWrite: 0, cost: { total: 0.1 } } } }),
1470
+ ...jsonlToAgentEvent({ type: "turn_end" }),
1471
+ ]) {
1472
+ updateFromEvent(r, event);
1473
+ }
1474
+ expect(r.turns[0]?.text).toBe("answer");
1475
+ expect(r.turns[0]?.toolCalls[0]).toMatchObject({ toolName: "read", _status: "done" });
1476
+ expect(r.turns[0]?.usageDelta).toEqual({ input: 7, output: 3, cacheRead: 0, cacheWrite: 0, cost: 0.1 });
1477
+ expect(r.totalTokens).toBe(10);
1478
+ expect(r.turnCount).toBe(1);
1479
+ });
1480
+ });
1481
+
1482
+ // ============================================================
1483
+ // addUsage 分支语义(经 message_end 累积路径锁定)
1484
+ // ============================================================
1485
+ describe("addUsage 分支语义(message_end 累积路径)", () => {
1486
+ it("首条 usage 缺 cost → cost 保留 undefined;累加分支缺 cost → 归 0(number)", () => {
1487
+ const r = makeRecord();
1488
+ updateFromEvent(r, { type: "message_end", usage: { input: 1, output: 1, cacheRead: 0, cacheWrite: 0 } });
1489
+ expect(r.turns[0]!.usageDelta?.cost).toBeUndefined();
1490
+ updateFromEvent(r, { type: "message_end", usage: { input: 1, output: 1, cacheRead: 0, cacheWrite: 0 } });
1491
+ expect(r.turns[0]!.usageDelta?.cost).toBe(0);
1492
+ });
1493
+ });
1494
+
1338
1495
  // ============================================================
1339
1496
  // U1 engine 三字段 entry 往返(engineHandle 贯通)
1340
1497
  // ============================================================