@zhushanwen/subagent-core 0.2.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 (330) hide show
  1. package/README.md +114 -0
  2. package/dist/chunk-3VOERJPJ.js +22 -0
  3. package/dist/chunk-A4IVZWVX.js +31 -0
  4. package/dist/execution/engine/engines/zcode/constants.cjs +54 -0
  5. package/dist/execution/engine/engines/zcode/constants.d.cts +31 -0
  6. package/dist/execution/engine/engines/zcode/constants.d.ts +31 -0
  7. package/dist/execution/engine/engines/zcode/constants.js +22 -0
  8. package/dist/execution/engine/engines/zcode/reader.cjs +276 -0
  9. package/dist/execution/engine/engines/zcode/reader.d.cts +20 -0
  10. package/dist/execution/engine/engines/zcode/reader.d.ts +20 -0
  11. package/dist/execution/engine/engines/zcode/reader.js +239 -0
  12. package/dist/execution/engine/paths.cjs +55 -0
  13. package/dist/execution/engine/paths.d.cts +8 -0
  14. package/dist/execution/engine/paths.d.ts +8 -0
  15. package/dist/execution/engine/paths.js +26 -0
  16. package/dist/execution/relay-env.cjs +62 -0
  17. package/dist/execution/relay-env.d.cts +33 -0
  18. package/dist/execution/relay-env.d.ts +33 -0
  19. package/dist/execution/relay-env.js +20 -0
  20. package/dist/index.cjs +1852 -0
  21. package/dist/index.d.cts +1184 -0
  22. package/dist/index.d.ts +1184 -0
  23. package/dist/index.js +1810 -0
  24. package/dist/types-BxyAidGf.d.cts +875 -0
  25. package/dist/types-BxyAidGf.d.ts +875 -0
  26. package/package.json +99 -0
  27. package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +142 -0
  28. package/src/__tests__/append-system-prompt-assembly.test.ts +242 -0
  29. package/src/__tests__/builtin-workflows-structure.test.ts +180 -0
  30. package/src/__tests__/derive-closed-display-parity.test.ts +93 -0
  31. package/src/__tests__/fr4-get-state-handshake.test.ts +125 -0
  32. package/src/__tests__/fr8-orphan-recovery.test.ts +259 -0
  33. package/src/__tests__/m2-append-content-probe.test.ts +73 -0
  34. package/src/__tests__/manifest-store.test.ts +368 -0
  35. package/src/__tests__/record-store-cache.test.ts +335 -0
  36. package/src/__tests__/record-store-index.test.ts +560 -0
  37. package/src/__tests__/record-store-last-line.test.ts +129 -0
  38. package/src/__tests__/review-fix-loop-script.test.ts +288 -0
  39. package/src/__tests__/review-fix-loop-utils.test.ts +2377 -0
  40. package/src/__tests__/robustness-low-batch1.test.ts +286 -0
  41. package/src/__tests__/robustness-medium-batch1.test.ts +69 -0
  42. package/src/__tests__/robustness-medium-batch2.test.ts +65 -0
  43. package/src/__tests__/robustness-medium-batch3.test.ts +30 -0
  44. package/src/__tests__/robustness-medium-batch4.test.ts +358 -0
  45. package/src/__tests__/session-runner.test.ts +69 -0
  46. package/src/__tests__/smoke.test.ts +9 -0
  47. package/src/__tests__/stream-sink.test.ts +203 -0
  48. package/src/core/__tests__/host-services.test.ts +144 -0
  49. package/src/core/__tests__/logger.test.ts +78 -0
  50. package/src/core/__tests__/notify-ports.test.ts +104 -0
  51. package/src/core/host-services.ts +97 -0
  52. package/src/core/logger.ts +47 -0
  53. package/src/core/notify-ports.ts +126 -0
  54. package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +53 -0
  55. package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +1 -0
  56. package/src/execution/__tests__/agent-result-mapper.test.ts +150 -0
  57. package/src/execution/__tests__/alive-store.test.ts +147 -0
  58. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +490 -0
  59. package/src/execution/__tests__/channel-registry-handshake.test.ts +242 -0
  60. package/src/execution/__tests__/chat-engine-routing.test.ts +610 -0
  61. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +190 -0
  62. package/src/execution/__tests__/concurrency-pool.test.ts +250 -0
  63. package/src/execution/__tests__/config.test.ts +302 -0
  64. package/src/execution/__tests__/delivery-methods.test.ts +424 -0
  65. package/src/execution/__tests__/dialog-queue.test.ts +299 -0
  66. package/src/execution/__tests__/epipe-fallback.test.ts +241 -0
  67. package/src/execution/__tests__/execute-and-await-worktree.test.ts +243 -0
  68. package/src/execution/__tests__/execute-nesting.test.ts +323 -0
  69. package/src/execution/__tests__/execute-options-mapper.test.ts +200 -0
  70. package/src/execution/__tests__/execution-record.test.ts +1394 -0
  71. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +171 -0
  72. package/src/execution/__tests__/finalize-record.test.ts +367 -0
  73. package/src/execution/__tests__/finalized-marker.test.ts +104 -0
  74. package/src/execution/__tests__/format-schema-instruction.test.ts +169 -0
  75. package/src/execution/__tests__/gc-timer.test.ts +184 -0
  76. package/src/execution/__tests__/get-record-for-action-restart.test.ts +254 -0
  77. package/src/execution/__tests__/helpers/mock-extension-api.ts +30 -0
  78. package/src/execution/__tests__/helpers/spawn-mock.ts +242 -0
  79. package/src/execution/__tests__/host-mode.test.ts +87 -0
  80. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +211 -0
  81. package/src/execution/__tests__/lifecycle-manager.test.ts +383 -0
  82. package/src/execution/__tests__/lifecycle-predicates.test.ts +116 -0
  83. package/src/execution/__tests__/manifest-parentid.test.ts +117 -0
  84. package/src/execution/__tests__/model-resolver.test.ts +465 -0
  85. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +287 -0
  86. package/src/execution/__tests__/nested-visibility.test.ts +325 -0
  87. package/src/execution/__tests__/output-collector.test.ts +358 -0
  88. package/src/execution/__tests__/path-encoding.test.ts +104 -0
  89. package/src/execution/__tests__/pi-invocation.test.ts +134 -0
  90. package/src/execution/__tests__/record-store.test.ts +1057 -0
  91. package/src/execution/__tests__/records-cwd-isolation.test.ts +91 -0
  92. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +339 -0
  93. package/src/execution/__tests__/recursive-visibility-env.test.ts +273 -0
  94. package/src/execution/__tests__/relay-env.test.ts +42 -0
  95. package/src/execution/__tests__/resource-policy.test.ts +109 -0
  96. package/src/execution/__tests__/rpc-mode.test.ts +89 -0
  97. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +267 -0
  98. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +253 -0
  99. package/src/execution/__tests__/run-spawn-edges.test.ts +687 -0
  100. package/src/execution/__tests__/run-spawn-integration.test.ts +933 -0
  101. package/src/execution/__tests__/run-spawn-resume.test.ts +322 -0
  102. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +196 -0
  103. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +199 -0
  104. package/src/execution/__tests__/session-context-resolver.test.ts +167 -0
  105. package/src/execution/__tests__/session-file-gc.test.ts +293 -0
  106. package/src/execution/__tests__/session-reconstructor.test.ts +379 -0
  107. package/src/execution/__tests__/session-runner-epipe.test.ts +178 -0
  108. package/src/execution/__tests__/session-runner-schema-env.test.ts +350 -0
  109. package/src/execution/__tests__/spawn-args.test.ts +445 -0
  110. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +189 -0
  111. package/src/execution/__tests__/spawn-event-adapter.test.ts +167 -0
  112. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +207 -0
  113. package/src/execution/__tests__/spawned-children.test.ts +92 -0
  114. package/src/execution/__tests__/start-sync-model-guard.test.ts +150 -0
  115. package/src/execution/__tests__/stdin-writer.test.ts +462 -0
  116. package/src/execution/__tests__/stream-sink-retirement.test.ts +261 -0
  117. package/src/execution/__tests__/subagent-service-abort.test.ts +60 -0
  118. package/src/execution/__tests__/subagent-service-message-close.test.ts +629 -0
  119. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +180 -0
  120. package/src/execution/__tests__/subagent-service.test.ts +788 -0
  121. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +310 -0
  122. package/src/execution/__tests__/subprocess-agent-runner.test.ts +612 -0
  123. package/src/execution/__tests__/temp-prompt.test.ts +53 -0
  124. package/src/execution/__tests__/timeout-integration.test.ts +615 -0
  125. package/src/execution/__tests__/tombstone-store.test.ts +73 -0
  126. package/src/execution/__tests__/turn-limiter-semantics.test.ts +194 -0
  127. package/src/execution/__tests__/turn-limiter.test.ts +65 -0
  128. package/src/execution/__tests__/ui-channels.test.ts +187 -0
  129. package/src/execution/__tests__/ui-interaction-model.test.ts +67 -0
  130. package/src/execution/__tests__/ui-request-handler-factory.test.ts +369 -0
  131. package/src/execution/__tests__/ui-request-handler.test.ts +204 -0
  132. package/src/execution/__tests__/ui-request-observability.test.ts +113 -0
  133. package/src/execution/__tests__/ui-request-queue.test.ts +133 -0
  134. package/src/execution/__tests__/worktree-manager.test.ts +633 -0
  135. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +229 -0
  136. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +181 -0
  137. package/src/execution/__tests__/worktree-registry.test.ts +199 -0
  138. package/src/execution/agent-registry.ts +199 -0
  139. package/src/execution/agent-result-mapper.ts +90 -0
  140. package/src/execution/alive-store.ts +119 -0
  141. package/src/execution/argv-mirror.ts +113 -0
  142. package/src/execution/best-effort.ts +38 -0
  143. package/src/execution/channel-registry-access.ts +144 -0
  144. package/src/execution/concurrency-pool.ts +116 -0
  145. package/src/execution/config.ts +165 -0
  146. package/src/execution/dialog-queue.ts +330 -0
  147. package/src/execution/engine/__tests__/common/data-dir.test.ts +78 -0
  148. package/src/execution/engine/__tests__/common/errors.test.ts +132 -0
  149. package/src/execution/engine/__tests__/common/event-journal.test.ts +177 -0
  150. package/src/execution/engine/__tests__/common/kill-chain.test.ts +192 -0
  151. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +81 -0
  152. package/src/execution/engine/__tests__/common/persona-router.test.ts +123 -0
  153. package/src/execution/engine/__tests__/common/pool-manager.test.ts +154 -0
  154. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +128 -0
  155. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +28 -0
  156. package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +141 -0
  157. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +109 -0
  158. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +101 -0
  159. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +77 -0
  160. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +104 -0
  161. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +201 -0
  162. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +76 -0
  163. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +79 -0
  164. package/src/execution/engine/__tests__/engine-discovery.test.ts +87 -0
  165. package/src/execution/engine/__tests__/model-prompt.test.ts +197 -0
  166. package/src/execution/engine/__tests__/paths.test.ts +39 -0
  167. package/src/execution/engine/__tests__/registry.test.ts +120 -0
  168. package/src/execution/engine/__tests__/routing.test.ts +231 -0
  169. package/src/execution/engine/common/data-dir.ts +66 -0
  170. package/src/execution/engine/common/errors.ts +183 -0
  171. package/src/execution/engine/common/event-journal.ts +254 -0
  172. package/src/execution/engine/common/journal-replay.ts +62 -0
  173. package/src/execution/engine/common/kill-chain.ts +221 -0
  174. package/src/execution/engine/common/nesting-guard.ts +50 -0
  175. package/src/execution/engine/common/persona-router.ts +108 -0
  176. package/src/execution/engine/common/pool-manager.ts +226 -0
  177. package/src/execution/engine/common/schema-emulation.ts +189 -0
  178. package/src/execution/engine/common/session-view-projection.ts +51 -0
  179. package/src/execution/engine/engine-discovery.ts +65 -0
  180. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +469 -0
  181. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +155 -0
  182. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +164 -0
  183. package/src/execution/engine/engines/pi/pi-engine.ts +415 -0
  184. package/src/execution/engine/engines/pi/reader.ts +48 -0
  185. package/src/execution/engine/engines/pi/registration.ts +35 -0
  186. package/src/execution/engine/engines/pi/task-spec-mapper.ts +100 -0
  187. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +39 -0
  188. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +150 -0
  189. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +246 -0
  190. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +228 -0
  191. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +210 -0
  192. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +71 -0
  193. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +127 -0
  194. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +580 -0
  195. package/src/execution/engine/engines/zcode/constants.ts +43 -0
  196. package/src/execution/engine/engines/zcode/golden-sample.ts +39 -0
  197. package/src/execution/engine/engines/zcode/launcher.ts +161 -0
  198. package/src/execution/engine/engines/zcode/parser.ts +436 -0
  199. package/src/execution/engine/engines/zcode/preparer.ts +363 -0
  200. package/src/execution/engine/engines/zcode/reader.ts +381 -0
  201. package/src/execution/engine/engines/zcode/registration.ts +37 -0
  202. package/src/execution/engine/engines/zcode/zcode-engine.ts +658 -0
  203. package/src/execution/engine/host-task-spec.ts +47 -0
  204. package/src/execution/engine/model-prompt.ts +158 -0
  205. package/src/execution/engine/paths.ts +42 -0
  206. package/src/execution/engine/port.ts +153 -0
  207. package/src/execution/engine/registry.ts +133 -0
  208. package/src/execution/engine/routing.ts +218 -0
  209. package/src/execution/engine/types.ts +309 -0
  210. package/src/execution/execute-options-mapper.ts +115 -0
  211. package/src/execution/execution-record.ts +984 -0
  212. package/src/execution/finalize-record.ts +254 -0
  213. package/src/execution/finalized-marker.ts +70 -0
  214. package/src/execution/get-state-handshake.ts +104 -0
  215. package/src/execution/host-mode.ts +56 -0
  216. package/src/execution/idle-gc.ts +47 -0
  217. package/src/execution/lifecycle-manager.ts +513 -0
  218. package/src/execution/lifecycle-predicates.ts +65 -0
  219. package/src/execution/manifest-store.ts +256 -0
  220. package/src/execution/model-config-service.ts +250 -0
  221. package/src/execution/model-resolver.ts +248 -0
  222. package/src/execution/notifier.ts +372 -0
  223. package/src/execution/notify-ledger.ts +580 -0
  224. package/src/execution/output-collector.ts +228 -0
  225. package/src/execution/path-encoding.ts +60 -0
  226. package/src/execution/pi-invocation.ts +120 -0
  227. package/src/execution/record-entry.ts +132 -0
  228. package/src/execution/record-store.ts +1265 -0
  229. package/src/execution/relay-env.ts +37 -0
  230. package/src/execution/session-context-resolver.ts +64 -0
  231. package/src/execution/session-file-gc.ts +120 -0
  232. package/src/execution/session-pending.ts +170 -0
  233. package/src/execution/session-reconstructor.ts +678 -0
  234. package/src/execution/session-runner.ts +1789 -0
  235. package/src/execution/sessions-index.ts +304 -0
  236. package/src/execution/spawn-event-adapter.ts +363 -0
  237. package/src/execution/stdin-writer.ts +198 -0
  238. package/src/execution/stream-sink.ts +126 -0
  239. package/src/execution/subagent-service.ts +2268 -0
  240. package/src/execution/subprocess-agent-runner.ts +317 -0
  241. package/src/execution/temp-prompt.ts +62 -0
  242. package/src/execution/tombstone-store.ts +72 -0
  243. package/src/execution/turn-limiter.ts +102 -0
  244. package/src/execution/types.ts +1023 -0
  245. package/src/execution/ui-channels.ts +216 -0
  246. package/src/execution/ui-interaction-model.ts +48 -0
  247. package/src/execution/ui-request-handler-factory.ts +243 -0
  248. package/src/execution/ui-request-observability.ts +81 -0
  249. package/src/execution/ui-request-queue.ts +184 -0
  250. package/src/execution/worktree-manager.ts +688 -0
  251. package/src/execution/worktree-registry.ts +279 -0
  252. package/src/index.ts +87 -0
  253. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +349 -0
  254. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +202 -0
  255. package/src/orchestration/__tests__/agent-call-stream.test.ts +152 -0
  256. package/src/orchestration/__tests__/args-validator.test.ts +143 -0
  257. package/src/orchestration/__tests__/config-loader.test.ts +503 -0
  258. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +809 -0
  259. package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +404 -0
  260. package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +56 -0
  261. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +166 -0
  262. package/src/orchestration/__tests__/execute-agent-call.test.ts +451 -0
  263. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +600 -0
  264. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +96 -0
  265. package/src/orchestration/__tests__/lifecycle.test.ts +659 -0
  266. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +95 -0
  267. package/src/orchestration/__tests__/review-fix-loop-scriptpath-failfast.test.ts +183 -0
  268. package/src/orchestration/__tests__/script-lint.test.ts +831 -0
  269. package/src/orchestration/__tests__/skill-discovery.test.ts +210 -0
  270. package/src/orchestration/__tests__/test-mocks.ts +197 -0
  271. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +368 -0
  272. package/src/orchestration/__tests__/worker-host.test.ts +120 -0
  273. package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +164 -0
  274. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +563 -0
  275. package/src/orchestration/__tests__/worker-script-builder.test.ts +309 -0
  276. package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +129 -0
  277. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +317 -0
  278. package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +110 -0
  279. package/src/orchestration/agent-opts-resolver.ts +174 -0
  280. package/src/orchestration/args-validator.ts +127 -0
  281. package/src/orchestration/config-loader.ts +316 -0
  282. package/src/orchestration/error-recovery.ts +1018 -0
  283. package/src/orchestration/execute-agent-call.ts +256 -0
  284. package/src/orchestration/launcher.ts +455 -0
  285. package/src/orchestration/lifecycle.ts +399 -0
  286. package/src/orchestration/models/__tests__/budget.test.ts +307 -0
  287. package/src/orchestration/models/agent-call.ts +83 -0
  288. package/src/orchestration/models/budget.ts +118 -0
  289. package/src/orchestration/models/ports.ts +164 -0
  290. package/src/orchestration/models/run-runtime.ts +104 -0
  291. package/src/orchestration/models/run-spec.ts +83 -0
  292. package/src/orchestration/models/run-state.ts +44 -0
  293. package/src/orchestration/models/trace.ts +183 -0
  294. package/src/orchestration/models/types.ts +301 -0
  295. package/src/orchestration/models/workflow-run.ts +254 -0
  296. package/src/orchestration/models/workflow-script-registry.ts +35 -0
  297. package/src/orchestration/models/workflow-script.ts +117 -0
  298. package/src/orchestration/script-lint.ts +766 -0
  299. package/src/orchestration/skill-discovery.ts +135 -0
  300. package/src/orchestration/worker-handle.ts +115 -0
  301. package/src/orchestration/worker-host.ts +98 -0
  302. package/src/orchestration/worker-script-builder.ts +421 -0
  303. package/src/orchestration/workflow-files.ts +85 -0
  304. package/src/orchestration/workflow-script-registry-impl.ts +133 -0
  305. package/src/shared/__tests__/agent-ref.test.ts +34 -0
  306. package/src/shared/__tests__/meta-parser.test.ts +304 -0
  307. package/src/shared/__tests__/model-ref.test.ts +306 -0
  308. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +288 -0
  309. package/src/shared/__tests__/resource-discovery.test.ts +749 -0
  310. package/src/shared/__tests__/resource-meta.test.ts +51 -0
  311. package/src/shared/__tests__/schema-jsonify.test.ts +81 -0
  312. package/src/shared/__tests__/timer-delay.test.ts +61 -0
  313. package/src/shared/agent-event.ts +13 -0
  314. package/src/shared/agent-ref.ts +57 -0
  315. package/src/shared/meta-parser.ts +261 -0
  316. package/src/shared/model-ref.ts +286 -0
  317. package/src/shared/resource-discovery.ts +835 -0
  318. package/src/shared/resource-meta.ts +65 -0
  319. package/src/shared/schema-env.ts +44 -0
  320. package/src/shared/schema-jsonify.ts +58 -0
  321. package/src/shared/timer-delay.ts +54 -0
  322. package/src/shared/xml-injection.ts +35 -0
  323. package/workflows/README.md +81 -0
  324. package/workflows/_shared/agent-refs.cjs +40 -0
  325. package/workflows/chain.js +137 -0
  326. package/workflows/map-reduce.js +180 -0
  327. package/workflows/parallel.js +154 -0
  328. package/workflows/review-fix-loop-utils.cjs +1542 -0
  329. package/workflows/review-fix-loop.js +1605 -0
  330. package/workflows/scatter-gather.js +184 -0
