@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
@@ -1,30 +1,29 @@
1
1
  // contract.agent-events.test.ts —— conformance C3(AgentEvent 不变量)+ 负例自证
2
2
  // (A12「套件有牙」:故意破坏一个不变量的样本必须被断言器检出——用「注入坏
3
- // parser」的形态:wrap 真实 synthesizeCoarseEvents 抽掉 message_end,断言套件转红;
3
+ // parser」的形态:构造抽掉 message_end / usage 半映射的坏样本流,断言套件转红;
4
4
  // 若断言器检不出破坏则本元测试失败)。
5
+ //
6
+ // 2026-09 重构(共享宿主 HOME):CLI spawn 链删除后引擎只剩 app-server 常驻链,
7
+ // C3 的引擎全链覆盖只走 app-server 形态(fake 常驻引擎 + stream 口径,文件末
8
+ // describe;app-server 设计 §3.4 不变量 1:text_delta 拼接 == read 全文、终态唯一
9
+ // turn.terminal 权威、message_end.usage 完整、tool 事件不合成——granularity 声明
10
+ // 与实际流出一致)。断言器行为正反例与负例自证均为手工构造样本,不依赖引擎实现。
5
11
 
6
12
  import { describe, expect, it } from "vitest";
7
13
 
8
14
  import type { AgentEvent } from "../../../types.ts";
9
- import { ZCODE_GOLDEN_STDOUT } from "../../engines/zcode/golden-sample.ts";
10
- import { parseZcodeTerminal, synthesizeCoarseEvents } from "../../engines/zcode/parser.ts";
15
+ import { ZCODE_APPSERVER_GOLDEN } from "../../engines/zcode/golden-sample.ts";
16
+ import { ZCODE_SHARED_POOL_KEY } from "../../engines/zcode/constants.ts";
17
+ import {
18
+ goldenReadFullText,
19
+ makeAppserverHarness,
20
+ } from "./zcode-appserver-harness.ts";
11
21
  import {
12
22
  assertAgentEventInvariants,
13
23
  checkAgentEventInvariants,
14
24
  } from "./agent-event-invariants.ts";
15
25
 
