@zhushanwen/subagent-core 0.2.0 → 0.5.1

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 (347) hide show
  1. package/README.md +45 -2
  2. package/agents/analyst.md +60 -0
  3. package/agents/coder.md +69 -0
  4. package/agents/debugger.md +66 -0
  5. package/agents/doc-reviewer.md +49 -0
  6. package/agents/explorer.md +63 -0
  7. package/agents/general-purpose.md +32 -0
  8. package/agents/orchestrator.md +61 -0
  9. package/agents/planner.md +53 -0
  10. package/agents/researcher.md +67 -0
  11. package/agents/reviewer.md +73 -0
  12. package/dist/chunk-43ONBFZX.js +240 -0
  13. package/dist/chunk-APZY4IME.js +27 -0
  14. package/dist/chunk-V3VHZ2VX.js +59 -0
  15. package/dist/execution/engine/engines/zcode/constants.cjs +62 -9
  16. package/dist/execution/engine/engines/zcode/constants.d.cts +116 -12
  17. package/dist/execution/engine/engines/zcode/constants.d.ts +116 -12
  18. package/dist/execution/engine/engines/zcode/constants.js +39 -7
  19. package/dist/execution/engine/engines/zcode/reader.d.cts +2 -1
  20. package/dist/execution/engine/engines/zcode/reader.d.ts +2 -1
  21. package/dist/execution/engine/engines/zcode/reader.js +4 -234
  22. package/dist/execution/engine/paths.js +7 -19
  23. package/dist/index.cjs +18234 -1277
  24. package/dist/index.d.cts +5646 -673
  25. package/dist/index.d.ts +5646 -673
  26. package/dist/index.js +17828 -1277
  27. package/dist/{types-BxyAidGf.d.cts → types-Dv4QhSJ_.d.cts} +678 -112
  28. package/dist/{types-BxyAidGf.d.ts → types-Dv4QhSJ_.d.ts} +678 -112
  29. package/package.json +7 -4
  30. package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
  31. package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
  32. package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
  33. package/src/__tests__/m2-append-content-probe.test.ts +0 -1
  34. package/src/__tests__/manifest-store.test.ts +10 -9
  35. package/src/__tests__/record-store-cache.test.ts +0 -2
  36. package/src/__tests__/record-store-index.test.ts +1 -2
  37. package/src/__tests__/review-fix-loop-script.test.ts +93 -3
  38. package/src/__tests__/review-fix-loop-utils.test.ts +31 -10
  39. package/src/__tests__/robustness-low-batch1.test.ts +6 -5
  40. package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
  41. package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
  42. package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
  43. package/src/__tests__/session-runner.test.ts +1 -1
  44. package/src/__tests__/smoke.test.ts +9 -2
  45. package/src/core/__tests__/host-services.test.ts +2 -2
  46. package/src/core/__tests__/logger.test.ts +1 -1
  47. package/src/core/error-message.ts +9 -0
  48. package/src/core/host-services.ts +21 -5
  49. package/src/core/notify-ports.ts +18 -5
  50. package/src/execution/__tests__/agent-profile.test.ts +232 -0
  51. package/src/execution/__tests__/agent-registry.test.ts +370 -0
  52. package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
  53. package/src/execution/__tests__/agents-assembly.test.ts +219 -0
  54. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
  55. package/src/execution/__tests__/chat-engine-routing.test.ts +136 -30
  56. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +5 -4
  57. package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
  58. package/src/execution/__tests__/create-concurrency-pool.test.ts +194 -0
  59. package/src/execution/__tests__/delivery-methods.test.ts +77 -62
  60. package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
  61. package/src/execution/__tests__/descendant-sweep.test.ts +269 -0
  62. package/src/execution/__tests__/dialog-queue.test.ts +199 -1
  63. package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
  64. package/src/execution/__tests__/epipe-fallback.test.ts +31 -24
  65. package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
  66. package/src/execution/__tests__/execute-nesting.test.ts +34 -188
  67. package/src/execution/__tests__/execution-record.test.ts +217 -60
  68. package/src/execution/__tests__/execution-runtime-face.test.ts +272 -0
  69. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +3 -3
  70. package/src/execution/__tests__/finalize-record.test.ts +278 -16
  71. package/src/execution/__tests__/gc-timer.test.ts +57 -2
  72. package/src/execution/__tests__/get-record-for-action-restart.test.ts +14 -12
  73. package/src/execution/__tests__/get-state-handshake.test.ts +127 -0
  74. package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
  75. package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
  76. package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
  77. package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
  78. package/src/execution/__tests__/keep-alive-no-progress.test.ts +280 -0
  79. package/src/execution/__tests__/kill-all-escalation.test.ts +196 -0
  80. package/src/execution/__tests__/lifecycle-manager-idle-timer-identity.test.ts +117 -0
  81. package/src/execution/__tests__/lifecycle-manager.test.ts +39 -0
  82. package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
  83. package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
  84. package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +99 -0
  85. package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +113 -0
  86. package/src/execution/__tests__/model-resolver.test.ts +2 -2
  87. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
  88. package/src/execution/__tests__/nested-visibility.test.ts +2 -0
  89. package/src/execution/__tests__/notify-ledger.test.ts +1249 -0
  90. package/src/execution/__tests__/output-collector.test.ts +117 -6
  91. package/src/execution/__tests__/pi-invocation.test.ts +1 -1
  92. package/src/execution/__tests__/record-store-orphan-revive.test.ts +159 -0
  93. package/src/execution/__tests__/record-store.test.ts +89 -5
  94. package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
  95. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
  96. package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
  97. package/src/execution/__tests__/rpc-mode.test.ts +2 -2
  98. package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
  99. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +19 -9
  100. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +5 -4
  101. package/src/execution/__tests__/run-spawn-edges.test.ts +418 -26
  102. package/src/execution/__tests__/run-spawn-integration.test.ts +3 -3
  103. package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
  104. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
  105. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +16 -8
  106. package/src/execution/__tests__/service-kill-escalation.test.ts +91 -0
  107. package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
  108. package/src/execution/__tests__/session-file-gc.test.ts +35 -0
  109. package/src/execution/__tests__/session-pending.test.ts +471 -0
  110. package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
  111. package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +110 -0
  112. package/src/execution/__tests__/session-runner-close-prune.test.ts +181 -0
  113. package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
  114. package/src/execution/__tests__/session-runner-epipe.test.ts +4 -3
  115. package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +227 -0
  116. package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
  117. package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
  118. package/src/execution/__tests__/settled-watchdog.test.ts +524 -0
  119. package/src/execution/__tests__/spawn-args.test.ts +11 -10
  120. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
  121. package/src/execution/__tests__/spawn-event-adapter.test.ts +1 -1
  122. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
  123. package/src/execution/__tests__/spawned-children.test.ts +155 -11
  124. package/src/execution/__tests__/start-sync-model-guard.test.ts +4 -4
  125. package/src/execution/__tests__/stdin-writer.test.ts +6 -4
  126. package/src/execution/__tests__/stream-sink-retirement.test.ts +6 -6
  127. package/src/execution/__tests__/subagent-actions-core.test.ts +1017 -0
  128. package/src/execution/__tests__/subagent-service-message-close.test.ts +99 -35
  129. package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +174 -0
  130. package/src/execution/__tests__/subagent-service-notify-gate.test.ts +271 -0
  131. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +33 -29
  132. package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +341 -0
  133. package/src/execution/__tests__/subagent-service.test.ts +37 -30
  134. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
  135. package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
  136. package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
  137. package/src/execution/__tests__/temp-prompt.test.ts +1 -1
  138. package/src/execution/__tests__/timeout-integration.test.ts +13 -12
  139. package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
  140. package/src/execution/__tests__/turn-limiter.test.ts +1 -1
  141. package/src/execution/__tests__/ui-request-handler-factory.test.ts +107 -7
  142. package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
  143. package/src/execution/__tests__/ui-request-queue.test.ts +167 -2
  144. package/src/execution/__tests__/worktree-git-ops.test.ts +571 -0
  145. package/src/execution/__tests__/worktree-manager.test.ts +14 -5
  146. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
  147. package/src/execution/__tests__/worktree-reconcile-aging.test.ts +204 -0
  148. package/src/execution/agent-registry.ts +298 -30
  149. package/src/execution/agent-result-mapper.ts +3 -0
  150. package/src/execution/agents-assembly.ts +88 -0
  151. package/src/execution/cold-resurrect.ts +199 -0
  152. package/src/execution/concurrency-pool.ts +71 -9
  153. package/src/execution/dialog-queue.ts +101 -3
  154. package/src/execution/engine/__tests__/common/capability-gate.test.ts +91 -0
  155. package/src/execution/engine/__tests__/common/data-dir.test.ts +1 -1
  156. package/src/execution/engine/__tests__/common/journal-wiring.test.ts +84 -0
  157. package/src/execution/engine/__tests__/common/kill-chain.test.ts +34 -7
  158. package/src/execution/engine/__tests__/common/persona-router.test.ts +4 -5
  159. package/src/execution/engine/__tests__/common/pool-manager.test.ts +211 -51
  160. package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +149 -0
  161. package/src/execution/engine/__tests__/common/session-view-service.test.ts +499 -0
  162. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +56 -99
  163. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +88 -15
  164. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +33 -7
  165. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +1 -1
  166. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +75 -54
  167. package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +128 -0
  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 +94 -3
  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/engine-discovery.ts +12 -16
  181. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +174 -28
  182. package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
  183. package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
  184. package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +86 -11
  185. package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
  186. package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
  187. package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
  188. package/src/execution/engine/engines/pi/reader.ts +11 -0
  189. package/src/execution/engine/engines/pi/registration.ts +4 -2
  190. package/src/execution/engine/engines/pi/session-runner.ts +2840 -0
  191. package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
  192. package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
  193. package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
  194. package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
  195. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +301 -0
  196. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json +36 -0
  197. package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
  198. package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +473 -0
  199. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
  200. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
  201. package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
  202. package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
  203. package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +792 -0
  204. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +782 -0
  205. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +168 -0
  206. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
  207. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
  208. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
  209. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
  210. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +65 -47
  211. package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
  212. package/src/execution/engine/engines/zcode/connection.ts +598 -0
  213. package/src/execution/engine/engines/zcode/constants.ts +147 -14
  214. package/src/execution/engine/engines/zcode/golden-sample.ts +42 -34
  215. package/src/execution/engine/engines/zcode/parser.ts +12 -346
  216. package/src/execution/engine/engines/zcode/preparer.ts +22 -150
  217. package/src/execution/engine/engines/zcode/session-channel.ts +968 -0
  218. package/src/execution/engine/engines/zcode/zcode-engine.ts +1023 -250
  219. package/src/execution/engine/host-task-spec.ts +32 -36
  220. package/src/execution/engine/model-validation.ts +177 -0
  221. package/src/execution/engine/port.ts +65 -7
  222. package/src/execution/engine/registry.ts +53 -0
  223. package/src/execution/engine/routing.ts +75 -1
  224. package/src/execution/engine/types.ts +30 -103
  225. package/src/execution/execution-record.ts +222 -144
  226. package/src/execution/finalize-record.ts +181 -85
  227. package/src/execution/idle-gc.ts +28 -0
  228. package/src/execution/lifecycle-manager.ts +27 -3
  229. package/src/execution/lifecycle-predicates.ts +1 -1
  230. package/src/execution/manifest-store.ts +53 -62
  231. package/src/execution/notifier.ts +10 -10
  232. package/src/execution/notify-host.ts +212 -0
  233. package/src/execution/notify-ledger.ts +117 -16
  234. package/src/execution/record-entry.ts +8 -2
  235. package/src/execution/record-store.ts +148 -88
  236. package/src/execution/round-settlement.ts +93 -0
  237. package/src/execution/session-file-gc.ts +96 -62
  238. package/src/execution/session-pending.ts +213 -62
  239. package/src/execution/session-reconstructor.ts +256 -143
  240. package/src/execution/sessions-index.ts +127 -102
  241. package/src/execution/settled-watchdog.ts +311 -0
  242. package/src/execution/subagent-actions-core.ts +686 -0
  243. package/src/execution/subagent-service.ts +1106 -907
  244. package/src/execution/subprocess-agent-runner.ts +144 -97
  245. package/src/execution/types.ts +9 -0
  246. package/src/execution/ui-request-handler-factory.ts +126 -75
  247. package/src/execution/ui-request-queue.ts +50 -19
  248. package/src/execution/worktree-git-ops.ts +397 -0
  249. package/src/execution/worktree-manager.ts +72 -10
  250. package/src/execution/worktree-registry.ts +6 -12
  251. package/src/index.ts +542 -9
  252. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +42 -3
  253. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +3 -5
  254. package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
  255. package/src/orchestration/__tests__/args-meta.test.ts +358 -0
  256. package/src/orchestration/__tests__/args-validator.test.ts +14 -0
  257. package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +312 -0
  258. package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +384 -0
  259. package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
  260. package/src/orchestration/__tests__/file-run-store-prune.test.ts +168 -0
  261. package/src/orchestration/__tests__/file-run-store-throttle.test.ts +168 -0
  262. package/src/orchestration/__tests__/file-run-store.test.ts +390 -0
  263. package/src/orchestration/__tests__/helpers/flush-microtasks.ts +13 -0
  264. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +34 -0
  265. package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +357 -0
  266. package/src/orchestration/__tests__/lifecycle-recover-crashed.test.ts +289 -0
  267. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
  268. package/src/orchestration/__tests__/lifecycle.test.ts +84 -5
  269. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
  270. package/src/orchestration/__tests__/run-snapshot.test.ts +356 -0
  271. package/src/orchestration/__tests__/script-generate.test.ts +314 -0
  272. package/src/orchestration/__tests__/script-lint.test.ts +17 -0
  273. package/src/orchestration/__tests__/test-mocks.ts +2 -0
  274. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +7 -6
  275. package/src/orchestration/__tests__/worker-message-pump-finalize-run.test.ts +229 -0
  276. package/src/orchestration/__tests__/{error-recovery-handlers.test.ts → worker-message-pump-handlers.test.ts} +28 -27
  277. package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
  278. package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
  279. package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
  280. package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +275 -0
  281. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +78 -1
  282. package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
  283. package/src/orchestration/__tests__/workflow-files.test.ts +186 -0
  284. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
  285. package/src/orchestration/__tests__/workflow-run-summary.test.ts +119 -0
  286. package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +124 -0
  287. package/src/orchestration/agent-opts-resolver.ts +8 -8
  288. package/src/orchestration/args-meta.ts +198 -0
  289. package/src/orchestration/args-validator.ts +53 -31
  290. package/src/orchestration/execute-agent-call.ts +25 -79
  291. package/src/orchestration/file-run-store.ts +327 -0
  292. package/src/orchestration/launcher.ts +160 -104
  293. package/src/orchestration/lifecycle.ts +371 -97
  294. package/src/orchestration/models/agent-call.ts +7 -7
  295. package/src/orchestration/models/budget.ts +5 -5
  296. package/src/orchestration/models/ports.ts +4 -4
  297. package/src/orchestration/models/run-runtime.ts +15 -15
  298. package/src/orchestration/models/trace.ts +9 -9
  299. package/src/orchestration/models/types.ts +111 -22
  300. package/src/orchestration/models/workflow-run.ts +28 -28
  301. package/src/orchestration/models/workflow-script.ts +4 -4
  302. package/src/orchestration/run-snapshot.ts +266 -0
  303. package/src/orchestration/script-generate.ts +154 -0
  304. package/src/orchestration/script-lint.ts +123 -90
  305. package/src/orchestration/worker-handle.ts +10 -10
  306. package/src/orchestration/worker-host.ts +10 -10
  307. package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +498 -221
  308. package/src/orchestration/worker-script-builder.ts +401 -346
  309. package/src/orchestration/workflow-files.ts +37 -11
  310. package/src/orchestration/workflow-run-summary.ts +69 -0
  311. package/src/orchestration/workflow-script-registry-impl.ts +31 -9
  312. package/src/shared/__tests__/agent-ref.test.ts +209 -2
  313. package/src/shared/__tests__/atomic-write.test.ts +267 -0
  314. package/src/shared/__tests__/bounded-serialize.test.ts +236 -0
  315. package/src/shared/__tests__/injection-render.test.ts +518 -0
  316. package/src/shared/__tests__/meta-parser.test.ts +151 -0
  317. package/src/shared/__tests__/resource-discovery-host-roots.test.ts +474 -0
  318. package/src/shared/__tests__/resource-discovery.test.ts +261 -217
  319. package/src/shared/agent-ref.ts +143 -2
  320. package/src/shared/atomic-write.ts +323 -0
  321. package/src/shared/bounded-serialize.ts +154 -0
  322. package/src/shared/injection-render.ts +279 -0
  323. package/src/shared/meta-parser.ts +182 -68
  324. package/src/shared/model-ref.ts +15 -2
  325. package/src/shared/resource-discovery.ts +97 -204
  326. package/src/shared/resource-meta.ts +14 -0
  327. package/src/shared/schema-jsonify.ts +1 -1
  328. package/src/shared/xml-injection.ts +9 -9
  329. package/workflows/README.md +9 -9
  330. package/workflows/chain.js +4 -2
  331. package/workflows/map-reduce.js +5 -3
  332. package/workflows/parallel.js +5 -3
  333. package/workflows/review-fix-loop-utils.cjs +165 -92
  334. package/workflows/review-fix-loop-utils.d.cts +287 -0
  335. package/workflows/review-fix-loop.js +18 -7
  336. package/workflows/scatter-gather.js +4 -2
  337. package/dist/chunk-3VOERJPJ.js +0 -22
  338. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  339. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  340. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  341. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  342. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  343. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -580
  344. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  345. package/src/execution/execute-options-mapper.ts +0 -115
  346. package/src/execution/session-runner.ts +0 -1789
  347. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
