@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,372 +0,0 @@
1
- // zcode-engine-timeout.test.ts —— [P0-1 U2] 引擎超时处置链测试(设计权威源
2
- // docs/design/timeout-zcode-turn-and-settled-watchdog.md §6 D3/D4、§5.2 F-1/F-2)。
3
- // 全部跑 __fixtures__/fake-appserver.mjs 子进程(scenario 注入),绝不 spawn 真
4
- // zcode.cjs。覆盖:
5
- // - stop 应答三态裁决各一(D3 v1.1 超时入口 escalateOn:"stop-outcome"):
6
- // ① stop 成功应答 → 止损确认链终止,共享进程不杀(boot 计数复用证据);
7
- // ② 协议性 error 应答(stopError 注入,健康形态竞态——closeSession 先行关会话)
8
- // → 不升级杀链(「stop 报错一律升级会误杀健康进程」的击穿修正回归面);
9
- // ③ stop 无应答(stopBehavior:'hang'——控制面假死形态,SIGSTOP 等价)→ 3s 超时
10
- // 判连接级失败 → killChain 升级 → 进程死亡 + 下一任务重建(boot 2 机械证据);
11
- // - engine_timeout 前缀归类(D4,与 engine_run_failed 分流)+ 会话 id 留痕;
12
- // - idle / ceiling 两形态文案有别(ceiling 附 XYZ_ZCODE_TURN_MAX_TIMEOUT_MS env
13
- // 自救通道——§5.2 F-2);
14
- // - 非超时错误不受影响(sendError → engine_run_failed 原路径,abort 链不触发);
15
- // - alive 守卫(修复轮):conn 已 finalize 的微窗口内 stop 分支不惰性重建进程
16
- // (对称 closeSession 的 !alive 守卫),按连接级失败形态终局。
17
- // idle/ceiling 阈值经 vi.stubEnv 缩短(session-channel 的 env 通道,D2)——真实默认
18
- // 30min/60min 不在单测等待范围。
19
-
20
- import * as fs from "node:fs";
21
- import * as os from "node:os";
22
- import * as path from "node:path";
23
- import { fileURLToPath } from "node:url";
24
-
25
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
26
-
27
- import type { EngineRunResult, RunContext } from "../../../port.ts";
28
- import type { AgentCallOpts } from "../../../../../orchestration/models/types.ts";
29
- import { ZCODE_SHARED_POOL_KEY } from "../constants.ts";
30
- import { ZCODE_APPSERVER_GOLDEN } from "../golden-sample.ts";
31
- import { AppServerConnection } from "../connection.ts";
32
- import { SessionChannel, TurnTimeoutError } from "../session-channel.ts";
33
- import { ZcodeEngine, hostZcodeDbPath, type ZcodeEngineDeps } from "../zcode-engine.ts";
34
-
35
- const FAKE_CLI = fileURLToPath(new URL("./__fixtures__/fake-appserver.mjs", import.meta.url));
36
- const PROVIDER = "test-provider";
37
-
38
- const GOLDEN_SESSION_ID = "sess_golden_r3_01";
39
- const GOLDEN_FULL_TEXT = "你好,任务完成";
40
- /** 挂起场景:send 后零推送——turn 无事件(idle 主判定的判死形态)。 */
41
- const HANG_PUSHES: string[] = [];
42
-
43
- interface RpcErrorSpec {
44
- code: number;
45
- message: string;
46
- data?: unknown;
47
- }
48
-
49
- interface ScenarioOverrides {
50
- replaceSendPushes?: string[];
51
- stopBehavior?: "terminal" | "none" | "hang";
52
- stopError?: RpcErrorSpec;
53
- sendError?: RpcErrorSpec;
54
- }
55
-
56
- const engines: ZcodeEngine[] = [];
57
- let seq = 0;
58
- let tmpRoot: string;
59
- let dataDir: string;
60
- let v2Path: string;
61
-
62
- function writeJson(p: string, v: unknown): void {
63
- fs.mkdirSync(path.dirname(p), { recursive: true });
64
- fs.writeFileSync(p, JSON.stringify(v, null, 2));
65
- }
66
-
67
- beforeEach(() => {
68
- tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "zcode-eng-timeout-"));
69
- dataDir = path.join(tmpRoot, "data");
70
- v2Path = path.join(tmpRoot, "v2.json");
71
- writeJson(v2Path, {
72
- provider: { [PROVIDER]: { options: { apiKey: "k", baseURL: "https://t.example" }, models: { m1: {} } } },
73
- });
74
- });
75
-
76
- afterEach(async () => {
77
- vi.unstubAllEnvs();
78
- for (const engine of engines.splice(0)) await engine.dispose().catch(() => undefined);
79
- fs.rmSync(tmpRoot, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
80
- });
81
-
82
- interface EngineFixture {
83
- engine: ZcodeEngine;
84
- stateFile: string;
85
- scenarioFile: string;
86
- workspace: string;
87
- /** 重写 scenario(新 fake 进程启动时重读——killChain 重建轮的形态切换通道)。 */
88
- rewriteScenario: (overrides: ScenarioOverrides) => void;
89
- }
90
-
91
- function makeEngine(overrides: ScenarioOverrides = {}): EngineFixture {
92
- seq += 1;
93
- const stateFile = path.join(tmpRoot, `state-${seq}.jsonl`);
94
- const scenarioFile = path.join(tmpRoot, `scenario-${seq}.json`);
95
- const workspace = path.join(tmpRoot, `ws-${seq}`);
96
- const write = (o: ScenarioOverrides): void => {
97
- writeJson(scenarioFile, {
98
- createResult: JSON.parse(ZCODE_APPSERVER_GOLDEN.createResponse),
99
- readResult: JSON.parse(ZCODE_APPSERVER_GOLDEN.readResponse),
100
- sendPushes: (o.replaceSendPushes ?? HANG_PUSHES).map((l) => JSON.parse(l) as Record<string, unknown>),
101
- ...(o.stopBehavior !== undefined ? { stopBehavior: o.stopBehavior } : {}),
102
- ...(o.stopError !== undefined ? { stopError: o.stopError } : {}),
103
- ...(o.sendError !== undefined ? { sendError: o.sendError } : {}),
104
- });
105
- };
106
- write(overrides);
107
- const deps: ZcodeEngineDeps = {
108
- engineDataDir: () => dataDir,
109
- cliPath: FAKE_CLI,
110
- sources: { v2ConfigPath: v2Path },
111
- processEnv: {
112
- PATH: process.env.PATH ?? "",
113
- // 钉扎 appserver 定向(定向不探不降);idle/ceiling 阈值走全局 env stub
114
- // (session-channel 的 resolveTurnTimerMs 直接读 process.env——D2 env 通道)
115
- XYZ_ZCODE_MODE: "appserver",
116
- FAKE_STATE_FILE: stateFile,
117
- FAKE_SESSION_SCENARIO: scenarioFile,
118
- },
119
- };
120
- const engine = new ZcodeEngine(deps);
121
- engines.push(engine);
122
- return {
123
- engine,
124
- stateFile,
125
- scenarioFile,
126
- workspace,
127
- rewriteScenario: (o) => write(o),
128
- };
129
- }
130
-
131
- // ── 流水读取 helpers(与 zcode-engine-appserver.test.ts 同款) ──
132
-
133
- interface StateEvent {
134
- seq: number;
135
- ev: string;
136
- [key: string]: unknown;
137
- }
138
-
139
- function readState(file: string): StateEvent[] {
140
- try {
141
- return fs
142
- .readFileSync(file, "utf8")
143
- .trim()
144
- .split("\n")
145
- .filter(Boolean)
146
- .map((l) => JSON.parse(l) as StateEvent);
147
- } catch {
148
- return [];
149
- }
150
- }
151
-
152
- function isRecord(v: unknown): v is Record<string, unknown> {
153
- return typeof v === "object" && v !== null && !Array.isArray(v);
154
- }
155
-
156
- function sentMethods(stateFile: string): string[] {
157
- return readState(stateFile)
158
- .map((e) => e.frame)
159
- .filter((f): f is Record<string, unknown> => isRecord(f) && typeof f.method === "string")
160
- .map((f) => f.method as string);
161
- }
162
-
163
- function bootCount(stateFile: string): number {
164
- return readState(stateFile).filter((e) => e.ev === "boot").length;
165
- }
166
-
167
- /** fake 进程 pid(boot 流水记录——进程探活的取证面:kill(pid,0) 不抛即存活)。 */
168
- function bootPid(stateFile: string): number {
169
- const boot = readState(stateFile).find((e) => e.ev === "boot");
170
- if (!boot || typeof boot["pid"] !== "number") throw new Error("boot 流水缺失 pid");
171
- return boot["pid"];
172
- }
173
-
174
- /** 进程探活(信号 0 不投递只探测):返回 true = 存活。 */
175
- function processAlive(pid: number): boolean {
176
- try {
177
- process.kill(pid, 0);
178
- return true;
179
- } catch {
180
- return false;
181
- }
182
- }
183
-
184
- function makeTask(overrides?: Partial<AgentCallOpts>): AgentCallOpts {
185
- return { prompt: "做点什么", description: "s", model: `${PROVIDER}/m1`, ...overrides };
186
- }
187
-
188
- function makeCtx(overrides?: Partial<RunContext>): RunContext {
189
- return { taskId: "sa-timeout", poolKey: "", ...overrides };
190
- }
191
-
192
- // ============================================================
193
- // stop 应答三态裁决(D3 v1.1 超时入口)+ engine_timeout 归类(D4)
194
- // ============================================================
195
-
196
- describe("超时处置链(P0-1 U2:catch 分流 → stop-outcome 三态裁决 → engine_timeout)", () => {
197
- it("态① stop 成功应答:止损确认链终止,outcome 止损路径=「stop 已送达」,共享进程不杀(复用轮 boot 1)", async () => {
198
- vi.stubEnv("XYZ_ZCODE_TURN_IDLE_TIMEOUT_MS", "300");
199
- const f = makeEngine(); // hang 场景(send 后零事件)+ stopBehavior 缺省 terminal(reply stopped)
200
- const r: EngineRunResult = await f.engine.run(makeTask({ cwd: f.workspace }), makeCtx());
201
- // D4 归类:engine_timeout 前缀 + idle 判定标注 + 会话 id 留痕
202
- expect(r.outcome.error).toMatch(/^engine_timeout:/);
203
- expect(r.outcome.error).toContain("idle 判定");
204
- expect(r.outcome.exitCode).toBeNull();
205
- expect(r.outcome.sessionId).toBe(GOLDEN_SESSION_ID);
206
- // D3 强制可观测面(r3 SG-4):止损路径 = stop 已送达
207
- expect(r.outcome.error).toContain("session/stop 已送达");
208
- expect(r.outcome.error).not.toContain("升级杀链");
209
- // 恢复指引(§5.2 F-1)
210
- expect(r.outcome.error).toContain("engine: pi");
211
- // stop 帧已发出(send 之后)
212
- const methods = sentMethods(f.stateFile);
213
- expect(methods).toContain("session/stop");
214
- expect(methods.indexOf("session/stop")).toBeGreaterThan(methods.indexOf("session/send"));
215
- // 不杀共享进程(机械证据):fake 进程仍存活 + 全程零重启(boot 计数 1)。
216
- // (复用进程时 scenario 固化在其内存——下一任务无法切正常场景,探活是「不杀」
217
- // 的直接证据;进程若被 killChain 收割则探活必失败。)
218
- expect(processAlive(bootPid(f.stateFile))).toBe(true);
219
- expect(bootCount(f.stateFile)).toBe(1);
220
- }, 20_000);
221
-
222
- it("态② 协议性 error 应答(会话已回收形态):不升级杀链(健康形态竞态——stop 报错 ≠ 控制面死)", async () => {
223
- vi.stubEnv("XYZ_ZCODE_TURN_IDLE_TIMEOUT_MS", "300");
224
- const f = makeEngine({
225
- stopError: { code: -32004, message: "Session is not active" },
226
- });
227
- const r = await f.engine.run(makeTask({ cwd: f.workspace }), makeCtx());
228
- expect(r.outcome.error).toMatch(/^engine_timeout:/);
229
- expect(r.outcome.error).toContain("idle 判定");
230
- // 止损路径 = 协议性 error 分支,绝不出现杀链分支专属文案
231
- expect(r.outcome.error).toContain("协议性 error");
232
- expect(r.outcome.error).not.toContain("无应答已升级杀链");
233
- expect(sentMethods(f.stateFile)).toContain("session/stop");
234
- // 进程未被杀(机械证据:探活 + 零重启)——本用例守护的正是「stop 失败一律升级」
235
- // 修正后不误杀健康共享进程的回归面(D3 被否谱系第四条)
236
- expect(processAlive(bootPid(f.stateFile))).toBe(true);
237
- expect(bootCount(f.stateFile)).toBe(1);
238
- }, 20_000);
239
-
240
- it("态③ stop 无应答(hang=控制面假死):3s 超时判连接级失败 → killChain 升级 → 进程死亡 + 重建(boot 2)", async () => {
241
- vi.stubEnv("XYZ_ZCODE_TURN_IDLE_TIMEOUT_MS", "300");
242
- const f = makeEngine({ stopBehavior: "hang" });
243
- const r = await f.engine.run(makeTask({ cwd: f.workspace }), makeCtx());
244
- expect(r.outcome.error).toMatch(/^engine_timeout:/);
245
- expect(r.outcome.error).toContain("idle 判定");
246
- // D3 强制可观测面(A2 对称):止损路径 = stop 无应答已升级杀链
247
- expect(r.outcome.error).toContain("session/stop 无应答已升级杀链");
248
- expect(sentMethods(f.stateFile)).toContain("session/stop");
249
- // killChain 真的收割了共享进程(机械证据):旧 fake 进程已死(探活失败)
250
- expect(processAlive(bootPid(f.stateFile))).toBe(false);
251
- // 切换正常场景后下一任务必须重建(boot 计数:U4 起首轮 killChain 收口后自动重试
252
- // 一次——重试轮经惰性重建 boot 2(同 scenario 仍 hang+stop hang → 重试轮也走
253
- // killChain 收口);本用例的下一任务再重建 boot 3——「killChain 后重建」语义不变,
254
- // 计数随 U4 重试 +1)
255
- f.rewriteScenario({ replaceSendPushes: [...ZCODE_APPSERVER_GOLDEN.pushStream, ...ZCODE_APPSERVER_GOLDEN.terminal] });
256
- const r2 = await f.engine.run(makeTask({ cwd: f.workspace }), makeCtx());
257
- expect(r2.outcome.error).toBeUndefined();
258
- expect(r2.outcome.content).toBe(GOLDEN_FULL_TEXT);
259
- expect(bootCount(f.stateFile)).toBe(3);
260
- }, 40_000);
261
-
262
- it("ceiling 形态(idle 关闭 + 总上界判死):文案标 chatty-wedge + 附 XYZ_ZCODE_TURN_MAX_TIMEOUT_MS env 自救通道(F-2)", async () => {
263
- vi.stubEnv("XYZ_ZCODE_TURN_IDLE_TIMEOUT_MS", "0"); // 显式关闭 idle(规则 19 opt-out)
264
- vi.stubEnv("XYZ_ZCODE_TURN_MAX_TIMEOUT_MS", "400");
265
- const f = makeEngine();
266
- const r = await f.engine.run(makeTask({ cwd: f.workspace }), makeCtx());
267
- expect(r.outcome.error).toMatch(/^engine_timeout:/);
268
- expect(r.outcome.error).toContain("总上界");
269
- expect(r.outcome.error).toContain("chatty-wedge");
270
- // env 自救通道提示(F-2 与 idle 形态的文案分野)
271
- expect(r.outcome.error).toContain("XYZ_ZCODE_TURN_MAX_TIMEOUT_MS");
272
- expect(r.outcome.error).toContain("0 关闭总上界");
273
- // idle 形态专属的「连续静默」文案不出现
274
- expect(r.outcome.error).not.toContain("连续静默");
275
- expect(r.outcome.error).toContain("session/stop 已送达");
276
- }, 20_000);
277
-
278
- it("非超时错误不受影响:sendError → engine_run_failed 原路径,abort 链不触发(流水无 session/stop)", async () => {
279
- const f = makeEngine({ sendError: { code: -32004, message: "Session is not active" } });
280
- const r = await f.engine.run(makeTask({ cwd: f.workspace }), makeCtx());
281
- expect(r.outcome.error).toContain("engine_run_failed");
282
- expect(r.outcome.error).not.toContain("engine_timeout");
283
- expect(r.outcome.error).toContain("-32004");
284
- expect(r.outcome.sessionId).toBe(GOLDEN_SESSION_ID);
285
- // abort 链未被触发:流水只有 create/subscribe/send/close,无 stop
286
- expect(sentMethods(f.stateFile)).not.toContain("session/stop");
287
- }, 15_000);
288
-
289
- it("handle 锚定不变量在超时收口下成立:onHandleReady 已回填 sessionId + poolKey(不变量 3 不因超时路径缺失)", async () => {
290
- vi.stubEnv("XYZ_ZCODE_TURN_IDLE_TIMEOUT_MS", "300");
291
- const f = makeEngine();
292
- const ready: Array<{ sessionId: unknown; poolKey: string }> = [];
293
- const r = await f.engine.run(
294
- makeTask({ cwd: f.workspace }),
295
- makeCtx({
296
- onHandleReady: (partial) =>
297
- ready.push({ sessionId: partial.sessionRef["sessionId"], poolKey: partial.poolKey }),
298
- }),
299
- );
300
- expect(ready).toEqual([
301
- { sessionId: GOLDEN_SESSION_ID, poolKey: ZCODE_SHARED_POOL_KEY },
302
- // U4 起首轮超时收口后自动重试一次(同 hang 场景)——重试轮 create 再回填一次,
303
- // 值相同(同一 fake 的 golden create 应答):不变量 3 每轮 create 都成立
304
- { sessionId: GOLDEN_SESSION_ID, poolKey: ZCODE_SHARED_POOL_KEY },
305
- ]);
306
- expect(r.handle.data.sessionRef).toEqual({ sessionId: GOLDEN_SESSION_ID, dbPath: hostZcodeDbPath() });
307
- expect(r.handle.data.poolKey).toBe(ZCODE_SHARED_POOL_KEY);
308
- }, 20_000);
309
-
310
- it("alive 守卫:conn 已 finalize(进程死+收割完成微窗口)时 stop 分支不惰性重建,按连接级失败形态终局", async () => {
311
- // 真实微拍窗口(turn 判死与 abort 链发 stop 之间进程 finalize 完成)不可从公开
312
- // 面同步注入——白盒构造同形态快照(dispose 窄竞态守卫测试同款先例):真实
313
- // AppServerConnection 从未启动(child=null 等价 finalize 完成快照),onSpawned
314
- // 探针锁「request → ensureStarted 惰性重建」未发生(守卫缺失时 stop 分支必凭空
315
- // spawn 新一代进程再写帧)。
316
- let spawned = false;
317
- const conn = new AppServerConnection({
318
- cliPath: FAKE_CLI,
319
- cwd: tmpRoot,
320
- env: {
321
- PATH: process.env.PATH ?? "",
322
- FAKE_STATE_FILE: path.join(tmpRoot, "state-alive-guard.jsonl"),
323
- FAKE_SESSION_SCENARIO: path.join(tmpRoot, "scenario-alive-guard.json"),
324
- },
325
- stderrLogPath: path.join(dataDir, "logs", "alive-guard-stderr.log"),
326
- onSpawned: () => {
327
- spawned = true;
328
- },
329
- });
330
- expect(conn.alive).toBe(false); // 快照前置:无活进程(finalize 完成形态)
331
- const engine = new ZcodeEngine({
332
- engineDataDir: () => dataDir,
333
- cliPath: FAKE_CLI,
334
- sources: { v2ConfigPath: v2Path },
335
- processEnv: { PATH: process.env.PATH ?? "", XYZ_ZCODE_MODE: "appserver" },
336
- });
337
- engines.push(engine);
338
- const ghostRt = {
339
- conn,
340
- channel: new SessionChannel(conn),
341
- activeSessions: new Set<string>(),
342
- };
343
- const turn: Promise<unknown> = Promise.reject(
344
- new TurnTimeoutError("idle", { thresholdMs: 300, elapsed: 301, lastEventAt: undefined }),
345
- );
346
- void turn.catch(() => undefined); // abort 链只 race 不 await reject——防 unhandled rejection
347
- const chain = (
348
- engine as unknown as {
349
- appServerAbortChain: (
350
- rt: unknown,
351
- turn: Promise<unknown>,
352
- getSessionId: () => string | undefined,
353
- sessionCreated: Promise<void>,
354
- entry: { escalateOn: "turn-settled" | "stop-outcome" },
355
- ) => Promise<string>;
356
- }
357
- ).appServerAbortChain.bind(engine);
358
- // 超时入口:conn 已死 = 连接级失败形态——不发 stop、不惰性重建,直接杀链终局
359
- const stopPath = await chain(ghostRt, turn, () => GOLDEN_SESSION_ID, Promise.resolve(), {
360
- escalateOn: "stop-outcome",
361
- });
362
- expect(stopPath).toBe("stop-unreachable-killed");
363
- expect(spawned).toBe(false); // 守卫生效:零惰性 spawn(无新进程被凭空拉起)
364
- expect(conn.alive).toBe(false); // 连接保持死亡态(无 request 触发重建)
365
- // 用户取消入口:跳过 stop 落回 grace race——turn 已 reject 立即 settled(零重建)
366
- const settledPath = await chain(ghostRt, turn, () => GOLDEN_SESSION_ID, Promise.resolve(), {
367
- escalateOn: "turn-settled",
368
- });
369
- expect(settledPath).toBe("settled-in-grace");
370
- expect(spawned).toBe(false);
371
- }, 15_000);
372
- });
@@ -1,145 +0,0 @@
1
- // zcode-engine.live.test.ts —— 端到端真机门(单一 app-server 形态,2026-09 起无
2
- // spawn 段):真实 zcode CLI + 真实凭据 + 真实 LLM 调用。手动门(设计 §3.3.8
3
- // conformance run 层同构):默认 skip,跑法:
4
- //
5
- // ENGINE_CONFORMANCE_LIVE=1 ZCODE_E2E_MODEL='<provider/model>' pnpm vitest run src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts
6
- //
7
- // ZCODE_E2E_MODEL 缺省值是采集 golden 样本的本机 provider(v2 config 实测带 apiKey、
8
- // 公网可达);换机器跑时用 env 覆盖为本机可用模型。共享宿主 HOME 形态:会话写入
9
- // 真实 ~/.zcode/cli/db/db.sqlite(与 GUI 共写,WAL 并发安全——已接受的拍板代价);
10
- // journal/引擎数据落 /tmp(跑完由本文件 afterAll 清理)。
11
-
12
- import { execFileSync } from "node:child_process";
13
- import * as fs from "node:fs";
14
- import * as os from "node:os";
15
- import * as path from "node:path";
16
-
17
- import { afterAll, beforeAll, describe, expect, it } from "vitest";
18
-
19
- import type { AgentEvent } from "../../../types.ts";
20
- import { ZCODE_SHARED_POOL_KEY } from "../constants.ts";
21
- import { ZcodeEngine } from "../zcode-engine.ts";
22
- import { assertAgentEventInvariants } from "../../../__tests__/conformance/agent-event-invariants.ts";
23
-
24
- const LIVE = process.env["ENGINE_CONFORMANCE_LIVE"] === "1";
25
- const E2E_MODEL = process.env["ZCODE_E2E_MODEL"] ?? "e512d53e-0bfc-4915-9081-860d4aa13cd0/mimo-v2.5-pro";
26
- const AS_DATA_ROOT = path.join(fs.realpathSync(os.tmpdir()), "zcode-appserver-e2e-data");
27
- const AS_WORK_CWD = path.join(fs.realpathSync(os.tmpdir()), "zcode-appserver-e2e-cwd");
28
-
29
- describe.skipIf(!LIVE)("ZcodeEngine 端到端真机(app-server 常驻,共享宿主 HOME)", () => {
30
- let engine: ZcodeEngine;
31
-
32
- beforeAll(() => {
33
- fs.mkdirSync(AS_WORK_CWD, { recursive: true });
34
- engine = new ZcodeEngine({
35
- engineDataDir: () => AS_DATA_ROOT,
36
- });
37
- });
38
-
39
- afterAll(async () => {
40
- // dispose 是常驻进程的唯一收割入口(D6)——先 dispose 再清目录
41
- await engine.dispose().catch(() => undefined);
42
- for (const dir of [AS_DATA_ROOT, AS_WORK_CWD]) {
43
- try {
44
- fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
45
- } catch {
46
- // 尽力清理
47
- }
48
- }
49
- });
50
-
51
- it("probe:二进制/版本两项全过", async () => {
52
- const report = await engine.probe();
53
- expect(report.ok).toBe(true);
54
- expect(report.engineVersion).toMatch(/^0\.\d+\.\d+$/);
55
- }, 60_000);
56
-
57
- it("run:常驻通道全链(stream 事件流出 + read①级 native + poolKey 锚定 'shared' + 会话落宿主 db)", async () => {
58
- const events: AgentEvent[] = [];
59
- const { handle, outcome } = await engine.run(
60
- {
61
- prompt: 'Verify this arithmetic check: 2 + 2 = 4. If it is correct the verdict must be "ok", otherwise "bad".',
62
- description: "e2e-appserver",
63
- model: E2E_MODEL,
64
- cwd: AS_WORK_CWD,
65
- schema: {
66
- type: "object",
67
- properties: { verdict: { type: "string", enum: ["ok", "bad"] } },
68
- required: ["verdict"],
69
- additionalProperties: false,
70
- },
71
- },
72
- { taskId: "sa-live-appserver", poolKey: "", onEvent: (e) => events.push(e) },
73
- );
74
-
75
- // C2:outcome 正确
76
- expect(outcome.error).toBeUndefined();
77
- expect(outcome.exitCode).toBe(0);
78
- expect(outcome.sessionId).toMatch(/^sess_/);
79
- expect(outcome.parsedOutput).toEqual({ verdict: "ok" });
80
- expect(outcome.usage?.input).toBeGreaterThan(0);
81
-
82
- // C3 stream 口径:text_delta 实时流出(非终态一次性)+ 不变量五条
83
- expect(events.some((e) => e.type === "text_delta")).toBe(true);
84
- assertAgentEventInvariants(events, { granularity: "stream", content: outcome.content });
85
-
86
- // handle 锚定:poolKey 恒 'shared',dbPath = 宿主 HOME 绝对路径(①级读取钥匙)。
87
- // 期望值独立展开(不调实现函数——实现改错时断言须红),非 path.join(homedir(), suffix) 同源
88
- const dbPath = handle.data.sessionRef["dbPath"];
89
- expect(dbPath).toBe(path.resolve(os.homedir(), ".zcode", "cli", "db", "db.sqlite"));
90
- expect(dbPath.startsWith("/")).toBe(true);
91
-
92
- // read 第①级:SQLite 完整重建(非降级)——读的是宿主 db(共享 HOME 形态)
93
- const view = await engine.read(handle);
94
- expect(view.source).toBe("native");
95
- expect(view.turns.length).toBeGreaterThanOrEqual(1);
96
- }, 300_000);
97
-
98
- it("abort:长任务中途取消 → stop 链合成终态 exitCode=null + 常驻进程不残留 + 后续任务可用", async () => {
99
- const controller = new AbortController();
100
- const runPromise = engine.run(
101
- {
102
- prompt:
103
- "Write an extremely detailed 5000-word technical essay about distributed systems consistency models. Do not stop early.",
104
- description: "e2e-appserver-abort",
105
- model: E2E_MODEL,
106
- cwd: AS_WORK_CWD,
107
- },
108
- { taskId: "sa-live-appserver-abort", poolKey: "", signal: controller.signal },
109
- );
110
- // 等 send 已发(会话在途),再中途 abort——覆盖 stop 链而非 pre-abort 短路
111
- await new Promise((r) => setTimeout(r, 4_000));
112
- controller.abort();
113
- const { outcome } = await runPromise;
114
-
115
- expect(outcome.exitCode).toBeNull();
116
- expect(outcome.error).toContain("session/stop");
117
-
118
- // 无残留:引擎数据目录锚定的 app-server 进程在 dispose 前应 ≤1(abort 不误杀
119
- // 共享进程;与其他 zcode 实例区分靠 --cwd 引擎数据目录路径)
120
- const leftovers = listZcodeProcessesForCwd(AS_DATA_ROOT);
121
- expect(leftovers.length).toBeLessThanOrEqual(1);
122
-
123
- // 崩溃/中止后下一任务自动重建或复用(不变量 4 同路径)——abort 不污染常驻进程
124
- const second = await engine.run(
125
- { prompt: "Reply with the single word: ok", description: "e2e-appserver-after-abort", model: E2E_MODEL, cwd: AS_WORK_CWD },
126
- { taskId: "sa-live-appserver-after-abort", poolKey: "" },
127
- );
128
- expect(second.outcome.error).toBeUndefined();
129
- expect(second.outcome.content.trim().length).toBeGreaterThan(0);
130
- }, 300_000);
131
- });
132
-
133
- /** 扫系统进程表:--cwd 锚定到指定目录的 app-server 常驻进程(僵尸检测)。spawn 形态
134
- * 是 `node .../engines/zcode/appserver-launcher.cjs app-server --cwd <dir>`——zcode.cjs
135
- * 经 launcher 的 import() 动态加载,不出现在 cmdline。 */
136
- function listZcodeProcessesForCwd(cwd: string): string[] {
137
- try {
138
- const out = execFileSync("ps", ["-eo", "command"], { encoding: "utf8" });
139
- return out
140
- .split("\n")
141
- .filter((line) => line.includes("appserver-launcher.cjs") && line.includes(`--cwd ${cwd}`));
142
- } catch {
143
- return [];
144
- }
145
- }