16
- /** golden 实录的 coarse 事件流(真实 parser + 真实合成器的产出)。 */
17
- function goldenCoarseEvents(): AgentEvent[] {
18
- const terminal = parseZcodeTerminal(ZCODE_GOLDEN_STDOUT);
19
- if (!terminal.ok) throw new Error("golden 样本解析失败");
20
- return synthesizeCoarseEvents(terminal.payload.response, terminal.payload.usage);
21
- }
22
-
23
- describe("conformance C3:AgentEvent 不变量(真实 parser 产出全绿)", () => {
24
- it("zcode golden 合成事件满足五条不变量(coarse 口径)", () => {
25
- assertAgentEventInvariants(goldenCoarseEvents(), { granularity: "coarse" });
26
- });
27
-
26
+ describe("conformance C3:AgentEvent 不变量(断言器正反例,手工构造样本)", () => {
28
27
  it("不变量 1:终态唯一——turn_end 后不得再出现非 error 事件", () => {
29
28
  const events: AgentEvent[] = [{ type: "message_end" }, { type: "turn_end" }, { type: "text_delta", delta: "x" }];
30
29
  const findings = checkAgentEventInvariants(events, { granularity: "coarse" });
@@ -99,3 +98,77 @@ describe("conformance 负例自证(A12:套件有牙)", () => {
99
98
  expect(findings.some((f) => f.invariant === "2")).toBe(true);
100
99
  });
101
100
  });
101
+
102
+ // ============================================================
103
+ // [R6] C3 app-server 口径:fake 常驻引擎全链(eventGranularity=stream 形态)
104
+ // —— 2026-09 重构后唯一生产形态(CLI spawn 降级链已删,无钉扎/降级双通道)。
105
+ // ============================================================
106
+
107
+ describe("conformance C3:zcode app-server 常驻通道(stream 口径,fake 常驻全链)", () => {
108
+ it("text_delta 拼接 == read 全文(byte 级)+ 终态唯一 + message_end.usage 完整 + tool 事件不合成", async () => {
109
+ const h = makeAppserverHarness();
110
+ try {
111
+ const events: AgentEvent[] = [];
112
+ const { outcome } = await h.engine.run(
113
+ { prompt: "做点什么", description: "c3-appserver", model: "conformance-provider/m1", cwd: h.workspace },
114
+ { taskId: "sa-c3-appserver", poolKey: "", onEvent: (e) => events.push(e) },
115
+ );
116
+
117
+ // granularity 声明与实际流出一致:声明 stream,流出有 text_delta 实时形态
118
+ expect(h.engine.capabilities().eventGranularity).toBe("stream");
119
+ expect(events.some((e) => e.type === "text_delta")).toBe(true);
120
+
121
+ // 事件形态:三条 delta(golden pushStream)→ message_end(usage) → turn_end
122
+ expect(events.map((e) => e.type)).toEqual([
123
+ "text_delta", "text_delta", "text_delta", "message_end", "turn_end",
124
+ ]);
125
+ const messageEnd = events.find((e) => e.type === "message_end") as
126
+ | { usage?: { input: number; output: number; cacheRead: number; cacheWrite: number } }
127
+ | undefined;
128
+ expect(messageEnd?.usage).toEqual({ input: 12599, output: 17, cacheRead: 0, cacheWrite: 0 });
129
+
130
+ // tool 事件不合成:首期无逐工具推送帧,流出面不伪造 tool_start/tool_end
131
+ // (granularity 声明与实际流出一致即合法——app-server 设计 §3.4 不变量 1)
132
+ expect(events.some((e) => e.type === "tool_start" || e.type === "tool_end")).toBe(false);
133
+
134
+ // 不变量五条(stream 口径):3a 的 content 用 read 全文(终态权威来源)
135
+ const readFullText = goldenReadFullText();
136
+ assertAgentEventInvariants(events, { granularity: "stream", content: readFullText });
137
+ expect(outcome.content).toBe(readFullText);
138
+ } finally {
139
+ await h.dispose();
140
+ }
141
+ }, 20_000);
142
+
143
+ it("终态权威 turn.terminal 缺失 → read 兜底收口,事件不变量仍全绿(宽松匹配防洪堤不破坏 C3)", async () => {
144
+ const h = makeAppserverHarness({ dropTurnTerminal: true });
145
+ try {
146
+ const events: AgentEvent[] = [];
147
+ const { outcome } = await h.engine.run(
148
+ { prompt: "做点什么", description: "c3-no-terminal", model: "conformance-provider/m1", cwd: h.workspace },
149
+ { taskId: "sa-c3-no-terminal", poolKey: "", onEvent: (e) => events.push(e) },
150
+ );
151
+ expect(outcome.error).toBeUndefined();
152
+ // 缺 turn.terminal 时收尾帧 + read 兜底仍产出完整终态(session-channel 宽松匹配)
153
+ assertAgentEventInvariants(events, { granularity: "stream", content: goldenReadFullText() });
154
+ } finally {
155
+ await h.dispose();
156
+ }
157
+ }, 20_000);
158
+
159
+ it("handle 携带 shared poolKey(共享宿主 HOME 的 journal 分组锚点,①级读取钥匙随 handle 走)", async () => {
160
+ const h = makeAppserverHarness();
161
+ try {
162
+ const { handle, outcome } = await h.engine.run(
163
+ { prompt: "做点什么", description: "c3-anchor", model: "conformance-provider/m1", cwd: h.workspace },
164
+ { taskId: "sa-c3-anchor", poolKey: "" },
165
+ );
166
+ expect(handle.data.poolKey).toBe(ZCODE_SHARED_POOL_KEY);
167
+ expect(handle.data.sessionRef["sessionId"]).toBe(outcome.sessionId);
168
+ // golden 锚点:sessionId 来自 session.sessionId(projection.sessionId 恒 "unknown" 勿用)
169
+ expect(JSON.parse(ZCODE_APPSERVER_GOLDEN.createResponse).session.sessionId).toBe("sess_golden_r3_01");
170
+ } finally {
171
+ await h.dispose();
172
+ }
173
+ }, 20_000);
174
+ });
@@ -25,10 +25,11 @@ import { describe, expect, it } from "vitest";
25
25
  import { getSubagentService } from "../../../subagent-service.ts";
26
26
  import { ZcodeEngine } from "../../engines/zcode/zcode-engine.ts";
27
27
  import { createPiEngine } from "../../engines/pi/registration.ts";
28
+ import type { PiEngineService } from "../../engines/pi/pi-engine.ts";
28
29
  import type { RunContext } from "../../port.ts";
29
30
  import type { AgentEvent } from "../../../types.ts";
30
- import type { AgentTaskSpec } from "../../types.ts";
31
- import { getPiInvocation } from "../../../pi-invocation.ts";
31
+ import type { AgentCallOpts } from "../../../../orchestration/models/types.ts";
32
+ import { getPiInvocation } from "../../engines/pi/pi-invocation.ts";
32
33
  import {
33
34
  RELAY_ENV_NODE,
34
35
  RELAY_ENV_RECORD_ID,
@@ -51,8 +52,8 @@ describe.skipIf(!LIVE)("conformance run 层(真实 spawn,手动门)", () =
51
52
  testCtx.skip("SubagentService 未装配(需在真实会话进程内运行)");
52
53
  return;
53
54
  }
54
- const engine = createPiEngine(() => service);
55
- const task: AgentTaskSpec = { task: "Reply with the single word: ok", slug: "live-c2" };
55
+ const engine = createPiEngine(() => service as unknown as PiEngineService);
56
+ const task: AgentCallOpts = { prompt: "Reply with the single word: ok", description: "live-c2" };
56
57
  const ctx: RunContext = { taskId: "sa-live-pi-c2", poolKey: "shared" };
57
58
  const { outcome } = await engine.run(task, ctx);
58
59
  expect(outcome.error).toBeUndefined();
@@ -66,6 +67,31 @@ describe.skipIf(!LIVE)("conformance run 层(真实 spawn,手动门)", () =
66
67
  expect(report.ok).toBe(true);
67
68
  expect(report.engineVersion).toMatch(/^0\.\d+\.\d+$/);
68
69
  }, 60_000);
70
+
71
+ // [R6] 常驻通道的 conformance run 层(RA8「C1-C8 适配后全绿」的 live 面):
72
+ // 跑最小任务——C2 outcome + C3 stream 不变量(app-server 设计 §3.4 不变量 1)。
73
+ // 2026-09 起单一 app-server 形态即缺省路径(无模式钉扎 env);更深断言(schema/
74
+ // abort/进程锚定)由 engines/zcode/__tests__/zcode-engine.live.test.ts 承载。
75
+ it("zcode:app-server 常驻通道 run 全链(C2 outcome 无 error + C3 stream 事件不变量)", async (testCtx) => {
76
+ const model = process.env["ZCODE_E2E_MODEL"];
77
+ if (model === undefined || model === "") {
78
+ testCtx.skip("ZCODE_E2E_MODEL 未设置(需真实 provider/model 凭据)——appserver live run 面跳过");
79
+ return;
80
+ }
81
+ const engine = new ZcodeEngine({
82
+ engineDataDir: () => "/tmp/zcode-conformance-live-appserver",
83
+ });
84
+ const events: AgentEvent[] = [];
85
+ const { outcome } = await engine.run(
86
+ { prompt: "Reply with the single word: ok", description: "live-appserver-c2", model, cwd: "/tmp" },
87
+ { taskId: "sa-live-zcode-appserver", poolKey: "", onEvent: (e) => events.push(e) },
88
+ );
89
+ expect(outcome.error).toBeUndefined();
90
+ expect(outcome.content.trim().length).toBeGreaterThan(0);
91
+ expect(outcome.sessionId).toMatch(/^sess_/);
92
+ assertAgentEventInvariants(events, { granularity: "stream", content: outcome.content });
93
+ await engine.dispose().catch(() => undefined);
94
+ }, 180_000);
69
95
  });
70
96
 
71
97
  // ── relay 变体(E 方案 §2.3:同一契约 × 不同 spawn 通道,手动门内的手动门)──
@@ -174,9 +200,9 @@ describe.skipIf(!LIVE)("conformance relay 变体(经代理 spawn 全链,手
174
200
  }
175
201
 
176
202
  try {
177
- const engine = createPiEngine(() => service);
203
+ const engine = createPiEngine(() => service as unknown as PiEngineService);
178
204
  const events: AgentEvent[] = [];
179
- const task: AgentTaskSpec = { task: "Reply with the single word: ok", slug: "live-relay-c2" };
205
+ const task: AgentCallOpts = { prompt: "Reply with the single word: ok", description: "live-relay-c2" };
180
206
  const ctx: RunContext = {
181
207
  taskId: "sa-live-pi-relay",
182
208
  poolKey: "shared",
@@ -195,7 +221,7 @@ describe.skipIf(!LIVE)("conformance relay 变体(经代理 spawn 全链,手
195
221
  else process.env[key] = savedEnv[key];
196
222
  }
197
223
  await new Promise<void>((resolve) => server.close(() => resolve()));
198
- fs.rmSync(tmpDir, { recursive: true, force: true });
224
+ fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
199
225
  }
200
226
  });
201
227
  });
