@zhushanwen/subagent-core 0.6.0 → 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 (278) 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-C3fE3R9x.d.cts → engine-discovery-scan-ocpM8FmI.d.cts} +770 -668
  6. package/dist/{types-C3fE3R9x.d.ts → engine-discovery-scan-ocpM8FmI.d.ts} +770 -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 +14045 -16059
  20. package/dist/index.d.cts +1035 -1579
  21. package/dist/index.d.ts +1035 -1579
  22. package/dist/index.js +9838 -13800
  23. package/dist.bundle/index.cjs +28875 -30323
  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__/chat-engine-routing.test.ts +62 -28
  30. package/src/execution/__tests__/chat-round-first-round-watchdog.test.ts +255 -0
  31. package/src/execution/__tests__/collect-coordinator-service.test.ts +36 -47
  32. package/src/execution/__tests__/collect-mixed-dispatch.test.ts +20 -53
  33. package/src/execution/__tests__/delivery-methods.test.ts +179 -237
  34. package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -2
  35. package/src/execution/__tests__/execute-nesting.test.ts +20 -13
  36. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +20 -33
  37. package/src/execution/__tests__/gc-timer.test.ts +7 -22
  38. package/src/execution/__tests__/get-record-for-action-restart.test.ts +20 -10
  39. package/src/execution/__tests__/helpers/fake-engine-port.ts +187 -0
  40. package/src/execution/__tests__/helpers/spawn-mock.ts +36 -9
  41. package/src/execution/__tests__/helpers/subagent-service-mocks.ts +1 -1
  42. package/src/execution/__tests__/idle-gc.test.ts +200 -0
  43. package/src/execution/__tests__/lifecycle-predicates.test.ts +26 -21
  44. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +5 -2
  45. package/src/execution/__tests__/reconcile-sweep.test.ts +200 -0
  46. package/src/execution/__tests__/record-store.test.ts +60 -6
  47. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +20 -13
  48. package/src/execution/__tests__/round-supervisor.test.ts +293 -0
  49. package/src/execution/__tests__/session-pending.test.ts +119 -17
  50. package/src/execution/__tests__/stream-sink-retirement.test.ts +10 -10
  51. package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +1 -11
  52. package/src/execution/__tests__/subagent-service-notify-gate.test.ts +33 -30
  53. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +2 -9
  54. package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +59 -129
  55. package/src/execution/__tests__/subagent-service.test.ts +2 -2
  56. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +109 -7
  57. package/src/execution/__tests__/subprocess-agent-runner.test.ts +108 -36
  58. package/src/execution/__tests__/sync-collect-recovery.test.ts +21 -36
  59. package/src/execution/__tests__/workflow-state-root.test.ts +232 -0
  60. package/src/execution/agent-registry.ts +6 -2
  61. package/src/execution/dialog-queue.ts +6 -73
  62. package/src/execution/engine/__tests__/common/capability-gate.test.ts +115 -15
  63. package/src/execution/engine/__tests__/common/errors.test.ts +11 -18
  64. package/src/execution/engine/__tests__/common/kill-chain.test.ts +7 -0
  65. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +9 -3
  66. package/src/execution/engine/__tests__/common/session-view-service.test.ts +90 -3
  67. package/src/execution/engine/__tests__/conformance/H9-test-disposition.md +116 -0
  68. package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/fake-engine-protocol.mjs +377 -0
  69. package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/recorded.fixture.json +331 -0
  70. package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/smoke-run.fixture.json +213 -0
  71. package/src/execution/engine/__tests__/conformance/chat-round-protocol.test.ts +230 -0
  72. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +69 -42
  73. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +4 -81
  74. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +67 -44
  75. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +81 -54
  76. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +133 -70
  77. package/src/execution/engine/__tests__/conformance/engine-crash.test.ts +143 -0
  78. package/src/execution/engine/__tests__/conformance/fake-engine-capabilities.ts +19 -0
  79. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +7 -2
  80. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +6 -5
  81. package/src/execution/engine/__tests__/conformance/protocol-blackbox.test.ts +398 -0
  82. package/src/execution/engine/__tests__/conformance/registry-fork-filter.test.ts +221 -0
  83. package/src/execution/engine/__tests__/conformance/round-liveness-supervisor.test.ts +302 -0
  84. package/src/execution/engine/__tests__/conformance/static-spawn-guard.test.ts +58 -0
  85. package/src/execution/engine/__tests__/engine-discovery-scan.test.ts +558 -0
  86. package/src/execution/engine/__tests__/host-task-spec.test.ts +45 -0
  87. package/src/execution/engine/__tests__/model-ref-split.test.ts +74 -0
  88. package/src/execution/engine/__tests__/registry.test.ts +206 -1
  89. package/src/execution/engine/__tests__/routing.test.ts +97 -0
  90. package/src/execution/engine/__tests__/run-failure-worktree-cleanup.test.ts +97 -0
  91. package/src/execution/engine/client/__tests__/__fixtures__/fake-engine.mjs +294 -0
  92. package/src/execution/engine/client/__tests__/engine-client.test.ts +516 -0
  93. package/src/execution/engine/client/__tests__/mirror.test.ts +67 -0
  94. package/src/execution/engine/client/__tests__/pid-file.test.ts +257 -0
  95. package/src/execution/engine/client/__tests__/protocol-closure.test.ts +95 -0
  96. package/src/execution/engine/client/__tests__/remote-engine.test.ts +457 -0
  97. package/src/execution/engine/client/client-options.ts +103 -0
  98. package/src/execution/engine/client/engine-client.ts +687 -0
  99. package/src/execution/engine/client/mirror.ts +167 -0
  100. package/src/execution/engine/client/pid-file.ts +392 -0
  101. package/src/execution/engine/client/reaper.ts +95 -0
  102. package/src/execution/engine/client/remote-engine.ts +441 -0
  103. package/src/execution/engine/client/reverse-router.ts +255 -0
  104. package/src/execution/engine/common/capability-gate.ts +109 -22
  105. package/src/execution/engine/common/errors.ts +9 -25
  106. package/src/execution/engine/common/event-journal.ts +4 -50
  107. package/src/execution/engine/common/journal-replay.ts +3 -1
  108. package/src/execution/engine/common/kill-chain.ts +18 -251
  109. package/src/execution/engine/common/nesting-guard.ts +18 -114
  110. package/src/execution/engine/common/pool-manager.ts +4 -0
  111. package/src/execution/engine/common/session-view-service.ts +56 -84
  112. package/src/execution/engine/config.ts +151 -0
  113. package/src/execution/engine/d8-compat.ts +346 -0
  114. package/src/execution/engine/engine-discovery-roots.ts +107 -0
  115. package/src/execution/engine/engine-discovery-scan.ts +269 -0
  116. package/src/execution/engine/engine-discovery.ts +30 -7
  117. package/src/execution/engine/engine-inspect-package.ts +282 -0
  118. package/src/execution/engine/engine-manifest.ts +244 -0
  119. package/src/execution/engine/host/__tests__/host-askuser-endpoint.test.ts +123 -0
  120. package/src/execution/engine/host/__tests__/host-bridge.test.ts +135 -0
  121. package/src/execution/engine/host/__tests__/spawned-children.test.ts +73 -0
  122. package/src/execution/engine/host/host-bridge.ts +150 -0
  123. package/src/execution/engine/host/host-ui-endpoint.ts +47 -0
  124. package/src/execution/engine/host/pi-host-binding.ts +91 -0
  125. package/src/execution/engine/host/spawned-children.ts +139 -0
  126. package/src/execution/engine/host-task-spec.ts +29 -2
  127. package/src/execution/engine/model-validation.ts +55 -2
  128. package/src/execution/engine/paths.ts +16 -41
  129. package/src/execution/engine/port.ts +48 -2
  130. package/src/execution/engine/registry.ts +153 -34
  131. package/src/execution/engine/routing.ts +225 -52
  132. package/src/execution/engine/types.ts +25 -200
  133. package/src/execution/finalize-record.ts +25 -0
  134. package/src/execution/idle-gc.ts +89 -14
  135. package/src/execution/lifecycle-manager.ts +10 -7
  136. package/src/execution/lifecycle-predicates.ts +10 -8
  137. package/src/execution/record-store.ts +29 -2
  138. package/src/execution/relay-env.ts +19 -36
  139. package/src/execution/round-supervisor/domain.ts +89 -0
  140. package/src/execution/round-supervisor/index.ts +33 -0
  141. package/src/execution/round-supervisor/notify-accounting.ts +87 -0
  142. package/src/execution/round-supervisor/reconcile-sweep.ts +235 -0
  143. package/src/execution/round-supervisor/service-binding.test.ts +661 -0
  144. package/src/execution/round-supervisor/service-binding.ts +273 -0
  145. package/src/execution/round-supervisor/supervisor.ts +426 -0
  146. package/src/execution/session-pending.ts +68 -74
  147. package/src/execution/settled-watchdog.ts +39 -0
  148. package/src/execution/subagent-service.ts +746 -400
  149. package/src/execution/subprocess-agent-runner.ts +16 -8
  150. package/src/execution/types.ts +41 -117
  151. package/src/execution/ui-channels.ts +13 -214
  152. package/src/execution/ui-request-handler-factory.ts +7 -4
  153. package/src/execution/ui-request-observability.ts +2 -2
  154. package/src/execution/workflow-state-root.ts +67 -0
  155. package/src/execution/worktree-git-ops.ts +5 -0
  156. package/src/execution/worktree-manager.ts +11 -1
  157. package/src/index.ts +55 -26
  158. package/src/orchestration/__tests__/execute-agent-call.test.ts +1 -1
  159. package/src/orchestration/execute-agent-call.ts +1 -1
  160. package/src/orchestration/file-run-store.ts +144 -59
  161. package/src/orchestration/models/types.ts +43 -42
  162. package/src/shared/zcode-model-ref.ts +31 -0
  163. package/dist/chunk-43ONBFZX.js +0 -240
  164. package/dist/chunk-A4IVZWVX.js +0 -31
  165. package/dist/chunk-APZY4IME.js +0 -27
  166. package/dist/chunk-V3VHZ2VX.js +0 -59
  167. package/dist/execution/engine/engines/zcode/constants.cjs +0 -107
  168. package/dist/execution/engine/engines/zcode/constants.d.cts +0 -135
  169. package/dist/execution/engine/engines/zcode/constants.d.ts +0 -135
  170. package/dist/execution/engine/engines/zcode/constants.js +0 -54
  171. package/dist/execution/engine/engines/zcode/reader.cjs +0 -276
  172. package/dist/execution/engine/engines/zcode/reader.d.cts +0 -21
  173. package/dist/execution/engine/engines/zcode/reader.d.ts +0 -21
  174. package/dist/execution/engine/engines/zcode/reader.js +0 -9
  175. package/src/__tests__/append-system-prompt-assembly.test.ts +0 -243
  176. package/src/__tests__/fr4-get-state-handshake.test.ts +0 -125
  177. package/src/__tests__/session-runner.test.ts +0 -69
  178. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
  179. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -191
  180. package/src/execution/__tests__/descendant-sweep-guards.test.ts +0 -220
  181. package/src/execution/__tests__/descendant-sweep.test.ts +0 -269
  182. package/src/execution/__tests__/engine-model-validation.test.ts +0 -741
  183. package/src/execution/__tests__/epipe-fallback.test.ts +0 -248
  184. package/src/execution/__tests__/execution-runtime-face.test.ts +0 -272
  185. package/src/execution/__tests__/get-state-handshake.test.ts +0 -127
  186. package/src/execution/__tests__/helpers/session-runner-mocks.ts +0 -113
  187. package/src/execution/__tests__/keep-alive-no-progress.test.ts +0 -280
  188. package/src/execution/__tests__/kill-all-escalation.test.ts +0 -196
  189. package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +0 -113
  190. package/src/execution/__tests__/output-collector.test.ts +0 -469
  191. package/src/execution/__tests__/pi-invocation.test.ts +0 -166
  192. package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -149
  193. package/src/execution/__tests__/rpc-mode.test.ts +0 -89
  194. package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +0 -387
  195. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -277
  196. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -254
  197. package/src/execution/__tests__/run-spawn-edges.test.ts +0 -1079
  198. package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
  199. package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
  200. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
  201. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +0 -207
  202. package/src/execution/__tests__/service-kill-escalation.test.ts +0 -91
  203. package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +0 -110
  204. package/src/execution/__tests__/session-runner-close-prune.test.ts +0 -181
  205. package/src/execution/__tests__/session-runner-dispatch.test.ts +0 -489
  206. package/src/execution/__tests__/session-runner-epipe.test.ts +0 -179
  207. package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +0 -227
  208. package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +0 -290
  209. package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -352
  210. package/src/execution/__tests__/settled-watchdog.test.ts +0 -524
  211. package/src/execution/__tests__/spawn-args.test.ts +0 -446
  212. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -192
  213. package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
  214. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -208
  215. package/src/execution/__tests__/spawned-children.test.ts +0 -236
  216. package/src/execution/__tests__/start-sync-model-guard.test.ts +0 -150
  217. package/src/execution/__tests__/stdin-writer.test.ts +0 -464
  218. package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -693
  219. package/src/execution/__tests__/temp-prompt.test.ts +0 -53
  220. package/src/execution/__tests__/timeout-integration.test.ts +0 -616
  221. package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
  222. package/src/execution/__tests__/turn-limiter.test.ts +0 -65
  223. package/src/execution/__tests__/ui-request-handler.test.ts +0 -205
  224. package/src/execution/__tests__/ui-request-queue.test.ts +0 -298
  225. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -230
  226. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
  227. package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +0 -149
  228. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
  229. package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +0 -128
  230. package/src/execution/engine/__tests__/paths.test.ts +0 -39
  231. package/src/execution/engine/common/schema-emulation.ts +0 -189
  232. package/src/execution/engine/common/session-view-projection.ts +0 -51
  233. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -615
  234. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
  235. package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +0 -257
  236. package/src/execution/engine/engines/pi/argv-mirror.ts +0 -135
  237. package/src/execution/engine/engines/pi/get-state-handshake.ts +0 -179
  238. package/src/execution/engine/engines/pi/output-collector.ts +0 -317
  239. package/src/execution/engine/engines/pi/pi-engine.ts +0 -811
  240. package/src/execution/engine/engines/pi/pi-invocation.ts +0 -120
  241. package/src/execution/engine/engines/pi/reader.ts +0 -59
  242. package/src/execution/engine/engines/pi/registration.ts +0 -37
  243. package/src/execution/engine/engines/pi/session-runner.ts +0 -2840
  244. package/src/execution/engine/engines/pi/spawn-event-adapter.ts +0 -404
  245. package/src/execution/engine/engines/pi/stdin-writer.ts +0 -199
  246. package/src/execution/engine/engines/pi/temp-prompt.ts +0 -62
  247. package/src/execution/engine/engines/pi/turn-limiter.ts +0 -102
  248. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +0 -301
  249. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json +0 -36
  250. package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +0 -321
  251. package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +0 -473
  252. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -43
  253. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -124
  254. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
  255. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -71
  256. package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +0 -247
  257. package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +0 -451
  258. package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +0 -792
  259. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +0 -782
  260. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +0 -168
  261. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +0 -210
  262. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +0 -353
  263. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +0 -282
  264. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +0 -372
  265. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -145
  266. package/src/execution/engine/engines/zcode/appserver-launcher.ts +0 -167
  267. package/src/execution/engine/engines/zcode/connection.ts +0 -598
  268. package/src/execution/engine/engines/zcode/constants.ts +0 -176
  269. package/src/execution/engine/engines/zcode/golden-sample.ts +0 -47
  270. package/src/execution/engine/engines/zcode/parser.ts +0 -102
  271. package/src/execution/engine/engines/zcode/preparer.ts +0 -235
  272. package/src/execution/engine/engines/zcode/reader.ts +0 -381
  273. package/src/execution/engine/engines/zcode/registration.ts +0 -37
  274. package/src/execution/engine/engines/zcode/session-channel.ts +0 -968
  275. package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -1431
  276. package/src/execution/round-settlement.ts +0 -93
  277. package/src/execution/ui-request-queue.ts +0 -215
  278. package/src/shared/schema-env.ts +0 -44
