@zhushanwen/subagent-core 0.4.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 (272) 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 +16418 -14070
  11. package/dist/index.d.cts +5136 -4016
  12. package/dist/index.d.ts +5136 -4016
  13. package/dist/index.js +16343 -14048
  14. package/dist/{types-DpUO16pj.d.cts → types-Dv4QhSJ_.d.cts} +215 -112
  15. package/dist/{types-DpUO16pj.d.ts → types-Dv4QhSJ_.d.ts} +215 -112
  16. package/package.json +3 -3
  17. package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
  18. package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
  19. package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
  20. package/src/__tests__/m2-append-content-probe.test.ts +0 -1
  21. package/src/__tests__/manifest-store.test.ts +10 -9
  22. package/src/__tests__/record-store-cache.test.ts +0 -2
  23. package/src/__tests__/record-store-index.test.ts +1 -2
  24. package/src/__tests__/review-fix-loop-script.test.ts +4 -2
  25. package/src/__tests__/review-fix-loop-utils.test.ts +10 -10
  26. package/src/__tests__/robustness-low-batch1.test.ts +6 -5
  27. package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
  28. package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
  29. package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
  30. package/src/__tests__/session-runner.test.ts +1 -1
  31. package/src/core/__tests__/host-services.test.ts +2 -2
  32. package/src/core/__tests__/logger.test.ts +1 -1
  33. package/src/core/error-message.ts +9 -0
  34. package/src/core/host-services.ts +21 -5
  35. package/src/core/notify-ports.ts +18 -5
  36. package/src/execution/__tests__/agent-profile.test.ts +4 -4
  37. package/src/execution/__tests__/agent-registry.test.ts +370 -0
  38. package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
  39. package/src/execution/__tests__/agents-assembly.test.ts +2 -2
  40. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
  41. package/src/execution/__tests__/chat-engine-routing.test.ts +68 -33
  42. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +4 -4
  43. package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
  44. package/src/execution/__tests__/delivery-methods.test.ts +75 -62
  45. package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
  46. package/src/execution/__tests__/descendant-sweep.test.ts +6 -6
  47. package/src/execution/__tests__/dialog-queue.test.ts +2 -2
  48. package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
  49. package/src/execution/__tests__/epipe-fallback.test.ts +29 -24
  50. package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
  51. package/src/execution/__tests__/execute-nesting.test.ts +34 -188
  52. package/src/execution/__tests__/execution-record.test.ts +217 -60
  53. package/src/execution/__tests__/execution-runtime-face.test.ts +5 -5
  54. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +3 -3
  55. package/src/execution/__tests__/finalize-record.test.ts +173 -17
  56. package/src/execution/__tests__/gc-timer.test.ts +55 -2
  57. package/src/execution/__tests__/get-record-for-action-restart.test.ts +12 -12
  58. package/src/execution/__tests__/get-state-handshake.test.ts +1 -1
  59. package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
  60. package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
  61. package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
  62. package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
  63. package/src/execution/__tests__/keep-alive-no-progress.test.ts +50 -148
  64. package/src/execution/__tests__/kill-all-escalation.test.ts +2 -2
  65. package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
  66. package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
  67. package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +1 -1
  68. package/src/execution/__tests__/model-resolver.test.ts +2 -2
  69. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
  70. package/src/execution/__tests__/nested-visibility.test.ts +2 -0
  71. package/src/execution/__tests__/notify-ledger.test.ts +973 -18
  72. package/src/execution/__tests__/output-collector.test.ts +117 -6
  73. package/src/execution/__tests__/pi-invocation.test.ts +1 -1
  74. package/src/execution/__tests__/record-store.test.ts +10 -9
  75. package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
  76. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
  77. package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
  78. package/src/execution/__tests__/rpc-mode.test.ts +2 -2
  79. package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
  80. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +15 -9
  81. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +4 -4
  82. package/src/execution/__tests__/run-spawn-edges.test.ts +17 -15
  83. package/src/execution/__tests__/run-spawn-integration.test.ts +2 -2
  84. package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
  85. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
  86. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +4 -4
  87. package/src/execution/__tests__/service-kill-escalation.test.ts +7 -5
  88. package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
  89. package/src/execution/__tests__/session-file-gc.test.ts +35 -0
  90. package/src/execution/__tests__/session-pending.test.ts +257 -14
  91. package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
  92. package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +1 -1
  93. package/src/execution/__tests__/session-runner-close-prune.test.ts +2 -2
  94. package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
  95. package/src/execution/__tests__/session-runner-epipe.test.ts +3 -3
  96. package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +5 -4
  97. package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
  98. package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
  99. package/src/execution/__tests__/settled-watchdog.test.ts +282 -47
  100. package/src/execution/__tests__/spawn-args.test.ts +11 -10
  101. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
  102. package/src/execution/__tests__/spawn-event-adapter.test.ts +1 -1
  103. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
  104. package/src/execution/__tests__/spawned-children.test.ts +2 -1
  105. package/src/execution/__tests__/start-sync-model-guard.test.ts +4 -4
  106. package/src/execution/__tests__/stdin-writer.test.ts +6 -4
  107. package/src/execution/__tests__/stream-sink-retirement.test.ts +6 -6
  108. package/src/execution/__tests__/subagent-actions-core.test.ts +42 -22
  109. package/src/execution/__tests__/subagent-service-message-close.test.ts +29 -26
  110. package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +8 -8
  111. package/src/execution/__tests__/subagent-service-notify-gate.test.ts +27 -22
  112. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +30 -29
  113. package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +45 -20
  114. package/src/execution/__tests__/subagent-service.test.ts +37 -30
  115. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
  116. package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
  117. package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
  118. package/src/execution/__tests__/temp-prompt.test.ts +1 -1
  119. package/src/execution/__tests__/timeout-integration.test.ts +6 -5
  120. package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
  121. package/src/execution/__tests__/turn-limiter.test.ts +1 -1
  122. package/src/execution/__tests__/ui-request-handler-factory.test.ts +12 -6
  123. package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
  124. package/src/execution/__tests__/ui-request-queue.test.ts +142 -2
  125. package/src/execution/__tests__/worktree-manager.test.ts +14 -5
  126. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
  127. package/src/execution/agent-registry.ts +74 -30
  128. package/src/execution/agent-result-mapper.ts +3 -0
  129. package/src/execution/cold-resurrect.ts +199 -0
  130. package/src/execution/engine/__tests__/common/capability-gate.test.ts +91 -0
  131. package/src/execution/engine/__tests__/common/data-dir.test.ts +1 -1
  132. package/src/execution/engine/__tests__/common/journal-wiring.test.ts +84 -0
  133. package/src/execution/engine/__tests__/common/kill-chain.test.ts +34 -7
  134. package/src/execution/engine/__tests__/common/persona-router.test.ts +4 -5
  135. package/src/execution/engine/__tests__/common/pool-manager.test.ts +211 -51
  136. package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +149 -0
  137. package/src/execution/engine/__tests__/common/session-view-service.test.ts +499 -0
  138. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +22 -112
  139. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +15 -28
  140. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +12 -12
  141. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +1 -1
  142. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +21 -82
  143. package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +4 -7
  144. package/src/execution/engine/__tests__/engine-discovery.test.ts +15 -3
  145. package/src/execution/engine/__tests__/model-prompt.test.ts +15 -3
  146. package/src/execution/engine/__tests__/registry.test.ts +4 -2
  147. package/src/execution/engine/__tests__/routing.test.ts +115 -6
  148. package/src/execution/engine/common/capability-gate.ts +92 -0
  149. package/src/execution/engine/common/journal-wiring.ts +97 -0
  150. package/src/execution/engine/common/kill-chain.ts +42 -10
  151. package/src/execution/engine/common/nesting-guard.ts +66 -0
  152. package/src/execution/engine/common/persona-router.ts +18 -8
  153. package/src/execution/engine/common/pool-manager.ts +332 -78
  154. package/src/execution/engine/common/session-view-service.ts +506 -0
  155. package/src/execution/engine/common/session-view-types.ts +125 -0
  156. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +174 -28
  157. package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
  158. package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
  159. package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +1 -1
  160. package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
  161. package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
  162. package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
  163. package/src/execution/engine/engines/pi/reader.ts +11 -0
  164. package/src/execution/engine/engines/pi/registration.ts +4 -2
  165. package/src/execution/{session-runner.ts → engine/engines/pi/session-runner.ts} +617 -412
  166. package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
  167. package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
  168. package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
  169. package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
  170. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +54 -27
  171. package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
  172. package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +13 -12
  173. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
  174. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
  175. package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
  176. package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
  177. package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +20 -8
  178. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +77 -110
  179. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +25 -319
  180. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
  181. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
  182. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
  183. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
  184. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +48 -148
  185. package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
  186. package/src/execution/engine/engines/zcode/connection.ts +24 -11
  187. package/src/execution/engine/engines/zcode/constants.ts +75 -71
  188. package/src/execution/engine/engines/zcode/golden-sample.ts +8 -46
  189. package/src/execution/engine/engines/zcode/parser.ts +12 -346
  190. package/src/execution/engine/engines/zcode/preparer.ts +12 -143
  191. package/src/execution/engine/engines/zcode/session-channel.ts +351 -39
  192. package/src/execution/engine/engines/zcode/zcode-engine.ts +665 -760
  193. package/src/execution/engine/host-task-spec.ts +32 -36
  194. package/src/execution/engine/model-validation.ts +177 -0
  195. package/src/execution/engine/port.ts +24 -6
  196. package/src/execution/engine/routing.ts +75 -1
  197. package/src/execution/engine/types.ts +30 -103
  198. package/src/execution/execution-record.ts +222 -144
  199. package/src/execution/finalize-record.ts +131 -93
  200. package/src/execution/idle-gc.ts +28 -0
  201. package/src/execution/lifecycle-predicates.ts +1 -1
  202. package/src/execution/notify-host.ts +212 -0
  203. package/src/execution/record-store.ts +119 -73
  204. package/src/execution/round-settlement.ts +93 -0
  205. package/src/execution/session-file-gc.ts +96 -62
  206. package/src/execution/session-reconstructor.ts +256 -143
  207. package/src/execution/sessions-index.ts +117 -47
  208. package/src/execution/settled-watchdog.ts +264 -52
  209. package/src/execution/subagent-actions-core.ts +22 -22
  210. package/src/execution/subagent-service.ts +815 -963
  211. package/src/execution/subprocess-agent-runner.ts +144 -97
  212. package/src/execution/types.ts +9 -0
  213. package/src/execution/ui-request-handler-factory.ts +102 -74
  214. package/src/execution/ui-request-queue.ts +50 -19
  215. package/src/index.ts +442 -316
  216. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +1 -1
  217. package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
  218. package/src/orchestration/__tests__/args-validator.test.ts +14 -0
  219. package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +1 -1
  220. package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +11 -9
  221. package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
  222. package/src/orchestration/__tests__/file-run-store.test.ts +7 -6
  223. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +2 -2
  224. package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +1 -1
  225. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
  226. package/src/orchestration/__tests__/lifecycle.test.ts +7 -5
  227. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
  228. package/src/orchestration/__tests__/run-snapshot.test.ts +8 -5
  229. package/src/orchestration/__tests__/script-lint.test.ts +17 -0
  230. package/src/orchestration/__tests__/test-mocks.ts +2 -0
  231. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +7 -6
  232. package/src/orchestration/__tests__/worker-message-pump-finalize-run.test.ts +229 -0
  233. package/src/orchestration/__tests__/{error-recovery-handlers.test.ts → worker-message-pump-handlers.test.ts} +27 -19
  234. package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
  235. package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
  236. package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
  237. package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +1 -1
  238. package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
  239. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
  240. package/src/orchestration/agent-opts-resolver.ts +1 -1
  241. package/src/orchestration/args-validator.ts +53 -31
  242. package/src/orchestration/execute-agent-call.ts +19 -73
  243. package/src/orchestration/launcher.ts +128 -81
  244. package/src/orchestration/lifecycle.ts +43 -45
  245. package/src/orchestration/models/ports.ts +4 -4
  246. package/src/orchestration/models/run-runtime.ts +2 -2
  247. package/src/orchestration/models/trace.ts +1 -1
  248. package/src/orchestration/models/types.ts +111 -22
  249. package/src/orchestration/models/workflow-run.ts +1 -1
  250. package/src/orchestration/script-lint.ts +91 -58
  251. package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +157 -150
  252. package/src/shared/__tests__/meta-parser.test.ts +151 -0
  253. package/src/shared/__tests__/resource-discovery.test.ts +258 -215
  254. package/src/shared/atomic-write.ts +12 -9
  255. package/src/shared/meta-parser.ts +158 -84
  256. package/src/shared/model-ref.ts +15 -2
  257. package/src/shared/resource-discovery.ts +9 -183
  258. package/src/shared/schema-jsonify.ts +1 -1
  259. package/workflows/review-fix-loop-utils.cjs +151 -89
  260. package/workflows/review-fix-loop-utils.d.cts +287 -0
  261. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  262. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  263. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  264. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  265. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  266. package/src/execution/engine/engines/zcode/__tests__/preparer-appserver.test.ts +0 -387
  267. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -710
  268. package/src/execution/engine/engines/zcode/appserver-home.ts +0 -442
  269. package/src/execution/engine/engines/zcode/appserver-probe.ts +0 -141
  270. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  271. package/src/execution/execute-options-mapper.ts +0 -115
  272. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
