@zhushanwen/subagent-core 0.5.1 → 0.7.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 (318) hide show
  1. package/README.md +1 -1
  2. package/dist/chunk-KXVBIVOU.js +16 -0
  3. package/dist/chunk-T2SYBW3I.js +24 -0
  4. package/dist/chunk-VURUAGMM.js +2305 -0
  5. package/dist/{types-Dv4QhSJ_.d.cts → engine-discovery-scan-ocpM8FmI.d.cts} +835 -668
  6. package/dist/{types-Dv4QhSJ_.d.ts → engine-discovery-scan-ocpM8FmI.d.ts} +835 -668
  7. package/dist/execution/engine/engine-discovery-scan.cjs +2210 -0
  8. package/dist/execution/engine/engine-discovery-scan.d.cts +4 -0
  9. package/dist/execution/engine/engine-discovery-scan.d.ts +4 -0
  10. package/dist/execution/engine/engine-discovery-scan.js +20 -0
  11. package/dist/execution/engine/paths.cjs +6 -23
  12. package/dist/execution/engine/paths.d.cts +1 -8
  13. package/dist/execution/engine/paths.d.ts +1 -8
  14. package/dist/execution/engine/paths.js +1 -1
  15. package/dist/execution/relay-env.cjs +12 -28
  16. package/dist/execution/relay-env.d.cts +1 -33
  17. package/dist/execution/relay-env.d.ts +1 -33
  18. package/dist/execution/relay-env.js +5 -3
  19. package/dist/index.cjs +14123 -15467
  20. package/dist/index.d.cts +1179 -1540
  21. package/dist/index.d.ts +1179 -1540
  22. package/dist/index.js +7694 -10986
  23. package/dist.bundle/index.cjs +33485 -0
  24. package/package.json +20 -26
  25. package/src/__tests__/record-store-last-line.test.ts +16 -7
  26. package/src/core/error-message.ts +7 -6
  27. package/src/core/host-services.ts +8 -2
  28. package/src/core/notify-ports.ts +17 -2
  29. package/src/execution/__tests__/agent-registry.test.ts +1 -1
  30. package/src/execution/__tests__/alive-store.test.ts +1 -1
  31. package/src/execution/__tests__/chat-engine-routing.test.ts +62 -28
  32. package/src/execution/__tests__/chat-round-first-round-watchdog.test.ts +255 -0
  33. package/src/execution/__tests__/collect-budget.test.ts +291 -0
  34. package/src/execution/__tests__/collect-coordinator-service.test.ts +316 -0
  35. package/src/execution/__tests__/collect-coordinator.test.ts +371 -0
  36. package/src/execution/__tests__/collect-mixed-dispatch.test.ts +229 -0
  37. package/src/execution/__tests__/config-collect-sync.test.ts +120 -0
  38. package/src/execution/__tests__/config.test.ts +1 -1
  39. package/src/execution/__tests__/delivery-methods.test.ts +179 -237
  40. package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -2
  41. package/src/execution/__tests__/execute-nesting.test.ts +20 -13
  42. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +21 -34
  43. package/src/execution/__tests__/finalized-marker.test.ts +1 -1
  44. package/src/execution/__tests__/gc-timer.test.ts +8 -23
  45. package/src/execution/__tests__/get-record-for-action-restart.test.ts +20 -10
  46. package/src/execution/__tests__/helpers/fake-engine-port.ts +187 -0
  47. package/src/execution/__tests__/helpers/spawn-mock.ts +36 -9
  48. package/src/execution/__tests__/helpers/subagent-service-mocks.ts +1 -1
  49. package/src/execution/__tests__/idle-gc.test.ts +200 -0
  50. package/src/execution/__tests__/lifecycle-predicates.test.ts +26 -21
  51. package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +1 -1
  52. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +5 -2
  53. package/src/execution/__tests__/notify-batch.test.ts +500 -0
  54. package/src/execution/__tests__/notify-ledger.test.ts +27 -0
  55. package/src/execution/__tests__/reconcile-sweep.test.ts +200 -0
  56. package/src/execution/__tests__/record-entry-collect.test.ts +102 -0
  57. package/src/execution/__tests__/record-store.test.ts +60 -6
  58. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +20 -13
  59. package/src/execution/__tests__/relay-env.test.ts +12 -1
  60. package/src/execution/__tests__/round-supervisor.test.ts +293 -0
  61. package/src/execution/__tests__/session-file-gc.test.ts +1 -1
  62. package/src/execution/__tests__/session-pending.test.ts +119 -17
  63. package/src/execution/__tests__/start-collect-guard.test.ts +255 -0
  64. package/src/execution/__tests__/stream-sink-retirement.test.ts +10 -10
  65. package/src/execution/__tests__/subagent-actions-core.test.ts +6 -0
  66. package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +14 -11
  67. package/src/execution/__tests__/subagent-service-notify-gate.test.ts +33 -30
  68. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +2 -9
  69. package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +59 -129
  70. package/src/execution/__tests__/subagent-service.test.ts +2 -2
  71. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +109 -7
  72. package/src/execution/__tests__/subprocess-agent-runner.test.ts +108 -36
  73. package/src/execution/__tests__/sync-collect-recovery.test.ts +1102 -0
  74. package/src/execution/__tests__/tombstone-store.test.ts +1 -1
  75. package/src/execution/__tests__/workflow-state-root.test.ts +232 -0
  76. package/src/execution/__tests__/worktree-git-ops.test.ts +1 -1
  77. package/src/execution/__tests__/worktree-reconcile-aging.test.ts +2 -2
  78. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +1 -1
  79. package/src/execution/__tests__/worktree-registry.test.ts +1 -1
  80. package/src/execution/agent-registry.ts +6 -2
  81. package/src/execution/collect-coordinator.ts +200 -0
  82. package/src/execution/config.ts +77 -5
  83. package/src/execution/dialog-queue.ts +6 -73
  84. package/src/execution/engine/__tests__/common/capability-gate.test.ts +115 -15
  85. package/src/execution/engine/__tests__/common/errors.test.ts +11 -18
  86. package/src/execution/engine/__tests__/common/event-journal.test.ts +1 -1
  87. package/src/execution/engine/__tests__/common/kill-chain.test.ts +7 -0
  88. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +9 -3
  89. package/src/execution/engine/__tests__/common/pool-manager.test.ts +2 -2
  90. package/src/execution/engine/__tests__/common/session-view-service.test.ts +90 -3
  91. package/src/execution/engine/__tests__/conformance/H9-test-disposition.md +116 -0
  92. package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/fake-engine-protocol.mjs +377 -0
  93. package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/recorded.fixture.json +331 -0
  94. package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/smoke-run.fixture.json +213 -0
  95. package/src/execution/engine/__tests__/conformance/chat-round-protocol.test.ts +230 -0
  96. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +69 -42
  97. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +4 -81
  98. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +67 -44
  99. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +82 -55
  100. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +133 -70
  101. package/src/execution/engine/__tests__/conformance/engine-crash.test.ts +143 -0
  102. package/src/execution/engine/__tests__/conformance/fake-engine-capabilities.ts +19 -0
  103. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +8 -3
  104. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +6 -5
  105. package/src/execution/engine/__tests__/conformance/protocol-blackbox.test.ts +398 -0
  106. package/src/execution/engine/__tests__/conformance/registry-fork-filter.test.ts +221 -0
  107. package/src/execution/engine/__tests__/conformance/round-liveness-supervisor.test.ts +302 -0
  108. package/src/execution/engine/__tests__/conformance/static-spawn-guard.test.ts +58 -0
  109. package/src/execution/engine/__tests__/engine-discovery-scan.test.ts +558 -0
  110. package/src/execution/engine/__tests__/host-task-spec.test.ts +45 -0
  111. package/src/execution/engine/__tests__/model-ref-split.test.ts +74 -0
  112. package/src/execution/engine/__tests__/registry.test.ts +206 -1
  113. package/src/execution/engine/__tests__/routing.test.ts +97 -0
  114. package/src/execution/engine/__tests__/run-failure-worktree-cleanup.test.ts +97 -0
  115. package/src/execution/engine/client/__tests__/__fixtures__/fake-engine.mjs +294 -0
  116. package/src/execution/engine/client/__tests__/engine-client.test.ts +516 -0
  117. package/src/execution/engine/client/__tests__/mirror.test.ts +67 -0
  118. package/src/execution/engine/client/__tests__/pid-file.test.ts +257 -0
  119. package/src/execution/engine/client/__tests__/protocol-closure.test.ts +95 -0
  120. package/src/execution/engine/client/__tests__/remote-engine.test.ts +457 -0
  121. package/src/execution/engine/client/client-options.ts +103 -0
  122. package/src/execution/engine/client/engine-client.ts +687 -0
  123. package/src/execution/engine/client/mirror.ts +167 -0
  124. package/src/execution/engine/client/pid-file.ts +392 -0
  125. package/src/execution/engine/client/reaper.ts +95 -0
  126. package/src/execution/engine/client/remote-engine.ts +441 -0
  127. package/src/execution/engine/client/reverse-router.ts +255 -0
  128. package/src/execution/engine/common/capability-gate.ts +109 -22
  129. package/src/execution/engine/common/errors.ts +9 -25
  130. package/src/execution/engine/common/event-journal.ts +4 -50
  131. package/src/execution/engine/common/journal-replay.ts +3 -1
  132. package/src/execution/engine/common/kill-chain.ts +18 -251
  133. package/src/execution/engine/common/nesting-guard.ts +18 -114
  134. package/src/execution/engine/common/pool-manager.ts +4 -0
  135. package/src/execution/engine/common/session-view-service.ts +56 -84
  136. package/src/execution/engine/config.ts +151 -0
  137. package/src/execution/engine/d8-compat.ts +346 -0
  138. package/src/execution/engine/engine-discovery-roots.ts +107 -0
  139. package/src/execution/engine/engine-discovery-scan.ts +269 -0
  140. package/src/execution/engine/engine-discovery.ts +30 -7
  141. package/src/execution/engine/engine-inspect-package.ts +282 -0
  142. package/src/execution/engine/engine-manifest.ts +244 -0
  143. package/src/execution/engine/host/__tests__/host-askuser-endpoint.test.ts +123 -0
  144. package/src/execution/engine/host/__tests__/host-bridge.test.ts +135 -0
  145. package/src/execution/engine/host/__tests__/spawned-children.test.ts +73 -0
  146. package/src/execution/engine/host/host-bridge.ts +150 -0
  147. package/src/execution/engine/host/host-ui-endpoint.ts +47 -0
  148. package/src/execution/engine/host/pi-host-binding.ts +91 -0
  149. package/src/execution/engine/host/spawned-children.ts +139 -0
  150. package/src/execution/engine/host-task-spec.ts +29 -2
  151. package/src/execution/engine/model-validation.ts +55 -2
  152. package/src/execution/engine/paths.ts +16 -41
  153. package/src/execution/engine/port.ts +48 -2
  154. package/src/execution/engine/registry.ts +153 -34
  155. package/src/execution/engine/routing.ts +225 -52
  156. package/src/execution/engine/types.ts +25 -200
  157. package/src/execution/execution-record.ts +7 -0
  158. package/src/execution/finalize-record.ts +40 -11
  159. package/src/execution/idle-gc.ts +89 -14
  160. package/src/execution/lifecycle-manager.ts +10 -7
  161. package/src/execution/lifecycle-predicates.ts +10 -8
  162. package/src/execution/notifier.ts +234 -25
  163. package/src/execution/notify-host.ts +21 -1
  164. package/src/execution/record-entry.ts +16 -0
  165. package/src/execution/record-store.ts +189 -31
  166. package/src/execution/relay-env.ts +19 -36
  167. package/src/execution/round-supervisor/domain.ts +89 -0
  168. package/src/execution/round-supervisor/index.ts +33 -0
  169. package/src/execution/round-supervisor/notify-accounting.ts +87 -0
  170. package/src/execution/round-supervisor/reconcile-sweep.ts +235 -0
  171. package/src/execution/round-supervisor/service-binding.test.ts +661 -0
  172. package/src/execution/round-supervisor/service-binding.ts +273 -0
  173. package/src/execution/round-supervisor/supervisor.ts +426 -0
  174. package/src/execution/session-pending.ts +68 -74
  175. package/src/execution/settled-watchdog.ts +39 -0
  176. package/src/execution/subagent-actions-core.ts +62 -6
  177. package/src/execution/subagent-service.ts +1161 -406
  178. package/src/execution/subprocess-agent-runner.ts +16 -8
  179. package/src/execution/sync-rebuild.ts +87 -0
  180. package/src/execution/types.ts +104 -117
  181. package/src/execution/ui-channels.ts +13 -214
  182. package/src/execution/ui-request-handler-factory.ts +7 -4
  183. package/src/execution/ui-request-observability.ts +2 -2
  184. package/src/execution/workflow-state-root.ts +67 -0
  185. package/src/execution/worktree-git-ops.ts +5 -0
  186. package/src/execution/worktree-manager.ts +11 -1
  187. package/src/index.ts +55 -26
  188. package/src/orchestration/__tests__/config-loader.test.ts +1 -1
  189. package/src/orchestration/__tests__/execute-agent-call.test.ts +1 -1
  190. package/src/orchestration/__tests__/file-run-store-prune.test.ts +1 -1
  191. package/src/orchestration/__tests__/file-run-store-throttle.test.ts +1 -1
  192. package/src/orchestration/__tests__/review-fix-loop-scriptpath-failfast.test.ts +1 -1
  193. package/src/orchestration/__tests__/script-generate.test.ts +5 -5
  194. package/src/orchestration/__tests__/skill-discovery.test.ts +2 -2
  195. package/src/orchestration/__tests__/workflow-files.test.ts +10 -10
  196. package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +1 -1
  197. package/src/orchestration/execute-agent-call.ts +1 -1
  198. package/src/orchestration/file-run-store.ts +144 -59
  199. package/src/orchestration/models/types.ts +43 -42
  200. package/src/shared/__tests__/atomic-write.test.ts +1 -1
  201. package/src/shared/__tests__/resource-discovery-host-roots.test.ts +5 -5
  202. package/src/shared/zcode-model-ref.ts +31 -0
  203. package/dist/chunk-43ONBFZX.js +0 -240
  204. package/dist/chunk-A4IVZWVX.js +0 -31
  205. package/dist/chunk-APZY4IME.js +0 -27
  206. package/dist/chunk-V3VHZ2VX.js +0 -59
  207. package/dist/execution/engine/engines/zcode/constants.cjs +0 -107
  208. package/dist/execution/engine/engines/zcode/constants.d.cts +0 -135
  209. package/dist/execution/engine/engines/zcode/constants.d.ts +0 -135
  210. package/dist/execution/engine/engines/zcode/constants.js +0 -54
  211. package/dist/execution/engine/engines/zcode/reader.cjs +0 -276
  212. package/dist/execution/engine/engines/zcode/reader.d.cts +0 -21
  213. package/dist/execution/engine/engines/zcode/reader.d.ts +0 -21
  214. package/dist/execution/engine/engines/zcode/reader.js +0 -9
  215. package/src/__tests__/append-system-prompt-assembly.test.ts +0 -243
  216. package/src/__tests__/fr4-get-state-handshake.test.ts +0 -125
  217. package/src/__tests__/session-runner.test.ts +0 -69
  218. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
  219. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -191
  220. package/src/execution/__tests__/descendant-sweep-guards.test.ts +0 -220
  221. package/src/execution/__tests__/descendant-sweep.test.ts +0 -269
  222. package/src/execution/__tests__/engine-model-validation.test.ts +0 -741
  223. package/src/execution/__tests__/epipe-fallback.test.ts +0 -248
  224. package/src/execution/__tests__/execution-runtime-face.test.ts +0 -272
  225. package/src/execution/__tests__/get-state-handshake.test.ts +0 -127
  226. package/src/execution/__tests__/helpers/session-runner-mocks.ts +0 -113
  227. package/src/execution/__tests__/keep-alive-no-progress.test.ts +0 -280
  228. package/src/execution/__tests__/kill-all-escalation.test.ts +0 -196
  229. package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +0 -113
  230. package/src/execution/__tests__/output-collector.test.ts +0 -469
  231. package/src/execution/__tests__/pi-invocation.test.ts +0 -134
  232. package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -149
  233. package/src/execution/__tests__/rpc-mode.test.ts +0 -89
  234. package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +0 -387
  235. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -277
  236. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -254
  237. package/src/execution/__tests__/run-spawn-edges.test.ts +0 -1079
  238. package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
  239. package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
  240. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
  241. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +0 -207
  242. package/src/execution/__tests__/service-kill-escalation.test.ts +0 -91
  243. package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +0 -110
  244. package/src/execution/__tests__/session-runner-close-prune.test.ts +0 -181
  245. package/src/execution/__tests__/session-runner-dispatch.test.ts +0 -489
  246. package/src/execution/__tests__/session-runner-epipe.test.ts +0 -179
  247. package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +0 -227
  248. package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +0 -290
  249. package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -352
  250. package/src/execution/__tests__/settled-watchdog.test.ts +0 -524
  251. package/src/execution/__tests__/spawn-args.test.ts +0 -446
  252. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -192
  253. package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
  254. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -208
  255. package/src/execution/__tests__/spawned-children.test.ts +0 -236
  256. package/src/execution/__tests__/start-sync-model-guard.test.ts +0 -150
  257. package/src/execution/__tests__/stdin-writer.test.ts +0 -464
  258. package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -693
  259. package/src/execution/__tests__/temp-prompt.test.ts +0 -53
  260. package/src/execution/__tests__/timeout-integration.test.ts +0 -616
  261. package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
  262. package/src/execution/__tests__/turn-limiter.test.ts +0 -65
  263. package/src/execution/__tests__/ui-request-handler.test.ts +0 -205
  264. package/src/execution/__tests__/ui-request-queue.test.ts +0 -298
  265. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -230
  266. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
  267. package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +0 -149
  268. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
  269. package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +0 -128
  270. package/src/execution/engine/__tests__/paths.test.ts +0 -39
  271. package/src/execution/engine/common/schema-emulation.ts +0 -189
  272. package/src/execution/engine/common/session-view-projection.ts +0 -51
  273. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -615
  274. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
  275. package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +0 -257
  276. package/src/execution/engine/engines/pi/argv-mirror.ts +0 -135
  277. package/src/execution/engine/engines/pi/get-state-handshake.ts +0 -179
  278. package/src/execution/engine/engines/pi/output-collector.ts +0 -317
  279. package/src/execution/engine/engines/pi/pi-engine.ts +0 -811
  280. package/src/execution/engine/engines/pi/pi-invocation.ts +0 -120
  281. package/src/execution/engine/engines/pi/reader.ts +0 -59
  282. package/src/execution/engine/engines/pi/registration.ts +0 -37
  283. package/src/execution/engine/engines/pi/session-runner.ts +0 -2840
  284. package/src/execution/engine/engines/pi/spawn-event-adapter.ts +0 -404
  285. package/src/execution/engine/engines/pi/stdin-writer.ts +0 -199
  286. package/src/execution/engine/engines/pi/temp-prompt.ts +0 -62
  287. package/src/execution/engine/engines/pi/turn-limiter.ts +0 -102
  288. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +0 -301
  289. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json +0 -36
  290. package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +0 -321
  291. package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +0 -473
  292. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -43
  293. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -124
  294. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
  295. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -71
  296. package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +0 -247
  297. package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +0 -451
  298. package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +0 -792
  299. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +0 -782
  300. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +0 -168
  301. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +0 -210
  302. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +0 -353
  303. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +0 -282
  304. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +0 -372
  305. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -145
  306. package/src/execution/engine/engines/zcode/appserver-launcher.ts +0 -167
  307. package/src/execution/engine/engines/zcode/connection.ts +0 -598
  308. package/src/execution/engine/engines/zcode/constants.ts +0 -176
  309. package/src/execution/engine/engines/zcode/golden-sample.ts +0 -47
  310. package/src/execution/engine/engines/zcode/parser.ts +0 -102
  311. package/src/execution/engine/engines/zcode/preparer.ts +0 -235
  312. package/src/execution/engine/engines/zcode/reader.ts +0 -381
  313. package/src/execution/engine/engines/zcode/registration.ts +0 -37
  314. package/src/execution/engine/engines/zcode/session-channel.ts +0 -968
  315. package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -1431
  316. package/src/execution/round-settlement.ts +0 -93
  317. package/src/execution/ui-request-queue.ts +0 -215
  318. package/src/shared/schema-env.ts +0 -44
