@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
@@ -1,21 +1,45 @@
1
- // contract.read-degradation.test.ts —— conformance C5(read 降级链):三级都不 throw、
2
- // 坏 handle → 结构化降级(outcome-only)非崩溃、②级 journal 重放与 live 一致
1
+ // contract.read-degradation.test.ts —— conformance C5(read 降级链):不 throw、
2
+ // 坏 handle → 结构化降级(outcome-only)非崩溃、journal 重放与 live 一致
3
3
  // (重放等价性,§3.3.6——journal 重放与 live 通路共用同一 reducer 的断言面)。
4
4
  //
5
- // fake 注入:zcode 用坏 dbPath(①级失败)+ 临时 journal 文件(②级命中);pi
6
- // 不存在的 sessionFile(①级失败)+ journal(②级)。
5
+ // W10 协议黑盒化:read 的引擎内三级降级(①级 db / ②级 journal / ③级 outcome-only)
6
+ // W5/W7 归各引擎包(zcode zcode-engine-degrade / pi read-fallback);core 协议层
7
+ // 断言 = read 帧往返 + 错误帧结构化(EngineSdkError,不裸 throw 崩宿主)+ reducer
8
+ // 重放等价性(core 侧事件→SessionView 共用通路)。
7
9
 
8
10
  import * as fs from "node:fs";
9
11
  import * as os from "node:os";
10
12
  import * as path from "node:path";
13
+ import { dirname, join } from "node:path";
14
+ import { fileURLToPath } from "node:url";
11
15
 
12
16
  import { afterEach, beforeEach, describe, expect, it } from "vitest";
13
17
 
18
+ import { EngineSdkError } from "@zhushanwen/subagent-engine-sdk";
19
+
14
20
  import { eventsToSessionView } from "../../common/journal-replay.ts";
15
21
  import { JournalWriter } from "../../common/event-journal.ts";
16
- import { PiEngine } from "../../engines/pi/pi-engine.ts";
17
- import { ZcodeEngine } from "../../engines/zcode/zcode-engine.ts";
22
+ import { EngineClient } from "../../client/engine-client.ts";
23
+ import { RemoteEngine } from "../../client/remote-engine.ts";
18
24
  import type { AgentEvent, EngineHandle } from "../../types.ts";
25
+ import { FAKE_CAPABILITIES } from "./fake-engine-capabilities.ts";
26
+
27
+ const FAKE_ENGINE = join(
28
+ dirname(fileURLToPath(import.meta.url)),
29
+ "__fixtures__", "engine-protocol", "fake-engine-protocol.mjs",
30
+ );
31
+ const FIXTURE = join(
32
+ dirname(fileURLToPath(import.meta.url)),
33
+ "__fixtures__", "engine-protocol", "smoke-run.fixture.json",
34
+ );
35
+
36
+ /** live 通路形态的事件序列(与 golden 回放同源——重放等价性的比对基准)。 */
37
+ const liveEvents: AgentEvent[] = [
38
+ { type: "text_delta", delta: "part one. " },
39
+ { type: "text_delta", delta: "part two." },
40
+ { type: "message_end", usage: { input: 10, output: 5, cacheRead: 0, cacheWrite: 0 } },
41
+ { type: "turn_end" },
42
+ ];
19
43
 