@@ -0,0 +1,271 @@
1
+ // src/execution/__tests__/subagent-service-notify-gate.test.ts
2
+ //
3
+ // [u-svc / T4] 通知可靠性(subagent-service 侧三措施):
4
+ // - T4①/PS-2:kickOffChatRound.then notify 门按 closedReason 白名单放行——
5
+ // parent-new/parent-fork 不注入(可能已切换的)新 session(A-6 决策落实);
6
+ // - T4②/PS-4:idleTimeoutMs 非法值(>2^31-1 / 非有限值)在 spawn 入口同步 fail-fast,
7
+ // 错误含合法范围(不静默 clamp、不静默不挂);
8
+ // - T4④/PS-5:shutdown flush 被 isIdle 门拦时,未投递 pending 复写落盘(ledger entry
9
+ // 通道,notifyId 幂等)供重启 replay——修复「flush 后 dispose 防丢失」注释承诺差距。
10
+ //
11
+ // mock 形态沿用 subagent-service-message-close.test.ts;notify-ledger 用真模块
12
+ //(bindNotifyLedgerHost + fake host 构造 pending)。
13
+
14
+ import * as fs from "node:fs";
15
+ import * as os from "node:os";
16
+ import * as path from "node:path";
17
+
18
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
19
+
20
+ const { loggerMock } = vi.hoisted(() => ({
21
+ loggerMock: { debug: vi.fn(), warn: vi.fn(), error: vi.fn() },
22
+ }));
23
+ vi.mock("../../core/logger.ts", () => ({ getLogger: () => loggerMock }));
24
+
25
+ const { killChildSpy } = vi.hoisted(() => ({ killChildSpy: vi.fn() }));
26
+ vi.mock("../engine/engines/pi/session-runner.ts", () => ({
27
+ runSpawn: vi.fn(),
28
+ killAllSpawnedChildren: vi.fn(),
29
+ getChildByRecord: vi.fn(() => undefined),
30
+ registerSpawnedChildForRecord: vi.fn(),
31
+ spawnedChildren: new Map(),
32
+ killRecordChildWithEscalation: killChildSpy,
33
+ }));
34
+
35
+ import { bindNotifyLedgerHost, NOTIFY_LEDGER_CUSTOM_TYPE, _resetNotifyLedgerForTest } from "../notify-ledger.ts";
36
+ import { createRecord } from "../execution-record.ts";
37
+ import { ModelConfigService } from "../model-config-service.ts";
38
+ import type { RecordStore } from "../record-store.ts";
39
+ import { notifyGateAllowsDelivery, SubagentService } from "../subagent-service.ts";
40
+ import type { PiLike } from "../subagent-service.ts";
41
+ import { MAX_TIMER_DELAY_MS } from "../../shared/timer-delay.ts";
42
+ import type { ExecutionRecord } from "../types.ts";
43
+
44
+ function makeTmpAgentDir(): string {
45
+ return fs.mkdtempSync(path.join(os.tmpdir(), "svc-notify-gate-"));
46
+ }
47
+
48
+ function makePi(): PiLike & {
49
+ appendEntry: ReturnType<typeof vi.fn>;
50
+ events: { emit: ReturnType<typeof vi.fn> };
51
+ sendMessage: ReturnType<typeof vi.fn>;
52
+ on?: ReturnType<typeof vi.fn>;
53
+ } {
54
+ return {
55
+ appendEntry: vi.fn(),
56
+ events: { emit: vi.fn() },
57
+ sendMessage: vi.fn(),
58
+ } as unknown as PiLike & {
59
+ appendEntry: ReturnType<typeof vi.fn>;
60
+ events: { emit: ReturnType<typeof vi.fn> };
61
+ sendMessage: ReturnType<typeof vi.fn>;
62
+ on?: ReturnType<typeof vi.fn>;
63
+ };
64
+ }
65
+
66
+ interface ServiceInternals {
67
+ store: RecordStore;
68
+ }
69
+
70
+ type MockPi = ReturnType<typeof makePi>;
71
+
72
+ function setup(initOverrides: Partial<{ isIdle: () => boolean }> = {}): {
73
+ agentDir: string;
74
+ service: SubagentService;
75
+ store: RecordStore;
76
+ pi: MockPi;
77
+ } {
78
+ const agentDir = makeTmpAgentDir();
79
+ const modelService = new ModelConfigService({ agentDir, cwd: agentDir });
80
+ const service = new SubagentService({ cwd: agentDir, modelService });
81
+ const pi = makePi();
82
+ service.initSession({ pi, sessionId: "root-session", isIdle: initOverrides.isIdle });
83
+ const store = (service as unknown as ServiceInternals).store;
84
+ return { agentDir, service, store, pi };
85
+ }
86
+
87
+ describe("T4① notify gate closedReason whitelist", () => {
88
+ it("blocks cancelled, parent-new, parent-fork; allows real closures and undefined (CAS-winner path)", () => {
89
+ expect(notifyGateAllowsDelivery("cancelled")).toBe(false);
90
+ expect(notifyGateAllowsDelivery("parent-new")).toBe(false);
91
+ expect(notifyGateAllowsDelivery("parent-fork")).toBe(false);
92
+ expect(notifyGateAllowsDelivery("user-close")).toBe(true);
93
+ expect(notifyGateAllowsDelivery("gc")).toBe(true);
94
+ expect(notifyGateAllowsDelivery("parent-shutdown")).toBe(true);
95
+ expect(notifyGateAllowsDelivery(undefined)).toBe(true);
96
+ });
97
+
98
+ it("kickOffChatRound.then does not inject parent-new closed records into the session", async () => {
99
+ const { agentDir, service, pi } = setup();
100
+ const record = createRecord("sa-gate-new", {
101
+ agent: "general-purpose",
102
+ model: "test/model",
103
+ mode: "background",
104
+ slug: "t",
105
+ task: "test",
106
+ startedAt: 1000,
107
+ rootSessionId: "root-session",
108
+ controller: new AbortController(),
109
+ });
110
+ // 模拟 disposeAllRecords 先行编排性关闭后,迟到的 kickOffChatRound.then 回注
111
+ record.closedReason = "parent-new";
112
+ const stub = vi.fn().mockResolvedValue({
113
+ text: "",
114
+ turns: 0,
115
+ durationMs: 1,
116
+ success: false,
117
+ error: "closed due to parent-new",
118
+ sessionId: record.id,
119
+ toolCalls: [],
120
+ });
121
+ (service as unknown as Record<string, unknown>).runAndFinalize = stub;
122
+ // [D4 后形态] 轮次编排入口 kickOffChatRound(私有,bracket 调用先例见
123
+ // subagent-service-recovery-bounds.test.ts privateFn);opts 形参仍是 ExecuteOptions
124
+ //(task/slug),chat 分支由 ticket lossless 携带——task 声明形参不参与校验。
125
+ const kickOffChatRound = (
126
+ service as unknown as Record<string, (...args: unknown[]) => void>
127
+ )["kickOffChatRound"];
128
+ kickOffChatRound.call(service, record, { task: "t", slug: "gate" }, {}, {}, undefined, 1000, undefined);
129
+ await vi.waitFor(() => expect(stub).toHaveBeenCalled());
130
+ await Promise.resolve();
131
+ await Promise.resolve();
132
+ expect(pi.sendMessage).not.toHaveBeenCalled();
133
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
134
+ });
135
+
136
+ it("kickOffChatRound.then still notifies for real failure closures (gc)", async () => {
137
+ const { agentDir, service, pi } = setup();
138
+ const record = createRecord("sa-gate-gc", {
139
+ agent: "general-purpose",
140
+ model: "test/model",
141
+ mode: "background",
142
+ slug: "t",
143
+ task: "test",
144
+ startedAt: 1000,
145
+ rootSessionId: "root-session",
146
+ controller: new AbortController(),
147
+ });
148
+ record.closedReason = "gc";
149
+ (service as unknown as Record<string, unknown>).runAndFinalize = vi.fn().mockResolvedValue({});
150
+ const kickOffChatRound = (
151
+ service as unknown as Record<string, (...args: unknown[]) => void>
152
+ )["kickOffChatRound"];
153
+ kickOffChatRound.call(service, record, { task: "t", slug: "gate" }, {}, {}, undefined, 1000, undefined);
154
+ await vi.waitFor(() => expect(pi.sendMessage).toHaveBeenCalled());
155
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
156
+ });
157
+ });
158
+
159
+ describe("T4② idleTimeoutMs entry fail-fast", () => {
160
+ let agentDir: string;
161
+ let service: SubagentService;
162
+
163
+ beforeEach(() => {
164
+ ({ agentDir, service } = setup());
165
+ });
166
+
167
+ afterEach(() => {
168
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
169
+ });
170
+
171
+ it("execute rejects idleTimeoutMs above the setTimeout limit with the valid range in the message", async () => {
172
+ await expect(service.execute({ task: "x", slug: "test", idleTimeoutMs: MAX_TIMER_DELAY_MS + 1 })).rejects.toThrow(
173
+ new RegExp(`${MAX_TIMER_DELAY_MS}`),
174
+ );
175
+ await expect(service.execute({ task: "x", slug: "test", idleTimeoutMs: 3_000_000_000 })).rejects.toThrow(/2\^31-1/);
176
+ });
177
+
178
+ it("execute rejects non-finite idleTimeoutMs", async () => {
179
+ await expect(service.execute({ task: "x", slug: "test", idleTimeoutMs: Number.NaN })).rejects.toThrow(/not a finite number/);
180
+ });
181
+
182
+ it("rejects before any record is created (no side effects)", async () => {
183
+ const internals = service as unknown as ServiceInternals;
184
+ await expect(service.executeAndAwait({ task: "x", slug: "test", idleTimeoutMs: 3_000_000_000 })).rejects.toThrow();
185
+ expect(internals.store.listRunning()).toHaveLength(0);
186
+ });
187
+
188
+ it("accepts valid values (0 = explicit disable, positive within limit)", async () => {
189
+ // 校验通过后执行链继续(runSpawn 被 mock,返回 undefined result 会在后续流程抛错/
190
+ // 返回——但绝不能是 idleTimeoutMs 校验错误)
191
+ await expect(service.execute({ task: "x", slug: "test", idleTimeoutMs: 0 })).rejects.not.toThrow(/idleTimeoutMs/);
192
+ });
193
+ });
194
+
195
+ describe("T4④ shutdown flush blocked → pending persisted for replay", () => {
196
+ let agentDir: string;
197
+ let service: SubagentService;
198
+ let pi: MockPi;
199
+
200
+ beforeEach(() => {
201
+ _resetNotifyLedgerForTest();
202
+ ({ agentDir, service, pi } = setup({ isIdle: () => false }));
203
+ });
204
+
205
+ afterEach(() => {
206
+ _resetNotifyLedgerForTest();
207
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
208
+ });
209
+
210
+ it("persists undelivered pending notifications as ledger entries on dispose when main agent is busy", () => {
211
+ // 绑定真 ledger 并制造一条未投递 pending(isIdle=false → attemptDeliver 挂回 pending)
212
+ const ledger = bindNotifyLedgerHost({
213
+ appendLedgerEntry: (customType, data) => pi.appendEntry(customType, data),
214
+ readSessionEntries: () => [],
215
+ isIdle: () => false,
216
+ onAgentSettled: () => {},
217
+ sendDelivery: (message) => pi.sendMessage(message as never),
218
+ });
219
+ const recorded = ledger.record("notify-1", "Subagent x completed", { id: "sa-x", agent: "x" });
220
+ expect(recorded).toBe(true);
221
+ expect(ledger.pendingEntries()).toHaveLength(1);
222
+
223
+ service.dispose();
224
+
225
+ // 复写落盘:NOTIFY_LEDGER_CUSTOM_TYPE entry 携带 notifyId(幂等键)+ v1 schema
226
+ const replayEntries = pi.appendEntry.mock.calls.filter(
227
+ (c) => c[0] === NOTIFY_LEDGER_CUSTOM_TYPE && (c[1] as { notifyId?: string })?.notifyId === "notify-1",
228
+ );
229
+ expect(replayEntries.length).toBeGreaterThanOrEqual(2); // record 原账 + dispose 复写
230
+ expect(replayEntries[0]?.[1]).toMatchObject({ v: 1, notifyId: "notify-1" });
231
+ expect(loggerMock.warn).toHaveBeenCalledWith(
232
+ expect.stringContaining("persisted to ledger for replay"),
233
+ expect.objectContaining({ count: 1 }),
234
+ );
235
+ // 重启 replay 可重放:新 ledger 实例扫账面(含复写 entry)应入账该 pending
236
+ const host2 = {
237
+ appendLedgerEntry: vi.fn(),
238
+ readSessionEntries: () =>
239
+ pi.appendEntry.mock.calls
240
+ .filter((c) => c[0] === NOTIFY_LEDGER_CUSTOM_TYPE)
241
+ .map((c) => ({ type: "custom", customType: c[0], data: c[1] })),
242
+ isIdle: () => false,
243
+ onAgentSettled: () => {},
244
+ sendDelivery: vi.fn(),
245
+ };
246
+ const ledger2 = bindNotifyLedgerHost(host2);
247
+ expect(ledger2.recoverFromSession()).toBe(1);
248
+ });
249
+
250
+ it("does not rewrite when main agent is idle (flush already delivered)", () => {
251
+ const ledger = bindNotifyLedgerHost({
252
+ appendLedgerEntry: (customType, data) => pi.appendEntry(customType, data),
253
+ readSessionEntries: () => [],
254
+ isIdle: () => false,
255
+ onAgentSettled: () => {},
256
+ sendDelivery: (message) => pi.sendMessage(message as never),
257
+ });
258
+ ledger.record("notify-2", "content", { id: "sa-y" });
259
+ pi.appendEntry.mockClear();
260
+
261
+ // idle service:flush 投出(无门拦),dispose 无复写动作
262
+ const idleService = new SubagentService({
263
+ cwd: agentDir,
264
+ modelService: new ModelConfigService({ agentDir, cwd: agentDir }),
265
+ });
266
+ const piIdle = makePi();
267
+ idleService.initSession({ pi: piIdle, sessionId: "root-session", isIdle: () => true });
268
+ idleService.dispose();
269
+ expect(piIdle.appendEntry).not.toHaveBeenCalled();
270
+ });
271
+ });
@@ -26,10 +26,13 @@ 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),
33
+ registerSpawnedChildForRecord: vi.fn(),
34
+ killRecordChildWithEscalation: vi.fn(),
35
+ spawnedChildren: new Map(),
33
36
  }));