@@ -0,0 +1,200 @@
1
+ // src/execution/__tests__/reconcile-sweep.test.ts
2
+ //
3
+ // [W4] 注册对账 sweep 单测:差集判据(record 终态 ∪ 已归档/不存在 → 补发;
4
+ // active → 跳过)、类型分流([F2]:workflow/畸形走 workflow run 判据——终态 ∪
5
+ // store 查不到 → 补注销,running → 跳过;bash 无收口通道保守跳过——显式偏差;
6
+ // 未注入 workflow 判据时保守跳过)、写法(appendEntry 权威落盘 + 尽力 emit;
7
+ // appendEntry 抛错不计入且不 emit)。差集输入 session 文件用
8
+ // mkdtempSync 自建自删(禁触真实数据目录)。
9
+
10
+ import * as fs from "node:fs";
11
+ import * as os from "node:os";
12
+ import * as path from "node:path";
13
+
14
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
15
+
16
+ import { runReconcileSweep, type SupervisedRecordState } from "../round-supervisor/reconcile-sweep.ts";
17
+
18
+ let tmpDir: string;
19
+ let sessionFile: string;
20
+
21
+ beforeEach(() => {
22
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "round-sweep-"));
23
+ sessionFile = path.join(tmpDir, "session.jsonl");
24
+ });
25
+
26
+ afterEach(() => {
27
+ fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
28
+ vi.restoreAllMocks();
29
+ });
30
+
31
+ function writeSessionFile(lines: unknown[]): void {
32
+ fs.writeFileSync(sessionFile, lines.map((l) => JSON.stringify(l)).join("\n") + "\n", "utf-8");
33
+ }
34
+
35
+ function reg(id: string, type = "subagent"): unknown {
36
+ return { customType: "pending:register", data: { id, type, name: id, registeredAt: 1, sessionId: "sess" } };
37
+ }
38
+
39
+ function unreg(id: string): unknown {
40
+ return { customType: "pending:unregister", data: { id, reason: "completed" } };
41
+ }
42
+
43
+ function makeDeps(overrides: {
44
+ states?: Map<string, SupervisedRecordState>;
45
+ workflowStates?: Map<string, SupervisedRecordState>;
46
+ injectWorkflowLookup?: boolean;
47
+ appendEntry?: (customType: string, data: unknown) => void;
48
+ emit?: (channel: string, data: unknown) => void;
49
+ sessionFile?: string;
50
+ } = {}) {
51
+ const states = overrides.states ?? new Map<string, SupervisedRecordState>();
52
+ const workflowStates = overrides.workflowStates;
53
+ const appended: Array<{ customType: string; data: unknown }> = [];
54
+ const emitted: Array<{ channel: string; data: unknown }> = [];
55
+ const deps = {
56
+ sessionFile: overrides.sessionFile ?? sessionFile,
57
+ lookupRecordState: (id: string): SupervisedRecordState => states.get(id) ?? "missing",
58
+ // [F2] workflow 判据:显式注入(injectWorkflowLookup !== false 或给了
59
+ // workflowStates)时按 Map 查;否则缺席(向后兼容形态)。
60
+ ...(overrides.injectWorkflowLookup === false && workflowStates === undefined
61
+ ? {}
62
+ : {
63
+ lookupWorkflowRunState: (id: string): SupervisedRecordState =>
64
+ workflowStates?.get(id) ?? "missing",
65
+ }),
66
+ appendEntry: overrides.appendEntry ?? ((customType: string, data: unknown) => appended.push({ customType, data })),
67
+ emit: overrides.emit ?? ((channel: string, data: unknown) => emitted.push({ channel, data })),
68
+ };
69
+ return { deps, appended, emitted };
70
+ }
71
+
72
+ describe("runReconcileSweep 差集补发", () => {
73
+ it("register(subagent) × record 终态 → 补发 unregister(appendEntry 权威 + 尽力 emit),reason 取 closedReason", () => {
74
+ writeSessionFile([reg("bg-1")]);
75
+ const { deps, appended, emitted } = makeDeps({
76
+ states: new Map([["bg-1", { terminal: true, closedReason: "cancelled" }]]),
77
+ });
78
+ const result = runReconcileSweep(deps);
79
+ expect(result.reconciled).toEqual(["bg-1"]);
80
+ expect(appended).toEqual([
81
+ { customType: "pending:unregister", data: { id: "bg-1", reason: "cancelled", status: "cancelled" } },
82
+ ]);
83
+ expect(emitted).toHaveLength(1);
84
+ });
85
+
86
+ it("record 已归档/不存在(查不到)→ 视同终态补注销(reason=expired)", () => {
87
+ writeSessionFile([reg("bg-gone")]);
88
+ const { deps, appended } = makeDeps({ states: new Map() }); // lookup 恒 missing
89
+ const result = runReconcileSweep(deps);
90
+ expect(result.reconciled).toEqual(["bg-gone"]);
91
+ expect(appended[0].data).toEqual({ id: "bg-gone", reason: "expired", status: "expired" });
92
+ });
93
+
94
+ it("record 活跃 → 保守跳过(不写不 emit)", () => {
95
+ writeSessionFile([reg("bg-live")]);
96
+ const { deps, appended, emitted } = makeDeps({ states: new Map([["bg-live", "active"]]) });
97
+ const result = runReconcileSweep(deps);
98
+ expect(result.skippedActive).toEqual(["bg-live"]);
99
+ expect(appended).toHaveLength(0);
100
+ expect(emitted).toHaveLength(0);
101
+ });
102
+
103
+ it("[F2] type=workflow × workflow run 终态 → 补注销(reason 取 run state reason)", () => {
104
+ writeSessionFile([reg("wf-1", "workflow")]);
105
+ const { deps, appended, emitted } = makeDeps({
106
+ workflowStates: new Map([["wf-1", { terminal: true, closedReason: "aborted" }]]),
107
+ });
108
+ const result = runReconcileSweep(deps);
109
+ expect(result.reconciled).toEqual(["wf-1"]);
110
+ expect(appended).toEqual([
111
+ { customType: "pending:unregister", data: { id: "wf-1", reason: "aborted", status: "aborted" } },
112
+ ]);
113
+ expect(emitted).toHaveLength(1);
114
+ });
115
+
116
+ it("[F2] type=workflow × workflow run running → 保守跳过(宁挂账不误注销活跃 run)", () => {
117
+ writeSessionFile([reg("wf-live", "workflow")]);
118
+ const { deps, appended } = makeDeps({
119
+ workflowStates: new Map([["wf-live", "active"]]),
120
+ });
121
+ const result = runReconcileSweep(deps);
122
+ expect(result.skippedActive).toEqual(["wf-live"]);
123
+ expect(result.reconciled).toEqual([]);
124
+ expect(appended).toHaveLength(0);
125
+ });
126
+
127
+ it("[F2] 畸形条目(type 缺失/未知,normalizePendingType 归 workflow)× store 查不到 → 视同终态补注销", () => {
128
+ writeSessionFile([reg("bad-1", "mystery")]);
129
+ const { deps, appended } = makeDeps({}); // workflowStates 缺省 = 恒 missing
130
+ const result = runReconcileSweep(deps);
131
+ expect(result.reconciled).toEqual(["bad-1"]);
132
+ expect(appended[0].data).toEqual({ id: "bad-1", reason: "expired", status: "expired" });
133
+ });
134
+
135
+ it("[F2] type=bash → 保守跳过(无 record/store 可查,显式偏差——宁挂账不失明)", () => {
136
+ writeSessionFile([reg("bt-1", "bash")]);
137
+ const { deps, appended } = makeDeps({});
138
+ const result = runReconcileSweep(deps);
139
+ expect(result.skippedNonSubagent).toEqual(["bt-1"]);
140
+ expect(appended).toHaveLength(0);
141
+ });
142
+
143
+ it("[F2] deps 未注入 workflow 判据 → workflow/未知类型保守跳过(判据缺席 ≠ 可注销)", () => {
144
+ writeSessionFile([reg("wf-1", "workflow"), reg("bad-1", "mystery")]);
145
+ const { deps, appended } = makeDeps({ injectWorkflowLookup: false });
146
+ const result = runReconcileSweep(deps);
147
+ expect(result.skippedNonSubagent.sort()).toEqual(["bad-1", "wf-1"]);
148
+ expect(appended).toHaveLength(0);
149
+ });
150
+
151
+ it("已注销的 id 不出现在差集 → 不补发", () => {
152
+ writeSessionFile([reg("bg-1"), unreg("bg-1")]);
153
+ const { deps, appended } = makeDeps();
154
+ const result = runReconcileSweep(deps);
155
+ expect(result.reconciled).toEqual([]);
156
+ expect(appended).toHaveLength(0);
157
+ });
158
+
159
+ it("unregister 之后的重注册重新进差集(同 id 重 register = 后写胜出)", () => {
160
+ writeSessionFile([reg("bg-1"), unreg("bg-1"), reg("bg-1")]);
161
+ const { deps, appended } = makeDeps();
162
+ const result = runReconcileSweep(deps);
163
+ expect(result.reconciled).toEqual(["bg-1"]);
164
+ expect(appended).toHaveLength(1);
165
+ });
166
+
167
+ it("sessionFile 缺失 → 空跑(不抛)", () => {
168
+ const { deps } = makeDeps({ sessionFile: undefined });
169
+ const result = runReconcileSweep(deps);
170
+ expect(result.reconciled).toEqual([]);
171
+ });
172
+
173
+ it("session 文件不可读(未 flush/被删)→ 空跑", () => {
174
+ const { deps } = makeDeps({ sessionFile: path.join(tmpDir, "nope.jsonl") });
175
+ const result = runReconcileSweep(deps);
176
+ expect(result.reconciled).toEqual([]);
177
+ });
178
+
179
+ it("appendEntry 抛错 → 不计 reconciled、不 emit(差集残留交下次 sweep 重试)", () => {
180
+ writeSessionFile([reg("bg-1"), reg("bg-2")]);
181
+ const { deps, emitted } = makeDeps({
182
+ appendEntry: (customType, data) => {
183
+ if ((data as { id: string }).id === "bg-1") throw new Error("EACCES");
184
+ },
185
+ });
186
+ const result = runReconcileSweep(deps);
187
+ expect(result.reconciled).toEqual(["bg-2"]);
188
+ expect(emitted.map((e) => (e.data as { id: string }).id)).toEqual(["bg-2"]);
189
+ });
190
+
191
+ it("坏行(截断 JSON)跳过不拖垮其余条目", () => {
192
+ fs.writeFileSync(sessionFile, [JSON.stringify(reg("bg-1")), '{"customType":"pending:regis'].join("\n"), "utf-8");
193
+ const { deps, appended } = makeDeps({
194
+ states: new Map([["bg-1", { terminal: true, closedReason: "gc" }]]),
195
+ });
196
+ const result = runReconcileSweep(deps);
197
+ expect(result.reconciled).toEqual(["bg-1"]);
198
+ expect(appended).toHaveLength(1);
199
+ });
200
+ });
@@ -0,0 +1,102 @@
1
+ // src/execution/__tests__/record-entry-collect.test.ts
2
+ //
3
+ // subagent-record entry 序列化白名单:collectMode / batchFinalized 两字段
4
+ // (subagent-sync-collect U1 foundation)。
5
+ //
6
+ // 锁三件事(设计 §3.1.3):
7
+ // 1. 持久化:两字段在 entry data 中如实透传(round-trip 经 JSON 序列化不丢);
8
+ // 2. 零迁移:无字段(旧 record 形态)的 entry 产物不含新键(JSON.stringify 自然缺省),
9
+ // 与改动前逐字节一致;
10
+ // 3. customType 稳定:SUBAGENT_RECORD_CUSTOM_TYPE 不因扩字段漂移。
11
+
12
+ import { describe, expect, it } from "vitest";
13
+
14
+ import {
15
+ SUBAGENT_RECORD_CUSTOM_TYPE,
16
+ toSubagentRecordEntry,
17
+ type SubagentRecordEntryData,
18
+ } from "../record-entry.ts";
19
+ import type { SubagentRecord } from "../types.ts";
20
+
21
+ /** 最小合法 SubagentRecord(缺省无 collect 两字段 = 旧记录形态)。 */
22
+ function makeRecord(over: Partial<SubagentRecord> = {}): SubagentRecord {
23
+ return {
24
+ id: "sa-1",
25
+ agent: "/home/u/agents/worker.md",
26
+ task: "t",
27
+ slug: "worker",
28
+ status: "running",
29
+ mode: "background",
30
+ startedAt: 1000,
31
+ rootSessionId: "root-A",
32
+ parentRecordId: undefined,
33
+ depth: 0,
34
+ endedAt: undefined,
35
+ turns: 1,
36
+ totalTokens: 42,
37
+ model: "prov/m1",
38
+ thinkingLevel: undefined,
39
+ eventLog: [],
40
+ displayItems: [],
41
+ sessionFile: "sess-1.jsonl",
42
+ ...over,
43
+ } as SubagentRecord;
44
+ }
45
+
46
+ /** entry data 的 JSONL 形态字符串(appendEntry 落盘即此产物)。 */
47
+ function serialize(entry: SubagentRecordEntryData): string {
48
+ return JSON.stringify(entry);
49
+ }
50
+
51
+ describe("record-entry serialization: collect fields (U1 foundation)", () => {
52
+ it("keeps SUBAGENT_RECORD_CUSTOM_TYPE stable", () => {
53
+ expect(SUBAGENT_RECORD_CUSTOM_TYPE).toBe("subagent-record");
54
+ });
55
+
56
+ it("passes collectMode through for a sync record", () => {
57
+ const entry = toSubagentRecordEntry(makeRecord({ collectMode: "sync" }));
58
+ expect(entry.collectMode).toBe("sync");
59
+ expect(entry.batchFinalized).toBeUndefined();
60
+ });
61
+
62
+ it("passes batchFinalized through for a member that left the batch", () => {
63
+ const entry = toSubagentRecordEntry(
64
+ makeRecord({
65
+ collectMode: "sync",
66
+ batchFinalized: true,
67
+ status: "closed",
68
+ endedAt: 2000,
69
+ }),
70
+ );
71
+ expect(entry.collectMode).toBe("sync");
72
+ expect(entry.batchFinalized).toBe(true);
73
+ expect(entry.status).toBe("closed");
74
+ });
75
+
76
+ it("round-trips both fields through JSON serialization (persisted form)", () => {
77
+ const entry = toSubagentRecordEntry(
78
+ makeRecord({ collectMode: "sync", batchFinalized: true }),
79
+ );
80
+ const revived = JSON.parse(serialize(entry)) as SubagentRecordEntryData;
81
+ expect(revived.collectMode).toBe("sync");
82
+ expect(revived.batchFinalized).toBe(true);
83
+ expect(revived.v).toBe(1);
84
+ });
85
+
86
+ it("emits no new keys for legacy records (旧记录零迁移)", () => {
87
+ const json = serialize(toSubagentRecordEntry(makeRecord()));
88
+ expect(json).not.toContain("collectMode");
89
+ expect(json).not.toContain("batchFinalized");
90
+ const revived = JSON.parse(json) as SubagentRecordEntryData;
91
+ expect(revived.collectMode).toBeUndefined();
92
+ expect(revived.batchFinalized).toBeUndefined();
93
+ });
94
+
95
+ it("still emits the full legacy whitelist for legacy records (既有字段不受扩字段影响)", () => {
96
+ const entry = toSubagentRecordEntry(makeRecord());
97
+ expect(entry.id).toBe("sa-1");
98
+ expect(entry.status).toBe("running");
99
+ expect(entry.model).toBe("prov/m1");
100
+ expect(entry.sessionFile).toBe("sess-1.jsonl");
101
+ });
102
+ });
@@ -36,7 +36,7 @@ vi.mock("../sessions-index.ts", async (importOriginal) => {
36
36
  });
