@zhushanwen/subagent-core 0.2.0 → 0.5.1

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 (347) hide show
  1. package/README.md +45 -2
  2. package/agents/analyst.md +60 -0
  3. package/agents/coder.md +69 -0
  4. package/agents/debugger.md +66 -0
  5. package/agents/doc-reviewer.md +49 -0
  6. package/agents/explorer.md +63 -0
  7. package/agents/general-purpose.md +32 -0
  8. package/agents/orchestrator.md +61 -0
  9. package/agents/planner.md +53 -0
  10. package/agents/researcher.md +67 -0
  11. package/agents/reviewer.md +73 -0
  12. package/dist/chunk-43ONBFZX.js +240 -0
  13. package/dist/chunk-APZY4IME.js +27 -0
  14. package/dist/chunk-V3VHZ2VX.js +59 -0
  15. package/dist/execution/engine/engines/zcode/constants.cjs +62 -9
  16. package/dist/execution/engine/engines/zcode/constants.d.cts +116 -12
  17. package/dist/execution/engine/engines/zcode/constants.d.ts +116 -12
  18. package/dist/execution/engine/engines/zcode/constants.js +39 -7
  19. package/dist/execution/engine/engines/zcode/reader.d.cts +2 -1
  20. package/dist/execution/engine/engines/zcode/reader.d.ts +2 -1
  21. package/dist/execution/engine/engines/zcode/reader.js +4 -234
  22. package/dist/execution/engine/paths.js +7 -19
  23. package/dist/index.cjs +18234 -1277
  24. package/dist/index.d.cts +5646 -673
  25. package/dist/index.d.ts +5646 -673
  26. package/dist/index.js +17828 -1277
  27. package/dist/{types-BxyAidGf.d.cts → types-Dv4QhSJ_.d.cts} +678 -112
  28. package/dist/{types-BxyAidGf.d.ts → types-Dv4QhSJ_.d.ts} +678 -112
  29. package/package.json +7 -4
  30. package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
  31. package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
  32. package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
  33. package/src/__tests__/m2-append-content-probe.test.ts +0 -1
  34. package/src/__tests__/manifest-store.test.ts +10 -9
  35. package/src/__tests__/record-store-cache.test.ts +0 -2
  36. package/src/__tests__/record-store-index.test.ts +1 -2
  37. package/src/__tests__/review-fix-loop-script.test.ts +93 -3
  38. package/src/__tests__/review-fix-loop-utils.test.ts +31 -10
  39. package/src/__tests__/robustness-low-batch1.test.ts +6 -5
  40. package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
  41. package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
  42. package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
  43. package/src/__tests__/session-runner.test.ts +1 -1
  44. package/src/__tests__/smoke.test.ts +9 -2
  45. package/src/core/__tests__/host-services.test.ts +2 -2
  46. package/src/core/__tests__/logger.test.ts +1 -1
  47. package/src/core/error-message.ts +9 -0
  48. package/src/core/host-services.ts +21 -5
  49. package/src/core/notify-ports.ts +18 -5
  50. package/src/execution/__tests__/agent-profile.test.ts +232 -0
  51. package/src/execution/__tests__/agent-registry.test.ts +370 -0
  52. package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
  53. package/src/execution/__tests__/agents-assembly.test.ts +219 -0
  54. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
  55. package/src/execution/__tests__/chat-engine-routing.test.ts +136 -30
  56. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +5 -4
  57. package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
  58. package/src/execution/__tests__/create-concurrency-pool.test.ts +194 -0
  59. package/src/execution/__tests__/delivery-methods.test.ts +77 -62
  60. package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
  61. package/src/execution/__tests__/descendant-sweep.test.ts +269 -0
  62. package/src/execution/__tests__/dialog-queue.test.ts +199 -1
  63. package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
  64. package/src/execution/__tests__/epipe-fallback.test.ts +31 -24
  65. package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
  66. package/src/execution/__tests__/execute-nesting.test.ts +34 -188
  67. package/src/execution/__tests__/execution-record.test.ts +217 -60
  68. package/src/execution/__tests__/execution-runtime-face.test.ts +272 -0
  69. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +3 -3
  70. package/src/execution/__tests__/finalize-record.test.ts +278 -16
  71. package/src/execution/__tests__/gc-timer.test.ts +57 -2
  72. package/src/execution/__tests__/get-record-for-action-restart.test.ts +14 -12
  73. package/src/execution/__tests__/get-state-handshake.test.ts +127 -0
  74. package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
  75. package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
  76. package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
  77. package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
  78. package/src/execution/__tests__/keep-alive-no-progress.test.ts +280 -0
  79. package/src/execution/__tests__/kill-all-escalation.test.ts +196 -0
  80. package/src/execution/__tests__/lifecycle-manager-idle-timer-identity.test.ts +117 -0
  81. package/src/execution/__tests__/lifecycle-manager.test.ts +39 -0
  82. package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
  83. package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
  84. package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +99 -0
  85. package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +113 -0
  86. package/src/execution/__tests__/model-resolver.test.ts +2 -2
  87. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
  88. package/src/execution/__tests__/nested-visibility.test.ts +2 -0
  89. package/src/execution/__tests__/notify-ledger.test.ts +1249 -0
  90. package/src/execution/__tests__/output-collector.test.ts +117 -6
  91. package/src/execution/__tests__/pi-invocation.test.ts +1 -1
  92. package/src/execution/__tests__/record-store-orphan-revive.test.ts +159 -0
  93. package/src/execution/__tests__/record-store.test.ts +89 -5
  94. package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
  95. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
  96. package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
  97. package/src/execution/__tests__/rpc-mode.test.ts +2 -2
  98. package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
  99. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +19 -9
  100. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +5 -4
  101. package/src/execution/__tests__/run-spawn-edges.test.ts +418 -26
  102. package/src/execution/__tests__/run-spawn-integration.test.ts +3 -3
  103. package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
  104. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
  105. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +16 -8
  106. package/src/execution/__tests__/service-kill-escalation.test.ts +91 -0
  107. package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
  108. package/src/execution/__tests__/session-file-gc.test.ts +35 -0
  109. package/src/execution/__tests__/session-pending.test.ts +471 -0
  110. package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
  111. package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +110 -0
  112. package/src/execution/__tests__/session-runner-close-prune.test.ts +181 -0
  113. package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
  114. package/src/execution/__tests__/session-runner-epipe.test.ts +4 -3
  115. package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +227 -0
  116. package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
  117. package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
  118. package/src/execution/__tests__/settled-watchdog.test.ts +524 -0
  119. package/src/execution/__tests__/spawn-args.test.ts +11 -10
  120. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
  121. package/src/execution/__tests__/spawn-event-adapter.test.ts +1 -1
  122. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
  123. package/src/execution/__tests__/spawned-children.test.ts +155 -11
  124. package/src/execution/__tests__/start-sync-model-guard.test.ts +4 -4
  125. package/src/execution/__tests__/stdin-writer.test.ts +6 -4
  126. package/src/execution/__tests__/stream-sink-retirement.test.ts +6 -6
  127. package/src/execution/__tests__/subagent-actions-core.test.ts +1017 -0
  128. package/src/execution/__tests__/subagent-service-message-close.test.ts +99 -35
  129. package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +174 -0
  130. package/src/execution/__tests__/subagent-service-notify-gate.test.ts +271 -0
  131. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +33 -29
  132. package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +341 -0
  133. package/src/execution/__tests__/subagent-service.test.ts +37 -30
  134. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
  135. package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
  136. package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
  137. package/src/execution/__tests__/temp-prompt.test.ts +1 -1
  138. package/src/execution/__tests__/timeout-integration.test.ts +13 -12
  139. package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
  140. package/src/execution/__tests__/turn-limiter.test.ts +1 -1
  141. package/src/execution/__tests__/ui-request-handler-factory.test.ts +107 -7
  142. package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
  143. package/src/execution/__tests__/ui-request-queue.test.ts +167 -2
  144. package/src/execution/__tests__/worktree-git-ops.test.ts +571 -0
  145. package/src/execution/__tests__/worktree-manager.test.ts +14 -5
  146. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
  147. package/src/execution/__tests__/worktree-reconcile-aging.test.ts +204 -0
  148. package/src/execution/agent-registry.ts +298 -30
  149. package/src/execution/agent-result-mapper.ts +3 -0
  150. package/src/execution/agents-assembly.ts +88 -0
  151. package/src/execution/cold-resurrect.ts +199 -0
  152. package/src/execution/concurrency-pool.ts +71 -9
  153. package/src/execution/dialog-queue.ts +101 -3
  154. package/src/execution/engine/__tests__/common/capability-gate.test.ts +91 -0
  155. package/src/execution/engine/__tests__/common/data-dir.test.ts +1 -1
  156. package/src/execution/engine/__tests__/common/journal-wiring.test.ts +84 -0
  157. package/src/execution/engine/__tests__/common/kill-chain.test.ts +34 -7
  158. package/src/execution/engine/__tests__/common/persona-router.test.ts +4 -5
  159. package/src/execution/engine/__tests__/common/pool-manager.test.ts +211 -51
  160. package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +149 -0
  161. package/src/execution/engine/__tests__/common/session-view-service.test.ts +499 -0
  162. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +56 -99
  163. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +88 -15
  164. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +33 -7
  165. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +1 -1
  166. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +75 -54
  167. package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +128 -0
  168. package/src/execution/engine/__tests__/engine-discovery.test.ts +15 -3
  169. package/src/execution/engine/__tests__/model-prompt.test.ts +15 -3
  170. package/src/execution/engine/__tests__/registry.test.ts +94 -3
  171. package/src/execution/engine/__tests__/routing.test.ts +115 -6
  172. package/src/execution/engine/common/capability-gate.ts +92 -0
  173. package/src/execution/engine/common/journal-wiring.ts +97 -0
  174. package/src/execution/engine/common/kill-chain.ts +42 -10
  175. package/src/execution/engine/common/nesting-guard.ts +66 -0
  176. package/src/execution/engine/common/persona-router.ts +18 -8
  177. package/src/execution/engine/common/pool-manager.ts +332 -78
  178. package/src/execution/engine/common/session-view-service.ts +506 -0
  179. package/src/execution/engine/common/session-view-types.ts +125 -0
  180. package/src/execution/engine/engine-discovery.ts +12 -16
  181. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +174 -28
  182. package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
  183. package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
  184. package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +86 -11
  185. package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
  186. package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
  187. package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
  188. package/src/execution/engine/engines/pi/reader.ts +11 -0
  189. package/src/execution/engine/engines/pi/registration.ts +4 -2
  190. package/src/execution/engine/engines/pi/session-runner.ts +2840 -0
  191. package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
  192. package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
  193. package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
  194. package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
  195. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +301 -0
  196. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json +36 -0
  197. package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
  198. package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +473 -0
  199. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
  200. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
  201. package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
  202. package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
  203. package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +792 -0
  204. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +782 -0
  205. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +168 -0
  206. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
  207. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
  208. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
  209. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
  210. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +65 -47
  211. package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
  212. package/src/execution/engine/engines/zcode/connection.ts +598 -0
  213. package/src/execution/engine/engines/zcode/constants.ts +147 -14
  214. package/src/execution/engine/engines/zcode/golden-sample.ts +42 -34
  215. package/src/execution/engine/engines/zcode/parser.ts +12 -346
  216. package/src/execution/engine/engines/zcode/preparer.ts +22 -150
  217. package/src/execution/engine/engines/zcode/session-channel.ts +968 -0
  218. package/src/execution/engine/engines/zcode/zcode-engine.ts +1023 -250
  219. package/src/execution/engine/host-task-spec.ts +32 -36
  220. package/src/execution/engine/model-validation.ts +177 -0
  221. package/src/execution/engine/port.ts +65 -7
  222. package/src/execution/engine/registry.ts +53 -0
  223. package/src/execution/engine/routing.ts +75 -1
  224. package/src/execution/engine/types.ts +30 -103
  225. package/src/execution/execution-record.ts +222 -144
  226. package/src/execution/finalize-record.ts +181 -85
  227. package/src/execution/idle-gc.ts +28 -0
  228. package/src/execution/lifecycle-manager.ts +27 -3
  229. package/src/execution/lifecycle-predicates.ts +1 -1
  230. package/src/execution/manifest-store.ts +53 -62
  231. package/src/execution/notifier.ts +10 -10
  232. package/src/execution/notify-host.ts +212 -0
  233. package/src/execution/notify-ledger.ts +117 -16
  234. package/src/execution/record-entry.ts +8 -2
  235. package/src/execution/record-store.ts +148 -88
  236. package/src/execution/round-settlement.ts +93 -0
  237. package/src/execution/session-file-gc.ts +96 -62
  238. package/src/execution/session-pending.ts +213 -62
  239. package/src/execution/session-reconstructor.ts +256 -143
  240. package/src/execution/sessions-index.ts +127 -102
  241. package/src/execution/settled-watchdog.ts +311 -0
  242. package/src/execution/subagent-actions-core.ts +686 -0
  243. package/src/execution/subagent-service.ts +1106 -907
  244. package/src/execution/subprocess-agent-runner.ts +144 -97
  245. package/src/execution/types.ts +9 -0
  246. package/src/execution/ui-request-handler-factory.ts +126 -75
  247. package/src/execution/ui-request-queue.ts +50 -19
  248. package/src/execution/worktree-git-ops.ts +397 -0
  249. package/src/execution/worktree-manager.ts +72 -10
  250. package/src/execution/worktree-registry.ts +6 -12
  251. package/src/index.ts +542 -9
  252. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +42 -3
  253. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +3 -5
  254. package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
  255. package/src/orchestration/__tests__/args-meta.test.ts +358 -0
  256. package/src/orchestration/__tests__/args-validator.test.ts +14 -0
  257. package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +312 -0
  258. package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +384 -0
  259. package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
  260. package/src/orchestration/__tests__/file-run-store-prune.test.ts +168 -0
  261. package/src/orchestration/__tests__/file-run-store-throttle.test.ts +168 -0
  262. package/src/orchestration/__tests__/file-run-store.test.ts +390 -0
  263. package/src/orchestration/__tests__/helpers/flush-microtasks.ts +13 -0
  264. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +34 -0
  265. package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +357 -0
  266. package/src/orchestration/__tests__/lifecycle-recover-crashed.test.ts +289 -0
  267. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
  268. package/src/orchestration/__tests__/lifecycle.test.ts +84 -5
  269. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
  270. package/src/orchestration/__tests__/run-snapshot.test.ts +356 -0
  271. package/src/orchestration/__tests__/script-generate.test.ts +314 -0
  272. package/src/orchestration/__tests__/script-lint.test.ts +17 -0
  273. package/src/orchestration/__tests__/test-mocks.ts +2 -0
  274. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +7 -6
  275. package/src/orchestration/__tests__/worker-message-pump-finalize-run.test.ts +229 -0
  276. package/src/orchestration/__tests__/{error-recovery-handlers.test.ts → worker-message-pump-handlers.test.ts} +28 -27
  277. package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
  278. package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
  279. package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
  280. package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +275 -0
  281. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +78 -1
  282. package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
  283. package/src/orchestration/__tests__/workflow-files.test.ts +186 -0
  284. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
  285. package/src/orchestration/__tests__/workflow-run-summary.test.ts +119 -0
  286. package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +124 -0
  287. package/src/orchestration/agent-opts-resolver.ts +8 -8
  288. package/src/orchestration/args-meta.ts +198 -0
  289. package/src/orchestration/args-validator.ts +53 -31
  290. package/src/orchestration/execute-agent-call.ts +25 -79
  291. package/src/orchestration/file-run-store.ts +327 -0
  292. package/src/orchestration/launcher.ts +160 -104
  293. package/src/orchestration/lifecycle.ts +371 -97
  294. package/src/orchestration/models/agent-call.ts +7 -7
  295. package/src/orchestration/models/budget.ts +5 -5
  296. package/src/orchestration/models/ports.ts +4 -4
  297. package/src/orchestration/models/run-runtime.ts +15 -15
  298. package/src/orchestration/models/trace.ts +9 -9
  299. package/src/orchestration/models/types.ts +111 -22
  300. package/src/orchestration/models/workflow-run.ts +28 -28
  301. package/src/orchestration/models/workflow-script.ts +4 -4
  302. package/src/orchestration/run-snapshot.ts +266 -0
  303. package/src/orchestration/script-generate.ts +154 -0
  304. package/src/orchestration/script-lint.ts +123 -90
  305. package/src/orchestration/worker-handle.ts +10 -10
  306. package/src/orchestration/worker-host.ts +10 -10
  307. package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +498 -221
  308. package/src/orchestration/worker-script-builder.ts +401 -346
  309. package/src/orchestration/workflow-files.ts +37 -11
  310. package/src/orchestration/workflow-run-summary.ts +69 -0
  311. package/src/orchestration/workflow-script-registry-impl.ts +31 -9
  312. package/src/shared/__tests__/agent-ref.test.ts +209 -2
  313. package/src/shared/__tests__/atomic-write.test.ts +267 -0
  314. package/src/shared/__tests__/bounded-serialize.test.ts +236 -0
  315. package/src/shared/__tests__/injection-render.test.ts +518 -0
  316. package/src/shared/__tests__/meta-parser.test.ts +151 -0
  317. package/src/shared/__tests__/resource-discovery-host-roots.test.ts +474 -0
  318. package/src/shared/__tests__/resource-discovery.test.ts +261 -217
  319. package/src/shared/agent-ref.ts +143 -2
  320. package/src/shared/atomic-write.ts +323 -0
  321. package/src/shared/bounded-serialize.ts +154 -0
  322. package/src/shared/injection-render.ts +279 -0
  323. package/src/shared/meta-parser.ts +182 -68
  324. package/src/shared/model-ref.ts +15 -2
  325. package/src/shared/resource-discovery.ts +97 -204
  326. package/src/shared/resource-meta.ts +14 -0
  327. package/src/shared/schema-jsonify.ts +1 -1
  328. package/src/shared/xml-injection.ts +9 -9
  329. package/workflows/README.md +9 -9
  330. package/workflows/chain.js +4 -2
  331. package/workflows/map-reduce.js +5 -3
  332. package/workflows/parallel.js +5 -3
  333. package/workflows/review-fix-loop-utils.cjs +165 -92
  334. package/workflows/review-fix-loop-utils.d.cts +287 -0
  335. package/workflows/review-fix-loop.js +18 -7
  336. package/workflows/scatter-gather.js +4 -2
  337. package/dist/chunk-3VOERJPJ.js +0 -22
  338. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  339. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  340. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  341. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  342. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  343. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -580
  344. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  345. package/src/execution/execute-options-mapper.ts +0 -115
  346. package/src/execution/session-runner.ts +0 -1789
  347. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