@@ -1,352 +0,0 @@
1
- // src/__tests__/session-runner-schema-env.test.ts
2
- //
3
- // Wave 2 (issue #3): schemaEnv bridge 测试。
4
- //
5
- // 覆盖 test-matrix 用例:
6
- // - T3.9 (boundary): schemaEnv 透传——传入时 childEnv 含 PI_WORKFLOW_SCHEMA
7
- // - T3.11 (state): schemaEnv 不传 → childEnv 无 PI_WORKFLOW_SCHEMA(BC-6 tool 层不变)
8
- // - T3.16 (NFR-compatibility): schemaEnv 不传时 BC-6 childEnv 等价——不传时与合并前
9
- // 行为一致,不注入 PI_WORKFLOW_SCHEMA → structured-output tool 不注册
10
- //
11
- // 测试策略:
12
- // - applySchemaEnvToChildEnv 纯函数单测(不依赖 runSpawn/spawn mock)
13
- // - runSpawn 集成测试:通过 mock spawn 拦截 childEnv,验证 schemaEnv 实际注入
14
- //
15
- // D-A6: schemaEnv 经 RunOptions 透传到 runSpawn childEnv。
16
- // BC-6: tool 层 execute 不传 schemaEnv → childEnv 不设 PI_WORKFLOW_SCHEMA → 行为不变。
17
-
18
- import type { PassThrough } from "node:stream";
19
-
20
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
21
-
22
- // ── mock modules (与 run-spawn-integration.test.ts 同模式) ──
23
-
24
- vi.mock("node:child_process", async () => {
25
- const { EventEmitter } = await import("node:events");
26
- const { PassThrough } = await import("node:stream");
27
-
28
- class FakeChild extends EventEmitter {
29
- pid = 12345;
30
- stdout = new PassThrough();
31
- stdin = new PassThrough(); // runSpawn 注册 stdin EPIPE handler(session-runner),FakeChild 必须提供
32
- stderr = new PassThrough();
33
- killed = false;
34
- killSignal: string | undefined;
35
- kill(sig?: string): boolean {
36
- this.killed = true;
37
- this.killSignal = sig;
38
- return true;
39
- }
40
- }
41
-
42
- return {
43
- spawn: vi.fn(() => new FakeChild()),
44
- // buildEnvBlock 用 execFile 异步取 git branch:默认 err-first 兜底(catch → branch="")
45
- execFile: vi.fn(
46
- (
47
- _cmd: string,
48
- _args: readonly string[],
49
- _opts: unknown,
50
- cb: (err: Error | null, stdout?: string, stderr?: string) => void,
51
- ) => cb(new Error("execFile not configured in this test")),
52
- ),
53
- };
54
- });
55
-
56
- vi.mock("node:fs", async () => {
57
- const actual = await import("node:fs");
58
- return {
59
- default: {
60
- ...actual,
61
- mkdirSync: vi.fn(),
62
- existsSync: vi.fn(() => false),
63
- appendFileSync: vi.fn(),
64
- writeFileSync: vi.fn(),
65
- readdirSync: vi.fn(() => []),
66
- },
67
- mkdirSync: vi.fn(),
68
- existsSync: vi.fn(() => false),
69
- appendFileSync: vi.fn(),
70
- writeFileSync: vi.fn(),
71
- readdirSync: vi.fn(() => []),
72
- promises: actual.promises,
73
- };
74
- });
75
-
76
- vi.mock("../alive-store.ts", () => ({
77
- writeAliveMarker: vi.fn(),
78
- }));
79
-
80
- vi.mock("../engine/engines/pi/temp-prompt.ts", () => ({
81
- writePromptToTempFile: vi.fn(async (agent: string) => {
82
- const safeName = agent.replace(/[^\w.-]+/g, "_");
83
- return { dir: `/tmp/fake-${safeName}`, filePath: `/tmp/fake-${safeName}/prompt-${safeName}.md` };
84
- }),
85
- cleanupTempPrompt: vi.fn(async () => {}),
86
- }));
87
-
88
- import { spawn } from "node:child_process";
89
- import * as fs from "node:fs";
90
-
91
- import { waitForSpawn } from "./helpers/spawn-mock.ts";
92
- import { createRecord } from "../execution-record.ts";
93
- import {
94
- applySchemaEnvToChildEnv,
95
- type RunOptions,
96
- runSpawn,
97
- SCHEMA_ENV_MAX_BYTES,
98
- type SessionRunnerContext,
99
- } from "../engine/engines/pi/session-runner.ts";
100
- import { schemaEnvByteLength } from "../../shared/schema-env.ts";
101
-
102
- const mockSpawn = vi.mocked(spawn);
103
- const mockExistsSync = vi.mocked(fs.existsSync);
104
-
105
- interface FakeChild {
106
- pid: number;
107
- stdout: PassThrough;
108
- stderr: PassThrough;
109
- killed: boolean;
110
- killSignal: string | undefined;
111
- kill(sig?: string): boolean;
112
- emit(event: string, ...args: unknown[]): boolean;
113
- }
114
-
115
- function getLastSpawnedChild(): FakeChild {
116
- const result = mockSpawn.mock.results.at(-1);
117
- if (!result) throw new Error("spawn was not called yet");
118
- return result.value as FakeChild;
119
- }
120
-
121
- function getLastSpawnEnv(): Record<string, string | undefined> {
122
- return mockSpawn.mock.calls.at(-1)?.[2]?.env as Record<string, string | undefined> ?? {};
123
- }
124
-
125
- // ── 公共 fixture ──
126
-
127
- function makeRecord() {
128
- return createRecord("test-1", {
129
- agent: "general-purpose",
130
- model: "test/model",
131
- mode: "background",
132
- task: "test task",
133
- slug: "test",
134
- startedAt: Date.now(),
135
- rootSessionId: "s1",
136
- parentRecordId: undefined,
137
- depth: 0,
138
- });
139
- }
140
-
141
- function makeRunOpts(overrides: Partial<RunOptions> = {}): RunOptions {
142
- return {
143
- resolved: { model: { provider: "test", id: "model", name: "Model", reasoning: false }, thinkingLevel: undefined },
144
- agentConfig: undefined,
145
- appendSystemPrompt: undefined,
146
- skillPath: undefined,
147
- schema: undefined,
148
- maxTurns: undefined,
149
- graceTurns: undefined,
150
- signal: undefined,
151
- onEvent: undefined,
152
- ...overrides,
153
- };
154
- }
155
-
156
- function makeCtx(overrides: Partial<SessionRunnerContext> = {}): SessionRunnerContext {
157
- return {
158
- cwd: "/fake/cwd",
159
- agentDir: "/fake/agent",
160
- skillDirs: [],
161
- mainCwd: "/fake/cwd",
162
- sessionRootId: "root-session-test",
163
- rootCwd: "/fake/cwd",
164
- ...overrides,
165
- };
166
- }
167
-
168
- // ── applySchemaEnvToChildEnv 纯函数单测 ──
169
-
170
- describe("applySchemaEnvToChildEnv (T3.9/T3.11/T3.16)", () => {
171
- // T3.11: schemaEnv 不传 → childEnv 无 PI_WORKFLOW_SCHEMA
172
- it("T3.11: schemaEnv 不传时 childEnv 不含 PI_WORKFLOW_SCHEMA(BC-6)", () => {
173
- const childEnv: Record<string, string | undefined> = { PATH: "/usr/bin" };
174
- applySchemaEnvToChildEnv(childEnv, undefined);
175
- expect(childEnv).not.toHaveProperty("PI_WORKFLOW_SCHEMA");
176
- expect(childEnv.PATH).toBe("/usr/bin"); // 其他 key 不受影响
177
- });
178
-
179
- // T3.16: schemaEnv 不传时 BC-6 childEnv 等价——合并前后行为一致
180
- it("T3.16: schemaEnv 不传时 childEnv 等价于合并前(BC-6,不注入 PI_WORKFLOW_SCHEMA)", () => {
181
- const childEnv: Record<string, string | undefined> = {};
182
- applySchemaEnvToChildEnv(childEnv, undefined);
183
- // 不传 schemaEnv 时,childEnv 应与调用前完全一致(不含 PI_WORKFLOW_SCHEMA)
184
- expect(Object.keys(childEnv)).toHaveLength(0);
185
- expect(childEnv.PI_WORKFLOW_SCHEMA).toBeUndefined();
186
- });
187
-
188
- // T3.16 补充: schemaEnv 为空串也不注入(空串不是有效 schema)
189
- it("T3.16 补充: schemaEnv 为空串时不注入(false-ish 语义)", () => {
190
- const childEnv: Record<string, string | undefined> = {};
191
- applySchemaEnvToChildEnv(childEnv, "");
192
- expect(childEnv).not.toHaveProperty("PI_WORKFLOW_SCHEMA");
193
- });
194
-
195
- // T3.9: schemaEnv 传入 → childEnv 含 PI_WORKFLOW_SCHEMA
196
- it("T3.9: schemaEnv 传入时 childEnv 含 PI_WORKFLOW_SCHEMA", () => {
197
- const childEnv: Record<string, string | undefined> = {};
198
- const schemaJson = '{"type":"object","properties":{"x":{"type":"number"}}}';
199
- applySchemaEnvToChildEnv(childEnv, schemaJson);
200
- expect(childEnv.PI_WORKFLOW_SCHEMA).toBe(schemaJson);
201
- });
202
-
203
- // T3.9 补充: schemaEnv 值为复杂 JSON 字符串时正确透传
204
- it("T3.9 补充: schemaEnv 值为复杂 JSON 字符串时完整透传", () => {
205
- const childEnv: Record<string, string | undefined> = {};
206
- const schemaJson = JSON.stringify({
207
- type: "object",
208
- properties: {
209
- name: { type: "string" },
210
- age: { type: "number", minimum: 0 },
211
- },
212
- required: ["name"],
213
- });
214
- applySchemaEnvToChildEnv(childEnv, schemaJson);
215
- expect(childEnv.PI_WORKFLOW_SCHEMA).toBe(schemaJson);
216
- // 验证可以 parse 回原始结构
217
- expect(() => JSON.parse(childEnv.PI_WORKFLOW_SCHEMA!)).not.toThrow();
218
- });
219
-
220
- // T3.9 补充: schemaEnv 与已有 key 不冲突
221
- it("T3.9 补充: schemaEnv 注入不覆盖 childEnv 已有 key", () => {
222
- const childEnv: Record<string, string | undefined> = {
223
- PATH: "/usr/bin",
224
- HOME: "/home/user",
225
- };
226
- applySchemaEnvToChildEnv(childEnv, '{"x":1}');
227
- expect(childEnv.PATH).toBe("/usr/bin");
228
- expect(childEnv.HOME).toBe("/home/user");
229
- expect(childEnv.PI_WORKFLOW_SCHEMA).toBe('{"x":1}');
230
- });
231
-
232
- // [SO-DATA-4] 边界内通过:255KB(< 256KiB 上限)正常注入,行为不变
233
- it("[SO-DATA-4] 255KB schema 正常注入(上限内不误拒)", () => {
234
- const childEnv: Record<string, string | undefined> = {};
235
- // ASCII 串 byteLength === length,构造 255KB 纯 JSON body(外层再包一层合法 JSON)
236
- const padding = "x".repeat(255 * 1024);
237
- const schemaJson = JSON.stringify({ type: "object", properties: { pad: { const: padding } } });
238
- expect(schemaEnvByteLength(schemaJson)).toBeLessThanOrEqual(SCHEMA_ENV_MAX_BYTES);
239
- applySchemaEnvToChildEnv(childEnv, schemaJson);
240
- expect(childEnv.PI_WORKFLOW_SCHEMA).toBe(schemaJson);
241
- });
242
-
243
- // [SO-DATA-4] 超限 fail-fast:257KB 拒绝,错误消息含实际大小 + 精简/拆分指引 + E2BIG 归因
244
- it("[SO-DATA-4] 257KB schema fail-fast 拒绝(错误含实际大小与恢复指引)", () => {
245
- const childEnv: Record<string, string | undefined> = {};
246
- const padding = "x".repeat(257 * 1024);
247
- const schemaJson = JSON.stringify({ type: "object", properties: { pad: { const: padding } } });
248
- expect(schemaEnvByteLength(schemaJson)).toBeGreaterThan(SCHEMA_ENV_MAX_BYTES);
249
- expect(() => applySchemaEnvToChildEnv(childEnv, schemaJson)).toThrow(
250
- expect.objectContaining({
251
- message: expect.stringContaining("bytes exceeds"),
252
- }),
253
- );
254
- // 错误消息含实际大小、上限、精简/拆分指引与 E2BIG 归因(可操作性验收)
255
- try {
256
- applySchemaEnvToChildEnv(childEnv, schemaJson);
257
- throw new Error("expected applySchemaEnvToChildEnv to throw");
258
- } catch (err) {
259
- const msg = err instanceof Error ? err.message : String(err);
260
- expect(msg).toContain(String(schemaEnvByteLength(schemaJson))); // 实际大小
261
- expect(msg).toContain(String(SCHEMA_ENV_MAX_BYTES)); // 上限值
262
- expect(msg).toContain("simplify the schema"); // 精简指引
263
- expect(msg).toContain("E2BIG"); // ARG_MAX/E2BIG 约束说明
264
- }
265
- // fail-fast:不写入半截值
266
- expect(childEnv.PI_WORKFLOW_SCHEMA).toBeUndefined();
267
- });
268
- });
269
-
270
- // ── runSpawn 集成测试:schemaEnv 经 RunOptions → childEnv ──
271
-
272
- describe("runSpawn schemaEnv childEnv 注入 (T3.9/T3.11)", () => {
273
- beforeEach(() => {
274
- vi.clearAllMocks();
275
- mockExistsSync.mockReturnValue(false);
276
- });
277
-
278
- afterEach(() => {
279
- vi.restoreAllMocks();
280
- });
281
-
282
- // T3.11: schemaEnv 不传 → childEnv 的 PI_WORKFLOW_SCHEMA 保持 process.env 原值
283
- // BC-6: applySchemaEnvToChildEnv 不注入新值,但 process.env 可能已有此 key(子进程继承父环境)。
284
- // 验证点: 不传 schemaEnv 时我们的代码不修改 PI_WORKFLOW_SCHEMA。
285
- it("T3.11 (integration): RunOptions 无 schemaEnv → childEnv 继承 process.env 原值(BC-6)", async () => {
286
- const record = makeRecord();
287
- const opts = makeRunOpts({ schemaEnv: undefined });
288
- const ctx = makeCtx();
289
-
290
- const resultPromise = runSpawn(record, "test task", opts, ctx);
291
- await waitForSpawn(mockSpawn);
292
- const childEnv = getLastSpawnEnv();
293
- // BC-6: schemaEnv 未传入 → PI_WORKFLOW_SCHEMA 应为 process.env 原值(我们的代码不注入)
294
- expect(childEnv.PI_WORKFLOW_SCHEMA).toBe(process.env.PI_WORKFLOW_SCHEMA);
295
-
296
- const child = getLastSpawnedChild();
297
- child.emit("close", 0);
298
- await resultPromise;
299
- });
300
-
301
- // T3.9: schemaEnv 传入 → childEnv 含 PI_WORKFLOW_SCHEMA
302
- it("T3.9 (integration): RunOptions 有 schemaEnv → childEnv 含 PI_WORKFLOW_SCHEMA", async () => {
303
- const record = makeRecord();
304
- const schemaJson = '{"type":"object","properties":{"result":{"type":"string"}}}';
305
- const opts = makeRunOpts({ schemaEnv: schemaJson });
306
- const ctx = makeCtx();
307
-
308
- const resultPromise = runSpawn(record, "test task", opts, ctx);
309
- await waitForSpawn(mockSpawn);
310
- const childEnv = getLastSpawnEnv();
311
- expect(childEnv.PI_WORKFLOW_SCHEMA).toBe(schemaJson);
312
-
313
- // 关闭子进程
314
- const child = getLastSpawnedChild();
315
- child.emit("close", 0);
316
- await resultPromise;
317
- });
318
-
319
- // T3.9 + fork: schemaEnv 与 fork env 共存时不冲突
320
- it("T3.9 + fork: schemaEnv 与 fork depth env 共存不冲突", async () => {
321
- const record = createRecord("test-fork-1", {
322
- agent: "general-purpose",
323
- model: "test/model",
324
- mode: "background",
325
- task: "test task",
326
- slug: "test",
327
- startedAt: Date.now(),
328
- rootSessionId: "s1",
329
- parentRecordId: undefined,
330
- depth: 1,
331
- });
332
- const schemaJson = '{"type":"object"}';
333
- const opts = makeRunOpts({
334
- schemaEnv: schemaJson,
335
- fork: true,
336
- parentForkDepth: 0,
337
- });
338
- const ctx = makeCtx();
339
-
340
- const resultPromise = runSpawn(record, "test task", opts, ctx);
341
- await waitForSpawn(mockSpawn);
342
- const childEnv = getLastSpawnEnv();
343
- // fork depth env 应存在
344
- expect(childEnv.PI_SUBAGENT_FORK_DEPTH).toBe("1");
345
- // schemaEnv 也应存在
346
- expect(childEnv.PI_WORKFLOW_SCHEMA).toBe(schemaJson);
347
-
348
- const child = getLastSpawnedChild();
349
- child.emit("close", 0);
350
- await resultPromise;
351
- });
352
- });