@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
@@ -0,0 +1,372 @@
1
+ // zcode-engine-timeout.test.ts —— [P0-1 U2] 引擎超时处置链测试(设计权威源
2
+ // docs/design/timeout-zcode-turn-and-settled-watchdog.md §6 D3/D4、§5.2 F-1/F-2)。
3
+ // 全部跑 __fixtures__/fake-appserver.mjs 子进程(scenario 注入),绝不 spawn 真
4
+ // zcode.cjs。覆盖:
5
+ // - stop 应答三态裁决各一(D3 v1.1 超时入口 escalateOn:"stop-outcome"):
6
+ // ① stop 成功应答 → 止损确认链终止,共享进程不杀(boot 计数复用证据);
7
+ // ② 协议性 error 应答(stopError 注入,健康形态竞态——closeSession 先行关会话)
8
+ // → 不升级杀链(「stop 报错一律升级会误杀健康进程」的击穿修正回归面);
9
+ // ③ stop 无应答(stopBehavior:'hang'——控制面假死形态,SIGSTOP 等价)→ 3s 超时
10
+ // 判连接级失败 → killChain 升级 → 进程死亡 + 下一任务重建(boot 2 机械证据);
11
+ // - engine_timeout 前缀归类(D4,与 engine_run_failed 分流)+ 会话 id 留痕;
12
+ // - idle / ceiling 两形态文案有别(ceiling 附 XYZ_ZCODE_TURN_MAX_TIMEOUT_MS env
13
+ // 自救通道——§5.2 F-2);
14
+ // - 非超时错误不受影响(sendError → engine_run_failed 原路径,abort 链不触发);
15
+ // - alive 守卫(修复轮):conn 已 finalize 的微窗口内 stop 分支不惰性重建进程
16
+ // (对称 closeSession 的 !alive 守卫),按连接级失败形态终局。
17
+ // idle/ceiling 阈值经 vi.stubEnv 缩短(session-channel 的 env 通道,D2)——真实默认
18
+ // 30min/60min 不在单测等待范围。
19
+
20
+ import * as fs from "node:fs";
21
+ import * as os from "node:os";
22
+ import * as path from "node:path";
23
+ import { fileURLToPath } from "node:url";
24
+
25
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
26
+
27
+ import type { EngineRunResult, RunContext } from "../../../port.ts";
28
+ import type { AgentCallOpts } from "../../../../../orchestration/models/types.ts";
29
+ import { ZCODE_SHARED_POOL_KEY } from "../constants.ts";
30
+ import { ZCODE_APPSERVER_GOLDEN } from "../golden-sample.ts";
31
+ import { AppServerConnection } from "../connection.ts";
32
+ import { SessionChannel, TurnTimeoutError } from "../session-channel.ts";
33
+ import { ZcodeEngine, hostZcodeDbPath, type ZcodeEngineDeps } from "../zcode-engine.ts";
34
+
35
+ const FAKE_CLI = fileURLToPath(new URL("./__fixtures__/fake-appserver.mjs", import.meta.url));
36
+ const PROVIDER = "test-provider";
37
+
38
+ const GOLDEN_SESSION_ID = "sess_golden_r3_01";
39
+ const GOLDEN_FULL_TEXT = "你好,任务完成";
40
+ /** 挂起场景:send 后零推送——turn 无事件(idle 主判定的判死形态)。 */
41
+ const HANG_PUSHES: string[] = [];
42
+
43
+ interface RpcErrorSpec {
44
+ code: number;
45
+ message: string;
46
+ data?: unknown;
47
+ }
48
+
49
+ interface ScenarioOverrides {
50
+ replaceSendPushes?: string[];
51
+ stopBehavior?: "terminal" | "none" | "hang";
52
+ stopError?: RpcErrorSpec;
53
+ sendError?: RpcErrorSpec;
54
+ }
55
+
56
+ const engines: ZcodeEngine[] = [];
57
+ let seq = 0;
58
+ let tmpRoot: string;
59
+ let dataDir: string;
60
+ let v2Path: string;
61
+
62
+ function writeJson(p: string, v: unknown): void {
63
+ fs.mkdirSync(path.dirname(p), { recursive: true });
64
+ fs.writeFileSync(p, JSON.stringify(v, null, 2));
65
+ }
66
+
67
+ beforeEach(() => {
68
+ tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "zcode-eng-timeout-"));
69
+ dataDir = path.join(tmpRoot, "data");
70
+ v2Path = path.join(tmpRoot, "v2.json");
71
+ writeJson(v2Path, {
72
+ provider: { [PROVIDER]: { options: { apiKey: "k", baseURL: "https://t.example" }, models: { m1: {} } } },
73
+ });
74
+ });
75
+
76
+ afterEach(async () => {
77
+ vi.unstubAllEnvs();
78
+ for (const engine of engines.splice(0)) await engine.dispose().catch(() => undefined);
79
+ fs.rmSync(tmpRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
80
+ });
81
+
82
+ interface EngineFixture {
83
+ engine: ZcodeEngine;
84
+ stateFile: string;
85
+ scenarioFile: string;
86
+ workspace: string;
87
+ /** 重写 scenario(新 fake 进程启动时重读——killChain 重建轮的形态切换通道)。 */
88
+ rewriteScenario: (overrides: ScenarioOverrides) => void;
89
+ }
90
+
91
+ function makeEngine(overrides: ScenarioOverrides = {}): EngineFixture {
92
+ seq += 1;
93
+ const stateFile = path.join(tmpRoot, `state-${seq}.jsonl`);
94
+ const scenarioFile = path.join(tmpRoot, `scenario-${seq}.json`);
95
+ const workspace = path.join(tmpRoot, `ws-${seq}`);
96
+ const write = (o: ScenarioOverrides): void => {
97
+ writeJson(scenarioFile, {
98
+ createResult: JSON.parse(ZCODE_APPSERVER_GOLDEN.createResponse),
99
+ readResult: JSON.parse(ZCODE_APPSERVER_GOLDEN.readResponse),
100
+ sendPushes: (o.replaceSendPushes ?? HANG_PUSHES).map((l) => JSON.parse(l) as Record<string, unknown>),
101
+ ...(o.stopBehavior !== undefined ? { stopBehavior: o.stopBehavior } : {}),
102
+ ...(o.stopError !== undefined ? { stopError: o.stopError } : {}),
103
+ ...(o.sendError !== undefined ? { sendError: o.sendError } : {}),
104
+ });
105
+ };
106
+ write(overrides);
107
+ const deps: ZcodeEngineDeps = {
108
+ engineDataDir: () => dataDir,
109
+ cliPath: FAKE_CLI,
110
+ sources: { v2ConfigPath: v2Path },
111
+ processEnv: {
112
+ PATH: process.env.PATH ?? "",
113
+ // 钉扎 appserver 定向(定向不探不降);idle/ceiling 阈值走全局 env stub
114
+ // (session-channel 的 resolveTurnTimerMs 直接读 process.env——D2 env 通道)
115
+ XYZ_ZCODE_MODE: "appserver",
116
+ FAKE_STATE_FILE: stateFile,
117
+ FAKE_SESSION_SCENARIO: scenarioFile,
118
+ },
119
+ };
120
+ const engine = new ZcodeEngine(deps);
121
+ engines.push(engine);
122
+ return {
123
+ engine,
124
+ stateFile,
125
+ scenarioFile,
126
+ workspace,
127
+ rewriteScenario: (o) => write(o),
128
+ };
129
+ }
130
+
131
+ // ── 流水读取 helpers(与 zcode-engine-appserver.test.ts 同款) ──
132
+
133
+ interface StateEvent {
134
+ seq: number;
135
+ ev: string;
136
+ [key: string]: unknown;
137
+ }
138
+
139
+ function readState(file: string): StateEvent[] {
140
+ try {
141
+ return fs
142
+ .readFileSync(file, "utf8")
143
+ .trim()
144
+ .split("\n")
145
+ .filter(Boolean)
146
+ .map((l) => JSON.parse(l) as StateEvent);
147
+ } catch {
148
+ return [];
149
+ }
150
+ }
151
+
152
+ function isRecord(v: unknown): v is Record<string, unknown> {
153
+ return typeof v === "object" && v !== null && !Array.isArray(v);
154
+ }
155
+
156
+ function sentMethods(stateFile: string): string[] {
157
+ return readState(stateFile)
158
+ .map((e) => e.frame)
159
+ .filter((f): f is Record<string, unknown> => isRecord(f) && typeof f.method === "string")
160
+ .map((f) => f.method as string);
161
+ }
162
+
163
+ function bootCount(stateFile: string): number {
164
+ return readState(stateFile).filter((e) => e.ev === "boot").length;
165
+ }
166
+
167
+ /** fake 进程 pid(boot 流水记录——进程探活的取证面:kill(pid,0) 不抛即存活)。 */
168
+ function bootPid(stateFile: string): number {
169
+ const boot = readState(stateFile).find((e) => e.ev === "boot");
170
+ if (!boot || typeof boot["pid"] !== "number") throw new Error("boot 流水缺失 pid");
171
+ return boot["pid"];
172
+ }
173
+
174
+ /** 进程探活(信号 0 不投递只探测):返回 true = 存活。 */
175
+ function processAlive(pid: number): boolean {
176
+ try {
177
+ process.kill(pid, 0);
178
+ return true;
179
+ } catch {
180
+ return false;
181
+ }
182
+ }
183
+
184
+ function makeTask(overrides?: Partial<AgentCallOpts>): AgentCallOpts {
185
+ return { prompt: "做点什么", description: "s", model: `${PROVIDER}/m1`, ...overrides };
186
+ }
187
+
188
+ function makeCtx(overrides?: Partial<RunContext>): RunContext {
189
+ return { taskId: "sa-timeout", poolKey: "", ...overrides };
190
+ }
191
+
192
+ // ============================================================
193
+ // stop 应答三态裁决(D3 v1.1 超时入口)+ engine_timeout 归类(D4)
194
+ // ============================================================
195
+
196
+ describe("超时处置链(P0-1 U2:catch 分流 → stop-outcome 三态裁决 → engine_timeout)", () => {
197
+ it("态① stop 成功应答:止损确认链终止,outcome 止损路径=「stop 已送达」,共享进程不杀(复用轮 boot 1)", async () => {
198
+ vi.stubEnv("XYZ_ZCODE_TURN_IDLE_TIMEOUT_MS", "300");
199
+ const f = makeEngine(); // hang 场景(send 后零事件)+ stopBehavior 缺省 terminal(reply stopped)
200
+ const r: EngineRunResult = await f.engine.run(makeTask({ cwd: f.workspace }), makeCtx());
201
+ // D4 归类:engine_timeout 前缀 + idle 判定标注 + 会话 id 留痕
202
+ expect(r.outcome.error).toMatch(/^engine_timeout:/);
203
+ expect(r.outcome.error).toContain("idle 判定");
204
+ expect(r.outcome.exitCode).toBeNull();
205
+ expect(r.outcome.sessionId).toBe(GOLDEN_SESSION_ID);
206
+ // D3 强制可观测面(r3 SG-4):止损路径 = stop 已送达
207
+ expect(r.outcome.error).toContain("session/stop 已送达");
208
+ expect(r.outcome.error).not.toContain("升级杀链");
209
+ // 恢复指引(§5.2 F-1)
210
+ expect(r.outcome.error).toContain("engine: pi");
211
+ // stop 帧已发出(send 之后)
212
+ const methods = sentMethods(f.stateFile);
213
+ expect(methods).toContain("session/stop");
214
+ expect(methods.indexOf("session/stop")).toBeGreaterThan(methods.indexOf("session/send"));
215
+ // 不杀共享进程(机械证据):fake 进程仍存活 + 全程零重启(boot 计数 1)。
216
+ // (复用进程时 scenario 固化在其内存——下一任务无法切正常场景,探活是「不杀」
217
+ // 的直接证据;进程若被 killChain 收割则探活必失败。)
218
+ expect(processAlive(bootPid(f.stateFile))).toBe(true);
219
+ expect(bootCount(f.stateFile)).toBe(1);
220
+ }, 20_000);
221
+
222
+ it("态② 协议性 error 应答(会话已回收形态):不升级杀链(健康形态竞态——stop 报错 ≠ 控制面死)", async () => {
223
+ vi.stubEnv("XYZ_ZCODE_TURN_IDLE_TIMEOUT_MS", "300");
224
+ const f = makeEngine({
225
+ stopError: { code: -32004, message: "Session is not active" },
226
+ });
227
+ const r = await f.engine.run(makeTask({ cwd: f.workspace }), makeCtx());
228
+ expect(r.outcome.error).toMatch(/^engine_timeout:/);
229
+ expect(r.outcome.error).toContain("idle 判定");
230
+ // 止损路径 = 协议性 error 分支,绝不出现杀链分支专属文案
231
+ expect(r.outcome.error).toContain("协议性 error");
232
+ expect(r.outcome.error).not.toContain("无应答已升级杀链");
233
+ expect(sentMethods(f.stateFile)).toContain("session/stop");
234
+ // 进程未被杀(机械证据:探活 + 零重启)——本用例守护的正是「stop 失败一律升级」
235
+ // 修正后不误杀健康共享进程的回归面(D3 被否谱系第四条)
236
+ expect(processAlive(bootPid(f.stateFile))).toBe(true);
237
+ expect(bootCount(f.stateFile)).toBe(1);
238
+ }, 20_000);
239
+
240
+ it("态③ stop 无应答(hang=控制面假死):3s 超时判连接级失败 → killChain 升级 → 进程死亡 + 重建(boot 2)", async () => {
241
+ vi.stubEnv("XYZ_ZCODE_TURN_IDLE_TIMEOUT_MS", "300");
242
+ const f = makeEngine({ stopBehavior: "hang" });
243
+ const r = await f.engine.run(makeTask({ cwd: f.workspace }), makeCtx());
244
+ expect(r.outcome.error).toMatch(/^engine_timeout:/);
245
+ expect(r.outcome.error).toContain("idle 判定");
246
+ // D3 强制可观测面(A2 对称):止损路径 = stop 无应答已升级杀链
247
+ expect(r.outcome.error).toContain("session/stop 无应答已升级杀链");
248
+ expect(sentMethods(f.stateFile)).toContain("session/stop");
249
+ // killChain 真的收割了共享进程(机械证据):旧 fake 进程已死(探活失败)
250
+ expect(processAlive(bootPid(f.stateFile))).toBe(false);
251
+ // 切换正常场景后下一任务必须重建(boot 计数:U4 起首轮 killChain 收口后自动重试
252
+ // 一次——重试轮经惰性重建 boot 2(同 scenario 仍 hang+stop hang → 重试轮也走
253
+ // killChain 收口);本用例的下一任务再重建 boot 3——「killChain 后重建」语义不变,
254
+ // 计数随 U4 重试 +1)
255
+ f.rewriteScenario({ replaceSendPushes: [...ZCODE_APPSERVER_GOLDEN.pushStream, ...ZCODE_APPSERVER_GOLDEN.terminal] });
256
+ const r2 = await f.engine.run(makeTask({ cwd: f.workspace }), makeCtx());
257
+ expect(r2.outcome.error).toBeUndefined();
258
+ expect(r2.outcome.content).toBe(GOLDEN_FULL_TEXT);
259
+ expect(bootCount(f.stateFile)).toBe(3);
260
+ }, 40_000);
261
+
262
+ it("ceiling 形态(idle 关闭 + 总上界判死):文案标 chatty-wedge + 附 XYZ_ZCODE_TURN_MAX_TIMEOUT_MS env 自救通道(F-2)", async () => {
263
+ vi.stubEnv("XYZ_ZCODE_TURN_IDLE_TIMEOUT_MS", "0"); // 显式关闭 idle(规则 19 opt-out)
264
+ vi.stubEnv("XYZ_ZCODE_TURN_MAX_TIMEOUT_MS", "400");
265
+ const f = makeEngine();
266
+ const r = await f.engine.run(makeTask({ cwd: f.workspace }), makeCtx());
267
+ expect(r.outcome.error).toMatch(/^engine_timeout:/);
268
+ expect(r.outcome.error).toContain("总上界");
269
+ expect(r.outcome.error).toContain("chatty-wedge");
270
+ // env 自救通道提示(F-2 与 idle 形态的文案分野)
271
+ expect(r.outcome.error).toContain("XYZ_ZCODE_TURN_MAX_TIMEOUT_MS");
272
+ expect(r.outcome.error).toContain("0 关闭总上界");
273
+ // idle 形态专属的「连续静默」文案不出现
274
+ expect(r.outcome.error).not.toContain("连续静默");
275
+ expect(r.outcome.error).toContain("session/stop 已送达");
276
+ }, 20_000);
277
+
278
+ it("非超时错误不受影响:sendError → engine_run_failed 原路径,abort 链不触发(流水无 session/stop)", async () => {
279
+ const f = makeEngine({ sendError: { code: -32004, message: "Session is not active" } });
280
+ const r = await f.engine.run(makeTask({ cwd: f.workspace }), makeCtx());
281
+ expect(r.outcome.error).toContain("engine_run_failed");
282
+ expect(r.outcome.error).not.toContain("engine_timeout");
283
+ expect(r.outcome.error).toContain("-32004");
284
+ expect(r.outcome.sessionId).toBe(GOLDEN_SESSION_ID);
285
+ // abort 链未被触发:流水只有 create/subscribe/send/close,无 stop
286
+ expect(sentMethods(f.stateFile)).not.toContain("session/stop");
287
+ }, 15_000);
288
+
289
+ it("handle 锚定不变量在超时收口下成立:onHandleReady 已回填 sessionId + poolKey(不变量 3 不因超时路径缺失)", async () => {
290
+ vi.stubEnv("XYZ_ZCODE_TURN_IDLE_TIMEOUT_MS", "300");
291
+ const f = makeEngine();
292
+ const ready: Array<{ sessionId: unknown; poolKey: string }> = [];
293
+ const r = await f.engine.run(
294
+ makeTask({ cwd: f.workspace }),
295
+ makeCtx({
296
+ onHandleReady: (partial) =>
297
+ ready.push({ sessionId: partial.sessionRef["sessionId"], poolKey: partial.poolKey }),
298
+ }),
299
+ );
300
+ expect(ready).toEqual([
301
+ { sessionId: GOLDEN_SESSION_ID, poolKey: ZCODE_SHARED_POOL_KEY },
302
+ // U4 起首轮超时收口后自动重试一次(同 hang 场景)——重试轮 create 再回填一次,
303
+ // 值相同(同一 fake 的 golden create 应答):不变量 3 每轮 create 都成立
304
+ { sessionId: GOLDEN_SESSION_ID, poolKey: ZCODE_SHARED_POOL_KEY },
305
+ ]);
306
+ expect(r.handle.data.sessionRef).toEqual({ sessionId: GOLDEN_SESSION_ID, dbPath: hostZcodeDbPath() });
307
+ expect(r.handle.data.poolKey).toBe(ZCODE_SHARED_POOL_KEY);
308
+ }, 20_000);
309
+
310
+ it("alive 守卫:conn 已 finalize(进程死+收割完成微窗口)时 stop 分支不惰性重建,按连接级失败形态终局", async () => {
311
+ // 真实微拍窗口(turn 判死与 abort 链发 stop 之间进程 finalize 完成)不可从公开
312
+ // 面同步注入——白盒构造同形态快照(dispose 窄竞态守卫测试同款先例):真实
313
+ // AppServerConnection 从未启动(child=null 等价 finalize 完成快照),onSpawned
314
+ // 探针锁「request → ensureStarted 惰性重建」未发生(守卫缺失时 stop 分支必凭空
315
+ // spawn 新一代进程再写帧)。
316
+ let spawned = false;
317
+ const conn = new AppServerConnection({
318
+ cliPath: FAKE_CLI,
319
+ cwd: tmpRoot,
320
+ env: {
321
+ PATH: process.env.PATH ?? "",
322
+ FAKE_STATE_FILE: path.join(tmpRoot, "state-alive-guard.jsonl"),
323
+ FAKE_SESSION_SCENARIO: path.join(tmpRoot, "scenario-alive-guard.json"),
324
+ },
325
+ stderrLogPath: path.join(dataDir, "logs", "alive-guard-stderr.log"),
326
+ onSpawned: () => {
327
+ spawned = true;
328
+ },
329
+ });
330
+ expect(conn.alive).toBe(false); // 快照前置:无活进程(finalize 完成形态)
331
+ const engine = new ZcodeEngine({
332
+ engineDataDir: () => dataDir,
333
+ cliPath: FAKE_CLI,
334
+ sources: { v2ConfigPath: v2Path },
335
+ processEnv: { PATH: process.env.PATH ?? "", XYZ_ZCODE_MODE: "appserver" },
336
+ });
337
+ engines.push(engine);
338
+ const ghostRt = {
339
+ conn,
340
+ channel: new SessionChannel(conn),
341
+ activeSessions: new Set<string>(),
342
+ };
343
+ const turn: Promise<unknown> = Promise.reject(
344
+ new TurnTimeoutError("idle", { thresholdMs: 300, elapsed: 301, lastEventAt: undefined }),
345
+ );
346
+ void turn.catch(() => undefined); // abort 链只 race 不 await reject——防 unhandled rejection
347
+ const chain = (
348
+ engine as unknown as {
349
+ appServerAbortChain: (
350
+ rt: unknown,
351
+ turn: Promise<unknown>,
352
+ getSessionId: () => string | undefined,
353
+ sessionCreated: Promise<void>,
354
+ entry: { escalateOn: "turn-settled" | "stop-outcome" },
355
+ ) => Promise<string>;
356
+ }
357
+ ).appServerAbortChain.bind(engine);
358
+ // 超时入口:conn 已死 = 连接级失败形态——不发 stop、不惰性重建,直接杀链终局
359
+ const stopPath = await chain(ghostRt, turn, () => GOLDEN_SESSION_ID, Promise.resolve(), {
360
+ escalateOn: "stop-outcome",
361
+ });
362
+ expect(stopPath).toBe("stop-unreachable-killed");
363
+ expect(spawned).toBe(false); // 守卫生效:零惰性 spawn(无新进程被凭空拉起)
364
+ expect(conn.alive).toBe(false); // 连接保持死亡态(无 request 触发重建)
365
+ // 用户取消入口:跳过 stop 落回 grace race——turn 已 reject 立即 settled(零重建)
366
+ const settledPath = await chain(ghostRt, turn, () => GOLDEN_SESSION_ID, Promise.resolve(), {
367
+ escalateOn: "turn-settled",
368
+ });
369
+ expect(settledPath).toBe("settled-in-grace");
370
+ expect(spawned).toBe(false);
371
+ }, 15_000);
372
+ });
@@ -1,12 +1,13 @@
1
- // zcode-engine.live.test.ts —— 端到端真机门(验收 5):真实 zcode CLI + 真实凭据 +
2
- // 真实 LLM 调用。手动门(设计 §3.3.8 conformance run 层同构):默认 skip,跑法:
1
+ // zcode-engine.live.test.ts —— 端到端真机门(单一 app-server 形态,2026-09 起无
2
+ // spawn 段):真实 zcode CLI + 真实凭据 + 真实 LLM 调用。手动门(设计 §3.3.8
3
+ // conformance run 层同构):默认 skip,跑法:
3
4
  //
4
- // cd extensions/universal/subagent-workflow
5
5
  // ENGINE_CONFORMANCE_LIVE=1 ZCODE_E2E_MODEL='<provider/model>' pnpm vitest run src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts
6
6
  //
7
7
  // ZCODE_E2E_MODEL 缺省值是采集 golden 样本的本机 provider(v2 config 实测带 apiKey、
8
- // 公网可达);换机器跑时用 env 覆盖为本机可用模型。池数据落 /tmp(跑完由本文件
9
- // afterAll 清理),不污染真实 ~/.zcode
8
+ // 公网可达);换机器跑时用 env 覆盖为本机可用模型。共享宿主 HOME 形态:会话写入
9
+ // 真实 ~/.zcode/cli/db/db.sqlite(与 GUI 共写,WAL 并发安全——已接受的拍板代价);
10
+ // journal/引擎数据落 /tmp(跑完由本文件 afterAll 清理)。
10
11
 
11
12
  import { execFileSync } from "node:child_process";
12
13
  import * as fs from "node:fs";
@@ -15,46 +16,52 @@ import * as path from "node:path";
15
16
 
16
17
  import { afterAll, beforeAll, describe, expect, it } from "vitest";
17
18
 
18
- import { resolvePoolDir } from "../../../paths.ts";
19
+ import type { AgentEvent } from "../../../types.ts";
20
+ import { ZCODE_SHARED_POOL_KEY } from "../constants.ts";
19
21
  import { ZcodeEngine } from "../zcode-engine.ts";
22
+ import { assertAgentEventInvariants } from "../../../__tests__/conformance/agent-event-invariants.ts";
20
23
 
21
24
  const LIVE = process.env["ENGINE_CONFORMANCE_LIVE"] === "1";
22
25
  const E2E_MODEL = process.env["ZCODE_E2E_MODEL"] ?? "e512d53e-0bfc-4915-9081-860d4aa13cd0/mimo-v2.5-pro";
23
- const DATA_ROOT = path.join(fs.realpathSync(os.tmpdir()), "zcode-p3-e2e-data");
24
- const WORK_CWD = path.join(fs.realpathSync(os.tmpdir()), "zcode-p3-e2e-cwd");
26
+ const AS_DATA_ROOT = path.join(fs.realpathSync(os.tmpdir()), "zcode-appserver-e2e-data");
27
+ const AS_WORK_CWD = path.join(fs.realpathSync(os.tmpdir()), "zcode-appserver-e2e-cwd");
25
28
 
26
- describe.skipIf(!LIVE)("ZcodeEngine 端到端真机(真实 LLM 调用)", () => {
29
+ describe.skipIf(!LIVE)("ZcodeEngine 端到端真机(app-server 常驻,共享宿主 HOME)", () => {
27
30
  let engine: ZcodeEngine;
28
31
 
29
32
  beforeAll(() => {
30
- fs.mkdirSync(WORK_CWD, { recursive: true });
31
- engine = new ZcodeEngine({ engineDataDir: () => DATA_ROOT });
33
+ fs.mkdirSync(AS_WORK_CWD, { recursive: true });
34
+ engine = new ZcodeEngine({
35
+ engineDataDir: () => AS_DATA_ROOT,
36
+ });
32
37
  });
33
38
 
34
- afterAll(() => {
35
- // 用完清理:池数据 + 任务 cwd(保持 /tmp 干净,实录/验证不留残留)
36
- for (const dir of [DATA_ROOT, WORK_CWD]) {
39
+ afterAll(async () => {
40
+ // dispose 是常驻进程的唯一收割入口(D6)——先 dispose 再清目录
41
+ await engine.dispose().catch(() => undefined);
42
+ for (const dir of [AS_DATA_ROOT, AS_WORK_CWD]) {
37
43
  try {
38
- fs.rmSync(dir, { recursive: true, force: true });
44
+ fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
39
45
  } catch {
40
46
  // 尽力清理
41
47
  }
42
48
  }
43
49
  });
44
50
 
45
- it("probe:二进制/版本/golden 三项全过", async () => {
51
+ it("probe:二进制/版本两项全过", async () => {
46
52
  const report = await engine.probe();
47
53
  expect(report.ok).toBe(true);
48
54
  expect(report.engineVersion).toMatch(/^0\.\d+\.\d+$/);
49
55
  }, 60_000);
50
56
 
51
- it("run:schema 任务全链成功(隔离 HOME session + outcome + read①级)", async () => {
57
+ it("run:常驻通道全链(stream 事件流出 + read①级 native + poolKey 锚定 'shared' + 会话落宿主 db)", async () => {
58
+ const events: AgentEvent[] = [];
52
59
  const { handle, outcome } = await engine.run(
53
60
  {
54
- task: 'Verify this arithmetic check: 2 + 2 = 4. If it is correct the verdict must be "ok", otherwise "bad".',
55
- slug: "e2e-schema",
61
+ prompt: 'Verify this arithmetic check: 2 + 2 = 4. If it is correct the verdict must be "ok", otherwise "bad".',
62
+ description: "e2e-appserver",
56
63
  model: E2E_MODEL,
57
- cwd: WORK_CWD,
64
+ cwd: AS_WORK_CWD,
58
65
  schema: {
59
66
  type: "object",
60
67
  properties: { verdict: { type: "string", enum: ["ok", "bad"] } },
@@ -62,65 +69,76 @@ describe.skipIf(!LIVE)("ZcodeEngine 端到端真机(真实 LLM 调用)", ()
62
69
  additionalProperties: false,
63
70
  },
64
71
  },
65
- { taskId: "sa-live-schema", poolKey: "" },
72
+ { taskId: "sa-live-appserver", poolKey: "", onEvent: (e) => events.push(e) },
66
73
  );
67
74
 
68
- // outcome 正确
75
+ // C2:outcome 正确
69
76
  expect(outcome.error).toBeUndefined();
70
77
  expect(outcome.exitCode).toBe(0);
71
- expect(outcome.content).toContain('"verdict"');
72
- expect(outcome.usage).toBeDefined();
73
- expect(outcome.usage!.input).toBeGreaterThan(0);
74
78
  expect(outcome.sessionId).toMatch(/^sess_/);
75
- // schema 仿真(D4 emulated 侧):公共层三级容错提取 + ajv 校验产出 parsedOutput
76
79
  expect(outcome.parsedOutput).toEqual({ verdict: "ok" });
80
+ expect(outcome.usage?.input).toBeGreaterThan(0);
77
81
 
78
- // 隔离 HOME 有新 session(db.sqlite 落池内,非真实 ~/.zcode)——路径经 resolvePoolDir
79
- // SSOT(poolKey 里的 '.' 会被 sanitizeSeg 编码为 '-',手工 join 会拼错目录)
80
- const dbPath = path.join(resolvePoolDir(DATA_ROOT, "zcode", handle.data.poolKey), ".zcode", "cli", "db", "db.sqlite");
81
- expect(fs.existsSync(dbPath)).toBe(true);
82
- expect(fs.statSync(dbPath).size).toBeGreaterThan(0);
82
+ // C3 stream 口径:text_delta 实时流出(非终态一次性)+ 不变量五条
83
+ expect(events.some((e) => e.type === "text_delta")).toBe(true);
84
+ assertAgentEventInvariants(events, { granularity: "stream", content: outcome.content });
83
85
 
84
- // read(handle) 第①级可读:turns 非空(验收 5 read 断言)
86
+ // handle 锚定:poolKey 'shared',dbPath = 宿主 HOME 绝对路径(①级读取钥匙)。
87
+ // 期望值独立展开(不调实现函数——实现改错时断言须红),非 path.join(homedir(), suffix) 同源
88
+ const dbPath = handle.data.sessionRef["dbPath"];
89
+ expect(dbPath).toBe(path.resolve(os.homedir(), ".zcode", "cli", "db", "db.sqlite"));
90
+ expect(dbPath.startsWith("/")).toBe(true);
91
+
92
+ // read 第①级:SQLite 完整重建(非降级)——读的是宿主 db(共享 HOME 形态)
85
93
  const view = await engine.read(handle);
86
94
  expect(view.source).toBe("native");
87
- expect(view.sessionId).toBe(outcome.sessionId);
88
95
  expect(view.turns.length).toBeGreaterThanOrEqual(1);
89
- expect(view.turns[0]!.text).toContain("verdict");
90
96
  }, 300_000);
91
97
 
92
- it("abort:长任务中途取消 → 杀链合成终态、无僵尸进程", async () => {
98
+ it("abort:长任务中途取消 → stop 链合成终态 exitCode=null + 常驻进程不残留 + 后续任务可用", async () => {
93
99
  const controller = new AbortController();
94
100
  const runPromise = engine.run(
95
101
  {
96
- task:
102
+ prompt:
97
103
  "Write an extremely detailed 5000-word technical essay about distributed systems consistency models. Do not stop early.",
98
- slug: "e2e-abort",
104
+ description: "e2e-appserver-abort",
99
105
  model: E2E_MODEL,
100
- cwd: WORK_CWD,
106
+ cwd: AS_WORK_CWD,
101
107
  },
102
- { taskId: "sa-live-abort", poolKey: "", signal: controller.signal },
108
+ { taskId: "sa-live-appserver-abort", poolKey: "", signal: controller.signal },
103
109
  );
104
- // 等 spawn 发生(prompt 已进 argv),再中途 abort
110
+ // 等 send 已发(会话在途),再中途 abort——覆盖 stop 链而非 pre-abort 短路
105
111
  await new Promise((r) => setTimeout(r, 4_000));
106
112
  controller.abort();
107
113
  const { outcome } = await runPromise;
108
114
 
109
115
  expect(outcome.exitCode).toBeNull();
110
- expect(outcome.error).toContain("SIGTERM");
111
- // 无僵尸进程:--cwd 指向本测试专用 tmp 目录的 zcode 进程应已消失
112
- const leftovers = listZcodeProcessesForCwd(WORK_CWD);
113
- expect(leftovers).toEqual([]);
114
- }, 120_000);
116
+ expect(outcome.error).toContain("session/stop");
117
+
118
+ // 无残留:引擎数据目录锚定的 app-server 进程在 dispose 前应 ≤1(abort 不误杀
119
+ // 共享进程;与其他 zcode 实例区分靠 --cwd 引擎数据目录路径)
120
+ const leftovers = listZcodeProcessesForCwd(AS_DATA_ROOT);
121
+ expect(leftovers.length).toBeLessThanOrEqual(1);
122
+
123
+ // 崩溃/中止后下一任务自动重建或复用(不变量 4 同路径)——abort 不污染常驻进程
124
+ const second = await engine.run(
125
+ { prompt: "Reply with the single word: ok", description: "e2e-appserver-after-abort", model: E2E_MODEL, cwd: AS_WORK_CWD },
126
+ { taskId: "sa-live-appserver-after-abort", poolKey: "" },
127
+ );
128
+ expect(second.outcome.error).toBeUndefined();
129
+ expect(second.outcome.content.trim().length).toBeGreaterThan(0);
130
+ }, 300_000);
115
131
  });
116
132
 
117
- /** 扫系统进程表:--cwd 锚定到指定目录的 zcode CLI 进程(僵尸检测)。 */
133
+ /** 扫系统进程表:--cwd 锚定到指定目录的 app-server 常驻进程(僵尸检测)。spawn 形态
134
+ * 是 `node .../engines/zcode/appserver-launcher.cjs app-server --cwd <dir>`——zcode.cjs
135
+ * 经 launcher 的 import() 动态加载,不出现在 cmdline。 */
118
136
  function listZcodeProcessesForCwd(cwd: string): string[] {
119
137
  try {
120
138
  const out = execFileSync("ps", ["-eo", "command"], { encoding: "utf8" });
121
139
  return out
122
140
  .split("\n")
123
- .filter((line) => line.includes("zcode.cjs") && line.includes(`--cwd ${cwd}`));
141
+ .filter((line) => line.includes("appserver-launcher.cjs") && line.includes(`--cwd ${cwd}`));
124
142
  } catch {
125
143
  return [];
126
144
  }