@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
package/dist/index.d.ts CHANGED
@@ -1,50 +1,15 @@
1
- import { ChildProcess } from 'node:child_process';
2
- import { E as EngineCapabilities, P as ProbeReport, A as AgentCallOpts, a as AgentEvent, M as ModelInfo, b as EngineHandleData, c as EngineHandle, d as AgentOutcome, I as InteractAction, e as InteractResult, S as SessionView, f as ExecutionRecord, R as RecordSnapshot, g as SubagentRecord, h as ExecuteOptions, i as AgentResult, j as AgentConfig, k as ResolvedModel, l as AgentResult$1, C as ClosedReason, m as ExecutionOutcome, T as ToolCall, n as AgentEventLogEntry, o as ExecutionStatus, p as ProjectedOutcome, q as SubagentsGlobalConfig, r as ModelRegistryLike, s as ExecutionHandle, t as ExecutionMode, W as WorktreeHandle, u as PatchResult, v as AgentUsage, w as ExecutionTraceNode, x as TracePatch, y as RunStatus, D as DoneReason, z as WorkerLogEntry, B as DisplayItem, F as CancelResponse, G as CloseResponse, H as ForkFromResponse, L as ListResponse, J as MessageResponse, K as BgResponse, N as ExternalState, O as SubagentListItem } from './types-Dv4QhSJ_.js';
3
- export { Q as CLOSED_REASONS, U as DEFAULT_AGENT_NAME, V as DirtyWorktreeError, X as ForkDepthExceededError, Y as ReplayedTurn, Z as ResurrectDeniedError, _ as SLUG_MAX_LENGTH, $ as SubagentToolResult, a0 as ToolCallEntry } from './types-Dv4QhSJ_.js';
1
+ import { E as EnginePort, D as DiscoverEnginesOptions, a as ExecutionRecord, C as ClosedReason, b as ExecutionOutcome, A as AgentEventLogEntry, c as ExecutionStatus, P as ProjectedOutcome, R as RecordSnapshot, S as SubagentRecord, d as ExecuteOptions, e as SubagentStream, f as AgentResult, g as AgentResult$1, h as SubagentsGlobalConfig, M as ModelRegistryLike, i as ModelInfo, j as AgentConfig, k as ResolvedModel, l as StreamSink, m as ExecutionHandle, n as ExecutionMode, o as PatchResult, p as AgentCallOpts, q as ExecutionTraceNode, T as TracePatch, r as RunStatus, s as DoneReason, W as WorkerLogEntry, t as DisplayItem, u as CancelResponse, v as CloseResponse, F as ForkFromResponse, L as ListResponse, w as MessageResponse, B as BgResponse, x as ExternalState, y as SubagentListItem, z as DiscoveryRoot } from './engine-discovery-scan-ocpM8FmI.js';
2
+ export { G as CLOSED_REASONS, H as CoreLogger, I as DEFAULT_AGENT_NAME, J as DEFAULT_DATA_ROOT, K as DEFAULT_ENGINE_ID, N as DirtyWorktreeError, O as EngineHandle, Q as EngineRunResult, U as ForkDepthExceededError, V as HostServices, X as LogLevel, Y as ResurrectDeniedError, Z as RunContext, _ as SLUG_MAX_LENGTH, $ as SubagentToolResult, a0 as configureCore, a1 as getHostServices, a2 as getLogger, a3 as normalizeEngineId } from './engine-discovery-scan-ocpM8FmI.js';
3
+ import { ProbeReport, SessionView, ToolCall, UiRequest, UiRequestHandler, UiResponse, AgentEvent, UiChannelRegistry, WorktreeHandle, AgentOutcomeUsage } from '@zhushanwen/subagent-engine-sdk';
4
+ export { AgentEvent, AgentOutcome, ChannelHandler, EngineCapabilities, EngineHandleData, InteractAction, InteractResult, ProbeReport, ReplayedTurn, SessionView, ToolCallEntry, UiChannelRegistry } from '@zhushanwen/subagent-engine-sdk';
4
5
  import { Worker } from 'node:worker_threads';
5
- export { ZCODE_FALLBACK_DEFAULT_MODEL } from './execution/engine/engines/zcode/constants.js';
6
+ import 'node:child_process';
6
7
  import '@xyz-agent/extension-protocol';
7
8
 
8
9
  /** thinking level 支持顺序(低→高)。spawn 侧 `:level` 后缀仅接受本白名单值。 */
9
10
  declare const THINKING_ORDER: readonly ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
10
11
 
11
- /** 日志级别。对齐 @zhushanwen/pi-extension-logger LogLevel(三值,无 info)。 */
12
- type LogLevel = "debug" | "warn" | "error";
13
- /** core logger 接口。与 pi-extension-logger 的 ExtensionLogger 结构兼容——
14
- * u0-log 批次替换是纯 import 源替换,调用面(方法名/参数序)逐文件等价。 */
15
- interface CoreLogger {
16
- debug(msg: string, data?: unknown): void;
17
- warn(msg: string, data?: unknown): void;
18
- error(msg: string, data?: unknown): void;
19
- }
20
- declare function getLogger(component: string): CoreLogger;
21
-
22
- /** 发现根条目:dir 为扫描根路径;source 是宿主提供的语义标签(遮蔽报告透传用)。
23
- * source 不枚举封闭集——core 只透传不解释(宿主如 pi 壳用 user-pi/npm/npm-dev)。 */
24
- interface DiscoveryRoot {
25
- dir: string;
26
- source: string;
27
- }
28
- interface HostServices {
29
- /** 数据根目录:引擎隔离池 / journal / record 派生存放的锚点。
30
- * pi 壳返回 getAgentDir()(独立 pi 用户 journal 不漂目录);zsw 壳返回 zsw 数据根。 */
31
- dataRoot(): string;
32
- /** 结构化日志:对齐现 getLogger 调用面(level/component/message/data)。缺省 sink 按级分化:
33
- * warn/error 走 console、debug no-op(对齐 pi-extension-logger 语义,见 NULL_HOST.log)。 */
34
- log(level: LogLevel, component: string, message: string, data?: unknown): void;
35
- /** agent/skill/workflow 资源发现根(可选端口,缺席 = 调用方降级)。宿主只提供根列表
36
- * (按优先级低→高);扫描 / 同名遮蔽(last-writer-wins)/ 遮蔽报告语义归 core 统一。 */
37
- discoveryRoots?(): {
38
- agents?: DiscoveryRoot[];
39
- skills?: DiscoveryRoot[];
40
- workflows?: DiscoveryRoot[];
41
- };
42
- }
43
- /** core 缺省数据根(~/.subagent-core,homedir 推导——禁止写死绝对路径,排查规则)。
44
- * 供无自有数据根的轻宿主显式采用;core 自身不静默兜底到该值。 */
45
- declare const DEFAULT_DATA_ROOT: string;
46
- declare function configureCore(host: HostServices): void;
47
- declare function getHostServices(): HostServices;
12
+ type ExtensionMode = "tui" | "rpc" | "json" | "print";
48
13
 
49
14
  /** 投递意图(与 session-delivery 的 DeliveryIntent 字面量一致)。 */
50
15
  type DeliveryIntent = "interrupt-at-turn-boundary" | "after-run";
@@ -118,229 +83,33 @@ interface DeliveryHandle {
118
83
  /** 销毁(清队列 + 清 timer + 退订)。 */
119
84
  dispose(): void;
120
85
  }
86
+ /** countActiveFromEntries 的过滤选项([F1] 与 pending-notifications 的
87
+ * CountActiveOptions 对齐的子集——core 契约面只暴露跨 session 基准一个字段)。 */
88
+ interface CountActivePortOptions {
89
+ /**
90
+ * [W4 读侧过滤②] 跨 session 残留过滤基准:传入时端口实现按「register entry 的
91
+ * sessionId ≠ 基准 → 跳过」过滤——fork 继承的父级注册残留(翻 process 档后 U4
92
+ * 补注销不再中性化,永久留存于子 session 文件)不进差集。
93
+ * 缺省(undefined)= 不过滤(向后兼容:既有调用方零改动行为不变)。
94
+ */
95
+ currentSessionId?: string;
96
+ }
121
97
  interface NotifyDomainPorts {
122
98
  /** pending 活跃计数(pi 会话 entries 中 register − unregister 差集的数值)。
123
99
  * 契约为 number 而非 pi 侧 CountActiveResult:core 消费面只读 count,契约面最窄;
124
- * pi 壳注入时拆 `countActiveFromEntries(entries).count`。 */
125
- countActiveFromEntries?(entries: unknown[]): number;
100
+ * pi 壳注入时拆 `countActiveFromEntries(entries).count`。
101
+ * [F1] 第二参为可选过滤基准(CountActivePortOptions)——core 消费方(后代判定
102
+ * 读侧)持有「被读 entries 所属 session」概念时必须传入,使跨 session 残留不进
103
+ * 差集;与 pending-notifications 实装签名(entries, opts?) 对齐。 */
104
+ countActiveFromEntries?(entries: unknown[], opts?: CountActivePortOptions): number;
126
105
  /** 投递内核工厂。签名与 @xyz-agent/session-delivery 的 createDelivery 结构兼容,
127
106
  * pi 壳直传其本体即可。缺席 = 消费方降级直发。 */
128
107
  createDelivery?(port: DeliveryPort, options?: DeliveryConfig): DeliveryHandle;
129
108
  }
130
109
  declare function configureNotifyDomain(ports: NotifyDomainPorts): void;
131
110
 
132
- type ExtensionMode = "tui" | "rpc" | "json" | "print";
133
-
134
- /**
135
- * subagent text_delta streaming sink。
136
- *
137
- * background subagent 执行期间,session-runner 的 agentEvent 出口把每个 text_delta
138
- * 传到 SubagentStream.onDelta。本模块做 100ms 时间窗合并后,通过 StreamSink.setWidget
139
- * 转发到 RPC stdout(经 ctx.ui.setWidget → extension_ui_request 通道)。
140
- *
141
- * SubagentStream 是一个生命周期对象——内聚 buffer/timer 状态 + onDelta/dispose 方法。
142
- * 调用方(subagent-service)创建后只需在 text_delta 时调 onDelta、终态时调 dispose,
143
- * 不需要拆散 push/clear 两个函数跨层透传。
144
- *
145
- * 设计要点:
146
- * - leading edge:第一个 delta 立即 flush(前端尽快看到开始)
147
- * - trailing edge:后续 delta 追加 buffer,timer 到期后 flush
148
- * - 每次 flush 把 buffer 的累积文本 split("\n") 截尾 MAX_WIDGET_LINES 行传给 setWidget
149
- * - dispose 清除 widget + 清 timer
150
- */
151
-
152
- /** UI streaming sink 的最小接口(ctx.ui.setWidget 的 duck-typed 子集)。
153
- *
154
- * 当前只有一个 adapter(index.ts session_start 包装 ctx.ui.setWidget)。
155
- * 保留接口而非裸函数类型,因为 StreamSink 的语义是「UI sink 契约」——
156
- * 测试 mock 和未来可能的第二 sink(如写文件)都走此契约。 */
157
- interface StreamSink {
158
- setWidget(key: string, lines: string[] | undefined): void;
159
- }
160
- /**
161
- * subagent text_delta streaming 生命周期对象。
162
- *
163
- * 创建后:
164
- * - `onDelta(delta)`:session-runner 每次 text_delta 调
165
- * - `dispose()`:subagent 终态时调,清除 widget + 清 timer
166
- *
167
- * buffer/timer 状态全部内聚在此对象,调用方不需要关心合并逻辑。
168
- */
169
- declare class SubagentStream {
170
- private readonly widgetKey;
171
- private readonly sink;
172
- private buffer;
173
- private timer;
174
- private hasFlushed;
175
- private disposed;
176
- constructor(recordId: string, sink: StreamSink);
177
- /** 接收一个 text_delta 增量。空串静默丢弃(不消耗 leading edge)。 */
178
- onDelta(delta: string): void;
179
- /** 终态清理:清除 widget + 清 timer(幂等)。 */
180
- dispose(): void;
181
- private flush;
182
- }
183
-
184
- /**
185
- * run 的运行期上下文。任务声明(AgentCallOpts,D6 合流后的单一形状)与运行期句柄
186
- * 分离——signal/ctxModel/onComplete 从 ExecuteOptions 移出(设计 §3.3.5 删字段去向),
187
- * 因为它们是宿主注入的运行期对象,不属于跨引擎持久化的任务声明。
188
- *
189
- * 常驻进程友好(D1):onEvent 回调式(而非迭代器式)+ AbortSignal——引擎内部换常驻
190
- * server 实现(未来 driver host)时接口不动。
191
- */
192
- interface RunContext {
193
- /** = record.id(bg-N-xxx / run-N)——journal 文件名与池引用计数 key(P2 消费)。 */
194
- taskId: string;
195
- /** D5 隔离池(宿主分配,设计 §3.3.9;pi 无池化恒 'shared')。 */
196
- poolKey: string;
197
- /** abort 分级入口(D1:引擎原生中断 → 公共杀链兜底)。 */
198
- signal?: AbortSignal;
199
- /** 事件流出口(host 消费后统一落 journal,D6 第②级)。 */
200
- onEvent?: (event: AgentEvent) => void;
201
- /**
202
- * model 解析第三层兜底(现有 D-008 语义不变)——**pi 链路专属兜底**:经
203
- * taskSpecToExecuteOptions → resolveModel 第三层消费(PiEngine 直通)。自带
204
- * provider 体系与缺省模型的引擎(如 zcode:requested > 引擎缺省常量链)按自身
205
- * 默认链解析,不消费本字段(zcode 侧在「ctx 有模型但被忽略」时出声留痕,
206
- * zcode-engine.warnIgnoredCtxModel)。
207
- */
208
- ctxModel?: ModelInfo;
209
- /**
210
- * text_delta streaming 通道(宿主侧 UI widget)。与 onEvent 平行的 text_delta 出口:
211
- * background 路径 onEvent=undefined 但流式仍需送达(双通道互斥设计,见 session-runner
212
- * agentEvent 出口注释)。pi 回填期承载 AgentRunner port 的 stream 透传(行为零变化),
213
- * 语义上是宿主设施而非引擎专有——未来引擎的 text_delta 同样可走此通道。
214
- */
215
- stream?: SubagentStream;
216
- /**
217
- * [P1 pi 回填透传] 调用方已持有的 schema 激活预编码值(AgentCallOpts.schemaEnv 直传
218
- * 形态)。生产路径中 resolveAgentOpts 恒耦合产出 schema+schemaEnv(值 = JSON.stringify
219
- * (schema)),引擎从 task.schema 派生即可逐字节等值;解耦形态(有 schemaEnv 无
220
- * schema)生产不可达、仅见于直构调用,派生无源——本字段是其唯一透交通道。
221
- * 引擎在 task.schema 存在时忽略此值(派生优先,设计 §3.3.5 删字段去向)。
222
- */
223
- schemaEnv?: string;
224
- /**
225
- * [P4 D9①] 引擎 fallback 留痕(probe 失败路由回默认引擎)。路由层(routing.ts)
226
- * 产出,引擎投影到 outcome.engineFallback(zcode 等无 record 通路的引擎以此留痕;
227
- * pi 引擎另经 ExecuteOptions 投影进 record)。
228
- */
229
- engineFallback?: {
230
- from: string;
231
- reason: string;
232
- };
233
- /**
234
- * [P4 对齐点③] 引擎声明实际隔离池 key(journal 落盘路径权威)。宿主创建 journal
235
- * writer 时只能用缺省占位 poolKey(pi 恒 'shared'),非池化稳定的引擎(zcode 按
236
- * provider+model 池化)在 prepare 期确定 poolKey 后回调本方法重定向 writer——
237
- * 保证 journal 落盘路径与 handle.poolKey 同源(单一权威,不再两边推导)。
238
- * 契约:必须在首个事件 emit 之前调用(zcode coarse 事件在终态后合成,天然满足;
239
- * 未来流式引擎需在事件出口前调用)。
240
- */
241
- onPoolResolved?: (poolKey: string) => void;
242
- /**
243
- * [R4 §3.4 不变量 3] 运行中句柄回填通道:引擎在「session/create 应答到达后」
244
- * 立即回调(早于 run resolve——stream 引擎的 run 生命周期远长于会话建立)。
245
- * 与 onPoolResolved 分立两个时点:poolKey 在 prepare 期(onPoolResolved,连接
246
- * 建立前即可知),sessionRef 在 create 应答后(本回调)。编排层收到后立即回填
247
- * record.engineHandle 并落 entry——运行中的 GUI 经 entry 重建 record 即拿到
248
- * ①②级读取钥匙,不再等 run resolve 后的终态回填。可选回调:不支持运行中回填
249
- * 的引擎(spawn 单轮、终态即回填)不调用,宿主语义不受影响。
250
- */
251
- onHandleReady?: (partial: Pick<EngineHandleData, "sessionRef" | "poolKey">) => void;
252
- /**
253
- * [U0 D10] 引擎 spawn 的子进程句柄注册钩子(宿主终止链记账)。引擎在 spawn 成功后
254
- * 同步回调(与 pi runSpawn 的 spawnedChildren.set 同构时机);宿主据此把 child 注册进
255
- * session-runner 的 spawnedChildren Map(cancel SIGTERM / dispose 收割兜底 / killAll
256
- * 全量清理对非 pi 引擎 record 生效)。close/error 后由宿主按句守卫移除。可选:引擎
257
- * 内部不 spawn 进程(如未来常驻 driver host 实现)时不调用,宿主记账自然为空。
258
- *
259
- * 边界声明(R1 D6):本钩子只用于 per-record 一次性 spawn(一任务一进程模态)。
260
- * 引擎持有的常驻进程(跨任务共享,如 app-server 常驻连接)不经本钩子注册、不进
261
- * spawnedChildren Map——其生命周期完全归引擎 dispose 管理(防 per-record 重复
262
- * SIGTERM / 单任务 abort 误杀共享进程)。
263
- */
264
- onChildSpawned?: (child: ChildProcess) => void;
265
- }
266
- /**
267
- * run 的返回:终态 + 可持久化 handle。
268
- *
269
- * handle 语义(设计 §3.3.5 run 错误语义三条):prepare 期错误(credential_missing /
270
- * model_not_available / prompt_too_large)在进程创建前 reject、不产生 handle;运行中
271
- * 失败不 reject——合成 error outcome + 正常 handle 返回(record 必须收尾);abort 走
272
- * 完杀链后同前(exitCode=null + error 含杀链标记)。
273
- */
274
- interface EngineRunResult {
275
- handle: EngineHandle;
276
- outcome: AgentOutcome;
277
- }
278
- /**
279
- * subagent 执行引擎的唯一契约点(D1)。实现方:PiEngine(回填)/ ZcodeEngine(P3)/
280
- * 未来各引擎适配器。上层(工具面/workflow 引擎/GUI)只消费中立类型,不感知引擎。
281
- *
282
- * 贯穿纪律(设计 §3.3.1):宿主编排——引擎只当单 agent 执行器,六家原生多 agent 机制
283
- * 一律禁用不依赖。
284
- */
285
- interface EnginePort {
286
- /** 注册表 key('pi' | 'zcode' | ...)。 */
287
- readonly id: string;
288
- /** D3(同步无副作用——调用前拒绝的判据)。 */
289
- capabilities(): EngineCapabilities;
290
- /** D7(factory 初始化 + 版本变化检测触发;opts.force 跳过缓存强探)。 */
291
- probe(opts?: {
292
- force?: boolean;
293
- }): Promise<ProbeReport>;
294
- /** D1 主语义:fire-to-completion。[D6 合流] task = AgentCallOpts(单一任务形状,
295
- * 原 AgentTaskSpec 已并入——字段裁定见 orchestration/models/types.ts)。 */
296
- run(task: AgentCallOpts, ctx: RunContext): Promise<EngineRunResult>;
297
- /**
298
- * D1 可选面:交互控制面。pi 首期原生实现(现有 chatMode 行为直通);不支持
299
- * conversation 的引擎返回 engine_capability_unsupported(同步拒绝、不创建进程)。
300
- */
301
- interact(handle: EngineHandle, action: InteractAction): Promise<InteractResult>;
302
- /** D6 三级降级链:①引擎原生读取 → ②宿主 event journal(P2)→ ③outcome-only。 */
303
- read(handle: EngineHandle): Promise<SessionView>;
304
- /**
305
- * [U7] 可选面:模型可发现性——引擎自带 provider/model 体系时(如 zcode 的 v2 桌面
306
- * 登录态),列出当前环境实际可用的模型清单(带凭据校验),供 system prompt 引擎段
307
- * 与 GUI 引擎选择器消费。省略/返回 null = 「与主 agent 模型体系一致」(pi 的语义:
308
- * system prompt 已有 <available_provider_models> 段,无需引擎再列)。
309
- * engine-neutral:未来引擎(AcpEngine 等)实现本方法即自动获得注入与展示,宿主
310
- * 侧零改动。
311
- */
312
- listModels?(): Array<{
313
- id: string;
314
- name?: string;
315
- }> | null;
316
- /**
317
- * [u-h2 D2-2] 可选面:派发同步期 model 校验(引擎 registry 单源裁决)。实现引擎复用其
318
- * prepare 期同一校验函数(zcode: resolveZcodeModelRef——同一函数两处消费,canonicalRef
319
- * 归一化与短名缺省 provider 决策不产生双实现漂移);校验失败同步 throw(编排层包装为
320
- * 「引擎与模型不配套」错误,见 engine/model-validation.ts)。
321
- *
322
- * modelRef undefined = 查询引擎缺省模型(D2-1:主 agent 的 pi id 不透传给非 pi 引擎,
323
- * 缺省语义归引擎——zcode 落 ZCODE_FALLBACK_DEFAULT_MODEL)。返回 canonical 全名供
324
- * record.model 留痕。
325
- *
326
- * 未实现:model 透传,引擎自身 prepare 期校验兜底(现状语义);pi 不实现(pi 链走
327
- * 既有三层解析 + assertCanonicalModelRef 裁决,搬迁是大重构,设计 D2-2 被否②)。
328
- */
329
- validateModel?(modelRef: string | undefined): {
330
- canonicalRef: string;
331
- };
332
- /**
333
- * [R1 D6] 可选停机面:释放引擎持有的常驻资源(如 app-server 常驻进程 / 长连接)。
334
- * 幂等契约(§3.4 不变量 4):重复调用无副作用;dispose 后首个 run 自动重建(与
335
- * 「进程死后重建」同一代码路径)。可选成员保持向后兼容——无常驻资源的引擎(pi
336
- * 现状 spawn 单轮)不必实现。等待策略(D6①「触发不等待」):宿主收割入口
337
- * (registry disposeEngines → killAllSpawnedChildren)只同步调用拿 Promise 不
338
- * await,引擎实现须自行保证同步面(立即 fire close 帧 + 同步 SIGTERM)在返回
339
- * Promise 前完成;grace→SIGKILL 升级序列属异步面(promise 段)。
340
- */
341
- dispose?(): Promise<void>;
342
- }
343
-
111
+ /** 宿主接线:登记补扫发现参数(与发现扫描同源;重复登记覆盖,幂等)。 */
112
+ declare function setEngineDiscoveryRescanOptions(opts: DiscoverEnginesOptions): void;
344
113
  /** 三层路由的输入(各层值由调用方装配;undefined = 该层不指定)。 */
