@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,210 +0,0 @@
1
- // reader.test.ts —— sqlite 只读 SessionView(验收 4 的 mock 半边:真实 node:sqlite 建库
2
- // → turns/usage/toolCalls 派生;db 缺失/表漂移 → 结构化错误供降级)。真机半边(实录池
3
- // 内 db)在 zcode-engine.live.test.ts。
4
-
5
- import * as fs from "node:fs";
6
- import * as os from "node:os";
7
- import * as path from "node:path";
8
-
9
- import { beforeAll, beforeEach, describe, expect, it } from "vitest";
10
-
11
- import { readZcodeSessionView, ZcodeReaderError } from "../reader.ts";
12
-
13
- let tmpDir: string;
14
- let dbPath: string;
15
-
16
- // 建出与 zcode 0.16.5 同形的三表最小 schema(列裁剪到 reader 消费面)
17
- async function createDb(file: string): Promise<void> {
18
- const { DatabaseSync } = (await import("node:sqlite")) as { DatabaseSync: new (p: string) => unknown };
19
- type Db = {
20
- exec: (s: string) => void;
21
- prepare: (s: string) => { run: (...a: unknown[]) => void };
22
- close: () => void;
23
- };
24
- const db = new DatabaseSync(file) as unknown as Db;
25
- db.exec(
26
- "CREATE TABLE session (id TEXT PRIMARY KEY, time_created INTEGER);" +
27
- "CREATE TABLE message (id TEXT PRIMARY KEY, session_id TEXT, sequence INTEGER, data TEXT);" +
28
- "CREATE TABLE part (id TEXT PRIMARY KEY, message_id TEXT, session_id TEXT, sequence INTEGER, data TEXT);",
29
- );
30
- const insertMessage = db.prepare("INSERT INTO message (id, session_id, sequence, data) VALUES (?, ?, ?, ?)");
31
- const insertPart = db.prepare("INSERT INTO part (id, message_id, session_id, sequence, data) VALUES (?, ?, ?, ?, ?)");
32
-
33
- // session 1(目标):user prompt + assistant 两轮(text/reasoning/tool/step-finish×2)
34
- db.prepare("INSERT INTO session (id, time_created) VALUES (?, ?)").run("sess_target", 2000);
35
- insertMessage.run("msg_user", "sess_target", 0, JSON.stringify({ role: "user" }));
36
- insertPart.run("part_user_text", "msg_user", "sess_target", 0, JSON.stringify({ type: "text", text: "the task" }));
37
-
38
- insertMessage.run("msg_asst", "sess_target", 1, JSON.stringify({ role: "assistant" }));
39
- insertPart.run("p0", "msg_asst", "sess_target", 0, JSON.stringify({ type: "step-start" }));
40
- insertPart.run("p1", "msg_asst", "sess_target", 1, JSON.stringify({ type: "reasoning", text: "thinking hard" }));
41
- insertPart.run(
42
- "p2",
43
- "msg_asst",
44
- "sess_target",
45
- 2,
46
- JSON.stringify({
47
- type: "tool",
48
- tool: "Bash",
49
- state: JSON.stringify({ status: "completed", input: { command: "ls" }, output: "file-a\nfile-b" }),
50
- }),
51
- );
52
- insertPart.run(
53
- "p3",
54
- "msg_asst",
55
- "sess_target",
56
- 3,
57
- JSON.stringify({
58
- type: "step-finish",
59
- reason: "stop",
60
- cost: 0,
61
- tokens: { total: 110, input: 100, output: 10, reasoning: 0, cache: { read: 5, write: 0 } },
62
- }),
63
- );
64
- // 第二轮(同 assistant message 内第二个 step 段)
65
- insertPart.run("p4", "msg_asst", "sess_target", 4, JSON.stringify({ type: "text", text: "final answer" }));
66
- insertPart.run(
67
- "p5",
68
- "msg_asst",
69
- "sess_target",
70
- 5,
71
- JSON.stringify({
72
- type: "step-finish",
73
- reason: "stop",
74
- cost: 0.5,
75
- tokens: { total: 60, input: 50, output: 10, reasoning: 0, cache: { read: 0, write: 0 } },
76
- }),
77
- );
78
-
79
- // session 2(更早):验证「缺省取最新」与定向读取互不干扰
80
- db.prepare("INSERT INTO session (id, time_created) VALUES (?, ?)").run("sess_older", 1000);
81
- insertMessage.run("msg_old", "sess_older", 0, JSON.stringify({ role: "assistant" }));
82
- insertPart.run("part_old", "msg_old", "sess_older", 0, JSON.stringify({ type: "text", text: "old turn" }));
83
- insertPart.run(
84
- "part_old2",
85
- "msg_old",
86
- "sess_older",
87
- 1,
88
- JSON.stringify({ type: "step-finish", tokens: { input: 1, output: 1, cache: {} } }),
89
- );
90
- db.close();
91
- }
92
-
93
- beforeAll(async () => {
94
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "zcode-reader-"));
95
- dbPath = path.join(tmpDir, "db.sqlite");
96
- await createDb(dbPath);
97
- });
98
-
99
- describe("readZcodeSessionView:native 读取", () => {
100
- it("turns 派生:两轮闭合、text/thinking/toolCalls/usage 齐备(验收 4)", async () => {
101
- const view = await readZcodeSessionView(dbPath, "sess_target");
102
- expect(view.engineId).toBe("zcode");
103
- expect(view.source).toBe("native");
104
- expect(view.sessionId).toBe("sess_target");
105
- expect(view.turns).toHaveLength(2);
106
-
107
- const [t1, t2] = view.turns!;
108
- expect(t1!.text).toBe("");
109
- expect(t1!.thinking).toBe("thinking hard");
110
- expect(t1!.toolCalls).toHaveLength(1);
111
- expect(t1!.toolCalls[0]!.toolName).toBe("Bash");
112
- expect(t1!.toolCalls[0]!.args).toEqual({ command: "ls" });
113
- expect(t1!.toolCalls[0]!.result).toEqual({ content: ["file-a\nfile-b"] });
114
- expect(t1!.toolCalls[0]!.isError).toBeUndefined(); // status completed
115
- expect(t1!.closed).toBe(true);
116
-
117
- expect(t2!.text).toBe("final answer");
118
- expect(t2!.closed).toBe(true);
119
-
120
- // usage 聚合 = 两轮 usageDelta 之和(cost 累计第二段的 0.5)
121
- expect(view.usage).toEqual({ input: 150, output: 20, cacheRead: 5, cacheWrite: 0, cost: 0.5, total: 175 });
122
- });
123
-
124
- it("缺省 sessionId 取池内最新 session(time_created DESC)", async () => {
125
- const view = await readZcodeSessionView(dbPath);
126
- expect(view.sessionId).toBe("sess_target");
127
- });
128
-
129
- it("tool 状态非 completed 标 isError", async () => {
130
- // 单独建一个带失败工具调用的 session,避免污染上面的聚合断言
131
- const failDb = path.join(tmpDir, "fail.sqlite");
132
- await createDb(failDb);
133
- const { DatabaseSync } = (await import("node:sqlite")) as { DatabaseSync: new (p: string) => unknown };
134
- type Db = { prepare: (s: string) => { run: (...a: unknown[]) => void }; close: () => void };
135
- const db = new DatabaseSync(failDb) as unknown as Db;
136
- db.prepare("INSERT INTO session (id, time_created) VALUES (?, ?)").run("sess_fail", 3000);
137
- db
138
- .prepare("INSERT INTO message (id, session_id, sequence, data) VALUES (?, ?, ?, ?)")
139
- .run("msg_f", "sess_fail", 0, JSON.stringify({ role: "assistant" }));
140
- db
141
- .prepare("INSERT INTO part (id, message_id, session_id, sequence, data) VALUES (?, ?, ?, ?, ?)")
142
- .run(
143
- "pf",
144
- "msg_f",
145
- "sess_fail",
146
- 0,
147
- JSON.stringify({
148
- type: "tool",
149
- tool: "Edit",
150
- state: JSON.stringify({ status: "error", input: { file: "a" }, output: "conflict" }),
151
- }),
152
- );
153
- db.close();
154
- const view = await readZcodeSessionView(failDb, "sess_fail");
155
- expect(view.turns[0]!.toolCalls[0]!.isError).toBe(true);
156
- });
157
- });
158
-
159
- describe("readZcodeSessionView:结构化错误(供降级②③级,验收 4 负例)", () => {
160
- beforeEach(() => {
161
- // 无共享状态需重置;保留钩子位置说明负例组意图
162
- });
163
-
164
- it("db 文件缺失 → engine_session_read_failed(detail 含路径)", async () => {
165
- const missing = path.join(tmpDir, "nope.sqlite");
166
- try {
167
- await readZcodeSessionView(missing, "sess_x");
168
- expect.unreachable("should throw");
169
- } catch (err) {
170
- expect(err).toBeInstanceOf(ZcodeReaderError);
171
- const e = err as ZcodeReaderError;
172
- expect(e.code).toBe("engine_session_read_failed");
173
- expect(e.detail).toContain(missing);
174
- expect(e.message).toContain("降级");
175
- }
176
- });
177
-
178
- it("表结构漂移(缺 part 表)→ 结构化错误含漂移提示", async () => {
179
- const drifted = path.join(tmpDir, "drifted.sqlite");
180
- const { DatabaseSync } = (await import("node:sqlite")) as { DatabaseSync: new (p: string) => unknown };
181
- type Db = { exec: (s: string) => void; close: () => void };
182
- const db = new DatabaseSync(drifted) as unknown as Db;
183
- // 只建 session/message(zcode 升级把 part 改名的形态);塞一行 session 让定位
184
- // 通过、失败必然发生在 part 查询(表缺失)
185
- db.exec(
186
- "CREATE TABLE session (id TEXT PRIMARY KEY, time_created INTEGER);" +
187
- "CREATE TABLE message (id TEXT PRIMARY KEY, session_id TEXT, sequence INTEGER, data TEXT);" +
188
- "INSERT INTO session (id, time_created) VALUES ('sess_d', 1);",
189
- );
190
- db.close();
191
- try {
192
- await readZcodeSessionView(drifted);
193
- expect.unreachable("should throw");
194
- } catch (err) {
195
- const e = err as ZcodeReaderError;
196
- expect(e.code).toBe("engine_session_read_failed");
197
- expect(e.message).toContain("漂移");
198
- expect(e.message).toContain("golden");
199
- }
200
- });
201
-
202
- it("session 不存在 → 结构化错误(不静默空视图)", async () => {
203
- try {
204
- await readZcodeSessionView(dbPath, "sess_ghost");
205
- expect.unreachable("should throw");
206
- } catch (err) {
207
- expect((err as ZcodeReaderError).detail).toContain("sess_ghost");
208
- }
209
- });
210
- });
@@ -1,71 +0,0 @@
1
- // registration.test.ts —— 注册表接线(验收 6):'zcode' 可经 getEngine 获取、幂等
2
- // 覆盖、engineDataDir 默认走 common/data-dir SSOT。clearEngines 隔离全局注册表状态。
3
-
4
- import { afterEach, describe, expect, it, vi } from "vitest";
5
-
6
- // u0-data-discovery 注入化后 data-dir 回退值来自 HostServices.dataRoot() 端口——
7
- // 用例内 configureCore 假宿主控制端口态,afterEach reset 防跨用例泄漏
8
- import { configureCore, resetCoreForTests } from "../../../../../core/host-services.ts";
9
-
10
- import { clearEngines, getEngine, hasEngine, listEngines } from "../../../registry.ts";
11
- import { createZcodeEngine, registerZcodeEngine } from "../registration.ts";
12
-
13
- const FAKE_DATA_ROOT = "/fake-registration-data-root";
14
-
15
- afterEach(() => {
16
- clearEngines();
17
- resetCoreForTests();
18
- vi.restoreAllMocks();
19
- });
20
-
21
- describe("registerZcodeEngine", () => {
22
- it("登记后 getEngine('zcode') 可用,id/capabilities 正确", () => {
23
- registerZcodeEngine(() => "/tmp/data");
24
- expect(hasEngine("zcode")).toBe(true);
25
- expect(listEngines()).toContain("zcode");
26
- const engine = getEngine("zcode");
27
- expect(engine.id).toBe("zcode");
28
- expect(engine.capabilities().schemaEnforcement).toBe("emulated");
29
- });
30
-
31
- it("幂等:重复注册覆盖不堆积(listEngines 单条)", () => {
32
- registerZcodeEngine(() => "/tmp/data");
33
- registerZcodeEngine(() => "/tmp/data2");
34
- expect(listEngines().filter((id) => id === "zcode")).toHaveLength(1);
35
- // 覆盖后单例按新工厂重建(engineDataDir 已换)
36
- expect(hasEngine("zcode")).toBe(true);
37
- });
38
-
39
- it("createZcodeEngine DI 工厂:deps 直达引擎", () => {
40
- const engine = createZcodeEngine({ engineDataDir: () => "/tmp/x" });
41
- expect(engine.id).toBe("zcode");
42
- });
43
- });
44
-
45
- describe("engineDataDir 默认通道(common/data-dir SSOT)", () => {
46
- it("缺省经 getEngineDataDir 解析:env 优先,缺失回落宿主数据根(warn 一次)", async () => {
47
- // warn 断言走 getEngineDataDir 自带的 DI warn 参数——缺省 warn 通道是
48
- // core logger facade(configureCore 后经 pi-host 桥接落文件,不经
49
- // console.warn),spy console 永远收不到且会让 logger 落文件产生测试副作用。
50
- const { getEngineDataDir, resetDataDirWarnForTests } = await import("../../../common/data-dir.ts");
51
- const warns: string[] = [];
52
- const prev = process.env["XYZ_AGENT_DATA_DIR"];
53
- delete process.env["XYZ_AGENT_DATA_DIR"];
54
- try {
55
- resetCoreForTests();
56
- configureCore({ dataRoot: () => FAKE_DATA_ROOT, log: () => {} });
57
- resetDataDirWarnForTests();
58
- // 回退分支:无 env → HostServices.dataRoot()(假宿主值)+ warn 一次
59
- expect(getEngineDataDir(process.env, (m) => warns.push(m))).toBe(FAKE_DATA_ROOT);
60
- expect(warns).toHaveLength(1);
61
- expect(warns[0]).toContain("XYZ_AGENT_DATA_DIR");
62
- // env 分支:显式注入即取 env 值(透传链证据见 common/data-dir.ts 文件头)
63
- process.env["XYZ_AGENT_DATA_DIR"] = "/from-host";
64
- expect(getEngineDataDir(process.env, (m) => warns.push(m))).toBe("/from-host");
65
- expect(warns).toHaveLength(1);
66
- } finally {
67
- if (prev !== undefined) process.env["XYZ_AGENT_DATA_DIR"] = prev;
68
- else delete process.env["XYZ_AGENT_DATA_DIR"];
69
- }
70
- });
71
- });
@@ -1,247 +0,0 @@
1
- // session-channel-dispose-harvest.test.ts —— P0-1 U5 dispose 前收割单测(机制层)。
2
- //
3
- // 设计权威源:docs/design/timeout-zcode-turn-and-settled-watchdog.md §3.4(退化路径)、
4
- // §6 D7(dispose 收割兜底)、§11 P-Z3(close 吞没 → dispose 触发 failAllTurns)。
5
- // P-Z3 的「close 事件吞没」在真实子进程形态不可确定性注入(Node child 进程退出后
6
- // stdio 关闭即触发 close 事件)——真实现场归 Gate B;本文件用 mock 连接承载机制层
7
- // 可判定形态:不触发 onClose(= close 吞没的机制等价物)→ dispose → 在途 turn 收敛
8
- // 为明确失败。与 zcode-engine-dispose.test.ts(fake-appserver 子进程集成面)互补。
9
- //
10
- // 覆盖:
11
- // ① close 吞没形态:dispose 触发 failAllTurns——在途 turn 于 dispose 时收割
12
- // (P-Z3 核心断言),收割后到达的终态不再改写(settled 守卫);
13
- // ② grace 窗口内全部终态化:并发多会话 turn 全量收割,不留永久 pending;
14
- // ③ 正常 close 主路径零回归:onClose 收割先行 → dispose no-op 不改写收割错误;
15
- // ④ 终态已落定(成功)后 dispose:settled 守卫不改写已成功结果;
16
- // ⑤ dispose 收割后 closeSession 短路:runTurn finally 不再发 session/close
17
- // (防写死进程/惰性重建——D7 收割语义的必要闭环)+ 正常完成对照(发 close);
18
- // ⑥ 二次 dispose 幂等。
19
-
20
- import { afterEach, describe, expect, it } from "vitest";
21
-
22
- import type { AppServerConnection } from "../connection.ts";
23
- import {
24
- SessionChannel,
25
- type SessionTurnResult,
26
- type SessionTurnOptions,
27
- } from "../session-channel.ts";
28
-
29
- // ============================================================
30
- // mock 连接 + 驱动器(与 session-channel-turn-timers.test.ts 同形态,
31
- // 增补 onClose handler 的手动触发面——close 吞没注入的机制等价物)
32
- // ============================================================
33
-
34
- interface MockChannel {
35
- ch: SessionChannel;
36
- /** 我方发出的请求帧流水(method 序可断言)。 */
37
- requests: Array<{ method: string; params: unknown }>;
38
- /** 手动触发连接崩溃广播(close 吞没形态 = 不触发;正常形态 = 测试显式触发)。 */
39
- emitClose: (reason: string) => void;
40
- emit: (method: string, params: unknown) => void;
41
- emitTerminal: (sessionId: string | undefined, status: string) => void;
42
- }
43
-
44
- let sidSeq = 0;
45
-
46
- function makeMockChannel(): MockChannel {
47
- const notifications = new Map<string, (params: unknown) => void>();
48
- const requests: Array<{ method: string; params: unknown }> = [];
49
- const closeHandlers = new Set<(reason: string) => void>();
50
- const conn = {
51
- alive: true,
52
- onNotification: (method: string, h: (params: unknown) => void) => {
53
- notifications.set(method, h);
54
- return () => notifications.delete(method);
55
- },
56
- onClose: (h: (reason: string) => void) => {
57
- closeHandlers.add(h);
58
- return () => closeHandlers.delete(h);
59
- },
60
- request: (method: string, params: unknown) => {
61
- requests.push({ method, params });
62
- if (method === "session/create") {
63
- sidSeq += 1;
64
- return Promise.resolve({ session: { sessionId: `sess_h${sidSeq}` } });
65
- }
66
- if (method === "session/send") return Promise.resolve({ accepted: true });
67
- if (method === "session/read") return Promise.resolve({ messages: [] });
68
- return Promise.resolve({});
69
- },
70
- } as unknown as AppServerConnection;
71
- const ch = new SessionChannel(conn);
72
- return {
73
- ch,
74
- requests,
75
- emitClose: (reason) => {
76
- for (const fn of [...closeHandlers]) fn(reason);
77
- },
78
- emit: (method, params) => notifications.get(method)?.(params),
79
- emitTerminal: (sessionId, status) =>
80
- notifications
81
- .get("v4/telemetry/event")
82
- ?.({ kind: "turn.terminal", status, sessionId }),
83
- };
84
- }
85
-
86
- interface TurnTracker {
87
- outcome: "pending" | "fulfilled" | "rejected";
88
- result: SessionTurnResult | undefined;
89
- error: unknown;
90
- promise: Promise<SessionTurnResult>;
91
- /** onSessionCreated 回填(getter——回调晚于 tracker 构造,值拷贝会恒空)。 */
92
- readonly sessionId: string;
93
- }
94
-
95
- function startTurn(ch: SessionChannel, opts: SessionTurnOptions = {}): TurnTracker {
96
- let sessionId = "";
97
- const promise = ch.runTurn({ workspacePath: "/tmp/ws-harvest", mode: "yolo" }, "任务", {
98
- onSessionCreated: (sid) => {
99
- sessionId = sid;
100
- },
101
- ...opts,
102
- });
103
- const t: TurnTracker = {
104
- outcome: "pending",
105
- result: undefined,
106
- error: undefined,
107
- promise,
108
- get sessionId(): string {
109
- return sessionId;
110
- },
111
- };
112
- void promise.then(
113
- (r) => {
114
- t.outcome = "fulfilled";
115
- t.result = r;
116
- },
117
- (e) => {
118
- t.outcome = "rejected";
119
- t.error = e;
120
- },
121
- );
122
- return t;
123
- }
124
-
125
- /** 排空微任务链(create→subscribe→send 全是已 resolve 的 promise——一拍 setTimeout 足够)。 */
126
- function flush(): Promise<void> {
127
- return new Promise((resolve) => setTimeout(resolve, 0));
128
- }
129
-
130
- async function settle(t: TurnTracker): Promise<void> {
131
- await t.promise.then(
132
- () => undefined,
133
- () => undefined,
134
- );
135
- }
136
-
137
- let enginesChannels: SessionChannel[] = [];
138
- afterEach(() => {
139
- for (const ch of enginesChannels.splice(0)) ch.dispose();
140
- });
141
-
142
- // ============================================================
143
- // dispose 收割(P0-1 U5/D7:close 缺失/被吞没的退化路径闭合)
144
- // ============================================================
145
-
146
- describe("dispose 收割(P-Z3 机制层:close 吞没 → dispose 触发 failAllTurns)", () => {
147
- it("close 吞没形态:dispose 时在途 turn 收割为明确失败,迟到终态不再改写", async () => {
148
- const m = makeMockChannel();
149
- enginesChannels.push(m.ch);
150
- const t = startTurn(m.ch);
151
- await flush();
152
- expect(t.outcome).toBe("pending"); // send 已发、无终态——在途
153
-
154
- m.ch.dispose(); // close 吞没(onClose 未触发)→ dispose 收割兜底
155
- await settle(t);
156
-
157
- expect(t.outcome).toBe("rejected");
158
- const err = t.error as Error;
159
- expect(err).toBeInstanceOf(Error);
160
- expect(err.message).toContain("已 dispose");
161
- expect(err.message).toContain("收割");
162
- expect(err.message).toContain("恢复指引");
163
- // 收割后到达的权威终态:settled 守卫——落定结果不改写
164
- m.emitTerminal(t.sessionId, "success");
165
- expect(t.outcome).toBe("rejected");
166
- expect((t.error as Error).message).toBe(err.message);
167
- });
168
-
169
- it("grace 窗口内全部终态化:并发双会话 turn 全量收割,不留永久 pending", async () => {
170
- const m = makeMockChannel();
171
- enginesChannels.push(m.ch);
172
- const t1 = startTurn(m.ch);
173
- const t2 = startTurn(m.ch);
174
- await flush();
175
- expect(t1.sessionId).not.toBe(t2.sessionId); // 双会话确实并发
176
- expect(t1.outcome).toBe("pending");
177
- expect(t2.outcome).toBe("pending");
178
-
179
- m.ch.dispose();
180
- await Promise.all([settle(t1), settle(t2)]);
181
-
182
- expect(t1.outcome).toBe("rejected");
183
- expect(t2.outcome).toBe("rejected");
184
- expect((t1.error as Error).message).toContain("已 dispose");
185
- expect((t2.error as Error).message).toContain("已 dispose");
186
- });
187
-
188
- it("正常 close 主路径零回归:onClose 收割先行(错误=连接层 reason),dispose no-op 不改写", async () => {
189
- const m = makeMockChannel();
190
- enginesChannels.push(m.ch);
191
- const t = startTurn(m.ch);
192
- await flush();
193
-
194
- m.emitClose("进程退出(code=0 signal=SIGTERM)"); // onClose 主路径收割(正常 close 到达)
195
- await settle(t);
196
- expect(t.outcome).toBe("rejected");
197
- const onCloseErr = t.error as Error;
198
- expect(onCloseErr.message).toContain("app-server 进程退出");
199
-
200
- m.ch.dispose(); // activeTurns 已空——幂等 no-op,收割错误不被 dispose 文案改写
201
- expect(t.outcome).toBe("rejected");
202
- expect((t.error as Error).message).toBe(onCloseErr.message);
203
- });
204
-
205
- it("终态已落定(成功)后 dispose:settled 守卫不改写已成功结果", async () => {
206
- const m = makeMockChannel();
207
- enginesChannels.push(m.ch);
208
- const t = startTurn(m.ch);
209
- await flush();
210
- m.emitTerminal(t.sessionId, "success");
211
- await settle(t);
212
- expect(t.outcome).toBe("fulfilled");
213
-
214
- m.ch.dispose(); // 已成功收尾的 turn 不受 dispose 收割影响
215
- expect(t.outcome).toBe("fulfilled");
216
- expect(t.result?.terminal).toEqual({ status: "success", source: "turn.terminal" });
217
- });
218
-
219
- it("dispose 收割后 closeSession 短路:finally 不发 session/close(防写死进程/惰性重建);正常完成对照=发 close", async () => {
220
- const m1 = makeMockChannel();
221
- enginesChannels.push(m1.ch);
222
- const t1 = startTurn(m1.ch);
223
- await flush();
224
- m1.ch.dispose();
225
- await settle(t1);
226
- await flush(); // runTurn finally 的 closeSession 已过
227
- expect(t1.outcome).toBe("rejected");
228
- expect(m1.requests.map((r) => r.method)).not.toContain("session/close");
229
-
230
- // 对照:正常完成的 turn,finally 发 session/close(D4 用后即毁——零回归面)
231
- const m2 = makeMockChannel();
232
- enginesChannels.push(m2.ch);
233
- const t2 = startTurn(m2.ch);
234
- await flush();
235
- m2.emitTerminal(t2.sessionId, "success");
236
- await settle(t2);
237
- expect(t2.outcome).toBe("fulfilled");
238
- expect(m2.requests.map((r) => r.method)).toContain("session/close");
239
- });
240
-
241
- it("二次 dispose 幂等:无在途 turn 时 dispose 是 no-op 不抛", async () => {
242
- const m = makeMockChannel();
243
- enginesChannels.push(m.ch);
244
- expect(() => m.ch.dispose()).not.toThrow();
245
- expect(() => m.ch.dispose()).not.toThrow();
246
- });
247
- });