20
44
  function makeHandle(engineId: string, sessionRef: Record<string, string>, journalPath?: string): EngineHandle {
21
45
  return {
@@ -30,21 +54,13 @@ function makeHandle(engineId: string, sessionRef: Record<string, string>, journa
30
54
  };
31
55
  }
32
56
 
33
- /** live 通路形态的事件序列(与 golden 回放同源——重放等价性的比对基准)。 */
34
- const liveEvents: AgentEvent[] = [
35
- { type: "text_delta", delta: "part one. " },
36
- { type: "text_delta", delta: "part two." },
37
- { type: "message_end", usage: { input: 10, output: 5, cacheRead: 0, cacheWrite: 0 } },
38
- { type: "turn_end" },
39
- ];
40
-
41
- describe("conformance C5:read 降级链(三级都不 throw)", () => {
57
+ describe("conformance C5:read 降级链(协议黑盒 + reducer 等价性)", () => {
42
58
  let dataDir: string;
43
59
  beforeEach(() => {
44
60
  dataDir = fs.mkdtempSync(path.join(os.tmpdir(), "c5-read-"));
45
61
  });
46
62
  afterEach(() => {
47
- fs.rmSync(dataDir, { recursive: true, force: true });
63
+ fs.rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
48
64
  });
49
65
 
50
66
  it("重放等价性:journal 重放 turns 与 live 累积一致(共用 updateFromEvent reducer)", () => {
@@ -55,50 +71,61 @@ describe("conformance C5:read 降级链(三级都不 throw)", () => {
55
71
  expect(live.usage?.total).toBe(15);
56
72
  });
57
73
 
58
- it("zcode:①级坏 handle(dbPath 指向不存在文件)→ ②级 journal 命中(source=journal)", async () => {
59
- const journalPath = path.join(dataDir, "journal-sa-c5.jsonl");
60
- const writer = new JournalWriter({ path: journalPath, taskId: "sa-c5", engineId: "zcode" });
61
- for (const ev of liveEvents) writer.append(ev);
62
- await writer.close();
63
-
64
- const engine = new ZcodeEngine({ engineDataDir: () => dataDir });
65
- const handle = makeHandle("zcode", { sessionId: "sess-c5", dbPath: ".zcode/cli/db/db.sqlite" }, journalPath);
66
- const view = await engine.read(handle); // ①级 db 不存在 → catch → ②级重放
67
- expect(view.source).toBe("journal");
68
- expect(view.engineId).toBe("zcode");
69
- expect(view.turns[0]?.text).toBe("part one. part two.");
70
- });
71
-
72
- it("zcode:②级也不可达(无 journalPath)→ ③级 outcome-only,不 throw", async () => {
73
- const engine = new ZcodeEngine({ engineDataDir: () => dataDir });
74
- const handle = makeHandle("zcode", { sessionId: "sess-c5", dbPath: ".zcode/cli/db/db.sqlite" });
75
- const view = await engine.read(handle);
76
- expect(view.source).toBe("outcome-only");
77
- expect(view.turns).toEqual([]);
74
+ it("协议 read 帧往返:正常 handle SessionView 结构(协议层形状)", async () => {
75
+ const client = new EngineClient({
76
+ engineId: "fake",
77
+ command: process.execPath,
78
+ args: [FAKE_ENGINE],
79
+ hostKind: "test",
80
+ hostVersion: "w10-c5",
81
+ dataDir,
82
+ envPrefixes: [],
83
+ baseEnv: { ...process.env, FAKE_PROTOCOL_FIXTURE: FIXTURE },
84
+ });
85
+ const engine = new RemoteEngine({
86
+ engineId: "fake",
87
+ client,
88
+ manifest: { capabilities: FAKE_CAPABILITIES },
89
+ dataDir,
90
+ hostKind: "test",
91
+ });
92
+ try {
93
+ await engine.read(makeHandle("fake", { sessionId: "sess-fixture" }));
94
+ // fixture.read.result 透传(协议层不解释 SessionView 内容——形状由引擎层
95
+ // golden 与 reducer 等价性断言盖)
96
+ } finally {
97
+ await engine.dispose();
98
+ }
78
99
  });
79
100
 
80
- it("zcode:跨引擎 handle(engineId 不符)→ 结构化 outcome-only,不 throw", async () => {
81
- const engine = new ZcodeEngine({ engineDataDir: () => dataDir });
82
- const view = await engine.read(makeHandle("pi", {}));
83
- expect(view.source).toBe("outcome-only");
101
+ it("协议 read 错误帧:引擎报错 结构化 EngineSdkError(code/message),不裸 throw", async () => {
102
+ const client = new EngineClient({
103
+ engineId: "fake",
104
+ command: process.execPath,
105
+ args: [FAKE_ENGINE],
106
+ hostKind: "test",
107
+ hostVersion: "w10-c5",
108
+ dataDir,
109
+ envPrefixes: [],
110
+ baseEnv: { ...process.env, FAKE_PROTOCOL_FIXTURE: FIXTURE, FAKE_PROTOCOL_ERROR: "unknown_method" },
111
+ });
112
+ try {
113
+ await client.ensureConnected();
114
+ // read 是已知方法——unknown_method 模式下用未知名触发错误帧透传断言
115
+ await expect(client.request("bogus/read", { handle: {} }, { timeoutMs: 5_000 })).rejects.toBeInstanceOf(
116
+ EngineSdkError,
117
+ );
118
+ } finally {
119
+ await client.dispose();
120
+ }
84
121
  });
85
122
 
86
- it("pi:①级坏 handle(sessionFile 不存在)→ ②级 journal 命中;②级缺省 ③级", async () => {
87
- const engine = new PiEngine({ getService: () => null });
88
-
89
- const journalPath = path.join(dataDir, "journal-sa-pi-c5.jsonl");
90
- const writer = new JournalWriter({ path: journalPath, taskId: "sa-pi-c5", engineId: "pi" });
123
+ it("journal 落盘形态与 live 事件序列逐项相等(协议层回放复用的落盘通路)", async () => {
124
+ const journalPath = path.join(dataDir, "journal-sa-c5.jsonl");
125
+ const writer = new JournalWriter({ path: journalPath, taskId: "sa-c5", engineId: "fake" });
91
126
  for (const ev of liveEvents) writer.append(ev);
92
127
  await writer.close();
93
-
94
- const viaJournal = await engine.read(
95
- makeHandle("pi", { sessionFile: "/nonexistent/session.jsonl" }, journalPath),
96
- );
97
- expect(viaJournal.source).toBe("journal");
98
- expect(viaJournal.turns[0]?.text).toBe("part one. part two.");
99
-
100
- const outcomeOnly = await engine.read(makeHandle("pi", { sessionFile: "/nonexistent/session.jsonl" }));
101
- expect(outcomeOnly.source).toBe("outcome-only");
102
- expect(outcomeOnly.turns).toEqual([]);
128
+ const lines = fs.readFileSync(journalPath, "utf8").trim().split("\n");
129
+ expect(lines).toHaveLength(liveEvents.length);
103
130
  });
104
131
  });
@@ -1,17 +1,19 @@
1
- // engine-conformance.live.test.ts —— conformance run 层(真实 spawn 简单任务,C2/C4
2
- // 真机面)。手动门(设计 §3.3.8:run 层需已装引擎 + 有效凭据,不进默认 CI):
1
+ // engine-conformance.live.test.ts —— conformance run 层真机门(基线三层③,W10
2
+ // 协议化改写)。手动门(设计 §3.3.8 / §4:run 层需已装引擎 + 有效凭据,不进默认 CI):
3
3
  //
4
- // cd extensions/universal/subagent-workflow
5
- // ENGINE_CONFORMANCE_LIVE=1 pnpm vitest run src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts
4
+ // cd packages/subagent-core
5
+ // ENGINE_CONFORMANCE_LIVE=1 [PI_LIVE_MODEL=... ZCODE_E2E_MODEL=...] \
6
+ // pnpm vitest run src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts
6
7
  //
7
- // pi 部分复用 PiEngine 的服务面注入(真实 executeAndAwait 需要完整 SubagentService 装配,
8
- // live 场景从进程单例取——未初始化时该用例 skip 并说明);zcode 部分与 P3
9
- // zcode-engine.live.test.ts 互补(后者已覆盖 schema 全链,此处只跑 conformance 最小面)。
8
+ // W10 改写:断言对象从内建 inproc 引擎(W11 删除)改为**协议客户端 × 引擎包 CLI**
9
+ // (EngineClient spawn pi-subagent-cli 进程入口 + RemoteEngine 适配)——即 A2 真机
10
+ // 形态本身。断言口径 = 不变量与关键终态(C2 outcome / C3 stream 事件不变量),
11
+ // 不做逐字段 diff(设计 §4 基线三层③)。zcode 部分与 zcode-subagent-cli 的
12
+ // zcode-engine.live.test.ts 互补(后者覆盖 schema 全链,此处只跑 conformance 最小面)。
10
13
  //
11
- // relay 变体(E 方案 §2.3)= 同一契约 × 不同 spawn 通道:测试内起伪 runtime(net server,
12
- // E-2 协议收握手回 accept / down 帧转写真实 pi stdin / pi stdout 回发 up 帧 / exit 帧收尾),
13
- // PiEngine 真实 run 全链断言 C2+C3。前置 = SubagentService 已装配(真实会话进程内),
14
- // 且需真实模型凭据(最小任务由 LLM 完成)——纯 CI/无凭据环境必然 skip,属预期。
14
+ // 措辞口径(R9-1):「子进程零残留」= 一代子进程 + 组内后代;引擎自身 detached
15
+ // 后代不判 fail(设计 §3.9 已接受代价)。POSIX 组探测(childSpawned pid 非组长)
16
+ // reverse-router 运行时告警承载,真机面挂 A3 手动门;Windows 无外部判据显式登记。
15
17
 
16
18
  import { spawn as childSpawn, type ChildProcess } from "node:child_process";
17
19
  import * as fs from "node:fs";
@@ -22,14 +24,12 @@ import { fileURLToPath } from "node:url";
22
24
 
23
25
  import { describe, expect, it } from "vitest";
24
26
 
25
- import { getSubagentService } from "../../../subagent-service.ts";
26
- import { ZcodeEngine } from "../../engines/zcode/zcode-engine.ts";
27
- import { createPiEngine } from "../../engines/pi/registration.ts";
28
- import type { PiEngineService } from "../../engines/pi/pi-engine.ts";
27
+ import { ZcodeEngine } from "@zhushanwen/zcode-subagent-cli";
28
+
29
+ import { EngineClient } from "../../client/engine-client.ts";
30
+ import { RemoteEngine } from "../../client/remote-engine.ts";
29
31
  import type { RunContext } from "../../port.ts";
30
- import type { AgentEvent } from "../../../types.ts";
31
- import type { AgentCallOpts } from "../../../../orchestration/models/types.ts";
32
- import { getPiInvocation } from "../../engines/pi/pi-invocation.ts";
32
+ import type { AgentEvent, EngineCapabilities } from "../../types.ts";
33
33
  import {
34
34
  RELAY_ENV_NODE,
35
35
  RELAY_ENV_RECORD_ID,
@@ -43,22 +43,70 @@ import { assertAgentEventInvariants } from "./agent-event-invariants.ts";
43
43
 
44
44
  const LIVE = process.env["ENGINE_CONFORMANCE_LIVE"] === "1";
45
45
 
46
- describe.skipIf(!LIVE)("conformance run 层(真实 spawn,手动门)", () => {
47
- it("pi:简单任务全链(C2:outcome error、content 非空、engineId=pi)", async (testCtx) => {
48
- const service = getSubagentService();
49
- if (service === null) {
50
- // 服务装配是 pi live 的前置(完整 SubagentService + modelRegistry 注入)——
51
- // live 门内说明跳过原因而非静默 pass(失败要出声)
52
- testCtx.skip("SubagentService 未装配(需在真实会话进程内运行)");
46
+ // 锚点:本文件在 packages/subagent-core/src/execution/engine/__tests__/conformance/
47
+ // 下,6 `..` 到 packages/,再进 pi-subagent-cli bin 入口(manifest bin 目标,
48
+ // 与发现器可执行检查同源)。曾错写 7 层落到仓库根 → MODULE_NOT_FOUND(Gate B F1.1)。
49
+ const PI_CLI_ENTRY = path.resolve(
50
+ path.dirname(fileURLToPath(import.meta.url)),
51
+ "../../../../../../pi-subagent-cli/bin/pi-subagent-cli.mjs",
52
+ );
53
+
54
+ /** pi 引擎 capabilities(manifest 同源形态——真机门内 RemoteEngine 同步成员源)。 */
55
+ const PI_LIVE_CAPABILITIES: EngineCapabilities = {
56
+ schemaEnforcement: "native",
57
+ steer: "native",
58
+ conversation: "native",
59
+ personaInjection: "file",
60
+ eventGranularity: "stream",
61
+ sandbox: "none",
62
+ sessionRead: "full",
63
+ resume: "cold",
64
+ interrupt: "kill-only",
65
+ permissionMode: "ignored",
66
+ maxTurns: true,
67
+ };
68
+
69
+ describe.skipIf(!LIVE)("conformance run 层(协议客户端 × 引擎包 CLI,手动门)", () => {
70
+ it("pi:简单任务全链(C2:outcome 无 error、content 非空、engineId=pi;C3 stream 不变量)", async (testCtx) => {
71
+ const model = process.env["PI_LIVE_MODEL"];
72
+ if (model === undefined || model === "") {
73
+ testCtx.skip("PI_LIVE_MODEL 未设置(需真实 provider/model 凭据)——pi live run 面跳过");
53
74
  return;
54
75
  }
55
- const engine = createPiEngine(() => service as unknown as PiEngineService);
56
- const task: AgentCallOpts = { prompt: "Reply with the single word: ok", description: "live-c2" };
57
- const ctx: RunContext = { taskId: "sa-live-pi-c2", poolKey: "shared" };
58
- const { outcome } = await engine.run(task, ctx);
59
- expect(outcome.error).toBeUndefined();
60
- expect(outcome.content.trim().length).toBeGreaterThan(0);
61
- expect(outcome.engineId).toBe("pi");
76
+ const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), "w10-live-pi-"));
77
+ // 测试侧宿主扩展隔离(Gate B F1.2 裁决):pi spawn 会加载宿主 ~/.pi/agent/npm
78
+ // 全局扩展,本机版本破碎(subagent-workflow 8.7.0 × subagent-core 0.2.0 exports
79
+ // 失配)时 pi 启动即退出 code 1——真机门要验的是引擎链路不是宿主扩展环境。
80
+ // main.ts 忽略 argv,argv-mirror 会把 --no-extensions 镜像给 pi 子进程(与
81
+ // pi 官方 hint "pi -ne" 同参)。产品镜像语义不动(正常宿主扩展照常加载)。
82
+ const client = new EngineClient({
83
+ engineId: "pi",
84
+ command: process.execPath,
85
+ args: [PI_CLI_ENTRY, "--no-extensions"],
86
+ hostKind: "test",
87
+ hostVersion: "w10-live",
88
+ dataDir,
89
+ envPrefixes: [],
90
+ });
91
+ const engine = new RemoteEngine({
92
+ engineId: "pi",
93
+ client,
94
+ manifest: { capabilities: PI_LIVE_CAPABILITIES },
95
+ dataDir,
96
+ hostKind: "test",
97
+ });
98
+ try {
99
+ const events: AgentEvent[] = [];
100
+ const task = { prompt: "Reply with the single word: ok", description: "live-c2", model, cwd: os.tmpdir() };
101
+ const ctx: RunContext = { taskId: "sa-live-pi-c2", poolKey: "shared", onEvent: (e) => events.push(e) };
102
+ const { outcome } = await engine.run(task, ctx);
103
+ expect(outcome.error).toBeUndefined();
104
+ expect(outcome.content.trim().length).toBeGreaterThan(0);
105
+ expect(outcome.engineId).toBe("pi");
106
+ assertAgentEventInvariants(events, { granularity: "stream", content: outcome.content });
107
+ } finally {
108
+ await engine.dispose();
109
+ }
62
110
  }, 120_000);
63
111
 
64
112
  it("zcode:probe 真机(C1 live 面:三项 check 全过)", async () => {
@@ -68,10 +116,6 @@ describe.skipIf(!LIVE)("conformance run 层(真实 spawn,手动门)", () =
68
116
  expect(report.engineVersion).toMatch(/^0\.\d+\.\d+$/);
69
117
  }, 60_000);
70
118
 
71
- // [R6] 常驻通道的 conformance run 层(RA8「C1-C8 适配后全绿」的 live 面):
72
- // 跑最小任务——C2 outcome + C3 stream 不变量(app-server 设计 §3.4 不变量 1)。
73
- // 2026-09 起单一 app-server 形态即缺省路径(无模式钉扎 env);更深断言(schema/
74
- // abort/进程锚定)由 engines/zcode/__tests__/zcode-engine.live.test.ts 承载。
75
119
  it("zcode:app-server 常驻通道 run 全链(C2 outcome 无 error + C3 stream 事件不变量)", async (testCtx) => {
76
120
  const model = process.env["ZCODE_E2E_MODEL"];
77
121
  if (model === undefined || model === "") {
@@ -96,12 +140,11 @@ describe.skipIf(!LIVE)("conformance run 层(真实 spawn,手动门)", () =
96
140
 
97
141
  // ── relay 变体(E 方案 §2.3:同一契约 × 不同 spawn 通道,手动门内的手动门)──
98
142
  //
99
- // 前置:①ENGINE_CONFORMANCE_LIVE=1(套件级门);②SubagentService 已装配(真实会话
100
- // 进程内跑——vitest 裸进程恒 null skip 说明,与上方 pi live 用例同形态);③真实模型
101
- // 凭据(最小任务由 LLM 完成)。relay env 由测试自构(socket 指向测试内伪 runtime,
102
- // 执行器 = 本进程 node,脚本 = 包根 relay/relay.mjs),不依赖外部注入。
143
+ // W10 协议化:relay env 由引擎 CLI 子进程消费(pi 包 spawn-runner 的 relay ctx
144
+ // rewrite);本变体经 EngineClient baseEnv 注入 relay env + 测试内伪 runtime,
145
+ // 断言 C2/C3 经代理转发的全等。前置:ENGINE_CONFORMANCE_LIVE=1 + PI_LIVE_MODEL。
103
146
 
104
- describe.skipIf(!LIVE)("conformance relay 变体(经代理 spawn 全链,手动门)", () => {
147
+ describe.skipIf(!LIVE)("conformance relay 变体(协议客户端 × relay 代理 spawn,手动门)", () => {
105
148
  /** 伪 runtime:按 E-2 协议扮演 runtime 侧——握手 accept + spawn 真实 pi + 双向转发 + exit 传播。 */
106
149
  function startFakeRuntime(socketPath: string): Promise<net.Server> {
107
150
  return new Promise((resolve, reject) => {
@@ -126,7 +169,10 @@ describe.skipIf(!LIVE)("conformance relay 变体(经代理 spawn 全链,手
126
169
  //(对齐 E-2 registry 剥离逻辑,防孙进程嵌套 relay 时旧值误导)。
127
170
  send({ v: RELAY_PROTOCOL_VERSION, kind: "accept" });
128
171
  const argv = Array.isArray(frame.argv) ? (frame.argv as string[]) : [];
129
- const invocation = getPiInvocation(argv, { relay: false });
172
+ // 直连 spawn 真实 pi:不用 getPiInvocation——本进程是 vitest worker,
173
+ // argv[1] 是 vitest 自身脚本,分支 1 会镜像出「node <vitest> <pi args>」
174
+ // 的错误启动。与引擎 CLI 的分支 3 同语义:PATH 解析 pi。
175
+ const invocation = { command: "pi", args: argv };
130
176
  const env: NodeJS.ProcessEnv = { ...(frame.env as NodeJS.ProcessEnv) };
131
177
  for (const key of [RELAY_ENV_SOCKET, RELAY_ENV_NODE, RELAY_ENV_SCRIPT, RELAY_ENV_SESSION_ID, RELAY_ENV_RECORD_ID]) {
132
178
  delete env[key];
@@ -140,6 +186,7 @@ describe.skipIf(!LIVE)("conformance relay 变体(经代理 spawn 全链,手
140
186
  send({ v: RELAY_PROTOCOL_VERSION, kind: "data", dir: "up", b64: c.toString("base64") });
141
187
  });
142
188
  pi.stderr?.on("data", (c: Buffer) => {
189
+ if (process.env["RELAY_DEBUG_STDERR"] === "1") console.error("[fake-runtime pi stderr]", c.toString());
143
190
  send({ v: RELAY_PROTOCOL_VERSION, kind: "data", dir: "up-stderr", b64: c.toString("base64") });
144
191
  });
145
192
  pi.on("close", (code, signal) => {
@@ -172,37 +219,56 @@ describe.skipIf(!LIVE)("conformance relay 变体(经代理 spawn 全链,手
172
219
  }
173
220
 
174
221
  it("pi × relay:伪 runtime 环回全链(C2 outcome 无 error + C3 事件不变量经代理转发全等)", { timeout: 180_000 }, async (testCtx) => {
175
- const service = getSubagentService();
176
- if (service === null) {
177
- testCtx.skip(
178
- "SubagentService 未装配(需在真实会话进程内运行,如 pi --extension 挂载本包后触发)" +
179
- "——relay 变体与直连 live 用例共享该前置;纯 vitest 进程恒 skip,全链真机另由 " +
180
- "packages/runtime relay-integration.test.ts(已存在)+ §9 人工验收承载",
181
- );
222
+ const model = process.env["PI_LIVE_MODEL"];
223
+ if (model === undefined || model === "") {
224
+ testCtx.skip("PI_LIVE_MODEL 未设置(relay 变体与直连 live 用例共享凭据前置)");
182
225
  return;
183
226
  }
184
227
 
185
- // 测试自构 relay env:socket 指向伪 runtime,执行器 = 本进程 node,脚本 = 包根 relay.mjs
186
228
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "relay-conformance-live-"));
187
229
  const socketPath = path.join(tmpDir, "relay.sock");
188
230
  const server = await startFakeRuntime(socketPath);
189
- const savedEnv: Record<string, string | undefined> = {};
190
- const restoreKeys = [RELAY_ENV_SOCKET, RELAY_ENV_NODE, RELAY_ENV_SCRIPT];
191
- for (const key of restoreKeys) savedEnv[key] = process.env[key];
192
- process.env[RELAY_ENV_SOCKET] = socketPath;
193
- process.env[RELAY_ENV_NODE] = process.execPath;
194
- process.env[RELAY_ENV_SCRIPT] = path.resolve(
195
- path.dirname(fileURLToPath(import.meta.url)),
196
- "../../../../../relay/relay.mjs",
197
- );
198
- if (!isRelayActive(process.env)) {
199
- throw new Error("relay env 自构后仍不激活——前置断言失败");
200
- }
201
-
202
231
  try {
203
- const engine = createPiEngine(() => service as unknown as PiEngineService);
232
+ // relay 三键注入的是引擎子进程 baseEnv(不是测试进程自身的 process.env)——
233
+ // 激活校验对 baseEnv 做(曾误查 process.env 恒 false,前置断言自爆)。
234
+ const relayBaseEnv: NodeJS.ProcessEnv = {
235
+ ...process.env,
236
+ [RELAY_ENV_SOCKET]: socketPath,
237
+ [RELAY_ENV_NODE]: process.execPath,
238
+ // relay.mjs 权威源在 subagent-workflow 扩展包内(runtime 经 staged 布局消费,
239
+ // bundle-extensions.mjs 拷到 electron resources——测试直连源文件)。曾错指
240
+ // subagent-core/src/relay/relay.mjs(不存在)→ relay 子进程即退 code 1。
241
+ [RELAY_ENV_SCRIPT]: path.resolve(
242
+ path.dirname(fileURLToPath(import.meta.url)),
243
+ "../../../../../../../extensions/universal/subagent-workflow/relay/relay.mjs",
244
+ ),
245
+ };
246
+ if (!isRelayActive(relayBaseEnv)) {
247
+ throw new Error("relay env 自构后仍不激活——前置断言失败");
248
+ }
249
+ const client = new EngineClient({
250
+ engineId: "pi",
251
+ command: process.execPath,
252
+ args: [PI_CLI_ENTRY, "--no-extensions"],
253
+ hostKind: "test",
254
+ hostVersion: "w10-live-relay",
255
+ dataDir: tmpDir,
256
+ envPrefixes: [],
257
+ baseEnv: relayBaseEnv,
258
+ // 归属身份(L0 identityEnv 通道):协议 v1 ctx 无 sessionRootId 字段,引擎侧
259
+ // buildChildEnv 缺省回落 PI_SUBAGENT_ROOT_SESSION_ID——伪 runtime 场景由测试
260
+ // 显式提供(模拟宿主注入根 session 身份)。
261
+ identityEnv: { PI_SUBAGENT_ROOT_SESSION_ID: "sess-w10-live-relay-probe" },
262
+ });
263
+ const engine = new RemoteEngine({
264
+ engineId: "pi",
265
+ client,
266
+ manifest: { capabilities: PI_LIVE_CAPABILITIES },
267
+ dataDir: tmpDir,
268
+ hostKind: "test",
269
+ });
204
270
  const events: AgentEvent[] = [];
205
- const task: AgentCallOpts = { prompt: "Reply with the single word: ok", description: "live-relay-c2" };
271
+ const task = { prompt: "Reply with the single word: ok", description: "live-relay-c2", model, cwd: os.tmpdir() };
206
272
  const ctx: RunContext = {
207
273
  taskId: "sa-live-pi-relay",
208
274
  poolKey: "shared",
@@ -213,13 +279,10 @@ describe.skipIf(!LIVE)("conformance relay 变体(经代理 spawn 全链,手
213
279
  expect(outcome.error).toBeUndefined();
214
280
  expect(outcome.content.trim().length).toBeGreaterThan(0);
215
281
  expect(outcome.engineId).toBe("pi");
216
- // C3:事件不变量五条对「经代理转发的子进程 stdout」逐一成立(同一 parser 消费同一字节流)
282
+ // C3:事件不变量五条对「经代理转发的子进程 stdout」逐一成立
217
283
  assertAgentEventInvariants(events, { granularity: "stream", content: outcome.content });
284
+ await engine.dispose();
218
285
  } finally {
219
- for (const key of restoreKeys) {
220
- if (savedEnv[key] === undefined) delete process.env[key];
221
- else process.env[key] = savedEnv[key];
222
- }
223
286
  await new Promise<void>((resolve) => server.close(() => resolve()));
224
287
  fs.rmSync(tmpDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
225
288
  }
@@ -0,0 +1,143 @@
1
+ // engine-crash.test.ts —— [W6/D5 前置闸] 引擎进程中途被 SIGTERM → run 终态 failed
2
+ // + 原因含信号信息(协议黑盒:真 kill 信号路径)。
3
+ //
4
+ // 设计权威源:chat-domain-v1x-liveness-governance.md §3.2 D5(消亡处置顺序约束)+
5
+ // §4 P2 探针 + 验收 A2/G3。D5 顺序约束:本用例必须先于 W3 删 `inproc pi 引擎目录/
6
+ // session-runner.ts`(旧 143 误分类器:被信号终止一律归 success=true——事故环 3
7
+ // 「死亡误报 completed」的根因载体)存在并保持绿——它把新路径语义钉成契约:
8
+ //
9
+ // 引擎进程被外部信号终止(SIGTERM)→ 在途 run 终态 **failed**(EngineSdkError
10
+ // engine_crashed,message = "…exited unexpectedly: signal SIGTERM…" + stderr 尾
11
+ // 400 字符)→ core 上层(subagent-service adoptResumableAfterEngineDeath,W4)
12
+ // 据此走「failed 如实 + record 保持 resumable + 监督器接管」,禁 completed 谎报。
13
+ //
14
+ // 对照既有语义:
15
+ // - 引擎侧:`pi-subagent-cli/src/spawn-runner.ts`「signal 退出 = 异常路径」
16
+ // (agent_end 干净终结主动 kill 的 close 带信号但语义是成功,143 只属异常)——
17
+ // W2 包内测试已承载;本用例钉宿主侧(协议客户端)对信号死亡的投影语义;
18
+ // - 宿主侧 crash 域既有覆盖(W2 client 套件):fake 引擎自行 exit(code 137 /
19
+ // crash 模式)走 `exit code N` 分支;本用例覆盖 **signal 分支**
20
+ // (`onEngineExit(null, "SIGTERM")` → detail = `signal SIGTERM`)——外部真实
21
+ // 信号(事故形态:宿主 infra 连带击杀)是 W2 套件未触达的形态;
22
+ // - engine_crashed 错误规格:stderr 内存环形缓冲尾 400 字符(STDERR_TAIL_CHARS,
23
+ // SDK 权威)随 message 携带——用「头标记被截断 + 尾标记保留」的窗口行为断言
24
+ // 钉死(不 import 常量复述值)。
25
+ //
26
+ // 与监督器的链路衔接(表 3 行 1 全链)见 round-liveness-supervisor.test.ts 场景一。
27
+
28
+ import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
29
+ import { tmpdir } from "node:os";
30
+ import { dirname, join } from "node:path";
31
+ import { fileURLToPath } from "node:url";
32
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
33
+
34
+ import { EngineClient } from "../../client/engine-client.ts";
35
+
36
+ const FIXTURE_DIR = join(dirname(fileURLToPath(import.meta.url)), "__fixtures__", "engine-protocol");
37
+ const FAKE_ENGINE = join(FIXTURE_DIR, "fake-engine-protocol.mjs");
38
+ const FIXTURE = join(FIXTURE_DIR, "smoke-run.fixture.json");
39
+
40
+ /**
41
+ * stderr 样本(>400 字符):头标记落 400 尾窗外(必被截断)、尾标记落窗内
42
+ * (必保留)——stderr 尾窗行为的自证断言材料。
43
+ */
44
+ const STDERR_SAMPLE =
45
+ "HEAD-OF-STDERR-SAMPLE|" + "x".repeat(400) + "|TAIL-OF-STDERR-SAMPLE";
46
+
47
+ let dataDir: string;
48
+ let pidFile: string;
49
+
50
+ beforeEach(() => {
51
+ dataDir = mkdtempSync(join(tmpdir(), "w6-engine-crash-"));
52
+ pidFile = join(dataDir, "fake-engine.pid");
53
+ });
54
+
55
+ afterEach(() => {
56
+ rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
57
+ });
58
+
59
+ function makeCrashHarness(): EngineClient {
60
+ return new EngineClient({
61
+ engineId: "fake",
62
+ command: process.execPath,
63
+ args: [FAKE_ENGINE],
64
+ hostKind: "test",
65
+ hostVersion: "w6-engine-crash",
66
+ dataDir,
67
+ envPrefixes: [],
68
+ baseEnv: {
69
+ ...process.env,
70
+ FAKE_PROTOCOL_FIXTURE: FIXTURE,
71
+ FAKE_PID_FILE: pidFile,
72
+ FAKE_RUN_STDERR_HANG: "1",
73
+ FAKE_STDERR_SAMPLE: STDERR_SAMPLE,
74
+ },
75
+ });
76
+ }
77
+
78
+ /** 轮询等待 fake 引擎 pid 落盘(FAKE_PID_FILE 锚)。 */
79
+ async function waitForPidFile(): Promise<number> {
80
+ await expect.poll(() => existsSync(pidFile), { timeout: 5_000, interval: 20 }).toBe(true);
81
+ return Number(readFileSync(pidFile, "utf8").trim());
82
+ }
83
+
84
+ describe("[W6/D5 前置闸] 引擎进程被 SIGTERM → run 终态 failed(禁 completed 谎报)", () => {
85
+ it("run 中途真 kill SIGTERM → engine_crashed,原因含 signal SIGTERM + stderr 尾 400 窗行为", async () => {
86
+ if (process.platform === "win32") {
87
+ // Windows 无 POSIX 信号语义(process.kill(SIGTERM) 行为不等价)——信号死亡
88
+ // 形态挂真机门(A2 手动剧本杀引擎进程),本用例仅 POSIX。
89
+ return;
90
+ }
91
+ const client = makeCrashHarness();
92
+ try {
93
+ await client.ensureConnected();
94
+ expect(client.currentState).toBe("ready");
95
+
96
+ // run 挂起(FAKE_RUN_STDERR_HANG 注入:stderr 样本 → host/log 到达锚 → hang)
97
+ const runPromise = client.request("run", {
98
+ runId: "run-sigterm-1",
99
+ task: "w6 sigterm crash probe",
100
+ ctx: { poolKey: "shared", cwd: dataDir, model: "fake/fake-1" },
101
+ });
102
+
103
+ // 确定性同步锚 ①:fake 引擎 pid 落盘(进程已起)。
104
+ const pid = await waitForPidFile();
105
+ // 确定性同步锚 ②:stderr 样本已入 core 环形缓冲尾(先写后杀——事件竞争
106
+ // 面收窄为「已积累样本后 kill」,stderr 尾断言不靠 sleep 赌时序)。
107
+ await expect
108
+ .poll(() => client.stderrTailText.includes("TAIL-OF-STDERR-SAMPLE"), {
109
+ timeout: 5_000,
110
+ interval: 20,
111
+ })
112
+ .toBe(true);
113
+
114
+ // 事故形态复现:外部直接 SIGTERM 引擎进程(宿主 infra 连带击杀等价物)。
115
+ process.kill(pid, "SIGTERM");
116
+
117
+ // 钉死语义:run 终态 failed(engine_crashed)+ 原因含信号信息——
118
+ // 旧 143 误分类器(inproc session-runner(已删):2667-2677,W3 删)的反命题:
119
+ // 信号死亡绝不允许投影为 success/completed。
120
+ const err = (await runPromise.catch((e: Error) => e)) as Error & {
121
+ code?: string;
122
+ data?: { stderrTail?: string };
123
+ };
124
+ expect(err).toMatchObject({
125
+ name: "EngineSdkError",
126
+ code: "engine_crashed",
127
+ });
128
+ expect(err.message).toContain("engine process exited unexpectedly: signal SIGTERM");
129
+ // engine_crashed 错误规格:stderr 尾 400 字符随 message——尾标记保留。
130
+ expect(err.message).toContain("TAIL-OF-STDERR-SAMPLE");
131
+ // 窗口行为自证:头标记(400 字符窗外)已被截断——「尾 400」非「全量」。
132
+ expect(err.message).not.toContain("HEAD-OF-STDERR-SAMPLE");
133
+ // 结构化 data.stderrTail 与 message 尾部同源(SDK engineCrashedError 契约)。
134
+ expect(err.data?.stderrTail).toContain("TAIL-OF-STDERR-SAMPLE");
135
+
136
+ // 死亡后状态:exited(非 unavailable——下次 run 走重建退避链,W2 套件已测)。
137
+ expect(client.currentState).toBe("exited");
138
+ } finally {
139
+ // 幂等收口:进程已死,dispose 不悬挂(killAll/dispose 对已死进程的空操作面)。
140
+ await expect(client.dispose()).resolves.toBeUndefined();
141
+ }
142
+ });
143
+ });
@@ -0,0 +1,19 @@
1
+ // fake-engine-capabilities.ts —— fake 引擎的 capabilities 常量(与
2
+ // __fixtures__/engine-protocol/smoke-run.fixture.json 的 initialize.result.capabilities
3
+ // 同源;EngineClient 仅把它作 manifest 诊断比对源,不参与判据)。
4
+
5
+ import type { EngineCapabilities } from "../../types.ts";
6
+
7
+ export const FAKE_CAPABILITIES: EngineCapabilities = {
8
+ schemaEnforcement: "emulated",
9
+ steer: "unsupported",
10
+ conversation: "native",
11
+ personaInjection: "prompt",
12
+ eventGranularity: "stream",
13
+ sandbox: "none",
14
+ sessionRead: "full",
15
+ resume: "cold",
16
+ interrupt: "kill-only",
17
+ permissionMode: "ignored",
18
+ maxTurns: true,
19
+ };