34
37
 
35
38
  import { createRecord } from "../execution-record.ts";
@@ -56,11 +59,12 @@ function makePi(): PiLike {
56
59
  } as unknown as PiLike;
57
60
  }
58
61
 
59
- /** 暴露私有字段供测试注入身份。 */
62
+ /** 暴露私有字段供测试注入身份。[D3-⑤] 基线住进 execNesting(公共层
63
+ * ExecutionNestingContext),注入经 setBaseline 测试面。 */
60
64
  interface ServiceInternals {
61
65
  store: RecordStore;
62
66
  sessionRootId: string | null;
63
- execCtxBaseline: { recordId: string | undefined; depth: number } | null;
67
+ execNesting: { setBaseline(state: { recordId: string | undefined; depth: number } | null): void };
64
68
  }
65
69
 
66
70
  /** 构造一个 chatMode idle record(message/close action 的典型目标态)。 */
@@ -74,12 +78,12 @@ function makeRecord(
74
78
  model: "test/model",
75
79
  mode: "background",
76
80
  task: "test",
77
- slug: "test",
78
81
  startedAt: 1000,
79
82
  rootSessionId: sessionRootId,
80
83
  chatMode: true,
81
84
  controller: new AbortController(),
82
85
  ...overrides,
86
+ slug: overrides.slug ?? "test",
83
87
  });
