@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
@@ -5,9 +5,12 @@
5
5
  // 收敛到 killRecordChildWithEscalation(spy 断言调用点与参数);
6
6
  // - T2⑥/PS-1:disposeAllRecords 补三回收面(controller.abort + kill + disarm idle timer
7
7
  // + disarm settled watchdog);
8
- // - T2③/LC-1:deliverMessage 热路径 armSettledWatchdog(挂载 + 到期 onTimeout 处置:
9
- // kill + 失败终态化 + error 含 'settled watchdog' 标记与恢复指引);
10
- // - T2⑧/PS-3:deliverMessage EPIPE 失败 re-arm idle timer(进程不再裸奔)。
8
+ // - T2③/LC-1 + D9:热路径投递 armMidRoundNoProgress(挂载点 D2 下沉后在编排层
9
+ // deliverChatMessage interact 返回点;挂载中段无进展检测 + 到期 onMidTimeout/
10
+ // onSettleTimeout 处置:kill + 失败终态化 + error 'settled watchdog' 标记与恢复
11
+ // 指引;agent_end 交棒收尾段的接线在 session-runner stdout pump,两路径共用);
12
+ // - T2⑧/PS-3:非 EPIPE 热路径写失败 re-arm idle timer(进程不再裸奔;挂载位 D2
13
+ // 下沉后在 PiEngine.deliverPrompt 的非 EPIPE catch——编排层无法区分错误类别)。
11
14
  //
12
15
  // mock 形态沿用 subagent-service-message-close.test.ts(真实 SubagentService + ServiceInternals
13
16
  // cast 暴露 store + mock session-runner/stdin-writer/logger)。