@@ -5,37 +5,44 @@
5
5
  // 从"自己 spawn pi"改为"委托 SubagentService.executeAndAwait"。
6
6
  // MF-3: 从 orchestration/infra 迁入 execution,同层委托 SubagentService。
7
7
  //
8
+ // [D6 任务形状合流] AgentCallOpts 已是 EnginePort.run 的单一任务形状——本类直传 opts
9
+ // 给 engine.run(无 ExecuteOptions/AgentTaskSpec 中间态映射);pi 边界的一次直出在
10
+ // PiEngine.agentCallToExecuteOptions。mergeTimeoutSignal(原 execute-options-mapper
11
+ // 的运行期件,D-A9)随 mapper 删除迁入本文件(唯一消费点)。
12
+ //
8
13
  // 接线层级:
9
14
  // [跨模块 port] implements AgentRunner(orchestration/models/ports.ts)
10
- // [模块内直调] mapToExecuteOptions + mergeTimeoutSignal(execute-options-mapper
11
- // [P4 路由层] engine/routing.ts routeEngine(三层优先级 + probe + fallback 三守卫,D9)
15
+ // [模块内直调] mergeTimeoutSignal(本文件,D-A9
16
+ // [P4 路由层] engine/routing.ts routeEngineForHost(D3-② 路由单点:三层优先级 +
17
+ // pi 同步短路 + probe + fallback 三守卫,D9)
18
+ // [公共预检] engine/common/capability-gate(D3-④:capabilities 驱动的调用前拒绝)
12
19
  // [引擎层] EnginePort.run(pi = 本地 DI 绑定实例;非 pi = registry.getEngine 动态获取)
