@zhushanwen/subagent-core 0.4.0 → 0.6.0

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 (309) hide show
  1. package/dist/{chunk-4KN4TTG7.js → chunk-43ONBFZX.js} +1 -1
  2. package/dist/{chunk-X7SZ5HLQ.js → chunk-V3VHZ2VX.js} +20 -27
  3. package/dist/execution/engine/engines/zcode/constants.cjs +29 -41
  4. package/dist/execution/engine/engines/zcode/constants.d.cts +65 -53
  5. package/dist/execution/engine/engines/zcode/constants.d.ts +65 -53
  6. package/dist/execution/engine/engines/zcode/constants.js +17 -27
  7. package/dist/execution/engine/engines/zcode/reader.d.cts +2 -1
  8. package/dist/execution/engine/engines/zcode/reader.d.ts +2 -1
  9. package/dist/execution/engine/engines/zcode/reader.js +2 -2
  10. package/dist/index.cjs +17100 -14082
  11. package/dist/index.d.cts +5336 -4033
  12. package/dist/index.d.ts +5336 -4033
  13. package/dist/index.js +17020 -14055
  14. package/dist/{types-DpUO16pj.d.cts → types-C3fE3R9x.d.cts} +280 -112
  15. package/dist/{types-DpUO16pj.d.ts → types-C3fE3R9x.d.ts} +280 -112
  16. package/dist.bundle/index.cjs +34933 -0
  17. package/package.json +3 -3
  18. package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
  19. package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
  20. package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
  21. package/src/__tests__/m2-append-content-probe.test.ts +0 -1
  22. package/src/__tests__/manifest-store.test.ts +10 -9
  23. package/src/__tests__/record-store-cache.test.ts +0 -2
  24. package/src/__tests__/record-store-index.test.ts +1 -2
  25. package/src/__tests__/review-fix-loop-script.test.ts +4 -2
  26. package/src/__tests__/review-fix-loop-utils.test.ts +10 -10
  27. package/src/__tests__/robustness-low-batch1.test.ts +6 -5
  28. package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
  29. package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
  30. package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
  31. package/src/__tests__/session-runner.test.ts +1 -1
  32. package/src/core/__tests__/host-services.test.ts +2 -2
  33. package/src/core/__tests__/logger.test.ts +1 -1
  34. package/src/core/error-message.ts +9 -0
  35. package/src/core/host-services.ts +21 -5
  36. package/src/core/notify-ports.ts +18 -5
  37. package/src/execution/__tests__/agent-profile.test.ts +4 -4
  38. package/src/execution/__tests__/agent-registry.test.ts +370 -0
  39. package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
  40. package/src/execution/__tests__/agents-assembly.test.ts +2 -2
  41. package/src/execution/__tests__/alive-store.test.ts +1 -1
  42. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
  43. package/src/execution/__tests__/chat-engine-routing.test.ts +68 -33
  44. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +4 -4
  45. package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
  46. package/src/execution/__tests__/collect-budget.test.ts +291 -0
  47. package/src/execution/__tests__/collect-coordinator-service.test.ts +327 -0
  48. package/src/execution/__tests__/collect-coordinator.test.ts +371 -0
  49. package/src/execution/__tests__/collect-mixed-dispatch.test.ts +262 -0
  50. package/src/execution/__tests__/config-collect-sync.test.ts +120 -0
  51. package/src/execution/__tests__/config.test.ts +1 -1
  52. package/src/execution/__tests__/delivery-methods.test.ts +75 -62
  53. package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
  54. package/src/execution/__tests__/descendant-sweep.test.ts +6 -6
  55. package/src/execution/__tests__/dialog-queue.test.ts +2 -2
  56. package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
  57. package/src/execution/__tests__/epipe-fallback.test.ts +29 -24
  58. package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
  59. package/src/execution/__tests__/execute-nesting.test.ts +34 -188
  60. package/src/execution/__tests__/execution-record.test.ts +217 -60
  61. package/src/execution/__tests__/execution-runtime-face.test.ts +5 -5
  62. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +4 -4
  63. package/src/execution/__tests__/finalize-record.test.ts +173 -17
  64. package/src/execution/__tests__/finalized-marker.test.ts +1 -1
  65. package/src/execution/__tests__/gc-timer.test.ts +56 -3
  66. package/src/execution/__tests__/get-record-for-action-restart.test.ts +12 -12
  67. package/src/execution/__tests__/get-state-handshake.test.ts +1 -1
  68. package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
  69. package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
  70. package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
  71. package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
  72. package/src/execution/__tests__/keep-alive-no-progress.test.ts +50 -148
  73. package/src/execution/__tests__/kill-all-escalation.test.ts +2 -2
  74. package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
  75. package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
  76. package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +1 -1
  77. package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +1 -1
  78. package/src/execution/__tests__/model-resolver.test.ts +2 -2
  79. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
  80. package/src/execution/__tests__/nested-visibility.test.ts +2 -0
  81. package/src/execution/__tests__/notify-batch.test.ts +500 -0
  82. package/src/execution/__tests__/notify-ledger.test.ts +1000 -18
  83. package/src/execution/__tests__/output-collector.test.ts +117 -6
  84. package/src/execution/__tests__/pi-invocation.test.ts +36 -4
  85. package/src/execution/__tests__/record-entry-collect.test.ts +102 -0
  86. package/src/execution/__tests__/record-store.test.ts +10 -9
  87. package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
  88. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
  89. package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
  90. package/src/execution/__tests__/relay-env.test.ts +12 -1
  91. package/src/execution/__tests__/rpc-mode.test.ts +2 -2
  92. package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
  93. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +15 -9
  94. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +4 -4
  95. package/src/execution/__tests__/run-spawn-edges.test.ts +17 -15
  96. package/src/execution/__tests__/run-spawn-integration.test.ts +2 -2
  97. package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
  98. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
  99. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +4 -4
  100. package/src/execution/__tests__/service-kill-escalation.test.ts +7 -5
  101. package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
  102. package/src/execution/__tests__/session-file-gc.test.ts +36 -1
  103. package/src/execution/__tests__/session-pending.test.ts +257 -14
  104. package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
  105. package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +1 -1
  106. package/src/execution/__tests__/session-runner-close-prune.test.ts +2 -2
  107. package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
  108. package/src/execution/__tests__/session-runner-epipe.test.ts +3 -3
  109. package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +5 -4
  110. package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
  111. package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
  112. package/src/execution/__tests__/settled-watchdog.test.ts +282 -47
  113. package/src/execution/__tests__/spawn-args.test.ts +11 -10
  114. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
  115. package/src/execution/__tests__/spawn-event-adapter.test.ts +3 -3
  116. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
  117. package/src/execution/__tests__/spawned-children.test.ts +2 -1
  118. package/src/execution/__tests__/start-collect-guard.test.ts +255 -0
  119. package/src/execution/__tests__/start-sync-model-guard.test.ts +5 -5
  120. package/src/execution/__tests__/stdin-writer.test.ts +6 -4
  121. package/src/execution/__tests__/stream-sink-retirement.test.ts +6 -6
  122. package/src/execution/__tests__/subagent-actions-core.test.ts +48 -22
  123. package/src/execution/__tests__/subagent-service-message-close.test.ts +29 -26
  124. package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +21 -8
  125. package/src/execution/__tests__/subagent-service-notify-gate.test.ts +27 -22
  126. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +30 -29
  127. package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +45 -20
  128. package/src/execution/__tests__/subagent-service.test.ts +37 -30
  129. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
  130. package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
  131. package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
  132. package/src/execution/__tests__/sync-collect-recovery.test.ts +1117 -0
  133. package/src/execution/__tests__/temp-prompt.test.ts +1 -1
  134. package/src/execution/__tests__/timeout-integration.test.ts +6 -5
  135. package/src/execution/__tests__/tombstone-store.test.ts +1 -1
  136. package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
  137. package/src/execution/__tests__/turn-limiter.test.ts +1 -1
  138. package/src/execution/__tests__/ui-request-handler-factory.test.ts +12 -6
  139. package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
  140. package/src/execution/__tests__/ui-request-queue.test.ts +142 -2
  141. package/src/execution/__tests__/worktree-git-ops.test.ts +1 -1
  142. package/src/execution/__tests__/worktree-manager.test.ts +14 -5
  143. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
  144. package/src/execution/__tests__/worktree-reconcile-aging.test.ts +2 -2
  145. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +1 -1
  146. package/src/execution/__tests__/worktree-registry.test.ts +1 -1
  147. package/src/execution/agent-registry.ts +74 -30
  148. package/src/execution/agent-result-mapper.ts +3 -0
  149. package/src/execution/cold-resurrect.ts +199 -0
  150. package/src/execution/collect-coordinator.ts +200 -0
  151. package/src/execution/config.ts +77 -5
  152. package/src/execution/engine/__tests__/common/capability-gate.test.ts +91 -0
  153. package/src/execution/engine/__tests__/common/data-dir.test.ts +1 -1
  154. package/src/execution/engine/__tests__/common/event-journal.test.ts +1 -1
  155. package/src/execution/engine/__tests__/common/journal-wiring.test.ts +84 -0
  156. package/src/execution/engine/__tests__/common/kill-chain.test.ts +34 -7
  157. package/src/execution/engine/__tests__/common/persona-router.test.ts +4 -5
  158. package/src/execution/engine/__tests__/common/pool-manager.test.ts +213 -53
  159. package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +149 -0
  160. package/src/execution/engine/__tests__/common/session-view-service.test.ts +499 -0
  161. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +22 -112
  162. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +15 -28
  163. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +1 -1
  164. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +12 -12
  165. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +2 -2
  166. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +21 -82
  167. package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +4 -7
  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 +4 -2
  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/engines/pi/__tests__/pi-engine.test.ts +174 -28
  181. package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
  182. package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
  183. package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +1 -1
  184. package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
  185. package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
  186. package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
  187. package/src/execution/engine/engines/pi/reader.ts +11 -0
  188. package/src/execution/engine/engines/pi/registration.ts +4 -2
  189. package/src/execution/{session-runner.ts → engine/engines/pi/session-runner.ts} +617 -412
  190. package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
  191. package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
  192. package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
  193. package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
  194. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +54 -27
  195. package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
  196. package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +13 -12
  197. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
  198. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
  199. package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
  200. package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
  201. package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +20 -8
  202. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +77 -110
  203. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +26 -320
  204. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
  205. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
  206. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
  207. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
  208. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +48 -148
  209. package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
  210. package/src/execution/engine/engines/zcode/connection.ts +24 -11
  211. package/src/execution/engine/engines/zcode/constants.ts +75 -71
  212. package/src/execution/engine/engines/zcode/golden-sample.ts +8 -46
  213. package/src/execution/engine/engines/zcode/parser.ts +12 -346
  214. package/src/execution/engine/engines/zcode/preparer.ts +12 -143
  215. package/src/execution/engine/engines/zcode/session-channel.ts +351 -39
  216. package/src/execution/engine/engines/zcode/zcode-engine.ts +665 -760
  217. package/src/execution/engine/host-task-spec.ts +32 -36
  218. package/src/execution/engine/model-validation.ts +177 -0
  219. package/src/execution/engine/port.ts +24 -6
  220. package/src/execution/engine/routing.ts +75 -1
  221. package/src/execution/engine/types.ts +30 -103
  222. package/src/execution/execution-record.ts +229 -144
  223. package/src/execution/finalize-record.ts +141 -99
  224. package/src/execution/idle-gc.ts +28 -0
  225. package/src/execution/lifecycle-predicates.ts +1 -1
  226. package/src/execution/notifier.ts +234 -25
  227. package/src/execution/notify-host.ts +232 -0
  228. package/src/execution/record-entry.ts +16 -0
  229. package/src/execution/record-store.ts +280 -103
  230. package/src/execution/round-settlement.ts +93 -0
  231. package/src/execution/session-file-gc.ts +96 -62
  232. package/src/execution/session-reconstructor.ts +256 -143
  233. package/src/execution/sessions-index.ts +117 -47
  234. package/src/execution/settled-watchdog.ts +264 -52
  235. package/src/execution/subagent-actions-core.ts +84 -28
  236. package/src/execution/subagent-service.ts +1225 -964
  237. package/src/execution/subprocess-agent-runner.ts +144 -97
  238. package/src/execution/sync-rebuild.ts +87 -0
  239. package/src/execution/types.ts +72 -0
  240. package/src/execution/ui-request-handler-factory.ts +102 -74
  241. package/src/execution/ui-request-queue.ts +50 -19
  242. package/src/index.ts +442 -316
  243. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +1 -1
  244. package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
  245. package/src/orchestration/__tests__/args-validator.test.ts +14 -0
  246. package/src/orchestration/__tests__/config-loader.test.ts +1 -1
  247. package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +1 -1
  248. package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +11 -9
  249. package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
  250. package/src/orchestration/__tests__/file-run-store-prune.test.ts +1 -1
  251. package/src/orchestration/__tests__/file-run-store-throttle.test.ts +1 -1
  252. package/src/orchestration/__tests__/file-run-store.test.ts +7 -6
  253. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +2 -2
  254. package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +1 -1
  255. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
  256. package/src/orchestration/__tests__/lifecycle.test.ts +7 -5
  257. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
  258. package/src/orchestration/__tests__/review-fix-loop-scriptpath-failfast.test.ts +1 -1
  259. package/src/orchestration/__tests__/run-snapshot.test.ts +8 -5
  260. package/src/orchestration/__tests__/script-generate.test.ts +5 -5
  261. package/src/orchestration/__tests__/script-lint.test.ts +17 -0
  262. package/src/orchestration/__tests__/skill-discovery.test.ts +2 -2
  263. package/src/orchestration/__tests__/test-mocks.ts +2 -0
  264. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +7 -6
  265. package/src/orchestration/__tests__/worker-message-pump-finalize-run.test.ts +229 -0
  266. package/src/orchestration/__tests__/{error-recovery-handlers.test.ts → worker-message-pump-handlers.test.ts} +27 -19
  267. package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
  268. package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
  269. package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
  270. package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +1 -1
  271. package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
  272. package/src/orchestration/__tests__/workflow-files.test.ts +10 -10
  273. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
  274. package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +1 -1
  275. package/src/orchestration/agent-opts-resolver.ts +1 -1
  276. package/src/orchestration/args-validator.ts +53 -31
  277. package/src/orchestration/execute-agent-call.ts +19 -73
  278. package/src/orchestration/launcher.ts +128 -81
  279. package/src/orchestration/lifecycle.ts +43 -45
  280. package/src/orchestration/models/ports.ts +4 -4
  281. package/src/orchestration/models/run-runtime.ts +2 -2
  282. package/src/orchestration/models/trace.ts +1 -1
  283. package/src/orchestration/models/types.ts +111 -22
  284. package/src/orchestration/models/workflow-run.ts +1 -1
  285. package/src/orchestration/script-lint.ts +91 -58
  286. package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +157 -150
  287. package/src/shared/__tests__/atomic-write.test.ts +1 -1
  288. package/src/shared/__tests__/meta-parser.test.ts +151 -0
  289. package/src/shared/__tests__/resource-discovery-host-roots.test.ts +5 -5
  290. package/src/shared/__tests__/resource-discovery.test.ts +258 -215
  291. package/src/shared/atomic-write.ts +12 -9
  292. package/src/shared/meta-parser.ts +158 -84
  293. package/src/shared/model-ref.ts +15 -2
  294. package/src/shared/resource-discovery.ts +9 -183
  295. package/src/shared/schema-jsonify.ts +1 -1
  296. package/workflows/review-fix-loop-utils.cjs +151 -89
  297. package/workflows/review-fix-loop-utils.d.cts +287 -0
  298. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  299. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  300. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  301. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  302. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  303. package/src/execution/engine/engines/zcode/__tests__/preparer-appserver.test.ts +0 -387
  304. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -710
  305. package/src/execution/engine/engines/zcode/appserver-home.ts +0 -442
  306. package/src/execution/engine/engines/zcode/appserver-probe.ts +0 -141
  307. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  308. package/src/execution/execute-options-mapper.ts +0 -115
  309. 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,145 +16,23 @@ 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