@@ -24,8 +27,8 @@ const { loggerMock } = vi.hoisted(() => ({
24
27
  vi.mock("../../core/logger.ts", () => ({ getLogger: () => loggerMock }));
25
28
 
26
29
  // killRecordChildWithEscalation 换 spy(收敛调用点断言);spawnedChildren 用真 Map
27
- //(deliverMessage 热路径判定 / EPIPE 兜底按值删除的消费者);getChildByRecord 从同
28
- // Map 查(mock 工厂与测试共享同一实例)。
30
+ //(热路径投递判定 / EPIPE 兜底按值删除的消费者);getChildByRecord 从同一 Map 查
31
+ //(mock 工厂与测试共享同一实例)。D2 后模块物理下沉 engines/pi/(mock 路径随迁)。
29
32
  const { killChildSpy, spawnedMap, getChildByRecordMock } = vi.hoisted(() => {
30
33
  const map = new Map<string, unknown>();
31
34
  return {
@@ -34,7 +37,7 @@ const { killChildSpy, spawnedMap, getChildByRecordMock } = vi.hoisted(() => {
34
37
  getChildByRecordMock: vi.fn((recordId: string) => map.get(recordId)),
35
38
  };
36
39
  });
37
- vi.mock("../session-runner.ts", () => ({
40
+ vi.mock("../engine/engines/pi/session-runner.ts", () => ({
38
41
  runSpawn: vi.fn(),
39
42
  killAllSpawnedChildren: vi.fn(),
40
43
  getChildByRecord: getChildByRecordMock,
@@ -45,7 +48,7 @@ vi.mock("../session-runner.ts", () => ({
45
48
 
46
49
  // sendPromptCommand 换 spy(控制热路径写成功 / 抛非 EPIPE 错误)。
47
50
  const { sendPromptCommandMock } = vi.hoisted(() => ({ sendPromptCommandMock: vi.fn() }));
48
- vi.mock("../stdin-writer.ts", () => ({
51
+ vi.mock("../engine/engines/pi/stdin-writer.ts", () => ({
49
52
  sendPromptCommand: sendPromptCommandMock,
50
53
  clearEpipeFailure: vi.fn(),
51
54
  recordEpipeFailure: vi.fn(() => 1),
@@ -59,7 +62,7 @@ import { ModelConfigService } from "../model-config-service.ts";
59
62
  import type { RecordStore } from "../record-store.ts";
60
63
  import { SubagentService } from "../subagent-service.ts";
61
64
  import type { PiLike } from "../subagent-service.ts";
62
- import { armSettledWatchdog, hasSettledWatchdog, SETTLED_WATCHDOG_TIMEOUT_MS, _resetSettledWatchdogsForTest } from "../settled-watchdog.ts";
65
+ import { armSettledWatchdog, hasSettledWatchdog, SETTLED_MID_ROUND_NO_PROGRESS_MS, _resetSettledWatchdogsForTest } from "../settled-watchdog.ts";
63
66
  import { armIdleTimer, hasIdleTimer, _resetLifecycleState } from "../lifecycle-manager.ts";
64
67
  import type { ExecutionRecord } from "../types.ts";
65
68
 
@@ -108,7 +111,7 @@ type MockPi = ReturnType<typeof makePi>;
108
111
 
109
112
  function setup(): { agentDir: string; service: SubagentService; store: RecordStore; pi: MockPi } {
110
113
  const agentDir = makeTmpAgentDir();
111
- const modelService = new ModelConfigService({ agentDir });
114
+ const modelService = new ModelConfigService({ agentDir, cwd: agentDir });
112
115
  const service = new SubagentService({ cwd: agentDir, modelService });
113
116
  const pi = makePi();
114
117
  service.initSession({ pi, sessionId: "root-session" });
@@ -121,6 +124,26 @@ function privateFn<K extends string>(service: SubagentService, key: K): (...args
121
124
  return (service as unknown as Record<string, (...args: never[]) => unknown>)[key];
122
125
  }
123
126
 
127
+ /**
128
+ * message 投递入口(D2 后形态:编排层私有 deliverChatMessage → PiEngine.interactRecord
129
+ * → deliverPrompt;旧直调形态 deliverMessage 已随协议知识下沉删除)。
130
+ */
131
+ async function deliverChat(
132
+ service: SubagentService,
133
+ record: ExecutionRecord,
134
+ text: string,
135
+ interrupt: boolean,
136
+ ): Promise<void> {
137
+ return (
138
+ privateFn(service, "deliverChatMessage") as (
139
+ this: SubagentService,
140
+ r: ExecutionRecord,
141
+ t: string,
142
+ i: boolean,
143
+ ) => Promise<void>
144
+ ).call(service, record, text, interrupt);
145
+ }
146
+
124
147
  describe("T2④ service-side kill convergence", () => {
125
148
  let agentDir: string;
126
149
  let service: SubagentService;
@@ -138,7 +161,7 @@ describe("T2④ service-side kill convergence", () => {
138
161
  _resetLifecycleState();
139
162
  _resetSettledWatchdogsForTest();
140
163
  spawnedMap.clear();
141
- fs.rmSync(agentDir, { recursive: true, force: true });
164
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
142
165
  });
143
166
 
144
167
  it("cancelBackground (via cancel) routes through killRecordChildWithEscalation", async () => {
@@ -156,7 +179,7 @@ describe("T2④ service-side kill convergence", () => {
156
179
  spawnedMap.set(record.id, new FakeChild());
157
180
  armIdleTimer(record.id, () => {}); // Path A:idle timer armed(进程保活)
158
181
  armSettledWatchdog(record.id, () => {});
159
- await service.closeSubagent(record, false);
182
+ await service["closeSubagent"](record, false);
160
183
  expect(killChildSpy).toHaveBeenCalledWith(record.id, "closeChatIdle");
161
184
  expect(hasIdleTimer(record.id)).toBe(false);
162
185
  expect(hasSettledWatchdog(record.id)).toBe(false);
@@ -223,28 +246,30 @@ describe("T2③ hot-path settled watchdog", () => {
223
246
  _resetLifecycleState();
224
247
  _resetSettledWatchdogsForTest();
225
248
  spawnedMap.clear();
226
- fs.rmSync(agentDir, { recursive: true, force: true });
249
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
227
250
  });
228
251
 
229
252
  it("arms the settled watchdog after a successful hot-path prompt", async () => {
230
253
  const record = makeRecord({ id: "sa-hot-arm" });
231
254
  store.register(record);
232
255
  spawnedMap.set(record.id, new FakeChild());
233
- await service.deliverMessage(record, "hello", false);
256
+ await deliverChat(service, record, "hello", false);
234
257
  expect(sendPromptCommandMock).toHaveBeenCalledTimes(1);
235
258
  expect(hasSettledWatchdog(record.id)).toBe(true);
236
259
  });
237
260
 
238
- it("onTimeout: kills the child, fails the round, error carries 'settled watchdog' marker and recovery hint", async () => {
261
+ it("onMidTimeout: kills the child, fails the round, error carries 'settled watchdog' marker and recovery hint", async () => {
239
262
  // fake timers 必须先于 arm 生效(useFakeTimers 不接管已存在的真实 timer)
240
263
  vi.useFakeTimers({ toFake: ["setTimeout", "clearTimeout"] });
241
264
  const record = makeRecord({ id: "sa-hot-timeout" });
242
265
  store.register(record);
243
266
  spawnedMap.set(record.id, new FakeChild());
244
- await service.deliverMessage(record, "hello", false);
267
+ await deliverChat(service, record, "hello", false);
245
268
  expect(hasSettledWatchdog(record.id)).toBe(true);
246
269
 
247
- await vi.advanceTimersByTimeAsync(SETTLED_WATCHDOG_TIMEOUT_MS + 1);
270
+ // [D9 两段式] 热路径 prompt 发出后挂中段:静默满中段窗长触发(本测试 mock 了
271
+ // session-runner,无 stdout pump 驱动事件刷新/交棒,中段静默形态直达)
272
+ await vi.advanceTimersByTimeAsync(SETTLED_MID_ROUND_NO_PROGRESS_MS + 1);
248
273
 
249
274
  // kill 收敛入口被触发(onTimeout 第一步)
250
275
  expect(killChildSpy).toHaveBeenCalledWith(record.id, "settled watchdog (hot path)");
@@ -278,7 +303,7 @@ describe("T2⑧ non-EPIPE hot-path failure re-arms idle timer", () => {
278
303
  _resetLifecycleState();
279
304
  _resetSettledWatchdogsForTest();
280
305
  spawnedMap.clear();
281
- fs.rmSync(agentDir, { recursive: true, force: true });
306
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
282
307
  });
283
308
 
284
309
  it("re-arms the idle timer (default duration) and rethrows on non-EPIPE write failure", async () => {
@@ -289,7 +314,7 @@ describe("T2⑧ non-EPIPE hot-path failure re-arms idle timer", () => {
289
314
  throw new Error("write after end: ERR_STREAM_DESTROYED");
290
315
  });
291
316
 
292
- await expect(service.deliverMessage(record, "hello", false)).rejects.toThrow(/ERR_STREAM_DESTROYED/);
317
+ await expect(deliverChat(service, record, "hello", false)).rejects.toThrow(/ERR_STREAM_DESTROYED/);
293
318
 
294
319
  // 防泄漏前提恢复:入口 disarm 过的 idle timer 被 re-arm(进程不再裸奔)
295
320
  expect(hasIdleTimer(record.id)).toBe(true);
@@ -303,14 +328,14 @@ describe("T2⑧ non-EPIPE hot-path failure re-arms idle timer", () => {
303
328
  const record = makeRecord({ id: "sa-nonpipe-bad" });
304
329
  // 直接注入非法值模拟「入口校验前已存在的 record」/ 回归形态:re-arm 首选值非法 →
305
330
  // 降级挂 DEFAULT(防御性兜底可见,不静默不挂)
306
- record.idleTimeoutMs = 3_000_000_000;
331
+ (record as { idleTimeoutMs: number }).idleTimeoutMs = 3_000_000_000;
307
332
  store.register(record);
308
333
  spawnedMap.set(record.id, new FakeChild());
309
334
  sendPromptCommandMock.mockImplementation(() => {
310
335
  throw new Error("ERR_STREAM_DESTROYED");
311
336
  });
312
337
 
313
- await expect(service.deliverMessage(record, "hello", false)).rejects.toThrow(/ERR_STREAM_DESTROYED/);
338
+ await expect(deliverChat(service, record, "hello", false)).rejects.toThrow(/ERR_STREAM_DESTROYED/);
314
339
  expect(hasIdleTimer(record.id)).toBe(true);
315
340
  });
316
341
  });
@@ -36,18 +36,18 @@ function makeTmpAgentDir(): string {
36
36
  }
37
37
 
38
38
  function makeModelService(agentDir: string): ModelConfigService {
39
- return new ModelConfigService({ agentDir });
39
+ return new ModelConfigService({ agentDir, cwd: agentDir });
40
40
  }
41
41
 
42
42
  function makePi(): PiLike & {
43
- appendEntry: ReturnType<typeof vi.fn>;
44
- events: { emit: ReturnType<typeof vi.fn> };
45
- sendMessage: ReturnType<typeof vi.fn>;
43
+ appendEntry: ReturnType<typeof vi.fn<(customType: string, data?: unknown) => void>>;
44
+ events: { emit: ReturnType<typeof vi.fn<(channel: string, data: unknown) => void>> };
45
+ sendMessage: ReturnType<typeof vi.fn<(message: Parameters<PiLike["sendMessage"]>[0], options?: Parameters<PiLike["sendMessage"]>[1]) => void>>;
46
46
  } {
47
47
  return {
48
- appendEntry: vi.fn(),
49
- events: { emit: vi.fn() },
50
- sendMessage: vi.fn(),
48
+ appendEntry: vi.fn((customType: string, data?: unknown) => {}),
49
+ events: { emit: vi.fn((channel: string, data: unknown) => {}) },
50
+ sendMessage: vi.fn(() => {}),
51
51
  };
52
52
  }
53
53
 
@@ -61,7 +61,7 @@ describe("SubagentService", () => {
61
61
  });
62
62
 
63
63
  afterEach(() => {
64
- fs.rmSync(agentDir, { recursive: true, force: true });
64
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
65
65
  });
66
66
 
67
67
  // ============================================================
@@ -75,7 +75,7 @@ describe("SubagentService", () => {
75
75
 
76
76
  it("未 initSession 时 findRecord/cancel 抛 'pi not injected'", () => {
77
77
  const service = new SubagentService({ cwd: agentDir, modelService });
78
- expect(() => service.findRecord("any")).toThrow(/pi not injected/);
78
+ expect(() => service.queries.findRecord("any")).toThrow(/pi not injected/);
79
79
  expect(() => service.cancel("any")).toThrow(/pi not injected/);
80
80
  });
81
81
 
@@ -83,7 +83,7 @@ describe("SubagentService", () => {
83
83
  const service = new SubagentService({ cwd: agentDir, modelService });
84
84
  service.initSession({ pi: makePi(), sessionId: "s1" });
85
85
  // findRecord 现在能过 assertReady,但 record 不存在 → 返回 undefined
86
- expect(service.findRecord("missing")).toBeUndefined();
86
+ expect(service.queries.findRecord("missing")).toBeUndefined();
87
87
  });
88
88
 
89
89
  it("dispose 后 findRecord 抛含 'disposed' 且带恢复指引", () => {
@@ -92,8 +92,8 @@ describe("SubagentService", () => {
92
92
  const service = new SubagentService({ cwd: agentDir, modelService });
93
93
  service.initSession({ pi: makePi(), sessionId: "s1" });
94
94
  service.dispose();
95
- expect(() => service.findRecord("any")).toThrow(/disposed/);
96
- expect(() => service.findRecord("any")).toThrow(/session ended|session_start|new session/i);
95
+ expect(() => service.queries.findRecord("any")).toThrow(/disposed/);
96
+ expect(() => service.queries.findRecord("any")).toThrow(/session ended|session_start|new session/i);
97
97
  });
98
98
 
99
99
  it("dispose 幂等(多次调用不抛)", () => {
@@ -113,7 +113,7 @@ describe("SubagentService", () => {
113
113
  // revive
114
114
  service.initSession({ pi: makePi(), sessionId: "s2" });
115
115
  // 现在 assertReady 又通过(findRecord 返回 undefined 而非 disposed)
116
- expect(service.findRecord("any")).toBeUndefined();
116
+ expect(service.queries.findRecord("any")).toBeUndefined();
117
117
  });
118
118
  });
119
119
 
@@ -125,7 +125,7 @@ describe("SubagentService", () => {
125
125
  it("findRecord 不存在的 id 返回 undefined", () => {
126
126
  const service = new SubagentService({ cwd: agentDir, modelService });
127
127
  service.initSession({ pi: makePi(), sessionId: "s1" });
128
- expect(service.findRecord("nonexistent-id")).toBeUndefined();
128
+ expect(service.queries.findRecord("nonexistent-id")).toBeUndefined();
129
129
  });
130
130
 
131
131
  it("cancel 不存在的 id 返回 false(不抛错,boolean 契约不变)", () => {
@@ -140,16 +140,13 @@ describe("SubagentService", () => {
140
140
  // ============================================================
141
141
 
142
142
  describe("状态查询", () => {
143
- it("listRunning 初始为空数组", () => {
144
- const service = new SubagentService({ cwd: agentDir, modelService });
145
- service.initSession({ pi: makePi(), sessionId: "s1" });
146
- expect(service.listRunning()).toEqual([]);
147
- });
143
+ // [D4] listRunning 已从 Service 删除(零生产调用方)——初始空态语义由
144
+ // collectRecords 用例与 store listRunning 测试覆盖。
148
145
 
149
146
  it("collectRecords 返回数组(空 sessions 目录时为空)", () => {
150
147
  const service = new SubagentService({ cwd: agentDir, modelService });
151
148
  service.initSession({ pi: makePi(), sessionId: "s1" });
152
- const records = service.collectRecords(100);
149
+ const records = service.queries.collectRecords(100);
153
150
  expect(Array.isArray(records)).toBe(true);
154
151
  });
155
152
 
@@ -157,7 +154,7 @@ describe("SubagentService", () => {
157
154
  const service = new SubagentService({ cwd: agentDir, modelService });
158
155
  service.initSession({ pi: makePi(), sessionId: "s1" });
159
156
  const listener = vi.fn();
160
- const unsubscribe = service.onChange(listener);
157
+ const unsubscribe = service.queries.onChange(listener);
161
158
  expect(typeof unsubscribe).toBe("function");
162
159
  expect(() => unsubscribe()).not.toThrow();
163
160
  });
@@ -218,6 +215,7 @@ describe("SubagentService", () => {
218
215
  agent: "general-purpose",
219
216
  model: "test/model",
220
217
  mode: "background",
218
+ slug: "t",
221
219
  task: "long task",
222
220
  startedAt: 1_000_000,
223
221
  rootSessionId: "s1",
@@ -233,8 +231,9 @@ describe("SubagentService", () => {
233
231
  const record = createRecord(id, {
234
232
  agent: "general-purpose",
235
233
  model: "test/model",
236
- mode: "sync",
234
+ mode: "background",
237
235
  task: "sync task",
236
+ slug: "test",
238
237
  startedAt: 1_000_000,
239
238
  rootSessionId: "s1",
240
239
  // sync 不传 controller → controller === undefined
@@ -250,13 +249,14 @@ describe("SubagentService", () => {
250
249
  agent: "general-purpose",
251
250
  model: "test/model",
252
251
  mode: "background",
252
+ slug: "t",
253
253
  task: "done task",
254
254
  startedAt: 1_000_000,
255
255
  rootSessionId: "s1",
256
256
  controller,
257
257
  });
258
258
  // 直接改 status 模拟终态(不走 CAS——测试不关心状态机,只关心 dispose 的 abort 过滤)
259
- record.status = "done";
259
+ record.status = "closed";
260
260
  getStore(service).register(record);
261
261
  return record;
262
262
  }
@@ -362,7 +362,8 @@ describe("SubagentService", () => {
362
362
 
363
363
  const service = new SubagentService({ cwd: agentDir, modelService });
364
364
  service.initSession({ pi: makePi(), sessionId: "s1" });
365
- service.setUiRequestHandler(staleHandler);
365
+ // [D4-④] setUiRequestHandler 已删——handler 注入走 initSession 参数(唯一入口)
366
+ service.initSession({ pi: makePi(), sessionId: "s1", uiRequestHandler: staleHandler });
366
367
 
367
368
  service.dispose();
368
369
 
@@ -427,6 +428,7 @@ describe("SubagentService", () => {
427
428
  try {
428
429
  await service.execute({
429
430
  task: "worktree without fork (decoupled)",
431
+ slug: "test",
430
432
  worktree: true,
431
433
  fork: false,
432
434
  ctxModel: { id: "ctx-model", name: "Ctx", provider: "p", reasoning: false },
@@ -443,6 +445,7 @@ describe("SubagentService", () => {
443
445
  try {
444
446
  await service.execute({
445
447
  task: "worktree with fork",
448
+ slug: "test",
446
449
  worktree: true,
447
450
  fork: true,
448
451
  ctxModel: { id: "ctx-model", name: "Ctx", provider: "p", reasoning: false },
@@ -460,6 +463,7 @@ describe("SubagentService", () => {
460
463
  try {
461
464
  await service.execute({
462
465
  task: "default path",
466
+ slug: "test",
463
467
  worktree: false,
464
468
  fork: false,
465
469
  ctxModel: { id: "ctx-model", name: "Ctx", provider: "p", reasoning: false },
@@ -473,7 +477,7 @@ describe("SubagentService", () => {
473
477
  // ============================================================
474
478
  // create-await 竞态守卫(Phase 2):create 的 await 窗口内 dispose/cancel
475
479
  // 可把 record CAS 成 closed——守卫须主动 cleanup + early-failed 返回,不 kickOff。
476
- // 实现约束固化:「赋值 record.worktreeHandle → 终态检查 → kickOffBackground
480
+ // 实现约束固化:「赋值 record.worktreeHandle → 终态检查 → 轮次 kick-off
477
481
  // 必须同一同步段(中间禁止 await),本用例即该不变量的回归锚点。
478
482
  // ============================================================
479
483
  it("守卫:create await 窗口内 dispose 抢先 → cleanup 被调 + early-failed 返回(不 kickOff)", async () => {
@@ -487,12 +491,13 @@ describe("SubagentService", () => {
487
491
  }) as Parameters<WorktreeManager["cleanup"]>[0];
488
492
  let resolveCreate!: (h: unknown) => void;
489
493
  vi.spyOn(wtm, "create").mockImplementation(
490
- () => new Promise((r) => { resolveCreate = r; }) as ReturnType<WorktreeManager["create"]>,
494
+ () => new Promise<unknown>((r) => { resolveCreate = r; }) as ReturnType<WorktreeManager["create"]>,
491
495
  );
492
496
  const cleanupSpy = vi.spyOn(wtm, "cleanup").mockResolvedValue(undefined);
493
497
 
494
498
  const execP = service.execute({
495
499
  task: "guard test",
500
+ slug: "test",
496
501
  worktree: true,
497
502
  fork: false,
498
503
  ctxModel: { id: "ctx-model", name: "Ctx", provider: "p", reasoning: false },
@@ -529,7 +534,7 @@ describe("SubagentService", () => {
529
534
  //
530
535
  // [未覆盖路径] 需 mock spawn 才能跑完 runSpawn 的路径,本文件约定不 mock spawn
531
536
  // (见文件头——execute 集成测试在 execute-nesting.test.ts / run-spawn-integration.test.ts):
532
- // - finalizeRecord status="done"(sync/background 正常完成 → unregister(done))
537
+ // - finalizeRecord status="closed"(background 正常完成 → unregister(closed))
533
538
  // - finalizeRecord status="cancelled" 经 runAndFinalize 路径(cancel 抢先 CAS 时
534
539
  // runAndFinalize 侧 tryTransition 失败跳过 finalizeRecord,由 cancelBackground 侧 emit——
535
540
  // 本块 cancel 用例覆盖的即此后端 emit)
@@ -572,6 +577,7 @@ describe("SubagentService", () => {
572
577
  agent: "general-purpose",
573
578
  model: "test/model",
574
579
  mode: "background",
580
+ slug: "t",
575
581
  task: "cancel target",
576
582
  startedAt: 1_000_000,
577
583
  rootSessionId: "s1",
@@ -588,12 +594,13 @@ describe("SubagentService", () => {
588
594
 
589
595
  const handle = await service.execute({
590
596
  task: "wt fail bg",
597
+ slug: "test",
591
598
  worktree: true,
592
599
  fork: true,
593
600
  ctxModel,
594
601
  });
595
602
 
596
- // worktree create 抛错在 kickOffBackground 之前(execute 同步 catch),返回 background 形状
603
+ // worktree create 抛错在轮次 kick-off 之前(executeViaEngine 同步 catch),返回 background 形状
597
604
  expect(handle.mode).toBe("background");
598
605
 
599
606
  // createRecordForMode 生成的 subagentId 带 sa- 前缀(sa-<uuid>)
@@ -670,7 +677,7 @@ describe("SubagentService", () => {
670
677
  injectRunningBackground(service, "bg-running-1");
671
678
  injectRunningBackground(service, "bg-running-2");
672
679
  const terminal = injectRunningBackground(service, "bg-done");
673
- terminal.status = "done"; // 模拟终态,dispose 不应为其 emit
680
+ terminal.status = "closed"; // 模拟终态,dispose 不应为其 emit
674
681
 
675
682
  service.dispose();
676
683
 
@@ -704,7 +711,7 @@ describe("ModelConfigService ctxModel 缓存", () => {
704
711
  agentDir = makeTmpAgentDir();
705
712
  });
706
713
  afterEach(() => {
707
- fs.rmSync(agentDir, { recursive: true, force: true });
714
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
708
715
  });
709
716
 
710
717
  /** 最小 mock registry:空可用列表(ctxModel 路径不需要 lookup)。 */
@@ -15,11 +15,11 @@ import * as path from "node:path";
15
15
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
16
16
 
17
17
  import type { AgentCallOpts, AgentResult } from "../../orchestration/models/types.ts";
18
- import type { RunContext } from "../engine/port.ts";
18
+ import type { RunContext, EnginePort } from "../engine/port.ts";
19
19
  import { clearEngines, registerEngine } from "../engine/registry.ts";
20
- import type { EnginePort, ProbeReport } from "../engine/types.ts";
20
+ import type { ProbeReport } from "../engine/types.ts";
21
21
  import { ModelConfigService, setModelConfigService } from "../model-config-service.ts";
22
- import { getChildByRecord } from "../session-runner.ts";
22
+ import { getChildByRecord } from "../engine/engines/pi/session-runner.ts";
23
23
  import { SubprocessAgentRunner } from "../subprocess-agent-runner.ts";
24
24
  import type { SubagentService } from "../subagent-service.ts";
25
25
  import type { ExecuteOptions } from "../types.ts";
@@ -31,7 +31,10 @@ interface FakeEngineCalls {
31
31
  runs: Array<{ taskSpec: unknown; ctx: RunContext }>;
32
32
  }
33
33
 
34
- function makeFakeZcodeEngine(probeOk: boolean): { engine: EnginePort; calls: FakeEngineCalls } {
34
+ /** fake zcode 引擎的池 key 缺省值(机制跟随性用例:任意 key 落对应目录)。 */
35
+ const FAKE_POOL_KEY = "home-test-provider-m1";
36
+
37
+ function makeFakeZcodeEngine(probeOk: boolean, poolKey: string = FAKE_POOL_KEY): { engine: EnginePort; calls: FakeEngineCalls } {
35
38
  const calls: FakeEngineCalls = { probed: 0, runs: [] };
36
39
  const engine: EnginePort = {
37
40
  id: "zcode",
@@ -46,6 +49,7 @@ function makeFakeZcodeEngine(probeOk: boolean): { engine: EnginePort; calls: Fak
46
49
  resume: "cold",
47
50
  interrupt: "kill-only",
48
51
  permissionMode: "native",
52
+ maxTurns: false,
49
53
  }),
50
54
  probe: () => {
51
55
  calls.probed++;
@@ -62,11 +66,11 @@ function makeFakeZcodeEngine(probeOk: boolean): { engine: EnginePort; calls: Fak
62
66
  run: (taskSpec, ctx) => {
63
67
  calls.runs.push({ taskSpec, ctx });
64
68
  // 对齐点③模拟:prepare 期声明池 key → 事件 emit(zcode coarse 形态:终态后合成)
65
- ctx.onPoolResolved?.("home-test-provider-m1");
69
+ ctx.onPoolResolved?.(poolKey);
66
70
  ctx.onEvent?.({ type: "message_end", usage: { input: 1, output: 1, cacheRead: 0, cacheWrite: 0 } });
67
71
  ctx.onEvent?.({ type: "turn_end" });
68
72
  return Promise.resolve({
69
- handle: { data: { v: 1, engineId: "zcode", sessionRef: {}, poolKey: "home-test-provider-m1", adapterVersion: "t" } },
73
+ handle: { data: { v: 1, engineId: "zcode", sessionRef: {}, poolKey, adapterVersion: "t" } },
70
74
  outcome: { engineId: "zcode", content: "from-zcode" },
71
75
  });
72
76
  },
@@ -84,7 +88,10 @@ function makeMockPiService() {
84
88
  executeOpts.push(opts);
85
89
  return { content: "from-pi", durationMs: 1, toolCalls: [] };
86
90
  });
87
- const service = { executeAndAwait } as unknown as SubagentService;
91
+ // [D4 聚合连带] SAR 构造器经 asEngineService 显式视图取 PiEngineService——fake
92
+ // face 即自身,getter 直接返回 self。
93
+ const service = { executeAndAwait } as unknown as SubagentService & { asEngineService: unknown };
94
+ (service as { asEngineService: unknown }).asEngineService = service;
88
95
  return { service, executeOpts, executeAndAwait };
89
96
  }
90
97
 
@@ -134,7 +141,7 @@ afterEach(() => {
134
141
  if (prevDataDirEnv === undefined) delete process.env["XYZ_AGENT_DATA_DIR"];
135
142
  else process.env["XYZ_AGENT_DATA_DIR"] = prevDataDirEnv;
136
143
  clearEngines();
137
- fs.rmSync(tmpRoot, { recursive: true, force: true });
144
+ fs.rmSync(tmpRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
138
145
  });
139
146
 
140
147
  describe("SAR 路由集成(P4 验收 1/2/3)", () => {
@@ -163,13 +170,31 @@ describe("SAR 路由集成(P4 验收 1/2/3)", () => {
163
170
  expect(result.content).toBe("from-zcode");
164
171
  expect(calls.runs).toHaveLength(1);
165
172
  expect(pi.executeAndAwait).not.toHaveBeenCalled();
166
- // 对齐点③断言:journal 落在引擎声明的池 key 目录(非 pi 'shared' 占位路径)
167
- const poolDir = path.join(tmpRoot, "engine-data", "engines", "zcode", "home-test-provider-m1");
173
+ // 机制跟随性断言:journal 落在引擎声明的池 key 目录(任意 key 落对应目录——
174
+ // 真实 zcode 引擎 poolKey 'shared',对齐真实行为的断言见下一用例)
175
+ const poolDir = path.join(tmpRoot, "engine-data", "engines", "zcode", FAKE_POOL_KEY);
168
176
  const journals = fs.existsSync(poolDir) ? fs.readdirSync(poolDir) : [];
169
177
  expect(journals).toHaveLength(1);
170
178
  expect(journals[0]).toMatch(/^journal-sa-.+\.jsonl$/);
171
- const sharedDir = path.join(tmpRoot, "engine-data", "engines", "zcode", "shared");
172
- expect(fs.existsSync(sharedDir)).toBe(false); // 占位 poolKey 未产生错位落盘
179
+ });
180
+
181
+ it("journal 落盘对齐真实行为:poolKey 'shared' → engines/zcode/shared/journal-<taskId>.jsonl", async () => {
182
+ // 生产 zcode 引擎 poolKey 恒 'shared'(ZCODE_SHARED_POOL_KEY)——fake 以同 key
183
+ // 声明,断言 journal 精确落 shared 池目录(旧池化时代「shared 目录不存在」的
184
+ // 反向锚定已随池化删除,此处锚定现行正向语义)
185
+ const agentRef = writeAgentMd("reviewer", "name: reviewer\ndescription: d\nengine: zcode");
186
+ installModelService();
187
+ const { engine, calls } = makeFakeZcodeEngine(true, "shared");
188
+ registerEngine("zcode", () => engine);
189
+ const pi = makeMockPiService();
190
+ const sar = new SubprocessAgentRunner({ subagentService: pi.service });
191
+
192
+ await sar.run(makeOpts({ agent: agentRef }), new AbortController().signal);
193
+
194
+ const taskId = calls.runs[0]?.ctx.taskId;
195
+ expect(taskId).toMatch(/^sa-/);
196
+ const sharedPoolDir = path.join(tmpRoot, "engine-data", "engines", "zcode", "shared");
197
+ expect(fs.readdirSync(sharedPoolDir)).toEqual([`journal-${taskId}.jsonl`]);
173
198
  });
174
199
 
175
200
  it("调用参数 engine 覆盖 frontmatter(三层优先级落到 run,A7)", async () => {
@@ -307,4 +332,55 @@ describe("SAR 路由集成(P4 验收 1/2/3)", () => {
307
332
  await new Promise<void>((resolve) => child.once("close", () => resolve()));
308
333
  expect(getChildByRecord(ctx.taskId)).toBeUndefined();
309
334
  });
335
+
336
+ // ── [D3-④] SAR 路径预检(capabilities 驱动;唯一有意行为变化 = zcode+worktree)──
337
+
338
+ it("[D3-④] zcode + worktree:true → engine_capability_unsupported(workflow 域漏拦缺口修复),无 engine.run、无 journal 产物", async () => {
339
+ const agentRef = writeAgentMd("reviewer", "name: reviewer\ndescription: d\nengine: zcode");
340
+ installModelService();
341
+ const { engine, calls } = makeFakeZcodeEngine(true);
342
+ registerEngine("zcode", () => engine);
343
+ const pi = makeMockPiService();
344
+ const sar = new SubprocessAgentRunner({ subagentService: pi.service });
345
+
346
+ const result = await sar.run(makeOpts({ agent: agentRef, worktree: true }), new AbortController().signal);
347
+
348
+ expect(result.error).toContain("engine_capability_unsupported");
349
+ expect(result.error).toContain("worktree");
350
+ // 无进程创建 + 无 journal 落盘(拒绝在 wiring/run 之前)
351
+ expect(calls.runs).toHaveLength(0);
352
+ expect(pi.executeAndAwait).not.toHaveBeenCalled();
353
+ const enginesRoot = path.join(tmpRoot, "engine-data", "engines");
354
+ expect(fs.existsSync(enginesRoot) ? fs.readdirSync(enginesRoot) : []).toEqual([]);
355
+ });
356
+
357
+ it("[D3-④] zcode + maxTurns / fork → engine_capability_unsupported(现状行为保持的正向守护)", async () => {
358
+ const agentRef = writeAgentMd("reviewer", "name: reviewer\ndescription: d\nengine: zcode");
359
+ installModelService();
360
+ const { engine, calls } = makeFakeZcodeEngine(true);
361
+ registerEngine("zcode", () => engine);
362
+ const pi = makeMockPiService();
363
+ const sar = new SubprocessAgentRunner({ subagentService: pi.service });
364
+
365
+ const maxTurnsResult = await sar.run(makeOpts({ agent: agentRef, maxTurns: 5 }), new AbortController().signal);
366
+ expect(maxTurnsResult.error).toContain("engine_capability_unsupported");
367
+ expect(maxTurnsResult.error).toContain("maxTurns");
368
+ expect(maxTurnsResult.error).toContain("capabilities.maxTurns = false");
369
+
370
+ const forkResult = await sar.run(makeOpts({ agent: agentRef, fork: true }), new AbortController().signal);
371
+ expect(forkResult.error).toContain("engine_capability_unsupported");
372
+ expect(forkResult.error).toContain("fork");
373
+ expect(calls.runs).toHaveLength(0);
374
+ });
375
+
376
+ it("[V4⑤ 反向] pi + maxTurns → 直通不拦(pi 既有合法能力零回归),executeAndAwait 收到 maxTurns", async () => {
377
+ installModelService();
378
+ const pi = makeMockPiService();
379
+ const sar = new SubprocessAgentRunner({ subagentService: pi.service });
380
+
381
+ const result = await sar.run(makeOpts({ maxTurns: 3 }), new AbortController().signal);
382
+
383
+ expect(result.content).toBe("from-pi");
384
+ expect(pi.executeOpts[0]?.maxTurns).toBe(3);
385
+ });
310
386
  });
@@ -0,0 +1,75 @@
1
+ // src/execution/__tests__/subprocess-agent-runner-timeout.test.ts
2
+ //
3
+ // [D6 合流迁移] mergeTimeoutSignal(D-A9:per-call timeoutMs 合并进 AbortSignal)的
4
+ // 行为测试——原定义在已删除的 execution/execute-options-mapper.ts(测试随迁),函数
5
+ // 现居 subprocess-agent-runner.ts(唯一消费点,运行期件随消费方落位)。
6
+ // 原用例编号(execute-options-mapper.test.ts 的 mergeTimeoutSignal describe,7 用例)
7
+ // 与行为语义逐条保持。
8
+ //
9
+ // 接线测试(timeoutMs → engine 收到 merged signal → abort 收口)在
10
+ // subprocess-agent-runner.test.ts 的 T3.6(经真实 PiEngine 链路),本文件锁纯函数行为。
11
+
12
+ import { describe, expect, it, vi } from "vitest";
13
+
14
+ import { mergeTimeoutSignal } from "../subprocess-agent-runner.ts";
15
+
16
+ describe("mergeTimeoutSignal (D-A9)", () => {
17
+ it("T3.6 timeoutMs===undefined → 原样返回 external signal", () => {
18
+ const ctrl = new AbortController();
19
+ const result = mergeTimeoutSignal(ctrl.signal, undefined);
20
+ expect(result).toBe(ctrl.signal);
21
+ });
22
+
23
+ it("T3.6 timeoutMs<=0 → 原样返回 external signal", () => {
24
+ const ctrl = new AbortController();
25
+ const result = mergeTimeoutSignal(ctrl.signal, 0);
26
+ expect(result).toBe(ctrl.signal);
27
+ });
28
+
29
+ it("T3.6 timeoutMs>0 → 返回新 signal(合并外部+超时两路)", () => {
30
+ const ctrl = new AbortController();
31
+ const result = mergeTimeoutSignal(ctrl.signal, 50);
32
+ expect(result).not.toBe(ctrl.signal);
33
+ expect(result.aborted).toBe(false);
34
+ });
35
+
36
+ it("T3.6 timeoutMs 到期 → merged signal abort", () => {
37
+ vi.useFakeTimers();
38
+ const ctrl = new AbortController();
39
+ const merged = mergeTimeoutSignal(ctrl.signal, 50);
40
+
41
+ expect(merged.aborted).toBe(false);
42
+ vi.advanceTimersByTime(51);
43
+ expect(merged.aborted).toBe(true);
44
+ vi.useRealTimers();
45
+ });
46
+
47
+ it("T3.6 外部 signal abort → merged signal abort", () => {
48
+ const ctrl = new AbortController();
49
+ const merged = mergeTimeoutSignal(ctrl.signal, 5000);
50
+ ctrl.abort();
51
+ expect(merged.aborted).toBe(true);
52
+ });
53
+
54
+ it("T3.6 外部 signal 已 abort → 返回已 abort 的 signal", () => {
55
+ const ctrl = new AbortController();
56
+ ctrl.abort();
57
+ const merged = mergeTimeoutSignal(ctrl.signal, 5000);
58
+ expect(merged.aborted).toBe(true);
59
+ });
60
+
61
+ it("T3.17 NFR: merged signal abort → timeout timer 清理", () => {
62
+ vi.useFakeTimers();
63
+ const ctrl = new AbortController();
64
+ const merged = mergeTimeoutSignal(ctrl.signal, 50);
65
+
66
+ ctrl.abort(); // 外部 abort → merged 也 abort
67
+ expect(merged.aborted).toBe(true);
68
+
69
+ // 推进时间,不应再有副作用
70
+ vi.advanceTimersByTime(100);
71
+ // timer 应被清理(通过 abort event listener)
72
+ // 无异常 = timer 已正确清理
73
+ vi.useRealTimers();
74
+ });
75
+ });