20
+ // [公共 journal] engine/common/journal-wiring(D3-③:writer + retarget + 回填单实现)
13
21
  // [模块内直调] this.subagentService.executeAndAwait(PiEngine 内部委托目标)
14
22
  //
15
23
  // 设计基线:
16
- // D-A2(映射归 adapter)/ D-A8(onEvent 桥接)/ D-A9(timeoutMs 合并 signal)/
24
+ // D-A8(onEvent 桥接)/ D-A9(timeoutMs 合并 signal)/
17
25
  // D-008(model 填底,不调 resolveModel)/ BC-9(timeoutMs 行为)/ BC-10(live-record 进度)
18
26
 
19
27
  import type { AgentRunner } from "../orchestration/models/ports.ts";
20
28
  import type { AgentCallOpts, AgentResult } from "../orchestration/models/types.ts";
21
29
  import type { AgentEvent } from "../shared/agent-event.ts";
22
- import { getEngineDataDir } from "./engine/common/data-dir.ts";
23
- import { JournalWriter } from "./engine/common/event-journal.ts";
24
- import { createPiEngine, PI_POOL_KEY } from "./engine/engines/pi/registration.ts";
25
- import { executeOptionsToTaskSpec } from "./engine/engines/pi/task-spec-mapper.ts";
26
- import { resolveJournalPath } from "./engine/paths.ts";
30
+ import { assertTaskShapeSupported } from "./engine/common/capability-gate.ts";
31
+ import { HOST_TIMEOUT_ABORT_REASON } from "./engine/common/kill-chain.ts";
32
+ import { JOURNAL_INITIAL_POOL_KEY, wireEventJournal } from "./engine/common/journal-wiring.ts";
33
+ import { createPiEngine } from "./engine/engines/pi/registration.ts";
27
34
  import type { EnginePort, RunContext } from "./engine/port.ts";