@@ -15,7 +15,7 @@ import { describe, expect, it } from "vitest";
15
15
 
16
16
  import type { AgentEvent } from "../../../types.ts";
17
17
  import { JournalWriter, replayJournal } from "../../common/event-journal.ts";
18
- import { parseSpawnLine } from "../../../spawn-event-adapter.ts";
18
+ import { parseSpawnLine } from "../../engines/pi/spawn-event-adapter.ts";
19
19
  import { assertAgentEventInvariants } from "./agent-event-invariants.ts";
20
20
 
21
21
  interface PiGoldenFile {
@@ -1,8 +1,13 @@
1
- // golden-replay.zcode.test.ts —— zcode 引擎 golden 回放层(conformance 免 LLM 默认 CI
2
- // 层)。数据源 = P3 验收前置门的真机实录(engines/zcode/__tests__/__fixtures__/
3
- // zcode-golden-spawn.json 的 stdoutRaw)——parser 对实录样本回归 + coarse 事件合成
4
- // 不变量断言 + 双副本 diff 校验(fixture 与 golden-sample.ts 内嵌副本一致,防漂移:
5
- // 更新样本必须同步两处,探针的干跑校验消费内嵌副本,两处不一致 = 探针在测旧契约)。
1
+ // golden-replay.zcode.test.ts —— zcode 引擎 golden 回放层(conformance 免 LLM 默认
2
+ // CI 层)。语料 = app-server NDJSON 帧序列(附录 A.2 任务生命周期帧序;采集 SSOT
3
+ // = engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json)——双副本 diff
4
+ // 校验(fixture 与 golden-sample.ts 内嵌副本一致,防漂移:更新样本必须同步两处,
5
+ // 探针的干跑校验消费内嵌副本,两处不一致 = 探针在测旧契约)+ 帧形态不变量断言
6
+ // (A8「golden 帧序列语料 diff 通过」的本仓段)。
7
+ //
8
+ // 2026-09 重构(共享宿主 HOME):CLI spawn 链删除后 spawn stdout 语料(单 JSON
9
+ // 样本及其 fixture)随 spawn 回归一并删除,本层仅保留 app-server 帧序列语料
10
+ // (常驻通道唯一生产形态)。
6
11
 
7
12
  import { readFileSync } from "node:fs";
8
13
  import { dirname, join } from "node:path";
@@ -10,70 +15,86 @@ import { fileURLToPath } from "node:url";
10
15
 
11
16
  import { describe, expect, it } from "vitest";
12
17
 
13
- import { ZCODE_GOLDEN_STDOUT } from "../../engines/zcode/golden-sample.ts";
14
- import {
15
- mapZcodeOutcomeUsage,
16
- parseZcodeTerminal,
17
- synthesizeCoarseEvents,
18
- } from "../../engines/zcode/parser.ts";
19
- import { assertAgentEventInvariants } from "./agent-event-invariants.ts";
18
+ import { ZCODE_APPSERVER_GOLDEN } from "../../engines/zcode/golden-sample.ts";
20
19
 
21
20
  // conformance 目录(engine/__tests__/conformance)→ engine 根的相对定位
22
- const fixturePath = join(
21
+ const appserverFixturePath = join(
23
22
  dirname(fileURLToPath(import.meta.url)),
24
23
  "..", "..", // conformance → __tests__ → engine
25
- "engines", "zcode", "__tests__", "__fixtures__", "zcode-golden-spawn.json",
24
+ "engines", "zcode", "__tests__", "__fixtures__", "zcode-golden-appserver.json",
26
25
  );
27
26
 
28
- interface ZcodeGoldenFile {
29
- _meta: { engineVersion: string; exitCode: number };
30
- stdoutRaw: string;
27
+ interface AppServerGoldenFile {
28
+ _meta: Record<string, unknown>;
29
+ frames: { createResponse: string; pushStream: string[]; terminal: string[]; readResponse: string };
31
30
  }
31
+ const appserverFixture = JSON.parse(readFileSync(appserverFixturePath, "utf8")) as AppServerGoldenFile;
32
32
 
33
- const fixture = JSON.parse(readFileSync(fixturePath, "utf8")) as ZcodeGoldenFile;
33
+ describe("zcode app-server golden 回放(conformance C3 帧形态,免 LLM/免二进制)", () => {
34
+ it("双副本 diff:golden-sample.ts 内嵌副本 === fixture frames(防漂移,A8 本仓段)", () => {
35
+ expect(ZCODE_APPSERVER_GOLDEN.createResponse).toBe(appserverFixture.frames.createResponse);
36
+ expect(ZCODE_APPSERVER_GOLDEN.pushStream).toEqual(appserverFixture.frames.pushStream);
37
+ expect(ZCODE_APPSERVER_GOLDEN.terminal).toEqual(appserverFixture.frames.terminal);
38
+ expect(ZCODE_APPSERVER_GOLDEN.readResponse).toBe(appserverFixture.frames.readResponse);
39
+ });
34
40
 
35
- describe("zcode golden 回放(conformance C3,免 LLM/免二进制)", () => {
36
- it("双副本 diff:golden-sample.ts 内嵌副本 === fixture stdoutRaw(防漂移,A12)", () => {
37
- expect(ZCODE_GOLDEN_STDOUT).toBe(fixture.stdoutRaw);
41
+ it("create 应答形状:权威 sessionId session.sessionId(projection.sessionId 恒 unknown 勿用)", () => {
42
+ const create = JSON.parse(ZCODE_APPSERVER_GOLDEN.createResponse) as {
43
+ session: { sessionId: string };
44
+ projection: { sessionId: string };
45
+ };
46
+ expect(create.session.sessionId).toMatch(/^sess_/);
47
+ expect(create.projection.sessionId).toBe("unknown");
38
48
  });
39
49
 
40
- it("parser 对实录样本回归:sessionId/response/usage 形状完整(探针干跑同源断言)", () => {
41
- const terminal = parseZcodeTerminal(fixture.stdoutRaw);
42
- expect(terminal.ok).toBe(true);
43
- if (!terminal.ok) return;
44
- expect(terminal.payload.sessionId).toMatch(/^sess_/);
45
- expect(terminal.payload.response).toBe("ok");
46
- expect(terminal.payload.usage).toEqual({ input: 12599, output: 17, cacheRead: 512, cacheWrite: 0 });
47
- // 终态层 usage(orchestration 版):cost 显式 0(无来源不给残缺)、contextTokens 取 projection
48
- expect(terminal.payload.outcomeUsage).toEqual({
49
- input: 12599,
50
- output: 17,
51
- cacheRead: 512,
52
- cacheWrite: 0,
53
- cost: 0,
54
- contextTokens: 12616,
55
- turns: 1,
50
+ it("推送流帧形态:stream.chunk 无文本(文本在 session/event delta)——文本三源恒等(A8 不变量 1)", () => {
51
+ const pushes = ZCODE_APPSERVER_GOLDEN.pushStream.map((l) => JSON.parse(l) as {
52
+ method: string;
53
+ params?: { kind?: string; payload?: { delta?: string } };
56
54
  });
57
- });
55
+ const chunks = pushes.filter((f) => f.params?.kind === "stream.chunk");
56
+ expect(chunks.length).toBeGreaterThan(0);
57
+ for (const c of chunks) expect(c.params?.payload?.delta).toBeUndefined();
58
+
59
+ const deltaJoined = pushes
60
+ .filter((f) => f.method === "session/event" && typeof f.params?.payload?.delta === "string")
61
+ .map((f) => f.params?.payload?.delta)
62
+ .join("");
63
+ const terminal = ZCODE_APPSERVER_GOLDEN.terminal.map((l) => JSON.parse(l) as {
64
+ params?: { kind?: string; payload?: { response?: string; usage?: { inputTokens: number; outputTokens: number } } };
65
+ });
66
+ const closing = terminal.find((f) => f.params?.payload?.response !== undefined);
67
+ expect(closing?.params?.payload?.response).toBe(deltaJoined);
58
68
 
59
- it("coarse 事件合成满足产出不变量(turn_end 最后、其前必有 message_end、usage 完整)", () => {
60
- const terminal = parseZcodeTerminal(fixture.stdoutRaw);
61
- if (!terminal.ok) throw new Error("golden 样本解析失败(上一用例应已转红)");
62
- const events = synthesizeCoarseEvents(terminal.payload.response, terminal.payload.usage);
63
- assertAgentEventInvariants(events, { granularity: "coarse" });
64
- expect(events.map((e) => e.type)).toEqual(["message_end", "turn_end"]);
69
+ const read = JSON.parse(ZCODE_APPSERVER_GOLDEN.readResponse) as {
70
+ messages: Array<{ info: { role: string }; parts: Array<{ type: string; text?: string }> }>;
71
+ };
72
+ const readText = (read.messages.at(-1)?.parts ?? [])
73
+ .filter((p) => p.type === "text")
74
+ .map((p) => p.text ?? "")
75
+ .join("");
76
+ expect(readText).toBe(deltaJoined); // text_delta 拼接 == 收尾帧 == read 全文
65
77
  });
66
78
 
67
- it("usage 无来源样本:mapZcodeOutcomeUsage 显式缺省(不给残缺对象,不变量 2 的输入面)", () => {
68
- expect(mapZcodeOutcomeUsage(undefined, undefined)).toBeUndefined();
69
- expect(mapZcodeOutcomeUsage({ inputTokens: 1 }, undefined)).toEqual({
70
- input: 1,
71
- output: 0,
72
- cacheRead: 0,
73
- cacheWrite: 0,
74
- cost: 0,
75
- contextTokens: 0,
76
- turns: 1,
79
+ it("终态权威帧:turn.terminal 存在且先于收尾帧;usage read step-finish tokens 同源(漂移对照锚点)", () => {
80
+ const terminal = ZCODE_APPSERVER_GOLDEN.terminal.map((l) => JSON.parse(l) as {
81
+ params?: { kind?: string; status?: string; payload?: { usage?: { inputTokens: number; outputTokens: number } } };
82
+ });
83
+ const terminalFrameIdx = terminal.findIndex((f) => f.params?.kind === "turn.terminal");
84
+ const closingFrameIdx = terminal.findIndex((f) => f.params?.payload?.usage !== undefined);
85
+ expect(terminalFrameIdx).toBeGreaterThanOrEqual(0);
86
+ expect(terminal[terminalFrameIdx]?.params?.status).toBe("success");
87
+ expect(terminalFrameIdx).toBeLessThan(closingFrameIdx);
88
+
89
+ // usage 跨源对照锚点:收尾帧 usage == read 应答 step-finish tokens(同一轮真实
90
+ // 计费面,两源必须一致;旧 spawn golden 对照随语料删除)
91
+ const read = JSON.parse(ZCODE_APPSERVER_GOLDEN.readResponse) as {
92
+ messages: Array<{ info: { role: string }; parts: Array<{ type: string; tokens?: { input: number; output: number } }> }>;
93
+ };
94
+ const stepFinish = (read.messages.at(-1)?.parts ?? []).find((p) => p.type === "step-finish");
95
+ expect(terminal[closingFrameIdx]?.params?.payload?.usage).toEqual({
96
+ inputTokens: stepFinish?.tokens?.input,
97
+ outputTokens: stepFinish?.tokens?.output,
77
98
  });
78
99
  });
79
100
  });
@@ -0,0 +1,128 @@
1
+ // zcode-appserver-harness.ts —— conformance 层的 fake app-server 引擎组装器(R6)。
2
+ //
3
+ // 与 engines/zcode/__tests__/zcode-engine-appserver.test.ts 的 makeEngine 同模式
4
+ // (scenario 文件随 env 固化进 fake 子进程),抽出为 conformance 专用副本而非跨测试
5
+ // 目录 import 测试文件——conformance 套件自包含(A12:套件不依赖被测引擎自己的
6
+ // 单测文件结构)。协议/断言面同源:fake-appserver.mjs + ZCODE_APPSERVER_GOLDEN。
7
+
8
+ import * as fs from "node:fs";
9
+ import * as os from "node:os";
10
+ import * as path from "node:path";
11
+ import { fileURLToPath } from "node:url";
12
+
13
+ import { ZCODE_APPSERVER_GOLDEN } from "../../engines/zcode/golden-sample.ts";
14
+ import { ZcodeEngine } from "../../engines/zcode/zcode-engine.ts";
15
+
16
+ const FAKE_CLI = fileURLToPath(
17
+ new URL("../../engines/zcode/__tests__/__fixtures__/fake-appserver.mjs", import.meta.url),
18
+ );
19
+ const PROVIDER = "conformance-provider";
20
+
21
+ export interface AppserverHarnessOptions {
22
+ /** 覆盖 send 推送帧(缺省 = golden pushStream + 终态两帧;dropTurnTerminal 置真时去 turn.terminal)。 */
23
+ dropTurnTerminal?: boolean;
24
+ /** 覆盖 read 应答(read 是全文权威来源)。 */
25
+ readResult?: unknown;
26
+ /** session/stop 行为(fake scenario.stopBehavior;缺省 'terminal' = stop 优雅生效)。 */
27
+ stopBehavior?: "terminal" | "none";
28
+ /** 只保留 state.updated(挂起场景——turn 永不自然落定,abort 用例用)。 */
29
+ hangOnly?: boolean;
30
+ }
31
+
32
+ export interface AppserverHarness {
33
+ engine: ZcodeEngine;
34
+ /** fake 子进程的事件流水文件(帧序断言数据源)。 */
35
+ stateFile: string;
36
+ workspace: string;
37
+ dataDir: string;
38
+ dispose(): Promise<void>;
39
+ }
40
+
41
+ /** 组装连到 fake-appserver 的常驻引擎(单一 app-server 形态——2026-09 起无模式分派)。 */
42
+ export function makeAppserverHarness(opts: AppserverHarnessOptions = {}): AppserverHarness {
43
+ const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "zcode-conformance-appserver-"));
44
+ const dataDir = path.join(tmpRoot, "data");
45
+ const stateFile = path.join(tmpRoot, "state.jsonl");
46
+ const scenarioFile = path.join(tmpRoot, "scenario.json");
47
+ const workspace = path.join(tmpRoot, "ws");
48
+ const v2Path = path.join(tmpRoot, "v2.json");
49
+
50
+ fs.mkdirSync(path.dirname(v2Path), { recursive: true });
51
+ fs.writeFileSync(
52
+ v2Path,
53
+ JSON.stringify({
54
+ provider: { [PROVIDER]: { options: { apiKey: "k", baseURL: "https://t.example" }, models: { m1: {} } } },
55
+ }),
56
+ );
57
+
58
+ const pushes = opts.hangOnly
59
+ ? [ZCODE_APPSERVER_GOLDEN.pushStream[0]].map((l) => JSON.parse(l) as unknown)
60
+ : [
61
+ ...ZCODE_APPSERVER_GOLDEN.pushStream,
62
+ ...(opts.dropTurnTerminal ? [] : [ZCODE_APPSERVER_GOLDEN.terminal[0]]),
63
+ ZCODE_APPSERVER_GOLDEN.terminal[1],
64
+ ].map((l) => JSON.parse(l) as unknown);
65
+ fs.writeFileSync(
66
+ scenarioFile,
67
+ JSON.stringify({
68
+ createResult: JSON.parse(ZCODE_APPSERVER_GOLDEN.createResponse),
69
+ readResult: opts.readResult ?? JSON.parse(ZCODE_APPSERVER_GOLDEN.readResponse),
70
+ sendPushes: pushes,
71
+ ...(opts.stopBehavior !== undefined ? { stopBehavior: opts.stopBehavior } : {}),
72
+ }),
73
+ );
74
+
75
+ const engine = new ZcodeEngine({
76
+ engineDataDir: () => dataDir,
77
+ cliPath: FAKE_CLI,
78
+ sources: { v2ConfigPath: v2Path },
79
+ processEnv: {
80
+ PATH: process.env.PATH ?? "",
81
+ FAKE_STATE_FILE: stateFile,
82
+ FAKE_SESSION_SCENARIO: scenarioFile,
83
+ },
84
+ });
85
+ return {
86
+ engine,
87
+ stateFile,
88
+ workspace,
89
+ dataDir,
90
+ dispose: () =>
91
+ engine.dispose().finally(() => {
92
+ fs.rmSync(tmpRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
93
+ }),
94
+ };
95
+ }
96
+
97
+ /** 读 fake 流水(帧序断言用)。 */
98
+ export function readFakeState(file: string): Array<Record<string, unknown>> {
99
+ try {
100
+ return fs
101
+ .readFileSync(file, "utf8")
102
+ .trim()
103
+ .split("\n")
104
+ .filter(Boolean)
105
+ .map((l) => JSON.parse(l) as Record<string, unknown>);
106
+ } catch {
107
+ return [];
108
+ }
109
+ }
110
+
111
+ /** fake 收到的客户端帧方法名序列(abort 链「stop 先于杀链」断言面)。 */
112
+ export function sentMethodNames(stateFile: string): string[] {
113
+ return readFakeState(stateFile)
114
+ .map((e) => (e as Record<string, unknown>)["frame"])
115
+ .filter((f): f is Record<string, unknown> => typeof f === "object" && f !== null && typeof (f as Record<string, unknown>)["method"] === "string")
116
+ .map((f) => f["method"] as string);
117
+ }
118
+
119
+ /** golden read 应答里 assistant 消息的 text parts 拼接(read 全文——不变量 3a 的比对基准)。 */
120
+ export function goldenReadFullText(): string {
121
+ const read = JSON.parse(ZCODE_APPSERVER_GOLDEN.readResponse) as {
122
+ messages: Array<{ info: { role: string }; parts: Array<{ type: string; text?: string }> }>;
123
+ };
124
+ return (read.messages.at(-1)?.parts ?? [])
125
+ .filter((p) => p.type === "text")
126
+ .map((p) => p.text ?? "")
127
+ .join("");
128
+ }
@@ -15,8 +15,20 @@ import { clearEngines, registerEngine } from "../registry.ts";
15
15
  function stubEngine(id: string): EnginePort {
16
16
  return {
17
17
  id,
18
- capabilities: () => ({ conversation: "unsupported", steer: "unsupported", sandbox: "none" }),
19
- probe: async () => ({ ok: true, engineVersion: "test" }),
18
+ capabilities: () => ({
19
+ schemaEnforcement: "emulated",
20
+ steer: "unsupported",
21
+ conversation: "unsupported",
22
+ personaInjection: "prompt",
23
+ eventGranularity: "coarse",
24
+ sandbox: "none",
25
+ sessionRead: "outcome-only",
26
+ resume: "unsupported",
27
+ interrupt: "kill-only",
28
+ permissionMode: "ignored",
29
+ maxTurns: false,
30
+ }),
31
+ probe: async () => ({ ok: true, engineVersion: "test", checks: [] }),
20
32
  run: async () => {
21
33
  throw new Error("unused");
22
34
  },
@@ -38,7 +50,7 @@ beforeEach(() => {
38
50
 
39
51
  afterEach(() => {
40
52
  clearEngines();
41
- fs.rmSync(tmpRoot, { recursive: true, force: true });
53
+ fs.rmSync(tmpRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
42
54
  });
43
55
 
44
56
  describe("syncEnginesFile", () => {
@@ -16,8 +16,20 @@ import { buildEngineModelsPromptAppend, buildSubagentEngineSection } from "../mo
16
16
  function fakeEngine(id: string, models: Array<{ id: string; name?: string }> | null): EnginePort {
17
17
  return {
18
18
  id,
19
- capabilities: () => ({ conversation: "unsupported", steer: "unsupported", sandbox: "none" }),
20
- probe: async () => ({ ok: true, engineVersion: "test" }),
19
+ capabilities: () => ({
20
+ schemaEnforcement: "emulated",
21
+ steer: "unsupported",
22
+ conversation: "unsupported",
23
+ personaInjection: "prompt",
24
+ eventGranularity: "coarse",
25
+ sandbox: "none",
26
+ sessionRead: "outcome-only",
27
+ resume: "unsupported",
28
+ interrupt: "kill-only",
29
+ permissionMode: "ignored",
30
+ maxTurns: false,
31
+ }),
32
+ probe: async () => ({ ok: true, engineVersion: "test", checks: [] }),
21
33
  run: async () => {
22
34
  throw new Error("not used in this test");
23
35
  },
@@ -38,7 +50,7 @@ beforeEach(() => {
38
50
 
39
51
  afterEach(() => {
40
52
  clearEngines();
41
- fs.rmSync(tmpRoot, { recursive: true, force: true });
53
+ fs.rmSync(tmpRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
42
54
  });
43
55
 
44
56
  describe("buildEngineModelsPromptAppend(defaultEngine 开关语义)", () => {