19
  import type { AgentEvent } from "../../../types.ts";
20
- import { ZCODE_APPSERVER_POOL_KEY } from "../constants.ts";
20
+ import { ZCODE_SHARED_POOL_KEY } from "../constants.ts";
21
21
  import { ZcodeEngine } from "../zcode-engine.ts";
22
22
  import { assertAgentEventInvariants } from "../../../__tests__/conformance/agent-event-invariants.ts";
23
23
 
24
24
  const LIVE = process.env["ENGINE_CONFORMANCE_LIVE"] === "1";
25
25
  const E2E_MODEL = process.env["ZCODE_E2E_MODEL"] ?? "e512d53e-0bfc-4915-9081-860d4aa13cd0/mimo-v2.5-pro";
26
- const DATA_ROOT = path.join(fs.realpathSync(os.tmpdir()), "zcode-p3-e2e-data");
27
- 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");
28
28
 
29
- describe.skipIf(!LIVE)("ZcodeEngine 端到端真机(真实 LLM 调用)", () => {
30
- let engine: ZcodeEngine;
31
-
32
- beforeAll(() => {
33
- fs.mkdirSync(WORK_CWD, { recursive: true });
34
- engine = new ZcodeEngine({
35
- engineDataDir: () => DATA_ROOT,
36
- // [R4] 钉扎 spawn 单轮(本门原为 spawn 链路实录;app-server 常驻真机门由 R6
37
- // live gate 改写接入——两模式各自的真机覆盖不合并)
38
- processEnv: { ...process.env, XYZ_ZCODE_MODE: "spawn" },
39
- });
40
- });
41
-
42
- afterAll(() => {
43
- // 用完清理:池数据 + 任务 cwd(保持 /tmp 干净,实录/验证不留残留)
44
- for (const dir of [DATA_ROOT, WORK_CWD]) {
45
- try {
46
- fs.rmSync(dir, { recursive: true, force: true });
47
- } catch {
48
- // 尽力清理
49
- }
50
- }
51
- });
52
-
53
- it("probe:二进制/版本/golden 三项全过", async () => {
54
- const report = await engine.probe();
55
- expect(report.ok).toBe(true);
56
- expect(report.engineVersion).toMatch(/^0\.\d+\.\d+$/);
57
- }, 60_000);
58
-
59
- it("run:schema 任务全链成功(隔离 HOME 新 session + outcome + read①级)", async () => {
60
- const { handle, outcome } = await engine.run(
61
- {
62
- task: 'Verify this arithmetic check: 2 + 2 = 4. If it is correct the verdict must be "ok", otherwise "bad".',
63
- slug: "e2e-schema",
64
- model: E2E_MODEL,
65
- cwd: WORK_CWD,
66
- schema: {
67
- type: "object",
68
- properties: { verdict: { type: "string", enum: ["ok", "bad"] } },
69
- required: ["verdict"],
70
- additionalProperties: false,
71
- },
72
- },
73
- { taskId: "sa-live-schema", poolKey: "" },
74
- );
75
-
76
- // outcome 正确
77
- expect(outcome.error).toBeUndefined();
78
- expect(outcome.exitCode).toBe(0);
79
- expect(outcome.content).toContain('"verdict"');
80
- expect(outcome.usage).toBeDefined();
81
- expect(outcome.usage!.input).toBeGreaterThan(0);
82
- expect(outcome.sessionId).toMatch(/^sess_/);
83
- // schema 仿真(D4 emulated 侧):公共层三级容错提取 + ajv 校验产出 parsedOutput
84
- expect(outcome.parsedOutput).toEqual({ verdict: "ok" });
85
-
86
- // 隔离 HOME 有新 session(db.sqlite 落池内,非真实 ~/.zcode)——路径经 resolvePoolDir
87
- // SSOT(poolKey 里的 '.' 会被 sanitizeSeg 编码为 '-',手工 join 会拼错目录)
88
- const dbPath = path.join(resolvePoolDir(DATA_ROOT, "zcode", handle.data.poolKey), ".zcode", "cli", "db", "db.sqlite");
89
- expect(fs.existsSync(dbPath)).toBe(true);
90
- expect(fs.statSync(dbPath).size).toBeGreaterThan(0);
91
-
92
- // read(handle) 第①级可读:turns 非空(验收 5 的 read 断言)
93
- const view = await engine.read(handle);
94
- expect(view.source).toBe("native");
95
- expect(view.sessionId).toBe(outcome.sessionId);
96
- expect(view.turns.length).toBeGreaterThanOrEqual(1);
97
- expect(view.turns[0]!.text).toContain("verdict");
98
- }, 300_000);
99
-
100
- it("abort:长任务中途取消 → 杀链合成终态、无僵尸进程", async () => {
101
- const controller = new AbortController();
102
- const runPromise = engine.run(
103
- {
104
- task:
105
- "Write an extremely detailed 5000-word technical essay about distributed systems consistency models. Do not stop early.",
106
- slug: "e2e-abort",
107
- model: E2E_MODEL,
108
- cwd: WORK_CWD,
109
- },
110
- { taskId: "sa-live-abort", poolKey: "", signal: controller.signal },
111
- );
112
- // 等 spawn 发生(prompt 已进 argv),再中途 abort
113
- await new Promise((r) => setTimeout(r, 4_000));
114
- controller.abort();
115
- const { outcome } = await runPromise;
116
-
117
- expect(outcome.exitCode).toBeNull();
118
- expect(outcome.error).toContain("SIGTERM");
119
- // 无僵尸进程:--cwd 指向本测试专用 tmp 目录的 zcode 进程应已消失
120
- const leftovers = listZcodeProcessesForCwd(WORK_CWD);
121
- expect(leftovers).toEqual([]);
122
- }, 120_000);
123
- });
124
-
125
- /** 扫系统进程表:--cwd 锚定到指定目录的 zcode CLI 进程(僵尸检测)。 */
126
- function listZcodeProcessesForCwd(cwd: string): string[] {
127
- try {
128
- const out = execFileSync("ps", ["-eo", "command"], { encoding: "utf8" });
129
- return out
130
- .split("\n")
131
- .filter((line) => line.includes("zcode.cjs") && line.includes(`--cwd ${cwd}`));
132
- } catch {
133
- return [];
134
- }
135
- }
136
-
137
- // ============================================================
138
- // [R6] app-server 常驻真机门(RA1/RA2/RA4 的本仓可测形态):真实 zcode.cjs +
139
- // 真实凭据 + 真实 app-server 进程,XYZ_ZCODE_MODE=appserver 定向(不探不降)。
140
- // 与上方 spawn 门分立(两模式各自的真机覆盖不合并);跨仓 live gate(RA8 live /
141
- // zsw 真机)另由跨仓段承载。skip 条件与 spawn 门一致(ENGINE_CONFORMANCE_LIVE)。
142
- // ============================================================
143
-
144
- const AS_DATA_ROOT = path.join(fs.realpathSync(os.tmpdir()), "zcode-r6-appserver-e2e-data");
145
- const AS_WORK_CWD = path.join(fs.realpathSync(os.tmpdir()), "zcode-r6-appserver-e2e-cwd");
146
-
147
- describe.skipIf(!LIVE)("ZcodeEngine 端到端真机(app-server 常驻,[R6] live gate 改写)", () => {
29
+ describe.skipIf(!LIVE)("ZcodeEngine 端到端真机(app-server 常驻,共享宿主 HOME)", () => {
148
30
  let engine: ZcodeEngine;
149
31
 
150
32
  beforeAll(() => {
151
33
  fs.mkdirSync(AS_WORK_CWD, { recursive: true });
152
34
  engine = new ZcodeEngine({
153
35
  engineDataDir: () => AS_DATA_ROOT,
154
- // 定向 appserver(D2①):不探不降——常驻路径本体;缺省路径门控真机另由
155
- // RA5-②③(跨仓段)承载
156
- processEnv: { ...process.env, XYZ_ZCODE_MODE: "appserver" },
157
36
  });
158
37
  });
159
38
 
@@ -162,19 +41,25 @@ describe.skipIf(!LIVE)("ZcodeEngine 端到端真机(app-server 常驻,[R6] l
162
41
  await engine.dispose().catch(() => undefined);
163
42
  for (const dir of [AS_DATA_ROOT, AS_WORK_CWD]) {
164
43
  try {
165
- fs.rmSync(dir, { recursive: true, force: true });
44
+ fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
166
45
  } catch {
167
46
  // 尽力清理
168
47
  }
169
48
  }
170
49
  });
171
50
 
172
- it("run:常驻通道全链(RA2——stream 事件流出 + read①级 native + poolKey 锚定 home-appserver)", async () => {
51
+ it("probe:二进制/版本两项全过", async () => {
52
+ const report = await engine.probe();
53
+ expect(report.ok).toBe(true);
54
+ expect(report.engineVersion).toMatch(/^0\.\d+\.\d+$/);
55
+ }, 60_000);
56
+
57
+ it("run:常驻通道全链(stream 事件流出 + read①级 native + poolKey 锚定 'shared' + 会话落宿主 db)", async () => {
173
58
  const events: AgentEvent[] = [];
174
59
  const { handle, outcome } = await engine.run(
175
60
  {
176
- task: 'Verify this arithmetic check: 2 + 2 = 4. If it is correct the verdict must be "ok", otherwise "bad".',
177
- slug: "e2e-appserver",
61
+ prompt: 'Verify this arithmetic check: 2 + 2 = 4. If it is correct the verdict must be "ok", otherwise "bad".',
62
+ description: "e2e-appserver",
178
63
  model: E2E_MODEL,
179
64
  cwd: AS_WORK_CWD,
180
65
  schema: {
@@ -194,27 +79,29 @@ describe.skipIf(!LIVE)("ZcodeEngine 端到端真机(app-server 常驻,[R6] l
194
79
  expect(outcome.parsedOutput).toEqual({ verdict: "ok" });
195
80
  expect(outcome.usage?.input).toBeGreaterThan(0);
196
81
 
197
- // C3 stream 口径(RA2-①断言面):text_delta 实时流出(非终态一次性)+ 不变量五条
198
- // (3a 拼接 == read 全文——content 来自 read 兜底/收尾帧,同源比对)
82
+ // C3 stream 口径:text_delta 实时流出(非终态一次性)+ 不变量五条
199
83
  expect(events.some((e) => e.type === "text_delta")).toBe(true);
200
84
  assertAgentEventInvariants(events, { granularity: "stream", content: outcome.content });
201
85
 
202
- // handle 锚定(RA2-②断言面):poolKey=home-appserver,①级读取钥匙随 handle
203
- expect(handle.data.poolKey).toBe(ZCODE_APPSERVER_POOL_KEY);
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);
204
91
 
205
- // read 第①级:SQLite 完整重建(非降级)
92
+ // read 第①级:SQLite 完整重建(非降级)——读的是宿主 db(共享 HOME 形态)
206
93
  const view = await engine.read(handle);
207
94
  expect(view.source).toBe("native");
208
95
  expect(view.turns.length).toBeGreaterThanOrEqual(1);
209
96
  }, 300_000);
210
97
 
211
- it("abort:长任务中途取消(RA4)→ stop 链合成终态 exitCode=null + 常驻进程不残留 + 后续任务可用", async () => {
98
+ it("abort:长任务中途取消 stop 链合成终态 exitCode=null + 常驻进程不残留 + 后续任务可用", async () => {
212
99
  const controller = new AbortController();
213
100
  const runPromise = engine.run(
214
101
  {
215
- task:
102
+ prompt:
216
103
  "Write an extremely detailed 5000-word technical essay about distributed systems consistency models. Do not stop early.",
217
- slug: "e2e-appserver-abort",
104
+ description: "e2e-appserver-abort",
218
105
  model: E2E_MODEL,
219
106
  cwd: AS_WORK_CWD,
220
107
  },
@@ -228,18 +115,31 @@ describe.skipIf(!LIVE)("ZcodeEngine 端到端真机(app-server 常驻,[R6] l
228
115
  expect(outcome.exitCode).toBeNull();
229
116
  expect(outcome.error).toContain("session/stop");
230
117
 
231
- // 无残留:常驻 HOME 锚定的 app-server 进程在 dispose 前应 ≤1(abort 不误杀共享
232
- // 进程;杀的是本仓 HOME,与其他 zcode 实例区分靠 --cwd HOME 路径)
233
- const homeDir = resolvePoolDir(AS_DATA_ROOT, "zcode", ZCODE_APPSERVER_POOL_KEY);
234
- const leftovers = listZcodeProcessesForCwd(homeDir);
118
+ // 无残留:引擎数据目录锚定的 app-server 进程在 dispose 前应 ≤1(abort 不误杀
119
+ // 共享进程;与其他 zcode 实例区分靠 --cwd 引擎数据目录路径)
120
+ const leftovers = listZcodeProcessesForCwd(AS_DATA_ROOT);
235
121
  expect(leftovers.length).toBeLessThanOrEqual(1);
236
122
 
237
123
  // 崩溃/中止后下一任务自动重建或复用(不变量 4 同路径)——abort 不污染常驻进程
238
124
  const second = await engine.run(
239
- { task: "Reply with the single word: ok", slug: "e2e-appserver-after-abort", model: E2E_MODEL, cwd: AS_WORK_CWD },
125
+ { prompt: "Reply with the single word: ok", description: "e2e-appserver-after-abort", model: E2E_MODEL, cwd: AS_WORK_CWD },
240
126
  { taskId: "sa-live-appserver-after-abort", poolKey: "" },
241
127
  );
242
128
  expect(second.outcome.error).toBeUndefined();
243
129
  expect(second.outcome.content.trim().length).toBeGreaterThan(0);
244
130
  }, 300_000);
245
131
  });
132
+
133
+ /** 扫系统进程表:--cwd 锚定到指定目录的 app-server 常驻进程(僵尸检测)。spawn 形态
134
+ * 是 `node .../engines/zcode/appserver-launcher.cjs app-server --cwd <dir>`——zcode.cjs
135
+ * 经 launcher 的 import() 动态加载,不出现在 cmdline。 */
136
+ function listZcodeProcessesForCwd(cwd: string): string[] {
137
+ try {
138
+ const out = execFileSync("ps", ["-eo", "command"], { encoding: "utf8" });
139
+ return out
140
+ .split("\n")
141
+ .filter((line) => line.includes("appserver-launcher.cjs") && line.includes(`--cwd ${cwd}`));
142
+ } catch {
143
+ return [];
144
+ }
145
+ }