@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
@@ -20,7 +20,7 @@ const { loggerMock, killEscalationSpy } = vi.hoisted(() => ({
20
20
  vi.mock("../../core/logger.ts", () => ({ getLogger: () => loggerMock }));
21
21
 
22
22
  // mock session-runner(import 链需要 runSpawn/killAllSpawnedChildren/getChildByRecord 存在)
23
- vi.mock("../session-runner.ts", () => ({
23
+ vi.mock("../engine/engines/pi/session-runner.ts", () => ({
24
24
  runSpawn: vi.fn(),
25
25
  killAllSpawnedChildren: vi.fn(),
26
26
  getChildByRecord: vi.fn(() => undefined),
@@ -30,12 +30,13 @@ vi.mock("../session-runner.ts", () => ({
30
30
  }));
31
31
 
32
32
  import { createRecord, updateFromEvent } from "../execution-record.ts";
33
+ import { createNotifyHost } from "../notify-host.ts";
33
34
  import { ModelConfigService } from "../model-config-service.ts";
34
35
  import { RecordStore } from "../record-store.ts";
35
36
  import { SubagentService } from "../subagent-service.ts";
36
37
  import type { PiLike } from "../subagent-service.ts";
37
38
  import type { ExecutionRecord } from "../types.ts";
38
- import { getChildByRecord } from "../session-runner.ts";
39
+ import { getChildByRecord } from "../engine/engines/pi/session-runner.ts";
39
40
 
40
41
  // [T2④] kill 收敛入口 spy(工厂引用,断言服务侧三条路径收敛到它)
41
42
  const killRecordChildWithEscalationMock = killEscalationSpy;
@@ -95,7 +96,7 @@ function setup(): {
95
96
  pi: MockPi;
96
97
  } {
97
98
  const agentDir = makeTmpAgentDir();
98
- const modelService = new ModelConfigService({ agentDir });
99
+ const modelService = new ModelConfigService({ agentDir, cwd: agentDir });
99
100
  const service = new SubagentService({ cwd: agentDir, modelService });
100
101
  // [C2] pi 提为外层引用(对照 real-chain :139-140 形态)——close 现状语义断言需读
101
102
  // pi.sendMessage.mock.calls(末条通知 content 指针行),内联构造不保留引用。
@@ -121,23 +122,23 @@ describe("getRecordForAction 归属守卫(决策 3)", () => {
121
122
 
122
123
  afterEach(() => {
123
124
  service.dispose();
124
- fs.rmSync(agentDir, { recursive: true, force: true });
125
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
125
126
  });
126
127
 
127
128
  it("正常(rootSessionId 匹配)→ 返回可变 record", () => {
128
129
  const record = makeRecord({ rootSessionId: sessionRootId });
129
130
  store.register(record);
130
- expect(service.getRecordForAction(record.id)).toBe(record);
131
+ expect(service.chatActions.getRecordForAction(record.id)).toBe(record);
131
132
  });
132
133
 
133
134
  it("不存在 → throw not found or not owned", () => {
134
- expect(() => service.getRecordForAction("sa-nonexistent")).toThrow(/not found or not owned/);
135
+ expect(() => service.chatActions.getRecordForAction("sa-nonexistent")).toThrow(/not found or not owned/);
135
136
  });
136
137
 
137
138
  it("rootSessionId 不匹配 → throw not found or not owned(不区分 not found vs not owned,防信息泄露)", () => {
138
139
  const record = makeRecord({ id: "sa-other", rootSessionId: "other-session" });
139
140
  store.register(record);
140
- expect(() => service.getRecordForAction("sa-other")).toThrow(/not found or not owned/);
141
+ expect(() => service.chatActions.getRecordForAction("sa-other")).toThrow(/not found or not owned/);
141
142
  });
142
143
  });
143
144
 
@@ -157,7 +158,7 @@ describe("closeSubagent 行为分流", () => {
157
158
 
158
159
  afterEach(() => {
159
160
  service.dispose();
160
- fs.rmSync(agentDir, { recursive: true, force: true });
161
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
161
162
  });
162
163
 
163
164
  it("running + force:false + 有活进程 → 置 closeAfterRound=true(不立即终态,等轮完)", async () => {
@@ -167,7 +168,7 @@ describe("closeSubagent 行为分流", () => {
167
168
  const record = makeRecord({ status: "running" });
168
169
  store.register(record);
169
170
 
170
- await service.closeSubagent(record, false);
171
+ await service.chatActions.closeSubagent(record, false);
171
172
 
172
173
  expect(record.closeAfterRound).toBe(true);
173
174
  expect(record.status).toBe("running"); // 仍 running
@@ -181,7 +182,7 @@ describe("closeSubagent 行为分流", () => {
181
182
  record.sessionFile = path.join(agentDir, "test.jsonl");
182
183
  store.register(record);
183
184
 
184
- await service.closeSubagent(record, false);
185
+ await service.chatActions.closeSubagent(record, false);
185
186
 
186
187
  expect(record.status).toBe("closed");
187
188
  expect(store.getMutable(record.id)).toBeUndefined(); // archived
@@ -191,7 +192,7 @@ describe("closeSubagent 行为分流", () => {
191
192
  const record = makeRecord({ status: "running", sessionFile: path.join(agentDir, "run.jsonl") });
192
193
  store.register(record);
193
194
 
194
- await service.closeSubagent(record, true);
195
+ await service.chatActions.closeSubagent(record, true);
195
196
 
196
197
  // v4 B-1:cancelled 折入 closed(closedReason='cancelled' 区分用户取消语义)
197
198
  expect(record.status).toBe("closed");
@@ -203,7 +204,7 @@ describe("closeSubagent 行为分流", () => {
203
204
  const record = makeRecord({ status: "closed" });
204
205
  store.register(record);
205
206
 
206
- await service.closeSubagent(record, false);
207
+ await service.chatActions.closeSubagent(record, false);
207
208
 
208
209
  expect(record.status).toBe("closed"); // 不变
209
210
  });
@@ -223,7 +224,7 @@ describe("closeSubagent 行为分流", () => {
223
224
  expect(hasIdleTimer(record.id)).toBe(true);
224
225
 
225
226
  try {
226
- await service.closeSubagent(record, false);
227
+ await service.chatActions.closeSubagent(record, false);
227
228
  } finally {
228
229
  disarmIdleTimer(record.id); // 断言失败路径的兜底清理
229
230
  }
@@ -242,7 +243,7 @@ describe("closeSubagent 行为分流", () => {
242
243
  record.sessionFile = path.join(agentDir, "path-b.jsonl");
243
244
  store.register(record);
244
245
 
245
- await service.closeSubagent(record, false);
246
+ await service.chatActions.closeSubagent(record, false);
246
247
 
247
248
  expect(record.status).toBe("closed");
248
249
  expect(record.closedReason).toBe("user-close");
@@ -269,7 +270,7 @@ describe("closeSubagent 行为分流", () => {
269
270
  expect(hasIdleTimer(record.id)).toBe(true);
270
271
 
271
272
  try {
272
- await service.closeSubagent(record, true);
273
+ await service.chatActions.closeSubagent(record, true);
273
274
  } finally {
274
275
  disarmIdleTimer(record.id); // 断言失败路径的兜底清理
275
276
  }
@@ -299,7 +300,7 @@ describe("cancelBackground CAS 抢锁(A2-1)——cancel 迟到不覆写已
299
300
 
300
301
  afterEach(() => {
301
302
  service.dispose();
302
- fs.rmSync(agentDir, { recursive: true, force: true });
303
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
303
304
  });
304
305
 
305
306
  it("record 已 closed 未 archive(doFinalizeRecord Step 0 await 窗口形态)→ cancel 返回 false,不覆写终态/不写 tombstone/不 notify/不 archive", () => {
@@ -354,7 +355,7 @@ describe("[M5] closeAfterRound 消费点挂 onRoundSettled(chatMode 轮完成
354
355
  afterEach(() => {
355
356
  service.dispose();
356
357
  _resetLifecycleState();
357
- fs.rmSync(agentDir, { recursive: true, force: true });
358
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
358
359
  });
359
360
 
360
361
  it("热路径轮完成(onRoundSettled)+ closeAfterRound=true → 消费标志终态化(closed+user-close + archive)", async () => {
@@ -428,7 +429,7 @@ describe("[C2] close 现状语义 + sessionFile 条件透传", () => {
428
429
  afterEach(() => {
429
430
  service.dispose();
430
431
  _resetLifecycleState();
431
- fs.rmSync(agentDir, { recursive: true, force: true });
432
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
432
433
  });
433
434
 
434
435
  it("close 语义:轮次通知(含指针行)发出后 closeAfterRoundSettled 终态化 + 终态通知,两条都送达", async () => {
@@ -473,8 +474,10 @@ describe("[C2] close 现状语义 + sessionFile 条件透传", () => {
473
474
 
474
475
  // running + 无活进程(getChildByRecord mock undefined)→ isResumable 放行 →
475
476
  // 非 chatMode 映射 closed 通知,立即 flush(无其他 running background)
476
- const svc = service as unknown as { notifyComplete(r: ExecutionRecord): void };
477
- svc.notifyComplete(record);
477
+ // [D4-①] notifyComplete 已随通知簇搬至 notify-host——按轴直接构造(同 pi/store
478
+ // 注入,行为与经 Service 的原路径等价;dedup 集为空与单次调用断言相容)
479
+ createNotifyHost({ getPi: () => pi, listRunning: () => store.listRunning(), getIsIdle: () => undefined })
480
+ .notifyComplete(record);
478
481
 
479
482
  expect(pi.sendMessage).toHaveBeenCalledTimes(1);
480
483
  const msg = pi.sendMessage.mock.calls[0]![0] as {
@@ -493,8 +496,8 @@ describe("[C2] close 现状语义 + sessionFile 条件透传", () => {
493
496
  record.sessionFile = path.join(agentDir, "c2-chat.jsonl");
494
497
  store.register(record);
495
498
 
496
- const svc = service as unknown as { notifyComplete(r: ExecutionRecord): void };
497
- svc.notifyComplete(record);
499
+ createNotifyHost({ getPi: () => pi, listRunning: () => store.listRunning(), getIsIdle: () => undefined })
500
+ .notifyComplete(record);
498
501
 
499
502
  expect(pi.sendMessage).toHaveBeenCalledTimes(1);
500
503
  const msg = pi.sendMessage.mock.calls[0]![0] as {
@@ -526,7 +529,7 @@ describe("[C-4] onRoundSettled 轮次增量 + [C-1] close 终态通知", () => {
526
529
  afterEach(() => {
527
530
  service.dispose();
528
531
  _resetLifecycleState();
529
- fs.rmSync(agentDir, { recursive: true, force: true });
532
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
530
533
  });
531
534
 
532
535
  /** 真实回调链(与生产一致:agent_settled → onRoundSettled),turns 经 updateFromEvent 累积。 */
@@ -601,7 +604,7 @@ describe("[C-4] onRoundSettled 轮次增量 + [C-1] close 终态通知", () => {
601
604
  updateFromEvent(record, { type: "text_delta", delta: "LAST-ROUND-INCREMENT" });
602
605
  updateFromEvent(record, { type: "turn_end" });
603
606
  settleRound(record); // 第 1 条:轮次通知
604
- await service.closeSubagent(record, false); // idle close(D2 路径②)
607
+ await service.chatActions.closeSubagent(record, false); // idle close(D2 路径②)
605
608
  } finally {
606
609
  disarmIdleTimer(record.id);
607
610
  }
@@ -651,7 +654,7 @@ describe("[C-4] onRoundSettled 轮次增量 + [C-1] close 终态通知", () => {
651
654
  record.sessionFile = path.join(agentDir, "oneshot-close.jsonl");
652
655
  store.register(record);
653
656
 
654
- await service.closeSubagent(record, false); // resumable → closeChatIdle → notifyClosed 拒绝
657
+ await service.chatActions.closeSubagent(record, false); // resumable → closeChatIdle → notifyClosed 拒绝
655
658
 
656
659
  expect(record.status).toBe("closed");
657
660
  expect(pi.sendMessage).not.toHaveBeenCalled();
@@ -672,7 +675,7 @@ describe("[C-4] onRoundSettled 轮次增量 + [C-1] close 终态通知", () => {
672
675
  updateFromEvent(record, { type: "turn_end" });
673
676
  settleRound(record); // 轮终:onRoundSettled 写 record.result = "ok"
674
677
  expect(record.result).toBe("ok"); // 前提锚点:轮终真实值在位
675
- await service.closeSubagent(record, false); // idle close → completeRecord + archive
678
+ await service.chatActions.closeSubagent(record, false); // idle close → completeRecord + archive
676
679
  } finally {
677
680
  disarmIdleTimer(record.id);
678
681
  }
@@ -34,7 +34,7 @@ vi.mock("../alive-store.ts", () => ({
34
34
  findForeignLiveInstance: foreignLiveSpy,
35
35
  }));
36
36
 
37
- vi.mock("../session-runner.ts", () => ({
37
+ vi.mock("../engine/engines/pi/session-runner.ts", () => ({
38
38
  runSpawn: vi.fn(),
39
39
  killAllSpawnedChildren: vi.fn(),
40
40
  getChildByRecord: vi.fn(() => undefined),
@@ -63,7 +63,7 @@ function makePi(): PiLike {
63
63
 
64
64
  function setup(): { agentDir: string; service: SubagentService; store: RecordStore } {
65
65
  const agentDir = makeTmpAgentDir();
66
- const modelService = new ModelConfigService({ agentDir });
66
+ const modelService = new ModelConfigService({ agentDir, cwd: agentDir });
67
67
  const service = new SubagentService({ cwd: agentDir, modelService });
68
68
  service.initSession({ pi: makePi(), sessionId: "root-session" });
69
69
  const store = (service as unknown as { store: RecordStore }).store;
@@ -79,7 +79,7 @@ describe("T5① child process skips orphan recovery scan", () => {
79
79
  recover: ReturnType<typeof vi.spyOn>;
80
80
  entryOnly: ReturnType<typeof vi.spyOn>;
81
81
  } => {
82
- const modelService = new ModelConfigService({ agentDir });
82
+ const modelService = new ModelConfigService({ agentDir, cwd: agentDir });
83
83
  const svc = new SubagentService({ cwd: agentDir, modelService });
84
84
  const store = (svc as unknown as { store: RecordStore }).store;
85
85
  const recover = vi.spyOn(store, "recoverOrphanRecords").mockImplementation(() => {});
@@ -95,7 +95,7 @@ describe("T5① child process skips orphan recovery scan", () => {
95
95
  afterEach(() => {
96
96
  vi.unstubAllEnvs();
97
97
  vi.restoreAllMocks();
98
- fs.rmSync(agentDir, { recursive: true, force: true });
98
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
99
99
  });
100
100
 
101
101
  it("root process (no self-record env) runs the orphan recovery scan", () => {
@@ -120,6 +120,19 @@ describe("T5③ cold-lookup running candidate foreign-instance guard", () => {
120
120
  let store: RecordStore;
121
121
 
122
122
  beforeEach(() => {
123
+ // 身份 env 剥离:initSession 会把 PI_SUBAGENT_ROOT_SESSION_ID 读作 sessionRootId 基线
124
+ //(env 优先于入参 sessionId)——宿主进程(xyz-agent 子 agent 环境)泄漏的身份 env
125
+ // 会让「root-session」桩记录归属校验恒不匹配 → 冷查用例误红(与 collect-coordinator-
126
+ // service.test.ts 同款剥离纪律)。
127
+ for (const k of [
128
+ "PI_SUBAGENT_ROOT_SESSION_ID",
129
+ "PI_SUBAGENT_SELF_RECORD_ID",
130
+ "PI_SUBAGENT_DEPTH",
131
+ "PI_SUBAGENT_ROOT_CWD",
132
+ "PI_SUBAGENT_FORK_DEPTH",
133
+ ] as const) {
134
+ delete process.env[k];
135
+ }
123
136
  foreignLiveSpy.mockReset();
124
137
  foreignLiveSpy.mockReturnValue(undefined);
125
138
  ({ agentDir, service, store } = setup());
@@ -127,7 +140,7 @@ describe("T5③ cold-lookup running candidate foreign-instance guard", () => {
127
140
 
128
141
  afterEach(() => {
129
142
  vi.restoreAllMocks();
130
- fs.rmSync(agentDir, { recursive: true, force: true });
143
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
131
144
  });
132
145
 
133
146
  const stubColdCandidate = (record: {
@@ -150,9 +163,9 @@ describe("T5③ cold-lookup running candidate foreign-instance guard", () => {
150
163
  });
151
164
  foreignLiveSpy.mockReturnValue({ pid: 4242, id: "sa-foreign", startedAt: Date.now() });
152
165
 
153
- expect(() => service.getRecordForAction("sa-foreign")).toThrow(ResurrectDeniedError);
166
+ expect(() => service["getRecordForAction"]("sa-foreign")).toThrow(ResurrectDeniedError);
154
167
  try {
155
- service.getRecordForAction("sa-foreign");
168
+ service["getRecordForAction"]("sa-foreign");
156
169
  } catch (err) {
157
170
  expect((err as Error).message).toContain("4242");
158
171
  expect((err as Error).message).toContain("double-write");
@@ -168,7 +181,7 @@ describe("T5③ cold-lookup running candidate foreign-instance guard", () => {
168
181
  sessionFile: "/tmp/fake-session-2.jsonl",
169
182
  rootSessionId: "root-session",
170
183
  });
171
- const found = service.getRecordForAction("sa-cold");
184
+ const found = service["getRecordForAction"]("sa-cold");
172
185
  expect(found.id).toBe("sa-cold");
173
186
  });
174
187
  });
@@ -1,7 +1,7 @@
1
1
  // src/execution/__tests__/subagent-service-notify-gate.test.ts
2
2
  //
3
3
  // [u-svc / T4] 通知可靠性(subagent-service 侧三措施):
4
- // - T4①/PS-2:kickOffBackground.then notify 门按 closedReason 白名单放行——
4
+ // - T4①/PS-2:kickOffChatRound.then notify 门按 closedReason 白名单放行——
5
5
  // parent-new/parent-fork 不注入(可能已切换的)新 session(A-6 决策落实);
6
6
  // - T4②/PS-4:idleTimeoutMs 非法值(>2^31-1 / 非有限值)在 spawn 入口同步 fail-fast,
7
7
  // 错误含合法范围(不静默 clamp、不静默不挂);
@@ -23,7 +23,7 @@ const { loggerMock } = vi.hoisted(() => ({
23
23
  vi.mock("../../core/logger.ts", () => ({ getLogger: () => loggerMock }));
24
24
 
25
25
  const { killChildSpy } = vi.hoisted(() => ({ killChildSpy: vi.fn() }));
26
- vi.mock("../session-runner.ts", () => ({
26
+ vi.mock("../engine/engines/pi/session-runner.ts", () => ({
27
27
  runSpawn: vi.fn(),
28
28
  killAllSpawnedChildren: vi.fn(),
29
29
  getChildByRecord: vi.fn(() => undefined),
@@ -76,7 +76,7 @@ function setup(initOverrides: Partial<{ isIdle: () => boolean }> = {}): {
76
76
  pi: MockPi;
77
77
  } {
78
78
  const agentDir = makeTmpAgentDir();
79
- const modelService = new ModelConfigService({ agentDir });
79
+ const modelService = new ModelConfigService({ agentDir, cwd: agentDir });
80
80
  const service = new SubagentService({ cwd: agentDir, modelService });
81
81
  const pi = makePi();
82
82
  service.initSession({ pi, sessionId: "root-session", isIdle: initOverrides.isIdle });
@@ -95,18 +95,19 @@ describe("T4① notify gate closedReason whitelist", () => {
95
95
  expect(notifyGateAllowsDelivery(undefined)).toBe(true);
96
96
  });
97
97
 
98
- it("kickOffBackground.then does not inject parent-new closed records into the session", async () => {
98
+ it("kickOffChatRound.then does not inject parent-new closed records into the session", async () => {
99
99
  const { agentDir, service, pi } = setup();
100
100
  const record = createRecord("sa-gate-new", {
101
101
  agent: "general-purpose",
102
102
  model: "test/model",
103
103
  mode: "background",
104
+ slug: "t",
104
105
  task: "test",
105
106
  startedAt: 1000,
106
107
  rootSessionId: "root-session",
107
108
  controller: new AbortController(),
108
109
  });
109
- // 模拟 disposeAllRecords 先行编排性关闭后,迟到的 kickOffBackground.then 回注
110
+ // 模拟 disposeAllRecords 先行编排性关闭后,迟到的 kickOffChatRound.then 回注
110
111
  record.closedReason = "parent-new";
111
112
  const stub = vi.fn().mockResolvedValue({
112
113
  text: "",
@@ -118,23 +119,27 @@ describe("T4① notify gate closedReason whitelist", () => {
118
119
  toolCalls: [],
119
120
  });
120
121
  (service as unknown as Record<string, unknown>).runAndFinalize = stub;
121
- const kickOffBackground = (
122
+ // [D4 后形态] 轮次编排入口 kickOffChatRound(私有,bracket 调用先例见
123
+ // subagent-service-recovery-bounds.test.ts privateFn);opts 形参仍是 ExecuteOptions
124
+ //(task/slug),chat 分支由 ticket lossless 携带——task 声明形参不参与校验。
125
+ const kickOffChatRound = (
122
126
  service as unknown as Record<string, (...args: unknown[]) => void>
123
- )["kickOffBackground"];
124
- kickOffBackground.call(service, record, { task: "t" }, {}, {}, undefined, 1000, undefined);
127
+ )["kickOffChatRound"];
128
+ kickOffChatRound.call(service, record, { task: "t", slug: "gate" }, {}, {}, undefined, 1000, undefined);
125
129
  await vi.waitFor(() => expect(stub).toHaveBeenCalled());
126
130
  await Promise.resolve();
127
131
  await Promise.resolve();
128
132
  expect(pi.sendMessage).not.toHaveBeenCalled();
129
- fs.rmSync(agentDir, { recursive: true, force: true });
133
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
130
134
  });
131
135
 
132
- it("kickOffBackground.then still notifies for real failure closures (gc)", async () => {
136
+ it("kickOffChatRound.then still notifies for real failure closures (gc)", async () => {
133
137
  const { agentDir, service, pi } = setup();
134
138
  const record = createRecord("sa-gate-gc", {
135
139
  agent: "general-purpose",
136
140
  model: "test/model",
137
141
  mode: "background",
142
+ slug: "t",
138
143
  task: "test",
139
144
  startedAt: 1000,
140
145
  rootSessionId: "root-session",
@@ -142,12 +147,12 @@ describe("T4① notify gate closedReason whitelist", () => {
142
147
  });
143
148
  record.closedReason = "gc";
144
149
  (service as unknown as Record<string, unknown>).runAndFinalize = vi.fn().mockResolvedValue({});
145
- const kickOffBackground = (
150
+ const kickOffChatRound = (
146
151
  service as unknown as Record<string, (...args: unknown[]) => void>
147
- )["kickOffBackground"];
148
- kickOffBackground.call(service, record, { task: "t" }, {}, {}, undefined, 1000, undefined);
152
+ )["kickOffChatRound"];
153
+ kickOffChatRound.call(service, record, { task: "t", slug: "gate" }, {}, {}, undefined, 1000, undefined);
149
154
  await vi.waitFor(() => expect(pi.sendMessage).toHaveBeenCalled());
150
- fs.rmSync(agentDir, { recursive: true, force: true });
155
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
151
156
  });
152
157
  });
153
158
 
@@ -160,30 +165,30 @@ describe("T4② idleTimeoutMs entry fail-fast", () => {
160
165
  });
161
166
 
162
167
  afterEach(() => {
163
- fs.rmSync(agentDir, { recursive: true, force: true });
168
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
164
169
  });
165
170
 
166
171
  it("execute rejects idleTimeoutMs above the setTimeout limit with the valid range in the message", async () => {
167
- await expect(service.execute({ task: "x", idleTimeoutMs: MAX_TIMER_DELAY_MS + 1 })).rejects.toThrow(
172
+ await expect(service.execute({ task: "x", slug: "test", idleTimeoutMs: MAX_TIMER_DELAY_MS + 1 })).rejects.toThrow(
168
173
  new RegExp(`${MAX_TIMER_DELAY_MS}`),
169
174
  );
170
- await expect(service.execute({ task: "x", idleTimeoutMs: 3_000_000_000 })).rejects.toThrow(/2\^31-1/);
175
+ await expect(service.execute({ task: "x", slug: "test", idleTimeoutMs: 3_000_000_000 })).rejects.toThrow(/2\^31-1/);
171
176
  });
172
177
 
173
178
  it("execute rejects non-finite idleTimeoutMs", async () => {
174
- await expect(service.execute({ task: "x", idleTimeoutMs: Number.NaN })).rejects.toThrow(/not a finite number/);
179
+ await expect(service.execute({ task: "x", slug: "test", idleTimeoutMs: Number.NaN })).rejects.toThrow(/not a finite number/);
175
180
  });
176
181
 
177
182
  it("rejects before any record is created (no side effects)", async () => {
178
183
  const internals = service as unknown as ServiceInternals;
179
- await expect(service.executeAndAwait({ task: "x", idleTimeoutMs: 3_000_000_000 })).rejects.toThrow();
184
+ await expect(service.executeAndAwait({ task: "x", slug: "test", idleTimeoutMs: 3_000_000_000 })).rejects.toThrow();
180
185
  expect(internals.store.listRunning()).toHaveLength(0);
181
186
  });
182
187
 
183
188
  it("accepts valid values (0 = explicit disable, positive within limit)", async () => {
184
189
  // 校验通过后执行链继续(runSpawn 被 mock,返回 undefined result 会在后续流程抛错/
185
190
  // 返回——但绝不能是 idleTimeoutMs 校验错误)
186
- await expect(service.execute({ task: "x", idleTimeoutMs: 0 })).rejects.not.toThrow(/idleTimeoutMs/);
191
+ await expect(service.execute({ task: "x", slug: "test", idleTimeoutMs: 0 })).rejects.not.toThrow(/idleTimeoutMs/);
187
192
  });
188
193
  });
189
194
 
@@ -199,7 +204,7 @@ describe("T4④ shutdown flush blocked → pending persisted for replay", () =>
199
204
 
200
205
  afterEach(() => {
201
206
  _resetNotifyLedgerForTest();
202
- fs.rmSync(agentDir, { recursive: true, force: true });
207
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
203
208
  });
204
209
 
205
210
  it("persists undelivered pending notifications as ledger entries on dispose when main agent is busy", () => {
@@ -256,7 +261,7 @@ describe("T4④ shutdown flush blocked → pending persisted for replay", () =>
256
261
  // idle service:flush 投出(无门拦),dispose 无复写动作
257
262
  const idleService = new SubagentService({
258
263
  cwd: agentDir,
259
- modelService: new ModelConfigService({ agentDir }),
264
+ modelService: new ModelConfigService({ agentDir, cwd: agentDir }),
260
265
  });
261
266
  const piIdle = makePi();
262
267
  idleService.initSession({ pi: piIdle, sessionId: "root-session", isIdle: () => true });
@@ -26,7 +26,7 @@ const { loggerMock } = vi.hoisted(() => ({
26
26
  vi.mock("../../core/logger.ts", () => ({ getLogger: () => loggerMock }));
27
27
 
28
28
  // mock session-runner(import 链需要 runSpawn/killAllSpawnedChildren/getChildByRecord 存在)
29
- vi.mock("../session-runner.ts", () => ({
29
+ vi.mock("../engine/engines/pi/session-runner.ts", () => ({
30
30
  runSpawn: vi.fn(),
31
31
  killAllSpawnedChildren: vi.fn(),
32
32
  getChildByRecord: vi.fn(() => undefined),
@@ -59,11 +59,12 @@ function makePi(): PiLike {
59
59
  } as unknown as PiLike;
60
60
  }
61
61
 
62
- /** 暴露私有字段供测试注入身份。 */
62
+ /** 暴露私有字段供测试注入身份。[D3-⑤] 基线住进 execNesting(公共层
63
+ * ExecutionNestingContext),注入经 setBaseline 测试面。 */
63
64
  interface ServiceInternals {
64
65
  store: RecordStore;
65
66
  sessionRootId: string | null;
66
- execCtxBaseline: { recordId: string | undefined; depth: number } | null;
67
+ execNesting: { setBaseline(state: { recordId: string | undefined; depth: number } | null): void };
67
68
  }
68
69
 
69
70
  /** 构造一个 chatMode idle record(message/close action 的典型目标态)。 */
@@ -77,12 +78,12 @@ function makeRecord(
77
78
  model: "test/model",
78
79
  mode: "background",
79
80
  task: "test",
80
- slug: "test",
81
81
  startedAt: 1000,
82
82
  rootSessionId: sessionRootId,
83
83
  chatMode: true,
84
84
  controller: new AbortController(),
85
85
  ...overrides,
86
+ slug: overrides.slug ?? "test",
86
87
  });
87
88
  }
88
89
 
@@ -95,7 +96,7 @@ describe("[v4 A-5 / P7] getRecordForAction 直接父校验", () => {
95
96
 
96
97
  beforeEach(() => {
97
98
  agentDir = makeTmpAgentDir();
98
- const modelService = new ModelConfigService({ agentDir });
99
+ const modelService = new ModelConfigService({ agentDir, cwd: agentDir });
99
100
  service = new SubagentService({ cwd: agentDir, modelService });
100
101
  // initSession 建立 sessionRootId=sessionId(本 session 树的根)。execCtxBaseline 的
101
102
  // 真实值由 initSession 从 env 读取(见 recursive-visibility-baseline.test.ts),但本测试
@@ -108,65 +109,65 @@ describe("[v4 A-5 / P7] getRecordForAction 直接父校验", () => {
108
109
 
109
110
  afterEach(() => {
110
111
  service.dispose();
111
- fs.rmSync(agentDir, { recursive: true, force: true });
112
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
112
113
  });
113
114
 
114
115
  // ---------- 身份 sa-A:直接父,放行孙级 B ----------
115
116
 
116
117
  it("身份=sa-A(直接父)→ 放行操作孙级 record B(parentRecordId=sa-A)", () => {
117
- const recordB = makeRecord("sa-B", sessionRootId, { parentRecordId: "sa-A", depth: 2, status: "idle" });
118
+ const recordB = makeRecord("sa-B", sessionRootId, { parentRecordId: "sa-A", depth: 2, status: "running" });
118
119
  store.register(recordB);
119
- internals.execCtxBaseline = PARENT_A;
120
+ internals.execNesting.setBaseline(PARENT_A);
120
121
 
121
- expect(service.getRecordForAction("sa-B")).toBe(recordB);
122
+ expect(service.chatActions.getRecordForAction("sa-B")).toBe(recordB);
122
123
  });
123
124
 
124
125
  // ---------- 身份 undefined(主进程):拒绝孙级,放行根层 ----------
125
126
 
126
127
  it("身份=undefined(主进程)拒绝孙级 record B,错误含 'direct parent' + 'parent=sa-A'", () => {
127
- const recordB = makeRecord("sa-B", sessionRootId, { parentRecordId: "sa-A", depth: 2, status: "idle" });
128
+ const recordB = makeRecord("sa-B", sessionRootId, { parentRecordId: "sa-A", depth: 2, status: "running" });
128
129
  store.register(recordB);
129
- internals.execCtxBaseline = MAIN_PROCESS;
130
+ internals.execNesting.setBaseline(MAIN_PROCESS);
130
131
 
131
- expect(() => service.getRecordForAction("sa-B")).toThrow(/direct parent/);
132
- expect(() => service.getRecordForAction("sa-B")).toThrow(/see \/subagents list, parent=sa-A/);
132
+ expect(() => service.chatActions.getRecordForAction("sa-B")).toThrow(/direct parent/);
133
+ expect(() => service.chatActions.getRecordForAction("sa-B")).toThrow(/see \/subagents list, parent=sa-A/);
133
134
  });
134
135
 
135
136
  it("身份=undefined(主进程)放行顶层 record(parentRecordId=undefined 视为根层)", () => {
136
- const topRecord = makeRecord("sa-top", sessionRootId, { parentRecordId: undefined, depth: 0, status: "idle" });
137
+ const topRecord = makeRecord("sa-top", sessionRootId, { parentRecordId: undefined, depth: 0, status: "running" });
137
138
  store.register(topRecord);
138
- internals.execCtxBaseline = MAIN_PROCESS;
139
+ internals.execNesting.setBaseline(MAIN_PROCESS);
139
140
 
140
- expect(service.getRecordForAction("sa-top")).toBe(topRecord);
141
+ expect(service.chatActions.getRecordForAction("sa-top")).toBe(topRecord);
141
142
  });
142
143
 
143
144
  // ---------- 身份 sa-B(兄弟进程):拒绝孙级 ----------
144
145
 
145
146
  it("身份=sa-B(兄弟进程)拒绝孙级 record B(parentRecordId=sa-A ≠ baseline sa-B)", () => {
146
- const recordB = makeRecord("sa-B", sessionRootId, { parentRecordId: "sa-A", depth: 2, status: "idle" });
147
+ const recordB = makeRecord("sa-B", sessionRootId, { parentRecordId: "sa-A", depth: 2, status: "running" });
147
148
  store.register(recordB);
148
- internals.execCtxBaseline = SIBLING_B;
149
+ internals.execNesting.setBaseline(SIBLING_B);
149
150
 
150
- expect(() => service.getRecordForAction("sa-B")).toThrow(/direct parent/);
151
- expect(() => service.getRecordForAction("sa-B")).toThrow(/see \/subagents list, parent=sa-A/);
151
+ expect(() => service.chatActions.getRecordForAction("sa-B")).toThrow(/direct parent/);
152
+ expect(() => service.chatActions.getRecordForAction("sa-B")).toThrow(/see \/subagents list, parent=sa-A/);
152
153
  });
153
154
 
154
155
  // ---------- 身份缺省语义 + 更深递归 ----------
155
156
 
156
157
  it("子进程(baseline=sa-A)拒绝顶层 record(身份缺省视为根层,仅主进程可操作)", () => {
157
- const topRecord = makeRecord("sa-top", sessionRootId, { parentRecordId: undefined, depth: 0, status: "idle" });
158
+ const topRecord = makeRecord("sa-top", sessionRootId, { parentRecordId: undefined, depth: 0, status: "running" });
158
159
  store.register(topRecord);
159
- internals.execCtxBaseline = PARENT_A;
160
+ internals.execNesting.setBaseline(PARENT_A);
160
161
 
161
- expect(() => service.getRecordForAction("sa-top")).toThrow(/direct parent/);
162
+ expect(() => service.chatActions.getRecordForAction("sa-top")).toThrow(/direct parent/);
162
163
  });
163
164
 
164
165
  it("P7 场景:主进程拒绝曾孙 record C(parentRecordId=sa-B),错误含 baseline=root + parent=sa-B", () => {
165
- const recordC = makeRecord("sa-C", sessionRootId, { parentRecordId: "sa-B", depth: 3, status: "idle" });
166
+ const recordC = makeRecord("sa-C", sessionRootId, { parentRecordId: "sa-B", depth: 3, status: "running" });
166
167
  store.register(recordC);
167
- internals.execCtxBaseline = MAIN_PROCESS;
168
+ internals.execNesting.setBaseline(MAIN_PROCESS);
168
169
 
169
- const fn = () => service.getRecordForAction("sa-C");
170
+ const fn = () => service.chatActions.getRecordForAction("sa-C");
170
171
  expect(fn).toThrow(/direct parent/);
171
172
  expect(fn).toThrow(/see \/subagents list, parent=sa-B/);
172
173
  expect(fn).toThrow(/baseline=\(root\)/);
@@ -174,10 +175,10 @@ describe("[v4 A-5 / P7] getRecordForAction 直接父校验", () => {
174
175
 
175
176
  it("rootSessionId 不匹配仍优先拒绝(直接父校验在 rootSessionId 校验之后,不绕过归属守卫)", () => {
176
177
  // 跨 session 树的 record:rootSessionId 不匹配 → 走首个 throw(not found or not owned)
177
- const foreignRecord = makeRecord("sa-foreign", "other-session", { parentRecordId: "sa-A", depth: 2, status: "idle" });
178
+ const foreignRecord = makeRecord("sa-foreign", "other-session", { parentRecordId: "sa-A", depth: 2, status: "running" });
178
179
  store.register(foreignRecord);
179
- internals.execCtxBaseline = PARENT_A;
180
+ internals.execNesting.setBaseline(PARENT_A);
180
181
 
181
- expect(() => service.getRecordForAction("sa-foreign")).toThrow(/not found or not owned/);
182
+ expect(() => service.chatActions.getRecordForAction("sa-foreign")).toThrow(/not found or not owned/);
182
183
  });
183
184
  });