84
88
  }
85
89
 
@@ -92,7 +96,7 @@ describe("[v4 A-5 / P7] getRecordForAction 直接父校验", () => {
92
96
 
93
97
  beforeEach(() => {
94
98
  agentDir = makeTmpAgentDir();
95
- const modelService = new ModelConfigService({ agentDir });
99
+ const modelService = new ModelConfigService({ agentDir, cwd: agentDir });
96
100
  service = new SubagentService({ cwd: agentDir, modelService });
97
101
  // initSession 建立 sessionRootId=sessionId(本 session 树的根)。execCtxBaseline 的
98
102
  // 真实值由 initSession 从 env 读取(见 recursive-visibility-baseline.test.ts),但本测试
@@ -105,65 +109,65 @@ describe("[v4 A-5 / P7] getRecordForAction 直接父校验", () => {
105
109
 
106
110
  afterEach(() => {
107
111
  service.dispose();
108
- fs.rmSync(agentDir, { recursive: true, force: true });
112
+ fs.rmSync(agentDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
109
113
  });
110
114
 
111
115
  // ---------- 身份 sa-A:直接父,放行孙级 B ----------
112
116
 
113
117
  it("身份=sa-A(直接父)→ 放行操作孙级 record B(parentRecordId=sa-A)", () => {
114
- 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" });
115
119
  store.register(recordB);
116
- internals.execCtxBaseline = PARENT_A;
120
+ internals.execNesting.setBaseline(PARENT_A);
117
121
 
118
- expect(service.getRecordForAction("sa-B")).toBe(recordB);
122
+ expect(service.chatActions.getRecordForAction("sa-B")).toBe(recordB);
119
123
  });
120
124
 
121
125
  // ---------- 身份 undefined(主进程):拒绝孙级,放行根层 ----------
122
126
 
123
127
  it("身份=undefined(主进程)拒绝孙级 record B,错误含 'direct parent' + 'parent=sa-A'", () => {
124
- 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" });
125
129
  store.register(recordB);
126
- internals.execCtxBaseline = MAIN_PROCESS;
130
+ internals.execNesting.setBaseline(MAIN_PROCESS);
127
131
 
128
- expect(() => service.getRecordForAction("sa-B")).toThrow(/direct parent/);
129
- 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/);
130
134
  });
131
135
 
132
136
  it("身份=undefined(主进程)放行顶层 record(parentRecordId=undefined 视为根层)", () => {
133
- 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" });
134
138
  store.register(topRecord);
135
- internals.execCtxBaseline = MAIN_PROCESS;
139
+ internals.execNesting.setBaseline(MAIN_PROCESS);
136
140
 
137
- expect(service.getRecordForAction("sa-top")).toBe(topRecord);
141
+ expect(service.chatActions.getRecordForAction("sa-top")).toBe(topRecord);
138
142
  });
139
143
 
140
144
  // ---------- 身份 sa-B(兄弟进程):拒绝孙级 ----------
141
145
 
142
146
  it("身份=sa-B(兄弟进程)拒绝孙级 record B(parentRecordId=sa-A ≠ baseline sa-B)", () => {
143
- 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" });
144
148
  store.register(recordB);
145
- internals.execCtxBaseline = SIBLING_B;
149
+ internals.execNesting.setBaseline(SIBLING_B);
146
150
 
147
- expect(() => service.getRecordForAction("sa-B")).toThrow(/direct parent/);
148
- 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/);
149
153
  });
150
154
 
151
155
  // ---------- 身份缺省语义 + 更深递归 ----------
152
156
 
153
157
  it("子进程(baseline=sa-A)拒绝顶层 record(身份缺省视为根层,仅主进程可操作)", () => {
154
- 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" });
155
159
  store.register(topRecord);
156
- internals.execCtxBaseline = PARENT_A;
160
+ internals.execNesting.setBaseline(PARENT_A);
157
161
 
158
- expect(() => service.getRecordForAction("sa-top")).toThrow(/direct parent/);
162
+ expect(() => service.chatActions.getRecordForAction("sa-top")).toThrow(/direct parent/);
159
163
  });
160
164
 
161
165
  it("P7 场景:主进程拒绝曾孙 record C(parentRecordId=sa-B),错误含 baseline=root + parent=sa-B", () => {
162
- 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" });
163
167
  store.register(recordC);
164
- internals.execCtxBaseline = MAIN_PROCESS;
168
+ internals.execNesting.setBaseline(MAIN_PROCESS);
165
169
 
166
- const fn = () => service.getRecordForAction("sa-C");
170
+ const fn = () => service.chatActions.getRecordForAction("sa-C");
167
171
  expect(fn).toThrow(/direct parent/);
168
172
  expect(fn).toThrow(/see \/subagents list, parent=sa-B/);
169
173
  expect(fn).toThrow(/baseline=\(root\)/);
@@ -171,10 +175,10 @@ describe("[v4 A-5 / P7] getRecordForAction 直接父校验", () => {
171
175
 
172
176
  it("rootSessionId 不匹配仍优先拒绝(直接父校验在 rootSessionId 校验之后,不绕过归属守卫)", () => {
173
177
  // 跨 session 树的 record:rootSessionId 不匹配 → 走首个 throw(not found or not owned)
174
- 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" });
175
179
  store.register(foreignRecord);
176
- internals.execCtxBaseline = PARENT_A;
180
+ internals.execNesting.setBaseline(PARENT_A);
177
181
 
178
- expect(() => service.getRecordForAction("sa-foreign")).toThrow(/not found or not owned/);
182
+ expect(() => service.chatActions.getRecordForAction("sa-foreign")).toThrow(/not found or not owned/);
179
183
  });
180
184
  });