37
37
 
38
38
  import { writeAliveMarker } from "../alive-store.ts";
39
- import { completeRecord, createRecord, tryTransition } from "../execution-record.ts";
39
+ import { completeRecord, createRecord, projectOutcome, tryTransition } from "../execution-record.ts";
40
40
  import { writeFinalized } from "../finalized-marker.ts";
41
41
  import type { ManifestRecord } from "../manifest-store.ts";
42
42
  import { ManifestStore } from "../manifest-store.ts";
@@ -817,7 +817,7 @@ describe("RecordStore", () => {
817
817
  return { store, appended };
818
818
  }
819
819
 
820
- it("末行完整 closed 终态 entry + .finalized sidecar(防重锚)", () => {
820
+ it("末行完整(in-flight,无 resumable)→ closed + 重启中断 error,投影 failed([F3] 表 3 行 2)", () => {
821
821
  const sessionFile = path.join(tmpDir, "orphan-done.jsonl");
822
822
  writeSessionJsonl(sessionFile, {
823
823
  id: "sa-orphan-1", agent: "worker", mode: "background", task: "orphan done",
@@ -831,7 +831,14 @@ describe("RecordStore", () => {
831
831
  expect(entry?.data.status).toBe("closed");
832
832
  expect(entry?.data.closedReason).toBe("gc");
833
833
  expect(entry?.data.endedAt).toEqual(expect.any(Number));
834
- expect(entry?.data.error).toBeUndefined();
834
+ // [F3] in-flight 直断 = boot 直断 failed 语义:任务因宿主重启中断,不得投影
835
+ // completed(事故环 3 残留)。error 载体 → deriveOutcome("gc", error) = failed。
836
+ expect(entry?.data.error).toContain("host restart");
837
+ expect(projectOutcome({
838
+ status: "closed",
839
+ closedReason: entry?.data.closedReason as never,
840
+ error: entry?.data.error as string | undefined,
841
+ })).toBe("failed");
835
842
  expect(fs.existsSync(`${sessionFile}.finalized`)).toBe(true);
836
843
  // 防重:sidecar 使下次重建走分支 2(closed),不再进判定
837
844
  const again = [...appended];
@@ -841,7 +848,51 @@ describe("RecordStore", () => {
841
848
  expect(found?.status).toBe("closed");
842
849
  });
843
850
 
844
- it("末行截断 closed + error(保守方向)", () => {
851
+ it("SP-5 完成态(resumable + result 有值)→ completed 无 error(不误标重启失败,[F3] 不回归)", () => {
852
+ const sessionFile = path.join(tmpDir, "orphan-sp5.jsonl");
853
+ writeSessionJsonl(sessionFile, {
854
+ id: "sa-orphan-sp5", agent: "worker", mode: "background", task: "sp5 done",
855
+ startedAt: 6000, rootSessionId: "sess-orphan",
856
+ });
857
+ // 主 session 末条 entry(v2 D3 merge 数据源)携 resumable+result——W4 起轮终
858
+ // 执行态信号随 entry 保留,子文件侧重建不带该信号。data 需过 rebuildEntryRecord
859
+ // 形状守卫(agent/task/startedAt 必带)。
860
+ const mainFile = writeMainSession([
861
+ { id: "sa-orphan-sp5", agent: "worker", task: "sp5 done", startedAt: 6000, status: "running", resumable: true, result: "final answer text" },
862
+ ]);
863
+ const { store, appended } = makeRecoveryStore();
864
+ store.recoverOrphanRecords("sess-orphan", mainFile);
865
+
866
+ const entry = appended.find((c) => c.data.id === "sa-orphan-sp5");
867
+ expect(entry?.data.status).toBe("closed");
868
+ expect(entry?.data.error).toBeUndefined();
869
+ expect(projectOutcome({
870
+ status: "closed",
871
+ closedReason: entry?.data.closedReason as never,
872
+ error: entry?.data.error as string | undefined,
873
+ })).toBe("completed");
874
+ });
875
+
876
+ it("resumable 无产出 → 保持 running 落 resumable entry(W4 死亡纳管态跨重启,boot 重认领源,不直断)", () => {
877
+ const sessionFile = path.join(tmpDir, "orphan-resumable.jsonl");
878
+ writeSessionJsonl(sessionFile, {
879
+ id: "sa-orphan-res", agent: "worker", mode: "background", task: "resumable orphan",
880
+ startedAt: 7000, rootSessionId: "sess-orphan",
881
+ });
882
+ const mainFile = writeMainSession([
883
+ { id: "sa-orphan-res", agent: "worker", task: "resumable orphan", startedAt: 7000, status: "running", resumable: true },
884
+ ]);
885
+ const { store, appended } = makeRecoveryStore();
886
+ store.recoverOrphanRecords("sess-orphan", mainFile);
887
+
888
+ const entry = appended.find((c) => c.data.id === "sa-orphan-res");
889
+ expect(entry?.data.status).toBe("running");
890
+ expect(entry?.data.resumable).toBe(true);
891
+ // 保留分支不写终态 sidecar
892
+ expect(fs.existsSync(`${sessionFile}.finalized`)).toBe(false);
893
+ });
894
+
895
+ it("末行截断 → closed + error(保守方向;[F3] in-flight 同时携重启中断语义)", () => {
845
896
  const sessionFile = path.join(tmpDir, "orphan-truncated.jsonl");
846
897
  writeSessionJsonl(sessionFile, {
847
898
  id: "sa-orphan-2", agent: "worker", mode: "background", task: "orphan truncated",
@@ -855,10 +906,11 @@ describe("RecordStore", () => {
855
906
  const entry = appended.find((c) => c.data.id === "sa-orphan-2");
856
907
  expect(entry?.data.status).toBe("closed");
857
908
  expect(entry?.data.error).toContain("truncated");
909
+ expect(entry?.data.error).toContain("host restart");
858
910
  expect(fs.existsSync(`${sessionFile}.finalized`)).toBe(true);
859
911
  });
860
912
 
861
- it("末行 >64KB 完整 JSON → 不误判截断,判 done(V1 探针实测回归)", () => {
913
+ it("末行 >64KB 完整 JSON → 不误判截断,[F3] in-flight 携重启中断 error(无 truncated)", () => {
862
914
  const sessionFile = path.join(tmpDir, "orphan-longline.jsonl");
863
915
  writeSessionJsonl(sessionFile, {
864
916
  id: "sa-orphan-5", agent: "worker", mode: "background", task: "orphan long line",
@@ -877,7 +929,9 @@ describe("RecordStore", () => {
877
929
 
878
930
  const entry = appended.find((c) => c.data.id === "sa-orphan-5");
879
931
  expect(entry?.data.status).toBe("closed");
880
- expect(entry?.data.error).toBeUndefined();
932
+ // [F3] in-flight 重启中断 error 必有;「不误判截断」= error 不含 truncated 标记
933
+ expect(entry?.data.error).toContain("host restart");
934
+ expect(entry?.data.error).not.toContain("truncated");
881
935
  expect(fs.existsSync(`${sessionFile}.finalized`)).toBe(true);
882
936
  });
883
937
 
@@ -27,7 +27,6 @@ import {
27
27
  finalizedMarkerModule,
28
28
  fsSyncModule,
29
29
  manifestStoreModule,
30
- tempPromptModule,
31
30
  } from "./helpers/subagent-service-mocks.ts";
32
31
 
33
32
  // ── mock modules(同 execute-nesting.test.ts)──
@@ -37,11 +36,11 @@ vi.mock("node:fs", async (importOriginal) => fsSyncModule(await importOriginal<t
37
36
  vi.mock("../alive-store.ts", async (importOriginal) => aliveStoreModule(await importOriginal<typeof import("../alive-store.ts")>()));
38
37
  vi.mock("../finalized-marker.ts", () => finalizedMarkerModule());
39
38
  vi.mock("../manifest-store.ts", () => manifestStoreModule());
40
- vi.mock("../engine/engines/pi/temp-prompt.ts", () => tempPromptModule());
41
39
 
42
40
  import { spawn } from "node:child_process";
43
41
 
44
- import { waitForSpawn, lastSpawnedChild } from "./helpers/spawn-mock.ts";
42
+ import { registerFakePiEngine, type FakePiEnginePort } from "./helpers/fake-engine-port.ts";
43
+ import { clearEngines } from "../engine/registry.ts";
45
44
  import { ModelConfigService } from "../model-config-service.ts";
46
45
  import type { ModelInfo, ModelRegistryLike } from "../model-resolver.ts";
47
46
  import { ManifestStore } from "../manifest-store.ts";
@@ -62,6 +61,13 @@ function getLastSpawnEnv(): Record<string, string | undefined> {
62
61
  return (mockSpawn.mock.calls.at(-1)?.[2]?.env as Record<string, string | undefined>) ?? {};
63
62
  }
64
63
 
64
+ /** [W3] 协议替身:execute → engine.run 挂起不 settle——record 保持 running 在 store
65
+ * 可观察(原 FakeChild 挂起不推进的等价形态)。 */
66
+ function registerHangingEngine(): FakePiEnginePort {
67
+ clearEngines();
68
+ return registerFakePiEngine();
69
+ }
70
+
65
71
  // ── 辅助:service 构造 ──
66
72
 
67
73
  function makeEmptyRegistry(): ModelRegistryLike {
@@ -122,6 +128,7 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
122
128
  process.env[ENV_DEPTH] = "1";
123
129
 
124
130
  const { service, store } = setup({});
131
+ registerHangingEngine();
125
132
 
126
133
  // 不在 execCtxAls.run 内调用(模拟 ALS 断裂:事件回调上下文读不到 store)
127
134
  const handle = await service.execute({ task: "child of parent", slug: "test", ctxModel });
@@ -143,6 +150,7 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
143
150
 
144
151
  it("[顶层] 无 env(根进程):parentRecordId undefined / depth 0", async () => {
145
152
  const { service, store } = setup({});
153
+ registerHangingEngine();
146
154
 
147
155
  const handle = await service.execute({ task: "top level", slug: "test", ctxModel });
148
156
 
@@ -158,6 +166,7 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
158
166
  process.env[ENV_DEPTH] = "0";
159
167
 
160
168
  const { service, store } = setup({});
169
+ registerHangingEngine();
161
170
  const execNesting = Reflect.get(service, "execNesting") as ExecCtxAls;
162
171
 
163
172
  const handle = await execNesting.run({ recordId: "sa-inline-parent", depth: 3 }, () =>
@@ -170,24 +179,22 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
170
179
  expect(rec!.depth).toBe(4);
171
180
  });
172
181
 
173
- it("[forkDepth 基线] env PI_SUBAGENT_FORK_DEPTH=1 + fork:spawn env 递增为 2(读点兜底基线生效)", async () => {
182
+ it("[forkDepth 基线] env PI_SUBAGENT_FORK_DEPTH=1 initSession 建立基线(读点兜底基线生效)", async () => {
183
+ // [W3 改写] spawn env 注入(PI_SUBAGENT_FORK_DEPTH 递增写子 env)属 inproc
184
+ // runSpawn 机制,随 inproc pi 引擎目录 删除迁入引擎包(pi-subagent-cli spawn 链);core
185
+ // 侧存留语义 = initSession 从 env 建立基线(ALS 断裂时的读点兜底),本用例锁定它。
174
186
  process.env[ENV_ROOT_SESSION_ID] = "root-main";
175
187
  process.env[ENV_SELF_RECORD_ID] = "sa-fork-parent";
176
188
  process.env[ENV_DEPTH] = "0";
177
189
  process.env[ENV_FORK_DEPTH] = "1";
178
190
 
179
191
  const { service } = setup({});
192
+ registerHangingEngine();
180
193
 
181
- const execPromise = service.execute({ task: "fork child", slug: "test", ctxModel, fork: true });
182
- await waitForSpawn(mockSpawn);
183
- const childEnv = getLastSpawnEnv();
184
-
185
- // 742 行 parentDepth = forkDepthAls.getStore() ?? forkDepthBaseline —— ALS 断裂时基线=1,+1 → 2
186
- expect(childEnv.PI_SUBAGENT_FORK_DEPTH).toBe("2");
194
+ expect(Reflect.get(service, "forkDepthBaseline")).toBe(1);
187
195
 
188
- const child = lastSpawnedChild(mockSpawn);
189
- child.emit("close", 0);
190
- await execPromise;
196
+ // fork 请求照常派发(引擎侧承载深度传递)——不因基线读取抛错
197
+ await expect(service.execute({ task: "fork child", slug: "test", ctxModel, fork: true })).resolves.toBeDefined();
191
198
  });
192
199
 
193
200
  it("[嵌套护栏] 基线 depth 参与 execute 入口嵌套护栏(depth>MAX 拒绝)", async () => {
@@ -25,7 +25,18 @@ describe('relay env SSOT', () => {
25
25
  expect(isRelayActive({ ...full, [RELAY_ENV_SOCKET]: '' })).toBe(false);
26
26
  expect(isRelayActive({ ...full, [RELAY_ENV_NODE]: undefined })).toBe(false);
27
27
  expect(isRelayActive({})).toBe(false);
28
- expect(isRelayActive(process.env)).toBe(false);
28
+ // [验收门修复] 宿主(pi 子进程链)可能注入 RELAY env——断言对象改为「清空 RELAY
29
+ // 键后的副本」:保留真实环境形态意图的同时对泄漏免疫(与 pi-invocation.test.ts
30
+ // 的 beforeEach 清理同病同修,不依赖 runner 环境)。
31
+ const sanitized: Record<string, string | undefined> = {
32
+ ...process.env,
33
+ [RELAY_ENV_SOCKET]: undefined,
34
+ [RELAY_ENV_NODE]: undefined,
35
+ [RELAY_ENV_SCRIPT]: undefined,
36
+ [RELAY_ENV_SESSION_ID]: undefined,
37
+ [RELAY_ENV_RECORD_ID]: undefined,
38
+ };
39
+ expect(isRelayActive(sanitized)).toBe(false);
29
40
  });
30
41
 
31
42
  it('env 名与退出码稳定(relay.mjs 镜像一致性由 conformance relay 断言锁定)', () => {