@@ -7,150 +7,46 @@
7
7
  //
8
8
  // 这是场景 1(端到端三层嵌套全树可见)的「env 传递机制」确定性验证——不依赖 LLM 配合,
9
9
  // mock spawn 拦截 childEnv 直接断言。端到端可见性由场景 1(真实 pi CLI + recursive-worker agent)覆盖。
10
-
11
- import type { PassThrough } from "node:stream";
10
+ //
11
+ // mock 块与 fixture 收敛 __tests__/helpers/spawn-mock.ts(vi.mock 工厂 await import 转发,
12
+ // 单源共享);vi.mocked 取回与收尾装配来自 helpers/session-runner-mocks.ts。
12
13
 
13
14
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
14
15
 
15
16
  import { getSubagentSessionDir } from "../path-encoding.ts";
16
17
 
17
- // ── mock modules(同 session-runner-schema-env.test.ts 模式)──
18
-
19
- vi.mock("node:child_process", async () => {
20
- const { EventEmitter } = await import("node:events");
21
- const { PassThrough } = await import("node:stream");
22
-
23
- class FakeChild extends EventEmitter {
24
- pid = 12345;
25
- stdout = new PassThrough();
26
- stdin = new PassThrough(); // runSpawn 注册 stdin EPIPE handler(session-runner),FakeChild 必须提供
27
- stderr = new PassThrough();
28
- killed = false;
29
- killSignal: string | undefined;
30
- kill(sig?: string): boolean {
31
- this.killed = true;
32
- this.killSignal = sig;
33
- return true;
34
- }
35
- }
36
-
37
- return {
38
- spawn: vi.fn(() => new FakeChild()),
39
- // buildEnvBlock execFile 异步取 git branch:默认 err-first 兜底(catch → branch=""),
40
- // 形态同 worktree-manager.test.ts 的 setupExecFile
41
- execFile: vi.fn(
42
- (
43
- _cmd: string,
44
- _args: readonly string[],
45
- _opts: unknown,
46
- cb: (err: Error | null, stdout?: string, stderr?: string) => void,
47
- ) => cb(new Error("execFile not configured in this test")),
48
- ),
49
- };
50
- });
51
-
52
- vi.mock("node:fs", async () => {
53
- const actual = await import("node:fs");
54
- return {
55
- default: {
56
- ...actual,
57
- mkdirSync: vi.fn(),
58
- existsSync: vi.fn(() => false),
59
- appendFileSync: vi.fn(),
60
- writeFileSync: vi.fn(),
61
- readdirSync: vi.fn(() => []),
62
- },
63
- mkdirSync: vi.fn(),
64
- existsSync: vi.fn(() => false),
65
- appendFileSync: vi.fn(),
66
- writeFileSync: vi.fn(),
67
- readdirSync: vi.fn(() => []),
68
- promises: actual.promises,
69
- };
70
- });
71
-
72
- vi.mock("../alive-store.ts", () => ({
73
- writeAliveMarker: vi.fn(),
74
- }));
75
-
76
- vi.mock("../temp-prompt.ts", () => ({
77
- writePromptToTempFile: vi.fn(async (agent: string) => {
78
- const safeName = agent.replace(/[^\w.-]+/g, "_");
79
- return { dir: `/tmp/fake-${safeName}`, filePath: `/tmp/fake-${safeName}/prompt-${safeName}.md` };
80
- }),
81
- cleanupTempPrompt: vi.fn(async () => {}),
82
- }));
83
-
84
- import { spawn } from "node:child_process";
85
- import * as fs from "node:fs";
86
-
87
- import { waitForSpawn } from "./helpers/spawn-mock.ts";
88
- import { createRecord } from "../execution-record.ts";
89
- import { type RunOptions, runSpawn, type SessionRunnerContext } from "../session-runner.ts";
90
-
91
- const mockSpawn = vi.mocked(spawn);
92
- const mockExistsSync = vi.mocked(fs.existsSync);
93
-
94
- interface FakeChild {
95
- pid: number;
96
- stdout: PassThrough;
97
- stderr: PassThrough;
98
- killed: boolean;
99
- killSignal: string | undefined;
100
- kill(sig?: string): boolean;
101
- emit(event: string, ...args: unknown[]): boolean;
102
- }
103
-
104
- function getLastSpawnedChild(): FakeChild {
105
- const result = mockSpawn.mock.results.at(-1);
106
- if (!result) throw new Error("spawn was not called yet");
107
- return result.value as FakeChild;
108
- }
109
-
110
- function getLastSpawnEnv(): Record<string, string | undefined> {
111
- return (mockSpawn.mock.calls.at(-1)?.[2]?.env as Record<string, string | undefined>) ?? {};
112
- }
113
-
114
- // ── fixture ──
115
-
116
- function makeRecord(overrides: { id?: string; depth?: number } = {}) {
117
- return createRecord(overrides.id ?? "sa-test-record", {
118
- agent: "general-purpose",
119
- model: "test/model",
120
- mode: "background",
121
- task: "test task",
122
- startedAt: Date.now(),
123
- rootSessionId: "should-be-overridden-by-sessionRootId-source",
124
- parentRecordId: undefined,
125
- depth: overrides.depth ?? 0,
126
- });
127
- }
128
-
129
- function makeRunOpts(overrides: Partial<RunOptions> = {}): RunOptions {
130
- return {
131
- resolved: { model: { provider: "test", id: "model" }, thinkingLevel: undefined },
132
- agentConfig: undefined,
133
- appendSystemPrompt: undefined,
134
- skillPath: undefined,
135
- schema: undefined,
136
- maxTurns: undefined,
137
- graceTurns: undefined,
138
- signal: undefined,
139
- onEvent: undefined,
140
- ...overrides,
141
- };
142
- }
143
-
144
- function makeCtx(overrides: Partial<SessionRunnerContext> = {}): SessionRunnerContext {
145
- return {
146
- cwd: "/fake/cwd",
147
- agentDir: "/fake/agent",
148
- skillDirs: [],
149
- mainCwd: "/fake/cwd",
150
- sessionRootId: "root-main-session",
151
- rootCwd: "/fake/cwd",
152
- ...overrides,
153
- };
18
+ // ── mock modules(同 session-runner-schema-env.test.ts 模式,工厂单源在 spawn-mock.ts)──
19
+
20
+ vi.mock("node:child_process", async () =>
21
+ (await import("./helpers/spawn-mock.ts")).childProcessModule());
22
+ vi.mock("node:fs", async () => (await import("./helpers/spawn-mock.ts")).fsModule());
23
+ vi.mock("../alive-store.ts", async () =>
24
+ (await import("./helpers/spawn-mock.ts")).aliveStoreModule());
25
+ vi.mock("../engine/engines/pi/temp-prompt.ts", async () =>
26
+ (await import("./helpers/spawn-mock.ts")).tempPromptModule());
27
+
28
+ import { runSpawn } from "../engine/engines/pi/session-runner.ts";
29
+ import {
30
+ getLastSpawnEnv,
31
+ makeRunOpts,
32
+ makeVisibilityCtx,
33
+ makeVisibilityRecord,
34
+ waitForSpawn,
35
+ } from "./helpers/spawn-mock.ts";
36
+ import { closeLastChildAndAwait, takeSessionRunnerMocks } from "./helpers/session-runner-mocks.ts";
37
+
38
+ const { mockSpawn, mockExistsSync } = takeSessionRunnerMocks();
39
+
40
+ /** runSpawn 前奏装配:启动、等 spawn 落位、取回 childEnv(断言留在各用例)。 */
41
+ async function spawnAndCaptureEnv(
42
+ record: ReturnType<typeof makeVisibilityRecord>,
43
+ task: string,
44
+ opts: ReturnType<typeof makeRunOpts>,
45
+ ctx: ReturnType<typeof makeVisibilityCtx>,
46
+ ): Promise<{ resultPromise: Promise<unknown>; childEnv: Record<string, string | undefined> }> {
47
+ const resultPromise = runSpawn(record, task, opts, ctx);
48
+ await waitForSpawn(mockSpawn);
49
+ return { resultPromise, childEnv: getLastSpawnEnv(mockSpawn) };
154
50
  }
155
51
 
156
52
  // ── runSpawn childEnv 身份 env 注入(场景 1b)──
@@ -166,13 +62,11 @@ describe("runSpawn 跨进程身份 env 注入(递归可见性场景 1b)", ()
166
62
  });
