@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
@@ -1,9 +1,10 @@
1
1
  // src/execution/__tests__/epipe-fallback.test.ts
2
2
  //
3
- // deliverMessage EPIPE 兜底集成测试——热路径 stdin 写入 EPIPE 时自动转冷路径 resume + 消息重放。
3
+ // deliverChatMessage EPIPE 兜底集成测试——热路径 stdin 写入 EPIPE 时自动转冷路径续轮 + 消息重放
4
+ //(D2 后投递协议知识在 PiEngine.deliverPrompt,编排层经 engine.interactRecord 进入)。
4
5
  //
5
6
  // 场景覆盖:
6
- // 1. 首次 EPIPE → 自动转冷路径 resumeRound(runSpawn 收到 resume 参数 + 原消息)
7
+ // 1. 首次 EPIPE → 自动转冷路径续轮(runSpawn 收到 resume 参数 + 原消息)
7
8
  // 2. 连续 2 次 EPIPE → throw 含恢复指引(防无限循环)
8
9
  // 3. 热路径成功写入后清零 EPIPE 计数(正常路径不受影响)
9
10
 
@@ -22,7 +23,7 @@ vi.mock("../../core/logger.ts", () => ({ getLogger: () => loggerMock }));
22
23
 
23
24
  // mock session-runner:runSpawn 受控 + killAllSpawnedChildren 空实现;
24
25
  // getChildByRecord/spawnedChildren 提供真实 Map 语义。