28
- import { routeEngine, resolveEngineRouting, type EngineRouteResult, type EngineRoutingInput } from "./engine/routing.ts";
29
- import { getEngine, hasEngine, listEngines } from "./engine/registry.ts";
30
- import type { AgentOutcome, EngineHandle } from "./engine/types.ts";
31
- import { mapToExecuteOptions, mergeTimeoutSignal } from "./execute-options-mapper.ts";
35
+ import { validateModelForEngine } from "./engine/model-validation.ts";
36
+ import { routeEngineForHost, type EngineRouteResult, type EngineRoutingInput } from "./engine/routing.ts";
37
+ import { getEngine } from "./engine/registry.ts";
38
+ import type { AgentOutcome } from "./engine/types.ts";
32
39
  import { getModelConfigService } from "./model-config-service.ts";
33
40
  import type { ModelInfo } from "./model-resolver.ts";
34
41
  import { modelRefFromVerified } from "../shared/model-ref";
35
- import { registerSpawnedChildForRecord } from "./session-runner.ts";
42
+ import { registerSpawnedChildForRecord } from "./engine/engines/pi/session-runner.ts";
36
43
  import type { SubagentStream } from "./stream-sink.ts";
37
44
  import type { SubagentService } from "./subagent-service.ts";
38
- import type { ExecuteOptions } from "./types.ts";
45
+ import { toErrorMessage } from "../core/error-message.ts";
39
46
 
40
47
  // ── 构造依赖(per-session 注入)──
41
48
 
