@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,8 +5,17 @@
5
5
  // (usage 收口进 getTotalUsage,text 收口进 getFullText,均在 execution-record.test 测)。
6
6
  import { describe, expect, it } from "vitest";
7
7
 
8
- import { isStaleContextErrorMsg, DETERMINISTIC_SCHEMA_FAILURE_PREFIX, isDeterministicSchemaFailureMsg, STALE_CONTEXT_PATTERNS } from "../../orchestration/execute-agent-call.ts";
9
- import { collectResult, describeMissingParsedOutput, extractParsedOutput, neutralizeStalePatterns } from "../output-collector.ts";
8
+ import {
9
+ classifyFailureKind,
10
+ collectResult,
11
+ describeMissingParsedOutput,
12
+ DETERMINISTIC_SCHEMA_FAILURE_PREFIX,
13
+ extractParsedOutput,
14
+ isDeterministicSchemaFailureMsg,
15
+ isStaleContextErrorMsg,
16
+ neutralizeStalePatterns,
17
+ STALE_CONTEXT_PATTERNS,
18
+ } from "../engine/engines/pi/output-collector.ts";
10
19
  import type { ExecutionRecord, ToolCall } from "../types.ts";
11
20
 
12
21
  // ============================================================
@@ -162,9 +171,9 @@ describe("describeMissingParsedOutput", () => {
162
171
  // ── [F-R1] 态2(isError 分支)错误摘要拼接段中和 ──
163
172
  //
164
173
  // 动态错误文本(模型/provider 原始错误)可能携带 "aborted"/"ctx is stale" 等
165
- // STALE_CONTEXT_PATTERNS 词;不中和则归因 error 经 collectResult → result.error
166
- // 流到 execute-agent-call 的 isStaleContextErrorMsg 分诊,被误诊为 stale-context
167
- // 跳过重试。固定前缀静态无命中(上一用例锁定),中和只针对动态段。
174
+ // STALE_CONTEXT_PATTERNS 词;不中和则归因 error 经 collectResult
175
+ // classifyFailureKind 分诊被误标 stale_context(归因语义被污染)。
176
+ // 固定前缀静态无命中(上一用例锁定),中和只针对动态段。
168
177
  describe("F-R1: 态2 错误摘要 STALE_CONTEXT_PATTERNS 中和", () => {
169
178
  function failedSoCallsWith(text: string): ToolCall[] {
170
179
  return [
@@ -233,7 +242,7 @@ describe("describeMissingParsedOutput", () => {
233
242
  // ============================================================
234
243
 
235
244
  describe("MF-1: 三态可重试性矩阵(确定性失败标记)", () => {
236
- // 矩阵(SSOT 注释在 execute-agent-call DETERMINISTIC_SCHEMA_FAILURE_PREFIX 与
245
+ // 矩阵(SSOT 注释在本模块 DETERMINISTIC_SCHEMA_FAILURE_PREFIX 与
237
246
  // describeMissingParsedOutput JSDoc,本 describe 是执行面锁定):
238
247
  // 态① 从未调用 SO → 带标记 → 不可重试(环境确定性,C1 安装盲区)
239
248
  // 态② SO isError(gate 终止/不可满足 schema)→ 带标记 → 不可重试(同 schema 重试必同结果)
@@ -356,3 +365,105 @@ describe("collectResult — F-1 schemaExpected 失败标注", () => {
356
365
  expect(isDeterministicSchemaFailureMsg(result.error)).toBe(true);
357
366
  });
358
367
  });
368
+
369
+ // ============================================================
370
+ // D5-③: failureKind 分类(产出侧单点识别)
371
+ // ============================================================
372
+
373
+ describe("classifyFailureKind(词表 → 结构化标签)", () => {
374
+ it("pi 真实 stale 文案 → stale_context", () => {
375
+ const piRealStale =
376
+ "This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession().";
377
+ expect(classifyFailureKind(piRealStale)).toBe("stale_context");
378
+ });
379
+
380
+ it("abort 族(context canceled / aborted)→ stale_context", () => {
381
+ expect(classifyFailureKind("Request context canceled by provider")).toBe("stale_context");
382
+ expect(classifyFailureKind("Subprocess aborted by runtime shutdown")).toBe("stale_context");
383
+ });
384
+
385
+ it("确定性 schema 失败标记前缀 → schema_deterministic", () => {
386
+ expect(classifyFailureKind(
387
+ `${DETERMINISTIC_SCHEMA_FAILURE_PREFIX} Agent finished without producing a structured output`,
388
+ )).toBe("schema_deterministic");
389
+ });
390
+
391
+ it("未知文案(词表零命中,pi 升级改写文案后的形态)→ unknown(安全默认,可重试)", () => {
392
+ expect(classifyFailureKind("provider 503 service unavailable")).toBe("unknown");
393
+ expect(classifyFailureKind("spawn EAGAIN")).toBe("unknown");
394
+ expect(classifyFailureKind("extension runtime was superseded by a newer orchestration epoch")).toBe("unknown");
395
+ });
396
+
397
+ it("undefined(成功路径)→ undefined(不落失败分诊)", () => {
398
+ expect(classifyFailureKind(undefined)).toBeUndefined();
399
+ });
400
+
401
+ it("标记词与 stale 词表零交集(分诊优先级无歧义)", () => {
402
+ expect(classifyFailureKind(DETERMINISTIC_SCHEMA_FAILURE_PREFIX)).toBe("schema_deterministic");
403
+ });
404
+ });
405
+
406
+ describe("collectResult — D5-③ failureKind 产出", () => {
407
+ /** 最小 ExecutionRecord stub(collectResult 只读 turns/toolCalls 派生面)。 */
408
+ function makeRecordWithCalls(calls: ToolCall[]): ExecutionRecord {
409
+ return {
410
+ id: "rec-fk",
411
+ turns: [{ toolCalls: calls, text: "done", turnCount: 1, closed: true }],
412
+ turnCount: 1,
413
+ } as unknown as ExecutionRecord;
414
+ }
415
+
416
+ const baseArgs = {
417
+ startTime: Date.now(),
418
+ sessionId: "s-fk",
419
+ sessionFile: undefined,
420
+ };
421
+
422
+ it("error 命中 stale 词表 → failureKind=stale_context", () => {
423
+ const record = makeRecordWithCalls([]);
424
+ const result = collectResult(record, {
425
+ ...baseArgs,
426
+ success: false,
427
+ error: "This extension ctx is stale after session replacement or reload.",
428
+ });
429
+ expect(result.failureKind).toBe("stale_context");
430
+ });
431
+
432
+ it("F-1 归因覆写(态①②确定性标记)→ failureKind=schema_deterministic", () => {
433
+ const record = makeRecordWithCalls([]);
434
+ const result = collectResult(record, { ...baseArgs, success: true, error: undefined, schemaExpected: true });
435
+ expect(result.error).toBeDefined();
436
+ expect(result.failureKind).toBe("schema_deterministic");
437
+ });
438
+
439
+ it("态③归因(调用过但无 details,无标记)→ failureKind=unknown(可重试,矩阵保留)", () => {
440
+ const record = makeRecordWithCalls([
441
+ { toolName: "structured-output", result: { content: [] } },
442
+ ]);
443
+ const result = collectResult(record, { ...baseArgs, success: true, error: undefined, schemaExpected: true });
444
+ expect(result.error).toBeDefined();
445
+ expect(result.failureKind).toBe("unknown");
446
+ });
447
+
448
+ it("普通 provider 错误 → failureKind=unknown", () => {
449
+ const record = makeRecordWithCalls([]);
450
+ const result = collectResult(record, { ...baseArgs, success: false, error: "provider boom 5xx" });
451
+ expect(result.failureKind).toBe("unknown");
452
+ });
453
+
454
+ it("成功路径(error undefined)→ failureKind 不写(缺省 = unknown = 可重试,消费侧语义)", () => {
455
+ const record = makeRecordWithCalls([]);
456
+ const result = collectResult(record, { ...baseArgs, success: true, error: undefined });
457
+ expect(result.failureKind).toBeUndefined();
458
+ });
459
+
460
+ it("词表漂移失效模式:未知文案(未来 pi 形态)→ failureKind=unknown(保守重试,非静默漏诊)", () => {
461
+ const record = makeRecordWithCalls([]);
462
+ const result = collectResult(record, {
463
+ ...baseArgs,
464
+ success: false,
465
+ error: "extension runtime was superseded by a newer orchestration epoch",
466
+ });
467
+ expect(result.failureKind).toBe("unknown");
468
+ });
469
+ });
@@ -3,10 +3,42 @@ import * as fs from "node:fs";
3
3
  import * as os from "node:os";
4
4
  import * as path from "node:path";
5
5
 
6
- import { afterEach, describe, expect, it } from "vitest";
7
-
8
- import { getPiInvocation } from "../pi-invocation.ts";
9
- import { RELAY_ENV_NODE, RELAY_ENV_SCRIPT, RELAY_ENV_SOCKET } from "../relay-env.ts";
6
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
7
+
8
+ import { getPiInvocation } from "../engine/engines/pi/pi-invocation.ts";
9
+ import {
10
+ RELAY_ENV_NODE,
11
+ RELAY_ENV_RECORD_ID,
12
+ RELAY_ENV_SCRIPT,
13
+ RELAY_ENV_SESSION_ID,
14
+ RELAY_ENV_SOCKET,
15
+ } from "../relay-env.ts";
16
+
17
+ // [验收门修复] getPiInvocation 的 relay 分支优先读宿主 RELAY env——根级 pnpm test
18
+ // 进程若继承宿主(pi 子进程链)的 RELAY 身份,直连分支用例的 execPath/argv 断言
19
+ // 会被改道(非自免疫,依赖 runner 环境)。文件级钩子对全部用例统一消毒:beforeEach
20
+ // 删五键、afterEach 恢复原值——有泄漏无泄漏双向绿;第二组 relay 分支用例自设
21
+ // RELAY_FULL 在清理之后执行,语义不受影响。
22
+ const RELAY_ENV_KEYS = [
23
+ RELAY_ENV_SOCKET,
24
+ RELAY_ENV_NODE,
25
+ RELAY_ENV_SCRIPT,
26
+ RELAY_ENV_SESSION_ID,
27
+ RELAY_ENV_RECORD_ID,
28
+ ] as const;
29
+ let savedRelayEnv: Record<string, string | undefined>;
30
+ beforeEach(() => {
31
+ savedRelayEnv = {};
32
+ for (const key of RELAY_ENV_KEYS) savedRelayEnv[key] = process.env[key];
33
+ for (const key of RELAY_ENV_KEYS) delete process.env[key];
34
+ });
35
+ afterEach(() => {
36
+ for (const key of RELAY_ENV_KEYS) {
37
+ const value = savedRelayEnv[key];
38
+ if (value === undefined) delete process.env[key];
39
+ else process.env[key] = value;
40
+ }
41
+ });
10
42
 
11
43
  describe("getPiInvocation", () => {
12
44
  const originalArgv = process.argv;
@@ -0,0 +1,102 @@
1
+ // src/execution/__tests__/record-entry-collect.test.ts
2
+ //
3
+ // subagent-record entry 序列化白名单:collectMode / batchFinalized 两字段
4
+ // (subagent-sync-collect U1 foundation)。
5
+ //
6
+ // 锁三件事(设计 §3.1.3):
7
+ // 1. 持久化:两字段在 entry data 中如实透传(round-trip 经 JSON 序列化不丢);
8
+ // 2. 零迁移:无字段(旧 record 形态)的 entry 产物不含新键(JSON.stringify 自然缺省),
9
+ // 与改动前逐字节一致;
10
+ // 3. customType 稳定:SUBAGENT_RECORD_CUSTOM_TYPE 不因扩字段漂移。
11
+
12
+ import { describe, expect, it } from "vitest";
13
+
14
+ import {
15
+ SUBAGENT_RECORD_CUSTOM_TYPE,
16
+ toSubagentRecordEntry,
17
+ type SubagentRecordEntryData,
18
+ } from "../record-entry.ts";
19
+ import type { SubagentRecord } from "../types.ts";
20
+
21
+ /** 最小合法 SubagentRecord(缺省无 collect 两字段 = 旧记录形态)。 */
22
+ function makeRecord(over: Partial<SubagentRecord> = {}): SubagentRecord {
23
+ return {
24
+ id: "sa-1",
25
+ agent: "/home/u/agents/worker.md",
26
+ task: "t",
27
+ slug: "worker",
28
+ status: "running",
29
+ mode: "background",
30
+ startedAt: 1000,
31
+ rootSessionId: "root-A",
32
+ parentRecordId: undefined,
33
+ depth: 0,
34
+ endedAt: undefined,
35
+ turns: 1,
36
+ totalTokens: 42,
37
+ model: "prov/m1",
38
+ thinkingLevel: undefined,
39
+ eventLog: [],
40
+ displayItems: [],
41
+ sessionFile: "sess-1.jsonl",
42
+ ...over,
43
+ } as SubagentRecord;
44
+ }
45
+
46
+ /** entry data 的 JSONL 形态字符串(appendEntry 落盘即此产物)。 */
47
+ function serialize(entry: SubagentRecordEntryData): string {
48
+ return JSON.stringify(entry);
49
+ }
50
+
51
+ describe("record-entry serialization: collect fields (U1 foundation)", () => {
52
+ it("keeps SUBAGENT_RECORD_CUSTOM_TYPE stable", () => {
53
+ expect(SUBAGENT_RECORD_CUSTOM_TYPE).toBe("subagent-record");
54
+ });
55
+
56
+ it("passes collectMode through for a sync record", () => {
57
+ const entry = toSubagentRecordEntry(makeRecord({ collectMode: "sync" }));
58
+ expect(entry.collectMode).toBe("sync");
59
+ expect(entry.batchFinalized).toBeUndefined();
60
+ });
61
+
62
+ it("passes batchFinalized through for a member that left the batch", () => {
63
+ const entry = toSubagentRecordEntry(
64
+ makeRecord({
65
+ collectMode: "sync",
66
+ batchFinalized: true,
67
+ status: "closed",
68
+ endedAt: 2000,
69
+ }),
70
+ );
71
+ expect(entry.collectMode).toBe("sync");
72
+ expect(entry.batchFinalized).toBe(true);
73
+ expect(entry.status).toBe("closed");
74
+ });
75
+
76
+ it("round-trips both fields through JSON serialization (persisted form)", () => {
77
+ const entry = toSubagentRecordEntry(
78
+ makeRecord({ collectMode: "sync", batchFinalized: true }),
79
+ );
80
+ const revived = JSON.parse(serialize(entry)) as SubagentRecordEntryData;
81
+ expect(revived.collectMode).toBe("sync");
82
+ expect(revived.batchFinalized).toBe(true);
83
+ expect(revived.v).toBe(1);
84
+ });
85
+
86
+ it("emits no new keys for legacy records (旧记录零迁移)", () => {
87
+ const json = serialize(toSubagentRecordEntry(makeRecord()));
88
+ expect(json).not.toContain("collectMode");
89
+ expect(json).not.toContain("batchFinalized");
90
+ const revived = JSON.parse(json) as SubagentRecordEntryData;
91
+ expect(revived.collectMode).toBeUndefined();
92
+ expect(revived.batchFinalized).toBeUndefined();
93
+ });
94
+
95
+ it("still emits the full legacy whitelist for legacy records (既有字段不受扩字段影响)", () => {
96
+ const entry = toSubagentRecordEntry(makeRecord());
97
+ expect(entry.id).toBe("sa-1");
98
+ expect(entry.status).toBe("running");
99
+ expect(entry.model).toBe("prov/m1");
100
+ expect(entry.sessionFile).toBe("sess-1.jsonl");
101
+ });
102
+ });
@@ -52,8 +52,9 @@ function makeRecord(over: Partial<ExecutionRecord> = {}): ExecutionRecord {
52
52
  const base = createRecord("r1", {
53
53
  agent: "worker",
54
54
  model: "m",
55
- mode: "sync",
55
+ mode: "background",
56
56
  task: "t",
57
+ slug: "test",
57
58
  startedAt: 1000,
58
59
  rootSessionId: "sess-current",
59
60
  // 对齐生产 register 路径(subagent-service createRecord:one-shot 显式 false)
@@ -68,7 +69,7 @@ function makeRecord(over: Partial<ExecutionRecord> = {}): ExecutionRecord {
68
69
  */
69
70
  function writeSessionJsonl(
70
71
  filePath: string,
71
- identity: { id: string; agent: string; mode: "sync" | "background"; task: string; startedAt: number; rootSessionId?: string; parentRecordId?: string; depth?: number; lastTs?: number; chatMode?: boolean },
72
+ identity: { id: string; agent: string; mode: "background"; task: string; startedAt: number; rootSessionId?: string; parentRecordId?: string; depth?: number; lastTs?: number; chatMode?: boolean },
72
73
  assistantText = "result text",
73
74
  ): void {
74
75
  const lastTs = identity.lastTs ?? identity.startedAt + 1000;
@@ -138,7 +139,7 @@ describe("RecordStore", () => {
138
139
  describe("archive 立即移除", () => {
139
140
  it("archive 后 record 立即从内存移除(不再 linger)", () => {
140
141
  const store = new RecordStore(tmpDir);
141
- const r = makeRecord({ id: "sync-1", mode: "sync", status: "closed" });
142
+ const r = makeRecord({ id: "sync-1", mode: "background", status: "closed" });
142
143
  store.register(r);
143
144
  expect(store.getMutable("sync-1")).toBeDefined();
144
145
  store.archive(r);
@@ -1012,7 +1013,7 @@ describe("RecordStore", () => {
1012
1013
  // chatMode 必须显式在场(one-shot=false)——renderer isDone 判据依赖它。
1013
1014
  expect(Object.keys(data).sort()).toEqual([
1014
1015
  "agent", "chatMode", "depth", "displayItems", "eventLog",
1015
- "id", "mode", "model", "rootSessionId", "round", "startedAt",
1016
+ "id", "mode", "model", "rootSessionId", "round", "slug", "startedAt",
1016
1017
  "status", "task", "totalTokens", "turns", "v", "worktree",
1017
1018
  ]);
1018
1019
  expect(data).toMatchObject({
@@ -1021,7 +1022,7 @@ describe("RecordStore", () => {
1021
1022
  agent: "worker",
1022
1023
  task: "t",
1023
1024
  status: "running",
1024
- mode: "sync",
1025
+ mode: "background",
1025
1026
  startedAt: 1000,
1026
1027
  rootSessionId: "sess-current",
1027
1028
  chatMode: false,
@@ -1091,13 +1092,13 @@ describe("RecordStore", () => {
1091
1092
  writeSessionJsonl(path.join(tmpDir, "sa-ps14.jsonl"), {
1092
1093
  id: "ps14",
1093
1094
  agent: "worker",
1094
- mode: "sync",
1095
+ mode: "background",
1095
1096
  task: "t",
1096
1097
  startedAt: 1000,
1097
1098
  });
1098
1099
 
1099
1100
  const store = new RecordStore(tmpDir);
1100
- const records = store.collectRecords();
1101
+ const records = store.collectRecords(100);
1101
1102
  expect(records).toHaveLength(1); // 扫描本身不受索引写失败影响
1102
1103
 
1103
1104
  // fire-and-forget saveIndex:等 .catch 执行
@@ -1122,13 +1123,13 @@ describe("RecordStore", () => {
1122
1123
  writeSessionJsonl(path.join(tmpDir, "sa-ps14-ok.jsonl"), {
1123
1124
  id: "ps14ok",
1124
1125
  agent: "worker",
1125
- mode: "sync",
1126
+ mode: "background",
1126
1127
  task: "t",
1127
1128
  startedAt: 1000,
1128
1129
  });
1129
1130
 
1130
1131
  const store = new RecordStore(tmpDir);
1131
- store.collectRecords();
1132
+ store.collectRecords(100);
1132
1133
  await vi.waitFor(() => expect(saveIndexMock).toHaveBeenCalled());
1133
1134
 
1134
1135
  const warnIndexMsgs = loggerMock.warn.mock.calls.filter((c) =>
@@ -26,7 +26,7 @@ beforeEach(() => {
26
26
  });
27
27
 
28
28
  afterEach(() => {
29
- fs.rmSync(tmpAgentDir, { recursive: true, force: true });
29
+ fs.rmSync(tmpAgentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
30
30
  });
31
31
 
32
32
  /** 写一个最小合法的 manifest 到指定 records 目录。 */
@@ -36,7 +36,7 @@ function writeManifest(recordsDir: string, id: string): string {
36
36
  id,
37
37
  rootSessionId: "sess-1",
38
38
  agentName: "worker",
39
- status: "completed",
39
+ status: "closed",
40
40
  createdAt: Date.now(),
41
41
  };
42
42
  const filePath = path.join(recordsDir, `${id}.json`);
@@ -16,102 +16,32 @@
16
16
  // 4. forkDepth 基线:env PI_SUBAGENT_FORK_DEPTH → fork spawn env 递增
17
17
  //
18
18
  // mock 策略与 execute-nesting.test.ts 一致(spawn → FakeChild,fs 同步方法 mock,
19
- // temp-prompt / alive-store / finalized-marker / manifest-store mock)。
20
-
21
- import type { PassThrough } from "node:stream";
19
+ // temp-prompt / alive-store / finalized-marker / manifest-store mock;已收敛
20
+ // ./helpers/subagent-service-mocks.ts 四文件共享单源)。
22
21
 
23
22
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
24
23
 
25
- // ── mock modules(同 execute-nesting.test.ts)──
26
-
27
- vi.mock("node:child_process", async () => {
28
- const { EventEmitter } = await import("node:events");
29
- const { PassThrough } = await import("node:stream");
30
-
31
- class FakeChild extends EventEmitter {
32
- pid = 12345;
33
- stdout = new PassThrough();
34
- stderr = new PassThrough();
35
- killed = false;
36
- killSignal: string | undefined;
37
- kill(sig?: string): boolean {
38
- this.killed = true;
39
- this.killSignal = sig;
40
- return true;
41
- }
42
- }
43
-
44
- return {
45
- spawn: vi.fn(() => new FakeChild()),
46
- // buildEnvBlock 用 execFile 异步取 git branch:默认 err-first 兜底(catch → branch="")
47
- execFile: vi.fn(
48
- (
49
- _cmd: string,
50
- _args: readonly string[],
51
- _opts: unknown,
52
- cb: (err: Error | null, stdout?: string, stderr?: string) => void,
53
- ) => cb(new Error("execFile not configured in this test")),
54
- ),
55
- };
56
- });
24
+ import {
25
+ aliveStoreModule,
26
+ childProcessModule,
27
+ finalizedMarkerModule,
28
+ fsSyncModule,
29
+ manifestStoreModule,
30
+ tempPromptModule,
31
+ } from "./helpers/subagent-service-mocks.ts";
57
32
 
58
- vi.mock("node:fs", async () => {
59
- const actual = await import("node:fs");
60
- return {
61
- default: {
62
- ...actual,
63
- mkdirSync: vi.fn(),
64
- existsSync: vi.fn(() => false),
65
- appendFileSync: vi.fn(),
66
- writeFileSync: vi.fn(),
67
- readdirSync: vi.fn(() => []),
68
- },
69
- mkdirSync: vi.fn(),
70
- existsSync: vi.fn(() => false),
71
- appendFileSync: vi.fn(),
72
- writeFileSync: vi.fn(),
73
- readdirSync: vi.fn(() => []),
74
- promises: actual.promises,
75
- };
76
- });
77
-
78
- vi.mock("../alive-store.ts", async (importOriginal) => {
79
- const actual = await importOriginal<typeof import("../alive-store.ts")>();
80
- return {
81
- ...actual,
82
- writeAliveMarker: vi.fn(),
83
- removeAliveMarker: vi.fn(),
84
- };
85
- });
86
-
87
- vi.mock("../finalized-marker.ts", () => ({
88
- writeFinalized: vi.fn(),
89
- readFinalized: vi.fn(() => false),
90
- }));
91
-
92
- vi.mock("../manifest-store.ts", () => {
93
- class FakeManifestStore {
94
- writeManifest = vi.fn(async () => {});
95
- readManifest = vi.fn(async () => null);
96
- listAllSync = vi.fn(() => []);
97
- recoverTmpFiles = vi.fn(async () => []);
98
- }
99
- // vi.fn 包裹:构造参数(recordsDir)可从 mock.calls 断言([MF-3] 目录统一验证)。
100
- // 注意用普通 function(箭头函数不能被 new 调用)。
101
- return { ManifestStore: vi.fn(function (_recordsDir: string) { return new FakeManifestStore(); }) };
102
- });
33
+ // ── mock modules(同 execute-nesting.test.ts)──
103
34
 
104
- vi.mock("../temp-prompt.ts", () => ({
105
- writePromptToTempFile: vi.fn(async (agent: string) => {
106
- const safeName = agent.replace(/[^\w.-]+/g, "_");
107
- return { dir: `/tmp/fake-${safeName}`, filePath: `/tmp/fake-${safeName}/prompt-${safeName}.md` };
108
- }),
109
- cleanupTempPrompt: vi.fn(async () => {}),
110
- }));
35
+ vi.mock("node:child_process", () => childProcessModule());
36
+ vi.mock("node:fs", async (importOriginal) => fsSyncModule(await importOriginal<typeof import("node:fs")>()));
37
+ vi.mock("../alive-store.ts", async (importOriginal) => aliveStoreModule(await importOriginal<typeof import("../alive-store.ts")>()));
38
+ vi.mock("../finalized-marker.ts", () => finalizedMarkerModule());
39
+ vi.mock("../manifest-store.ts", () => manifestStoreModule());
40
+ vi.mock("../engine/engines/pi/temp-prompt.ts", () => tempPromptModule());
111
41
 
112
42
  import { spawn } from "node:child_process";
113
43
 
114
- import { waitForSpawn } from "./helpers/spawn-mock.ts";
44
+ import { waitForSpawn, lastSpawnedChild } from "./helpers/spawn-mock.ts";
115
45
  import { ModelConfigService } from "../model-config-service.ts";
116
46
  import type { ModelInfo, ModelRegistryLike } from "../model-resolver.ts";
117
47
  import { ManifestStore } from "../manifest-store.ts";
@@ -128,43 +58,10 @@ const ENV_DEPTH = "PI_SUBAGENT_DEPTH";
128
58
  const ENV_ROOT_CWD = "PI_SUBAGENT_ROOT_CWD";
129
59
  const ENV_FORK_DEPTH = "PI_SUBAGENT_FORK_DEPTH";
130
60
 
131
- interface FakeChild {
132
- pid: number;
133
- stdout: PassThrough;
134
- stderr: PassThrough;
135
- killed: boolean;
136
- killSignal: string | undefined;
137
- kill(sig?: string): boolean;
138
- emit(event: string, ...args: unknown[]): boolean;
139
- }
140
-
141
- function lastSpawnedChild(): FakeChild {
142
- const result = mockSpawn.mock.results.at(-1);
143
- if (!result) throw new Error("spawn was not called yet");
144
- return result.value as FakeChild;
145
- }
146
-
147
61
  function getLastSpawnEnv(): Record<string, string | undefined> {
148
62
  return (mockSpawn.mock.calls.at(-1)?.[2]?.env as Record<string, string | undefined>) ?? {};
149
63
  }
150
64
 
151
- function sessionHeader(id = "baseline-session"): Record<string, unknown> {
152
- return { type: "session", id, timestamp: "2026-08-11T00-00-00-000Z", cwd: "/tmp/test" };
153
- }
154
-
155
- function emitStdoutLine(child: FakeChild, obj: Record<string, unknown>): void {
156
- child.stdout.write(`${JSON.stringify(obj)}\n`);
157
- }
158
-
159
- /** 驱动 FakeChild 完成:header + 可选事件 + close(0)(runSpawn 自然 resolve)。 */
160
- async function driveChildToCompletion(child: FakeChild, events: Record<string, unknown>[] = []): Promise<void> {
161
- emitStdoutLine(child, sessionHeader());
162
- for (const e of events) emitStdoutLine(child, e);
163
- child.stdout.end();
164
- child.stderr.end();
165
- child.emit("close", 0);
166
- }
167
-
168
65
  // ── 辅助:service 构造 ──
169
66
 
170
67
  function makeEmptyRegistry(): ModelRegistryLike {
@@ -177,7 +74,7 @@ function makePi() {
177
74
 
178
75
  function setup(env: Record<string, string>): { service: SubagentService; store: RecordStore } {
179
76
  const agentDir = "/tmp/baseline-it";
180
- const modelService = new ModelConfigService({ agentDir });
77
+ const modelService = new ModelConfigService({ agentDir, cwd: agentDir });
181
78
  modelService.initModel({
182
79
  modelRegistry: makeEmptyRegistry(),
183
80
  sessionId: "baseline-it",
@@ -227,7 +124,7 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
227
124
  const { service, store } = setup({});
228
125
 
229
126
  // 不在 execCtxAls.run 内调用(模拟 ALS 断裂:事件回调上下文读不到 store)
230
- const handle = await service.execute({ task: "child of parent", ctxModel });
127
+ const handle = await service.execute({ task: "child of parent", slug: "test", ctxModel });
231
128
 
232
129
  const rec = store.collectRecords(10, "all", "root-main").find((r) => r.id === handle.subagentId);
233
130
  expect(rec).toBeDefined();
@@ -239,7 +136,7 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
239
136
  // 旧实现传 this.sessionId(子进程自己的 session id ≠ ROOT)→ 子进程内列表恒空。
240
137
  // 子进程的本进程 sessionId 是 "baseline-it"(initSession 注入),而 record 归属
241
138
  // root-main(env 贯穿的真 ROOT)——能查到即证明过滤用的是 sessionRootId。
242
- const viaService = service.collectRecords(10);
139
+ const viaService = service.queries.collectRecords(10);
243
140
  expect(viaService.map((r) => r.id)).toContain(handle.subagentId);
244
141
  expect(viaService[0]!.rootSessionId).toBe("root-main");
245
142
  });
@@ -247,7 +144,7 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
247
144
  it("[顶层] 无 env(根进程):parentRecordId undefined / depth 0", async () => {
248
145
  const { service, store } = setup({});
249
146
 
250
- const handle = await service.execute({ task: "top level", ctxModel });
147
+ const handle = await service.execute({ task: "top level", slug: "test", ctxModel });
251
148
 
252
149
  const rec = store.collectRecords(10, "all", "baseline-it").find((r) => r.id === handle.subagentId);
253
150
  expect(rec).toBeDefined();
@@ -261,10 +158,10 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
261
158
  process.env[ENV_DEPTH] = "0";
262
159
 
263
160
  const { service, store } = setup({});
264
- const execCtxAls = Reflect.get(service, "execCtxAls") as ExecCtxAls;
161
+ const execNesting = Reflect.get(service, "execNesting") as ExecCtxAls;
265
162
 
266
- const handle = await execCtxAls.run({ recordId: "sa-inline-parent", depth: 3 }, () =>
267
- service.execute({ task: "inline nested", ctxModel }),
163
+ const handle = await execNesting.run({ recordId: "sa-inline-parent", depth: 3 }, () =>
164
+ service.execute({ task: "inline nested", slug: "test", ctxModel }),
268
165
  );
269
166
 
270
167
  const rec = store.collectRecords(10, "all", "root-main").find((r) => r.id === handle.subagentId);
@@ -281,14 +178,14 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
281
178
 
282
179
  const { service } = setup({});
283
180
 
284
- const execPromise = service.execute({ task: "fork child", ctxModel, fork: true });
181
+ const execPromise = service.execute({ task: "fork child", slug: "test", ctxModel, fork: true });
285
182
  await waitForSpawn(mockSpawn);
286
183
  const childEnv = getLastSpawnEnv();
287
184
 
288
185
  // 742 行 parentDepth = forkDepthAls.getStore() ?? forkDepthBaseline —— ALS 断裂时基线=1,+1 → 2
289
186
  expect(childEnv.PI_SUBAGENT_FORK_DEPTH).toBe("2");
290
187
 
291
- const child = lastSpawnedChild();
188
+ const child = lastSpawnedChild(mockSpawn);
292
189
  child.emit("close", 0);
293
190
  await execPromise;
294
191
  });
@@ -303,7 +200,7 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
303
200
  // MAX_FORK_DEPTH 至少 > 5 才不会被误拒;这里验证基线参与计数的方式是
304
201
  // 用直接深度断言——execute 不抛错说明 nestingDepth=6 未超限,护栏不误伤。
305
202
  // (MAX_FORK_DEPTH 具体值由 session-context-resolver 定义,这里不硬编码。)
306
- await expect(service.execute({ task: "deep but allowed", ctxModel })).resolves.toBeDefined();
203
+ await expect(service.execute({ task: "deep but allowed", slug: "test", ctxModel })).resolves.toBeDefined();
307
204
  });
308
205
 
309
206
  it("[MF-3 回归] 有 ENV_ROOT_CWD(worktree 子进程):sessions 与 records 两套目录统一编码在 ROOT cwd 段", () => {
@@ -314,7 +211,7 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
314
211
 
315
212
  const agentDir = "/tmp/baseline-it";
316
213
  const checkoutPath = "/var/folders/worktree/pi-subagents/--root-project--/branch";
317
- const modelService = new ModelConfigService({ agentDir });
214
+ const modelService = new ModelConfigService({ agentDir, cwd: agentDir });
318
215
  modelService.initModel({
319
216
  modelRegistry: makeEmptyRegistry(),
320
217
  sessionId: "baseline-it",