345
114
  interface EngineRoutingInput {
346
115
  /** 第一层:调用参数 engine(workflow step 级 / AgentCallOpts.engine)。 */
@@ -376,6 +145,12 @@ interface EngineRouteOptions {
376
145
  hasEngineFn?: (engineId: string) => boolean;
377
146
  /** 注册表清单(缺省 registry.listEngines——engine_not_found 文案的数据源)。 */
378
147
  listEnginesFn?: () => string[];
148
+ /**
149
+ * 可用引擎清单(D4 回落目标序:manifest displayName 稳定序;缺省
150
+ * registry.listEnginesByDisplayName)。清单内 id 即视为可用(发现且已注册)——
151
+ * 调用方负责排序口径;routeEngine 按序取第一个 ≠ 请求引擎的 id 作回落目标。
152
+ */
153
+ listAvailableEnginesFn?: () => string[];
379
154
  }
380
155
  interface EngineRouteResult {
381
156
  engine: EnginePort;
@@ -395,177 +170,607 @@ interface EngineRouteResult {
395
170
  * 路由 + 探针 + fallback 编排(SAR run 入口调用)。
396
171
  *
397
172
  * 失败形态(全部抛结构化错误,调用方转 AgentResult.error):
398
- * - 未注册 id(调用参数层漏网):EngineNotFoundError(engine_not_found)
173
+ * - 未注册 id(call/frontmatter 层):EngineNotFoundError(engine_not_found)
174
+ * - default 层缺省引擎不在清单且无任何可用引擎:EngineNotFoundError
175
+ * (「未发现任何引擎包」+ 安装指引,D4)
399
176
  * - strict 或守卫命中:EngineError(engine_probe_failed)
400
177
  * - 守卫 c(显式 model + 将换引擎):EngineError(model_not_available)
401
178
  */
402
179
  declare function routeEngine(opts: EngineRouteOptions): Promise<EngineRouteResult>;
403
180
 
404
181
  /**
405
- * 把注册表引擎列表同步到 engines.json(session_start 时调用)。
182
+ * 三级发现装载 + 把引擎清单同步到 engines.json(session_start 时调用)。
183
+ *
184
+ * 发现时机(W4 §2.4):与 syncEnginesFile 同点——扩展组合根的模块加载点与
185
+ * session_start 兜底点即本函数既有调用点(调用方零改动),扫描一次 + 装载进注册表
186
+ * (装载结果即缓存);只读 manifest 不握手(portFactory 惰性,扫描不 spawn 引擎)。
187
+ *
188
+ * 投影源(§3.4 投影面表「清单 = 已发现且可执行」)= 本次发现装载结果 ∪ inproc 过渡
189
+ * 注册快照(listEngines() 剔除历史发现装载的 id——registry 无撤销 API,引擎包卸载
190
+ * 后已装载 descriptor 会滞留,投影时经 loadedDiscoveryIds 排除即「卸载 → 下次扫描
191
+ * 自动消失」清理通道;A4 新引擎装包零改 core 出现在清单)。W11 删 inproc 后清单 =
192
+ * 纯发现结果(零命中 → 空清单,GUI 按既有语义给 engine_not_found + 安装指引)。
406
193
  *
407
194
  * 幂等:内容与现文件一致时零写入(mtime 不动——读侧无谓失效);写入走 tmp+rename
408
195
  * 原子替换(shared/atomic-write 统一原语,U6b 迁移——与池 config 同防线)。
409
- * fail-safe:任何 IO 异常吞掉(可发现性降级不阻塞
410
- * session 启动——GUI 兜底显示 ['pi'])。
196
+ * fail-safe:发现与 IO 异常都吞掉(可发现性降级不阻塞 session 启动——GUI 兜底显示
197
+ * 既有清单)。
411
198
  */
412
199
  declare function syncEnginesFile(agentDir: string): void;
413
200
 
414
- interface ManifestRecord {
415
- id: string;
416
- rootSessionId: string;
417
- /** 直接父 subagent record ID(层级树构建用)。顶层 record 缺失(undefined)。M3a 补字段。 */
418
- parentRecordId?: string;
419
- agentName: string;
420
- /**
421
- * 终态枚举:finalizeRecord running/closed/cancelled 三态。
422
- * SP-1 重构:旧 completed/failed 合并为 closed(L1 统一终态)。
423
- * cancelled 保持独立(用户取消语义)。crashed 不进 manifest——
424
- * crashed 是重启重建时靠 sidecar 四分支推断的派生态(见 record-store.ts reconstructAll)。
425
- * 历史 "error"/"completed"/"failed" 值由读侧 mapManifestStatus 向后兼容映射。
426
- */
427
- status: "running" | "closed" | "cancelled";
428
- createdAt: number;
429
- completedAt?: number;
430
- sessionFile?: string;
431
- /** FR-7 补字段:manifest 写入时从 ExecutionRecord 抓取,供 manifestToSubagent 投影真实值。 */
432
- task?: string;
433
- slug?: string;
434
- model?: string;
435
- }
436
- declare class ManifestStore {
437
- private readonly dir;
438
- /** [perf] per-file 缓存:file → { stamp, record }。record=null 表示「已解析但非法」(缓存
439
- * 负结果避免反复 parse 损坏文件)。stat 戳变化(writeManifest tmp→rename 后 mtime/size 变)
440
- * 自动失效;删除的文件在下次扫描时修剪。 */
441
- private readonly cache;
442
- constructor(dir: string);
443
- /**
444
- * 原子写:tmp → fsync → rename → fsync dir(shared/atomic-write 统一原语,
445
- * U6b 迁移——原逐行实现与 writeAtomicFile 逐环等值)。真异步(fs.promises,
446
- * 不阻塞 event loop)。
447
- *
448
- * 失败时原语尽力清理残留 tmp(debug 记录,不掩盖原错误)并原样上抛——
449
- * 调用方(finalizeRecord)决定降级策略。
450
- */
451
- writeManifest(record: ManifestRecord): Promise<void>;
452
- /**
453
- * 按 id 读 manifest。文件不存在/JSON 损坏/schema 不合法均返回 null。
454
- * 调用方需处理 null。
455
- */
456
- readManifest(id: string): Promise<ManifestRecord | null>;
457
- /**
458
- * 同步读取所有 manifest 记录(best-effort,损坏/非法文件跳过)。
459
- * 供 RecordStore.collectRecords 投影 orphan 记录使用——替代对私有 dir 的反射访问。
460
- * 仅返回通过 isValidManifest 校验的记录。
461
- *
462
- * [perf] per-file 缓存 + stat 戳校验:collectRecords 每次渲染都调本方法,旧实现每次
463
- * 全量 readFileSync + JSON.parse 千级 manifest(实测 ~300ms/次)。命中缓存的文件零读取。
464
- */
465
- listAllSync(): readonly ManifestRecord[];
466
- /**
467
- * 启动时恢复 tmp 文件。
468
- * 3 分支逻辑:
469
- * 1. manifest 已存在 → 删 tmp(陈旧)
470
- * 2. tmp 合法 + manifest 缺失 → rename tmp 为 manifest
471
- * 3. tmp 非法 + manifest 缺失 → 删 tmp
472
- *
473
- * [T5④ / PS-13] per-file 容错:单个 tmp 文件操作失败(ENOENT——并发回收/外部清理
474
- * 抢先、EACCES 等)只 warn + 跳过该文件,不再中断整轮——旧实现单文件 ENOENT 即抛,
475
- * 剩余 tmp 本轮不再处理,自愈但不可见(残留顺延下次启动)。跳过数经 warn 汇总留痕,
476
- * 调用方返回值形态不变(跳过者不计数)。
477
- */
478
- recoverTmpFiles(): Promise<{
479
- deleted: number;
480
- recovered: number;
481
- }>;
482
- }
201
+ /**
202
+ * 单 record 终止记账(镜像置死位):实际终止在引擎进程内(协议 interact cancel /
203
+ * close 或 run 域 cancel 帧承载);宿主侧调用点是终止意图的记账面,宿主进程组级
204
+ * 收割兜底 = EngineClient killAll(EnginePort.dispose / abort 杀链,见 remote-engine)。
205
+ */
206
+ declare function killRecordChildWithEscalation(recordId: string, _source: string): void;
207
+ /** 全量收割记账(dispose / parent-shutdown):镜像整体置死。 */
208
+ declare function killAllSpawnedChildren(_signal?: NodeJS.Signals): number;
483
209
 
484
- /** store 变更监听器(返回取消订阅函数)。 */
485
- type ChangeListener = () => void;
486
- /** status 过滤模式(collectRecords 的核心能力参数)。 */
487
- type StatusFilter = "running" | "all";
488
- /** Pi ExtensionAPI 的最小子集(仅 collectRecords 跳过损坏 manifest 时上报用)。
489
- * 解构为局部类型,避免与 subagent-service 的 PiLike 循环依赖。 */
490
- type RecordStorePi = {
491
- appendEntry?: (customType: string, data: unknown) => void;
492
- } | null | undefined;
493
210
  /**
494
- * Record 容器。进程单例(随 SubagentService 重建)。
495
- *
496
- * 内存只留 running record——终态 record 在 archive 时立即移除,collectRecords
497
- * 读时从 sessions/*.jsonl 重建([perf] light 头部扫描 + per-file 缓存)。
211
+ * D8 兼容 deps 形状(zsw runner-core.js:163 实测调用面 {engineDataDir, cliPath?})。
212
+ * 与 engines/zcode ZcodeEngineDeps 结构兼容:zsw 传入对象可直接赋值;sources /
213
+ * probeVersion 为兼容残留字段——协议形态下不跨进程(忽略 + warn)。
214
+ */
215
+ interface D8CompatZcodeEngineDeps {
216
+ /** 引擎数据根(→ 引擎子进程 env XYZ_AGENT_DATA_DIR,见设计 §3.6 注入矩阵)。 */
217
+ engineDataDir: () => string;
218
+ /** 引擎 CLI 入口覆盖(L3 等价;缺省 = vendored 相对定位)。 */
219
+ cliPath?: string;
220
+ /** 兼容残留:模型来源/凭据路径——不跨进程(不变量 5),忽略。 */
221
+ sources?: unknown;
222
+ /** 兼容残留:版本探测执行器——协议 probe 由引擎实现承担,忽略。 */
223
+ probeVersion?: unknown;
224
+ /** env 基底合并(buildEngineChildEnv baseEnv;缺省 {...process.env})。 */
225
+ processEnv?: NodeJS.ProcessEnv;
226
+ }
227
+ /**
228
+ * [W11 收口] 旧 ZcodeEngineDeps 的兼容别名:barrel 原类型导出(zsw 调用面的 deps
229
+ * 形状契约)与 D8CompatZcodeEngineDeps 合并——结构同源(engineDataDir/cliPath/
230
+ * sources/probeVersion/processEnv),别名保留免 zsw 侧机械改名。
231
+ */
232
+ type ZcodeEngineDeps = D8CompatZcodeEngineDeps;
233
+ /**
234
+ * D8 薄壳:确保 id 'zcode' 的引擎 descriptor 已注册,engineDataDir 记入 descriptor。
498
235
  *
499
- * 任何 mutate notifyChange()(仅通知监听器;磁盘缓存靠 stat 戳自校验,不清空)。
236
+ * 注册表已有 descriptor(W4 发现器先装载 / 重复调用)→ 直接保留——发现器 cli
237
+ * descriptor 携带完整 manifest 快照,权威高于薄壳构造。未注册 → vendored 定位构造
238
+ * cli descriptor(经 W4 inspectEnginePackage 全量 manifest 解析;engineDataDir 经
239
+ * 合成 env XYZ_AGENT_DATA_DIR 被 portFactory 捕获——「以显式值为准」)。[W11/DoD#5]
240
+ * 定位/解析失败保持未注册(inproc 回退已删,不变量 6「失败不静默」——派发期
241
+ * engine_not_found 显式报错 + 恢复指引;XYZ_ZCODE_CLI 覆盖通道由 createZcodeEngine
242
+ * 的 deps.cliPath 等价承载)。
243
+ */
244
+ declare function registerZcodeEngine(engineDataDir?: () => string): void;
245
+ /**
246
+ * D8 薄壳:deps → 协议客户端映射,返回 RemoteEngine('zcode')(implements EnginePort,
247
+ * 对 zsw 透传结构兼容)。构造同步、不 throw(§3.5.3 代理形态)——引擎包缺失时
248
+ * command = 期望路径,失败显式发生在首次协议调用(engine_crashed + 恢复指引)。
249
+ */
250
+ declare function createZcodeEngine(deps: D8CompatZcodeEngineDeps): EnginePort;
251
+
252
+ /** maxTurns → spawn watchdog 毫秒估算(floor 语义:maxTurns 小时取下限)。 */
253
+ declare function maxTurnsToWatchdogMs(maxTurns: number): number;
254
+
255
+ /**
256
+ * 恒在状态段 <current_subagent_engine>(设计 D6:pi 引擎也声明——AI 不需要
257
+ * 「从段缺失反推」当前引擎)。三种形态(§3.1 终态逐字基准 + 失败路径表):
258
+ * - 缺省 / pi:声明 pi + 指向上方核心段 <available_provider_models>(无冲突 bullet);
259
+ * - 非 pi 且已注册:指向下方该引擎清单段 + 「pi registry id 不适用」+ AGENTS.md
260
+ * 冲突裁决 bullet + 省略 model 用引擎默认;
261
+ * - 未注册引擎(如配置手误 "ghost"):如实显示配置值 + 警告行(派发将报
262
+ * engine_not_found,指引修 subagents/config.json)——G4 诚实降级:不静默、不伪造。
500
263
  *
501
- * record 状态查询面(U10① D6):按状态枚举 listRunning/collectRecords(statusFilter)、
502
- * id 查询 getMutable/findLightById/getFullRecord——方法签名即导出形态,本类零改动。
264
+ * 字节稳定(D7):纯字符串确定性拼装(无 localeCompare / 无随机序 / 无时间态);
265
+ * 引擎注册与否经 hasEngine 只读判断(不取实例、不触发工厂副作用),同输入恒同输出。
266
+ */
267
+ declare function buildSubagentEngineSection(defaultEngine: string | undefined): string;
268
+ /**
269
+ * 依据全局 defaultEngine 生成追加段(不含前导换行)。
503
270
  *
504
- * @experimental execution 运行时面(设计 docs/design/subagent-core-sink-design.md §3.3 D6):
505
- * 一个 minor 周期内允许签名微调,稳定后转常规 semver 承诺。
271
+ * 规则(设计 §3.1 失败路径表 + G4 + U2 一致性审查修订):
272
+ * - defaultEngine pi / 缺省 → 不注入(pi 段已由核心提供);
273
+ * - 引擎未注册 → 不注入(状态段 <current_subagent_engine> 已有警告行,避免双份);
274
+ * - 已注册且 listModels 有清单 → 注入该引擎段(渲染不变);
275
+ * - 已注册但 listModels 未实现 / 返回 null → 「与主 agent 模型体系一致」声明段
276
+ * (port 契约语义:引擎无自有 provider 枚举面,id 见上方核心段,见
277
+ * buildCoreAlignedHint);
278
+ * - 已注册但空清单 / listModels 抛异常 → 「无凭据模型」提示行段(引擎 provider
279
+ * 体系存在但当前无可用模型,见 buildEmptyModelsHint;从「静默不注入」改为如实
280
+ * 声明——空清单返回空串会让 AI 误以为没有任何引擎清单可看)。
281
+ * fail-safe:listModels 异常同样落提示行段、不向外抛(注入失败不阻塞 agent loop——
282
+ * 与 system-prompt extension 的 before_agent_start 处置一致)。
506
283
  */
507
- declare class RecordStore {
508
- private readonly sessionsDir;
509
- private readonly manifestStore?;
510
- private readonly records;
511
- private readonly listeners;
512
- private _disposed;
513
- /** 孤儿终态恢复的已判定缓存(residual-fixes):resumable 形态无 sidecar 锚,同进程重复调用跳过。 */
514
- private orphanJudged;
515
- /** Pi handle(用于 appendEntry 上报损坏 manifest)。构造时可空,setPi() 后续注入。
516
- * 显式存为字段而非构造参数 readonly:setPi 需要写权限。 */
517
- private pi;
518
- /** [perf] per-file 缓存(key = sessionFile 绝对路径)。不再整体失效——stat 戳精准校验。
519
- * 值含负缓存(确认无 identity 的文件),防每轮全文 fallback 重读。 */
520
- private readonly fileCache;
521
- /** record id → sessionFile 索引(getFullRecord 按 id 定位文件)。随 fileCache 同步维护。 */
522
- private readonly idToFile;
523
- /** [perf] sessionsDir 最近一次全量扫描的 mtime(快路径判变,见 reconstructAll)。
524
- * null = 未扫过 / dispose。 */
525
- private dirStamp;
526
- /** [perf L-1] 首扫惰性装载的磁盘索引只读映像(key = jsonl basename)。
527
- * 扫描尾(flushIndexAfterScan)与 readdir 失败路径释放——运行期索引不再被读(L1 接管)。 */
528
- private indexEntries;
529
- /** [perf L-1] 本轮起未落盘的探测标志:scanFile 走过探测分支即置位。发起写时消费
530
- * (置 false)、写失败恢复;未写路径不清位——未落盘的探测成果跨轮携带直至真正写入。 */
531
- private indexDirty;
532
- /** [perf L-1] 上次成功落盘墙钟(节流基准)。0 = 从未写过 → 首扫 dirty 必写;
533
- * 仅成功分支推进(写失败不推进节流窗,下轮过窗重试)。 */
534
- private lastIndexWriteAt;
535
- /** [perf L-1] loadIndex 高版本标志的进程级持久态:true 时本进程所有后续扫描均不
536
- * 落盘(防 v1/v2 last-writer-wins 覆盖振荡),直至下次 loadIndex 重新评估。 */
537
- private indexHigherVersion;
538
- constructor(sessionsDir: string, manifestStore?: ManifestStore | undefined,
539
- /** Pi 入口(注入 appendEntry 用于上报损坏 manifest)。
540
- * SubagentService 构造时 this.pi 尚未注入(session_start 之前),传 undefined 兜底;
541
- * 后续通过 setPi() 注入(见下)。允许 null = 兼容 PiLike 字段类型。 */
542
- pi?: RecordStorePi);
543
- /** session_start 后由 SubagentService.initSession 调,注入真实 Pi handle。
544
- * 设计为独立方法而非要求构造时必传——RecordStore 在 SubagentService 构造时即建
545
- * (与 sessionsDir/manifestStore 一同初始化),但 this.pi 此时尚未注入。
546
- * 后续构造期外的 appendEntry 上报才有意义。 */
547
- setPi(pi: RecordStorePi): void;
548
- /** 注册新 record。触发 onChange。
549
- * W16 [D4]:record 诞生(→ running)即 append 自描述快照 entry——pi 文件是
550
- * 扩展数据持久化权威,custom entry 不进 LLM context。 */
551
- register(record: ExecutionRecord): void;
552
- /**
553
- * 归档:record 已被 completeRecord 设置了终态 status。
554
- * 立即从内存移除(终态 record 下次读时从 session.jsonl 重建)。
555
- * cancelled record 由调用方先写 tombstone(cancel 路径),此处只负责移除。
556
- *
557
- * W16 [D4]:终态冻结字段(result/endedAt/closedReason)在 completeRecord 已就绪,
558
- * 此处 append 的快照即完整终态记录(所有终态路径的必经锚点)。
559
- */
560
- archive(record: ExecutionRecord): void;
561
- /**
562
- * W16 [D4]:类外状态写点上报(record-store 内的迁移点 register/archive 已内置)。
563
- *
564
- * service 层直接改 record.status 的恢复写点调用(chatMode 续轮 idle→running
565
- * 冷路径 resumeRound、轮终 finalizeRoundToIdle 回 running-resumable)——这些
566
- * 写点绕过 register/archive,若不显式上报,pi 文件缺失该次迁移、重建源滞后。
567
- * pi 未注入(session_start 前)时可选链静默降级,不阻断主流程。
568
- */
284
+ declare function buildEngineModelsPromptAppend(defaultEngine: string | undefined): string;
285
+
286
+ /**
287
+ * record 携带的引擎 handle 消费面(EngineHandleData 的结构子集,双端契约不变):
288
+ * journalPath 绝对路径;sessionRef 内 dbPath 相对池目录 / 绝对路径均可。
289
+ */
290
+ interface EngineHandleView {
291
+ /** 引擎自定义定位符(zcode = { sessionId, dbPath })。 */
292
+ sessionRef: Record<string, string>;
293
+ /** journal 绝对路径(②级数据源;读前校验 engines 根前缀白名单)。 */
294
+ journalPath?: string;
295
+ /** 隔离池定位(路径布局 SSOT:resolvePoolDir 消费)。 */
296
+ poolKey: string;
297
+ }
298
+ /**
299
+ * 历史读取输入的 record 快照(消费字段级子集,不绑定 runtime 的完整
300
+ * SubagentRecord 形状——core import workspace private 类型)。
301
+ * engine / engineHandle 是不可信源(JSONL 文本派生),由 extractEngineId /
302
+ * parseEngineHandle 守卫式消费。
303
+ */
304
+ interface SubagentRecordSnapshot {
305
+ subagentId: string;
306
+ task: string;
307
+ result?: string;
308
+ error?: string;
309
+ startedAt?: number;
310
+ endedAt?: number;
311
+ /** record.engine('pi' | 'zcode' | ...,缺省 = pi 由 extractEngineId 归一)。 */
312
+ engine?: unknown;
313
+ /** record.engineHandle(parseEngineHandle 守卫消费)。 */
314
+ engineHandle?: unknown;
315
+ }
316
+ /** GUI 工具调用视图(结构兼容 shared ToolCall 的消费子集;id/时间戳为展示占位)。 */
317
+ interface HistoryToolCallView {
318
+ id: string;
319
+ toolName: string;
320
+ input: unknown;
321
+ output?: string;
322
+ details?: Record<string, unknown>;
323
+ status: "completed" | "error";
324
+ startTime: number;
325
+ endTime: number;
326
+ }
327
+ /** GUI thinking 块视图(结构兼容 shared ThinkingBlock)。 */
328
+ interface HistoryThinkingView {
329
+ id: string;
330
+ content: string;
331
+ collapsed: boolean;
332
+ }
333
+ /** GUI usage 视图(结构兼容 shared Usage)。 */
334
+ interface HistoryUsageView {
335
+ inputTokens: number;
336
+ outputTokens: number;
337
+ }
338
+ /** GUI 消息视图(结构兼容 shared Message 的消费子集——见文件头「为什么不 import shared」)。 */
339
+ interface HistoryMessage {
340
+ id: string;
341
+ role: "user" | "assistant";
342
+ content: string;
343
+ status: "complete" | "error";
344
+ toolCalls?: HistoryToolCallView[];
345
+ thinking?: HistoryThinkingView[];
346
+ usage?: HistoryUsageView;
347
+ timestamp: number;
348
+ error?: string;
349
+ }
350
+ /**
351
+ * engineHandle 唯一守卫(D1 双守卫收敛点)。
352
+ * 语义取收敛前 extractor 侧的严格版(两份 guard 此前已在「sessionRef 含非 string 值」
353
+ * 维度分叉:extractor 整体拒绝、history 侧逐键过滤——收敛选整体拒绝,坏形状不进
354
+ * record,读侧按缺 handle 降级 outcome-only,两侧行为面等价落点都是降级):
355
+ * - poolKey 缺失 / 非 string / 空串 → undefined(定位符不完整,读侧降③级)
356
+ * - sessionRef 非 plain object 或含非 string 值 → undefined(整体拒绝)
357
+ * - journalPath 可选 string(空串视为缺省)
358
+ */
359
+ declare function parseEngineHandle(raw: unknown): EngineHandleView | undefined;
360
+
361
+ /**
362
+ * 引擎原生 reader(①级):handle + dataDir → SessionView。
363
+ * 返回 undefined = 本级不可达/失败(编排层降②级);reader 内部自行留 debug 日志。
364
+ * 双端复用约束(设计 §3.3.7):实现必须无状态纯函数、不 import 引擎运行时件。
365
+ *
366
+ * [W11/H1] 本模块零静态引擎依赖:①级 reader 全部经注入面注册——生产调用方 =
367
+ * runtime 协议客户端(W8 subagent-engine-history 把「协议 read」注册为引擎原生
368
+ * reader,引擎 id 动态、zcode sqlite 直读在引擎进程内完成);注册表初始为空,
369
+ * 未注册引擎直接落②级 journal。
370
+ */
371
+ type NativeSessionReader = (handle: EngineHandleView, dataDir: string) => Promise<SessionView | undefined>;
372
+ /**
373
+ * 登记引擎原生 reader(W11/H1 后的唯①级接入点)。重复注册同 id = 覆盖
374
+ * (幂等,对齐 registerEngine 惯例)。生产调用方 = 宿主协议客户端接线
375
+ * (runtime subagent-engine-history 的 ensureProtocolReaderFor)。
376
+ */
377
+ declare function registerNativeSessionReader(engineId: string, reader: NativeSessionReader): void;
378
+ /**
379
+ * 非 pi record 的历史详情读取(三级降级主入口,D1 收敛后的唯一生产实现)。
380
+ *
381
+ * 降级顺序 ①→②→③ 逐级尝试,每级失败留 debug/warn 日志不抛崩溃(GUI 详情页
382
+ * 永不白屏报错,设计 A8)。engineId='pi' 返回 [](pi 的①级 = 调用方现有 JSONL
383
+ * 直读链,A1 守护)。未注册 reader 的引擎(W11 后 = 宿主未接线协议 reader 的
384
+ * 进程)跳过①级直落②级 journal——record 字段就够,详情页至少有摘要卡。
385
+ *
386
+ * @param record record 快照(engine/engineHandle 为不可信源,内部守卫消费)
387
+ * @param dataDir xyz-agent 数据根(journal/dbPath 白名单经 paths.ts 布局 SSOT 推导)
388
+ */
389
+ declare function readSubagentHistoryMessages(record: SubagentRecordSnapshot, dataDir: string): Promise<HistoryMessage[]>;
390
+
391
+ /**
392
+ * 从 turns[] 末尾推导当前活动行(running 时)。
393
+ *
394
+ * 优先级:最后一个未闭合 turn 的末尾 running toolCall → thinking → text → undefined
395
+ *
396
+ * 仅 status==="running" 时返回;terminal 态返回 undefined。
397
+ *
398
+ * 注意:返回的 type 联合("tool"|"text"|"thinking")是手写的,未通过类型守卫从
399
+ * AgentEvent 派生——它映射的是累积的 turn 状态(InternalToolCall._status + turn.thinking/text),
400
+ * 而非单个事件。若未来新增 turn 内容模式(如 reasoning_summary),须同步扩展本函数,
401
+ * 否则会静默返回 undefined(活动行运行中途消失)。updateFromEvent 的 switch 有 never 穷尽
402
+ * 检查,但本函数没有,依赖人工同步。
403
+ */
404
+ declare function getCurrentActivity(record: ExecutionRecord): {
405
+ type: "tool" | "text" | "thinking";
406
+ label: string;
407
+ } | undefined;
408
+ /**
409
+ * 聚合所有 turn 的 toolCalls(扁平化),并 strip InternalToolCall 的内部字段。
410
+ * 供 collectResult / schema enforcement 读,替代旧闭包 toolCalls 旁路。
411
+ *
412
+ * 返回 ToolCall[](不含 _status / startedTs)——跨边界导出形状清洁,
413
+ * 避免内部状态机字段泄漏到 AgentResult.toolCalls / 持久化层。
414
+ */
415
+ declare function getAllToolCalls(record: ExecutionRecord): ToolCall[];
416
+ /**
417
+ * 聚合所有 turn 的 toolCalls 总数(免克隆计数)。
418
+ *
419
+ * getAllToolCalls 会 flatMap + strip 克隆出完整数组——只需计数的调用方(渲染签名
420
+ * 每 200ms tick 调用一次)用它是纯浪费;本函数 reduce 累加各 turn 的 length,零分配。
421
+ * 与 getAllToolCalls(...).length 恒等(同一 turns 源)。
422
+ */
423
+ declare function countAllToolCalls(record: ExecutionRecord): number;
424
+ /**
425
+ * closed 终态 → 三态 outcome 的唯一权威派生(D6 收敛:原 notifier/bg-notify-render/
426
+ * shared deriveClosedDisplay 三处手写同构 switch 的单一实现)。
427
+ *
428
+ * 判定顺序(顺序敏感,勿回退成「error 有值即 failed」的无视取消规则):
429
+ * 1. closedReason === "cancelled" → "cancelled"(取消优先,不参与 error——abort 合成
430
+ * result 可能携带 error,但用户取消语义优先)
431
+ * 2. error 非空(truthy,与旧三处同构的 `record.error &&` 判定逐字对齐——空串 error
432
+ * 不构成失败)→ "failed"
433
+ * 3. 其余 → "completed"
434
+ *
435
+ * [D6 待核项保真] 「failed 优先于 patchFile 提示」:失败轮也会写 patchFile
436
+ * (doFinalizeRecord Step 0 对 worktreeHandle 无条件 collectPatch),消费方必须先按
437
+ * outcome 分流再渲染 patch 提示——failed 分支不展示 patch/result。历史 bug:notifier
438
+ * 的 patchFile 分支曾遮蔽 gc+error 判定,失败终态被 LLM 告知 completed(M1 修复存档)。
439
+ *
440
+ * [D6 显式取舍] parent-shutdown/parent-fork/parent-new 合成关闭(subagent-service
441
+ * disposeAllRecords 合成 result 恒写 error:"closed due to ${reason}")在本映射下落
442
+ * "failed"——语义为「父进程关闭时子 agent 未完成即失败」,选定行为而非疏漏,
443
+ * 勿当 bug 改回 cancelled 造成派生矛盾。
444
+ *
445
+ * 唯一写点 completeRecord 调用本函数冻结 record.outcome;通知 payload(notifier 投影
446
+ * 边界)与无 outcome 字段的存量/重建 record 由 projectOutcome 兜底复用本函数。
447
+ */
448
+ declare function deriveOutcome(closedReason: ClosedReason | undefined, error: string | undefined | null): ExecutionOutcome;
449
+ /**
450
+ * 投影层 outcome 唯一出口:running → undefined(终态语义不适用活跃态);closed →
451
+ * 一等 outcome 字段直读优先,字段缺失(存量/磁盘重建 record——outcome 持久化不在
452
+ * U3 领地内)时回退 deriveOutcome(closedReason, error) 兜底——单一权威函数,
453
+ * 消费方零手写推导。返回值联合含 "closed-legacy" 预留态,消费方必须处理。
454
+ */
455
+ declare function projectOutcome(record: {
456
+ status: ExecutionStatus;
457
+ outcome?: ExecutionOutcome;
458
+ closedReason?: ClosedReason;
459
+ error?: string;
460
+ }): ProjectedOutcome | undefined;
461
+ /** elapsedSeconds 唯一计算点(共享 helper,消除三处发散)。endedAt 缺失用 Date.now()。 */
462
+ declare function computeElapsedSeconds(record: {
463
+ startedAt: number;
464
+ endedAt?: number;
465
+ }): number;
466
+ /**
467
+ * 投影到 live 进度快照。elapsedSeconds/currentActivity/eventLog 均现算派生。
468
+ * 供 WorkflowsView 在 agent 运行期间读取实时进度。
469
+ */
470
+ declare function projectLiveProgress(record: ExecutionRecord): {
471
+ status: ExecutionRecord["status"];
472
+ turns: number;
473
+ totalTokens: number;
474
+ elapsedSeconds: number;
475
+ eventLog: AgentEventLogEntry[];
476
+ currentActivity: ReturnType<typeof getCurrentActivity>;
477
+ lastError: string | undefined;
478
+ };
479
+
480
+ /** 入队项的 child 引用形状(只取 pid 用于 rejectChildDialogs 匹配)。 */
481
+ interface DialogChildRef {
482
+ pid: number;
483
+ }
484
+ /** enqueue 的可选项。child 用于 rejectChildDialogs 关联(child close 时批量 reject)。 */
485
+ interface EnqueueOptions {
486
+ child?: DialogChildRef;
487
+ }
488
+ /**
489
+ * L2 跨子进程全局 dialog 串行队列(进程单例)。
490
+ *
491
+ * 用法(createUiRequestHandlerForMode 返回的总 handler 内):
492
+ * ```ts
493
+ * const dialogQueue = new DialogGlobalQueue();
494
+ * return async (req: UiRequest) => {
495
+ * // 调用方负责判断:dialog 入队,fire-and-forget 直接调 realHandler
496
+ * if (isDialogMethod(req.method)) return dialogQueue.enqueue(req, realHandler);
497
+ * return realHandler(req);
498
+ * };
499
+ * ```
500
+ *
501
+ * 语义保证:
502
+ * - FIFO 串行:前一个 handler settle 后才处理下一个
503
+ * - SR-4:rejectChildDialogs(child) 把该 child 的 pending 全部 resolve 为 {cancelled:true}
504
+ * - handler 抛错兜底:catch → {cancelled:true} → 继续下一个(队列不卡死)
505
+ * - 超时上界(LC-3/T2⑦):每个 dialog 项必有上界——req.timeout 显式传值优先,
506
+ * 未传挂 DEFAULT_DIALOG_TIMEOUT_MS(30min,裁决值);到点 settle {cancelled:true}
507
+ * 并 warn(恢复指引见 dialogTimeoutLogMessage),L2 processing 释放、队列继续推进。
508
+ * 「等用户无限久」改为默认有界是有意的行为变更。
509
+ * - 调用方约定只对 dialog 类调 enqueue;fire-and-forget 由调用方直接调 handler 不入队
510
+ *(enqueue 内仍防御性兼容 fire-and-forget,但不保证行为)
511
+ *
512
+ * 线程模型:纯 Promise + 微任务驱动,无锁。Node 单线程 event loop 保证队列状态一致。
513
+ *
514
+ * 单 session 假设(M-2,与 index.ts lastSessionId 同源):本队列是进程级单例(实例挂在
515
+ * globalThis[Symbol.for("@zhushanwen/pi-subagents.dialogQueue")],见 getOrCreateDialogQueue)。
516
+ * rejectAll() 清空所有 pending dialog——无 per-session 隔离。Pi 当前架构保证单进程
517
+ * 单 session 串行(同进程不会并发多个 session),故 session_shutdown 调 rejectAll() 只会清掉
518
+ * 当前 session 的 pending。若未来 Pi 支持同进程多 session 并发,session A 退出会误清 session B
519
+ * 的 pending dialog——届时需改为 per-session 隔离(入队项 QueueItem 带 sessionId,rejectAll
520
+ * 改 rejectAllForSession(sessionId),session_shutdown 只清当前 session)。
521
+ */
522
+ declare class DialogGlobalQueue {
523
+ /** 等待处理的队列(FIFO)。正在处理的项从 queue shift 出后由 current 持有。 */
524
+ private queue;
525
+ /** 正在处理的项(handler 已调、未 settle)。用于 rejectChildDialogs 取消占位中的 dialog。 */
526
+ private current;
527
+ private processing;
528
+ /**
529
+ * 入队一个 UI 请求,返回 Promise<UiResponse>。
530
+ *
531
+ * 调用方约定:只对 dialog 类(isDialogMethod===true)调 enqueue。fire-and-forget 由
532
+ * 调用方(ui-request-handler-factory.ts)在 enqueue 前判 isDialogMethod 后直接调 handler,
533
+ * 不经过本队列。enqueue 内仍防御性兼容 fire-and-forget(万一调用方未判):直接调 handler 返回,
534
+ * 不入队串行,但调用方不应依赖此防御行为。
535
+ *
536
+ * dialog 项处理(TC-E4 case 1):进队列 FIFO 串行,等前一个 settle 后才调 handler
537
+ *(争输入焦点,防并发弹窗)。
538
+ *
539
+ * handler 抛错兜底:catch → 回 {cancelled:true}(dialog 路径,队列不卡死)。
540
+ * SR-4:opts.child 用于 rejectChildDialogs 关联(dialog 项会被批量 reject,含 current)。
541
+ *
542
+ * @param req UI 请求(约定只传 dialog 类;fire-and-forget 防御性兼容)
543
+ * @param handler 真正执行请求的 handler(TUI/GUI 模式分流后的 realHandler)
544
+ * @param opts 可选 child 引用(用于 rejectChildDialogs 关联)
545
+ * @returns handler 的响应;dialog 抛错时回 {cancelled:true};child close 时回 {cancelled:true}
546
+ */
547
+ enqueue(req: UiRequest, handler: UiRequestHandler, opts?: EnqueueOptions): Promise<UiResponse>;
548
+ /**
549
+ * settle 一个 item(幂等)。handler 完成 / rejectChildDialogs / rejectAll / 超时 timer
550
+ * 都通过本方法,settled 标志保证只 settle 一次(防竞争)。
551
+ *
552
+ * #19 单一推进点:本方法 settle Promise + 清状态后,**唯一**调 processNext 推进队列。
553
+ * processNext 尾部不再调 processNext(旧代码双重推进,虽靠 processing 标志幂等,但语义混乱)。
554
+ * 为什么推进必须在 settleItem 而非 processNext 尾部:rejectChildDialogs 取消一个永不 settle
555
+ * 的 current(handler 等用户输入卡死)时,processNext 的 `await item.handler` 永不 resume,
556
+ * 尾部不会执行;只有 settleItem 里的 processNext 才能打破死锁,推进下一个。
557
+ *
558
+ * [A2-2] 超时 timer 清理也统一收口在这里:任何路径抢先 settle(reject/rejectAll/超时
559
+ * 自身)都必须撤下 armed timer——handler 永挂时 processNext 内联的 clearTimeout 不可达,
560
+ * 不在这里清则 timer 到期触发虚假「dialog timed out」warn 且句柄滞留至超时点。
561
+ */
562
+ private settleItem;
563
+ /**
564
+ * SR-4:把指定 child 的所有 pending dialog resolve 为 {cancelled:true}。
565
+ *
566
+ * 触发场景:子进程 close(用户取消 / crash / 超时 kill)时,其 pending dialog 的 handler
567
+ * 可能永不 settle(等用户输入),导致 Promise 永挂 + 内存泄漏。本方法批量清理。
568
+ *
569
+ * 处理范围(TC-E4 case 2):
570
+ * - 正在处理中(current)的该 child 项:settle {cancelled:true},解阻塞队列推进下一个
571
+ * (关键:handler 可能永不 settle,必须由这里打破死锁)
572
+ * - 队列中等待处理的该 child 项:settle {cancelled:true} 并移除
573
+ *
574
+ * 不影响其他 child 的 pending dialog(TC-E4 case 2 子测试 2)。
575
+ */
576
+ rejectChildDialogs(child: DialogChildRef): void;
577
+ /**
578
+ * 处理队列下一项(FIFO)。
579
+ *
580
+ * processing 标志保证串行:handler 运行期间 processing=true,新的 processNext 调用直接返回;
581
+ * handler settle 后由 settleItem 清 processing=false 并推进下一项(#19 单一推进点)。
582
+ *
583
+ * handler 抛错兜底(TC-E4 case 3):catch → settle {cancelled:true} → 继续。
584
+ * 不能让一个失败卡死队列(processing 永远 true)。
585
+ *
586
+ * LC-3/T2⑦ 超时上界:`await item.handler` 原本无上界——host UI promise 挂死或用户
587
+ * 永不回答时 processing 恒 true(全局 dialog 死锁)。现在每项挂队列级 timer:
588
+ * req.timeout(请求方显式传值)优先,未传/非法挂 DEFAULT_DIALOG_TIMEOUT_MS。
589
+ * 到点 settle {cancelled:true}(完整错误消息落父进程日志,含恢复指引与等待时长),
590
+ * settleItem 的 settled 标志保证与 handler 完成 / rejectChildDialogs 三方竞态下
591
+ * 恰 settle 一次。timer 回调闭包捕获 item(非读 this.current):迟到触发时
592
+ * settled 标志已置位,直接 noop,不误伤后继项。
593
+ */
594
+ private processNext;
595
+ /**
596
+ * #10:把所有 pending dialog(queue + current)全部 settle 为 {cancelled:true},
597
+ * 并清空 queue/current/processing 状态。session_shutdown 调用,保证不留永挂 Promise。
598
+ *
599
+ * 约定签名:rejectAll(): void(无参,返 void)。Group C 的 index.ts session_shutdown 依赖此契约。
600
+ *
601
+ * 幂等:依赖 settleItem 的 settled 标志——重复调用只会对已 settled 项 noop。
602
+ * 顺序敏感(#19 推进点在 settleItem):必须先清空 queue 数组再 settle current,
603
+ * 否则 settleItem(current) 同步触发的 processNext 会从旧 queue 抢占下一项作为新 current,
604
+ * 避开本方法的 cancel 语义。清空后 processNext 看到空队列直接返回,新 current 不会被抢占。
605
+ *
606
+ * 单 session 假设(M-2):见类注释。本方法清空所有 pending 不分 session——依赖 Pi 单进程
607
+ * 单 session 串行保证。session_shutdown handler(index.ts)调用本方法时,进程内只会有当前
608
+ * session 的 pending dialog。多 session 并发场景的迁移策略(rejectAllForSession)见类注释。
609
+ */
610
+ rejectAll(): void;
611
+ /** 清空队列状态(仅在 rejectAll 之后调用)。pending Promise 必须先由 rejectAll settle。
612
+ * 不 settle Promise 的纯状态重置——单独调用会导致 Promise 永挂(footgun),故设为 private。
613
+ * 外部调用方应使用 rejectAll()(它 settle 所有 pending + 重置状态,是原子操作)。 */
614
+ private resetState;
615
+ /** 当前队列长度(测试/诊断用)。含等待处理项(不含 current)。 */
616
+ get size(): number;
617
+ }
618
+
619
+ interface ManifestRecord {
620
+ id: string;
621
+ rootSessionId: string;
622
+ /** 直接父 subagent record ID(层级树构建用)。顶层 record 缺失(undefined)。M3a 补字段。 */
623
+ parentRecordId?: string;
624
+ agentName: string;
625
+ /**
626
+ * 终态枚举:finalizeRecord 写 running/closed/cancelled 三态。
627
+ * SP-1 重构:旧 completed/failed 合并为 closed(L1 统一终态)。
628
+ * cancelled 保持独立(用户取消语义)。crashed 不进 manifest——
629
+ * crashed 是重启重建时靠 sidecar 四分支推断的派生态(见 record-store.ts reconstructAll)。
630
+ * 历史 "error"/"completed"/"failed" 值由读侧 mapManifestStatus 向后兼容映射。
631
+ */
632
+ status: "running" | "closed" | "cancelled";
633
+ createdAt: number;
634
+ completedAt?: number;
635
+ sessionFile?: string;
636
+ /** FR-7 补字段:manifest 写入时从 ExecutionRecord 抓取,供 manifestToSubagent 投影真实值。 */
637
+ task?: string;
638
+ slug?: string;
639
+ model?: string;
640
+ }
641
+ declare class ManifestStore {
642
+ private readonly dir;
643
+ /** [perf] per-file 缓存:file → { stamp, record }。record=null 表示「已解析但非法」(缓存
644
+ * 负结果避免反复 parse 损坏文件)。stat 戳变化(writeManifest tmp→rename 后 mtime/size 变)
645
+ * 自动失效;删除的文件在下次扫描时修剪。 */
646
+ private readonly cache;
647
+ constructor(dir: string);
648
+ /**
649
+ * 原子写:tmp → fsync → rename → fsync dir(shared/atomic-write 统一原语,
650
+ * U6b 迁移——原逐行实现与 writeAtomicFile 逐环等值)。真异步(fs.promises,
651
+ * 不阻塞 event loop)。
652
+ *
653
+ * 失败时原语尽力清理残留 tmp(debug 记录,不掩盖原错误)并原样上抛——
654
+ * 调用方(finalizeRecord)决定降级策略。
655
+ */
656
+ writeManifest(record: ManifestRecord): Promise<void>;
657
+ /**
658
+ * 按 id 读 manifest。文件不存在/JSON 损坏/schema 不合法均返回 null。
659
+ * 调用方需处理 null。
660
+ */
661
+ readManifest(id: string): Promise<ManifestRecord | null>;
662
+ /**
663
+ * 同步读取所有 manifest 记录(best-effort,损坏/非法文件跳过)。
664
+ * 供 RecordStore.collectRecords 投影 orphan 记录使用——替代对私有 dir 的反射访问。
665
+ * 仅返回通过 isValidManifest 校验的记录。
666
+ *
667
+ * [perf] per-file 缓存 + stat 戳校验:collectRecords 每次渲染都调本方法,旧实现每次
668
+ * 全量 readFileSync + JSON.parse 千级 manifest(实测 ~300ms/次)。命中缓存的文件零读取。
669
+ */
670
+ listAllSync(): readonly ManifestRecord[];
671
+ /**
672
+ * 启动时恢复 tmp 文件。
673
+ * 3 分支逻辑:
674
+ * 1. manifest 已存在 → 删 tmp(陈旧)
675
+ * 2. tmp 合法 + manifest 缺失 → rename tmp 为 manifest
676
+ * 3. tmp 非法 + manifest 缺失 → 删 tmp
677
+ *
678
+ * [T5④ / PS-13] per-file 容错:单个 tmp 文件操作失败(ENOENT——并发回收/外部清理
679
+ * 抢先、EACCES 等)只 warn + 跳过该文件,不再中断整轮——旧实现单文件 ENOENT 即抛,
680
+ * 剩余 tmp 本轮不再处理,自愈但不可见(残留顺延下次启动)。跳过数经 warn 汇总留痕,
681
+ * 调用方返回值形态不变(跳过者不计数)。
682
+ */
683
+ recoverTmpFiles(): Promise<{
684
+ deleted: number;
685
+ recovered: number;
686
+ }>;
687
+ }
688
+
689
+ /** store 变更监听器(返回取消订阅函数)。 */
690
+ type ChangeListener = () => void;
691
+ /** status 过滤模式(collectRecords 的核心能力参数)。 */
692
+ type StatusFilter = "running" | "all";
693
+ /** Pi ExtensionAPI 的最小子集(仅 collectRecords 跳过损坏 manifest 时上报用)。
694
+ * 解构为局部类型,避免与 subagent-service 的 PiLike 循环依赖。 */
695
+ type RecordStorePi = {
696
+ appendEntry?: (customType: string, data: unknown) => void;
697
+ } | null | undefined;
698
+ /**
699
+ * Record 容器。进程单例(随 SubagentService 重建)。
700
+ *
701
+ * 内存只留 running record——终态 record 在 archive 时立即移除,collectRecords
702
+ * 读时从 sessions/*.jsonl 重建([perf] light 头部扫描 + per-file 缓存)。
703
+ *
704
+ * 任何 mutate → notifyChange()(仅通知监听器;磁盘缓存靠 stat 戳自校验,不清空)。
705
+ *
706
+ * record 状态查询面(U10① D6):按状态枚举 listRunning/collectRecords(statusFilter)、
707
+ * 按 id 查询 getMutable/findLightById/getFullRecord——方法签名即导出形态,本类零改动。
708
+ *
709
+ * @experimental execution 运行时面(设计 docs/design/subagent-core-sink-design.md §3.3 D6):
710
+ * 一个 minor 周期内允许签名微调,稳定后转常规 semver 承诺。
711
+ */
712
+ declare class RecordStore {
713
+ private readonly sessionsDir;
714
+ private readonly manifestStore?;
715
+ private readonly records;
716
+ private readonly listeners;
717
+ private _disposed;
718
+ /** 孤儿终态恢复的已判定缓存(residual-fixes):resumable 形态无 sidecar 锚,同进程重复调用跳过。 */
719
+ private orphanJudged;
720
+ /** Pi handle(用于 appendEntry 上报损坏 manifest)。构造时可空,setPi() 后续注入。
721
+ * 显式存为字段而非构造参数 readonly:setPi 需要写权限。 */
722
+ private pi;
723
+ /** [perf] per-file 缓存(key = sessionFile 绝对路径)。不再整体失效——stat 戳精准校验。
724
+ * 值含负缓存(确认无 identity 的文件),防每轮全文 fallback 重读。 */
725
+ private readonly fileCache;
726
+ /** record id → sessionFile 索引(getFullRecord 按 id 定位文件)。随 fileCache 同步维护。 */
727
+ private readonly idToFile;
728
+ /** [perf] sessionsDir 最近一次全量扫描的 mtime(快路径判变,见 reconstructAll)。
729
+ * null = 未扫过 / 已 dispose。 */
730
+ private dirStamp;
731
+ /** [perf L-1] 首扫惰性装载的磁盘索引只读映像(key = jsonl basename)。
732
+ * 扫描尾(flushIndexAfterScan)与 readdir 失败路径释放——运行期索引不再被读(L1 接管)。 */
733
+ private indexEntries;
734
+ /** [perf L-1] 本轮起未落盘的探测标志:scanFile 走过探测分支即置位。发起写时消费
735
+ * (置 false)、写失败恢复;未写路径不清位——未落盘的探测成果跨轮携带直至真正写入。 */
736
+ private indexDirty;
737
+ /** [perf L-1] 上次成功落盘墙钟(节流基准)。0 = 从未写过 → 首扫 dirty 必写;
738
+ * 仅成功分支推进(写失败不推进节流窗,下轮过窗重试)。 */
739
+ private lastIndexWriteAt;
740
+ /** [perf L-1] loadIndex 高版本标志的进程级持久态:true 时本进程所有后续扫描均不
741
+ * 落盘(防 v1/v2 last-writer-wins 覆盖振荡),直至下次 loadIndex 重新评估。 */
742
+ private indexHigherVersion;
743
+ constructor(sessionsDir: string, manifestStore?: ManifestStore | undefined,
744
+ /** Pi 入口(注入 appendEntry 用于上报损坏 manifest)。
745
+ * SubagentService 构造时 this.pi 尚未注入(session_start 之前),传 undefined 兜底;
746
+ * 后续通过 setPi() 注入(见下)。允许 null = 兼容 PiLike 字段类型。 */
747
+ pi?: RecordStorePi);
748
+ /** session_start 后由 SubagentService.initSession 调,注入真实 Pi handle。
749
+ * 设计为独立方法而非要求构造时必传——RecordStore 在 SubagentService 构造时即建
750
+ * (与 sessionsDir/manifestStore 一同初始化),但 this.pi 此时尚未注入。
751
+ * 后续构造期外的 appendEntry 上报才有意义。 */
752
+ setPi(pi: RecordStorePi): void;
753
+ /** 注册新 record。触发 onChange。
754
+ * W16 [D4]:record 诞生(→ running)即 append 自描述快照 entry——pi 文件是
755
+ * 扩展数据持久化权威,custom entry 不进 LLM context。 */
756
+ register(record: ExecutionRecord): void;
757
+ /**
758
+ * 归档:record 已被 completeRecord 设置了终态 status。
759
+ * 立即从内存移除(终态 record 下次读时从 session.jsonl 重建)。
760
+ * cancelled record 由调用方先写 tombstone(cancel 路径),此处只负责移除。
761
+ *
762
+ * W16 [D4]:终态冻结字段(result/endedAt/closedReason)在 completeRecord 已就绪,
763
+ * 此处 append 的快照即完整终态记录(所有终态路径的必经锚点)。
764
+ */
765
+ archive(record: ExecutionRecord): void;
766
+ /**
767
+ * W16 [D4]:类外状态写点上报(record-store 内的迁移点 register/archive 已内置)。
768
+ *
769
+ * 供 service 层直接改 record.status 的恢复写点调用(chatMode 续轮 idle→running
770
+ * 冷路径 resumeRound、轮终 finalizeRoundToIdle 回 running-resumable)——这些
771
+ * 写点绕过 register/archive,若不显式上报,pi 文件缺失该次迁移、重建源滞后。
772
+ * pi 未注入(session_start 前)时可选链静默降级,不阻断主流程。
773
+ */
569
774
  reportRecordTransition(record: ExecutionRecord): void;
570
775
  /** 按 id 查找。返回可变 record(仅 runtime 内部用)。 */
571
776
  getMutable(id: string): ExecutionRecord | undefined;
@@ -633,1067 +838,207 @@ declare class RecordStore {
633
838
  * - 文件不可读(IO 错误,可能暂时)→ 不判终态,落 resumable entry(防御性路径,
634
839
  * IO 恢复后重开可重判)。
635
840
  *
636
- * 防重:orphanJudged 实例级缓存(resumable 形态无 sidecar 锚,同进程重复调用跳过;
637
- * 终态形态双重防护 = sidecar + 缓存)。调用方:index.ts session_start 恢复段(一次)。
638
- */
639
- recoverOrphanRecords(rootSessionFilter?: string): void;
640
- /**
641
- * 单孤儿 record 的终态判定与落 entry(residual-fixes §5.2 三判据 + chat 分流)。
642
- * 防重锚(orphanJudged 标记)已由调用方完成。
643
- */
644
- private finalizeOrphanRecord;
645
- /**
646
- * [E2E 实测缺口] entry-born 孤儿恢复:register entry 已落主 session、但子 session 文件
647
- * 从未创建(父进程死在 spawn 窗口期——register 写点与子进程首笔写入之间的窗口;外部
648
- * 删除子文件的已知边界同形)。目录扫描(reconstructAll)看不见这类 record(无文件即
649
- * 无扫描集),recoverOrphanRecords 判不到,侧栏(runtime entry 扫描源)永久 spinner。
650
- *
651
- * 判定:读主 session 的 subagent-record entry,取每 id 末条;末条 status=running 且
652
- * 无子文件锚(不在 reconstructAll 结果中)且不在内存活 record(防误杀刚 register 的
653
- * 在途 spawn)→ 按无文件判据收敛:chatMode=true → resumable(分流语义一致);否则
654
- * closed+gc+error(子文件由子进程创建,无文件 = 子进程从未开跑,error 方向安全)。
655
- * 调用点:initSession 的 recoverOrphanRecords 之后(session_start,内存恒空)。
656
- */
657
- recoverEntryOnlyOrphans(mainSessionFile: string | undefined, rootSessionFilter?: string): void;
658
- /**
659
- * entry-born 孤儿候选判定(recoverEntryOnlyOrphans 的守卫链拆出):末条 running、
660
- * root session 匹配、无子文件锚、不在内存活 record(防误杀在途 spawn)、未判过。
661
- */
662
- private isEntryOrphanCandidate;
663
- /** entry-born 孤儿按无文件判据收敛落 entry:chatMode → resumable(分流语义一致);
664
- * 否则 closed+gc+error(子文件由子进程创建,无文件 = 子进程从未开跑,error 方向安全)。 */
665
- private finalizeEntryOnlyOrphan;
666
- /** 订阅变更。返回取消订阅函数。 */
667
- onChange(listener: ChangeListener): () => void;
668
- /** 触发所有监听器(TUI widget/list requestRender)。dispose 后短路。
669
- * [perf] 不清空磁盘缓存:per-file stat 戳自校验(任何磁盘写入改变戳 → 单文件重建),
670
- * 内存事件(register/archive)不改变磁盘文件——旧实现整体失效是全量重扫的根因。 */
671
- notifyChange(): void;
672
- /** session 结束清理。 */
673
- dispose(): void;
674
- /**
675
- * /resume /fork /new 后复活(dispose 的逆操作)。
676
- *
677
- * [PS-10/T6④] 同步复位 orphanJudged 防重缓存:resumable 形态(IO-error 保守分支 /
678
- * chatMode 分流)没有 .finalized sidecar 锚,重判资格完全由本缓存承载——dispose 时
679
- * 有 clear(session 结束),但 revive 此前不复位,导致「同进程内曾经的 IO 失败记录
680
- * 永久停留 resumable」,与本文件 recoverOrphanRecords 注释承诺的「IO 恢复后重开可重判」
681
- * 不符。/new 复活正是「重开」语义:IO 已恢复的记录下次 recoverOrphanRecords 重新判定
682
- * 收敛终态;仍不可读的记录重判再落一次 resumable entry(幂等,末条语义不变)。
683
- */
684
- revive(): void;
685
- /**
686
- * 四分支 sidecar 矩阵重建([perf] light 版)。
687
- *
688
- * 优先级:
689
- * 1. .cancelled → closed(closedReason=cancelled)
690
- * 2. .finalized → closed(closedReason=sidecar 内容 reason;空/旧格式 → disconnected)
691
- * 3. .alive + pid 存活 + 未超软超时 → running, externalInstance=true
692
- * 4. 兜底(无 marker、pid 死、超时)→ running(v4 B-1 可续聊语义)
693
- *
694
- * [perf]:逐文件 scanFile(stat 戳校验 + 头部 identity 轻量重建)。命中缓存的
695
- * 文件零文件读取;变化的文件只重建自身,其余 N-1 个复用缓存。
696
- *
697
- * session 隔离:rootSessionFilter 非空时,只保留 rootSessionId 匹配的 record。
698
- * rootSessionId 缺失(旧文件,未带身份字段)一律排除(无法判定归属)。
699
- */
700
- private reconstructAll;
701
- /**
702
- * 扫描单文件:stat 戳(jsonl + 3 sidecar)校验,全同 → 复用缓存(零文件读取,
703
- * 含负缓存直接返回 null);否则重建 light。
704
- * identity 定位两级:头部 64KB(首轮会话)→ 全文 fallback(续聊场景 identity
705
- * append 在尾部);两级都找不到 → 写负缓存(防每轮全文重读)。
706
- * 返回 null:文件消失/读失败/无 identity → 跳过。
707
- */
708
- private scanFile;
709
- /**
710
- * [perf L-1] 磁盘索引查询(首扫惰性装载,miss/空索引时 get 恒 undefined = 无索引)。
711
- * 条目戳匹配 jsonl 当前 stat → 零内容读取构造缓存条目。sidecar payload(tombstone/
712
- * alive)是活态数据,沿用探测分支的每轮重读语义;finalized reason 静态数据仅在
713
- * sidecar 存在时读一次(文件小,成本可忽略)。
714
- *
715
- * 返回 undefined = 索引未命中/戳不匹配(调用方落到原三级探测);null = 负条目命中
716
- * (「确认无 identity」跨实例持久,零探测跳过,与内存负缓存同款形态)。
717
- */
718
- private buildEntryFromIndex;
719
- /**
720
- * [perf L-1] 扫描尾索引落盘(节流):释放映像 → dirty/高版本/60s 节流窗三重门 →
721
- * fire-and-forget saveIndex(fileCache 全量投影)。写决策与发起在同步栈(collectRecords
722
- * 返回后不会再有本轮写);仅写完成的回调(推进节流窗)是异步的。所有 return 路径均
723
- * 不清 dirty——未落盘的探测成果跨轮携带,直至真正写入。
724
- *
725
- * 并发安全:节流基准只在写成功后推进,W1 在途时新一轮过窗扫描可再 dispatch W2(不做
726
- * 进程内排队——fire-and-forget 语义保持)。安全性由 saveIndex 的 tmp 唯一性
727
- * (pid+单调序号)保证:交错 rename 的终态必为某一次的完整快照(last-writer-wins,
728
- * 陈旧快照胜出时下轮戳不匹配自愈),不依赖本方法串行化。
729
- */
730
- private flushIndexAfterScan;
731
- /**
732
- * [perf L-1] fileCache 全量投影 → 索引快照(basename → 正/负条目)。
733
- * 投影式单一 SSOT:不维护第二份可变索引映像(防双轨漂移);fileCache 已被
734
- * reconstructAll 修剪掉消失文件(修剪时置 indexDirty),下次过窗写时快照清除
735
- * 磁盘上的陈旧条目。
736
- */
737
- private projectIndexEntries;
738
- /**
739
- * [perf] byId 索引直查 light record(单文件 stat 校验,不触发 getFullRecord 的
740
- * 全量重建)。idToFile 未热(进程重启后尚未扫描过)时返回 undefined,调用方
741
- * 自行兜底全目录扫描——用于把「跨重启后每条 message 一次 collectRecords 全扫」
742
- * 降为 O(1) 索引命中。
743
- */
744
- findLightById(id: string): SubagentRecord | undefined;
745
- /**
746
- * [perf] 单 record 详情懒加载:内存 running record 投影全量;磁盘 record 全量重建
747
- * (reconstructFromFile)并套用同一 sidecar 状态矩阵。结果缓存在 FileCacheEntry.full,
748
- * stat 戳变化时随 light 一起失效。列表 collectRecords 返回 light(无 eventLog/
749
- * result/turns 等重数据),详情面板/工具 list 按需调本方法补齐。
750
- *
751
- * 返回 undefined:id 不存在(内存与磁盘均无)。reconstructFromFile 失败(无
752
- * assistant message 等)→ 返回 light(无详情可补,缓存哨兵防重复全文重读)。
753
- */
754
- getFullRecord(id: string): SubagentRecord | undefined;
755
- /** alive 探活刷新(scanFile 缓存命中与 reconstructAll 快路径共用):
756
- * 分支 3 的 running + alive 条目每扫重查 pid(结果不落盘,进程死亡无 IO),
757
- * 保留旧实现「每次 collectRecords 重新 isProcessAlive」的语义。 */
758
- private static refreshAlive;
759
- /** identity 基底 + sidecar 状态矩阵 → 缓存条目(索引命中与探测重建两分支的公共装配点)。 */
760
- private static buildFileCacheEntry;
761
- /** identity 基底(头部 light 或全量 recon)+ 四分支 sidecar 状态矩阵 → SubagentRecord。 */
762
- private static buildRecord;
763
- /** 排序比较器:status priority(running<failed<cancelled<done)+ startedAt desc。 */
764
- private static compareRecords;
765
- /** FR-8: 同步读取所有 manifest 记录(封装 ManifestStore.listAllSync,消除反射访问)。 */
766
- private readManifestsSync;
767
- /** FR-8: ManifestRecord → SubagentRecord(manifest 源投影)。
768
- * task/slug/model 从 manifest 真实值投影(配合 writeManifest 补字段),缺失兜底空串。
769
- * status 越界(mapManifestStatus 返回 null)时返回 null,由 collectRecords 跳过。 */
770
- private static manifestToSubagent;
771
- /** ExecutionRecord → SubagentRecord(内存源投影)。 */
772
- private static recordToSubagent;
773
- }
774
-
775
- /** Pi extension_ui_request 的方法枚举(dialog + fire-and-forget 两类)。
776
- * dialog 类:select/confirm/input/editor(占输入焦点,等响应)。
777
- * fire-and-forget 类:notify/setStatus/setWidget/setTitle/set_editor_text(纯展示/写入)。
778
- * (string & {}) 兜底:Pi 未来新增 method 或未知 method 走字符串字面量类型。 */
779
- type UiMethod = "select" | "confirm" | "input" | "editor" | "notify" | "setStatus" | "setWidget" | "setTitle" | "set_editor_text" | (string & {});
780
- /** UI 请求(session-runner 构造后传给 handler)。
781
- *
782
- * method 是判别字段,决定排队策略(dialog 排队)和业务路由(channel 分发)。
783
- * method 特定字段按 method 可选出现(与 ExtensionUiRequest 1:1,由 session-runner 从
784
- * ExtensionUiRequest 平铺构造)。channel/channelPayload 由 parseChannel 填充。
785
- *
786
- * 契约来源:.fix-plans/00-master-summary.md §二 2.2。 */
787
- interface UiRequest {
788
- /** Pi rpc-types.ts 的 method(select/confirm/input/editor 为 dialog 类)。 */
789
- method: UiMethod;
790
- /** 请求 id(从 extension_ui_request envelope 顶层提取,用于 response 关联)。 */
791
- id: string;
792
- title?: string;
793
- options?: string[];
794
- message?: string;
795
- placeholder?: string;
796
- prefill?: string;
797
- notifyType?: string;
798
- statusKey?: string;
799
- statusText?: string | undefined;
800
- widgetKey?: string;
801
- widgetLines?: string[] | undefined;
802
- widgetPlacement?: "aboveEditor" | "belowEditor";
803
- text?: string;
804
- timeout?: number;
805
- /** channel 名(从 method 对应字段的 NUL 前缀解析)。
806
- * select → 从 title 解析;setWidget → 从 widgetLines[0] 解析;其他 → undefined。
807
- * 已知值:"ask_user"(select)、"gui_widget"(setWidget)。handler 按 channel 分发。 */
808
- channel?: string;
809
- /** channel 解析后的结构化 payload(已 JSON.parse)。
810
- * ask_user: {questions, allowCancel};gui_widget: {component};无 channel: undefined。 */
811
- channelPayload?: unknown;
812
- /** 内部元数据字段:发起该 UI 请求的子进程 pid(由 session-runner.handleUiRequest 从
813
- * child.pid 填入)。L2 队列据此关联 rejectChildDialogs(child close 时批量 reject)。
814
- * 下划线前缀表示内部字段,非 Pi 协议字段,不参与 stdin 回写。 */
815
- _childPid?: number;
816
- }
817
- /** UI 响应(handler 返回,session-runner 按 shape 回写 stdin)。
818
- * - {value}: select/input/editor 的答案
819
- * - {confirmed}: confirm 的答案
820
- * - {cancelled}: 取消(child close / handler 抛错 / 用户取消)
821
- * - {ack}: fire-and-forget(当前不透传到 TUI,留作协议完整) */
822
- type UiResponse = {
823
- value: string;
824
- } | {
825
- confirmed: boolean;
826
- } | {
827
- cancelled: true;
828
- } | {
829
- ack: true;
830
- };
831
- /** UI 请求 handler 签名(单函数,按 req.method 内部路由)。
832
- * 实现方负责:channel 业务路由(ask_user → AskUserComponent)+ 默认转发(ctx.ui.*)。
833
- * 抛错由调用方(DialogGlobalQueue / session-runner)兜底为 {cancelled:true}。 */
834
- type UiRequestHandler = (req: UiRequest) => Promise<UiResponse>;
835
- /** 入队项的 child 引用形状(只取 pid 用于 rejectChildDialogs 匹配)。 */
836
- interface DialogChildRef {
837
- pid: number;
838
- }
839
- /** enqueue 的可选项。child 用于 rejectChildDialogs 关联(child close 时批量 reject)。 */
840
- interface EnqueueOptions {
841
- child?: DialogChildRef;
842
- }
843
- /**
844
- * L2 跨子进程全局 dialog 串行队列(进程单例)。
845
- *
846
- * 用法(createUiRequestHandlerForMode 返回的总 handler 内):
847
- * ```ts
848
- * const dialogQueue = new DialogGlobalQueue();
849
- * return async (req: UiRequest) => {
850
- * // 调用方负责判断:dialog 入队,fire-and-forget 直接调 realHandler
851
- * if (isDialogMethod(req.method)) return dialogQueue.enqueue(req, realHandler);
852
- * return realHandler(req);
853
- * };
854
- * ```
855
- *
856
- * 语义保证:
857
- * - FIFO 串行:前一个 handler settle 后才处理下一个
858
- * - SR-4:rejectChildDialogs(child) 把该 child 的 pending 全部 resolve 为 {cancelled:true}
859
- * - handler 抛错兜底:catch → {cancelled:true} → 继续下一个(队列不卡死)
860
- * - 超时上界(LC-3/T2⑦):每个 dialog 项必有上界——req.timeout 显式传值优先,
861
- * 未传挂 DEFAULT_DIALOG_TIMEOUT_MS(30min,裁决值);到点 settle {cancelled:true}
862
- * 并 warn(恢复指引见 dialogTimeoutLogMessage),L2 processing 释放、队列继续推进。
863
- * 「等用户无限久」改为默认有界是有意的行为变更。
864
- * - 调用方约定只对 dialog 类调 enqueue;fire-and-forget 由调用方直接调 handler 不入队
865
- *(enqueue 内仍防御性兼容 fire-and-forget,但不保证行为)
866
- *
867
- * 线程模型:纯 Promise + 微任务驱动,无锁。Node 单线程 event loop 保证队列状态一致。
868
- *
869
- * 单 session 假设(M-2,与 index.ts lastSessionId 同源):本队列是进程级单例(实例挂在
870
- * globalThis[Symbol.for("@zhushanwen/pi-subagents.dialogQueue")],见 getOrCreateDialogQueue)。
871
- * rejectAll() 清空所有 pending dialog——无 per-session 隔离。Pi 当前架构保证单进程
872
- * 单 session 串行(同进程不会并发多个 session),故 session_shutdown 调 rejectAll() 只会清掉
873
- * 当前 session 的 pending。若未来 Pi 支持同进程多 session 并发,session A 退出会误清 session B
874
- * 的 pending dialog——届时需改为 per-session 隔离(入队项 QueueItem 带 sessionId,rejectAll
875
- * 改 rejectAllForSession(sessionId),session_shutdown 只清当前 session)。
876
- */
877
- declare class DialogGlobalQueue {
878
- /** 等待处理的队列(FIFO)。正在处理的项从 queue shift 出后由 current 持有。 */
879
- private queue;
880
- /** 正在处理的项(handler 已调、未 settle)。用于 rejectChildDialogs 取消占位中的 dialog。 */
881
- private current;
882
- private processing;
883
- /**
884
- * 入队一个 UI 请求,返回 Promise<UiResponse>。
885
- *
886
- * 调用方约定:只对 dialog 类(isDialogMethod===true)调 enqueue。fire-and-forget 由
887
- * 调用方(ui-request-handler-factory.ts)在 enqueue 前判 isDialogMethod 后直接调 handler,
888
- * 不经过本队列。enqueue 内仍防御性兼容 fire-and-forget(万一调用方未判):直接调 handler 返回,
889
- * 不入队串行,但调用方不应依赖此防御行为。
890
- *
891
- * dialog 项处理(TC-E4 case 1):进队列 FIFO 串行,等前一个 settle 后才调 handler
892
- *(争输入焦点,防并发弹窗)。
893
- *
894
- * handler 抛错兜底:catch → 回 {cancelled:true}(dialog 路径,队列不卡死)。
895
- * SR-4:opts.child 用于 rejectChildDialogs 关联(dialog 项会被批量 reject,含 current)。
896
- *
897
- * @param req UI 请求(约定只传 dialog 类;fire-and-forget 防御性兼容)
898
- * @param handler 真正执行请求的 handler(TUI/GUI 模式分流后的 realHandler)
899
- * @param opts 可选 child 引用(用于 rejectChildDialogs 关联)
900
- * @returns handler 的响应;dialog 抛错时回 {cancelled:true};child close 时回 {cancelled:true}
901
- */
902
- enqueue(req: UiRequest, handler: UiRequestHandler, opts?: EnqueueOptions): Promise<UiResponse>;
903
- /**
904
- * settle 一个 item(幂等)。handler 完成 / rejectChildDialogs / rejectAll / 超时 timer
905
- * 都通过本方法,settled 标志保证只 settle 一次(防竞争)。
906
- *
907
- * #19 单一推进点:本方法 settle Promise + 清状态后,**唯一**调 processNext 推进队列。
908
- * processNext 尾部不再调 processNext(旧代码双重推进,虽靠 processing 标志幂等,但语义混乱)。
909
- * 为什么推进必须在 settleItem 而非 processNext 尾部:rejectChildDialogs 取消一个永不 settle
910
- * 的 current(handler 等用户输入卡死)时,processNext 的 `await item.handler` 永不 resume,
911
- * 尾部不会执行;只有 settleItem 里的 processNext 才能打破死锁,推进下一个。
912
- *
913
- * [A2-2] 超时 timer 清理也统一收口在这里:任何路径抢先 settle(reject/rejectAll/超时
914
- * 自身)都必须撤下 armed timer——handler 永挂时 processNext 内联的 clearTimeout 不可达,
915
- * 不在这里清则 timer 到期触发虚假「dialog timed out」warn 且句柄滞留至超时点。
916
- */
917
- private settleItem;
918
- /**
919
- * SR-4:把指定 child 的所有 pending dialog resolve 为 {cancelled:true}。
920
- *
921
- * 触发场景:子进程 close(用户取消 / crash / 超时 kill)时,其 pending dialog 的 handler
922
- * 可能永不 settle(等用户输入),导致 Promise 永挂 + 内存泄漏。本方法批量清理。
923
- *
924
- * 处理范围(TC-E4 case 2):
925
- * - 正在处理中(current)的该 child 项:settle {cancelled:true},解阻塞队列推进下一个
926
- * (关键:handler 可能永不 settle,必须由这里打破死锁)
927
- * - 队列中等待处理的该 child 项:settle {cancelled:true} 并移除
928
- *
929
- * 不影响其他 child 的 pending dialog(TC-E4 case 2 子测试 2)。
841
+ * [v2 D3] mainSessionFile = 覆写 merge 数据源(主 session 每 id 末条 entry,与 E1
842
+ * scanLastRecordEntries 同款通路):崩溃前的批域标记(collectMode/batchFinalized)
843
+ * 与轮终 result/model 只活在主文件 entry——重建矩阵(buildRecord)的数据源
844
+ * (sidecar/子文件 identity)不含它们,覆写前不 merge 就会被抹掉(v2 §2.2 断链 2:
845
+ * E1 候选集恒空的真根因)。缺省(undefined)时 merge 无源,行为与旧版一致。
846
+ * 参数为追加式第二参(rootSessionFilter 保持首参):既有调用面只传过滤参。
847
+ *
848
+ * 防重:orphanJudged 实例级缓存(resumable 形态无 sidecar 锚,同进程重复调用跳过;
849
+ * 终态形态双重防护 = sidecar + 缓存)。调用方:index.ts session_start 恢复段(一次)。
930
850
  */
931
- rejectChildDialogs(child: DialogChildRef): void;
851
+ recoverOrphanRecords(rootSessionFilter?: string, mainSessionFile?: string): void;
932
852
  /**
933
- * 处理队列下一项(FIFO)。
934
- *
935
- * processing 标志保证串行:handler 运行期间 processing=true,新的 processNext 调用直接返回;
936
- * handler settle 后由 settleItem 清 processing=false 并推进下一项(#19 单一推进点)。
937
- *
938
- * handler 抛错兜底(TC-E4 case 3):catch → settle {cancelled:true} → 继续。
939
- * 不能让一个失败卡死队列(processing 永远 true)。
853
+ * 单孤儿 record 的终态判定与落 entry(residual-fixes §5.2 三判据 + chat 分流)。
854
+ * 防重锚(orphanJudged 标记)已由调用方完成。
940
855
  *
941
- * LC-3/T2⑦ 超时上界:`await item.handler` 原本无上界——host UI promise 挂死或用户
942
- * 永不回答时 processing 恒 true(全局 dialog 死锁)。现在每项挂队列级 timer:
943
- * req.timeout(请求方显式传值)优先,未传/非法挂 DEFAULT_DIALOG_TIMEOUT_MS。
944
- * 到点 settle {cancelled:true}(完整错误消息落父进程日志,含恢复指引与等待时长),
945
- * settleItem 的 settled 标志保证与 handler 完成 / rejectChildDialogs 三方竞态下
946
- * 恰 settle 一次。timer 回调闭包捕获 item(非读 this.current):迟到触发时
947
- * settled 标志已置位,直接 noop,不误伤后继项。
856
+ * [v2 D3] 覆写前 merge(lastEntry = session 同 id 末条 entry 重建,调用方构建):
857
+ * 覆写是状态迁移不是信息重建,迁移不应丢末条既有信息。三个落 entry 分支(chatMode
858
+ * 分流 / IO 保守 / 终态覆写)统一基于 merge 后的 rec,同款口径。
948
859
  */
949
- private processNext;
860
+ private finalizeOrphanRecord;
861
+ /** [v2 D3] 孤儿覆写 merge 字段集:末条 entry 的批域标记 + 轮终正文/模型,仅补 rec 侧
862
+ * undefined/空值(model 的空值形态是 ""——light 重建无 model_change entry 时起步
863
+ * 空串),不覆盖已有值。merge 后写 entry 经 reportSubagentRecord →
864
+ * toSubagentRecordEntry 序列化,undefined 字段自然缺省(不引入显式 null)。 */
865
+ private static mergeOrphanLastEntry;
950
866
  /**
951
- * #10:把所有 pending dialog(queue + current)全部 settle {cancelled:true},
952
- * 并清空 queue/current/processing 状态。session_shutdown 调用,保证不留永挂 Promise。
953
- *
954
- * 约定签名:rejectAll(): void(无参,返 void)。Group C 的 index.ts session_shutdown 依赖此契约。
955
- *
956
- * 幂等:依赖 settleItem 的 settled 标志——重复调用只会对已 settled 项 noop。
957
- * 顺序敏感(#19 推进点在 settleItem):必须先清空 queue 数组再 settle current,
958
- * 否则 settleItem(current) 同步触发的 processNext 会从旧 queue 抢占下一项作为新 current,
959
- * 避开本方法的 cancel 语义。清空后 processNext 看到空队列直接返回,新 current 不会被抢占。
867
+ * [E2E 实测缺口] entry-born 孤儿恢复:register entry 已落主 session、但子 session 文件
868
+ * 从未创建(父进程死在 spawn 窗口期——register 写点与子进程首笔写入之间的窗口;外部
869
+ * 删除子文件的已知边界同形)。目录扫描(reconstructAll)看不见这类 record(无文件即
870
+ * 无扫描集),recoverOrphanRecords 判不到,侧栏(runtime entry 扫描源)永久 spinner。
960
871
  *
961
- * session 假设(M-2):见类注释。本方法清空所有 pending 不分 session——依赖 Pi 单进程
962
- * session 串行保证。session_shutdown handler(index.ts)调用本方法时,进程内只会有当前
963
- * session pending dialog。多 session 并发场景的迁移策略(rejectAllForSession)见类注释。
872
+ * 判定:读主 session 的 subagent-record entry,取每 id 末条;末条 status=running
873
+ * 无子文件锚(不在 reconstructAll 结果中)且不在内存活 record(防误杀刚 register 的
874
+ * 在途 spawn)→ 按无文件判据收敛:chatMode=true resumable(分流语义一致);否则
875
+ * closed+gc+error(子文件由子进程创建,无文件 = 子进程从未开跑,error 方向安全)。
876
+ * 调用点:initSession 的 recoverOrphanRecords 之后(session_start,内存恒空)。
964
877
  */
965
- rejectAll(): void;
966
- /** 清空队列状态(仅在 rejectAll 之后调用)。pending Promise 必须先由 rejectAll settle。
967
- * 不 settle Promise 的纯状态重置——单独调用会导致 Promise 永挂(footgun),故设为 private。
968
- * 外部调用方应使用 rejectAll()(它 settle 所有 pending + 重置状态,是原子操作)。 */
969
- private resetState;
970
- /** 当前队列长度(测试/诊断用)。含等待处理项(不含 current)。 */
971
- get size(): number;
972
- }
973
-
974
- /**
975
- * [M-1] maxTurns → watchdog 毫秒换算(纯函数,可导出复用)。
976
- *
977
- * **换算语义(floor 文档化)**:`max(30min, maxTurns × 5min)`——按 maxTurns 线性估算,
978
- * 带 30 分钟下限(floor)。maxTurns 换算结果低于 30 分钟时(含 ≤6 的整数与小数,
979
- * 如 0.5)一律钳到 30 分钟:单 turn 约 5 分钟是经验值(复杂 tool + 长 LLM 响应约
980
- * 3-4 分钟,留 1-2 分钟余量),maxTurns 过小时不设 floor 会把 watchdog 紧到误杀。
981
- * - maxTurns=2 → 30min(floor 生效,非 2×5=10min——zsw 曾自实现无 floor 版本致该
982
- * 配置被 10min 误杀,见 sink 设计 §2.1 例 1;两宿主统一消费本函数即同语义)
983
- * - maxTurns=6 → 30min(恰为 floor 临界)
984
- * - maxTurns=20 → 100 分钟
985
- * - maxTurns=100 → 500 分钟(8 小时+,覆盖全量重构)
986
- *
987
- * 旧实现固定 30 分钟(SPAWN_WATCHDOG_MS),与 maxTurns 无关:maxTurns=100 的长任务
988
- * (全量重构/大规模迁移)正常需数小时,30 分钟到达即被误杀,limiter 机制形同虚设。
989
- *
990
- * [预算语义对齐 2026-08] maxTurns 未传/<=0 → 不挂 watchdog(不限)的挂载判定**不归本
991
- * 函数**——本函数只做换算,挂载判定单一入口是 resolveSpawnWatchdogMs(未传时走
992
- * SPAWN_WATCHDOG_ENV 兑底,显式 <=0 = 显式不限压过 env)。用户须知风险:watchdog 防
993
- * 的是 pi 子进程 hang 泄漏(卡死在单个 tool 内 turn_end 永不触发,limiter 失效),
994
- * 默认关闭意味着无 maxTurns 的 spawn 若 hang 将永不自动回收——须用 SPAWN_WATCHDOG_ENV
995
- * 显式兑底。
996
- *
997
- * [MF-4] 同时是 agent_end keep-alive 的「有活跃后代」等待超时(不 kill 分支),
998
- * 替代旧固定 2h(WAIT_DESCENDANT_TIMEOUT_MS,已删除)——wave 开发 >2h 不被误杀。
999
- * [export] 测试可观测(run-spawn-edges MF-4 用例断言 keep-alive 等待超时 = 动态值;
1000
- * max-turns-to-watchdog-ms.test.ts 锚定 floor/边界换算)。
1001
- *
1002
- * @param maxTurns 调用方指定的 turn 上限;调用方保证 > 0(否则走 resolveSpawnWatchdogMs)
1003
- */
1004
- declare function maxTurnsToWatchdogMs(maxTurns: number): number;
1005
- /**
1006
- * kill 所有未退出的 spawned 子进程(dispose 兜底用)。
1007
- *
1008
- * [R1 D6③] 编排扩容:先触发 engine registry 各已实例化引擎的 dispose(常驻资源
1009
- * 归引擎所有,见 EnginePort.dispose / registry.disposeEngines),再杀 per-record
1010
- * children——顺序不可反(D6①:SIGTERM 先发会导致引擎侧 close 帧必丢)。dispose
1011
- * 触发不等待:本函数保持同步契约(宿主调用点零改动,函数签名与导出名不变),
1012
- * 引擎 dispose 的同步面(fire close 帧 + 同步 SIGTERM)由引擎实现保证,异步
1013
- * promise 段(grace→SIGKILL)的 rejection 由 registry 侧 catch 吞掉,防
1014
- * unhandledRejection 崩宿主。
1015
- *
1016
- * [R1 D6 注释契约] spawnedChildren Map 是 per-record 一次性 spawn 模态(一任务一
1017
- * 进程,key=record.id);引擎持有的常驻进程(跨任务共享)**不进本 Map**——其生命
1018
- * 周期完全归引擎 dispose 管理(边界声明见 RunContext.onChildSpawned)。常驻进程的
1019
- * 注册/回收问题在引擎层解决(R4),此处只立 Map 模态契约。
1020
- *
1021
- * 遍历 spawnedChildren Map 的 values(),对每个「未确认死亡」的子进程发信号。
1022
- * 已退出的子进程在 close/error 事件时已从 Map 移除(按句守卫 removeChildRegistration——
1023
- * Map 当前值仍是该 child 才删,防误删 resume spawn 的新注册),故 Map 中只剩「活着的」
1024
- * 或「已被 kill 但 close 事件尚未回调的」。
1025
- *
1026
- * [T2-⑤ / LC-2] 死亡判定按 exitCode/signalCode 而非 killed 标记——killed=true 只表示
1027
- * 「发过 kill 请求」,不等于「已死」:SIGTERM 可能被无视(卡死在不可中断 native 调用),
1028
- * 旧实现按 killed 跳过会让这类进程脱离最后一次回收窗口。现规则:
1029
- * - 已确认死亡(exitCode/signalCode 任一非 null)→ 跳过(无论 killed 与否);
1030
- * - killed 但未确认死亡(SIGTERM 已发、进程仍在)→ 直接升级 SIGKILL(dispose 是
1031
- * 最后兜底,没有 30s 升级窗口可等——killAllSpawnedChildren 保持快速返回契约);
1032
- * - 未 killed 且未确认死亡 → 发调用方指定 signal。
1033
- *
1034
- * 用于 SubagentService.dispose(进程退出路径):覆盖 sync 子进程(controller 为 undefined,
1035
- * abortRunningControllers 跳过它们)。background 子进程此时已被 abortRunningControllers 经
1036
- * controller.abort 路径 kill,本函数对它们的再处理是 SIGKILL 升级检查(T2-⑤ 语义),
1037
- * 对已死句柄 child.kill 返回 false 无害。
1038
- *
1039
- * 不 await 子进程退出(dispose 要快速返回)。
1040
- *
1041
- * @returns 被 kill 的子进程数(诊断用)
1042
- */
1043
- declare function killAllSpawnedChildren(signal?: NodeJS.Signals): number;
1044
- /** SessionRunner 的依赖注入容器(由 Runtime 提供,解耦 Core 与 Pi SDK 实例)。 */
1045
- interface SessionRunnerContext {
1046
- /** 进程当前工作目录(作为 spawn 子进程的 cwd 基准)。 */
1047
- cwd: string;
1048
- /** agent 配置目录(由 Pi 核心 getAgentDir() 决定,默认 ~/.pi/agent)。 */
1049
- agentDir: string;
1050
- /** 额外 skill 目录(ADR-031 废弃 discovery.json 后固定为空数组)。供子进程 --skill 注入。 */
1051
- skillDirs: string[];
1052
- /** 主 agent cwd(fork sessionDir 编码用)。fork 未开启时等于 cwd。 */
1053
- mainCwd: string;
1054
- /** 主 agent session 文件路径(fork 源)。fork 未开启时 undefined。 */
1055
- mainSessionFile?: string;
878
+ recoverEntryOnlyOrphans(mainSessionFile: string | undefined, rootSessionFilter?: string): void;
1056
879
  /**
1057
- * worktree 子进程 pid 就绪回调(first header 时触发)。
1058
- * Runtime 层接线为 WorktreeManager.registerPid,用于注册表补全 pid。
1059
- * 解耦 Core 与 Runtime——session-runner 不直接依赖 WorktreeManager。
1060
- * [D5a] 返回 Promise(注册表 pid 补全走跨进程锁内 RMW);实现方保证不 reject
1061
- * (WorktreeRegistry.mutate 内部降级兜底),本侧 fire-and-forget 安全。
880
+ * entry-born 孤儿候选判定(recoverEntryOnlyOrphans 的守卫链拆出):末条 running、
881
+ * root session 匹配、无子文件锚、不在内存活 record(防误杀在途 spawn)、未判过。
1062
882
  */
1063
- onWorktreePid?: (branch: string, pid: number, sessionFile?: string) => void | Promise<void>;
883
+ private isEntryOrphanCandidate;
884
+ /** entry-born 孤儿按无文件判据收敛落 entry:chatMode → resumable(分流语义一致);
885
+ * 否则 closed+gc+error(子文件由子进程创建,无文件 = 子进程从未开跑,error 方向安全)。 */
886
+ private finalizeEntryOnlyOrphan;
1064
887
  /**
1065
- * UI 请求处理回调。子进程发 extension_ui_request 时调用。
1066
- *
1067
- * 入参 UiRequest(method + channel/channelPayload + method 特定字段),
1068
- * 返回 UiResponse({value}/{confirmed}/{cancelled}/{ack})。
1069
- * 实现方按 req.channel 分发业务路由(ask_user AskUserComponent)+
1070
- * 默认转发(ctx.ui.*),收到用户回答后 resolve。
1071
- *
1072
- * 未设置时不再静默忽略——console.warn 兜底(FR-9 可观测性),
1073
- * W3 接入 SubagentService.notifyMissingHandler 的 appendEntry。
888
+ * [E1/U5] sync 批崩溃恢复扫描:主 session 文件「每 id 末条 subagent-record entry」
889
+ * (collectLastRecordEntries + rebuildEntryRecord 组合通路,设计 §3.1.3「标记读取
890
+ * 通路」——batchFinalized 落标 entry 写主 session 文件,本扫描同文件域才可见;禁走
891
+ * collectRecords light 路径,它只读子文件 identity 头+sidecar,主 session 落标
892
+ * entry 不可见)。返回每 id 末条重建的完整 record(含 collectMode/batchFinalized /
893
+ * 终态五字段,损坏 entry 跳过);调用方(service.recoverSyncCollectBatch 的 E1 过滤、
894
+ * recoverOrphanRecords 的覆写 merge)自行取舍。主文件不可读(含新 session 未 flush
895
+ * ENOENT)→ 空数组静默。
1074
896
  */
1075
- uiRequestHandler?: UiRequestHandler;
897
+ scanLastRecordEntries(mainSessionFile: string | undefined): SubagentRecord[];
898
+ /** 订阅变更。返回取消订阅函数。 */
899
+ onChange(listener: ChangeListener): () => void;
900
+ /** 触发所有监听器(TUI widget/list requestRender)。dispose 后短路。
901
+ * [perf] 不清空磁盘缓存:per-file stat 戳自校验(任何磁盘写入改变戳 → 单文件重建),
902
+ * 内存事件(register/archive)不改变磁盘文件——旧实现整体失效是全量重扫的根因。 */
903
+ notifyChange(): void;
904
+ /** session 结束清理。 */
905
+ dispose(): void;
1076
906
  /**
1077
- * L2 跨子进程全局 dialog 串行队列(进程单例,由 SubagentService 注入)。
907
+ * /resume /fork /new 后复活(dispose 的逆操作)。
1078
908
  *
1079
- * SR-4:child close 时调 rejectChildDialogs 清理该 child 在 L2 的 pending dialog,
1080
- * Promise 永挂(handler 等用户输入永不 settle)导致队列死锁(processing 永远 true,
1081
- * 其他子进程的 dialog 永久阻塞)。未注入(旧调用方/测试)时 onclose 只清 L1。
909
+ * [PS-10/T6④] 同步复位 orphanJudged 防重缓存:resumable 形态(IO-error 保守分支 /
910
+ * chatMode 分流)没有 .finalized sidecar 锚,重判资格完全由本缓存承载——dispose
911
+ * clear(session 结束),但 revive 此前不复位,导致「同进程内曾经的 IO 失败记录
912
+ * 永久停留 resumable」,与本文件 recoverOrphanRecords 注释承诺的「IO 恢复后重开可重判」
913
+ * 不符。/new 复活正是「重开」语义:IO 已恢复的记录下次 recoverOrphanRecords 重新判定
914
+ * 收敛终态;仍不可读的记录重判再落一次 resumable entry(幂等,末条语义不变)。
1082
915
  */
1083
- dialogQueue?: DialogGlobalQueue;
1084
- /** 主进程运行模式(W4 守卫:headless 不注入 ask_user RPC 提示词)。 */
1085
- mode?: ExtensionMode;
1086
- /** 所属根 session ID(跨进程身份贯穿用)。子进程的 record.rootSessionId 全指向真 ROOT,
1087
- * 使主进程 /subagents 能看到完整递归树。runSpawn 无条件注入为子进程 env(设计 recursive-subagent-visibility.md)。 */
1088
- sessionRootId: string;
1089
- /** [MF-3] 所属根进程 cwd(跨进程落盘目录编码键)。根进程=自身 cwd;worktree 模式下子进程
1090
- * mainCwd=checkout 路径,rootCwd 贯穿真 ROOT——session 文件落盘统一用 ROOT cwd 编码,
1091
- * 主进程磁盘重建才能看到全树(设计 recursive-subagent-visibility.md)。 */
1092
- rootCwd: string;
1093
- /**
1094
- * [V2 模块 3] chatMode 本轮完成通知挂载点。
916
+ revive(): void;
917
+ /**
918
+ * 四分支 sidecar 矩阵重建([perf] light 版)。
1095
919
  *
1096
- * V2 决策:chatMode 进程长驻(agent_end 不 kill),「本轮完成」的真空闲边界是
1097
- * `agent_settled`(agent_end 之后、post-run 完成后 emit,见 pi `agent-session.js`
1098
- * `_runAgentPrompt` finally 块),而非 agent_endagent_end post-run 可能仍在跑)。
1099
- * session-runner agent_settled 时调本回调,调用方(subagent-service)注入
1100
- * notifyComplete 通知父 agent。
920
+ * 优先级:
921
+ * 1. .cancelled closed(closedReason=cancelled)
922
+ * 2. .finalized closedclosedReason=sidecar 内容 reason;空/旧格式 → disconnected)
923
+ * 3. .alive + pid 存活 + 未超软超时 → running, externalInstance=true
924
+ * 4. 兜底(无 marker、pid 死、超时)→ running(v4 B-1 可续聊语义)
1101
925
  *
1102
- * **本步只定义挂载点,不接线**:subagent-service 未改,回调未注入 = no-op。
1103
- * notify 端到端 + runSpawn resolve 语义重构留 Step 4(与统一投递 + subagent-service
1104
- * 一起系统处理)。非 chatMode 路径不触发 agent_settled handler,本字段无影响。
926
+ * [perf]:逐文件 scanFile(stat 戳校验 + 头部 identity 轻量重建)。命中缓存的
927
+ * 文件零文件读取;变化的文件只重建自身,其余 N-1 个复用缓存。
1105
928
  *
1106
- * @param record 当前 ExecutionRecord(chatMode、已完成本轮)
929
+ * session 隔离:rootSessionFilter 非空时,只保留 rootSessionId 匹配的 record。
930
+ * rootSessionId 缺失(旧文件,未带身份字段)一律排除(无法判定归属)。
1107
931
  */
1108
- onRoundSettled?: (record: ExecutionRecord) => void;
1109
- }
1110
- /**
1111
- * resume spawn 选项——重开已结束的 session 文件继续对话(M1 基建)。
1112
- *
1113
- * resume 时 pi 子进程用 `--session <sessionFile> --mode rpc` 续写原文件(探针 P-1/P-8
1114
- * 实测:路径不变、entry 续写、上下文保留)。runSpawn 收到此参数后:
1115
- * - buildSpawnArgs 追加 `--session <sessionFile>`
1116
- * - record.sessionFile 提前设为 resume.sessionFile(handshake 只验证 spawn 成功,不覆盖)
1117
- * - model/thinkingLevel 优先用此处的值(防多轮对话模型漂移,探针 P-10),否则回退 opts.resolved
1118
- *
1119
- * 注意:M1 只暴露能力,messageHandler(M2)才会真正调用。
1120
- */
1121
- interface SpawnResumeOpts {
1122
- /** resume 目标 session 文件绝对路径(pi `--session` 参数值)。 */
1123
- sessionFile: string;
932
+ private reconstructAll;
1124
933
  /**
1125
- * resume 时覆盖的 model(`"provider/id"` 格式,防漂移,探针 P-10 证明必须传);
1126
- * 不传则回退 opts.resolved
934
+ * 扫描单文件:stat 戳(jsonl + 3 sidecar)校验,全同 → 复用缓存(零文件读取,
935
+ * 含负缓存直接返回 null);否则重建 light
936
+ * identity 定位两级:头部 64KB(首轮会话)→ 全文 fallback(续聊场景 identity
937
+ * append 在尾部);两级都找不到 → 写负缓存(防每轮全文重读)。
938
+ * 返回 null:文件消失/读失败/无 identity → 跳过。
1127
939
  */
1128
- model?: string;
1129
- /** resume 时覆盖的 thinkingLevel;不传则回退 opts.resolved。 */
1130
- thinkingLevel?: string;
1131
- }
1132
- declare function killRecordChildWithEscalation(recordId: string, source: string): void;
1133
-
1134
- /** chat 域轮次的身份快照(编排层 resolveIdentity 的产物形态——引擎侧透传给 launcher;
1135
- * 身份解析产物是 host 编排件,不并入任务声明 AgentCallOpts,见 ChatRoundTicket 注释)。 */
1136
- interface ChatRoundIdentity {
1137
- agent: string;
1138
- agentConfig: AgentConfig | undefined;
1139
- resolved: ResolvedModel;
1140
- }
1141
- /**
1142
- * chat 域预备轮次交接包(D2 单轨):编排层(executeViaEngine / 冷路径续轮)预建的
1143
- * record/opts/identity/host 上下文经 run 的 ctx.taskId 交接给引擎。
1144
- *
1145
- * [u-3b D6 双形态消化评估结论:双形态保留(结构性裁决,非过渡态)]
1146
- * run 的 task 形参(AgentCallOpts,任务声明)与 ticket 是两个变化轴的载体,不可合一:
1147
- * - task 形参 = 纯数据任务声明(跨引擎持久化语义,workflow 域由 SAR 直传);
1148
- * - ticket = chat 域 host 编排交接件,主体是运行期对象与 Service 内部形态——
1149
- * ① ctx: SessionRunnerContext 回调簇 / signal / priority / stream 是运行期句柄
1150
- * (port 设计 §3.3.5 删字段去向:运行期对象不入任务声明);
1151
- * ② record: ExecutionRecord 是 Service 内部 record 生命周期对象;
1152
- * ③ resume: SpawnResumeOpts 是 session-runner 私有 spawn 选项;
1153
- * ④ opts: ExecuteOptions 是 Service 内部编排形状(D6 明确保留的类型),且是
1154
- * forkFromSessionFile 的唯一 lossless 载体(该字段仅 pi chat 域消费,不入
1155
- * 合流形状——chat pi fork-from 链路 = 壳 fork-from action → ExecuteOptions
1156
- * .forkFromSessionFile → 本 ticket → runChatRound → runAndFinalize → runSpawn,
1157
- * 全程不经任务声明,由 pi-engine 测试锁定零回归)。
1158
- * 把任一类塞进 AgentCallOpts 会让 engine 契约反向耦合 execution 内部类型。故 chat
1159
- * 分支 ticket 优先消费(task 形参仅满足 port 签名),workflow 分支消费 task 形参——
1160
- * 这是「编排交接」与「任务声明」的职责分界,不是待消除的中间态。
1161
- */
1162
- interface ChatRoundTicket {
1163
- record: ExecutionRecord;
1164
- opts: ExecuteOptions;
1165
- identity: ChatRoundIdentity;
1166
- ctx: SessionRunnerContext;
1167
- signal: AbortSignal | undefined;
1168
- priority: number;
1169
- stream?: SubagentStream;
1170
- /** resume 选项(冷路径续轮):重开已 idle 的 session 续聊。undefined = 新 session。 */
1171
- resume?: SpawnResumeOpts;
1172
- }
1173
- /**
1174
- * PiEngine 委托的编排服务面——SubagentService 的结构子集(鸭子类型:生产实现是
1175
- * SubagentService 单例;测试可注入 fake,不必构造整个 Service)。
1176
- * 为什么用结构接口而非直接 import SubagentService 类型:pi-engine 只依赖它实际消费的
1177
- * 方法面,防 Service 内部演进(增删私有方法)连锁影响引擎适配层。
1178
- *
1179
- * chat 域轮次面(takeChatRound/runChatRound/resumeChatRound/reportRecordTransition)
1180
- * 声明为可选项(u-2c 聚合后形态):两处生产绑定(registration.ts / SAR)均绑
1181
- * subagentService.asEngineService(= piEngineServiceAdapter),可选面实际恒被提供——
1182
- * 并非「仅 chat 绑定的实例提供、SAR 的实例不提供」。两域分支改由 taskId 空间区分:
1183
- * chat ticket 的 key 是 record.id(编排层预建时 set),SAR 的 taskId 是独立铸造的
1184
- * `sa-<uuid>`(subprocess-agent-runner.ts),恒不在 ticket map 中 → run 的
1185
- * takeChatRound 探测恒 miss → 恒走 executeAndAwait 分支。可选面保留 optional 的意义
1186
- * 是测试可注入仅含 workflow 面的 fake;requireResumeFace / runChatTicket 的 throw
1187
- * 分支在生产绑定(asEngineService 全量提供)下不可达,仅防 fake 绑定漏面时静默
1188
- * 丢消息/丢轮次。
1189
- */
1190
- interface PiEngineService {
1191
- executeAndAwait(opts: ExecuteOptions, signal?: AbortSignal, onEvent?: (event: AgentEvent) => void, stream?: SubagentStream): Promise<AgentResult>;
1192
- getRecordForAction(id: string): ExecutionRecord;
1193
- closeSubagent(record: ExecutionRecord, force: boolean): Promise<void>;
1194
- cancel(id: string): boolean;
1195
- collectRecords(limit: number, statusFilter?: StatusFilter): SubagentRecord[];
1196
- /** chat 域轮次交接(run 的 chat 分支入口):按 taskId 取走预备包(一次性消费)。 */
1197
- takeChatRound?(taskId: string): ChatRoundTicket | undefined;
1198
- /** 执行预备的 chat 轮次(编排归 Service:pool 槽 + runSpawn + 终态迁移)。 */
1199
- runChatRound?(ticket: ChatRoundTicket): Promise<AgentResult$1>;
1200
- /** 冷路径续轮(interact message 分支的编排回调:守卫 + record 迁移 + 预备轮次 kick-off)。 */
1201
- resumeChatRound?(record: ExecutionRecord, text: string): void;
1202
- /** record 状态迁移上报(热路径投递后让 runtime 派生缓存失效 / GUI 回流)。 */
1203
- reportRecordTransition?(record: ExecutionRecord): void;
1204
- }
1205
-
1206
- /**
1207
- * 把 'pi' 引擎登记进 registry(幂等——组合根可能多次执行,如每次 session_start)。
1208
- * 工厂绑进程单例 getSubagentService:惰性求值,session_start 注入前调用 getEngine
1209
- * 只会拿到引擎实例,真正 run 时才解析服务。
1210
- */
1211
- declare function registerPiEngine(): void;
1212
-
1213
- /** provider 注册表条目的最小消费面(凭据 + 模型清单校验)。 */
1214
- interface ZcodeProviderEntry {
1215
- options?: {
1216
- apiKey?: unknown;
1217
- };
1218
- models?: Record<string, unknown>;
1219
- [k: string]: unknown;
1220
- }
1221
- /** [R4] 规范化全名 provider/model → create 参数的 per-session model 拆分(A.2 ① strict 对象)。 */
1222
- declare function splitZcodeModelRef(modelRef: string): {
1223
- providerId: string;
1224
- modelId: string;
1225
- };
1226
- declare function hasApiKey(entry: ZcodeProviderEntry): boolean;
1227
- interface ZcodeSourcePaths {
1228
- /** 桌面登录态 config(唯一凭据源)。缺省 ~/.zcode/v2/config.json。 */
1229
- v2ConfigPath?: string;
1230
- }
1231
- /**
1232
- * 短名(无 provider 前缀)解析的默认 provider(zsub DEFAULT_PROVIDER_ID 同构)。
1233
- * 导出(sink 设计 U1 模型切分四件之一):barrel re-export 供第三宿主模型路由消费,
1234
- * 实现体内聚本文件不挪。
1235
- */
1236
- declare const DEFAULT_PROVIDER_ID = "builtin:bigmodel-coding-plan";
1237
-
1238
- /** ZcodeEngine 构造依赖(全部可注入——测试不依赖真机 CLI/真凭据)。 */
1239
- interface ZcodeEngineDeps {
940
+ private scanFile;
1240
941
  /**
1241
- * 引擎数据目录(journal 分组根 <dir>/engines/zcode/shared/ stderr 日志落点)。
1242
- * 来源通道(宿主 dataDir)见 registration.ts 缺省解析。
1243
- */
1244
- engineDataDir: () => string;
1245
- /** zcode CLI 路径;缺省 ZCODE_CLI_DEFAULT_PATH。 */
1246
- cliPath?: string;
1247
- /** 源 config 路径覆盖(测试注入临时源;缺省读 ~/.zcode)。 */
1248
- sources?: ZcodeSourcePaths;
1249
- /** 版本探测执行器(probe check "version";测试注入 fake 防真实子进程)。 */
1250
- probeVersion?: (cliPath: string) => Promise<string | undefined>;
1251
- /** env 基底(测试注入;缺省 process.env——app-server env 组装经它)。 */
1252
- processEnv?: NodeJS.ProcessEnv;
1253
- }
1254
- /** zcode 引擎适配器。 */
1255
- declare class ZcodeEngine implements EnginePort {
1256
- readonly id = "zcode";
1257
- private readonly deps;
1258
- private probeCache;
1259
- private appserverRuntime;
1260
- /**
1261
- * [P0-1 U4] 引擎停机标志(dispose 置位,不重置——dispose 后首个 run 走重建路径
1262
- * 不受影响):瞬时重试判定据此排除 dispose 收割引发的崩溃形态——停机后的重试轮
1263
- * 会经 ensureAppServerRuntime 惰性重建进程(复活已停机引擎),违背 dispose 防泄漏
1264
- * 语义。
1265
- */
1266
- private disposed;
1267
- constructor(deps: ZcodeEngineDeps);
1268
- /**
1269
- * zcode 链路实际接通的能力(D3 链路口径。声明升级必须先改链路再改声明(C4 原则)。
1270
- */
1271
- capabilities(): EngineCapabilities;
1272
- /** 探针(D7):二进制存在 + 版本解析(zcode 无公开契约,版本漂移的入口信号)。 */
1273
- probe(opts?: {
1274
- force?: boolean;
1275
- }): Promise<ProbeReport>;
1276
- /** check 1:二进制存在性(isFile 才算——同名目录不是可执行入口)。 */
1277
- private probeBinaryCheck;
1278
- /** check 2:`--version` 解析(probeVersion 可注入——测试 fake 防真实子进程)。 */
1279
- private probeVersionCheck;
1280
- /** 探针失败的恢复指引(§3.3.3 终态四:版本确认命令 + 探针重跑 + 调研文档路径)。 */
1281
- private probeFailureRecovery;
1282
- /** D1 主语义:唯一通道 = app-server 常驻连接(spawn 降级链已删除)。 */
1283
- run(task: AgentCallOpts, ctx: RunContext): Promise<EngineRunResult>;
1284
- /**
1285
- * 常驻路径主编排:模型解析(v2 单源校验)→ 惰性连接 + runTurn(事件时序前移:
1286
- * text_delta 流式、终态后 message_end/turn_end)→ schema 仿真重试 → outcome/handle。
1287
- * poolKey 固定 'shared'(共享宿主 HOME,无池),onPoolResolved 在 prepare 期、
1288
- * onHandleReady 在 create 应答后(§3.4 不变量 3)。
1289
- */
1290
- private runViaAppServer;
1291
- /** pre-aborted 短路收口:合成中止 outcome + 'shared' 锚定 handle。 */
1292
- private abortedAppServerRun;
1293
- /**
1294
- * 首轮执行 + 双重试编排(常驻路径):
1295
- * - **schema 仿真重试**(既有语义):parsed 但校验失败时重试一次(强化 JSON 输出
1296
- * 指令——与 structured-output 的重试语义对齐)。
1297
- * - **瞬时失败自动重试一次**([P0-1 U4/D6]):末次 attempt 为 timeout 类(idle/
1298
- * ceiling)或连接崩溃类失败且非用户 abort → 用新会话重跑一次(attempt 本就每次
1299
- * 新建会话)。重试轮 prompt 用 basePrompt 原样重跑(失败形态非 schema),文案补
1300
- * 「已自动重试一次」句(retried 标记仅对真实发生的重试生效)。
1301
- *
1302
- * 两次重试一次封顶各自独立(D6 被否①:多次重试/指数退避不做——重跑一轮=整任务
1303
- * 重算,一次封顶)。组合序:瞬时重试在前、schema 重试在后——瞬时重试轮 parsed 且
1304
- * 校验失败时仍进 schema 重试(末次 attempt 语义,schema 重试编排保持现状不动)。
942
+ * [perf L-1] 磁盘索引查询(首扫惰性装载,miss/空索引时 get undefined = 无索引)。
943
+ * 条目戳匹配 jsonl 当前 stat → 零内容读取构造缓存条目。sidecar payload(tombstone/
944
+ * alive)是活态数据,沿用探测分支的每轮重读语义;finalized reason 静态数据仅在
945
+ * sidecar 存在时读一次(文件小,成本可忽略)。
1305
946
  *
1306
- * 重试轮是独立会话的独立 LLM 调用:token 计入 outcome.usage 总量;事件面
1307
- * text_delta 按实际流出(含失败轮——journal 记录真实流水),message_end/turn_end
1308
- * 只在最终轮终态后合成(不变量 2/5)。
947
+ * 返回 undefined = 索引未命中/戳不匹配(调用方落到原三级探测);null = 负条目命中
948
+ * (「确认无 identity」跨实例持久,零探测跳过,与内存负缓存同款形态)。
1309
949
  */
1310
- private runAppServerAttemptsWithRetry;
1311
- /** 常驻路径的 handle 合成(poolKey 固定 'shared';dbPath = 宿主 HOME 绝对路径)。 */
1312
- private appServerHandle;
950
+ private buildEntryFromIndex;
1313
951
  /**
1314
- * 单轮常驻执行:runTurn 组合面 + D3 abort + 事件前移(text_delta 实时流出;
1315
- * 终态数据经 read 兜底收口后才 resolve——不变量 1/2)。
952
+ * [perf L-1] 扫描尾索引落盘(节流):释放映像 dirty/高版本/60s 节流窗三重门
953
+ * fire-and-forget saveIndex(fileCache 全量投影)。写决策与发起在同步栈(collectRecords
954
+ * 返回后不会再有本轮写);仅写完成的回调(推进节流窗)是异步的。所有 return 路径均
955
+ * 不清 dirty——未落盘的探测成果跨轮携带,直至真正写入。
1316
956
  *
1317
- * @param opts turnTimeoutMs:显式总上界传参面(D2 内部传参点)——U4/D6 预算继承
1318
- * 向重试轮传剩余值;缺省不传(channel env→默认,首轮行为)。
1319
- * retried:瞬时重试轮标记——失败文案补「已自动重试一次」句(F-1/F-4)。
1320
- */
1321
- private attemptAppServerTurn;
1322
- /**
1323
- * killChain 后等待连接 finalize 实际完成(child 置空 + onClose 广播)再宣告链终局:
1324
- * shutdown resolve 于 `exit` 事件,而 finalize 挂 `close`(stdio 排空)——两者之间的
1325
- * 事件窗口内 conn.child 仍非 null,紧接的下一任务 request 会复用垂死进程(写入成功
1326
- * 但必败,走崩溃路径)而非触发重建。与 shutdownRuntimeAndDisposeChannel 的
1327
- * HARVEST_GRACE 同款 race 形态(close 永不到达不挂死)。超时入口的 await 链终局
1328
- * 语义(D6 重试时序依据)因此是「进程收割确认完成」而非「SIGTERM 已发出」。
1329
- */
1330
- private awaitConnFinalized;
1331
- /**
1332
- * D3 abort 链执行体(双入口分岔,P0-1 U2 参数化——设计
1333
- * timeout-zcode-turn-and-settled-watchdog.md §6 D3 v1.1):
1334
- * - **用户取消入口**(`escalateOn: "turn-settled"`,现状语义零改动;fire-and-forget——
1335
- * 与 turn promise 并行推进):stop 帧(超时 ZCODE_APPSERVER_STOP_TIMEOUT_MS)→
1336
- * grace 窗口内 turn 落定即止(不杀共享进程)→ 超窗 killChain(conn.shutdown 全序:
1337
- * SIGTERM→grace→SIGKILL)。turn 的最终落定由 attempt 主路径 await 收口,本链不
1338
- * 直接产出终态。abort 与 create 竞态(signal 先到、session 未建立):等会话建立
1339
- * (带上限)再发 stop——否则 stop 永远发不出,直接连坐杀共享进程。
1340
- * - **超时入口**(`escalateOn: "stop-outcome"`,channel 判死后由 catch await 链终局):
1341
- * turn 已 reject,对它 race 恒真不可用(v1 击穿点)——升级判据改挂在 **stop 应答
1342
- * 三态**:①成功应答 → 服务端接受停 turn,止损确认,链终止;②协议性 error 应答
1343
- * (有 error 帧即控制面活的证据,多因 runTurn finally 的 closeSession 先行关会话,
1344
- * 健康形态竞态)→ 链终止**不升级**(止损由 close 回收 + 服务端自治承担;把
1345
- * 「stop 报错」一律升级会误杀健康共享进程并连坐并发任务);③超时/写入失败/进程
1346
- * 死等连接级失败(控制面死)→ killChain 升级。判据实现依据:error 应答帧 reject
1347
- * 携带 number code(isAppServerRpcError);连接级失败是无 code 的新 Error
1348
- * (connection.request 三态 reject 形态)。返回值即止损路径(超时入口的 outcome
1349
- * 文案素材——D3 强制可观测面)。
1350
- */
1351
- private appServerAbortChain;
1352
- /**
1353
- * 惰性获取常驻运行时(D1:每引擎实例一条连接,全任务共享;连接自身的崩溃重建在
1354
- * connection 层内部完成——同一条代码路径,§3.4 不变量 4)。常驻进程不进宿主
1355
- * spawnedChildren、不调 onChildSpawned(D6——生命周期归 dispose)。进程级 --cwd
1356
- * 用引擎数据目录(连接跨任务共享的中性位置,工作区由 create 的
1357
- * workspace.workspacePath 按任务传递——D10 基线不预设任务级进程 cwd)。
1358
- * spawn 经 fs 拦截 wrapper(appserver-launcher:cli config 读取重定向为
1359
- * 「真实文件 + v2 provider 注入」——CLI 形态 app-server 在共享宿主 HOME 下的
1360
- * 唯一凭据供数通路,机制与漂移面见该文件头注)。
1361
- */
1362
- private ensureAppServerRuntime;
1363
- /**
1364
- * [R5 修复 R4 既有竞态] shutdown → 等崩溃收割实际发生 → channel 退订。killChain 在
1365
- * `exit` 事件 resolve,而连接 finalize(onClose → channel 的 failAllTurns)挂
1366
- * `close` 事件——两者之间有一个事件循环窗口:shutdown resolve 后立即退订,在途
1367
- * turn 会错过收割、挂到 turnTimeoutMs(300s)。退订前等 onClose 触发(本方法先于
1368
- * shutdown 订阅;channel 的订阅在构造期更早——其 failAllTurns 先于本 promise
1369
- * resolve 执行);ZCODE_APPSERVER_HARVEST_GRACE_MS 兜底防 `close` 永不到达时挂死。
1370
- * [P0-1 U5/D7] grace race 输掉(close 迟到/永不到达——stdio 被孙进程持有排空不
1371
- * 尽等病态形态)时,channel.dispose() 内置的 dispose 收割(failAllTurns 先于退订,
1372
- * SessionChannel.dispose)兜底在途 turn——退化终点从「挂满 turn 自身 idle/总上界
1373
- * 预算」收敛为「grace 窗口内明确失败」(设计 §3.4 退化路径闭合);race 窗口与
1374
- * awaitConnFinalized 同源同量级(ZCODE_APPSERVER_HARVEST_GRACE_MS)。正常 close
1375
- * 先到时 onClose 收割先行,dispose 收割幂等 no-op(零回归)。
1376
- */
1377
- private shutdownRuntimeAndDisposeChannel;
1378
- /**
1379
- * [R1 D6 主体] 引擎停机面:①fire 全部在途会话的 session/close 帧(不等待
1380
- * 应答——D6① 顺序规定:close 帧必须先于 SIGTERM,否则对面来不及处理即被杀)→
1381
- * ②同步 SIGTERM(conn.shutdown 调用内 killChain 前缀同步执行——同步面在返回
1382
- * Promise 前完成)→ ③grace → SIGKILL(异步面,Promise resolve 于进程退出)。
1383
- * 幂等:运行时字段取走即置空,二次调用零副作用;dispose 后首个 run 经
1384
- * ensureAppServerRuntime 自动重建(与崩溃重建同一代码路径,不变量 4)。
1385
- */
1386
- dispose(): Promise<void>;
1387
- /** 终态合成(extension-conventions 函数 80 行上限,从 run 提取):aborted / run-failed / parsed 三分支。 */
1388
- private finalizeOutcome;
1389
- /** abort 合成终态:exitCode=null(record 正常收尾,不留僵尸)。 */
1390
- private applyAbortedOutcome;
1391
- /**
1392
- * run-failed 合成终态:错误信息由 buildAppServerRunFailedMessage 产出(已含恢复
1393
- * 指引)直接透传;附带的会话 id 落 outcome.sessionId(错误规格表 -32004 行「含会话
1394
- * id」——appServerHandle 据此写 handle.sessionRef,run-failed 不再恒缺)。
1395
- */
1396
- private applyRunFailedOutcome;
1397
- /** parsed 合成终态:content/sessionId/usage 落位 + schema 校验分流 + coarse 事件。 */
1398
- private applyParsedOutcome;
1399
- /**
1400
- * D1 可选面:zcode 首期不支持 conversation(capabilities 声明)——同步拒绝、
1401
- * 不创建进程,文案给可操作建议(A11)。
1402
- */
1403
- interact(_handle: EngineHandle, _action: InteractAction): Promise<InteractResult>;
1404
- /** [U7] 模型可发现性:v2 桌面登录态聚合(带凭据 provider × models),失败安全返回清单本身可能为空。 */
1405
- listModels(): Array<{
1406
- id: string;
1407
- name?: string;
1408
- }>;
957
+ * 并发安全:节流基准只在写成功后推进,W1 在途时新一轮过窗扫描可再 dispatch W2(不做
958
+ * 进程内排队——fire-and-forget 语义保持)。安全性由 saveIndex 的 tmp 唯一性
959
+ * (pid+单调序号)保证:交错 rename 的终态必为某一次的完整快照(last-writer-wins,
960
+ * 陈旧快照胜出时下轮戳不匹配自愈),不依赖本方法串行化。
961
+ */
962
+ private flushIndexAfterScan;
1409
963
  /**
1410
- * [u-h2 D2-2] 派发同步期 model 校验:委托 resolveZcodeModelRef(与 run prepare 期
1411
- * 同一函数——canonicalRef 归一化、短名缺省 provider、凭据与清单校验单一权威,无双实现)。
1412
- * modelRef undefined = 返回引擎缺省模型 canonical 全名(ZCODE_FALLBACK_DEFAULT_MODEL,
1413
- * D2-1 ctxModel 不透传的承接面)。校验失败原样抛 ZcodePrepareError,由编排层
1414
- * (engine/model-validation.ts)包装成「引擎与模型不配套」文案。
964
+ * [perf L-1] fileCache 全量投影 索引快照(basename 正/负条目)。
965
+ * 投影式单一 SSOT:不维护第二份可变索引映像(防双轨漂移);fileCache 已被
966
+ * reconstructAll 修剪掉消失文件(修剪时置 indexDirty),下次过窗写时快照清除
967
+ * 磁盘上的陈旧条目。
1415
968
  */
1416
- validateModel(modelRef: string | undefined): {
1417
- canonicalRef: string;
1418
- };
969
+ private projectIndexEntries;
1419
970
  /**
1420
- * D6 read 三级降级:①sqlite 原生读取 ②宿主 event journal 重放(对齐点①接线:
1421
- * replayJournalToSessionView 复用 live reducer,重放等价性见 §3.3.6)→ ③outcome-only。
1422
- * sessionId 缺失(解析失败的 run 无法定位 session)跳过①级;②级依赖
1423
- * handle.journalPath(宿主 run 后回填)。dbPath:新 handle 恒绝对路径(宿主
1424
- * ~/.zcode/cli/db/db.sqlite,tier1 精确匹配白名单见方法体);旧 records(池时代)
1425
- * 的相对路径仍按 poolKey 锚定解析(read 兼容旧数据,池目录不存在时自然落②级
1426
- * journal 降级)。
1427
- */
1428
- read(handle: EngineHandle): Promise<SessionView>;
1429
- /**
1430
- * [RX2-F1] appserver 路径的非常见档位提示:thinkingLevel → thoughtLevel 恒等透传
1431
- * (F15a),全 7 档放行不拦截——但部分档位(off/minimal/medium/xhigh 等)不在部分
1432
- * 模型的合法值域内(如 GLM-5.3 仅接受 low/high/max),app-server 侧对不支持的档位
1433
- * warn-skip(会话照常但档位静默失效),调用方无从察觉。此处仅对
1434
- * COMMON_THOUGHT_LEVELS 之外的档位出声一行提示(措辞是「若不支持将被忽略/回落」的
1435
- * 或然警告,非无效断言);是否真不支持由目标模型决定,core 不做权威校验(引擎层
1436
- * 不掌握各模型值域)。
1437
- */
1438
- private warnThoughtLevelUncommon;
1439
- /**
1440
- * [F16b] ctxModel 忽略留痕:ctxModel pi 链路的第三层兜底(port.ts 契约——
1441
- * 依赖 pi resolveModel 链的引擎才消费它),zcode 自带 provider 体系与缺省模型
1442
- * (resolveZcodeModelRef:requested > ZCODE_FALLBACK_DEFAULT_MODEL),不消费
1443
- * ctxModel。「调用方给了 ctxModel 但 task.model 未显式指定」时出声一行,说明
1444
- * 实际落引擎缺省模型(含实际 model id)——防静默降档无据可查。只在「ctx 有模型
1445
- * 但被忽略」场景输出:显式 task.model 走正常解析链、ctx 本就无模型属预期缺省,
1446
- * 均不出声(避免噪音)。
1447
- */
1448
- private warnIgnoredCtxModel;
1449
- /**
1450
- * persona 拼接后的完整 prompt(personaInjection: 'prompt'——zcode flag 通道):
1451
- * appendSystemPrompt 段在前(人设/约束语境——D6 合流后 persona≡skillPath+
1452
- * appendSystemPrompt 平铺,由上游解析进 appendSystemPrompt),task 正文居中,
1453
- * schema 仿真段尾置(common/schema-emulation 公共层产出)。
1454
- */
1455
- private buildPrompt;
1456
- }
1457
- /**
1458
- * prepare 期能力拒绝的历史载体(code 进 message 前缀,调用方可程序化分流)。
1459
- * [U10① D6] execution 运行时面错误族成员:export 供宿主 instanceof 分流。
1460
- * [D3-④ 合并注] 引擎内 shape 拒绝已上提 common/capability-gate(EngineError 承载),
1461
- * 本引擎不再抛出;保留 export 维持错误族面兼容(execution-runtime-face.test 消费),
1462
- * 待波 2 收口时随 export 面清理一并裁决。
1463
- */
1464
- declare class ZcodeTaskShapeError extends Error {
1465
- readonly code: string;
1466
- constructor(code: string, message: string);
1467
- }
1468
-
1469
- /** 构造 ZcodeEngine(DI 工厂——测试/宿主注入 deps)。 */
1470
- declare function createZcodeEngine(deps: ZcodeEngineDeps): ZcodeEngine;
1471
- /**
1472
- * 把 'zcode' 引擎登记进 registry(幂等——组合根可能多次执行,registerEngine 覆盖
1473
- * 语义)。工厂惰性:登记不触发任何文件/进程探测,首次 getEngine 才建实例。
1474
- */
1475
- declare function registerZcodeEngine(engineDataDir?: () => string): void;
1476
-
1477
- /**
1478
- * 缺省引擎 id(D9:缺省引擎 = 'pi',回填期零风险默认)。
1479
- * P1 无 per-agent/调用级 engine 字段(P4 配置路由引入三层优先级),一切执行恒走缺省。
1480
- */
1481
- declare const DEFAULT_ENGINE_ID = "pi";
1482
- /**
1483
- * defaultEngine 缺省归一(单一权威源):空白 / undefined 归一到缺省引擎('pi')。
1484
- * 引擎感知检测 diff 与状态段渲染必须对同一读取结果给出同一引擎 id——若两处各自
1485
- * 内联归一,一致性只靠注释人工耦合,漂移即两处说谎;故收敛到本函数供各处调用。
1486
- * sanitize 保证透传值非空,但可能带首尾空格,故 trim 后再判。
1487
- */
1488
- declare function normalizeEngineId(engine: string | undefined): string;
1489
-
1490
- /**
1491
- * 恒在状态段 <current_subagent_engine>(设计 D6:pi 引擎也声明——AI 不需要
1492
- * 「从段缺失反推」当前引擎)。三种形态(§3.1 终态逐字基准 + 失败路径表):
1493
- * - 缺省 / pi:声明 pi + 指向上方核心段 <available_provider_models>(无冲突 bullet);
1494
- * - 非 pi 且已注册:指向下方该引擎清单段 + 「pi registry id 不适用」+ AGENTS.md
1495
- * 冲突裁决 bullet + 省略 model 用引擎默认;
1496
- * - 未注册引擎(如配置手误 "ghost"):如实显示配置值 + 警告行(派发将报
1497
- * engine_not_found,指引修 subagents/config.json)——G4 诚实降级:不静默、不伪造。
1498
- *
1499
- * 字节稳定(D7):纯字符串确定性拼装(无 localeCompare / 无随机序 / 无时间态);
1500
- * 引擎注册与否经 hasEngine 只读判断(不取实例、不触发工厂副作用),同输入恒同输出。
1501
- */
1502
- declare function buildSubagentEngineSection(defaultEngine: string | undefined): string;
1503
- /**
1504
- * 依据全局 defaultEngine 生成追加段(不含前导换行)。
1505
- *
1506
- * 规则(设计 §3.1 失败路径表 + G4 + U2 一致性审查修订):
1507
- * - defaultEngine 为 pi / 缺省 → 不注入(pi 段已由核心提供);
1508
- * - 引擎未注册 → 不注入(状态段 <current_subagent_engine> 已有警告行,避免双份);
1509
- * - 已注册且 listModels 有清单 → 注入该引擎段(渲染不变);
1510
- * - 已注册但 listModels 未实现 / 返回 null → 「与主 agent 模型体系一致」声明段
1511
- * (port 契约语义:引擎无自有 provider 枚举面,id 见上方核心段,见
1512
- * buildCoreAlignedHint);
1513
- * - 已注册但空清单 / listModels 抛异常 → 「无凭据模型」提示行段(引擎 provider
1514
- * 体系存在但当前无可用模型,见 buildEmptyModelsHint;从「静默不注入」改为如实
1515
- * 声明——空清单返回空串会让 AI 误以为没有任何引擎清单可看)。
1516
- * fail-safe:listModels 异常同样落提示行段、不向外抛(注入失败不阻塞 agent loop——
1517
- * 与 system-prompt extension 的 before_agent_start 处置一致)。
1518
- */
1519
- declare function buildEngineModelsPromptAppend(defaultEngine: string | undefined): string;
971
+ * [perf] byId 索引直查 light record(单文件 stat 校验,不触发 getFullRecord
972
+ * 全量重建)。idToFile 未热(进程重启后尚未扫描过)时返回 undefined,调用方
973
+ * 自行兜底全目录扫描——用于把「跨重启后每条 message 一次 collectRecords 全扫」
974
+ * 降为 O(1) 索引命中。
975
+ */
976
+ findLightById(id: string): SubagentRecord | undefined;
977
+ /**
978
+ * [perf] 单 record 详情懒加载:内存 running record 投影全量;磁盘 record 全量重建
979
+ * (reconstructFromFile)并套用同一 sidecar 状态矩阵。结果缓存在 FileCacheEntry.full,
980
+ * stat 戳变化时随 light 一起失效。列表 collectRecords 返回 light(无 eventLog/
981
+ * result/turns 等重数据),详情面板/工具 list 按需调本方法补齐。
982
+ *
983
+ * 返回 undefined:id 不存在(内存与磁盘均无)。reconstructFromFile 失败(无
984
+ * assistant message 等)→ 返回 light(无详情可补,缓存哨兵防重复全文重读)。
985
+ */
986
+ getFullRecord(id: string): SubagentRecord | undefined;
987
+ /** alive 探活刷新(scanFile 缓存命中与 reconstructAll 快路径共用):
988
+ * 分支 3 的 running + alive 条目每扫重查 pid(结果不落盘,进程死亡无 IO),
989
+ * 保留旧实现「每次 collectRecords 重新 isProcessAlive」的语义。 */
990
+ private static refreshAlive;
991
+ /** identity 基底 + sidecar 状态矩阵 缓存条目(索引命中与探测重建两分支的公共装配点)。 */
992
+ private static buildFileCacheEntry;
993
+ /** identity 基底(头部 light 或全量 recon)+ 四分支 sidecar 状态矩阵 → SubagentRecord。 */
994
+ private static buildRecord;
995
+ /** 排序比较器:status priority(running<failed<cancelled<done)+ startedAt desc。 */
996
+ private static compareRecords;
997
+ /** FR-8: 同步读取所有 manifest 记录(封装 ManifestStore.listAllSync,消除反射访问)。 */
998
+ private readManifestsSync;
999
+ /** FR-8: ManifestRecord → SubagentRecord(manifest 源投影)。
1000
+ * task/slug/model 从 manifest 真实值投影(配合 writeManifest 补字段),缺失兜底空串。
1001
+ * status 越界(mapManifestStatus 返回 null)时返回 null,由 collectRecords 跳过。 */
1002
+ private static manifestToSubagent;
1003
+ /** ExecutionRecord SubagentRecord(内存源投影)。 */
1004
+ private static recordToSubagent;
1005
+ }
1520
1006
 
1521
1007
  /**
1522
- * record 携带的引擎 handle 消费面(EngineHandleData 的结构子集,双端契约不变):
1523
- * journalPath 绝对路径;sessionRef dbPath 相对池目录 / 绝对路径均可。
1008
+ * chat 域轮次交接包的 core 契约基座(设计 §3.8 D2「ChatRoundTicket → HostBridge」)。
1009
+ * pi 专有扩展(identity / SessionRunnerContext / SpawnResumeOpts resume)在
1010
+ * pi-engine.ChatRoundTicket extends 本接口(W7 随包迁移;过渡期 record/opts/signal/
1011
+ * priority/stream 五字段的宿主编排语义在此单一权威)。
1524
1012
  */
1525
- interface EngineHandleView {
1526
- /** 引擎自定义定位符(zcode = { sessionId, dbPath })。 */
1527
- sessionRef: Record<string, string>;
1528
- /** journal 绝对路径(②级数据源;读前校验 engines 根前缀白名单)。 */
1529
- journalPath?: string;
1530
- /** 隔离池定位(路径布局 SSOT:resolvePoolDir 消费)。 */
1531
- poolKey: string;
1013
+ interface HostChatRoundTicket {
1014
+ record: ExecutionRecord;
1015
+ opts: ExecuteOptions;
1016
+ signal: AbortSignal | undefined;
1017
+ priority: number;
1018
+ stream?: SubagentStream;
1532
1019
  }
1533
1020
  /**
1534
- * 历史读取输入的 record 快照(消费字段级子集,不绑定 runtime 的完整
1535
- * SubagentRecord 形状——core import workspace private 类型)。
1536
- * engine / engineHandle 是不可信源(JSONL 文本派生),由 extractEngineId /
1537
- * parseEngineHandle 守卫式消费。
1021
+ * HostBridge 的服务实现面(SubagentService 的结构子集,鸭子类型——与原 pi-engine
1022
+ * PiEngineService 同一形态的协议化泛化:chat 域轮次面泛型参数化,pi 绑定 =
1023
+ * HostBridgeServiceFace<ChatRoundTicket>,见 pi-host-binding.ts re-export)。
1024
+ * 为什么用结构接口而非 import SubagentService 类型:防 Service 内部演进连锁影响
1025
+ * 契约面 + 测试可注入 fake(PiEngineService 的既有先例,语义照搬)。
1538
1026
  */
1539
- interface SubagentRecordSnapshot {
1540
- subagentId: string;
1541
- task: string;
1542
- result?: string;
1543
- error?: string;
1544
- startedAt?: number;
1545
- endedAt?: number;
1546
- /** record.engine('pi' | 'zcode' | ...,缺省 = pi 由 extractEngineId 归一)。 */
1547
- engine?: unknown;
1548
- /** record.engineHandle(parseEngineHandle 守卫消费)。 */
1549
- engineHandle?: unknown;
1550
- }
1551
- /** GUI 工具调用视图(结构兼容 shared ToolCall 的消费子集;id/时间戳为展示占位)。 */
1552
- interface HistoryToolCallView {
1553
- id: string;
1554
- toolName: string;
1555
- input: unknown;
1556
- output?: string;
1557
- details?: Record<string, unknown>;
1558
- status: "completed" | "error";
1559
- startTime: number;
1560
- endTime: number;
1561
- }
1562
- /** GUI thinking 块视图(结构兼容 shared ThinkingBlock)。 */
1563
- interface HistoryThinkingView {
1564
- id: string;
1565
- content: string;
1566
- collapsed: boolean;
1567
- }
1568
- /** GUI usage 视图(结构兼容 shared Usage)。 */
1569
- interface HistoryUsageView {
1570
- inputTokens: number;
1571
- outputTokens: number;
1572
- }
1573
- /** GUI 消息视图(结构兼容 shared Message 的消费子集——见文件头「为什么不 import shared」)。 */
1574
- interface HistoryMessage {
1575
- id: string;
1576
- role: "user" | "assistant";
1577
- content: string;
1578
- status: "complete" | "error";
1579
- toolCalls?: HistoryToolCallView[];
1580
- thinking?: HistoryThinkingView[];
1581
- usage?: HistoryUsageView;
1582
- timestamp: number;
1583
- error?: string;
1027
+ interface HostBridgeServiceFace<TTicket extends HostChatRoundTicket = HostChatRoundTicket> {
1028
+ executeAndAwait(opts: ExecuteOptions, signal?: AbortSignal, onEvent?: (event: AgentEvent) => void, stream?: SubagentStream): Promise<AgentResult>;
1029
+ getRecordForAction(id: string): ExecutionRecord;
1030
+ closeSubagent(record: ExecutionRecord, force: boolean): Promise<void>;
1031
+ cancel(id: string): boolean;
1032
+ collectRecords(limit: number, statusFilter?: StatusFilter): SubagentRecord[];
1033
+ /** chat 域轮次交接(run 的 chat 分支入口):按 taskId 取走预备包(一次性消费)。 */
1034
+ takeChatRound?(taskId: string): TTicket | undefined;
1035
+ /** 执行预备的 chat 轮次(编排归 Service:pool 槽 + runSpawn + 终态迁移)。 */
1036
+ runChatRound?(ticket: TTicket): Promise<AgentResult$1>;
1037
+ /** 冷路径续轮(interact message 分支的编排回调:守卫 + record 迁移 + kick-off)。 */
1038
+ resumeChatRound?(record: ExecutionRecord, text: string): void;
1039
+ /** record 状态迁移上报(热路径投递后让 runtime 派生缓存失效 / GUI 回流)。 */
1040
+ reportRecordTransition?(record: ExecutionRecord): void;
1584
1041
  }
1585
- /**
1586
- * engineHandle 唯一守卫(D1 双守卫收敛点)。
1587
- * 语义取收敛前 extractor 侧的严格版(两份 guard 此前已在「sessionRef 含非 string 值」
1588
- * 维度分叉:extractor 整体拒绝、history 侧逐键过滤——收敛选整体拒绝,坏形状不进
1589
- * record,读侧按缺 handle 降级 outcome-only,两侧行为面等价落点都是降级):
1590
- * - poolKey 缺失 / 非 string / 空串 → undefined(定位符不完整,读侧降③级)
1591
- * - sessionRef 非 plain object 或含非 string 值 → undefined(整体拒绝)
1592
- * - journalPath 可选 string(空串视为缺省)
1593
- */
1594
- declare function parseEngineHandle(raw: unknown): EngineHandleView | undefined;
1595
-
1596
- /**
1597
- * 非 pi record 的历史详情读取(三级降级主入口,D1 收敛后的唯一生产实现)。
1598
- *
1599
- * 降级顺序 ①→②→③ 逐级尝试,每级失败留 debug/warn 日志不抛崩溃(GUI 详情页
1600
- * 永不白屏报错,设计 A8)。engineId='pi' 返回 [](pi 的①级 = 调用方现有 JSONL
1601
- * 直读链,A1 守护)。未注册 reader 的引擎(未来)直接落③级——record 字段就够,
1602
- * 详情页至少有摘要卡。
1603
- *
1604
- * @param record record 快照(engine/engineHandle 为不可信源,内部守卫消费)
1605
- * @param dataDir xyz-agent 数据根(journal/dbPath 白名单经 paths.ts 布局 SSOT 推导)
1606
- */
1607
- declare function readSubagentHistoryMessages(record: SubagentRecordSnapshot, dataDir: string): Promise<HistoryMessage[]>;
1608
-
1609
- /**
1610
- * 从 turns[] 末尾推导当前活动行(running 时)。
1611
- *
1612
- * 优先级:最后一个未闭合 turn 的末尾 running toolCall → thinking → text → undefined
1613
- *
1614
- * 仅 status==="running" 时返回;terminal 态返回 undefined。
1615
- *
1616
- * 注意:返回的 type 联合("tool"|"text"|"thinking")是手写的,未通过类型守卫从
1617
- * AgentEvent 派生——它映射的是累积的 turn 状态(InternalToolCall._status + turn.thinking/text),
1618
- * 而非单个事件。若未来新增 turn 内容模式(如 reasoning_summary),须同步扩展本函数,
1619
- * 否则会静默返回 undefined(活动行运行中途消失)。updateFromEvent 的 switch 有 never 穷尽
1620
- * 检查,但本函数没有,依赖人工同步。
1621
- */
1622
- declare function getCurrentActivity(record: ExecutionRecord): {
1623
- type: "tool" | "text" | "thinking";
1624
- label: string;
1625
- } | undefined;
1626
- /**
1627
- * 聚合所有 turn 的 toolCalls(扁平化),并 strip InternalToolCall 的内部字段。
1628
- * 供 collectResult / schema enforcement 读,替代旧闭包 toolCalls 旁路。
1629
- *
1630
- * 返回 ToolCall[](不含 _status / startedTs)——跨边界导出形状清洁,
1631
- * 避免内部状态机字段泄漏到 AgentResult.toolCalls / 持久化层。
1632
- */
1633
- declare function getAllToolCalls(record: ExecutionRecord): ToolCall[];
1634
- /**
1635
- * 聚合所有 turn 的 toolCalls 总数(免克隆计数)。
1636
- *
1637
- * getAllToolCalls 会 flatMap + strip 克隆出完整数组——只需计数的调用方(渲染签名
1638
- * 每 200ms tick 调用一次)用它是纯浪费;本函数 reduce 累加各 turn 的 length,零分配。
1639
- * 与 getAllToolCalls(...).length 恒等(同一 turns 源)。
1640
- */
1641
- declare function countAllToolCalls(record: ExecutionRecord): number;
1642
- /**
1643
- * closed 终态 → 三态 outcome 的唯一权威派生(D6 收敛:原 notifier/bg-notify-render/
1644
- * shared deriveClosedDisplay 三处手写同构 switch 的单一实现)。
1645
- *
1646
- * 判定顺序(顺序敏感,勿回退成「error 有值即 failed」的无视取消规则):
1647
- * 1. closedReason === "cancelled" → "cancelled"(取消优先,不参与 error——abort 合成
1648
- * result 可能携带 error,但用户取消语义优先)
1649
- * 2. error 非空(truthy,与旧三处同构的 `record.error &&` 判定逐字对齐——空串 error
1650
- * 不构成失败)→ "failed"
1651
- * 3. 其余 → "completed"
1652
- *
1653
- * [D6 待核项保真] 「failed 优先于 patchFile 提示」:失败轮也会写 patchFile
1654
- * (doFinalizeRecord Step 0 对 worktreeHandle 无条件 collectPatch),消费方必须先按
1655
- * outcome 分流再渲染 patch 提示——failed 分支不展示 patch/result。历史 bug:notifier
1656
- * 的 patchFile 分支曾遮蔽 gc+error 判定,失败终态被 LLM 告知 completed(M1 修复存档)。
1657
- *
1658
- * [D6 显式取舍] parent-shutdown/parent-fork/parent-new 合成关闭(subagent-service
1659
- * disposeAllRecords 合成 result 恒写 error:"closed due to ${reason}")在本映射下落
1660
- * "failed"——语义为「父进程关闭时子 agent 未完成即失败」,选定行为而非疏漏,
1661
- * 勿当 bug 改回 cancelled 造成派生矛盾。
1662
- *
1663
- * 唯一写点 completeRecord 调用本函数冻结 record.outcome;通知 payload(notifier 投影
1664
- * 边界)与无 outcome 字段的存量/重建 record 由 projectOutcome 兜底复用本函数。
1665
- */
1666
- declare function deriveOutcome(closedReason: ClosedReason | undefined, error: string | undefined | null): ExecutionOutcome;
1667
- /**
1668
- * 投影层 outcome 唯一出口:running → undefined(终态语义不适用活跃态);closed →
1669
- * 一等 outcome 字段直读优先,字段缺失(存量/磁盘重建 record——outcome 持久化不在
1670
- * U3 领地内)时回退 deriveOutcome(closedReason, error) 兜底——单一权威函数,
1671
- * 消费方零手写推导。返回值联合含 "closed-legacy" 预留态,消费方必须处理。
1672
- */
1673
- declare function projectOutcome(record: {
1674
- status: ExecutionStatus;
1675
- outcome?: ExecutionOutcome;
1676
- closedReason?: ClosedReason;
1677
- error?: string;
1678
- }): ProjectedOutcome | undefined;
1679
- /** elapsedSeconds 唯一计算点(共享 helper,消除三处发散)。endedAt 缺失用 Date.now()。 */
1680
- declare function computeElapsedSeconds(record: {
1681
- startedAt: number;
1682
- endedAt?: number;
1683
- }): number;
1684
- /**
1685
- * 投影到 live 进度快照。elapsedSeconds/currentActivity/eventLog 均现算派生。
1686
- * 供 WorkflowsView 在 agent 运行期间读取实时进度。
1687
- */
1688
- declare function projectLiveProgress(record: ExecutionRecord): {
1689
- status: ExecutionRecord["status"];
1690
- turns: number;
1691
- totalTokens: number;
1692
- elapsedSeconds: number;
1693
- eventLog: AgentEventLogEntry[];
1694
- currentActivity: ReturnType<typeof getCurrentActivity>;
1695
- lastError: string | undefined;
1696
- };
1697
1042
 
1698
1043
  /** 三态读取结果(判别联合,调用方按 status 分派)。 */
1699
1044
  type GlobalConfigReadResult =
@@ -2013,8 +1358,25 @@ declare class SubagentService {
2013
1358
  /** [D4-①] 通知簇 host 面(notifyComplete/notifyClosed/pending 注册注销 + notifier
2014
1359
  * 实例封装,原私有通知簇四方法与模块函数的搬移落点——notify-host.ts)。
2015
1360
  * deps 惰性求值(pi/session 级状态运行时可变),行为与原 constructor 内
2016
- * createNotifier(this.piAdapter()) 逐字节等价。session_start revive,shutdown dispose。 */
1361
+ * createNotifier(this.piAdapter()) 逐字节等价。session_start revive,shutdown dispose。
1362
+ * [sync-collect 合并] toNotifyRecord/notify/notifyBatch 随批路由需要由 host 导出
1363
+ * (collectCoordinator 闭包与 E9/E1 直发路径消费,见 notify-host.ts 接口注释)。 */
2017
1364
  private readonly notifyHost;
1365
+ /** collectCoordinator(subagent-sync-collect U2):sync 批缓冲 + 闭合检测 + flush 分流。 */
1366
+ private readonly collectCoordinator;
1367
+ /** [E9] dispose 时已转 async 写账的成员 id(revive 后 flushBatch 防御过滤用)。
1368
+ * 背景:dispose 后同进程 revive(/resume /fork /new)时协调器内部缓冲仍持有已转换
1369
+ * 成员快照(协调器无 drain API,U5 领地不含 collect-coordinator.ts)——若后续新
1370
+ * sync 成员触发闭合,陈旧快照会随批重投(新成员集新 hash,账本跨键不拦)→ 双重
1371
+ * 通知。flushBatch 闭包按本集过滤,陈旧成员零重投。id 唯一 per spawn,无误伤面。 */
1372
+ private readonly e9ConvertedIds;
1373
+ /** [v2 D4] E1 等待分支的 settled 有界重扫状态(null = 未注册)。disposed 后保持
1374
+ * 非 null——同 session 内不再重复注册(补发完成/达限后 settled 边沿已无事可做,
1375
+ * 单注册即单重扫);initSession(revive)置 null 允许新 session 重新注册。
1376
+ * pi.on 无 off(见 armSettledRescan):旧 handler 闭包捕获旧 state,未 disposed 时
1377
+ * 遇 settled 边沿仍会执行,扫描 this.mainSessionFile 当前值(handler 不绑定注册时
1378
+ * 的文件域);dispose 的惰化处置见 dispose()。 */
1379
+ private settledRescanState;
2018
1380
  /** [MF#4][MF#2] fork 深度按 async 调用链传递(AsyncLocalStorage),替代共享可变计数器。
2019
1381
  * 主 session=0;fork 进入子 session 期间推进为子深度,供嵌套 fork 经 ALS 读到自身深度作为
2020
1382
  * parentForkDepth。并发 background fork 各自独立调用链,不再互相压低深度值。
@@ -2029,19 +1391,26 @@ declare class SubagentService {
2029
1391
  * 在子进程注册(session-runner spawnedChildren.set)之前,锁空洞由此守卫兜住;EPIPE
2030
1392
  * 兜底不持锁,同样被覆盖)。child 注册完成后投递走热路径,不经此守卫。 */
2031
1393
  private readonly resumesInFlight;
2032
- /** chat 域 pi 引擎实例(D2 单轨:chat 域执行/投递统一经 EnginePort)。per-service DI——
2033
- * getService 经适配器绑本实例;registry 全局 'pi' 单例绑进程级 getSubagentService(),
2034
- * 直构 Service 的测试场景解析不到本实例。不能 import registration.ts(其 import 本文件
2035
- * 循环依赖),直接构造 PiEnginepi-engine 不反向依赖本文件)。 */
2036
- private readonly chatPiEngine;
2037
- /** chat 域轮次交接包(executeViaEngine / 冷路径续轮挂载 PiEngine.run taskId 消费)。 */
2038
- private readonly chatRoundTickets;
2039
- /** [D4-②] 轮次结算回调(原 buildSessionRunnerContext 内的 onRoundSettled 业务闭包
2040
- * 搬移至 round-settlement.ts;deps 回调闭包惰性求值,session-runner agent_settled 时消费)。 */
2041
- private readonly settleRound;
1394
+ /**
1395
+ * [W3 chat 域收口] chat 轮次反向通道路由表(recordId 键):首轮 run chat 注册、
1396
+ * interact 续聊轮复用——host/streamDelta(recordId 分支)与 host/roundLifecycle
1397
+ * (recordId 键)的分发目标(EngineClient.recordRoutes
1398
+ * EnginePort.registerChatRoundRoute 注册)。record 终态化路径注销([F-5 修复]
1399
+ * 汇聚点 = doFinalizeRecord onFinalized 钩子 + cancelBackground /
1400
+ * disposeAllRecords 两处直连终态化路径显式注销)。
1401
+ */
1402
+ private readonly chatRoundRoutes;
2042
1403
  /** [D4-③] 冷路径复活依赖(原四件 private 方法的搬移落点——cold-resurrect.ts;
2043
1404
  * deps 闭包惰性求值:sessionRootId / execNesting 基线运行时可变)。 */
2044
1405
  private readonly coldResurrectDeps;
1406
+ /**
1407
+ * [W4] 轮次活性监督器(D2「等待有主」权威层):死亡事件纳管(run failed / 引擎
1408
+ * exited → adoptOnProcessDeath)+ boot 分区重认领(initSession)+ 三态判定
1409
+ * (record 级视图)+ 该放弃(终态化 failed + 注销 + 终止通知)。装配绑定面
1410
+ * (deps/giveUp 编排/sweep 挂点)在 round-supervisor/service-binding.ts——变化轴
1411
+ * 独立(通知文案 / 终态化编排 / store 读侧判据只动该文件),本字段只持实例。
1412
+ */
1413
+ private readonly roundSupervisor;
2045
1414
  /** [D4 查询面聚合] 读模型消费面(壳 interface/ 视图与 tool 查询经此访问;
2046
1415
  * 纯委托——方法本体保留 private 实现不重写,行为逐字节等价)。 */
2047
1416
  readonly queries: SubagentQueries;
@@ -2049,6 +1418,11 @@ declare class SubagentService {
2049
1418
  * 纯委托同上。PiEngineService 适配器不经此——引擎边界走 piEngineServiceAdapter)。 */
2050
1419
  readonly chatActions: SubagentChatActions;
2051
1420
  private readonly manifestStore;
1421
+ /**
1422
+ * [D6 #7a] records 目录(与 manifestStore 同源同一推导)——屏障失败 warn 带 manifest
1423
+ * 文件路径用(ManifestStore.dir 私有,此处不破封装另存同源值;漂移由构造点同语句保证不发生)。
1424
+ */
1425
+ private readonly recordsDir;
2052
1426
  /**
2053
1427
  * [T1/PS-9] subagent sessionDir(getSubagentSessionDir 推导,与 store 同源同一 rootCwd)。
2054
1428
  * 传给 doFinalizeRecord 的 FinalizeDeps.sessionDir——record.sessionFile 缺失时 finalize
@@ -2088,6 +1462,8 @@ declare class SubagentService {
2088
1462
  /** 孤儿终态恢复委托(RecordStore.recoverOrphanRecords 的唯一调用入口,维持 store
2089
1463
  * private 封装——与 recoverManifestTmpFiles 同模式;[D4] public 面收窄:唯一调用方
2090
1464
  * 是 initSession,转 private)。判定语义见 store 侧注释。
1465
+ * mainSessionFile 随调用透传(v2 D3 覆写 merge 数据源:主文件末条 entry 的批域
1466
+ * 标记与轮终 result/model;initSession 先赋值后恢复,时序就绪)。
2091
1467
  * 随后跑 entry-born 孤儿恢复(无子文件锚的 register-only record,spawn 窗口期死亡,
2092
1468
  * E2E 实测缺口)——主 session 文件经 getMainSessionFile 注入(构造期可空)。 */
2093
1469
  private recoverOrphanRecords;
@@ -2129,7 +1505,13 @@ declare class SubagentService {
2129
1505
  onParentNew(): number;
2130
1506
  /** SP-4: idle record GC(30 天 TTL,实现抽至 idle-gc.ts)。stop 函数(dispose 调)。 */
2131
1507
  private stopIdleGc;
2132
- /** 启动 idle record GC 定时器(session_start 调用,幂等)。 */
1508
+ /** 启动 idle record GC 定时器(session_start 调用,幂等)。
1509
+ * [W4] WorkflowRun store(FileRunStore)同批纳入:running 且 startedAt 超 30 天
1510
+ * 锚窗的 run 终态化归档(只终态化不补注销,见 idle-gc.ts 头注)。宿主未
1511
+ * configureCore 时 loadAll 抛错由 idle-gc 内部吞掉(单轮跳过)。
1512
+ * [F-1 修复] stateDir 与 pi 壳 JsonlRunStore 落盘布局同源
1513
+ * (resolvePiWorkflowStateDir → <sessionDir>/workflow-state/)——缺省 dataRoot 根
1514
+ * 与 pi 生产落盘不相交,WorkflowRun GC 曾恒空转(W4 引入的装配错位)。 */
2133
1515
  startGcTimer(): void;
2134
1516
  /** 停止 idle record GC 定时器(dispose 调用)。 */
2135
1517
  private stopGcTimer;
@@ -2139,6 +1521,107 @@ declare class SubagentService {
2139
1521
  * listener 仍然存活。若 pending-notifications 先于本扩展执行 session_shutdown(后注册
2140
1522
  * 先执行的语义下会如此),listener 已注销,unregister 事件被静默丢弃。这是可接受的
2141
1523
  * 退化——进程退出后两侧状态本就不保证一致,下次 session_start 的 crash recovery 会修正。 */
1524
+ /** [U4 deviation #8 接线] collectSync 预算热读(flush 时读值,与 getCollectSyncDefault
1525
+ * 同款访问链 modelService.getGlobalConfig().collectSync)。节缺失/读失败 → undefined
1526
+ * → notifyBatch 落 buildBatchLlmContent 设计默认值(4000/24000,E5 不炸启动)。
1527
+ * sanitizeCollectSync 保证节存在时两字段必有合法正整数。 */
1528
+ private getCollectSyncBudget;
1529
+ /** [E9 专用] batchFinalized 落标 + manifest fire-and-forget 写(设计 §3.1.5 E9)。
1530
+ * 批通知路径(flush/E1)已改走「manifest 屏障 → 写账 → 纯落标」序列(「通知可达
1531
+ * ⇒ 索引就位」的构造性保证,见 flushBatch 闭包 / runSyncCollectRecoveryScan),
1532
+ * 不再经本 helper;仅 E9 转换的成员保持原形态——其走 async 单条通知(全文注入、
1533
+ * 无指针行消费),manifest 无时序要求,落标后 fire-and-forget 补写(list 后手动
1534
+ * 反查的顺带索引)。
1535
+ * 路径 = getFullRecord 冷路径重建 → appendBatchFinalizedEntry 纯落标 → fire
1536
+ * manifest。getFullRecord 不可达(子 session 文件缺失/已 GC)→ 跳过该成员
1537
+ * (详见 flushBatch 闭包注释)。 */
1538
+ private markMembersBatchFinalized;
1539
+ /** batchFinalized 落标唯一出口(appendEntry 公共末步,纯落标):显式覆写
1540
+ * collectMode/batchFinalized → reportSubagentRecord。覆写动机:recordToSubagent
1541
+ * 投影已含两字段(U5 修复),但 getFullRecord 冷路径含 sidecar/manifest 重建分支
1542
+ * (非 entry 源),显式赋值防非 entry 源重建时丢标记。
1543
+ *
1544
+ * [v2 D1 断链 1] 落标即「离开批 = 通知已/即将送达 = 指针行即将被消费」——成功
1545
+ * 成员走 SP-5 改道 doFinalizeRoundToIdle(不写 manifest),批路径不补写则
1546
+ * records/<sa-id>.json 永不产生、session-reader 反查 0 命中。manifest 写点已从
1547
+ * 本出口的 fire-and-forget 前移至各调用方:批通知路径(flush/E1)在写账前屏障
1548
+ * await 全部落盘(「通知可达 ⇒ 索引就位」的构造性保证);E9 保持落标后
1549
+ * fire-and-forget(async 单条通知无指针行消费,无时序要求)。
1550
+ * rec 两来源(flush 的 getFullRecord 内存全量 / E1 的 rebuildEntryRecord 重建
1551
+ * 快照)必需字段恒齐备(id/agentName←agent/rootSessionId/createdAt←startedAt),
1552
+ * task/slug/parentRecordId 等可选 undefined 自然缺省。 */
1553
+ private appendBatchFinalizedEntry;
1554
+ /** 批成员 manifest(sa- id → sessionFile 反查索引)写的唯一投影点(D2 字段投影 +
1555
+ * status 如实投影:成功成员此刻 record 实态 running+resumable → "running",后续
1556
+ * message upgrade 走完整 finalize 时 Step 4 原子覆盖为 "closed")。
1557
+ * 返回原始 promise 不吞错——失败语义由调用方定:批通知路径经
1558
+ * writeSyncBatchManifestBarrier 的 allSettled(debug 不阻断写账);E9 经
1559
+ * fire-and-forget catch(debug 不阻断落标)。 */
1560
+ private writeBatchMemberManifest;
1561
+ /** [时序屏障] 批通知路径(flush/E1)专用:成员 manifest 并行写 + await 全部完成
1562
+ * (allSettled)后才允许写账投递——「通知可达 ⇒ 索引就位」的构造性保证。写失败
1563
+ * 不阻断(best-effort 语义与 doFinalizeRecord Step 4 一致:反查索引缺失只影响指针行
1564
+ * 反查,session-reader 错误文案已指引绝对路径兜底,不构成写账失败);warn 留痕
1565
+ * (D6 #7a / SC-1:屏障失败意味着该成员指针行反查索引缺失,debug 级在排障时不可见)。 */
1566
+ private writeSyncBatchManifestBarrier;
1567
+ /** [E9] dispose 时批未闭合:缓冲中已终态未通知成员逐条转 async 语义写账(放弃攒批)
1568
+ * + 落 batchFinalized 标记(E1 重建扫描据此排除,防双重通知),交由既有 shutdown
1569
+ * flush / resume 重放兑底;仍在跑的成员走现有退出路径(disposeAllRecords 关闭,
1570
+ * 与 async 一致)。写账用 notifier.notify 现有通路(ledger.record + attemptDeliver)。
1571
+ * 源序:写账先于落标——写账后崩溃 → E1 重建收该成员,但 async notifyId 与批 hash
1572
+ * 跨键不拦的重发属设计披露的 E9 残余窗(at-least-once 良性,PS-17 同族,v1 接受)。 */
1573
+ private convertPendingSyncBufferToAsync;
1574
+ /**
1575
+ * [E1] sync 批崩溃恢复钩子(设计 §3.1.5 E1,index.ts session_start 恢复编排处调用,
1576
+ * 须晚于 initSession——孤儿终态恢复先行收敛 running 成员,「全员终态」判定才可达):
1577
+ *
1578
+ * - 扫描主 session 文件每 id 末条 subagent-record entry(store.scanLastRecordEntries,
1579
+ * collectLastRecordEntries 同构 + 投影扩展含 collectMode/batchFinalized + 终态五
1580
+ * 字段;禁走 collectRecords light 路径——主 session 落标 entry 对它不可见);
1581
+ * - 只收 collectMode=sync 且无 batchFinalized 的成员(排除已通过批 flush 或 E9
1582
+ * 转换离场的,防双重通知),按 rootSessionId 过滤当前根;
1583
+ * - 全员终态且账本无同成员集批记录 → manifest 屏障(await 落盘,「通知可达 ⇒
1584
+ * 索引就位」构造性保证,与 flushBatch 同款)→ notifyBatch 补发(内容 = 末条
1585
+ * entry 终态快照;账本 record 同 hash 幂等拒绝 = 已投递/已在账,两种结局都算
1586
+ * 「已处理」);
1587
+ * - 仍有 running → 本次不动,注册 settled 有界重扫(D4,见 armSettledRescan)——
1588
+ * 成员延迟终态(主 agent 冷路径 resume → 正常流落 entry)由 settled 边沿驱动
1589
+ * 重扫收敛,不再依赖「下次 session_start」作唯一再驱动(v2 §2.4 断链 4);
1590
+ * running 口径与协调器同构
1591
+ * (resumable 豁免,v2 D3——覆写不可达的防御分支残余不被误判「仍在跑」);
1592
+ * - 补发尝试后统一补 batchFinalized 标记(账本拒绝也算已投递;直接用末条重建快照
1593
+ * 落标不经 getFullRecord——子文件缺失/已 GC 时标记仍可落盘,窗口自愈不依赖二次
1594
+ * 重启;补标自身崩溃重入幂等收敛,末条 entry last-writer-wins)。
1595
+ *
1596
+ * async 化(时序屏障修复):返回 Promise 但**内部自捕获不外抛**——宿主 index.ts
1597
+ * session_start 以同步 try/catch 调用(其 catch 兑现不到 promise 内的异常),
1598
+ * 自捕获维持同款 warn 容错语义,浮动调用零适配、不产生 unhandled rejection。
1599
+ *
1600
+ * [U8 拆批修复] 与协调器合批排程无交集:E1 只在 session_start 编排处运行(此前
1601
+ * dispose 已取消挂起排程),补发直走 notifier.notifyBatch 不经协调器;异常时序
1602
+ * 相撞由账本 sync-batch:<hash> 幂等拒绝兜底。
1603
+ */
1604
+ recoverSyncCollectBatch(): Promise<void>;
1605
+ /** [E1/D4] 单次「扫描→判定→可达则补发+落标」,E1 首扫与 settled 重扫共用同一实现
1606
+ * (防两处复制粘贴分岔)。三态返回:idle(无 sync 候选——已全部落标/E9 转换/异根,
1607
+ * 无事可等)/ waiting(仍有 running 成员,本次不动)/ dispatched(全员终态,已补发
1608
+ * +统一落标)。async:补发前有 manifest 屏障 await(见函数头 E1 注释)。 */
1609
+ /** 返回 outcome + waitingIds(达限 warn 需滞留成员 id,D6 #7b——仅 waiting 态非空)。 */
1610
+ private runSyncCollectRecoveryScan;
1611
+ /** [v2 D4] 注册 agent_settled 有界重扫(幂等:settledRescanState 非 null 不叠加注册
1612
+ * ——E1 现仅 session_start 单调用点,守卫是防第二入口引入时的注册叠加断言面)。
1613
+ * 每次 settled 边沿重跑同一 E1 扫描(runSyncCollectRecoveryScan):dispatched
1614
+ * (补发+落标完成,scan 的 warn 已留痕)或 idle(候选已被其他通路落标)→ disposed;
1615
+ * 累计 SETTLED_RESCAN_LIMIT 次仍在等 → disposed + warn 留痕(D6 #7b / SC-2:达限
1616
+ * 放弃重扫意味着滞留成员的批通知要等下次 session_start 才收敛,含滞留 id 的 warn
1617
+ * 是唯一线索,debug 级排障不可见;后续事件零处理,下次 session_start 再收敛)。
1618
+ * pi.on 无 off(0.84.4 实装)——disposed 标志包装兑现退订(scheduler extension
1619
+ * index.ts subscribeSettled 同款先例)。P-settled 定谳(0.84.4 dist 实装证据):
1620
+ * pi.on 为 per-extension 列表分发——loader.js `on()` 把 handler push 进
1621
+ * extension.handlers.get(event) 数组(非覆盖),runner.js `emit()` 对全部
1622
+ * extension 的全部 handler 逐一 await;故本注册与 ledger host 经
1623
+ * piAdapter.onAgentSettled 注册的 settled 分发互不干扰,无需降级并入 host 链。 */
1624
+ private armSettledRescan;
2142
1625
  dispose(): void;
2143
1626
  /**
2144
1627
  * [T4④ / PS-5] shutdown flush 被门拦时把未投递 pending 复写落盘(供重启 replay)。
@@ -2187,21 +1670,20 @@ declare class SubagentService {
2187
1670
  */
2188
1671
  private lookupRecordAnyState;
2189
1672
  /**
2190
- * [V2 决策 3] chatMode 统一投递入口(message action 的 Service 面)——经引擎交互面
2191
- * 执行(D2:PiEngine.interactRecord——port face interact record 锚定形态,协议知识
2192
- * 在引擎边界,编排层不做 stdin 写入)。分流语义(按**进程死活**,
2193
- * 不按 record.status)与热/冷路径细节见 PiEngine.deliverPrompt:
2194
- *
2195
- * 热路径(进程活):prompt + streamingBehavior——pi 权威裁决 busy/idle(F3/F4)。
2196
- * 冷路径(进程死):冷路径续轮(resumeChatRound)重开 session + prompt(仅崩溃/
2197
- * timeout kill/跨重启命中)。
1673
+ * [V2 决策 3 → W3 协议形态] chatMode 统一投递入口(message action 的 Service 面)
1674
+ * ——经协议 interact(message action)发往 pi-subagent-cli 引擎进程。协议知识
1675
+ * stdin prompt 命令 + streamingBehavior 映射 + EPIPE 兜底)在引擎进程内
1676
+ * (chat-session.deliverMessage);编排层按结构化结果分流:
2198
1677
  *
2199
- * 失败语义与直调形态一致:业务拒绝(not ready / EPIPE 兜底耗尽等,文案自带行动语言)
2200
- * interact 结构化结果回传后原样 throw(错误文本逐字节保持)。
1678
+ * 受理(引擎侧进程活):prompt + streamingBehavior——pi 权威裁决 busy/idle。
1679
+ * 冷路径(engine_session_not_resumable = 进程死/无活进程):冷路径续轮
1680
+ * (resumeColdRound → run chat + resume 锚点接续,仅崩溃/timeout kill/跨重启命中)。
1681
+ * 其他拒绝(EPIPE 兜底耗尽 / engine_interact_failed):业务拒绝原样 throw
1682
+ * (文案自带行动语言——与 inproc 形态逐字节一致)。
2201
1683
  *
2202
1684
  * @param record 目标 record(chatMode,running 或 idle)
2203
1685
  * @param text 消息正文
2204
- * @param interrupt true=steer(抢占)/ false=followUp(排队),仅热路径 streamingBehavior 用
1686
+ * @param interrupt true=steer(抢占)/ false=followUp(排队)
2205
1687
  */
2206
1688
  private deliverChatMessage;
2207
1689
  /**
@@ -2332,6 +1814,17 @@ declare class SubagentService {
2332
1814
  * [perf] 磁盘源为 light(头部 identity + 状态,无 eventLog/result/turns 等重数据)
2333
1815
  * ——列表/补全/hasRunning 够用;详情场景调 getFullRecord(id) 懒加载补齐。 */
2334
1816
  private collectRecords;
1817
+ /**
1818
+ * collectSync.default 当前生效值(subagent-sync-collect U2,偏差#3 接线:
1819
+ * startHandler 缺省 collect 解析用)。
1820
+ * config 未配/读失败 → DEFAULT_COLLECT_SYNC.default 兜底(E5 不炸启动)。
1821
+ * 新 session 生效语义与 engine 配置一致(globalConfig 由 ModelConfigService
1822
+ * reloadGlobalConfig 刷新)。
1823
+ */
1824
+ /** collectSync 节单读取点(S9,code-simplify):「读节」一处,「投影成 default 或
1825
+ * budget」各自 accessor 负责(getCollectSyncDefault / getCollectSyncBudget)。 */
1826
+ private collectSyncSection;
1827
+ getCollectSyncDefault(): "async" | "sync";
2335
1828
  /** [perf] 单 record 详情懒加载(全量:eventLog/displayItems/result/turns/tokens)。
2336
1829
  * 内存 running record 直接投影;磁盘 record 全量重建(per-file 缓存,stat 戳校验)。
2337
1830
  * 返回 undefined:id 不存在于内存与磁盘。 */
@@ -2388,6 +1881,18 @@ declare class SubagentService {
2388
1881
  * 落 entry 前)→ 终态迁移。bg notify 归编排侧(与 pi 轮次收尾通知归编排对称)。
2389
1882
  */
2390
1883
  private runEngineTask;
1884
+ /**
1885
+ * [W4 表 3 行 1] 引擎/子进程死亡、宿主存活的 record 处置:run 终态如实记 failed
1886
+ * 证据(record.error),record **保持 resumable**(session 文件在盘,逻辑任务可续
1887
+ * ——冷路径 resume 可直接续写),交监督器接管(合并单条通知 + 三态判定)。禁止
1888
+ * 两个事故方向:completed 谎报(G3)与 closed 直接终局(resume 可能性丢失,等待
1889
+ * 无主——2026-09-08 事故环 2/3 的 core 侧形态)。
1890
+ *
1891
+ * 判据状态源钉死 record 级:写点只动 record 字段(resumable/result/error),
1892
+ * 不清镜像不查引擎——引擎进程被动重建(ensureConnected 退避重填镜像)不翻转
1893
+ * 本处置(纳管模型:死亡事件纳管、重建不解管)。
1894
+ */
1895
+ private adoptResumableAfterEngineDeath;
2391
1896
  /**
2392
1897
  * 分层并发配额:depth 越深可用配额越少(下限 1)。fork 深度护栏在池维度的投影,
2393
1898
  * 公式约定以 concurrency-pool.ts 注释为登记处、此处为唯一代码锚点。
@@ -2396,71 +1901,124 @@ declare class SubagentService {
2396
1901
  /**
2397
1902
  * engine.run resolve 的终态迁移:outcome.error → failed(success=false + error 文案);
2398
1903
  * 否则 done(result=content)。CAS 抢锁(tryTransition)防与 cancelBackground 双收尾。
1904
+ *
1905
+ * [W4 表 3 行 1] 进程死亡分诊:outcome.error 存在且 **exitCode === null**(引擎侧
1906
+ * 进程被信号终止/崩溃的合成 outcome 形态——RemoteEngine 运行中失败合成分支恒
1907
+ * exitCode:null,引擎如实上报的 turn 失败带数值 exitCode;engine-client 注释同源
1908
+ * 「exitCode null = 被信号杀死,杀链判据」)且宿主存活且非 conversation 形态 →
1909
+ * record 保持 resumable 交监督器接管(如实 failed 证据 + 合并通知 + 三态判定),
1910
+ * 不再 closed 终局。返回 true = 走了接管分支(调用方跳过 bg 完成回注)。
2399
1911
  */
2400
1912
  private finalizeEngineOutcome;
2401
- /** 共享的"干活 + 收尾"——sync 直接 await,background 在 detached 里调。 */
1913
+ /**
1914
+ * workflow 域"干活 + 收尾"(sync await;[W3] 执行叶 = 协议 engine.run——原 inproc
1915
+ * runSpawn 链随 inproc pi 引擎目录 删除消亡,journal 接线 / record 终态迁移语义保持)。
1916
+ * 编排分段保持「装配(池槽/worktree)→ 执行 → 回收(finally)→ 错误收口 → 终态收口」。
1917
+ */
2402
1918
  private runAndFinalize;
1919
+ /** engine.run taskSpec 装配单一来源(runAndFinalize 与 kickOffChatRound 共用):
1920
+ * executeOptions 协议映射 + model = record 留痕词形(resolved 解析产物,
1921
+ * joinEngineModelRef 规范形)覆盖——原 identity.resolved 经 runSpawn --model
1922
+ * 兜底的协议等价承载。 */
1923
+ private taskSpecWithModel;
1924
+ /**
1925
+ * one-shot(非 chatMode)终态收口(原 settleOneShotOutcome 分支):成功轮消费
1926
+ * closeAfterRound 挂起标志;失败/取消一次性销毁。CAS 抢锁失败(cancel/dispose 抢先
1927
+ * 终态化)静默跳过。runAndFinalize(workflow 域)与 kickOffChatRound 非 chatMode
1928
+ * 分支共用。
1929
+ */
1930
+ private settleOneShotOutcome;
1931
+ /** AgentOutcome → execution AgentResult 单一映射源(workflow run 域映射;
1932
+ * finalizeEngineOutcome 终态 result 复用此处构造——exitCode null = 被信号杀死的
1933
+ * 合成终态,error 如实透传)。 */
1934
+ private outcomeToAgentResult;
2403
1935
  /** [U04 提取·装配] 池槽获取:pooled(background)record 排队 acquire。成功返回 undefined
2404
1936
  * 继续执行;失败返回终态 result 供调用方 early-return(该路径在 try/finally 之前,
2405
1937
  * 不触发轮次资源回收——与原控制流逐字节一致)。 */
2406
1938
  private acquirePoolOrFinalize;
2407
1939
  /** [U04 提取·装配] 解析 worktree 参数:boolean → WorktreeHandle | undefined(true/undefined 由 run 内部处理)。 */
2408
1940
  private resolveWorktreeHandle;
2409
- /** [U04 提取·装配] [MF#4][MF#2] fork 深度护栏:ALS 传递深度(主 session 链无 store→0,fork 推进 +1)。 */
2410
- private resolveForkDepths;
2411
- /** [U04 提取·执行] runSpawn 的两层 ALS 包装(forkDepthAls 外层 + execNesting 内层)。 */
2412
- private runSpawnNested;
2413
1941
  /** [U04 提取·回收] 轮次资源回收(finally 语义,幂等):池槽归还(仅 pooled 且 acquire
2414
- * 成功)、streaming widget 清除、在途 resume 守卫清除。 */
1942
+ * 成功)、streaming widget 清除。 */
2415
1943
  private releaseRoundResources;
2416
1944
  /** [U04 提取·错误收口] MF-6(决策 6 spec §3.1):chatMode(含 resume)spawn/创建失败
2417
1945
  * 不销毁对话——回退 idle(可恢复),让 agent 可重试 message 或 close。与一次性模式
2418
1946
  * (finalizeFailed 终态销毁)区分。返回合成 failed result(swallow,不 re-throw)。 */
2419
1947
  private finalizeChatSpawnFailure;
2420
- /** [U04 提取·收口派生] closedReason 派生:aborted → cancelled;否则 success → user-close,!success → gc。 */
2421
- private deriveClosedReason;
2422
- /** [U04 提取·终态收口] CAS 抢锁:抢到则按 chatMode 分流完整收尾;没抢到(cancel 已先设
2423
- * closed+cancelled)则跳过。 */
2424
- private settleFinalOutcome;
2425
- /** [U04 提取·终态收口] chatMode 轮次分流(原 A/B 分支,De Morgan 等价拆分):
2426
- * 成功轮(!aborted && success)与失败/取消轮(其补集 !success || aborted)各自处理
2427
- * closeAfterRound 挂起语义。 */
2428
- private settleChatRoundOutcome;
2429
- /** [U04 提取·终态收口] one-shot(非 chatMode)分流(原 C/D 分支):成功轮消费
2430
- * closeAfterRound 挂起标志;失败/取消一次性销毁。 */
2431
- private settleOneShotOutcome;
2432
1948
  /** [U04 提取·终态收口] closeAfterRound 挂起标志消费(原三处分支的公共收尾序列):
2433
1949
  * 清标志 + 终态化 closed。reason:成功轮恒 user-close;失败/取消轮用派生值。 */
2434
1950
  private consumeCloseAfterRound;
2435
1951
  /**
2436
- * pi chat 域轮次的 detached 编排(D2 单轨——旧 pi 主路径绕过 EnginePort 的 detached
2437
- * 编排删除后的 EnginePort 化形态):
2438
- * 预备轮次(record/opts/identity/host ctx/stream/resume)挂载交接 Map engine.run
2439
- * ctx.taskId 消费(PiEngine chat 分支回调 runChatRound——即 runAndFinalize 链,含 pool
2440
- * 并发槽 acquire/release 与杀链,行为零变化)→ 完成回注 notify(cancel 抢先时跳过,
2441
- * 与旧 .then 语义一致)。
2442
- * stream 在挂载前同步创建(spawn 前置不变量,stream-sink 退役步骤 2 守护)。
1952
+ * pi chat 域轮次的 detached 编排([W3 协议形态]):轮次经协议 run(会话形态
1953
+ * chat{recordId, resume?})发往 pi-subagent-cli 引擎进程——
1954
+ * - 应答时点 = 首轮 agent_settled(W2 契约:idle 帧先于应答帧;outcome = 本轮
1955
+ * 内容非会话终态)→ 应答到达即本轮 settle(round+1 / 增量通知 / closeAfterRound
1956
+ * 消费,见 settleChatRoundFromResponse);
1957
+ * - 流式 delta / 轮次生命周期经 host/streamDelta + host/roundLifecycle 反向通道
1958
+ * 回流:首轮 runId 键(RunContext.stream / onRoundLifecycle)、续聊轮 recordId
1959
+ * 键(chatRoundRoutes 注册的 recordId 路由);
1960
+ * - recordId 路由在本方法注册(首轮 + 冷续轮替换式重注册),record 终态化路径注销。
2443
1961
  * chat 域不接 event journal(pi 子代理 session JSONL 即原生数据源;与迁移前产物
2444
1962
  * 形态一致——journal 接线仅 workflow 域 SAR 与非 pi 引擎 chat 路径)。
2445
1963
  */
2446
1964
  private kickOffChatRound;
2447
- /** PiEngine 的编排服务适配器(chat 绑定):闭包持有本实例的编排面——chat 轮次交接
2448
- * 由此成为 PiEngineService 的可选面(SAR 直绑 Service workflow 实例不提供,
2449
- * Service 公共接口不为引擎内部交接扩面)。 */
1965
+ /**
1966
+ * [W3] chat 轮次生命周期帧消费(host/roundLifecycle,runId 键首轮 / recordId 键续聊轮
1967
+ * 经本方法收敛)。相位 → 宿主编排语义(W4 协议事件面三入口):
1968
+ * - settled:轮收敛——settled-watchdog 中段让位收尾段(noteRoundSettledFromProtocol);
1969
+ * - idle:轮收口进 idle 稳态——两段守护一并清(disarmRoundFromProtocol)+ 冷续锚点
1970
+ * 回填(sessionFile/engineHandle,idle 帧先于 run 应答帧)+ **idle 定时器挂载**
1971
+ * (引擎不实现 idle 定时器——core arm,W2 交接契约);
1972
+ * - failed:轮异常终止(engine_round_aborted / engine_round_crashed /
1973
+ * engine_round_epipe_exhausted)——record 如实标 failed(禁 completed 谎报),
1974
+ * chatMode 按 MF-6 回退可恢复(onChatRoundFailed)。
1975
+ */
1976
+ private handleChatRoundPhase;
1977
+ /**
1978
+ * [W3] idle 相位 = idle 定时器锚点(原 session-runner handleAgentSettledForChatMode
1979
+ * 的 armIdleTimer 段):挂载降级链(配置值 → DEFAULT 兜底 + warn)语义保持;超时
1980
+ * 处置 = 引擎侧进程回收(协议 interact close force)——idle timer SIGTERM 的协议形态。
1981
+ */
1982
+ private armChatIdleTimer;
1983
+ /** [W3] idle 帧锚点回填(冷续锚点 = 引擎侧会话滚动/compaction 后的最新定位)。 */
1984
+ private backfillChatAnchor;
1985
+ /**
1986
+ * [W3] chat 轮 failed 相位分诊:错误如实落 record(失败相位错误码——engine_round_
1987
+ * aborted(宿主 cancel/close)/ engine_round_crashed(子进程外部死亡)/
1988
+ * engine_round_epipe_exhausted(EPIPE 兜底耗尽)),禁 completed 谎报。chatMode 按
1989
+ * MF-6 不销毁对话——回退可恢复(finalizeRoundToIdle + 通知),冷续 run 接续;
1990
+ * record 已终态(cancel/close 抢先)= 迟到帧,幂等跳过。
1991
+ */
1992
+ private onChatRoundFailed;
1993
+ /**
1994
+ * [W3] 首轮 run 应答到达(= 首轮 agent_settled,W2 契约)的本轮 settle:round+1 /
1995
+ * 轮次增量通知 / base 推进 / reportRecordTransition / closeAfterRound 消费——语义
1996
+ * 权威自持于此(原 round-settlement.ts createRoundSettler 已删,本闭包为其唯一后继),
1997
+ * 唯一偏差 = 轮次文本源:协议形态下 live turns 留在引擎进程内,core 以应答
1998
+ * outcome.content(W2「outcome = 本轮内容」)为增量权威,record.turns 派生不可用。
1999
+ * idle 定时器挂载不在此处——idle 相位帧先于应答帧到达,armChatIdleTimer 已锚定。
2000
+ */
2001
+ private settleChatRoundFromResponse;
2002
+ /** [W3] chat 域引擎终止意图(协议面):cancel = interact cancel(引擎侧 SIGTERM →
2003
+ * settle 等待 → 杀链升级);close = interact close force(立即杀链收割)。fire-and-forget
2004
+ * ——失败 best-effort 留证(宿主组级收割兜底 = EngineClient killAll,dispose 路径)。 */
2005
+ private terminateChatSession;
2006
+ /** chat record 的协议 interact handle(engineHandle 缺省时按 recordId 合成——
2007
+ * 引擎侧 interact 定位键 = sessionRef.recordId;sessionFile 有值时一并携带)。 */
2008
+ private chatHandleFor;
2009
+ /** [W3] pi 引擎 port 解析(chat 域路由与终止面共用):registry cli 形态 port,
2010
+ * 未注册 = 不可用 stub(engine_not_found,见 pi-host-binding)。 */
2011
+ private resolveChatEnginePort;
2012
+ /** [W3] record 终态化路径的 chat 反向通道路由注销(幂等)。 */
2013
+ private unregisterChatRoundRoute;
2014
+ /** 引擎服务面适配器(HostBridgeServiceFace 结构视图):闭包持有本实例的编排面。
2015
+ * [W3] chat 域轮次交接可选面(takeChatRound/runChatRound/resumeChatRound)随
2016
+ * inproc PiEngine 删除移除——引擎经协议 converse,不再回调宿主编排面。 */
2450
2017
  private piEngineServiceAdapter;
2451
- /** [D4 聚合连带] PiEngineService 的显式结构视图(registration / SAR 直绑消费)。
2452
- * 原两绑定点把 SubagentService 整体结构化兼容为 PiEngineService——依赖查询/交互
2453
- * 方法 public;聚合收窄后改经本视图显式适配(成员集合与原直绑等价,行为零差异)。
2454
- * getter 形态:face 视图(惰性构造的适配对象)而非动作方法。 */
2455
- get asEngineService(): PiEngineService;
2456
- /** chat 域轮次交接的消费侧(PiEngine.run 回调):一次性取走,防重复消费。私有名与
2457
- * PiEngineService 可选面成员不同名(历史约束:D4 聚合前的结构化直绑时代,私有同名
2458
- * 成员会阻断 SubagentService 直绑;聚合后经 asEngineService 显式视图,约束已消失,
2459
- * 不同名保留为与 adapter 显式映射一致的命名纪律)。 */
2460
- private takeChatTicket;
2461
- /** PiEngine chat 分支的执行回调:原 runAndFinalize 直调链的 EnginePort 化落点
2462
- * (编排归 Service——pool 槽 + runSpawn + 终态迁移,行为零变化)。 */
2463
- private runTicketRound;
2018
+ /** [D4 聚合连带] 引擎服务面的显式结构视图(SAR 构造 resolveHostPiEnginePort
2019
+ * 传入的 getService 兼容位消费——W3 后该面无引擎侧消费方,保留使 SAR 调用点
2020
+ * 零改动,W8 收口时随签名一并清理)。getter 形态:face 视图(惰性构造)。 */
2021
+ get asEngineService(): HostBridgeServiceFace;
2464
2022
  /**
2465
2023
  * 取消 background record。CAS 抢锁(tryTransition)——抢到则 notify + 写 tombstone;
2466
2024
  * 没抢到(detached 已 finalize,record 已终态)返回 false,不触碰任何收尾副作用。
@@ -2482,7 +2040,13 @@ declare class SubagentService {
2482
2040
  private finalizeRoundToIdle;
2483
2041
  /** run() 创建期异常的收尾(H1 修复):createAndConfigureSession 失败会抛,本方法合成 failed
2484
2042
  * AgentResult → CAS 抢锁 → finalizeRecord(与正常路径同形)。返回合成 result 供 runAndFinalize
2485
- * 继续返回(不 re-throw,swallow 策略)。 */
2043
+ * 继续返回(不 re-throw,swallow 策略)。
2044
+ * [W3 契约变更⑤(run 期失败清理前置副作用)] kickOffEngineRun 前已建的 worktree
2045
+ * (executeViaEngine 创建点,record.worktreeHandle 已绑定)经本方法 → finalizeRecord
2046
+ * → doFinalizeRecord Step 3b cleanupWorktreeIfBound 清理(manifest 多声明 run 期
2047
+ * 失败 / engine.run prepare 期 reject 共用本收尾链);CAS 没抢锁(cancel 抢先终态)
2048
+ * 时由 cancelBackground 的 worktree cleanup 覆盖。唯一前置副作用 = worktree(并发
2049
+ * 池槽 acquire/release 在 kickOffEngineRun finally 内自回收,journal 是宿主数据不清理)。 */
2486
2050
  private finalizeFailed;
2487
2051
  /** S1: 排队中被 abort 走 cancelled 终态(对齐已运行被 abort 的 cancelBackground)。 */
2488
2052
  private finalizeAborted;
@@ -2508,8 +2072,6 @@ declare class SubagentService {
2508
2072
  * 由 lifecycle-manager 的 warn 回落承接)。execute/executeAndAwait 两入口共用。
2509
2073
  */
2510
2074
  private assertIdleTimeoutMsSafe;
2511
- /** 构造 SessionRunnerContext(spawn 模式:无需 SDK 实例)。 */
2512
- private buildSessionRunnerContext;
2513
2075
  }
2514
2076
  /** 获取进程单例。session_start 前为 null。 */
2515
2077
  declare function getSubagentService(): SubagentService | null;
@@ -2674,20 +2236,6 @@ type BestEffortLevel = "debug" | "error";
2674
2236
  */
2675
2237
  declare function bestEffort(err: unknown, context: string, level?: BestEffortLevel): void;
2676
2238
 
2677
- /** channel handler 签名:接收 UiRequest,返回 UiResponse。
2678
- * 具体类型定义在 session-runner.ts(W2 工作),此处用最小形状避免循环依赖。
2679
- * handler 实现方按 channel 注册,由 session-runner 按 req.channel 分派。 */
2680
- type ChannelHandler = (req: unknown) => Promise<unknown>;
2681
- /** channel 注册表接口。职责单一:只管业务路由,不管排队、不管透传判定。
2682
- * - register(channel, handler):注册 channel 对应的 handler(同名覆盖)
2683
- * - resolve(channel):取 channel 对应的 handler,未注册返回 undefined
2684
- * - list():列举所有已注册 channel 名 */
2685
- interface UiChannelRegistry {
2686
- register(channel: string, handler: ChannelHandler): void;
2687
- resolve(channel: string): ChannelHandler | undefined;
2688
- list(): string[];
2689
- }
2690
-
2691
2239
  /** 获取或创建进程级 channel registry(canonical 单例)。
2692
2240
  *
2693
2241
  * **唯一创建点**:canonical UiChannelRegistry 实例仅由本函数创建。
@@ -3017,7 +2565,7 @@ declare class Budget {
3017
2565
  * 而非原始 token 数直接相加。retry 间的真实消耗如实记录,避免预算被低估。
3018
2566
  * 详见上方权重常量的口径说明。
3019
2567
  */
3020
- consume(usage: AgentUsage): void;
2568
+ consume(usage: AgentOutcomeUsage): void;
3021
2569
  /** 累加调用计数(每次 agent dispatch 后调用;持久化快照同步)。 */
3022
2570
  incrementCallCount(): void;
3023
2571
  /**
@@ -3826,6 +3374,18 @@ interface SubagentRecordEntryData {
3826
3374
  journalPath?: string;
3827
3375
  poolKey: string;
3828
3376
  };
3377
+ /**
3378
+ * 同步收集模式标记(subagent-sync-collect 设计 §3.1.3,U1 foundation)。
3379
+ * undefined = async(缺省语义,旧 entry 零迁移——undefined 经 JSON.stringify 自然缺省)。
3380
+ * 消费方:U5 rebuildEntryRecord 投影扩展 + E1 重建扫描。
3381
+ */
3382
+ collectMode?: "sync";
3383
+ /**
3384
+ * 离开批终局标记(subagent-sync-collect 设计 §3.1.3,U1 foundation)。两出口统一
3385
+ * 落标(批闭合 flush / E9 dispose 转换,均 appendEntry 持久化)。undefined =
3386
+ * 未离开批 / 旧 entry 零迁移。消费方:U5 E1 重建扫描只收无标记成员(防双重通知)。
3387
+ */
3388
+ batchFinalized?: boolean;
3829
3389
  }
3830
3390
  /** SubagentRecord → 自描述 entry data(快照投影,不 mutate 源)。
3831
3391
  *
@@ -4035,6 +3595,14 @@ interface StartHandlerInput {
4035
3595
  idleTimeoutMs?: number;
4036
3596
  /** 执行引擎(三层路由第一层:本参数 > agent frontmatter engine > config defaultEngine)。 */
4037
3597
  engine?: string;
3598
+ /**
3599
+ * 同步收集模式(subagent-sync-collect U1 foundation)。undefined = config
3600
+ * collectSync.default(缺省 "async")。schema 层枚举限 "async"|"sync";运行时
3601
+ * 宽收 string 与 engine 字段同风格(pi 工具框架把 schema Static 解析为 string;
3602
+ * 非法值 ≠ "sync" 按 async 处理,E4 守卫用精确 "sync" 判定)。透传
3603
+ * service.execute(ExecuteOptions.collect;record.collectMode 落点归 U2 接线)。
3604
+ */
3605
+ collect?: string;
4038
3606
  }
4039
3607
  /** start 领域对象(宿主 adapter 包成 bg 工具结果)。 */
4040
3608
  type StartHandlerResult = {
@@ -4248,6 +3816,23 @@ interface CreateConcurrencyPoolOptions {
4248
3816
  */
4249
3817
  declare function createConcurrencyPool(options: CreateConcurrencyPoolOptions): ConcurrencyPool;
4250
3818
 
3819
+ /** provider 条目(v2 config.provider.<id>)的最小消费面(索引签名形态)。 */
3820
+ interface ZcodeProviderEntryLike {
3821
+ options?: {
3822
+ apiKey?: unknown;
3823
+ };
3824
+ }
3825
+ /** 短名(无 provider 前缀)解析的默认 provider(zsub DEFAULT_PROVIDER_ID 同构)。 */
3826
+ declare const DEFAULT_PROVIDER_ID = "builtin:bigmodel-coding-plan";
3827
+ /** zsub 同构的兜底缺省模型(v2 config 无 model.main 且 task 未指定时)。 */
3828
+ declare const ZCODE_FALLBACK_DEFAULT_MODEL = "builtin:bigmodel-coding-plan/GLM-5.3";
3829
+ /** [R4] 规范化全名 provider/model → create 参数的 per-session model 拆分。 */
3830
+ declare function splitZcodeModelRef(modelRef: string): {
3831
+ providerId: string;
3832
+ modelId: string;
3833
+ };
3834
+ declare function hasApiKey(entry: ZcodeProviderEntryLike): boolean;
3835
+
4251
3836
  /**
4252
3837
  * gitRun 的包装错误:message 格式与提取源 gitRunAsync 逐字一致;exitCode/stderr/
4253
3838
  * timedOut 为诊断属性(P-errshape 实测 Node 24:execFile 的 err.stderr 为
@@ -5435,7 +5020,38 @@ interface FileRunStoreOptions {
5435
5020
  * {@link DEFAULT_SAVE_MIN_INTERVAL_MS}。测试经此注入小窗口(fake timers 推进)。
5436
5021
  */
5437
5022
  saveMinIntervalMs?: number;
5023
+ /**
5024
+ * [F-1 修复] run 状态目录覆盖。缺省 = `<dataRoot>/workflow-state`(zcode 宿主布局,
5025
+ * 见 stateDir());pi 宿主的读侧装配点(round-supervisor sweep / idle-gc)必须传
5026
+ * resolvePiWorkflowStateDir()(execution/workflow-state-root.ts)——pi 宿主 run state
5027
+ * 由 JsonlRunStore 落 `<sessionDir>/workflow-state/`,与缺省根不相交。
5028
+ */
5029
+ stateDir?: string;
5030
+ }
5031
+ /** pruneStateFilesBeyondCap 的宿主注入依赖(日志与错误字符串化——tag 前缀由注入方决定)。 */
5032
+ interface PruneStateDeps {
5033
+ /** warn 通道(readdir / unlink 失败留证;清理是旁路维护,失败不抛) */
5034
+ warn: (msg: string) => void;
5035
+ /** debug 通道(成功裁剪记录) */
5036
+ debug: (msg: string) => void;
5037
+ /** error → 可读字符串(core 侧 err.message 兜底 String,宿主可用自有 error 工具) */
5038
+ toMsg: (err: unknown) => string;
5438
5039
  }
5040
+ /**
5041
+ * 把 state 目录裁剪到 cap 个最新 state 文件(mtime 升序删最旧,C1)。
5042
+ *
5043
+ * 语义(OR-5,两宿主单源):
5044
+ * - 只删目录内命中 {@link STATE_FILE_GLOB} 的文件;任何失败都不抛(清理是旁路
5045
+ * 维护,不能拖垮持久化主链路):readdir 失败静默放弃本轮(ENOENT = 从未持久化,
5046
+ * 正常态),单个 unlink 失败(非 ENOENT)warn 留证后继续删其余——ENOENT 视为
5047
+ * 并发删除竞态下的已达成目标,不告警;
5048
+ * - stat 全集取 mtime,allSettled 部分降级——单文件 stat 失败(并发删除 ENOENT
5049
+ * 等)静默跳过该文件,不阻断本轮裁剪。
5050
+ *
5051
+ * cap 解析(env 通道等)归调用方:FileRunStore 方法含 envName 通道超集;
5052
+ * pi 宿主 jsonl-run-store 经 getEnvStateMaxRuns 解析后直传。
5053
+ */
5054
+ declare function pruneStateFilesBeyondCap(stateDir: string, cap: number, deps: PruneStateDeps): Promise<void>;
5439
5055
  /**
5440
5056
  * RunStore port 的宿主无关文件实现(port 见 models/ports.ts)。
5441
5057
  *
@@ -5448,15 +5064,21 @@ interface FileRunStoreOptions {
5448
5064
  * warn——单行损坏不拖垮整个 run 的恢复(与 pi 壳 kill-9 恢复同容忍度)。
5449
5065
  * 版本衔接(快照 codec 归 run-snapshot.ts 单源,D4):存量无 v 行按当前版本
5450
5066
  * 宽容读、写入恒补 v、v 不匹配跳过 + warn(三裁决明细见 parseLine 注释)。
5451
- * - stateFilePath:纯路径计算(<dataRoot>/workflow-state/<runId>.jsonl),不建目录。
5067
+ * - stateFilePath:纯路径计算(<状态目录>/<runId>.jsonl),不建目录。状态目录 =
5068
+ * 构造注入的 stateDir 覆盖,或缺省 <dataRoot>/workflow-state(pi 宿主读侧装配点
5069
+ * 必须传 resolvePiWorkflowStateDir()——见 FileRunStoreOptions.stateDir 与
5070
+ * execution/workflow-state-root.ts 的同源布局论证)。
5452
5071
  *
5453
5072
  * 未 configureCore 即 save/loadAll 会抛 core_host_not_configured(dataRoot 端口
5454
5073
  * 语义,host-services.ts §3.4)——宿主壳必须在初始化最早期注入。
5455
5074
  */
5456
5075
  declare class FileRunStore implements RunStore {
5457
- /** run 状态目录绝对路径(dataRoot 每次现取——宿主覆盖配置即刻生效,对齐
5458
- * data-dir.ts「不缓存路径防测试/宿主切换读到旧值」先例)。 */
5076
+ /** run 状态目录绝对路径(显式覆盖优先——pi 宿主读侧装配点;缺省 dataRoot 每次现取
5077
+ * ——宿主覆盖配置即刻生效,对齐 data-dir.ts「不缓存路径防测试/宿主切换读到旧值」
5078
+ * 先例)。 */
5459
5079
  private stateDir;
5080
+ /** 显式状态目录覆盖(构造注入;见 FileRunStoreOptions.stateDir)。 */
5081
+ private readonly stateDirOverride;
5460
5082
  /** save 节流最小间隔(ms),0 = 禁用。 */
5461
5083
  private readonly saveMinIntervalMs;
5462
5084
  /**
@@ -5482,6 +5104,29 @@ declare class FileRunStore implements RunStore {
5482
5104
  */
5483
5105
  save(run: WorkflowRun): Promise<void>;
5484
5106
  loadAll(): Promise<WorkflowRun[]>;
5107
+ /**
5108
+ * [W4 sweep 判据,F2] 按 runId 同步查 run 状态(注册对账 sweep 的 workflow 收口
5109
+ * 判据)。同步形态:sweep 在 session_start 同步链内运行(runReconcileSweep 同步
5110
+ * 契约),不能 await loadAll——对单 runId 做同步文件读(对齐 sweep 自身的 sync fs
5111
+ * 读先例),逐行解析复用 parseLine(版本衔接 + 形状校验与 loadLatestValidLine
5112
+ * 单源,同步只读不触碰 lastSavedAt 节流记账)。
5113
+ *
5114
+ * 判定(宁挂账不失明——误注销活跃 run 是事故方向,判据保守侧取「不可判定」):
5115
+ * - state 文件不存在 → missing(设计判据「已归档/不存在视同终态」——run 从未
5116
+ * 落盘或已被清理,注册是死亡窗口残留);
5117
+ * - 末条有效快照 status = running → running(活跃,sweep 跳过);
5118
+ * - 末条有效快照 status ≠ running(done)→ terminal + reason(I2:done ⟹ reason
5119
+ * 有值;reason 作 pending unregister 的 status 语义源);
5120
+ * - 文件存在但全部行损坏(无有效快照)→ running(读不出 ≠ 不存在,不补注销)。
5121
+ */
5122
+ findStateByIdSync(runId: string): {
5123
+ kind: "running";
5124
+ } | {
5125
+ kind: "terminal";
5126
+ reason: string | undefined;
5127
+ } | {
5128
+ kind: "missing";
5129
+ };
5485
5130
  /** 单文件从尾向头取第一条有效快照行;整文件无有效行返回 undefined(warn)。 */
5486
5131
  private loadLatestValidLine;
5487
5132
  /**
@@ -5500,15 +5145,12 @@ declare class FileRunStore implements RunStore {
5500
5145
  private parseLine;
5501
5146
  /**
5502
5147
  * 把 workflow-state 目录裁剪到上限个最新 state 文件(mtime 升序删最旧,C1)。
5503
- *
5504
- * 语义对齐 pi jsonl-run-store.pruneStateFilesBeyondCap(逐段同构):
5505
- * - 只删本目录内命中 {@link STATE_FILE_GLOB} 的文件;任何失败都不抛(清理是
5506
- * 旁路维护,不能拖垮持久化主链路):readdir 失败静默放弃本轮(ENOENT =
5507
- * 从未持久化,正常态),单个 unlink 失败(非 ENOENT)warn 留证后继续删
5508
- * 其余——ENOENT 视为并发删除竞态下的已达成目标,不告警;
5509
- * - stat 全集取 mtime,allSettled 部分降级——单文件 stat 失败(并发删除
5510
- * ENOENT 等)静默跳过该文件,不阻断本轮裁剪。
5511
- *
5148
+ *
5149
+ * 主体委托导出单源 {@link pruneStateFilesBeyondCap}(retention 语义两宿主单源,
5150
+ * S4-A7;日志经 deps 注入本模块 logger + `[file-run-store]` tag,行为与收口前
5151
+ * 逐字一致)。磁盘裁剪不动内存 runs Map(内存侧淘汰归
5152
+ * lifecycle.evictDoneRunsBeyondCap,两域独立)。
5153
+ *
5512
5154
  * 上限解析(envName 通道,OR-5 ⑥b 默认开;显式非法值 opt-out 对齐 pi 解析风格):
5513
5155
  * - `envName` 提供 → env 通道:`process.env[envName]` 未设/空 → 按默认上限
5514
5156
  * {@link DEFAULT_STATE_MAX_RUNS} 裁剪(**默认开**——OR-5 修复前的 opt-in
@@ -5518,14 +5160,11 @@ declare class FileRunStore implements RunStore {
5518
5160
  * 宿主如需自管保留可设足够大的正数值);
5519
5161
  * - `envName` 缺省 → 无 env 通道,直接按 `max` 参数裁剪(上限 = max,调用方
5520
5162
  * 自管启用时机)。
5521
- *
5522
- * 本方法只做磁盘裁剪,不动内存 runs Map(内存侧淘汰归
5523
- * lifecycle.evictDoneRunsBeyondCap,两域独立)。
5524
- *
5525
- * @param max 上限(envName 缺省时生效;env 通道启用时被 env 值覆盖)
5526
- * @param envName opt-in 开关 + 上限覆盖 env 变量名(可选;pi 先例
5527
- * `XYZ_SUBAGENT_STATE_MAX_RUNS`)
5528
- */
5163
+ *
5164
+ * @param max 上限(envName 缺省时生效;env 通道启用时被 env 值覆盖)
5165
+ * @param envName opt-in 开关 + 上限覆盖 env 变量名(可选;pi 先例
5166
+ * `XYZ_SUBAGENT_STATE_MAX_RUNS`)
5167
+ */
5529
5168
  pruneStateFilesBeyondCap(max: number, envName?: string): Promise<void>;
5530
5169
  }
5531
5170
 
@@ -6134,8 +5773,8 @@ declare function boundedPrettySerialize(value: unknown, budget: number): string;
6134
5773
  * @zhushanwen/subagent-core — 公共 API barrel(D5 定稿 + post-convergence B-2 扩面)
6135
5774
  *
6136
5775
  * 公共 API 面 = 本文件导出 + package.json exports 的语义子入口
6137
- * (./engines/zcode/reader、./engines/zcode/constants、./engine/paths、./relay-env
6138
- * + ./workflows/* 资产子入口。exports 面即 semver 契约(D5):收窄不放宽——
5776
+ * (./engine/paths、./engine/engine-discovery-scan、./relay-env——[W11/H3] 引擎
5777
+ * 子入口 ./engines/zcode/* 已随内建引擎删除)+ ./workflows/* 资产子入口。exports 面即 semver 契约(D5):收窄不放宽——
6139
5778
  * 新增导出走 minor,本文件刻意不使用 `export *`,逐名列出以使 diff 可审。
6140
5779
  * 内部实现细节(error-recovery / execute-agent-call / worker-script-builder 等
6141
5780
  * engine 编排件)不经 barrel 导出;host-surface 扩面(zsw 回接 U0,2026-08-30)
@@ -6152,6 +5791,6 @@ declare function boundedPrettySerialize(value: unknown, budget: number): string;
6152
5791
  * docs/design/subagent-core-sink-design.md(sink 下沉收口扩面,2026-08-31);
6153
5792
  * 宿主接入示例见包 README(§3.4 core_host_not_configured 恢复指引的落点)。
6154
5793
  */
6155
- declare const CORE_PACKAGE_VERSION = "0.5.1";
5794
+ declare const CORE_PACKAGE_VERSION = "0.7.0";
6156
5795
 
6157
- export { AGENT_REF_EXT, AgentCall, AgentCallOpts, type AgentEntry, AgentEvent, AgentEventLogEntry, AgentOutcome, type AgentProfile, AgentRegistry, AgentResult, type AgentRunner, type ArgKeySet, type ArgMetaOptions, type ArgMetaWarning, type AtomicTmpRef, type AtomicWriteFileOptions, type AtomicWriteOptions, BG_MESSAGE, BgResponse, Budget, CORE_PACKAGE_VERSION, type CachedWorkflowMeta, type CancelHandlerInput, type CancelHandlerResult, CancelResponse, type ChangeListener, type ChannelHandler, type CleanupStaleTmpOptions, type CleanupStaleTmpResult, type CleanupWorktreeOptions, type CloseHandlerInput, type CloseHandlerResult, CloseResponse, ClosedReason, type CollectWorktreePatchOptions, type ConcurrencyPool, type CoreLogger, type CreateConcurrencyPoolOptions, DEFAULT_DATA_ROOT, DEFAULT_ENGINE_ID, DEFAULT_LIST_LIMIT, DEFAULT_PROVIDER_ID, DEFAULT_SAVE_MIN_INTERVAL_MS, DEFAULT_STATE_MAX_RUNS, DEFAULT_WORKFLOW_SAVED_DIR, DEFAULT_WORKFLOW_TMP_DIR, DialogGlobalQueue, type DiscoveredResource, type DiscoveryRoot, DisplayItem, DoneReason, EngineCapabilities, EngineHandle, EngineHandleData, type EnginePort, type EngineRouteOptions, type EngineRouteResult, type EngineRouting, type EngineRoutingInput, type EngineRoutingSource, type EngineRunResult, ExecutionMode, ExecutionOutcome, ExecutionRecord, ExecutionStatus, ExecutionTraceNode, ExternalState, FORK_FROM_DEFAULT_PROMPT, FileRunStore, type FinalizeRunOptions, type ForkFromHandlerInput, type ForkFromHandlerResult, ForkFromResponse, type GenerateWorkflowScriptOptions, type GenerateWorkflowScriptResult, GitRunError, type GlobalConfigReadResult, type HostServices, IDENTITY_CUSTOM_TYPE, INDEX_FILENAME, InteractAction, InteractResult, type InvalidAgentRefMessageOptions, type LauncherDeps, type LifecycleDeps, type LintFinding, type LintResult, type ListFormatOptions, type ListHandlerInput, type ListHandlerResult, ListResponse, type ListWorktreePorcelainOptions, type LogLevel, MAX_LIST_LIMIT, MAX_RETAINED_DONE_RUNS, MAX_TIMER_DELAY_MS, type MessageHandlerInput, type MessageHandlerResult, MessageResponse, ModelConfigService, type ModelConfigServiceInit, type ModelEntry, ModelInfo, type ModelListFormatOptions, type ModelReasoningInfo, NOTIFY_CONTRACT, type NormalizeWorkflowRefOptions, type NormalizedArgs, type NormalizedWorkflowRef, type NotifyDomainPorts, type NotifyLedgerHost, type PatchBaselineAnchor, ProbeReport, type QueuePolicy, RecordStore, type RecordStorePi, type RecoverCrashedRunsHooks, type RecoverCrashedRunsResult, type ResourceKind, type ResourceSource, type RunContext, type RunSnapshot, type RunSpec, type RunState, RunStatus, type RunStore, SAFE_ID_RE, SNAPSHOT_VERSION, SUBAGENT_RECORD_CUSTOM_TYPE, type ScanConfig, SessionView, type StartHandlerInput, type StartHandlerResult, type StatusFilter, type SubagentIdentityData, SubagentListItem, SubagentRecord, type SubagentRecordEntryData, SubagentService, type SubagentServiceInit, SubagentStream, SubprocessAgentRunner, THINKING_ORDER, Trace, type UiChannelRegistry, WORKFLOW_REF_EXT, WORKFLOW_REF_RESERVED_NAMES, type WorkerHandlers, type WorkerHost, WorkerHostImpl, WorkerLogEntry, type WorkflowDirOptions, type WorkflowEntry, type WorkflowMeta, type WorkflowRefInvalidReason, WorkflowRun, type WorkflowRunMeta, type WorkflowRunResult, type WorkflowRunSummary, type WorkflowScanConfig, WorkflowScript, type WorkflowScriptRegistry, WorkflowScriptRegistryImpl, type WorkflowSource, WorktreeManager, type WorktreePatchResult, type ZcodeEngineDeps, ZcodeTaskShapeError, abortRun, argKeysFromMeta, assertSafeId, atomicTmpPathFor, bestEffort, bindNotifyLedgerHost, boundedPrettySerialize, buildEngineModelsPromptAppend, buildSubagentEngineSection, cancelHandler, cleanupStaleTmpFiles, cleanupWorktree, clearSkillPathCache, closeHandler, closeOutInFlightCalls, collectWorktreePatch, computeElapsedSeconds, configureCore, configureNotifyDomain, countAllToolCalls, createConcurrencyPool, createSubagentService, createUiRequestHandlerForMode, createZcodeEngine, deleteWorkflow, deriveOutcome, discoverAgents, discoverResources, discoverWorkflows, displayAgentName, endedMessageGuard, escapeXml, evictDoneRunsBeyondCap, executeNestedWorkflow, finalizeRun, findFlattenedArgKeys, findWorkspaceRoot, forkFromHandler, formatAgentList, formatModelList, formatWorkflowList, fromRunSnapshot, generateWorkflowScript, getAllToolCalls, getBoundNotifyLedger, getCachedFileContent, getCachedParsed, getHostServices, getLogger, getModelConfigService, getOrCreateChannelRegistry, getSubagentService, getWorkflow, getWorkflowByPath, gitRun, hasApiKey, invalidAgentRefMessage, invalidateCache, isProcessAlive, isResumable, isSafeId, isScriptRunning, isTreeDirty, killAllSpawnedChildren, killRecordChildWithEscalation, lintScript, listHandler, listStaleTmpFiles, listWorktreePorcelain, loadWorkflowScriptByPath, loadWorkflows, makeSerializeFailedResult, mapExternalState, maxTurnsToWatchdogMs, maybeCleanupExpiredSessionFiles, messageHandler, normalizeArgsByMeta, normalizeEngineId, normalizeRef, normalizeWorkflowRef, notifyGateAllowsDelivery, parseAgentProfile, parseAtomicTmpPath, parseEngineHandle, parseResourceMeta, parseResourceMetaDetailed, postBudgetUpdate, projectLiveProgress, projectOutcome, readGlobalConfig, readSubagentHistoryMessages, recordToListItem, recoverCrashedRuns, registerPiEngine, registerZcodeEngine, renderXmlSection, resetRebuildFailureInjectionForTest, routeEngine, runAndWait, runSummary, runWorkflow, saveWorkflow, scheduleTimeBudget, setModelConfigService, setSubagentService, sortByCodepoint, splitZcodeModelRef, startHandler, summarizeDescription, syncEnginesFile, terminateRunningRuns, toRunSnapshot, toSubagentRecordEntry, wrapForkFromPrompt, writeAtomicFile, writeAtomicFileSync };
5796
+ export { AGENT_REF_EXT, AgentCall, AgentCallOpts, type AgentEntry, AgentEventLogEntry, type AgentProfile, AgentRegistry, AgentResult, type AgentRunner, type ArgKeySet, type ArgMetaOptions, type ArgMetaWarning, type AtomicTmpRef, type AtomicWriteFileOptions, type AtomicWriteOptions, BG_MESSAGE, BgResponse, Budget, CORE_PACKAGE_VERSION, type CachedWorkflowMeta, type CancelHandlerInput, type CancelHandlerResult, CancelResponse, type ChangeListener, type CleanupStaleTmpOptions, type CleanupStaleTmpResult, type CleanupWorktreeOptions, type CloseHandlerInput, type CloseHandlerResult, CloseResponse, ClosedReason, type CollectWorktreePatchOptions, type ConcurrencyPool, type CreateConcurrencyPoolOptions, type D8CompatZcodeEngineDeps, DEFAULT_LIST_LIMIT, DEFAULT_PROVIDER_ID, DEFAULT_SAVE_MIN_INTERVAL_MS, DEFAULT_STATE_MAX_RUNS, DEFAULT_WORKFLOW_SAVED_DIR, DEFAULT_WORKFLOW_TMP_DIR, DialogGlobalQueue, type DiscoveredResource, DiscoveryRoot, DisplayItem, DoneReason, EnginePort, type EngineRouteOptions, type EngineRouteResult, type EngineRouting, type EngineRoutingInput, type EngineRoutingSource, ExecutionMode, ExecutionOutcome, ExecutionRecord, ExecutionStatus, ExecutionTraceNode, ExternalState, FORK_FROM_DEFAULT_PROMPT, FileRunStore, type FinalizeRunOptions, type ForkFromHandlerInput, type ForkFromHandlerResult, ForkFromResponse, type GenerateWorkflowScriptOptions, type GenerateWorkflowScriptResult, GitRunError, type GlobalConfigReadResult, IDENTITY_CUSTOM_TYPE, INDEX_FILENAME, type InvalidAgentRefMessageOptions, type LauncherDeps, type LifecycleDeps, type LintFinding, type LintResult, type ListFormatOptions, type ListHandlerInput, type ListHandlerResult, ListResponse, type ListWorktreePorcelainOptions, MAX_LIST_LIMIT, MAX_RETAINED_DONE_RUNS, MAX_TIMER_DELAY_MS, type MessageHandlerInput, type MessageHandlerResult, MessageResponse, ModelConfigService, type ModelConfigServiceInit, type ModelEntry, ModelInfo, type ModelListFormatOptions, type ModelReasoningInfo, NOTIFY_CONTRACT, type NormalizeWorkflowRefOptions, type NormalizedArgs, type NormalizedWorkflowRef, type NotifyDomainPorts, type NotifyLedgerHost, type PatchBaselineAnchor, type PruneStateDeps, type QueuePolicy, RecordStore, type RecordStorePi, type RecoverCrashedRunsHooks, type RecoverCrashedRunsResult, type ResourceKind, type ResourceSource, type RunSnapshot, type RunSpec, type RunState, RunStatus, type RunStore, SAFE_ID_RE, SNAPSHOT_VERSION, SUBAGENT_RECORD_CUSTOM_TYPE, type ScanConfig, type StartHandlerInput, type StartHandlerResult, type StatusFilter, type SubagentIdentityData, SubagentListItem, SubagentRecord, type SubagentRecordEntryData, SubagentService, type SubagentServiceInit, SubagentStream, SubprocessAgentRunner, THINKING_ORDER, Trace, WORKFLOW_REF_EXT, WORKFLOW_REF_RESERVED_NAMES, type WorkerHandlers, type WorkerHost, WorkerHostImpl, WorkerLogEntry, type WorkflowDirOptions, type WorkflowEntry, type WorkflowMeta, type WorkflowRefInvalidReason, WorkflowRun, type WorkflowRunMeta, type WorkflowRunResult, type WorkflowRunSummary, type WorkflowScanConfig, WorkflowScript, type WorkflowScriptRegistry, WorkflowScriptRegistryImpl, type WorkflowSource, WorktreeManager, type WorktreePatchResult, ZCODE_FALLBACK_DEFAULT_MODEL, type ZcodeEngineDeps, abortRun, argKeysFromMeta, assertSafeId, atomicTmpPathFor, bestEffort, bindNotifyLedgerHost, boundedPrettySerialize, buildEngineModelsPromptAppend, buildSubagentEngineSection, cancelHandler, cleanupStaleTmpFiles, cleanupWorktree, clearSkillPathCache, closeHandler, closeOutInFlightCalls, collectWorktreePatch, computeElapsedSeconds, configureNotifyDomain, countAllToolCalls, createConcurrencyPool, createSubagentService, createUiRequestHandlerForMode, createZcodeEngine, deleteWorkflow, deriveOutcome, discoverAgents, discoverResources, discoverWorkflows, displayAgentName, endedMessageGuard, escapeXml, evictDoneRunsBeyondCap, executeNestedWorkflow, finalizeRun, findFlattenedArgKeys, findWorkspaceRoot, forkFromHandler, formatAgentList, formatModelList, formatWorkflowList, fromRunSnapshot, generateWorkflowScript, getAllToolCalls, getBoundNotifyLedger, getCachedFileContent, getCachedParsed, getModelConfigService, getOrCreateChannelRegistry, getSubagentService, getWorkflow, getWorkflowByPath, gitRun, hasApiKey, invalidAgentRefMessage, invalidateCache, isProcessAlive, isResumable, isSafeId, isScriptRunning, isTreeDirty, killAllSpawnedChildren, killRecordChildWithEscalation, lintScript, listHandler, listStaleTmpFiles, listWorktreePorcelain, loadWorkflowScriptByPath, loadWorkflows, makeSerializeFailedResult, mapExternalState, maxTurnsToWatchdogMs, maybeCleanupExpiredSessionFiles, messageHandler, normalizeArgsByMeta, normalizeRef, normalizeWorkflowRef, notifyGateAllowsDelivery, parseAgentProfile, parseAtomicTmpPath, parseEngineHandle, parseResourceMeta, parseResourceMetaDetailed, postBudgetUpdate, projectLiveProgress, projectOutcome, pruneStateFilesBeyondCap, readGlobalConfig, readSubagentHistoryMessages, recordToListItem, recoverCrashedRuns, registerNativeSessionReader, registerZcodeEngine, renderXmlSection, resetRebuildFailureInjectionForTest, routeEngine, runAndWait, runSummary, runWorkflow, saveWorkflow, scheduleTimeBudget, setEngineDiscoveryRescanOptions, setModelConfigService, setSubagentService, sortByCodepoint, splitZcodeModelRef, startHandler, summarizeDescription, syncEnginesFile, terminateRunningRuns, toRunSnapshot, toSubagentRecordEntry, wrapForkFromPrompt, writeAtomicFile, writeAtomicFileSync };