@@ -71,10 +78,12 @@ export interface SubprocessAgentRunnerDeps {
71
78
  * 非 pi 引擎(P4 路由可达:frontmatter/调用参数/全局默认指定)经 registry.getEngine
72
79
  * 动态获取——「引擎身份」的归属边界在注册表,SAR 不感知具体引擎实现。
73
80
  *
74
- * [P4 配置路由] 每次运行经 engine/routing.ts 解析三层优先级(调用参数 opts.engine >
75
- * agent frontmatter engine > 全局默认 'pi')+ probe + fallback 三守卫(D9)。路由失败
76
- * (engine_not_found / engine_probe_failed / model_not_available)不 reject,入
77
- * result.error——与 executeAgentCall 契约一致。
81
+ * [P4 配置路由] 每次运行经 engine/routing.ts routeEngineForHost(D3-② 路由单点:
82
+ * 唯一实现承载三层优先级(调用参数 opts.engine > agent frontmatter engine > 全局默认
83
+ * 'pi')+ pi 同步短路 + registry 注入 + probe/fallback 三守卫,D9;本类与
84
+ * SubagentService.execute 是其仅有的两调用点)。路由失败(engine_not_found /
85
+ * engine_probe_failed / model_not_available)与预检命中(engine_capability_unsupported,
86
+ * D3-④)不 reject,入 result.error——与 executeAgentCall 契约一致。
78
87
  */
79
88
  export class SubprocessAgentRunner implements AgentRunner {
80
89
  private readonly subagentService: SubagentService;
@@ -85,7 +94,8 @@ export class SubprocessAgentRunner implements AgentRunner {
85
94
  constructor(deps: SubprocessAgentRunnerDeps) {
86
95
  this.subagentService = deps.subagentService;
87
96
  this.ctxModel = deps.ctxModel;
88
- this.piEngine = createPiEngine(() => this.subagentService);
97
+ // [D4 聚合连带] asEngineService 显式视图适配(原结构化直绑依赖查询面 public)。
98
+ this.piEngine = createPiEngine(() => this.subagentService.asEngineService);
89
99
  }
90
100
 
91
101
  /**
@@ -99,16 +109,21 @@ export class SubprocessAgentRunner implements AgentRunner {
99
109
  }
100
110
 
101
111
  /**
102
- * 执行单次 agent 调用:路由(P4)→ EnginePort.run → PiEngine 委托
112
+ * 执行单次 agent 调用:路由(P4)→ 预检(D3-④)→ EnginePort.run → PiEngine 委托
103
113
  * SubagentService.executeAndAwait。
104
114
  *
105
115
  * 接线链路:
106
- * routeEngine(三层 + probe + 守卫)→ mergeTimeoutSignal → mapToExecuteOptions →
107
- * AgentTaskSpec → engine.runPiEngine:spec ExecuteOptions 还原 + engine 留痕)→
108
- * executeAndAwait AgentOutcome AgentResult
116
+ * routeEngineForHost(D3-② 路由单点:三层 + pi 同步短路 + probe + 守卫)→
117
+ * assertTaskShapeSupportedD3-④ 预检 capabilities 化)→ mergeTimeoutSignal
118
+ * engine.run(opts 直传——D6 合流:AgentCallOpts EnginePort 任务形状,零映射;
119
+ * PiEngine 内一次直出 ExecuteOptions + engine 留痕) → executeAndAwait →
120
+ * AgentOutcome → AgentResult
109
121
  *
110
122
  * 错误处理:不 reject。
111
123
  * - 路由失败(未注册 id / probe 失败 + 守卫或 strict)→ AgentResult.error(错误码前缀)
124
+ * - 预检命中(capabilities 不支持的任务形状参数)→ AgentResult.error
125
+ * (engine_capability_unsupported——[D3-④] workflow 域 zcode+worktree 由漏拦变
126
+ * 拦截,本单元唯一有意行为变化;拒绝在 journal/run 之前,无进程无 journal 产物)
112
127
  * - executeAndAwait 内部失败 → 返回 AgentResult(success:false) → 已映射 error 字段
113
128
  * - executeAndAwait throw(嵌套超限 BC-12)→ catch → AgentResult.error
114
129
  * - spawn 级失败已由 runSpawn 内部收口为 failed AgentResult(不逃逸)
@@ -121,69 +136,57 @@ export class SubprocessAgentRunner implements AgentRunner {
121
136
  ): Promise<AgentResult> {
122
137
  const startedAt = Date.now();
123
138
 
124
- // ── P4 路由:三层优先级 + probe + fallback 三守卫(D9①/D7)──
125
- // 路由在最前——引擎身份决定 journal 路径与后续一切执行面;失败(未注册 id /
126
- // probe 失败 + strict/守卫)按「不 reject」契约转 result.error。
127
- // pi 快路径同步短路(不经 routeEngine 的 await):pi 恒免探、无 fallback 可言、
128
- // engineFor('pi') 本地 DI 绑定恒可用——不引入微任务边界,缺省路径时序与 P1 接线
129
- // 前完全一致(下游依赖「run 内首个 await 前已触达 executeAndAwait」的时序契约)。
130
- let routingInput: EngineRoutingInput;
139
+ // ── P4 路由(D3-② 单点:routeEngineForHost)+ D3-④ 预检 ──
140
+ // 路由在最前——引擎身份决定 journal 路径与后续一切执行面。pi 快路径同步短路
141
+ //(routed Promise,零微任务——缺省路径时序与 P1 接线前完全一致,下游依赖
142
+ // 「run 内首个 await 前已触达 executeAndAwait」的时序契约)。路由失败(未注册
143
+ // id / probe 失败 + strict/守卫)与预检命中(capabilities 驱动,含 worktree——
144
+ // workflow 域漏拦缺口修复)一并按「不 reject」契约转 result.error。
131
145
  let route: EngineRouteResult;
132
146
  try {
133
- routingInput = this.buildRoutingInput(opts);
134
- const routing = resolveEngineRouting(routingInput);
135
- if (routing.engineId === "pi") {
136
- route = {
137
- engine: this.piEngine,
138
- engineId: "pi",
139
- requestedEngineId: "pi",
140
- source: routing.source,
141
- };
142
- } else {
143
- route = await routeEngine({
144
- routing: routingInput,
145
- taskModel: opts.model,
146
- strict: getModelConfigService()?.getGlobalConfig().engineRouting?.strict === true,
147
- probe: (engineId) => this.engineFor(engineId).probe(),
148
- getEngineFn: (engineId) => this.engineFor(engineId),
149
- // pi 经本地 DI 绑定恒可用(不依赖 registry 全局注册态——SAR 持有服务引用),
150
- // has/list 注入同一口径,engine_not_found 文案不会把本地 pi 漏报成未注册
151
- hasEngineFn: (engineId) => engineId === "pi" || hasEngine(engineId),
152
- listEnginesFn: () => (hasEngine("pi") ? listEngines() : ["pi", ...listEngines()]),
153
- });
147
+ const routed = routeEngineForHost({
148
+ routing: this.buildRoutingInput(opts),
149
+ taskModel: opts.model,
150
+ strict: getModelConfigService()?.getGlobalConfig().engineRouting?.strict === true,
151
+ probe: (engineId) => this.engineFor(engineId).probe(),
152
+ piEngine: this.piEngine,
153
+ });
154
+ route = routed instanceof Promise ? await routed : routed;
155
+ // [D3-④] SAR 路径预检调用点(run 前同模块调用;唯一实现 = common/capability-gate)。
156
+ // pi 全参数放行(V4⑤ 反向守护);zcode 拦 fork/conversation/maxTurns/worktree。
157
+ // [D6 合流] opts(AgentCallOpts)直传预检——TaskShapeForGate 是结构子集,
158
+ // conversation/fork/worktree/maxTurns 均在合流形状字段表内。
159
+ assertTaskShapeSupported(route.engineId, route.engine.capabilities(), opts);
160
+ // [u-h2 D2-2 调用点②] workflow 域非 pi 引擎的派发同步期 model 校验——与 chat
161
+ // 路径(subagent-service.executeViaEngine)共享同一入口 validateModelForEngine
162
+ // 与同一错误文案(V2-4④:agent({engine:'zcode', model:<pi id>}) 同步期报
163
+ // 「引擎与模型不配套」,不再落 engine.run prepare 期晚炸)。校验对象是显式
164
+ // opts.model(frontmatter model 的解析归 pi 链,workflow 域非 pi 路径现状不消费
165
+ // ——维持现状语义不扩散)。「不 reject」契约:throw 由本 try catch 收口
166
+ // errorResult,不进入 journal 创建与 engine.run(零 record/spawn 副作用)。
167
+ if (route.engineId !== "pi") {
168
+ validateModelForEngine(route.engine, opts.model);
154
169
  }
155
170
  } catch (err) {
156
- // buildRoutingInput 的 agent 解析期校验(未注册 frontmatter engine)与路由失败
157
- // (probe + strict/守卫)一并在此收口——「不 reject」契约
171
+ // buildRoutingInput 的 agent 解析期校验(未注册 frontmatter engine)、路由失败
172
+ //(probe + strict/守卫)与预检拒绝(engine_capability_unsupported)一并在此
173
+ // 收口——「不 reject」契约
158
174
  return errorResult(err, startedAt);
159
175
  }
160
176
 
161
177
  // ── P2 event journal 接线(设计 D6 第②级;对齐点③:路径权威 = 引擎池 key)──
162
- // host onEvent 回调内统一落盘(全引擎免费获得②级数据源)。初始 poolKey pi
163
- // 缺省占位(pi 'shared');非池化稳定引擎(zcode)在 prepare 期经
164
- // RunContext.onPoolResolved 声明实际池 key → writer.retarget——保证 journal 落盘
165
- // 路径与 handle.poolKey 同源(handle.journalPath 由本方法 run 返回后回填)。
178
+ // [D3-③] writer + retarget + 回填收敛 common/journal-wiring(与 chat 域同一实现):
179
+ // 初始 poolKey 占位 'shared'(pi 恒终值);非池化稳定引擎(zcode)在 prepare 期经
180
+ // RunContext.onPoolResolved 声明实际池 key → retarget——保证 journal 落盘路径与
181
+ // handle.poolKey 同源(handle.journalPath 由本方法 run 返回后回填)。
166
182
  //
167
183
  // taskId 为宿主侧任务标识(journal 文件名与池引用计数 key)——executeAndAwait
168
184
  // 不外露内部 record id(取真实 id 需 hook record store 且改 createRecordForMode
169
185
  // 签名,影响面大;P4 决策:保留占位,`sa-` 前缀与 record id 同构。影响面:record
170
- // GC 时无法按 taskId 联动删 journal(journal 依赖 30 TTL 自然回收),read ②级
171
- // handle.journalPath 自描述定位不受影响)。
186
+ // GC 时无法按 taskId 联动删 journal(journal 依赖 TTL 兜底回收,见 D8 分域裁决),
187
+ // read ②级经 handle.journalPath 自描述定位不受影响)。
172
188
  const taskId = `sa-${crypto.randomUUID()}`;
173
- const journal = new JournalWriter({
174
- path: resolveJournalPath(getEngineDataDir(), route.engineId, PI_POOL_KEY, taskId),
175
- taskId,
176
- engineId: route.engineId,
177
- });
178
- const retargetJournal = (poolKey: string): void => {
179
- journal.retarget(resolveJournalPath(getEngineDataDir(), route.engineId, poolKey, taskId));
180
- };
181
- // 包装:先写 journal 再转发原 onEvent(原 onEvent 未传时也恒传包装版——
182
- // 下游 onEvent 通道是事件生成后的纯转发,无行为分支,仅多一次入队)
183
- const journalingOnEvent = (event: AgentEvent): void => {
184
- journal.append(event);
185
- onEvent?.(event);
186
- };
189
+ const journal = wireEventJournal({ engineId: route.engineId, taskId, forwardEvents: onEvent });
187
190
 
188
191
  try {
189
192
  // ── [U1 D2] RunContext.modelRef 接入:ctxModel 继承路径的孪生守卫 ──
@@ -202,40 +205,39 @@ export class SubprocessAgentRunner implements AgentRunner {
202
205
  // ── D-A9: timeoutMs 合并 signal(超时 abort 带 HOST_TIMEOUT_ABORT_REASON 标记)──
203
206
  const mergedSignal = mergeTimeoutSignal(signal, opts.timeoutMs);
204
207
 
205
- // ── D-A2 + D-008: AgentCallOpts → ExecuteOptions 映射 ──
206
- const mappedOpts: ExecuteOptions = mapToExecuteOptions(opts, this.ctxModel);
207
-
208
208
  // ── P1/P4 引擎接线:EnginePort.run ──
209
209
  const runCtx: RunContext = {
210
210
  taskId,
211
- poolKey: PI_POOL_KEY,
211
+ poolKey: JOURNAL_INITIAL_POOL_KEY,
212
212
  signal: mergedSignal,
213
- onEvent: journalingOnEvent,
213
+ onEvent: journal.onEvent,
214
214
  ctxModel: this.ctxModel,
215
215
  ...(route.engineFallback !== undefined ? { engineFallback: route.engineFallback } : {}),
216
- onPoolResolved: retargetJournal,
216
+ onPoolResolved: journal.onPoolResolved,
217
217
  // [U0 D10] 终止链路径①:引擎 spawn 的子进程注册进 session-runner 的
218
218
  // spawnedChildren 记账(dispose killAll 收割兜底对 workflow 域引擎任务生效);
219
219
  // taskId('sa-' 前缀)即记账 key,与 chat 域 kickOffEngineRun 的 record.id 同构
220
220
  onChildSpawned: (child) => registerSpawnedChildForRecord(taskId, child),
221
221
  ...(stream !== undefined ? { stream } : {}),
222
- // 解耦形态(有 schemaEnv 无 schema)的兜底通道——耦合形态下引擎从 task.schema
223
- // 派生等值,此值被忽略(见 RunContext.schemaEnv 注释)
224
- ...(mappedOpts.schemaEnv !== undefined ? { schemaEnv: mappedOpts.schemaEnv } : {}),
222
+ // [D6 合流] 解耦形态(有 schemaEnv 无 schema)不再经 RunContext.schemaEnv
223
+ // 兜底通道——schemaEnv 已在合流形状 AgentCallOpts.schemaEnv 内,pi 直出
224
+ // (agentCallToExecuteOptions)以「schema 派生优先、schemaEnv 兜底」取值,
225
+ // 与原 ctx 兜底链路逐字节等值。
225
226
  };
226
227
  const { handle, outcome } = await route.engine.run(
227
- // 泛化为中立声明(PiEngine 内部再还原回 ExecuteOptions——往返保真,
228
- // engines/pi/__tests__/task-spec-mapper.test.ts 逐字段锁定)
229
- executeOptionsToTaskSpec(mappedOpts),
228
+ // [D6 合流] opts 直传——AgentCallOpts 即 EnginePort 任务形状(缺省路径零映射;
229
+ // pi 边界一次直出由 PiEngine.agentCallToExecuteOptions 承担,逐字段等值由
230
+ // engines/pi/__tests__/spawn-opts-direct.test.ts 对照表锁定)
231
+ opts,
230
232
  runCtx,
231
233
  );
232
234
  // handle.journalPath 回填(§3.3.6:read ②级的自描述定位符——运行期落盘路径
233
235
  // 权威在 writer,handle 记录最终路径供跨重启 read 消费)
234
- backfillJournalPath(handle, journal.path);
236
+ journal.backfillHandle(handle);
235
237
  return outcomeToRunnerResult(outcome);
236
238
  } catch (err) {
237
239
  // executeAndAwait throw(嵌套超限 ForkDepthExceededError,BC-12)或未预期异常 → 不 reject,入 error。
238
- const message = err instanceof Error ? err.message : String(err);
240
+ const message = toErrorMessage(err);
239
241
  return {
240
242
  content: "",
241
243
  durationMs: Date.now() - startedAt,
@@ -252,9 +254,11 @@ export class SubprocessAgentRunner implements AgentRunner {
252
254
  // ── 内部 ──
253
255
 
254
256
  /**
255
- * 引擎获取:pi 走 per-session DI 绑定(mock 语义 + 生产同单例,P1 行为零变化);
256
- * pi 经 registry.getEngine 动态获取(P4:引擎身份归属注册表,未注册 id 抛
257
- * EngineNotFoundError——路由期已前置校验,这里是防御性兜底)。
257
+ * 引擎获取(routeEngineForHost 的 probe 注入体):pi 走 per-session DI 绑定(mock
258
+ * 语义 + 生产同单例,P1 行为零变化);非 pi 经 registry.getEngine 动态获取(P4
259
+ * 引擎身份归属注册表,未注册 id 抛 EngineNotFoundError——路由期已前置校验,这里
260
+ * 是防御性兜底)。[D3-②] get/has/list 的路由期注入已由 routeEngineForHost 内部
261
+ * 承载(本地 pi 恒可用口径),本方法只剩 probe 一个消费点(pi 请求同步短路恒免探)。
258
262
  */
259
263
  private engineFor(engineId: string): EnginePort {
260
264
  if (engineId === "pi") return this.piEngine;
@@ -280,21 +284,16 @@ export class SubprocessAgentRunner implements AgentRunner {
280
284
  }
281
285
  }
282
286
 
283
- /** 路由期错误 → AgentResult.error(错误码前缀格式保留——engine_not_found 等)。 */
287
+ /** 路由期/预检错误 → AgentResult.error(错误码前缀格式保留——engine_not_found 等)。 */
284
288
  function errorResult(err: unknown, startedAt: number): AgentResult {
285
289
  return {
286
290
  content: "",
287
291
  durationMs: Date.now() - startedAt,
288
- error: err instanceof Error ? err.message : String(err),
292
+ error: toErrorMessage(err),
289
293
  toolCalls: [],
290
294
  };
291
295
  }
292
296
 
293
- /** handle.journalPath 回填(一次写者:SAR 是 handle 的首个消费者)。 */
294
- function backfillJournalPath(handle: EngineHandle, journalPath: string): void {
295
- handle.data.journalPath = journalPath;
296
- }
297
-
298
297
  /**
299
298
  * AgentOutcome → workflow AgentResult:剥离引擎层新增字段(engineId/engineFallback/
300
299
  * exitCode——engineFallback 经 record(pi 路径)/outcome(zcode 路径)留痕,GUI 投影
@@ -305,6 +304,9 @@ function backfillJournalPath(handle: EngineHandle, journalPath: string): void {
305
304
  function outcomeToRunnerResult(outcome: AgentOutcome): AgentResult {
306
305
  return {
307
306
  content: outcome.content,
307
+ // [D5-③] 失败分诊标签透传(pi 引擎产出;zcode 不产 failureKind,缺省 =
308
+ // unknown = 可重试)。成功路径 undefined 不落键。
309
+ ...(outcome.failureKind !== undefined ? { failureKind: outcome.failureKind } : {}),
308
310
  parsedOutput: outcome.parsedOutput,
309
311
  usage: outcome.usage,
310
312
  durationMs: outcome.durationMs,
@@ -315,3 +317,48 @@ function outcomeToRunnerResult(outcome: AgentOutcome): AgentResult {
315
317
  toolCalls: outcome.toolCalls,
316
318
  };
317
319
  }
320
+
321
+ /**
322
+ * D-A9: per-call timeoutMs 合并进 AbortSignal([D6 合流迁入]——原定义在已删除的
323
+ * execution/execute-options-mapper.ts,本类是唯一消费点,运行期件随消费方落位)。
324
+ *
325
+ * 墙钟 timeoutMs(per-call)+ 外部 signal(run 级 abort)都生效。
326
+ * 缺此合并则 agent({timeoutMs:5000}) 静默无效(BC-9)。
327
+ *
328
+ * @param signal 外部 signal(workflow run 级 controller.signal)
329
+ * @param timeoutMs per-call 墙钟超时;undefined/<=0 → 不设超时,原样返回 signal
330
+ * @returns 合并后的 signal(timeoutMs 或外部 signal 任一 abort 都触发)
331
+ */
332
+ export function mergeTimeoutSignal(
333
+ signal: AbortSignal,
334
+ timeoutMs?: number,
335
+ ): AbortSignal {
336
+ if (!timeoutMs || timeoutMs <= 0) {
337
+ return signal;
338
+ }
339
+
340
+ const controller = new AbortController();
341
+ // 超时 abort 带 reason 标记(对齐点④):引擎合成终态时判别「宿主超时」
342
+ // (engine_timeout 公共合成)vs「外部 cancel」(中止标记)——pi 链路不读 reason,
343
+ // 行为不变。外部 signal abort 不带标记(用户/编排层 cancel 语义)。
344
+ const timer = setTimeout(() => controller.abort(HOST_TIMEOUT_ABORT_REASON), timeoutMs);
345
+ timer.unref();
346
+
347
+ const onExternalAbort = (): void => controller.abort();
348
+ if (signal.aborted) {
349
+ controller.abort();
350
+ } else {
351
+ signal.addEventListener("abort", onExternalAbort, { once: true });
352
+ }
353
+
354
+ controller.signal.addEventListener(
355
+ "abort",
356
+ () => {
357
+ clearTimeout(timer);
358
+ if (!signal.aborted) signal.removeEventListener("abort", onExternalAbort);
359
+ },
360
+ { once: true },
361
+ );
362
+
363
+ return controller.signal;
364
+ }
@@ -9,6 +9,7 @@
9
9
 
10
10
  import type { GuiRenderResult } from "@xyz-agent/extension-protocol";
11
11
 
12
+ import type { AgentFailureKind } from "../orchestration/models/types.ts";
12
13
  import type { ModelInfo, ModelRegistryLike } from "./model-resolver.ts";
13
14
 
14
15
  // ============================================================
@@ -318,6 +319,12 @@ export interface AgentResult {
318
319
  durationMs: number;
319
320
  success: boolean;
320
321
  error?: string;
322
+ /**
323
+ * [D5-③] 失败分诊结构化标签(类型 SSOT 在 orchestration/models/types.ts 的
324
+ * AgentFailureKind——消费语义「unknown=可重试」与其文档同源)。collectResult 对
325
+ * 最终 error 分类后写入;缺省 = unknown(可重试)。type-only 引用零运行时依赖。
326
+ */
327
+ failureKind?: AgentFailureKind;
321
328
  sessionId: string;
322
329
  toolCalls: ToolCall[];
323
330
  usage?: AgentUsageTotal;
@@ -831,6 +838,8 @@ export interface SubagentRecord {
831
838
  status: ExecutionStatus;
832
839
  /** L2 关闭原因子枚举(仅 status="closed" 时有意义)。SP-1 新增。 */
833
840
  closedReason?: ClosedReason;
841
+ /** 终态三态对外语义(U3 C-outcome)。磁盘重建源一等直读;无字段的存量兜底走 projectOutcome。 */
842
+ outcome?: ExecutionOutcome;
834
843
  mode: ExecutionMode;
835
844
  startedAt: number;
836
845
  /** 根 Pi session ID(session 隔离过滤用)。递归链上所有层 record 同值。 */
@@ -20,7 +20,13 @@
20
20
 
21
21
  import { getLogger } from "../core/logger.ts";
22
22
 
23
- import { DialogGlobalQueue, type UiRequest, type UiRequestHandler, type UiResponse } from "./dialog-queue.ts";
23
+ import {
24
+ DialogGlobalQueue,
25
+ isValidDialogTimeout,
26
+ type UiRequest,
27
+ type UiRequestHandler,
28
+ type UiResponse,
29
+ } from "./dialog-queue.ts";
24
30
  import { type HostMode, resolveHostMode } from "./host-mode.ts";
25
31
  import type { UiChannelRegistry } from "./ui-channels.ts";
26
32
  import { isDialogMethod } from "./ui-interaction-model.ts";
@@ -157,87 +163,132 @@ function coerceUiResponse(raw: unknown, reqId: string): UiResponse {
157
163
  * input(title: string, placeholder?: string, opts?): Promise<string | undefined>
158
164
  * editor(title: string, prefill?: string): Promise<string | undefined>
159
165
  * 注意:SDK 是位置参数(非对象参数);返回 undefined 表示用户取消。
166
+ * opts 为 ExtensionUIDialogOptions(signal?/timeout?,timeout 毫秒,SDK auto-dismiss
167
+ * 带倒计时展示)——LC-3/T2⑦ 协同:请求方显式传 timeout 时透传给 SDK,SDK 层超时
168
+ * (正常路径,用户可见倒计时)先于队列级兜底 settle;队列级上界(dialog-queue,
169
+ * 未传挂 30min 默认)兜住 SDK timeout 未生效的形态(host 实现不完整 / channel handler
170
+ * 路径不经 SDK)。两层取先到,settle 恰一次由 DialogGlobalQueue 的 settled 标志保证。
171
+ * editor 的 SDK 签名无 opts,不透传(其上界只由队列级兜底承担)。
160
172
  *
161
173
  * Stage 4 风险点:TUI 下 ask_user channel 未注册时,select 会以普通列表渲染
162
174
  * (title 可能含 marker)。channel 注册后由 createRealHandler 优先走 channel handler,
163
175
  * 不进这里。editor 不可用/抛错时降级 cancelled + warn,不卡队列。 */
176
+ /** select/confirm/input 的 SDK 第三参(opts):请求方传了**合法** timeout(>0 且有限,
177
+ * 判定源 = dialog-queue 的 isValidDialogTimeout,与队列层上界同一权威)才透传——
178
+ * 未传或非法(0/负数/NaN/±Infinity)时不加第三参,参数个数与旧调用完全一致(严格
179
+ * additive)。非法值透传会让 SDK 收到语义反转的 opts(<=0 可能立即 auto-dismiss),
180
+ * 且与队列层「非法回落默认上界」的判定不一致(A2-3);不透传时数组为空,SDK 无界
181
+ * 由队列层默认上界(30min)兜底。
182
+ * 返回元组联合以支持 spread 到固定签名(TS2556)。 */
183
+ function sdkTimeoutArg(req: UiRequest): [] | [{ timeout: number }] {
184
+ return isValidDialogTimeout(req.timeout) ? [{ timeout: req.timeout }] : [];
185
+ }
186
+
187
+ /** 各 method 的默认转发器(表驱动分发;dialog 类 await SDK,fire-and-forget 类同步调用后回 ack)。
188
+ * 落空(未知 method)语义留在 defaultDialogForward,与原 default 分支逐字节一致。 */
189
+ type DialogMethodForwarder = (req: UiRequest, ui: HostUIChannel) => Promise<UiResponse>;
190
+
191
+ async function forwardSelect(req: UiRequest, ui: HostUIChannel): Promise<UiResponse> {
192
+ const selected = await ui.select(req.title ?? "", req.options ?? [], ...sdkTimeoutArg(req));
193
+ return selected === undefined ? { cancelled: true } : { value: selected };
194
+ }
195
+
196
+ async function forwardConfirm(req: UiRequest, ui: HostUIChannel): Promise<UiResponse> {
197
+ // SDK confirm 必传 message(req.message 缺失时降级空串,不报错阻塞)
198
+ const confirmed = await ui.confirm(req.title ?? "", req.message ?? "", ...sdkTimeoutArg(req));
199
+ return { confirmed };
200
+ }
201
+
202
+ async function forwardInput(req: UiRequest, ui: HostUIChannel): Promise<UiResponse> {
203
+ const text = await ui.input(req.title ?? "", req.placeholder, ...sdkTimeoutArg(req));
204
+ return text === undefined ? { cancelled: true } : { value: text };
205
+ }
206
+
207
+ async function forwardEditor(req: UiRequest, ui: HostUIChannel): Promise<UiResponse> {
208
+ // SDK editor 必填,但部分 host 运行时未实现——try/catch 降级 cancelled + warn(不卡队列)。
209
+ // 不用 typeof 守卫:editor 在类型上必填,typeof 检查会被 TS2367 拒(条件永假)。
210
+ try {
211
+ const text = await ui.editor(req.title ?? "", req.prefill);
212
+ return text === undefined ? { cancelled: true } : { value: text };
213
+ } catch (err) {
214
+ logger.warn(
215
+ "[subagents] ctx.ui.editor unavailable/threw, returning cancelled",
216
+ { detail: { id: req.id, error: err instanceof Error ? err.message : String(err) } },
217
+ );
218
+ return { cancelled: true };
219
+ }
220
+ }
221
+
222
+ // ── fire-and-forget 类(§3.2 映射表:GUI 模式下由 createUiRequestHandlerForMode 直接转发)
223
+ // 子进程 rpc-mode 发出的 fire-and-forget method,channel miss 后落到此处。
224
+ // 全部回 {ack:true}(fire-and-forget 语义:子进程不等响应)。
225
+
226
+ async function forwardNotify(req: UiRequest, ui: HostUIChannel): Promise<UiResponse> {
227
+ // notifyType 运行时收窄:UiRequest.notifyType 是宽 string,ctx.ui.notify 要字面量联合。
228
+ // 非法值 fallback "info"(pi 侧也会静默降级 info,此处显式 fallback 避免类型不安全)。
229
+ const rawType = req.notifyType;
230
+ const notifyType = rawType === "info" || rawType === "warning" || rawType === "error"
231
+ ? rawType
232
+ : "info";
233
+ ui.notify(req.message ?? "", notifyType);
234
+ return { ack: true };
235
+ }
236
+
237
+ async function forwardSetStatus(req: UiRequest, ui: HostUIChannel): Promise<UiResponse> {
238
+ ui.setStatus(req.statusKey ?? "", req.statusText);
239
+ return { ack: true };
240
+ }
241
+
242
+ async function forwardSetWidget(req: UiRequest, ui: HostUIChannel): Promise<UiResponse> {
243
+ // setWidget channel-miss 语义(§3.2 D1):
244
+ // req.channel === "gui_widget"(带 marker 但 channel 未注册)→ 不转发(marker 行无渲染意义)
245
+ // req.channel === undefined(普通 widget)→ 转发文本行到主 agent
246
+ // channel 命中 registry 时由 createRealHandler 优先走 channel handler,不进这里。
247
+ if (req.channel === "gui_widget") {
248
+ return { ack: true };
249
+ }
250
+ ui.setWidget(req.widgetKey ?? "", req.widgetLines, { placement: req.widgetPlacement });
251
+ return { ack: true };
252
+ }
253
+
254
+ async function forwardSetTitle(req: UiRequest, ui: HostUIChannel): Promise<UiResponse> {
255
+ ui.setTitle(req.title ?? "");
256
+ return { ack: true };
257
+ }
258
+
259
+ async function forwardSetEditorText(req: UiRequest, ui: HostUIChannel): Promise<UiResponse> {
260
+ ui.setEditorText(req.text ?? "");
261
+ return { ack: true };
262
+ }
263
+
264
+ /** method → 转发器路由表(key 与原 switch case 标签一一对应;值可选表达落空语义)。 */
265
+ const DIALOG_METHOD_FORWARDERS: Readonly<
266
+ Record<string, DialogMethodForwarder | undefined>
267
+ > = {
268
+ select: forwardSelect,
269
+ confirm: forwardConfirm,
270
+ input: forwardInput,
271
+ editor: forwardEditor,
272
+ notify: forwardNotify,
273
+ setStatus: forwardSetStatus,
274
+ setWidget: forwardSetWidget,
275
+ setTitle: forwardSetTitle,
276
+ set_editor_text: forwardSetEditorText,
277
+ };
278
+
164
279
  async function defaultDialogForward(
165
280
  req: UiRequest,
166
281
  ctx: HostUIContext,
167
282
  ): Promise<UiResponse> {
168
- const ui = ctx.ui;
169
- switch (req.method) {
170
- case "select": {
171
- const selected = await ui.select(req.title ?? "", req.options ?? []);
172
- return selected === undefined ? { cancelled: true } : { value: selected };
173
- }
174
- case "confirm": {
175
- // SDK confirm 必传 message(req.message 缺失时降级空串,不报错阻塞)
176
- const confirmed = await ui.confirm(req.title ?? "", req.message ?? "");
177
- return { confirmed };
178
- }
179
- case "input": {
180
- const text = await ui.input(req.title ?? "", req.placeholder);
181
- return text === undefined ? { cancelled: true } : { value: text };
182
- }
183
- case "editor": {
184
- // SDK editor 必填,但部分 host 运行时未实现——try/catch 降级 cancelled + warn(不卡队列)。
185
- // 不用 typeof 守卫:editor 在类型上必填,typeof 检查会被 TS2367 拒(条件永假)。
186
- try {
187
- const text = await ui.editor(req.title ?? "", req.prefill);
188
- return text === undefined ? { cancelled: true } : { value: text };
189
- } catch (err) {
190
- logger.warn(
191
- "[subagents] ctx.ui.editor unavailable/threw, returning cancelled",
192
- { detail: { id: req.id, error: err instanceof Error ? err.message : String(err) } },
193
- );
194
- return { cancelled: true };
195
- }
196
- }
197
- // ── fire-and-forget 类(§3.2 映射表:GUI 模式下由 createUiRequestHandlerForMode 直接转发)
198
- // 子进程 rpc-mode 发出的 fire-and-forget method,channel miss 后落到此处。
199
- // 全部回 {ack:true}(fire-and-forget 语义:子进程不等响应)。
200
- case "notify": {
201
- // notifyType 运行时收窄:UiRequest.notifyType 是宽 string,ctx.ui.notify 要字面量联合。
202
- // 非法值 fallback "info"(pi 侧也会静默降级 info,此处显式 fallback 避免类型不安全)。
203
- const rawType = req.notifyType;
204
- const notifyType = rawType === "info" || rawType === "warning" || rawType === "error"
205
- ? rawType
206
- : "info";
207
- ui.notify(req.message ?? "", notifyType);
208
- return { ack: true };
209
- }
210
- case "setStatus": {
211
- ui.setStatus(req.statusKey ?? "", req.statusText);
212
- return { ack: true };
213
- }
214
- case "setWidget": {
215
- // setWidget channel-miss 语义(§3.2 D1):
216
- // req.channel === "gui_widget"(带 marker 但 channel 未注册)→ 不转发(marker 行无渲染意义)
217
- // req.channel === undefined(普通 widget)→ 转发文本行到主 agent
218
- // channel 命中 registry 时由 createRealHandler 优先走 channel handler,不进这里。
219
- if (req.channel === "gui_widget") {
220
- return { ack: true };
221
- }
222
- ui.setWidget(req.widgetKey ?? "", req.widgetLines, { placement: req.widgetPlacement });
223
- return { ack: true };
224
- }
225
- case "setTitle": {
226
- ui.setTitle(req.title ?? "");
227
- return { ack: true };
228
- }
229
- case "set_editor_text": {
230
- ui.setEditorText(req.text ?? "");
231
- return { ack: true };
232
- }
233
- default: {
234
- // 未知 method(非 dialog 非 fire-and-forget)——保留 warn(协议演进信号,P3 限流兜底),
235
- // 回 ack(落到 default 的一定不是 dialog,fire-and-forget 正确应答是 ack,与 TUI 分支先例一致)。
236
- logger.warn(
237
- "[subagents] defaultDialogForward: unknown method",
238
- { detail: { method: req.method, id: req.id } },
239
- );
240
- return { ack: true };
241
- }
283
+ const forwarder = DIALOG_METHOD_FORWARDERS[req.method];
284
+ if (!forwarder) {
285
+ // 未知 method(非 dialog 非 fire-and-forget)——保留 warn(协议演进信号,P3 限流兜底),
286
+ // ack(落到 default 的一定不是 dialog,fire-and-forget 正确应答是 ack,与 TUI 分支先例一致)。
287
+ logger.warn(
288
+ "[subagents] defaultDialogForward: unknown method",
289
+ { detail: { method: req.method, id: req.id } },
290
+ );
291
+ return { ack: true };
242
292
  }
293
+ return forwarder(req, ctx.ui);
243
294
  }