@@ -0,0 +1,658 @@
1
+ // src/execution/engine/engines/zcode/zcode-engine.ts
2
+ //
3
+ // ZcodeEngine(P3):zcode CLI spawn 单轮模式的 EnginePort 实现。设计权威源:
4
+ // docs/architecture/subagent-engine-abstraction.md D10(MVP 引擎集 + zcode 首期只做
5
+ // spawn 单轮)、§3.3.4(reviewer@zcode 物理数据流)、§3.3.5(run 错误语义三条)。
6
+ //
7
+ // 职责编排(四件套的消费方):
8
+ // preparer(隔离 HOME 池 + 凭据 config)→ launcher(argv/env/spawn/杀链)
9
+ // → parser(stdout 收集 + 终 JSON + coarse 事件合成)→ reader(read 第①级 sqlite)。
10
+ //
11
+ // run 错误语义(设计 §3.3.5):
12
+ // ① prepare 期错误(credential_missing / model_not_available / prompt_too_large /
13
+ // capability 拒绝)在进程创建前 reject,不产生 handle;
14
+ // ② 运行中失败不 reject——合成 engine_run_failed outcome + 正常 handle 返回
15
+ // (record 必须收尾);
16
+ // ③ abort 走杀链(SIGTERM→grace→SIGKILL,interrupt: kill-only 无原生中断)后同 ②
17
+ // (exitCode=null + error 含杀链标记)。
18
+ //
19
+ // schema 仿真接线(D4 emulated 侧):common/schema-emulation.ts(并行任务 P2 交付,
20
+ // 2026-08-25 已就绪并接线)——spawn 前拼 prompt 仿真段、终态后三级容错提取 + ajv
21
+ // 校验、失败强化重试一次、仍失败报 schema_emulation_failed。read 第②级 journal 降级
22
+ // 已接线(P4 对齐点①:common/journal-replay 复用 live reducer)。
23
+
24
+ import { execFile } from "node:child_process";
25
+ import * as fs from "node:fs";
26
+ import * as path from "node:path";
27
+
28
+ import { getLogger } from "../../../../core/logger.ts";
29
+
30
+ import {
31
+ buildSchemaEmulationSegment,
32
+ extractAndValidateStructuredOutput,
33
+ } from "../../common/schema-emulation.ts";
34
+ import { HOST_TIMEOUT_ABORT_REASON, synthesizeTimeoutOutcome } from "../../common/kill-chain.ts";
35
+ import { engineTimeoutDetail } from "../../common/errors.ts";
36
+ import { replayJournalToSessionView } from "../../common/journal-replay.ts";
37
+ import type { EnginePort, EngineRunResult, RunContext } from "../../port.ts";
38
+ import type {
39
+ AgentEvent,
40
+ AgentOutcome,
41
+ AgentTaskSpec,
42
+ EngineCapabilities,
43
+ EngineHandle,
44
+ InteractAction,
45
+ InteractResult,
46
+ ProbeReport,
47
+ SessionView,
48
+ } from "../../types.ts";
49
+ import { resolvePoolDir } from "../../paths.ts";
50
+ import {
51
+ ZCODE_ADAPTER_VERSION,
52
+ ZCODE_CLI_DEFAULT_PATH,
53
+ ZCODE_ENGINE_ID,
54
+ ZCODE_ERROR_TAIL_CHARS,
55
+ ZCODE_KILL_GRACE_MS,
56
+ ZCODE_POOL_DB_RELATIVE_PATH,
57
+ } from "./constants.ts";
58
+ import { ZCODE_GOLDEN_STDOUT } from "./golden-sample.ts";
59
+ import {
60
+ buildZcodeArgv,
61
+ buildZcodeEnv,
62
+ assertZcodeArgvBudget,
63
+ launchZcodeProcess,
64
+ type ZcodeLaunchedProcess,
65
+ } from "./launcher.ts";
66
+ import {
67
+ buildRunFailedMessage,
68
+ collectZcodeOutput,
69
+ parseZcodeTerminal,
70
+ synthesizeCoarseEvents,
71
+ type ZcodeCollectedOutput,
72
+ type ZcodeTerminalPayload,
73
+ } from "./parser.ts";
74
+ import { listZcodeModels, prepareZcodeHome, resolveZcodeModelRef, type ZcodeSourcePaths } from "./preparer.ts";
75
+ import { readZcodeSessionView } from "./reader.ts";
76
+
77
+ const logger = getLogger("subagents");
78
+
79
+ /** probe 的版本探测超时(ms)——二进制无响应按探针失败处理,不静默挂死。 */
80
+ const PROBE_VERSION_TIMEOUT_MS = 15_000;
81
+
82
+ /** ZcodeEngine 构造依赖(全部可注入——测试不依赖真机 CLI/真凭据)。 */
83
+ export interface ZcodeEngineDeps {
84
+ /**
85
+ * 引擎数据目录(池根:<dir>/engines/zcode/<poolKey>/)。来源通道(宿主 dataDir)
86
+ * 由并行任务/W3 解决——本引擎只消费,见 registration.ts 缺省解析。
87
+ */
88
+ engineDataDir: () => string;
89
+ /** zcode CLI 路径;缺省 ZCODE_CLI_DEFAULT_PATH。 */
90
+ cliPath?: string;
91
+ /** 源 config 路径覆盖(测试注入临时源;缺省读 ~/.zcode)。 */
92
+ sources?: ZcodeSourcePaths;
93
+ /** 版本探测执行器(probe check "version";测试注入 fake 防真实子进程)。 */
94
+ probeVersion?: (cliPath: string) => Promise<string | undefined>;
95
+ /** spawn 执行器(测试注入 fake 进程)。 */
96
+ launch?: (opts: { cliPath: string; args: string[]; env: NodeJS.ProcessEnv }) => ZcodeLaunchedProcess;
97
+ /** env 基底(测试注入;缺省 process.env)。 */
98
+ processEnv?: NodeJS.ProcessEnv;
99
+ }
100
+
101
+ /** zcode 引擎适配器。 */
102
+ export class ZcodeEngine implements EnginePort {
103
+ readonly id = ZCODE_ENGINE_ID;
104
+
105
+ private readonly deps: ZcodeEngineDeps;
106
+ private probeCache: ProbeReport | undefined;
107
+
108
+ constructor(deps: ZcodeEngineDeps) {
109
+ this.deps = deps;
110
+ }
111
+
112
+ /**
113
+ * zcode 链路首期实际接通的能力(D3 链路口径)。声明升级(如 schema 仿真段接入
114
+ * common 层后仍为 emulated;app-server 常驻化后 eventGranularity 升 stream)必须
115
+ * 先改链路再改声明。
116
+ */
117
+ capabilities(): EngineCapabilities {
118
+ return {
119
+ // 无 --json-schema 类通道;公共 schema 仿真层(prompt 约定 + 容错提取 + ajv)
120
+ schemaEnforcement: "emulated",
121
+ // argv-only spawn,无运行中插话通道(app-server 属引擎内部优化,首期不接)
122
+ steer: "unsupported",
123
+ // 无同进程 idle 复用;--resume 是冷启动
124
+ conversation: "unsupported",
125
+ // 无 --append-system-prompt flag(实测拒收)——persona 只能拼进 prompt
126
+ personaInjection: "prompt",
127
+ // stdout 只有终态单 JSON(message_end/turn_end 合成)
128
+ eventGranularity: "coarse",
129
+ // 首期未接 worktree 隔离(公共层 worktree-manager 接入后升 emulated)
130
+ sandbox: "none",
131
+ // sqlite 三级 JOIN 完整重建 turns(reader 实测)
132
+ sessionRead: "full",
133
+ // --resume 冷启动可用(实测)
134
+ resume: "cold",
135
+ // 无原生中断——AbortSignal 走公共杀链(SIGTERM→grace→SIGKILL)
136
+ interrupt: "kill-only",
137
+ // --mode build/edit/plan/yolo 原生权限档位
138
+ permissionMode: "native",
139
+ };
140
+ }
141
+
142
+ /** 探针(D7):二进制存在 + 版本解析 + golden 样本干跑回归(zsub 式逆向契约引擎必做)。 */
143
+ async probe(opts?: { force?: boolean }): Promise<ProbeReport> {
144
+ if (!opts?.force && this.probeCache) return this.probeCache;
145
+
146
+ const cliPath = this.deps.cliPath ?? ZCODE_CLI_DEFAULT_PATH;
147
+ // check 1:二进制存在(不在 PATH,固定绝对路径形态——存在性即可用性的第一道判据)
148
+ const binary = this.probeBinaryCheck(cliPath);
149
+ const checks: ProbeReport["checks"] = [binary];
150
+
151
+ // check 2:版本解析(存在才尝试——必败进程不再 spawn)
152
+ let engineVersion = "";
153
+ if (binary.ok) {
154
+ const version = await this.probeVersionCheck(cliPath);
155
+ checks.push(version.check);
156
+ engineVersion = version.engineVersion;
157
+ }
158
+
159
+ // check 3:golden 样本干跑回归(parser 对实录样本解析——格式漂移入口拦截)
160
+ checks.push(this.probeGoldenCheck());
161
+
162
+ const ok = checks.every((c) => c.ok);
163
+ const report: ProbeReport = {
164
+ ok,
165
+ engineVersion,
166
+ checks,
167
+ ...(ok ? {} : { error: this.probeFailureRecovery(cliPath) }),
168
+ };
169
+ this.probeCache = report;
170
+ return report;
171
+ }
172
+
173
+ /** check 1:二进制存在性(isFile 才算——同名目录不是可执行入口)。 */
174
+ private probeBinaryCheck(cliPath: string): ProbeReport["checks"][number] {
175
+ const binaryOk = fs.existsSync(cliPath) && fs.statSync(cliPath).isFile();
176
+ return {
177
+ name: "binary",
178
+ ok: binaryOk,
179
+ detail: binaryOk ? cliPath : `zcode CLI 不存在:${cliPath}`,
180
+ };
181
+ }
182
+
183
+ /** check 2:`--version` 解析(probeVersion 可注入——测试 fake 防真实子进程)。 */
184
+ private async probeVersionCheck(
185
+ cliPath: string,
186
+ ): Promise<{ check: ProbeReport["checks"][number]; engineVersion: string }> {
187
+ const runVersion = this.deps.probeVersion ?? defaultProbeVersion;
188
+ const version = await runVersion(cliPath);
189
+ const versionOk = version !== undefined && version.length > 0;
190
+ return {
191
+ check: {
192
+ name: "version",
193
+ ok: versionOk,
194
+ detail: versionOk ? version : "zcode --version 返回空或失败",
195
+ },
196
+ engineVersion: version ?? "",
197
+ };
198
+ }
199
+
200
+ /** check 3:golden 样本干跑(parser 对实录样本解析——stdout 格式漂移的入口拦截)。 */
201
+ private probeGoldenCheck(): ProbeReport["checks"][number] {
202
+ const golden = parseZcodeTerminal(ZCODE_GOLDEN_STDOUT);
203
+ const goldenOk = golden.ok && golden.payload.sessionId !== undefined && golden.payload.usage !== undefined;
204
+ return {
205
+ name: "golden-regression",
206
+ ok: goldenOk,
207
+ detail: goldenOk
208
+ ? "parser 对 0.16.5 实录样本回归通过(sessionId/response/usage 形状完整)"
209
+ : `解析实录样本失败:${golden.ok ? "字段缺失(sessionId/usage)" : golden.reason}`,
210
+ };
211
+ }
212
+
213
+ /** 探针失败的恢复指引(§3.3.3 终态四:版本确认命令 + 探针重跑 + 调研文档路径)。 */
214
+ private probeFailureRecovery(cliPath: string): NonNullable<ProbeReport["error"]> {
215
+ return {
216
+ code: "engine_probe_failed",
217
+ recovery:
218
+ `Run \`node ${cliPath} --version\` 确认 zcode CLI 可用且版本未漂移,然后重跑探针(重新初始化引擎或 probe({force:true}))。` +
219
+ `若 stdout 格式已变:把新样本补录进 golden 库(__tests__/__fixtures__/zcode-golden-spawn.json 与 golden-sample.ts)并更新 parser。` +
220
+ `参照 docs/research/agent-engine-zcode.md。`,
221
+ };
222
+ }
223
+
224
+ /** D1 主语义:preparer → launcher → parser →(schema 仿真校验 + 一次重试)→ outcome/handle。 */
225
+ async run(task: AgentTaskSpec, ctx: RunContext): Promise<EngineRunResult> {
226
+ const startedAt = Date.now();
227
+ this.rejectUnsupportedTaskShapes(task);
228
+
229
+ // ① prepare 期:模型解析(provider 体系校验)+ 隔离 HOME 池引导(凭据 + model.main)
230
+ const modelRef = resolveZcodeModelRef(task.model, this.deps.sources);
231
+ const prepared = prepareZcodeHome({
232
+ engineDataDir: this.deps.engineDataDir(),
233
+ modelRef,
234
+ sources: this.deps.sources,
235
+ });
236
+ // 对齐点③:把实际池 key 声明给宿主(journal writer 重定向到 handle.poolKey 同源
237
+ // 的路径——单一权威,宿主不再两边推导);须在首个事件 emit 前(终态后合成,天然满足)
238
+ ctx.onPoolResolved?.(prepared.poolKey);
239
+ logger.debug("[zcode-engine] isolated home prepared", {
240
+ poolKey: prepared.poolKey,
241
+ wroteConfig: prepared.wroteConfig,
242
+ modelRef,
243
+ taskId: ctx.taskId,
244
+ });
245
+
246
+ const cwd = task.cwd ?? process.cwd();
247
+ const schema = isPlainObject(task.schema) ? task.schema : undefined;
248
+ const basePrompt = this.buildPrompt(task, schema);
249
+
250
+ // ②-④ 首轮执行;schema 任务校验失败时重试一次(强化 JSON 输出指令——与
251
+ // structured-output 的重试语义对齐,设计 §3.3.3 schema_emulation_failed 行)。
252
+ // 重试轮产生的新 session 是独立 LLM 调用:token 计入 outcome.usage 总量,
253
+ // 事件只在最终轮终态后一次性合成(不变量 5:事件 emit 完成先于 run resolve)。
254
+ const usageAcc = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, has: false };
255
+ let final = await this.attemptOnce(task, ctx, prepared, cwd, basePrompt);
256
+ accumulateUsage(usageAcc, final);
257
+ if (final.kind === "parsed" && final.schemaResult !== undefined && !final.schemaResult.ok && schema !== undefined) {
258
+ const retryPrompt = appendSchemaRetryDirective(basePrompt, final.schemaResult.error);
259
+ const retry = await this.attemptOnce(task, ctx, prepared, cwd, retryPrompt);
260
+ accumulateUsage(usageAcc, retry);
261
+ final = retry;
262
+ }
263
+
264
+ const outcome = this.finalizeOutcome(task, ctx, final, usageAcc, startedAt);
265
+
266
+ const handle: EngineHandle = {
267
+ data: {
268
+ v: 1,
269
+ engineId: ZCODE_ENGINE_ID,
270
+ sessionRef: {
271
+ // 相对池目录自描述(设计 §3.3.6)——read 时经 resolvePoolDir + 此相对路径重定位
272
+ dbPath: ZCODE_POOL_DB_RELATIVE_PATH,
273
+ ...(outcome.sessionId !== undefined ? { sessionId: outcome.sessionId } : {}),
274
+ },
275
+ poolKey: prepared.poolKey,
276
+ ...(this.probeCache?.engineVersion !== undefined && this.probeCache.engineVersion !== ""
277
+ ? { engineVersion: this.probeCache.engineVersion }
278
+ : {}),
279
+ adapterVersion: ZCODE_ADAPTER_VERSION,
280
+ },
281
+ };
282
+ return { handle, outcome };
283
+ }
284
+
285
+ /** 终态合成(extension-conventions 函数 80 行上限,从 run 提取):aborted / run-failed / parsed 三分支。 */
286
+ private finalizeOutcome(
287
+ task: AgentTaskSpec,
288
+ ctx: RunContext,
289
+ final: AttemptResult,
290
+ usageAcc: { input: number; output: number; cacheRead: number; cacheWrite: number; has: boolean },
291
+ startedAt: number,
292
+ ): AgentOutcome {
293
+ const outcome: AgentOutcome = {
294
+ engineId: ZCODE_ENGINE_ID,
295
+ content: "",
296
+ durationMs: Date.now() - startedAt,
297
+ ...(typeof task.worktree === "object" && task.worktree !== null ? { worktreePath: task.worktree.path } : {}),
298
+ // D9① fallback 留痕:路由层经 RunContext 投影(zcode 无 record 通路,outcome 是
299
+ // 唯一留痕面;pi 引擎另有 record 投影)
300
+ ...(ctx.engineFallback !== undefined ? { engineFallback: ctx.engineFallback } : {}),
301
+ };
302
+ const emit = (event: AgentEvent): void => {
303
+ ctx.onEvent?.(event);
304
+ };
305
+
306
+ if (final.kind === "aborted") {
307
+ this.applyAbortedOutcome(outcome, task, ctx, final, emit);
308
+ } else if (final.kind === "run-failed") {
309
+ this.applyRunFailedOutcome(outcome, final, emit);
310
+ } else {
311
+ this.applyParsedOutcome(outcome, final, usageAcc, emit);
312
+ }
313
+ return outcome;
314
+ }
315
+
316
+ /** abort 合成终态:exitCode=null(record 正常收尾,不留僵尸)。 */
317
+ private applyAbortedOutcome(
318
+ outcome: AgentOutcome,
319
+ task: AgentTaskSpec,
320
+ ctx: RunContext,
321
+ final: Extract<AttemptResult, { kind: "aborted" }>,
322
+ emit: (event: AgentEvent) => void,
323
+ ): void {
324
+ outcome.exitCode = null;
325
+ // 对齐点④:宿主超时(mergeTimeoutSignal 的 timeout abort)统一走公共合成终态
326
+ // (common/kill-chain.synthesizeTimeoutOutcome——engine_timeout 文案 SSOT:stdout
327
+ // 尾部 + 「可用 engine: pi 重跑」建议);用户主动 cancel 维持 engine_run_failed
328
+ // 中止标记(非超时语义,不冒充超时)。?? 兜底是类型收窄(合成器恒写 error)
329
+ outcome.error = isHostTimeoutAbort(ctx)
330
+ ? synthesizeTimeoutOutcome(task, final.output.stdoutText, ZCODE_ENGINE_ID).error ??
331
+ engineTimeoutDetail(final.output.stdoutText)
332
+ : `engine_run_failed: zcode 任务被中止(杀链 SIGTERM→${ZCODE_KILL_GRACE_MS}ms→SIGKILL,宿主合成终态)。` +
333
+ `stdout 尾部: ${final.output.stdoutText.slice(-ZCODE_ERROR_TAIL_CHARS)}`;
334
+ emit({ type: "error", message: outcome.error });
335
+ }
336
+
337
+ /** run-failed 合成终态:错误信息由 buildRunFailedMessage 产出(已含恢复指引),直接透传。 */
338
+ private applyRunFailedOutcome(
339
+ outcome: AgentOutcome,
340
+ final: Extract<AttemptResult, { kind: "run-failed" }>,
341
+ emit: (event: AgentEvent) => void,
342
+ ): void {
343
+ outcome.exitCode = final.output.exitCode;
344
+ outcome.error = final.message;
345
+ emit({ type: "error", message: outcome.error });
346
+ }
347
+
348
+ /** parsed 合成终态:content/sessionId/usage 落位 + schema 校验分流 + coarse 事件。 */
349
+ private applyParsedOutcome(
350
+ outcome: AgentOutcome,
351
+ final: Extract<AttemptResult, { kind: "parsed" }>,
352
+ usageAcc: { input: number; output: number; cacheRead: number; cacheWrite: number; has: boolean },
353
+ emit: (event: AgentEvent) => void,
354
+ ): void {
355
+ const payload = final.payload;
356
+ outcome.content = payload.response;
357
+ outcome.exitCode = final.output.exitCode;
358
+ if (payload.sessionId !== undefined) outcome.sessionId = payload.sessionId;
359
+ // usage:token 四项取两轮之和(重试的 LLM 调用真实发生),contextTokens/turns 取末轮
360
+ if (usageAcc.has) {
361
+ const last = payload.outcomeUsage;
362
+ outcome.usage = {
363
+ input: usageAcc.input,
364
+ output: usageAcc.output,
365
+ cacheRead: usageAcc.cacheRead,
366
+ cacheWrite: usageAcc.cacheWrite,
367
+ cost: 0,
368
+ contextTokens: last?.contextTokens ?? usageAcc.input + usageAcc.output + usageAcc.cacheRead + usageAcc.cacheWrite,
369
+ turns: last?.turns ?? 1,
370
+ };
371
+ }
372
+ if (final.schemaResult !== undefined) {
373
+ if (final.schemaResult.ok) {
374
+ // D4 硬分流的 emulated 侧产出:公共仿真层的 ajv 校验结果即 parsedOutput
375
+ outcome.parsedOutput = final.schemaResult.parsed;
376
+ } else {
377
+ // 两轮(原始 + 强化重试)均未通过三级容错提取/ajv 校验
378
+ outcome.error =
379
+ `schema_emulation_failed: zcode 输出经两轮(含强化 prompt 重试)仍未通过 schema 校验。` +
380
+ `末轮失败原因: ${final.schemaResult.error}。原始输出尾部: ${final.schemaResult.tail}。` +
381
+ `恢复指引:简化 schema 或拆小任务后重派;需要强 schema 约束时改用 engine: pi(native schema 注入)。`;
382
+ emit({ type: "error", message: outcome.error });
383
+ }
384
+ }
385
+ // coarse 事件(不变量 5:事件 emit 完成先于 run resolve——journal 完整性)
386
+ for (const ev of synthesizeCoarseEvents(payload.response, payload.usage)) emit(ev);
387
+ }
388
+
389
+ /**
390
+ * 单轮执行(launch → collect → parse → schema 校验)。产出三态之一给 run 编排:
391
+ * aborted(我方杀链)/ run-failed(非零退出或解析失败)/ parsed(含 schema 校验结果)。
392
+ */
393
+ private async attemptOnce(
394
+ task: AgentTaskSpec,
395
+ ctx: RunContext,
396
+ prepared: ReturnType<typeof prepareZcodeHome>,
397
+ cwd: string,
398
+ prompt: string,
399
+ ): Promise<AttemptResult> {
400
+ // ② argv 组装 + 字节估算(超限抛 prompt_too_large——进程创建前;公共预算权威)
401
+ const args = buildZcodeArgv({ cwd, prompt, denyTools: task.denyTools });
402
+ const cliPath = this.deps.cliPath ?? ZCODE_CLI_DEFAULT_PATH;
403
+ assertZcodeArgvBudget("node", cliPath, args);
404
+
405
+ // ③ launch:spawn 单轮(stdin ignore;HOME=池目录;嵌套标记经公共 nesting-guard)
406
+ const launch = this.deps.launch ?? launchZcodeProcess;
407
+ const env = buildZcodeEnv(prepared.homeDir, this.deps.processEnv ?? process.env);
408
+ let proc: ZcodeLaunchedProcess;
409
+ try {
410
+ proc = launch({ cliPath, args, env });
411
+ } catch (err) {
412
+ // spawn 同步失败(node 缺失等):进程未创建,按 prepare 期语义 reject
413
+ throw new Error(
414
+ `[engine_run_failed] 无法启动 zcode CLI(${cliPath}):${err instanceof Error ? err.message : String(err)}。` +
415
+ `恢复指引:确认 node 在 PATH 且 ${cliPath} 存在(probe 可探测),或改用 engine: pi。`,
416
+ );
417
+ }
418
+
419
+ // [U0 D10] 终止链路径①:spawn 成功后同步注册子进程句柄进宿主 spawnedChildren
420
+ // 记账(port.ts 契约「spawn 成功后同步回调」)——cancelBackground SIGTERM /
421
+ // dispose killAll 收割兜底对引擎 record 生效,防 controller 丢失/竞态场景下孤儿进程
422
+ ctx.onChildSpawned?.(proc.child);
423
+
424
+ // abort 分级(D1):zcode 无原生中断(interrupt: kill-only),AbortSignal 直通
425
+ // SIGTERM → grace → SIGKILL 杀链,终态由宿主合成
426
+ const onAbort = (): void => {
427
+ void proc.abort(ZCODE_KILL_GRACE_MS);
428
+ };
429
+ if (ctx.signal !== undefined) {
430
+ if (ctx.signal.aborted) onAbort();
431
+ else ctx.signal.addEventListener("abort", onAbort, { once: true });
432
+ }
433
+
434
+ // ④ parser:有界收集 + 终 JSON
435
+ const output = await collectZcodeOutput(proc);
436
+ if (ctx.signal !== undefined) ctx.signal.removeEventListener("abort", onAbort);
437
+
438
+ if (proc.killedByUs()) return { kind: "aborted", output };
439
+ if (output.exitCode !== 0) {
440
+ return {
441
+ kind: "run-failed",
442
+ output,
443
+ message: buildRunFailedMessage({
444
+ cliPath,
445
+ exitCode: output.exitCode,
446
+ stdoutTail: output.stdoutText,
447
+ stderrTail: output.stderrTail,
448
+ modelRef: prepared.modelRef,
449
+ configPath: prepared.configPath,
450
+ }),
451
+ };
452
+ }
453
+ const terminal = parseZcodeTerminal(output.stdoutText);
454
+ if (!terminal.ok) {
455
+ return {
456
+ kind: "run-failed",
457
+ output,
458
+ message: buildRunFailedMessage({
459
+ cliPath,
460
+ exitCode: output.exitCode,
461
+ stdoutTail: output.stdoutText,
462
+ stderrTail: output.stderrTail,
463
+ parseReason: terminal.reason,
464
+ modelRef: prepared.modelRef,
465
+ configPath: prepared.configPath,
466
+ }),
467
+ };
468
+ }
469
+ const schema = isPlainObject(task.schema) ? task.schema : undefined;
470
+ return {
471
+ kind: "parsed",
472
+ output,
473
+ payload: terminal.payload,
474
+ ...(schema !== undefined
475
+ ? { schemaResult: extractAndValidateStructuredOutput(terminal.payload.response, schema) }
476
+ : {}),
477
+ };
478
+ }
479
+
480
+ /**
481
+ * D1 可选面:zcode 首期不支持 conversation(capabilities 声明)——同步拒绝、
482
+ * 不创建进程,文案给可操作建议(A11)。
483
+ */
484
+ async interact(_handle: EngineHandle, _action: InteractAction): Promise<InteractResult> {
485
+ return {
486
+ ok: false,
487
+ code: "engine_capability_unsupported",
488
+ message:
489
+ "zcode 引擎不支持 conversation 交互控制面(capabilities.conversation = 'unsupported'," +
490
+ "spawn 单轮模式无同进程 idle 复用)。恢复指引:改用单次 subagent 调用重新派发任务," +
491
+ "或使用 engine: 'pi'(chatMode idle 复用,支持 message/close/cancel)。",
492
+ };
493
+ }
494
+
495
+ /**
496
+ * D6 read 三级降级:①sqlite 原生读取 → ②宿主 event journal 重放(对齐点①接线:
497
+ * replayJournalToSessionView 复用 live reducer,重放等价性见 §3.3.6)→ ③outcome-only。
498
+ * sessionId 缺失(解析失败的 run 无法在共享池 db 内定位 session)跳过①级;②级
499
+ * 依赖 handle.journalPath(宿主 run 后回填)。
500
+ */
501
+ /** [U7] 模型可发现性:v2 桌面登录态聚合(带凭据 provider × models),失败安全返回清单本身可能为空。 */
502
+ listModels(): Array<{ id: string; name?: string }> {
503
+ return listZcodeModels(this.deps.sources);
504
+ }
505
+
506
+ async read(handle: EngineHandle): Promise<SessionView> {
507
+ if (handle.data.engineId !== ZCODE_ENGINE_ID) {
508
+ return { engineId: ZCODE_ENGINE_ID, turns: [], source: "outcome-only" };
509
+ }
510
+ const sessionId = handle.data.sessionRef["sessionId"];
511
+ const dbPathRaw = handle.data.sessionRef["dbPath"];
512
+ if (typeof sessionId === "string" && typeof dbPathRaw === "string") {
513
+ // 相对路径锚定池目录(handle.poolKey 自描述);绝对路径(未来形态)直用
514
+ const dbPath = path.isAbsolute(dbPathRaw)
515
+ ? dbPathRaw
516
+ : path.join(resolvePoolDir(this.deps.engineDataDir(), ZCODE_ENGINE_ID, handle.data.poolKey), dbPathRaw);
517
+ try {
518
+ return await readZcodeSessionView(dbPath, sessionId);
519
+ } catch (err) {
520
+ logger.warn("[zcode-engine] native session read failed, degrade to journal replay", {
521
+ dbPath,
522
+ sessionId,
523
+ reason: err instanceof Error ? err.message : String(err),
524
+ });
525
+ }
526
+ }
527
+ // ②级:journal 重放(journalPath 缺省 / 文件不存在 / 无事件 → undefined 落③级)
528
+ const journaled = replayJournalToSessionView(handle, ZCODE_ENGINE_ID);
529
+ if (journaled !== undefined) return journaled;
530
+ return { engineId: ZCODE_ENGINE_ID, turns: [], source: "outcome-only" };
531
+ }
532
+
533
+ // ── 内部 ──
534
+
535
+ /**
536
+ * prepare 期的能力拒绝(进程创建前):fork 是 pi 专属(AgentTaskSpec.fork 契约:
537
+ * 其他引擎按 capabilities 拒绝);conversation 是 interact 控制面的 task 标志,
538
+ * zcode 无此面(A11:同步拒绝 + 可操作建议,无进程创建);maxTurns 是 pi 引擎
539
+ * 专属(turn limiter + spawn watchdog 估算依赖 pi 的 turn_end 事件流)——zcode
540
+ * 无 turn_end 语义,静默丢弃会造成「传了上限却失控」的假象,显式拒绝(U4,
541
+ * 同 fork 模式)。
542
+ */
543
+ private rejectUnsupportedTaskShapes(task: AgentTaskSpec): void {
544
+ if (task.fork === true) {
545
+ throw new ZcodeTaskShapeError(
546
+ "engine_capability_unsupported",
547
+ "zcode 引擎不支持 fork(pi 专属会话分叉语义)。恢复指引:去掉 fork 参数重派,或使用 engine: 'pi'。",
548
+ );
549
+ }
550
+ if (task.conversation === true) {
551
+ throw new ZcodeTaskShapeError(
552
+ "engine_capability_unsupported",
553
+ "zcode 引擎不支持 conversation 模式(spawn 单轮,无同进程 idle 复用)。" +
554
+ "恢复指引:改用单次调用(去掉 conversation),或使用 engine: 'pi'。",
555
+ );
556
+ }
557
+ if (task.maxTurns !== undefined) {
558
+ throw new ZcodeTaskShapeError(
559
+ "engine_capability_unsupported",
560
+ "zcode 引擎不支持 maxTurns(pi 引擎专属 turn limiter;zcode 无 turn_end 语义,无法兑现轮数上限)。" +
561
+ "恢复指引:去掉 maxTurns 参数重派,或使用 engine: 'pi'。",
562
+ );
563
+ }
564
+ }
565
+
566
+ /**
567
+ * persona 拼接后的完整 prompt(personaInjection: 'prompt'——zcode 无 flag 通道):
568
+ * appendSystemPrompt 段在前(人设/约束语境),task 正文居中,schema 仿真段尾置
569
+ * (common/schema-emulation 公共层产出,D4 emulated 侧——zcode 无 native schema 通道)。
570
+ */
571
+ private buildPrompt(task: AgentTaskSpec, schema: object | undefined): string {
572
+ const segments: string[] = [...(task.persona?.appendSystemPrompt ?? [])];
573
+ segments.push(task.task);
574
+ if (schema !== undefined) segments.push(buildSchemaEmulationSegment(schema));
575
+ return segments.join("\n\n");
576
+ }
577
+ }
578
+
579
+ // ── 模块级辅助(run 的重试编排件) ──
580
+
581
+ /** attemptOnce 的三态产物(run 按序编排重试与终态合成)。 */
582
+ type AttemptResult =
583
+ | { kind: "aborted"; output: ZcodeCollectedOutput }
584
+ | { kind: "run-failed"; output: ZcodeCollectedOutput; message: string }
585
+ | {
586
+ kind: "parsed";
587
+ output: ZcodeCollectedOutput;
588
+ payload: ZcodeTerminalPayload;
589
+ schemaResult?: { ok: true; parsed: unknown } | { ok: false; error: string; tail: string };
590
+ };
591
+
592
+ /** Record 形状 guard(task.schema 的运行时窄化——Record<string, unknown> 不满足 ajv 的 object 入参)。 */
593
+ function isPlainObject(v: unknown): v is object {
594
+ return typeof v === "object" && v !== null && !Array.isArray(v);
595
+ }
596
+
597
+ /** 跨重试轮累计 token 用量(重试的 LLM 调用真实发生)。 */
598
+ function accumulateUsage(acc: { input: number; output: number; cacheRead: number; cacheWrite: number; has: boolean }, r: AttemptResult): void {
599
+ if (r.kind !== "parsed") return;
600
+ const u = r.payload.usage;
601
+ if (u === undefined) return;
602
+ acc.has = true;
603
+ acc.input += u.input;
604
+ acc.output += u.output;
605
+ acc.cacheRead += u.cacheRead;
606
+ acc.cacheWrite += u.cacheWrite;
607
+ }
608
+
609
+ /** 强化重试 prompt:首战校验失败后追加更明确的 JSON 输出指令(structured-output 重试语义)。 */
610
+ function appendSchemaRetryDirective(basePrompt: string, validationError: string): string {
611
+ return (
612
+ basePrompt +
613
+ "\n\n## Retry: Structured Output Failed\n" +
614
+ `Your previous answer failed schema validation: ${validationError}\n` +
615
+ "Answer again. Output ONLY the JSON value conforming to the schema above — " +
616
+ "no prose, no markdown fences, no extra text."
617
+ );
618
+ }
619
+
620
+ /** prepare 期能力拒绝的载体(code 进 message 前缀,调用方可程序化分流)。 */
621
+ class ZcodeTaskShapeError extends Error {
622
+ readonly code: string;
623
+
624
+ constructor(code: string, message: string) {
625
+ super(`[${code}] ${message}`);
626
+ this.name = "ZcodeTaskShapeError";
627
+ this.code = code;
628
+ }
629
+ }
630
+
631
+ /** 宿主超时 abort 判别(对齐点④):signal.reason 带超时标记 = 超时杀链合成终态路径。 */
632
+ function isHostTimeoutAbort(ctx: RunContext): boolean {
633
+ return ctx.signal?.aborted === true && ctx.signal.reason === HOST_TIMEOUT_ABORT_REASON;
634
+ }
635
+
636
+ /** 默认版本探测:`node <cli> --version`(首行 trim;超时按探针失败处理)。 */
637
+ async function defaultProbeVersion(cliPath: string): Promise<string | undefined> {
638
+ try {
639
+ return await new Promise<string | undefined>((resolve, reject) => {
640
+ execFile(
641
+ "node",
642
+ [cliPath, "--version"],
643
+ { encoding: "utf8", timeout: PROBE_VERSION_TIMEOUT_MS },
644
+ (err: Error | null, stdout: string) => {
645
+ if (err) reject(err);
646
+ else resolve(stdout.trim().split("\n")[0]?.trim() || undefined);
647
+ },
648
+ );
649
+ });
650
+ } catch (err) {
651
+ logger.debug(
652
+ `[zcode-engine] probe version check failed (best-effort continue): ${
653
+ err instanceof Error ? err.message : String(err)
654
+ }`,
655
+ );
656
+ return undefined;
657
+ }
658
+ }