25
- vi.mock("../session-runner.ts", () => {
26
+ vi.mock("../engine/engines/pi/session-runner.ts", () => {
26
27
  const spawnedChildren = new Map<string, unknown>();
27
28
  return {
28
29
  runSpawn: vi.fn(),
@@ -34,7 +35,7 @@ vi.mock("../session-runner.ts", () => {
34
35
  };
35
36
  });
36
37
 
37
- import { runSpawn, spawnedChildren } from "../session-runner.ts";
38
+ import { runSpawn, spawnedChildren } from "../engine/engines/pi/session-runner.ts";
38
39
  import * as lifecycle from "../lifecycle-manager.ts";
39
40
  import { createRecord } from "../execution-record.ts";
40
41
  import { ModelConfigService } from "../model-config-service.ts";
@@ -50,11 +51,15 @@ function makeTmpAgentDir(): string {
50
51
  }
51
52
 
52
53
  function makePi(): PiLike & {
53
- appendEntry: ReturnType<typeof vi.fn>;
54
- events: { emit: ReturnType<typeof vi.fn> };
55
- sendMessage: ReturnType<typeof vi.fn>;
54
+ appendEntry: ReturnType<typeof vi.fn<(customType: string, data?: unknown) => void>>;
55
+ events: { emit: ReturnType<typeof vi.fn<(channel: string, data: unknown) => void>> };
56
+ sendMessage: ReturnType<typeof vi.fn<(message: Parameters<PiLike["sendMessage"]>[0], options?: Parameters<PiLike["sendMessage"]>[1]) => void>>;
56
57
  } {
57
- return { appendEntry: vi.fn(), events: { emit: vi.fn() }, sendMessage: vi.fn() };
58
+ return {
59
+ appendEntry: vi.fn((customType: string, data?: unknown) => {}),
60
+ events: { emit: vi.fn((channel: string, data: unknown) => {}) },
61
+ sendMessage: vi.fn(() => {}),
62
+ };
58
63
  }
59
64
 
60
65
  function makeResult(success: boolean): AgentResult {
@@ -110,17 +115,17 @@ function makeNormalChild(): ChildProcess {
110
115
  }
111
116
 
112
117
  // ============================================================
113
- // deliverMessage EPIPE 兜底
118
+ // deliverChatMessage EPIPE 兜底
114
119
  // ============================================================
115
120
 
116
- describe("deliverMessage EPIPE 兜底(热路径 stdin EPIPE → 冷路径 resume)", () => {
121
+ describe("deliverChatMessage EPIPE 兜底(热路径 stdin EPIPE → 冷路径续轮)", () => {
117
122
  let agentDir: string;
118
123
  let service: SubagentService;
119
124
  let record: ExecutionRecord;
120
125
 
121
126
  beforeEach(() => {
122
127
  agentDir = makeTmpAgentDir();
123
- const modelService = new ModelConfigService({ agentDir });
128
+ const modelService = new ModelConfigService({ agentDir, cwd: agentDir });
124
129
  service = new SubagentService({ cwd: agentDir, modelService });
125
130
  service.initSession({ pi: makePi(), sessionId: "root-session" });
126
131
  record = makeIdleRecord();
@@ -135,7 +140,7 @@ describe("deliverMessage EPIPE 兜底(热路径 stdin EPIPE → 冷路径 resu
135
140
  service.dispose();
136
141
  spawnedChildren.clear();
137
142
  lifecycle._resetLifecycleState();
138
- fs.rmSync(agentDir, { recursive: true, force: true });
143
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
139
144
  });
140
145
 
141
146
  it("首次 EPIPE → 自动转冷路径 resumeRound + 原消息重放", async () => {
@@ -143,13 +148,13 @@ describe("deliverMessage EPIPE 兜底(热路径 stdin EPIPE → 冷路径 resu
143
148
  // 注册 EPIPE child(热路径会命中但 stdin.write 抛 EPIPE)
144
149
  spawnedChildren.set(record.id, makeEpipeChild());
145
150
 
146
- // deliverMessage throw(首次 EPIPE 走 resume 兜底)
147
- await expect(service.deliverMessage(record, "msg after epipe", false)).resolves.toBeUndefined();
151
+ // 投递不 throw(首次 EPIPE 走续轮兜底)
152
+ await expect(service.chatActions.deliverChatMessage(record, "msg after epipe", false)).resolves.toBeUndefined();
148
153
 
149
154
  // spawnedChildren 中的死进程条目已清理(EPIPE catch 块 delete)
150
155
  expect(spawnedChildren.has(record.id)).toBe(false);
151
156
 
152
- // resumeRound 被触发(冷路径),runSpawn 收到 resume 参数 + 原消息
157
+ // 冷路径续轮被触发,runSpawn 收到 resume 参数 + 原消息
153
158
  await vi.waitFor(() => expect(mockRunSpawn).toHaveBeenCalledTimes(1));
154
159
  const call = mockRunSpawn.mock.calls[0]!;
155
160
  expect(call[1]).toBe("msg after epipe");
@@ -174,7 +179,7 @@ describe("deliverMessage EPIPE 兜底(热路径 stdin EPIPE → 冷路径 resu
174
179
  spawnedChildren.set(record.id, makeEpipeChild());
175
180
 
176
181
  // 第 1 次:EPIPE → resume(不 throw)
177
- await service.deliverMessage(record, "first epipe", false);
182
+ await service.chatActions.deliverChatMessage(record, "first epipe", false);
178
183
  await vi.waitFor(() => expect(mockRunSpawn).toHaveBeenCalledTimes(1));
179
184
 
180
185
  // resume 完成后 record 回 running(v4 B-1:finalizeRoundToIdle 设 running,旧 idle 折入)
@@ -184,10 +189,10 @@ describe("deliverMessage EPIPE 兜底(热路径 stdin EPIPE → 冷路径 resu
184
189
  spawnedChildren.set(record.id, makeEpipeChild());
185
190
 
186
191
  // 第 2 次 EPIPE → throw 含恢复指引(连续 2 次触发 exhaustion)
187
- // 注意:第二 EPIPE 时 count 已为 2,catch 块立即 throw(不经过 resumeRound)。
192
+ // 注意:第二 EPIPE 时 count 已为 2,catch 块立即 throw(不经过续轮)。
188
193
  let thrown: unknown;
189
194
  try {
190
- await service.deliverMessage(record, "second epipe", false);
195
+ await service.chatActions.deliverChatMessage(record, "second epipe", false);
191
196
  } catch (err) {
192
197
  thrown = err;
193
198
  }
@@ -203,13 +208,13 @@ describe("deliverMessage EPIPE 兜底(热路径 stdin EPIPE → 冷路径 resu
203
208
 
204
209
  // 第 1 轮:EPIPE → resume
205
210
  spawnedChildren.set(record.id, makeEpipeChild());
206
- await service.deliverMessage(record, "epipe msg", false);
211
+ await service.chatActions.deliverChatMessage(record, "epipe msg", false);
207
212
  await vi.waitFor(() => expect(mockRunSpawn).toHaveBeenCalledTimes(1));
208
213
  await vi.waitFor(() => expect(record.status).toBe("running"));
209
214
 
210
215
  // 第 2 轮:正常 child,成功写入(清零 EPIPE 计数)
211
216
  spawnedChildren.set(record.id, makeNormalChild());
212
- await service.deliverMessage(record, "normal msg", true);
217
+ await service.chatActions.deliverChatMessage(record, "normal msg", true);
213
218
  // 不 throw,status=running(热路径成功)
214
219
  expect(record.status).toBe("running");
215
220
 
@@ -217,7 +222,7 @@ describe("deliverMessage EPIPE 兜底(热路径 stdin EPIPE → 冷路径 resu
217
222
  // 需要先让 record 回 running(等待续聊态)
218
223
  record.status = "running";
219
224
  spawnedChildren.set(record.id, makeEpipeChild());
220
- await expect(service.deliverMessage(record, "after reset", false)).resolves.toBeUndefined();
225
+ await expect(service.chatActions.deliverChatMessage(record, "after reset", false)).resolves.toBeUndefined();
221
226
  });
222
227
 
223
228
  it("EPIPE 兜底与冷路径共用 in-flight 守卫:resume 在途时 EPIPE 兜底不再二次 spawn(review round2 MF1)", async () => {
@@ -226,14 +231,14 @@ describe("deliverMessage EPIPE 兜底(热路径 stdin EPIPE → 冷路径 resu
226
231
  mockRunSpawn.mockImplementationOnce(
227
232
  () => new Promise<AgentResult>((res) => { releaseFirst = res; }),
228
233
  );
229
- await service.deliverMessage(record, "cold path first", false);
234
+ await service.chatActions.deliverChatMessage(record, "cold path first", false);
230
235
  await vi.waitFor(() => expect(mockRunSpawn).toHaveBeenCalledTimes(1));
231
236
 
232
- // 注册 EPIPE child → deliverMessage 走热路径 → stdin EPIPE → 兜底调 resumeRound
237
+ // 注册 EPIPE child → 投递走热路径 → stdin EPIPE → 兜底调冷路径续轮
233
238
  // → in-flight 命中 → throw(不再走第二次 spawn。EPIPE 计数仍 +1 但未达阈值 2,
234
239
  // exhaustion 分支不触发;throw 由兜底路径的 resumeRound 守卫抛出)
235
240
  spawnedChildren.set(record.id, makeEpipeChild());
236
- await expect(service.deliverMessage(record, "epipe during resume", false)).rejects.toThrow(
241
+ await expect(service.chatActions.deliverChatMessage(record, "epipe during resume", false)).rejects.toThrow(
237
242
  /already starting a new round/,
238
243
  );
239
244
  expect(mockRunSpawn).toHaveBeenCalledTimes(1);
@@ -8,101 +8,31 @@
8
8
  // ── mock 策略 ──
9
9
  //
10
10
  // 复用 execute-nesting.test.ts 的 spawn / node:fs / manifest-store / temp-prompt / alive-store
11
- // / finalized-marker mock 范式(见该文件头部详细注释)。本文件 **不驱动 FakeChild 完成**——
12
- // 被测的两个分支都在 runSpawn 之前抛/收尾(worktree create 在步骤 2.5,runSpawn 在步骤 5),
13
- // 因此 spawn 即使被调也无人驱动,测试在抛错后立即断言即可结束。
11
+ // / finalized-marker mock 范式,已收敛到 ./helpers/subagent-service-mocks.ts 单源(四文件
12
+ // 共享)。本文件 **不驱动 FakeChild 完成**——被测的两个分支都在 runSpawn 之前抛/收尾
13
+ // (worktree create 在步骤 2.5,runSpawn 在步骤 5),因此 spawn 即使被调也无人驱动,
14
+ // 测试在抛错后立即断言即可结束。
14
15
  //
15
16
  // worktreeManager 是 SubagentService 构造时 new 出的私有字段(WorktreeManager 实例,非模块)。
16
17
  // 测试 2 用 vi.spyOn(Reflect.get(service, "worktreeManager"), "create") 注入抛错,无需模块级 mock。
17
18
 
18
- import { PassThrough } from "node:stream";
19
-
20
19
  import { afterEach, describe, expect, it, vi } from "vitest";
21
20
 
22
- // ── mock modules(与 execute-nesting.test.ts 同范式)──
23
-
24
- vi.mock("node:child_process", async () => {
25
- const { EventEmitter } = await import("node:events");
26
- const { PassThrough } = await import("node:stream");
27
-
28
- class FakeChild extends EventEmitter {
29
- pid = 12345;
30
- stdout = new PassThrough();
31
- stderr = new PassThrough();
32
- killed = false;
33
- killSignal: string | undefined;
34
- kill(sig?: string): boolean {
35
- this.killed = true;
36
- this.killSignal = sig;
37
- return true;
38
- }
39
- }
40
-
41
- return {
42
- spawn: vi.fn(() => new FakeChild()),
43
- // buildEnvBlock 的 git branch 调用(execFile 异步):默认 err-first 兜底 → catch → branch=""
44
- execFile: vi.fn(
45
- (
46
- _cmd: string,
47
- _args: readonly string[],
48
- _opts: unknown,
49
- cb: (err: Error | null, stdout?: string, stderr?: string) => void,
50
- ) => cb(new Error("execFile not configured in this test")),
51
- ),
52
- };
53
- });
54
-
55
- vi.mock("node:fs", async () => {
56
- const actual = await import("node:fs");
57
- return {
58
- default: {
59
- ...actual,
60
- mkdirSync: vi.fn(),
61
- existsSync: vi.fn(() => false),
62
- appendFileSync: vi.fn(),
63
- writeFileSync: vi.fn(),
64
- readdirSync: vi.fn(() => []),
65
- },
66
- mkdirSync: vi.fn(),
67
- existsSync: vi.fn(() => false),
68
- appendFileSync: vi.fn(),
69
- writeFileSync: vi.fn(),
70
- readdirSync: vi.fn(() => []),
71
- promises: actual.promises,
72
- };
73
- });
74
-
75
- vi.mock("../alive-store.ts", async (importOriginal) => {
76
- const actual = await importOriginal<typeof import("../alive-store.ts")>();
77
- return {
78
- ...actual,
79
- writeAliveMarker: vi.fn(),
80
- removeAliveMarker: vi.fn(),
81
- };
82
- });
83
-
84
- vi.mock("../finalized-marker.ts", () => ({
85
- writeFinalized: vi.fn(),
86
- readFinalized: vi.fn(() => false),
87
- }));
88
-
89
- vi.mock("../manifest-store.ts", () => {
90
- class FakeManifestStore {
91
- writeManifest = vi.fn(async () => {});
92
- readManifest = vi.fn(async () => null);
93
- listAllSync = vi.fn(() => []);
94
- recoverTmpFiles = vi.fn(async () => []);
95
- }
96
- return { ManifestStore: FakeManifestStore };
97
- });
98
-
99
- vi.mock("../temp-prompt.ts", () => ({
100
- writePromptToTempFile: vi.fn(async (agent: string) => {
101
- const safeName = agent.replace(/[^\w.-]+/g, "_");
102
- return { dir: `/tmp/fake-${safeName}`, filePath: `/tmp/fake-${safeName}/prompt-${safeName}.md` };
103
- }),
104
- cleanupTempPrompt: vi.fn(async () => {}),
105
- }));
21
+ import {
22
+ aliveStoreModule,
23
+ childProcessModule,
24
+ finalizedMarkerModule,
25
+ fsSyncModule,
26
+ manifestStoreModule,
27
+ tempPromptModule,
28
+ } from "./helpers/subagent-service-mocks.ts";
29
+
30
+ vi.mock("node:child_process", () => childProcessModule());
31
+ vi.mock("node:fs", async (importOriginal) => fsSyncModule(await importOriginal<typeof import("node:fs")>()));
32
+ vi.mock("../alive-store.ts", async (importOriginal) => aliveStoreModule(await importOriginal<typeof import("../alive-store.ts")>()));
33
+ vi.mock("../finalized-marker.ts", () => finalizedMarkerModule());
34
+ vi.mock("../manifest-store.ts", () => manifestStoreModule());
35
+ vi.mock("../engine/engines/pi/temp-prompt.ts", () => tempPromptModule());
106
36
 
107
37
  import { ModelConfigService } from "../model-config-service.ts";
108
38
  import type { ModelInfo, ModelRegistryLike } from "../model-resolver.ts";
@@ -127,7 +57,7 @@ interface SetupResult {
127
57
 
128
58
  function setup(): SetupResult {
129
59
  const agentDir = "/tmp/exec-await-worktree-it"; // fs 已 mock,路径不需真实存在
130
- const modelService = new ModelConfigService({ agentDir });
60
+ const modelService = new ModelConfigService({ agentDir, cwd: agentDir });
131
61
  modelService.initModel({
132
62
  modelRegistry: makeEmptyRegistry(),
133
63
  sessionId: "exec-await-worktree-it",
@@ -219,7 +149,7 @@ describe("executeAndAwait worktree 失败收尾", () => {
219
149
  }) as Parameters<WorktreeManager["cleanup"]>[0];
220
150
  let resolveCreate!: (h: unknown) => void;
221
151
  vi.spyOn(worktreeManager, "create").mockImplementation(
222
- () => new Promise((r) => { resolveCreate = r; }) as ReturnType<WorktreeManager["create"]>,
152
+ () => new Promise<unknown>((r) => { resolveCreate = r; }) as ReturnType<WorktreeManager["create"]>,
223
153
  );
224
154
  const cleanupSpy = vi.spyOn(worktreeManager, "cleanup").mockResolvedValue(undefined);
225
155
 
@@ -15,134 +15,36 @@
15
15
  // 因此本文件 mock 的是 node:child_process.spawn(返回 FakeChild),而非 getSdk/fakeSession
16
16
  // (那是对 in-process run() 的旧 mock,在 spawn 改造后是死代码)。
17
17
  //
18
- // mock 模式参考 run-spawn-integration.test.ts(该文件是 spawn 改造后的正确 mock 范式):
19
- // - node:child_process.spawn → FakeChild(EventEmitter + PassThrough),测试控制器
20
- // emit stdout JSON 行(header + SdkEvent)/ stderr / close 时序。
21
- // - node:child_process.execFile → err-first callback 默认兜底(buildEnvBlock 的 git
22
- // branch 调用失败 → catch → branch="",避免副作用)。
23
- // - node:fs 同步方法 → mock(mkdirSync/existsSync/appendFileSync/writeFileSync/readdirSync),
24
- // 避免 sessionDir/sessionFile 触碰真实文件系统。
25
- // - fs.promises.* → 保留真实实现(temp-prompt 整体被 mock,不触发真实 I/O)。
26
- // - temp-prompt → mock(writePromptToTempFile 返回固定路径,消除 fake-timers flaky)。
27
- // - alive-store.writeAliveMarker → mock(避免写 .alive sidecar)。
18
+ // mock 模块工厂已收敛 ./helpers/subagent-service-mocks.ts(四文件共享单源,含
19
+ // spawn → FakeChild / fs 同步方法 / temp-prompt / alive-store / finalized-marker /
20
+ // manifest-store 的完整桩形与动机注释)。
28
21
  //
29
22
  // 所有断言语义不变:它们测的是 SubagentService 的 **编排逻辑**
30
23
  // (pool.acquire / execCtxAls 深度),这些逻辑
31
24
  // 无论事件来自 fakeSession.subscribe 还是 FakeChild.stdout 都一致。
32
25
 
33
- import type { PassThrough } from "node:stream";
34
-
35
26
  import { afterEach, describe, expect, it, vi } from "vitest";
36
27
 
37
- // ── mock modules ──
38
- //
39
- // vitest 会把 vi.mock 提升到文件顶部(早于其他 import / 声明)。mock 工厂若要引用
40
- // FakeChild,需在工厂内部 import(async 工厂可用 await import),而非引用顶部
41
- // 顶层 import(它们在 vi.mock 执行时尚未绑定)。
42
-
43
- vi.mock("node:child_process", async () => {
44
- const { EventEmitter } = await import("node:events");
45
- const { PassThrough } = await import("node:stream");
46
-
47
- // FakeChild:模拟 ChildProcess(EventEmitter + PassThrough streams)。
48
- // 测试通过 lastSpawnedChild() 取回实例,控制 emit stdout JSON 行 / close 时序。
49
- class FakeChild extends EventEmitter {
50
- pid = 12345;
51
- stdout = new PassThrough();
52
- stderr = new PassThrough();
53
- killed = false;
54
- killSignal: string | undefined;
55
- kill(sig?: string): boolean {
56
- this.killed = true;
57
- this.killSignal = sig;
58
- return true;
59
- }
60
- }
61
-
62
- return {
63
- spawn: vi.fn(() => new FakeChild()),
64
- // buildEnvBlock 的 git branch 调用(execFile 异步):默认 err-first 兜底 → catch → branch=""
65
- execFile: vi.fn(
66
- (
67
- _cmd: string,
68
- _args: readonly string[],
69
- _opts: unknown,
70
- cb: (err: Error | null, stdout?: string, stderr?: string) => void,
71
- ) => cb(new Error("execFile not configured in this test")),
72
- ),
73
- };
74
- });
75
-
76
- // node:fs:同步方法 mock(runSpawn 用到的全部),promises 保留真实实现(temp-prompt 用)。
77
- vi.mock("node:fs", async () => {
78
- const actual = await import("node:fs");
79
- return {
80
- default: {
81
- ...actual,
82
- mkdirSync: vi.fn(),
83
- existsSync: vi.fn(() => false),
84
- appendFileSync: vi.fn(),
85
- writeFileSync: vi.fn(),
86
- readdirSync: vi.fn(() => []),
87
- },
88
- // 具名导出与 default 保持一致
89
- mkdirSync: vi.fn(),
90
- existsSync: vi.fn(() => false),
91
- appendFileSync: vi.fn(),
92
- writeFileSync: vi.fn(),
93
- readdirSync: vi.fn(() => []),
94
- // promises 保留真实实现——temp-prompt 已被 mock(见下方 vi.mock),不再触发真实 I/O
95
- promises: actual.promises,
96
- };
97
- });
98
-
99
- // alive-store:mock writeAliveMarker(runSpawn 写 .alive sidecar)+ removeAliveMarker
100
- // (finalizeRecord 收尾删 .alive)。其余导出(readAliveMarker/isProcessAlive)保留真实实现
101
- // (worktree-manager/record-store 用,本组用例不涉及但保留以避免间接报错)。
102
- vi.mock("../alive-store.ts", async (importOriginal) => {
103
- const actual = await importOriginal<typeof import("../alive-store.ts")>();
104
- return {
105
- ...actual,
106
- writeAliveMarker: vi.fn(),
107
- removeAliveMarker: vi.fn(),
108
- };
109
- });
110
-
111
- // finalized-marker mock:避免真实 fs 写 sidecar(测试不关心 finalized 行为)
112
- vi.mock("../finalized-marker.ts", () => ({
113
- writeFinalized: vi.fn(),
114
- readFinalized: vi.fn(() => false),
115
- }));
116
-
117
- // manifest-store mock:writeManifest 用真实 fs.promises 写盘,但本文件 fs 同步方法已 mock
118
- // (目录从不真实创建)→ open/rename/unlink 全 ENOENT → bestEffort 异步 console.debug。
119
- // 这些延迟 console 通过 worker RPC(onUserConsoleLog)回流,与 vitest teardown 形成 race:
120
- // "Closing rpc while onUserConsoleLog was pending" → unhandled rejection / exit 1(flaky)。
121
- // 本组用例测编排逻辑(pool / depth / throttle),不测 manifest 持久化(有 manifest-store.test.ts
122
- // 独立覆盖)。故 mock 成 no-op,消除 teardown race 的根因——异步 console 输出。
123
- vi.mock("../manifest-store.ts", () => {
124
- class FakeManifestStore {
125
- writeManifest = vi.fn(async () => {});
126
- readManifest = vi.fn(async () => null);
127
- listAllSync = vi.fn(() => []);
128
- recoverTmpFiles = vi.fn(async () => []);
129
- }
130
- return { ManifestStore: FakeManifestStore };
131
- });
132
-
133
- // temp-prompt:mock 掉真实 fs.promises I/O,消除 fake-timers 下的 flaky 竞态
134
- // (详见 run-spawn-integration.test.ts 同名 mock 的注释)。
135
- vi.mock("../temp-prompt.ts", () => ({
136
- writePromptToTempFile: vi.fn(async (agent: string) => {
137
- const safeName = agent.replace(/[^\w.-]+/g, "_");
138
- return { dir: `/tmp/fake-${safeName}`, filePath: `/tmp/fake-${safeName}/prompt-${safeName}.md` };
139
- }),
140
- cleanupTempPrompt: vi.fn(async () => {}),
141
- }));
28
+ import {
29
+ aliveStoreModule,
30
+ childProcessModule,
31
+ driveChildToCompletion,
32
+ finalizedMarkerModule,
33
+ fsSyncModule,
34
+ manifestStoreModule,
35
+ tempPromptModule,
36
+ } from "./helpers/subagent-service-mocks.ts";
37
+
38
+ vi.mock("node:child_process", () => childProcessModule());
39
+ vi.mock("node:fs", async (importOriginal) => fsSyncModule(await importOriginal<typeof import("node:fs")>()));
40
+ vi.mock("../alive-store.ts", async (importOriginal) => aliveStoreModule(await importOriginal<typeof import("../alive-store.ts")>()));
41
+ vi.mock("../finalized-marker.ts", () => finalizedMarkerModule());
42
+ vi.mock("../manifest-store.ts", () => manifestStoreModule());
43
+ vi.mock("../engine/engines/pi/temp-prompt.ts", () => tempPromptModule());
142
44
 
143
45
  import { spawn } from "node:child_process";
144
46
 
145
- import { waitForSpawn } from "./helpers/spawn-mock.ts";
47
+ import { waitForSpawn, lastSpawnedChild } from "./helpers/spawn-mock.ts";
146
48
  import { ModelConfigService } from "../model-config-service.ts";
147
49
  import type { ModelInfo, ModelRegistryLike } from "../model-resolver.ts";
148
50
  import { MAX_FORK_DEPTH } from "../session-context-resolver.ts";
@@ -150,63 +52,6 @@ import { SubagentService } from "../subagent-service.ts";
150
52
 
151
53
  const mockSpawn = vi.mocked(spawn);
152
54
 
153
- /**
154
- * spawn mock 返回的 fake child 类型。
155
- * 由于 FakeChild 定义在 vi.mock 工厂内部(作用域隔离),此处用结构子集类型描述,
156
- * 测试代码通过此类型访问 stdout/stderr/kill 等成员。
157
- */
158
- interface FakeChild {
159
- pid: number;
160
- stdout: PassThrough;
161
- stderr: PassThrough;
162
- killed: boolean;
163
- killSignal: string | undefined;
164
- kill(sig?: string): boolean;
165
- emit(event: string, ...args: unknown[]): boolean;
166
- }
167
-
168
- /** 从最近一次 spawn 调用取回返回的 FakeChild(测试控制器)。 */
169
- function lastSpawnedChild(): FakeChild {
170
- const result = mockSpawn.mock.results.at(-1);
171
- if (!result) throw new Error("spawn was not called yet");
172
- return result.value as FakeChild;
173
- }
174
-
175
- // ============================================================
176
- // 辅助:FakeChild stdout 驱动(替代旧 fakeSession.subscribe 的事件注入)
177
- // ============================================================
178
-
179
- /** 构造 session header 行(stdout 首行,runSpawn 据此回填 record.sessionFile)。 */
180
- function sessionHeader(id = "nest-session"): Record<string, unknown> {
181
- return {
182
- type: "session",
183
- id,
184
- timestamp: "2026-07-03T12-00-00-000Z",
185
- cwd: "/tmp/test",
186
- };
187
- }
188
-
189
- /** 向 stdout 写一行 JSON(自动补换行,runSpawn 按 \n split 行)。 */
190
- function emitStdoutLine(child: FakeChild, obj: Record<string, unknown>): void {
191
- child.stdout.write(`${JSON.stringify(obj)}\n`);
192
- }
193
-
194
- /**
195
- * 驱动 FakeChild 完成 session:写 header + 可选事件 + close(0)。
196
- *
197
- * 这是「让 runSpawn 自然 resolve」的标准收尾路径。runSpawn 在 close 后判定 success
198
- * (exitCode=0 → success=true),并跑 identity 补写 + finalizeRecord。
199
- *
200
- * @param events header 之后、close 之前 emit 的 SdkEvent 行(tool/message/turn 等)
201
- */
202
- async function driveChildToCompletion(child: FakeChild, events: Record<string, unknown>[] = []): Promise<void> {
203
- emitStdoutLine(child, sessionHeader());
204
- for (const e of events) emitStdoutLine(child, e);
205
- child.stdout.end();
206
- child.stderr.end();
207
- child.emit("close", 0);
208
- }
209
-
210
55
  // ============================================================
211
56
  // 辅助:service 构造(与旧 setup 等价,但不再装配 fakeSdk)
212
57
  // ============================================================
@@ -225,7 +70,7 @@ interface SetupResult {
225
70
 
226
71
  function setup(): SetupResult {
227
72
  const agentDir = "/tmp/nest-it"; // fs 已 mock,路径不需真实存在
228
- const modelService = new ModelConfigService({ agentDir });
73
+ const modelService = new ModelConfigService({ agentDir, cwd: agentDir });
229
74
  modelService.initModel({
230
75
  modelRegistry: makeEmptyRegistry(),
231
76
  sessionId: "nest-it",
@@ -242,7 +87,8 @@ function setup(): SetupResult {
242
87
 
243
88
  const ctxModel: ModelInfo = { id: "m", name: "M", provider: "p", reasoning: false };
244
89
 
245
- /** execCtxAls.run 的 duck-type(绕过 import AsyncLocalStorage,足够本组用例)。 */
90
+ /** [D3-⑤] execNesting(公共层 ExecutionNestingContext).run 的 duck-type(绕过
91
+ * import AsyncLocalStorage,足够本组用例——私字段经 Reflect 取,机制与旧 execCtxAls 同构)。 */
246
92
  interface ExecCtxAls {
247
93
  run: <T>(store: { recordId: string | undefined; depth: number }, cb: () => T) => T;
248
94
  }
@@ -262,12 +108,12 @@ describe("嵌套护栏 / 并发池 / 节流(D-030~D-033 回归锁)", () => {
262
108
  const pool = Reflect.get(service, "pool") as { acquire: ReturnType<typeof vi.fn>; release: ReturnType<typeof vi.fn> };
263
109
  const acquireSpy = vi.spyOn(pool, "acquire");
264
110
 
265
- const execPromise = service.execute({ task: "bg in pool", ctxModel });
111
+ const execPromise = service.execute({ task: "bg in pool", slug: "test", ctxModel });
266
112
  // detached runAndFinalize → acquire。等 spawn 拿到 child 再驱动完成。
267
113
  await waitForSpawn(mockSpawn);
268
- await driveChildToCompletion(lastSpawnedChild());
114
+ await driveChildToCompletion(lastSpawnedChild(mockSpawn));
269
115
 
270
- // 等 detached promise 链跑完(kickOffBackground 的 .then notify)
116
+ // 等 detached promise 链跑完(kickOffChatRound 的 .then notify)
271
117
  await new Promise<void>((r) => setTimeout(r, 10));
272
118
 
273
119
  expect(acquireSpy).toHaveBeenCalled();
@@ -283,16 +129,16 @@ describe("嵌套护栏 / 并发池 / 节流(D-030~D-033 回归锁)", () => {
283
129
  it("[D-033] execCtxAls depth=MAX 时 execute 抛错(nestingDepth=MAX+1 被拒)", async () => {
284
130
  const { service } = setup();
285
131
 
286
- const execCtxAls = Reflect.get(service, "execCtxAls") as ExecCtxAls;
132
+ const execNesting = Reflect.get(service, "execNesting") as ExecCtxAls;
287
133
 
288
134
  await expect(
289
- execCtxAls.run({ recordId: "parent", depth: MAX_FORK_DEPTH }, () =>
290
- service.execute({ task: "too deep", ctxModel }),
135
+ execNesting.run({ recordId: "parent", depth: MAX_FORK_DEPTH }, () =>
136
+ service.execute({ task: "too deep", slug: "test", ctxModel }),
291
137
  ),
292
138
  ).rejects.toThrow(/nesting depth/);
293
139
 
294
140
  // 无副作用:guard 在 createRecordForMode 之前,record 未创建
295
- expect(service.collectRecords(10)).toHaveLength(0);
141
+ expect(service.queries.collectRecords(10)).toHaveLength(0);
296
142
  // guard 在 spawn 之前——不应 spawn 任何子进程
297
143
  expect(mockSpawn).not.toHaveBeenCalled();
298
144
  });
@@ -300,13 +146,13 @@ describe("嵌套护栏 / 并发池 / 节流(D-030~D-033 回归锁)", () => {
300
146
  it("[D-033] execCtxAls depth=MAX-1 时 execute 不抛(nestingDepth=MAX 允许)", async () => {
301
147
  const { service } = setup();
302
148
 
303
- const execCtxAls = Reflect.get(service, "execCtxAls") as ExecCtxAls;
149
+ const execNesting = Reflect.get(service, "execNesting") as ExecCtxAls;
304
150
 
305
- const execPromise = execCtxAls.run({ recordId: "parent", depth: MAX_FORK_DEPTH - 1 }, () =>
306
- service.execute({ task: "at limit", ctxModel }),
151
+ const execPromise = execNesting.run({ recordId: "parent", depth: MAX_FORK_DEPTH - 1 }, () =>
152
+ service.execute({ task: "at limit", slug: "test", ctxModel }),
307
153
  );
308
154
  await waitForSpawn(mockSpawn);
309
- await driveChildToCompletion(lastSpawnedChild(), [
155
+ await driveChildToCompletion(lastSpawnedChild(mockSpawn), [
310
156
  { type: "turn_end" },
311
157
  { type: "message_end", message: { usage: { input: 1 } } },
312
158
  ]);