167
63
 
168
64
  it("非 fork(fork=false/undefined):无条件注入 4 个身份 env(决策 2)", async () => {
169
- const record = makeRecord({ id: "sa-aaa", depth: 0 });
170
- const ctx = makeCtx({ sessionRootId: "root-main" });
65
+ const record = makeVisibilityRecord({ id: "sa-aaa", depth: 0 });
66
+ const ctx = makeVisibilityCtx({ sessionRootId: "root-main" });
171
67
  const opts = makeRunOpts({ fork: false });
172
68
 
173
- const resultPromise = runSpawn(record, "test task", opts, ctx);
174
- await waitForSpawn(mockSpawn);
175
- const childEnv = getLastSpawnEnv();
69
+ const { resultPromise, childEnv } = await spawnAndCaptureEnv(record, "test task", opts, ctx);
176
70
 
177
71
  expect(childEnv.PI_SUBAGENT_ROOT_SESSION_ID).toBe("root-main");
178
72
  expect(childEnv.PI_SUBAGENT_SELF_RECORD_ID).toBe("sa-aaa");
@@ -182,19 +76,15 @@ describe("runSpawn 跨进程身份 env 注入(递归可见性场景 1b)", ()
182
76
  // fork=false 不注入 fork depth env(与既有行为一致,本测试不改变它)
183
77
  expect(childEnv.PI_SUBAGENT_FORK_DEPTH).toBeUndefined();
184
78
 
185
- const child = getLastSpawnedChild();
186
- child.emit("close", 0);
187
- await resultPromise;
79
+ await closeLastChildAndAwait(resultPromise);
188
80
  });
189
81
 
190
82
  it("fork=true:4 个身份 env 与 fork depth env 共存(决策 2 无条件注入不依赖 fork)", async () => {
191
- const record = makeRecord({ id: "sa-bbb", depth: 2 });
192
- const ctx = makeCtx({ sessionRootId: "root-main" });
83
+ const record = makeVisibilityRecord({ id: "sa-bbb", depth: 2 });
84
+ const ctx = makeVisibilityCtx({ sessionRootId: "root-main" });
193
85
  const opts = makeRunOpts({ fork: true, parentForkDepth: 1 });
194
86
 
195
- const resultPromise = runSpawn(record, "test task", opts, ctx);
196
- await waitForSpawn(mockSpawn);
197
- const childEnv = getLastSpawnEnv();
87
+ const { resultPromise, childEnv } = await spawnAndCaptureEnv(record, "test task", opts, ctx);
198
88
 
199
89
  // 身份 env 无条件存在(决策 2)
200
90
  expect(childEnv.PI_SUBAGENT_ROOT_SESSION_ID).toBe("root-main");
@@ -204,46 +94,36 @@ describe("runSpawn 跨进程身份 env 注入(递归可见性场景 1b)", ()
204
94
  // fork depth env 同时存在(fork=true + parentForkDepth=1 → 2)
205
95
  expect(childEnv.PI_SUBAGENT_FORK_DEPTH).toBe("2");
206
96
 
207
- const child = getLastSpawnedChild();
208
- child.emit("close", 0);
209
- await resultPromise;
97
+ await closeLastChildAndAwait(resultPromise);
210
98
  });
211
99
 
212
100
  it("深层 record(depth=3):DEPTH env = String(record.depth),正确贯穿嵌套层级", async () => {
213
- const record = makeRecord({ id: "sa-deep", depth: 3 });
214
- const ctx = makeCtx({ sessionRootId: "root-topmost" });
101
+ const record = makeVisibilityRecord({ id: "sa-deep", depth: 3 });
102
+ const ctx = makeVisibilityCtx({ sessionRootId: "root-topmost" });
215
103
 
216
- const resultPromise = runSpawn(record, "test task", makeRunOpts(), ctx);
217
- await waitForSpawn(mockSpawn);
218
- const childEnv = getLastSpawnEnv();
104
+ const { resultPromise, childEnv } = await spawnAndCaptureEnv(record, "test task", makeRunOpts(), ctx);
219
105
 
220
106
  expect(childEnv.PI_SUBAGENT_DEPTH).toBe("3");
221
107
  expect(childEnv.PI_SUBAGENT_SELF_RECORD_ID).toBe("sa-deep");
222
108
  expect(childEnv.PI_SUBAGENT_ROOT_SESSION_ID).toBe("root-topmost");
223
109
 
224
- const child = getLastSpawnedChild();
225
- child.emit("close", 0);
226
- await resultPromise;
110
+ await closeLastChildAndAwait(resultPromise);
227
111
  });
228
112
 
229
113
  it("ROOT_SESSION_ID 恒等于 ctx.sessionRootId(贯穿真 ROOT,非 record.rootSessionId)", async () => {
230
114
  // record.rootSessionId 是 createRecord 时写入的值(可能来自旧逻辑),但 env 注入用的是
231
115
  // ctx.sessionRootId(经 buildSessionRunnerContext 从 this.sessionRootId 透传,贯穿真 ROOT)。
232
116
  // 这保证深层 subagent 的子进程仍归顶层 ROOT(设计决策 1/3)。
233
- const record = makeRecord({ id: "sa-ccc" }); // record.rootSessionId = fixture 默认值
234
- const ctx = makeCtx({ sessionRootId: "real-root-session" });
117
+ const record = makeVisibilityRecord({ id: "sa-ccc" }); // record.rootSessionId = fixture 默认值
118
+ const ctx = makeVisibilityCtx({ sessionRootId: "real-root-session" });
235
119
 
236
- const resultPromise = runSpawn(record, "test task", makeRunOpts(), ctx);
237
- await waitForSpawn(mockSpawn);
238
- const childEnv = getLastSpawnEnv();
120
+ const { resultPromise, childEnv } = await spawnAndCaptureEnv(record, "test task", makeRunOpts(), ctx);
239
121
 
240
122
  // env 用 ctx.sessionRootId,不是 record.rootSessionId
241
123
  expect(childEnv.PI_SUBAGENT_ROOT_SESSION_ID).toBe("real-root-session");
242
124
  expect(childEnv.PI_SUBAGENT_ROOT_SESSION_ID).not.toBe(record.rootSessionId);
243
125
 
244
- const child = getLastSpawnedChild();
245
- child.emit("close", 0);
246
- await resultPromise;
126
+ await closeLastChildAndAwait(resultPromise);
247
127
  });
248
128
 
249
129
  it("[MF-3 回归] worktree 模式(mainCwd=checkout ≠ rootCwd):sessionDir 用 ROOT cwd 编码,深层 record 落盘到 ROOT 可扫描段", async () => {
@@ -252,12 +132,10 @@ describe("runSpawn 跨进程身份 env 注入(递归可见性场景 1b)", ()
252
132
  const rootCwd = "/root/project";
253
133
  const checkoutPath = "/var/folders/worktree/pi-subagents/--root-project--/branch";
254
134
  const agentDir = "/fake/agent";
255
- const record = makeRecord({ id: "sa-deep", depth: 2 });
256
- const ctx = makeCtx({ cwd: checkoutPath, mainCwd: checkoutPath, rootCwd, agentDir });
135
+ const record = makeVisibilityRecord({ id: "sa-deep", depth: 2 });
136
+ const ctx = makeVisibilityCtx({ cwd: checkoutPath, mainCwd: checkoutPath, rootCwd, agentDir });
257
137
 
258
- const resultPromise = runSpawn(record, "test task", makeRunOpts(), ctx);
259
- await waitForSpawn(mockSpawn);
260
- const childEnv = getLastSpawnEnv();
138
+ const { resultPromise, childEnv } = await spawnAndCaptureEnv(record, "test task", makeRunOpts(), ctx);
261
139
  const spawnArgs = mockSpawn.mock.calls.at(-1)?.[1] as string[];
262
140
 
263
141
  // 第 4 个 env 贯穿 ROOT cwd
@@ -266,8 +144,6 @@ describe("runSpawn 跨进程身份 env 注入(递归可见性场景 1b)", ()
266
144
  expect(spawnArgs).toContain(getSubagentSessionDir(agentDir, rootCwd));
267
145
  expect(spawnArgs).not.toContain(getSubagentSessionDir(agentDir, checkoutPath));
268
146
 
269
- const child = getLastSpawnedChild();
270
- child.emit("close", 0);
271
- await resultPromise;
147
+ await closeLastChildAndAwait(resultPromise);
272
148
  });
273
149
  });
@@ -6,8 +6,8 @@
6
6
 
7
7
  import { describe, expect, it } from "vitest";
8
8
 
9
- import { buildSpawnArgs } from "../session-runner.ts";
10
- import { parseSpawnLine } from "../spawn-event-adapter.ts";
9
+ import { buildSpawnArgs } from "../engine/engines/pi/session-runner.ts";
10
+ import { parseSpawnLine } from "../engine/engines/pi/spawn-event-adapter.ts";
11
11
 
12
12
  describe("buildSpawnArgs - RPC mode", () => {
13
13
  const baseParams = {