@zhushanwen/subagent-core 0.4.0 → 0.6.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 (309) hide show
  1. package/dist/{chunk-4KN4TTG7.js → chunk-43ONBFZX.js} +1 -1
  2. package/dist/{chunk-X7SZ5HLQ.js → chunk-V3VHZ2VX.js} +20 -27
  3. package/dist/execution/engine/engines/zcode/constants.cjs +29 -41
  4. package/dist/execution/engine/engines/zcode/constants.d.cts +65 -53
  5. package/dist/execution/engine/engines/zcode/constants.d.ts +65 -53
  6. package/dist/execution/engine/engines/zcode/constants.js +17 -27
  7. package/dist/execution/engine/engines/zcode/reader.d.cts +2 -1
  8. package/dist/execution/engine/engines/zcode/reader.d.ts +2 -1
  9. package/dist/execution/engine/engines/zcode/reader.js +2 -2
  10. package/dist/index.cjs +17100 -14082
  11. package/dist/index.d.cts +5336 -4033
  12. package/dist/index.d.ts +5336 -4033
  13. package/dist/index.js +17020 -14055
  14. package/dist/{types-DpUO16pj.d.cts → types-C3fE3R9x.d.cts} +280 -112
  15. package/dist/{types-DpUO16pj.d.ts → types-C3fE3R9x.d.ts} +280 -112
  16. package/dist.bundle/index.cjs +34933 -0
  17. package/package.json +3 -3
  18. package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
  19. package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
  20. package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
  21. package/src/__tests__/m2-append-content-probe.test.ts +0 -1
  22. package/src/__tests__/manifest-store.test.ts +10 -9
  23. package/src/__tests__/record-store-cache.test.ts +0 -2
  24. package/src/__tests__/record-store-index.test.ts +1 -2
  25. package/src/__tests__/review-fix-loop-script.test.ts +4 -2
  26. package/src/__tests__/review-fix-loop-utils.test.ts +10 -10
  27. package/src/__tests__/robustness-low-batch1.test.ts +6 -5
  28. package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
  29. package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
  30. package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
  31. package/src/__tests__/session-runner.test.ts +1 -1
  32. package/src/core/__tests__/host-services.test.ts +2 -2
  33. package/src/core/__tests__/logger.test.ts +1 -1
  34. package/src/core/error-message.ts +9 -0
  35. package/src/core/host-services.ts +21 -5
  36. package/src/core/notify-ports.ts +18 -5
  37. package/src/execution/__tests__/agent-profile.test.ts +4 -4
  38. package/src/execution/__tests__/agent-registry.test.ts +370 -0
  39. package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
  40. package/src/execution/__tests__/agents-assembly.test.ts +2 -2
  41. package/src/execution/__tests__/alive-store.test.ts +1 -1
  42. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
  43. package/src/execution/__tests__/chat-engine-routing.test.ts +68 -33
  44. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +4 -4
  45. package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
  46. package/src/execution/__tests__/collect-budget.test.ts +291 -0
  47. package/src/execution/__tests__/collect-coordinator-service.test.ts +327 -0
  48. package/src/execution/__tests__/collect-coordinator.test.ts +371 -0
  49. package/src/execution/__tests__/collect-mixed-dispatch.test.ts +262 -0
  50. package/src/execution/__tests__/config-collect-sync.test.ts +120 -0
  51. package/src/execution/__tests__/config.test.ts +1 -1
  52. package/src/execution/__tests__/delivery-methods.test.ts +75 -62
  53. package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
  54. package/src/execution/__tests__/descendant-sweep.test.ts +6 -6
  55. package/src/execution/__tests__/dialog-queue.test.ts +2 -2
  56. package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
  57. package/src/execution/__tests__/epipe-fallback.test.ts +29 -24
  58. package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
  59. package/src/execution/__tests__/execute-nesting.test.ts +34 -188
  60. package/src/execution/__tests__/execution-record.test.ts +217 -60
  61. package/src/execution/__tests__/execution-runtime-face.test.ts +5 -5
  62. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +4 -4
  63. package/src/execution/__tests__/finalize-record.test.ts +173 -17
  64. package/src/execution/__tests__/finalized-marker.test.ts +1 -1
  65. package/src/execution/__tests__/gc-timer.test.ts +56 -3
  66. package/src/execution/__tests__/get-record-for-action-restart.test.ts +12 -12
  67. package/src/execution/__tests__/get-state-handshake.test.ts +1 -1
  68. package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
  69. package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
  70. package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
  71. package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
  72. package/src/execution/__tests__/keep-alive-no-progress.test.ts +50 -148
  73. package/src/execution/__tests__/kill-all-escalation.test.ts +2 -2
  74. package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
  75. package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
  76. package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +1 -1
  77. package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +1 -1
  78. package/src/execution/__tests__/model-resolver.test.ts +2 -2
  79. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
  80. package/src/execution/__tests__/nested-visibility.test.ts +2 -0
  81. package/src/execution/__tests__/notify-batch.test.ts +500 -0
  82. package/src/execution/__tests__/notify-ledger.test.ts +1000 -18
  83. package/src/execution/__tests__/output-collector.test.ts +117 -6
  84. package/src/execution/__tests__/pi-invocation.test.ts +36 -4
  85. package/src/execution/__tests__/record-entry-collect.test.ts +102 -0
  86. package/src/execution/__tests__/record-store.test.ts +10 -9
  87. package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
  88. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
  89. package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
  90. package/src/execution/__tests__/relay-env.test.ts +12 -1
  91. package/src/execution/__tests__/rpc-mode.test.ts +2 -2
  92. package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
  93. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +15 -9
  94. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +4 -4
  95. package/src/execution/__tests__/run-spawn-edges.test.ts +17 -15
  96. package/src/execution/__tests__/run-spawn-integration.test.ts +2 -2
  97. package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
  98. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
  99. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +4 -4
  100. package/src/execution/__tests__/service-kill-escalation.test.ts +7 -5
  101. package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
  102. package/src/execution/__tests__/session-file-gc.test.ts +36 -1
  103. package/src/execution/__tests__/session-pending.test.ts +257 -14
  104. package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
  105. package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +1 -1
  106. package/src/execution/__tests__/session-runner-close-prune.test.ts +2 -2
  107. package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
  108. package/src/execution/__tests__/session-runner-epipe.test.ts +3 -3
  109. package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +5 -4
  110. package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
  111. package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
  112. package/src/execution/__tests__/settled-watchdog.test.ts +282 -47
  113. package/src/execution/__tests__/spawn-args.test.ts +11 -10
  114. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
  115. package/src/execution/__tests__/spawn-event-adapter.test.ts +3 -3
  116. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
  117. package/src/execution/__tests__/spawned-children.test.ts +2 -1
  118. package/src/execution/__tests__/start-collect-guard.test.ts +255 -0
  119. package/src/execution/__tests__/start-sync-model-guard.test.ts +5 -5
  120. package/src/execution/__tests__/stdin-writer.test.ts +6 -4
  121. package/src/execution/__tests__/stream-sink-retirement.test.ts +6 -6
  122. package/src/execution/__tests__/subagent-actions-core.test.ts +48 -22
  123. package/src/execution/__tests__/subagent-service-message-close.test.ts +29 -26
  124. package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +21 -8
  125. package/src/execution/__tests__/subagent-service-notify-gate.test.ts +27 -22
  126. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +30 -29
  127. package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +45 -20
  128. package/src/execution/__tests__/subagent-service.test.ts +37 -30
  129. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
  130. package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
  131. package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
  132. package/src/execution/__tests__/sync-collect-recovery.test.ts +1117 -0
  133. package/src/execution/__tests__/temp-prompt.test.ts +1 -1
  134. package/src/execution/__tests__/timeout-integration.test.ts +6 -5
  135. package/src/execution/__tests__/tombstone-store.test.ts +1 -1
  136. package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
  137. package/src/execution/__tests__/turn-limiter.test.ts +1 -1
  138. package/src/execution/__tests__/ui-request-handler-factory.test.ts +12 -6
  139. package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
  140. package/src/execution/__tests__/ui-request-queue.test.ts +142 -2
  141. package/src/execution/__tests__/worktree-git-ops.test.ts +1 -1
  142. package/src/execution/__tests__/worktree-manager.test.ts +14 -5
  143. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
  144. package/src/execution/__tests__/worktree-reconcile-aging.test.ts +2 -2
  145. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +1 -1
  146. package/src/execution/__tests__/worktree-registry.test.ts +1 -1
  147. package/src/execution/agent-registry.ts +74 -30
  148. package/src/execution/agent-result-mapper.ts +3 -0
  149. package/src/execution/cold-resurrect.ts +199 -0
  150. package/src/execution/collect-coordinator.ts +200 -0
  151. package/src/execution/config.ts +77 -5
  152. package/src/execution/engine/__tests__/common/capability-gate.test.ts +91 -0
  153. package/src/execution/engine/__tests__/common/data-dir.test.ts +1 -1
  154. package/src/execution/engine/__tests__/common/event-journal.test.ts +1 -1
  155. package/src/execution/engine/__tests__/common/journal-wiring.test.ts +84 -0
  156. package/src/execution/engine/__tests__/common/kill-chain.test.ts +34 -7
  157. package/src/execution/engine/__tests__/common/persona-router.test.ts +4 -5
  158. package/src/execution/engine/__tests__/common/pool-manager.test.ts +213 -53
  159. package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +149 -0
  160. package/src/execution/engine/__tests__/common/session-view-service.test.ts +499 -0
  161. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +22 -112
  162. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +15 -28
  163. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +1 -1
  164. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +12 -12
  165. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +2 -2
  166. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +21 -82
  167. package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +4 -7
  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 +4 -2
  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/engines/pi/__tests__/pi-engine.test.ts +174 -28
  181. package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
  182. package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
  183. package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +1 -1
  184. package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
  185. package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
  186. package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
  187. package/src/execution/engine/engines/pi/reader.ts +11 -0
  188. package/src/execution/engine/engines/pi/registration.ts +4 -2
  189. package/src/execution/{session-runner.ts → engine/engines/pi/session-runner.ts} +617 -412
  190. package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
  191. package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
  192. package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
  193. package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
  194. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +54 -27
  195. package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
  196. package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +13 -12
  197. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
  198. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
  199. package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
  200. package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
  201. package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +20 -8
  202. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +77 -110
  203. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +26 -320
  204. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
  205. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
  206. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
  207. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
  208. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +48 -148
  209. package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
  210. package/src/execution/engine/engines/zcode/connection.ts +24 -11
  211. package/src/execution/engine/engines/zcode/constants.ts +75 -71
  212. package/src/execution/engine/engines/zcode/golden-sample.ts +8 -46
  213. package/src/execution/engine/engines/zcode/parser.ts +12 -346
  214. package/src/execution/engine/engines/zcode/preparer.ts +12 -143
  215. package/src/execution/engine/engines/zcode/session-channel.ts +351 -39
  216. package/src/execution/engine/engines/zcode/zcode-engine.ts +665 -760
  217. package/src/execution/engine/host-task-spec.ts +32 -36
  218. package/src/execution/engine/model-validation.ts +177 -0
  219. package/src/execution/engine/port.ts +24 -6
  220. package/src/execution/engine/routing.ts +75 -1
  221. package/src/execution/engine/types.ts +30 -103
  222. package/src/execution/execution-record.ts +229 -144
  223. package/src/execution/finalize-record.ts +141 -99
  224. package/src/execution/idle-gc.ts +28 -0
  225. package/src/execution/lifecycle-predicates.ts +1 -1
  226. package/src/execution/notifier.ts +234 -25
  227. package/src/execution/notify-host.ts +232 -0
  228. package/src/execution/record-entry.ts +16 -0
  229. package/src/execution/record-store.ts +280 -103
  230. package/src/execution/round-settlement.ts +93 -0
  231. package/src/execution/session-file-gc.ts +96 -62
  232. package/src/execution/session-reconstructor.ts +256 -143
  233. package/src/execution/sessions-index.ts +117 -47
  234. package/src/execution/settled-watchdog.ts +264 -52
  235. package/src/execution/subagent-actions-core.ts +84 -28
  236. package/src/execution/subagent-service.ts +1225 -964
  237. package/src/execution/subprocess-agent-runner.ts +144 -97
  238. package/src/execution/sync-rebuild.ts +87 -0
  239. package/src/execution/types.ts +72 -0
  240. package/src/execution/ui-request-handler-factory.ts +102 -74
  241. package/src/execution/ui-request-queue.ts +50 -19
  242. package/src/index.ts +442 -316
  243. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +1 -1
  244. package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
  245. package/src/orchestration/__tests__/args-validator.test.ts +14 -0
  246. package/src/orchestration/__tests__/config-loader.test.ts +1 -1
  247. package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +1 -1
  248. package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +11 -9
  249. package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
  250. package/src/orchestration/__tests__/file-run-store-prune.test.ts +1 -1
  251. package/src/orchestration/__tests__/file-run-store-throttle.test.ts +1 -1
  252. package/src/orchestration/__tests__/file-run-store.test.ts +7 -6
  253. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +2 -2
  254. package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +1 -1
  255. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
  256. package/src/orchestration/__tests__/lifecycle.test.ts +7 -5
  257. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
  258. package/src/orchestration/__tests__/review-fix-loop-scriptpath-failfast.test.ts +1 -1
  259. package/src/orchestration/__tests__/run-snapshot.test.ts +8 -5
  260. package/src/orchestration/__tests__/script-generate.test.ts +5 -5
  261. package/src/orchestration/__tests__/script-lint.test.ts +17 -0
  262. package/src/orchestration/__tests__/skill-discovery.test.ts +2 -2
  263. package/src/orchestration/__tests__/test-mocks.ts +2 -0
  264. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +7 -6
  265. package/src/orchestration/__tests__/worker-message-pump-finalize-run.test.ts +229 -0
  266. package/src/orchestration/__tests__/{error-recovery-handlers.test.ts → worker-message-pump-handlers.test.ts} +27 -19
  267. package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
  268. package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
  269. package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
  270. package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +1 -1
  271. package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
  272. package/src/orchestration/__tests__/workflow-files.test.ts +10 -10
  273. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
  274. package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +1 -1
  275. package/src/orchestration/agent-opts-resolver.ts +1 -1
  276. package/src/orchestration/args-validator.ts +53 -31
  277. package/src/orchestration/execute-agent-call.ts +19 -73
  278. package/src/orchestration/launcher.ts +128 -81
  279. package/src/orchestration/lifecycle.ts +43 -45
  280. package/src/orchestration/models/ports.ts +4 -4
  281. package/src/orchestration/models/run-runtime.ts +2 -2
  282. package/src/orchestration/models/trace.ts +1 -1
  283. package/src/orchestration/models/types.ts +111 -22
  284. package/src/orchestration/models/workflow-run.ts +1 -1
  285. package/src/orchestration/script-lint.ts +91 -58
  286. package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +157 -150
  287. package/src/shared/__tests__/atomic-write.test.ts +1 -1
  288. package/src/shared/__tests__/meta-parser.test.ts +151 -0
  289. package/src/shared/__tests__/resource-discovery-host-roots.test.ts +5 -5
  290. package/src/shared/__tests__/resource-discovery.test.ts +258 -215
  291. package/src/shared/atomic-write.ts +12 -9
  292. package/src/shared/meta-parser.ts +158 -84
  293. package/src/shared/model-ref.ts +15 -2
  294. package/src/shared/resource-discovery.ts +9 -183
  295. package/src/shared/schema-jsonify.ts +1 -1
  296. package/workflows/review-fix-loop-utils.cjs +151 -89
  297. package/workflows/review-fix-loop-utils.d.cts +287 -0
  298. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  299. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  300. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  301. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  302. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  303. package/src/execution/engine/engines/zcode/__tests__/preparer-appserver.test.ts +0 -387
  304. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -710
  305. package/src/execution/engine/engines/zcode/appserver-home.ts +0 -442
  306. package/src/execution/engine/engines/zcode/appserver-probe.ts +0 -141
  307. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  308. package/src/execution/execute-options-mapper.ts +0 -115
  309. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
@@ -0,0 +1,506 @@
1
+ // src/execution/engine/common/session-view-service.ts
2
+ //
3
+ // 非 pi 引擎 record 的 GUI 历史详情读取链单一实现(dual-track-convergence D1:
4
+ // journal 读取链收敛)。收敛三段:①三级降级链编排(引擎原生 reader → journal 重放
5
+ // → outcome-only)②SessionView → HistoryMessage[] 投影(原 runtime 手写版)③引擎
6
+ // 分发(reader registry 查表,取代引擎 id 硬编码分支——接入第三引擎 runtime 零改动)。
7
+ //
8
+ // 收益口径(设计 D1 / r2 审查钉正):守护对称(生产路径从零测试手写副本切到
9
+ // conformance C5 守护的 updateFromEvent reducer)+ engine-generic 正确性
10
+ // (message_end 携带 error 的记账语义就位);对现役 zcode 是内容 parity——同一
11
+ // journal 输入,新旧链投影输出等价(zcode 现役 journal 形态 = coarse 两事件
12
+ // [message_end(usage), turn_end] 与失败态 [error(, message_end, turn_end)],两者
13
+ // 的新旧投影逐字段一致,见 __tests__ 的 parity 用例)。
14
+ //
15
+ // ②级重放的 reducer 唯一性:turns 累积走 execution-record.updateFromEvent(C5
16
+ // conformance 守护实现,journal 重放与 live 通路共用同一 reducer)——本模块不持有
17
+ // 第二套事件 reducer。与原 runtime 手写 reducer 的两个已知投影差异均为现役不可达
18
+ // 形态(zcode journal 不产出),属「记账语义就位」的新增行为而非 parity 破坏:
19
+ // - message_end 带 error 且其后无 turn_end 清除 → 记账进末条 assistant 的
20
+ // status='error' + error 字段(原手写版不记——设计 §2.2 #1 漂移维度,收敛方向
21
+ // 以守护实现为准);
22
+ // - 交错多 error 事件(独立 error 事件 × N 且与 turn_end 交错)→ 收敛为单条物化
23
+ // 消息(现役 zcode 每任务至多 emit 一个 error 事件,形态不可达)。
24
+ //
25
+ // pi 分支维持现状(A1 守护):pi 历史走 runtime 自有 JSONL 直读链
26
+ // (session-service.getSubagentHistory),不经本模块;engineId='pi' 的防御分支
27
+ // 返回空数组,与被收敛前的 runtime 实现一致。
28
+
29
+ import { randomUUID } from "node:crypto";
30
+ import { homedir } from "node:os";
31
+ import { isAbsolute, relative, resolve } from "node:path";
32
+
33
+ // 相对 import 用 .js 形态(本文件是双端复用模块,被 xyz-agent runtime import——对齐
34
+ // engines/zcode/reader.ts 先例:runtime tsconfig 无 allowImportingTsExtensions,.ts
35
+ // 形态在 runtime tsc 下报 TS5097;.js 后缀经 bundler/ESM 解析器 substitution 到 .ts)。
36
+ import { getLogger } from "../../../core/logger.js";
37
+ import { createRecord, updateFromEvent } from "../../execution-record.js";
38
+ import type { Turn } from "../../types.js";
39
+ import { readZcodeSessionView } from "../engines/zcode/reader.js";
40
+ import { ZCODE_ENGINE_ID, ZCODE_HOST_DB_SUFFIX } from "../engines/zcode/constants.js";
41
+ import { resolveEnginesRoot, resolvePoolDir } from "../paths.js";
42
+ import type { SessionView } from "../types.js";
43
+ import { replayJournal } from "./event-journal.js";
44
+ import { aggregateUsage } from "./session-view-projection.js";
45
+ import type {
46
+ EngineHandleView,
47
+ EngineToolCallSource,
48
+ HistoryMessage,
49
+ HistoryToolCallView,
50
+ SubagentRecordSnapshot,
51
+ } from "./session-view-types.js";
52
+ import { parseEngineHandle } from "./session-view-types.js";
53
+ import { toErrorMessage } from "../../../core/error-message.ts";
54
+
55
+ const logger = getLogger("subagents");
56
+
57
+ /**
58
+ * 缺省引擎 id(与 registry.ts 的 DEFAULT_ENGINE_ID 同值本地锚定——对齐
59
+ * engines/pi/reader.ts 的 PI_ENGINE_ID 先例:import registry 会连带 port.ts →
60
+ * stream-sink.ts 的 .ts 后缀值 import 链进 runtime tsc 编译图,破坏双端复用闭包
61
+ * 约束;锚定漂移由本包 registry.test / 读取链测试双重守护)。
62
+ */
63
+ const DEFAULT_ENGINE_ID = "pi";
64
+
65
+ // ============================================================
66
+ // 引擎 id 提取(record 路由段)
67
+ // ============================================================
68
+
69
+ /**
70
+ * record 的引擎路由段:engine 非 string 或空串 → 缺省 pi(存量 record 零迁移)。
71
+ * 与被收敛前的 runtime extractRecordEngine 语义一致(非 trim 透传——空白 id 由
72
+ * reader registry miss 落③级,与旧行为等价)。
73
+ */
74
+ export function extractEngineId(record: SubagentRecordSnapshot): string {
75
+ const engine = record.engine;
76
+ return typeof engine === "string" && engine.length > 0 ? engine : DEFAULT_ENGINE_ID;
77
+ }
78
+
79
+ // ============================================================
80
+ // reader registry(③引擎分发:查表取代引擎 id 硬编码)
81
+ // ============================================================
82
+
83
+ /**
84
+ * 引擎原生 reader(①级):handle + dataDir → SessionView。
85
+ * 返回 undefined = 本级不可达/失败(编排层降②级);reader 内部自行留 debug 日志。
86
+ * 双端复用约束(设计 §3.3.7,与 zcode/reader.ts 同款):实现必须无状态纯函数、
87
+ * 不 import 引擎运行时件(launcher/preparer/parser)。
88
+ */
89
+ export type NativeSessionReader = (
90
+ handle: EngineHandleView,
91
+ dataDir: string,
92
+ ) => Promise<SessionView | undefined>;
93
+
94
+ /** 进程级注册表槽位(globalThis[Symbol.for] 防 jiti 双路径加载分裂,对齐 registry.ts 惯例)。 */
95
+ const NATIVE_READER_SLOT_KEY = Symbol.for(
96
+ "@zhushanwen/pi-subagent-workflow.nativeSessionReaders",
97
+ );
98
+
99
+ function getReaderSlot(): Map<string, NativeSessionReader> {
100
+ let slot = Reflect.get(globalThis, NATIVE_READER_SLOT_KEY) as
101
+ | Map<string, NativeSessionReader>
102
+ | undefined;
103
+ if (!slot) {
104
+ slot = new Map();
105
+ // 内置注册:core 自带 reader 的引擎(当前仅 zcode——pi 的历史读取按 D1 范围声明
106
+ // 走 runtime 自有 JSONL 直读链,不注册原生 reader)
107
+ slot.set(ZCODE_ENGINE_ID, readZcodeNativeTier);
108
+ Reflect.set(globalThis, NATIVE_READER_SLOT_KEY, slot);
109
+ }
110
+ return slot;
111
+ }
112
+
113
+ /**
114
+ * 登记引擎原生 reader(未来引擎 / 测试注入 fake 用)。重复注册同 id = 覆盖
115
+ * (幂等,对齐 registerEngine 惯例)。生产调用方 = core 内新引擎的接入模块;
116
+ * xyz-agent runtime 不需要注册(zcode 内置)。
117
+ */
118
+ export function registerNativeSessionReader(engineId: string, reader: NativeSessionReader): void {
119
+ getReaderSlot().set(engineId, reader);
120
+ }
121
+
122
+ /** 查表(未注册引擎返回 undefined → 编排层落③级,行为面与旧「无 native reader 分支」一致)。 */
123
+ function lookupNativeSessionReader(engineId: string): NativeSessionReader | undefined {
124
+ return getReaderSlot().get(engineId);
125
+ }
126
+
127
+ /** 清空注册表并重置为内置集(测试隔离专用,生产禁用——对齐 clearEngines 惯例)。 */
128
+ export function resetNativeSessionReaders(): void {
129
+ const slot = getReaderSlot();
130
+ slot.clear();
131
+ slot.set(ZCODE_ENGINE_ID, readZcodeNativeTier);
132
+ }
133
+
134
+ // ============================================================
135
+ // ①级:zcode sqlite 原生读取(内置注册的 reader)
136
+ // ============================================================
137
+
138
+ /**
139
+ * zcode ①级 reader:sessionRef 的 dbPath/sessionId 重定位 + 白名单 +
140
+ * readZcodeSessionView(extension/runtime 双端复用的同一份 reader)。
141
+ * 语义复刻被收敛前的 runtime readZcodeNativeTier(含共享宿主 HOME 形态的绝对
142
+ * dbPath 精确白名单):绝对 dbPath 只认宿主 zcode 会话 db(ZCODE_HOST_DB_SUFFIX
143
+ * SSOT 推导,防任意读);相对路径锚池目录 resolve,越界路径(../ 逃逸 / 跨池)
144
+ * 拒绝降②级;读取失败(结构化错误)降②级。
145
+ */
146
+ async function readZcodeNativeTier(
147
+ handle: EngineHandleView,
148
+ dataDir: string,
149
+ ): Promise<SessionView | undefined> {
150
+ const dbPathRaw = handle.sessionRef["dbPath"];
151
+ const sessionId = handle.sessionRef["sessionId"];
152
+ if (typeof dbPathRaw !== "string" || typeof sessionId !== "string") {
153
+ logger.debug("[session-view-service] zcode tier1 skipped: handle missing dbPath/sessionId");
154
+ return undefined;
155
+ }
156
+ let dbPath: string;
157
+ if (dbPathRaw.startsWith("/")) {
158
+ // 共享宿主 HOME 形态(2026-09 起,写侧 zcode-engine 恒绝对路径):唯一合法绝对
159
+ // 路径 = 宿主 zcode 会话 db(record 来自 JSONL 文本不可信,精确匹配 core SSOT
160
+ // 后缀拼出的路径,防任意读)
161
+ if (dbPathRaw !== resolve(homedir(), ...ZCODE_HOST_DB_SUFFIX)) {
162
+ logger.warn(
163
+ `[session-view-service] zcode absolute dbPath not host db, reject tier1: ${dbPathRaw}`,
164
+ );
165
+ return undefined;
166
+ }
167
+ dbPath = dbPathRaw;
168
+ } else {
169
+ // 旧池时代 records(HOME 池化时期):相对路径锚池目录重定位,白名单防逃逸
170
+ const poolDir = resolvePoolDir(dataDir, ZCODE_ENGINE_ID, handle.poolKey);
171
+ dbPath = resolve(poolDir, dbPathRaw);
172
+ if (!isStrictlyUnder(poolDir, dbPath)) {
173
+ logger.warn(`[session-view-service] zcode dbPath escapes pool dir, reject tier1: ${dbPath}`);
174
+ return undefined;
175
+ }
176
+ }
177
+ try {
178
+ return await readZcodeSessionView(dbPath, sessionId);
179
+ } catch (err) {
180
+ logger.debug(
181
+ `[session-view-service] zcode tier1 read failed, degrade to journal tier: ` +
182
+ `${toErrorMessage(err)}`,
183
+ );
184
+ return undefined;
185
+ }
186
+ }
187
+
188
+ // ============================================================
189
+ // ②级:宿主 event journal 重放(C5 守护 reducer)
190
+ // ============================================================
191
+
192
+ /**
193
+ * ②级:journalPath 白名单 + 重放。返回 undefined = 本级不可达 / 重放无内容(降③级)。
194
+ */
195
+ function readJournalTier(
196
+ record: SubagentRecordSnapshot,
197
+ handle: EngineHandleView,
198
+ dataDir: string,
199
+ ): HistoryMessage[] | undefined {
200
+ const journalPath = handle.journalPath;
201
+ if (journalPath === undefined) {
202
+ logger.debug("[session-view-service] tier2 skipped: no journalPath in handle");
203
+ return undefined;
204
+ }
205
+ if (!isStrictlyUnder(resolveEnginesRoot(dataDir), journalPath)) {
206
+ logger.warn(
207
+ `[session-view-service] journalPath escapes engines root, reject tier2: ${journalPath}`,
208
+ );
209
+ return undefined;
210
+ }
211
+ const messages = replayEventsToHistory(replayJournal(journalPath), record);
212
+ if (messages === undefined) {
213
+ logger.debug(
214
+ `[session-view-service] tier2 journal replay produced no content, degrade to outcome-only ` +
215
+ `(path=${journalPath})`,
216
+ );
217
+ }
218
+ return messages;
219
+ }
220
+
221
+ /** ①②级共用的中间 turn 形状(投影到 HistoryMessage 前的聚合单元)。 */
222
+ interface HistoryTurnView {
223
+ text: string;
224
+ thinking: string;
225
+ toolCalls: EngineToolCallSource[];
226
+ usage?: { input: number; output: number };
227
+ }
228
+
229
+ /**
230
+ * journal 事件流 → HistoryMessage[](②级重放的投影半段)。
231
+ *
232
+ * turns 累积 = updateFromEvent(C5 守护 reducer,唯一实现)。本函数只做投影决策:
233
+ * - 有内容 turn(text/thinking/toolCalls 任一非空)→ 逐 turn 投影(per-turn
234
+ * usageDelta → Message.usage,与旧手写 reducer 的 message_end 挂点一致);
235
+ * - 无内容但事件流含独立 error 事件(或 reducer 记账的 lastError 存活)→ 物化单条
236
+ * assistant(旧手写 reducer 的 applyErrorEvent「错误文本落空 turn」语义的投影面;
237
+ * 现役 zcode 失败 journal 即此形态);
238
+ * - 全空 → undefined(降③级——zcode 成功 journal 的 coarse 两事件重放无内容,
239
+ * 与旧链 sawAssistantContent=false 同落点)。
240
+ */
241
+ function replayEventsToHistory(
242
+ events: ReturnType<typeof replayJournal>,
243
+ record: SubagentRecordSnapshot,
244
+ ): HistoryMessage[] | undefined {
245
+ if (events.length === 0) return undefined;
246
+ // createRecord 参数取 journal-replay.ts eventsToSessionView 的同款中性占位——
247
+ // record 身份字段不参与投影(投影输入是外部 record 快照),只需 turns 累积容器
248
+ const replayRecord = createRecord("journal-replay", {
249
+ agent: "journal-replay",
250
+ model: "",
251
+ mode: "background",
252
+ task: "",
253
+ slug: "",
254
+ startedAt: 0,
255
+ });
256
+ for (const ev of events) updateFromEvent(replayRecord, ev);
257
+
258
+ const contentTurns = replayRecord.turns.filter(hasTurnContent);
259
+ if (contentTurns.length > 0) {
260
+ const messages = turnsToMessages(
261
+ contentTurns.map(turnToHistoryTurnView),
262
+ record,
263
+ );
264
+ // message_end.error 的记账语义(engine-generic,现役 zcode 不可达):存活至重放
265
+ // 末尾的 lastError 落到末条 assistant 的 status/error 字段——守护实现的记账
266
+ // 随投影就位(设计 D1「未来 parser 演进或新引擎接入产出该形态时正确生效」)。
267
+ if (replayRecord.lastError !== undefined) {
268
+ applyAccountedError(messages, replayRecord.lastError);
269
+ }
270
+ return messages;
271
+ }
272
+
273
+ const materializedError = firstStandaloneErrorMessage(events) ?? replayRecord.lastError;
274
+ if (materializedError !== undefined) {
275
+ // 物化单条 assistant:text = 首个 error 事件文本;usage = 全 turn 聚合
276
+ // ([error, message_end(usage), turn_end] 形态下 usage 落在无内容 turn 上,
277
+ // 聚合后随物化消息带出——与旧链「同 turn text+usage」逐字段一致)。
278
+ const usage = aggregateUsage(replayRecord.turns);
279
+ return turnsToMessages(
280
+ [
281
+ {
282
+ text: materializedError,
283
+ thinking: "",
284
+ toolCalls: [],
285
+ ...(usage !== undefined ? { usage: { input: usage.input, output: usage.output } } : {}),
286
+ },
287
+ ],
288
+ record,
289
+ );
290
+ }
291
+ return undefined;
292
+ }
293
+
294
+ function hasTurnContent(turn: Turn): boolean {
295
+ return turn.text !== "" || turn.thinking !== "" || turn.toolCalls.length > 0;
296
+ }
297
+
298
+ /** Turn(reducer 内部态)→ 投影中间形状(usageDelta → usage,剥内部字段)。 */
299
+ function turnToHistoryTurnView(turn: Turn): HistoryTurnView {
300
+ return {
301
+ text: turn.text,
302
+ thinking: turn.thinking,
303
+ toolCalls: turn.toolCalls,
304
+ ...(turn.usageDelta !== undefined
305
+ ? { usage: { input: turn.usageDelta.input, output: turn.usageDelta.output } }
306
+ : {}),
307
+ };
308
+ }
309
+
310
+ /** 事件流中首个独立 error 事件的 message(物化分支的数据源;非 reducer,纯过滤)。 */
311
+ function firstStandaloneErrorMessage(events: ReturnType<typeof replayJournal>): string | undefined {
312
+ for (const ev of events) {
313
+ if (ev.type === "error" && typeof ev.message === "string" && ev.message.length > 0) {
314
+ return ev.message;
315
+ }
316
+ }
317
+ return undefined;
318
+ }
319
+
320
+ /** 存活 lastError → 末条 assistant 记账(status='error' + error 字段同源)。 */
321
+ function applyAccountedError(messages: HistoryMessage[], lastError: string): void {
322
+ for (let i = messages.length - 1; i >= 0; i--) {
323
+ const msg = messages[i];
324
+ if (msg !== undefined && msg.role === "assistant") {
325
+ msg.status = "error";
326
+ msg.error = lastError;
327
+ return;
328
+ }
329
+ }
330
+ }
331
+
332
+ // ============================================================
333
+ // 投影(HistoryTurnView[] / SessionView → HistoryMessage[])
334
+ // ============================================================
335
+
336
+ /** ①级 SessionView → HistoryMessage[](usage 聚合挂最后一个 turn 供 GUI 展示)。 */
337
+ function sessionViewToMessages(
338
+ view: SessionView,
339
+ record: SubagentRecordSnapshot,
340
+ ): HistoryMessage[] {
341
+ const turns: HistoryTurnView[] = view.turns.map((t) => ({
342
+ text: t.text,
343
+ thinking: t.thinking,
344
+ toolCalls: t.toolCalls,
345
+ }));
346
+ if (view.usage !== undefined && turns.length > 0) {
347
+ const last = turns[turns.length - 1];
348
+ if (last !== undefined) {
349
+ last.usage = { input: view.usage.input, output: view.usage.output };
350
+ }
351
+ }
352
+ return turnsToMessages(turns, record);
353
+ }
354
+
355
+ /** HistoryTurnView[] → HistoryMessage[](①②级共用投影;user task 前置一条)。 */
356
+ function turnsToMessages(
357
+ turns: HistoryTurnView[],
358
+ record: SubagentRecordSnapshot,
359
+ ): HistoryMessage[] {
360
+ const base = record.startedAt ?? Date.now();
361
+ const messages: HistoryMessage[] = [];
362
+ if (record.task.length > 0) {
363
+ messages.push({
364
+ id: randomUUID(),
365
+ role: "user",
366
+ content: record.task,
367
+ status: "complete",
368
+ timestamp: base,
369
+ });
370
+ }
371
+ for (const [i, turn] of turns.entries()) {
372
+ messages.push({
373
+ id: randomUUID(),
374
+ role: "assistant",
375
+ content: turn.text,
376
+ status: "complete",
377
+ ...(turn.thinking.length > 0
378
+ ? { thinking: [{ id: randomUUID(), content: turn.thinking, collapsed: true }] }
379
+ : {}),
380
+ ...(turn.toolCalls.length > 0
381
+ ? { toolCalls: turn.toolCalls.map((tc) => toHistoryToolCall(tc, base + i + 1)) }
382
+ : {}),
383
+ ...(turn.usage !== undefined
384
+ ? { usage: { inputTokens: turn.usage.input, outputTokens: turn.usage.output } }
385
+ : {}),
386
+ timestamp: base + i + 1,
387
+ });
388
+ }
389
+ return messages;
390
+ }
391
+
392
+ /** 引擎 toolCall → GUI 工具调用视图(id/时间戳为展示占位)。 */
393
+ function toHistoryToolCall(tc: EngineToolCallSource, ts: number): HistoryToolCallView {
394
+ const output = extractTextFromContent(tc.result?.content);
395
+ const details = tc.result?.details;
396
+ return {
397
+ id: randomUUID(),
398
+ toolName: tc.toolName,
399
+ input: tc.args ?? {},
400
+ ...(output !== undefined ? { output } : {}),
401
+ ...(typeof details === "object" && details !== null && !Array.isArray(details)
402
+ ? { details: details as Record<string, unknown> }
403
+ : {}),
404
+ status: tc.isError === true ? "error" : "completed",
405
+ startTime: ts,
406
+ endTime: ts,
407
+ };
408
+ }
409
+
410
+ /** tool result content(unknown[])→ 拼接文本(string 元素 + {type:'text',text} 块)。 */
411
+ function extractTextFromContent(content: unknown[] | undefined): string | undefined {
412
+ if (content === undefined) return undefined;
413
+ let text = "";
414
+ for (const block of content) {
415
+ if (typeof block === "string") {
416
+ text += block;
417
+ } else if (typeof block === "object" && block !== null) {
418
+ const b = block as { type?: unknown; text?: unknown };
419
+ if (b.type === "text" && typeof b.text === "string") text += b.text;
420
+ }
421
+ }
422
+ return text.length > 0 ? text : undefined;
423
+ }
424
+
425
+ // ============================================================
426
+ // ③级:outcome-only(摘要卡数据源)
427
+ // ============================================================
428
+
429
+ /**
430
+ * ③级:outcome-only 投影(record 现有字段就够)。①②级都不可达时兜底,
431
+ * 永不返回空数组(详情页至少有 task/结果)。
432
+ */
433
+ function outcomeOnlyMessages(record: SubagentRecordSnapshot): HistoryMessage[] {
434
+ const base = record.startedAt ?? Date.now();
435
+ const messages: HistoryMessage[] = [];
436
+ if (record.task.length > 0) {
437
+ messages.push({
438
+ id: randomUUID(),
439
+ role: "user",
440
+ content: record.task,
441
+ status: "complete",
442
+ timestamp: base,
443
+ });
444
+ }
445
+ const isErrorOutcome = record.result === undefined && record.error !== undefined;
446
+ messages.push({
447
+ id: randomUUID(),
448
+ role: "assistant",
449
+ // result 优先(正常轮终文本);error 次之(失败终态);双缺占位(运行中被杀等)
450
+ content: record.result ?? record.error ?? "(no outcome recorded)",
451
+ status: isErrorOutcome ? "error" : "complete",
452
+ timestamp: record.endedAt ?? base,
453
+ ...(isErrorOutcome && record.error !== undefined ? { error: record.error } : {}),
454
+ });
455
+ return messages;
456
+ }
457
+
458
+ // ============================================================
459
+ // 主入口(三级降级编排)
460
+ // ============================================================
461
+
462
+ /**
463
+ * 非 pi record 的历史详情读取(三级降级主入口,D1 收敛后的唯一生产实现)。
464
+ *
465
+ * 降级顺序 ①→②→③ 逐级尝试,每级失败留 debug/warn 日志不抛崩溃(GUI 详情页
466
+ * 永不白屏报错,设计 A8)。engineId='pi' 返回 [](pi 的①级 = 调用方现有 JSONL
467
+ * 直读链,A1 守护)。未注册 reader 的引擎(未来)直接落③级——record 字段就够,
468
+ * 详情页至少有摘要卡。
469
+ *
470
+ * @param record record 快照(engine/engineHandle 为不可信源,内部守卫消费)
471
+ * @param dataDir xyz-agent 数据根(journal/dbPath 白名单经 paths.ts 布局 SSOT 推导)
472
+ */
473
+ export async function readSubagentHistoryMessages(
474
+ record: SubagentRecordSnapshot,
475
+ dataDir: string,
476
+ ): Promise<HistoryMessage[]> {
477
+ const engineId = extractEngineId(record);
478
+ if (engineId === DEFAULT_ENGINE_ID) return [];
479
+ const handle = parseEngineHandle(record.engineHandle);
480
+ if (handle === undefined) {
481
+ logger.debug(
482
+ `[session-view-service] engine '${engineId}' record has no engineHandle, ` +
483
+ `degrade to outcome-only (subagentId=${record.subagentId})`,
484
+ );
485
+ return outcomeOnlyMessages(record);
486
+ }
487
+ const reader = lookupNativeSessionReader(engineId);
488
+ if (reader === undefined) {
489
+ logger.debug(
490
+ `[session-view-service] engine '${engineId}' has no native reader tier, ` +
491
+ `degrade to outcome-only (subagentId=${record.subagentId})`,
492
+ );
493
+ return outcomeOnlyMessages(record);
494
+ }
495
+ const native = await reader(handle, dataDir);
496
+ if (native !== undefined) return sessionViewToMessages(native, record);
497
+ const journaled = readJournalTier(record, handle, dataDir);
498
+ if (journaled !== undefined) return journaled;
499
+ return outcomeOnlyMessages(record);
500
+ }
501
+
502
+ /** 路径白名单判定(语义复刻 runtime path-utils.isStrictlyUnder:严格子路径,不含自身)。 */
503
+ function isStrictlyUnder(parent: string, child: string): boolean {
504
+ const rel = relative(resolve(parent), resolve(child));
505
+ return rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
506
+ }
@@ -0,0 +1,125 @@
1
+ // src/execution/engine/common/session-view-types.ts
2
+ //
3
+ // session-view-service 的窄接口层 + engineHandle 单一守卫(dual-track-convergence D1:
4
+ // 双守卫收敛——此前 runtime subagent-extractor.projectEngineHandle 与
5
+ // subagent-engine-history.extractRecordEngineHandle 两份 guard 各自演进,收敛为本文件
6
+ // 的 parseEngineHandle 唯一实现,读写两侧共用)。
7
+ //
8
+ // 零相对 import(纯类型 + 纯函数):本文件与 zcode/reader.ts 同属「双端复用模块」
9
+ // (设计 §3.3.7——xyz-agent runtime 可直接 import,不连带 core 内部 .ts 后缀 import 链
10
+ // 进 runtime tsc 编译图)。改动本文件时保持该约束。
11
+ //
12
+ // 为什么不 import @xyz-agent/shared 的 Message/SubagentRecord:shared 是 workspace
13
+ // private 包(不发 npm),而本包是 dual-form 发布包(npm 消费面见 package.json
14
+ // publishConfig)——import shared 会把 private 依赖拖进发布闭包。输出类型采用
15
+ // 结构兼容形状(HistoryMessage 是 shared Message 的结构子集),runtime 侧靠 TS
16
+ // 结构类型直接赋值,兼容性由 runtime 消费点类型检查 + 本包投影测试双重守护。
17
+
18
+ /**
19
+ * record 携带的引擎 handle 消费面(EngineHandleData 的结构子集,双端契约不变):
20
+ * journalPath 绝对路径;sessionRef 内 dbPath 相对池目录 / 绝对路径均可。
21
+ */
22
+ export interface EngineHandleView {
23
+ /** 引擎自定义定位符(zcode = { sessionId, dbPath })。 */
24
+ sessionRef: Record<string, string>;
25
+ /** journal 绝对路径(②级数据源;读前校验 engines 根前缀白名单)。 */
26
+ journalPath?: string;
27
+ /** 隔离池定位(路径布局 SSOT:resolvePoolDir 消费)。 */
28
+ poolKey: string;
29
+ }
30
+
31
+ /**
32
+ * 历史读取输入的 record 快照(消费字段级子集,不绑定 runtime 的完整
33
+ * SubagentRecord 形状——core 不 import workspace private 类型)。
34
+ * engine / engineHandle 是不可信源(JSONL 文本派生),由 extractEngineId /
35
+ * parseEngineHandle 守卫式消费。
36
+ */
37
+ export interface SubagentRecordSnapshot {
38
+ subagentId: string;
39
+ task: string;
40
+ result?: string;
41
+ error?: string;
42
+ startedAt?: number;
43
+ endedAt?: number;
44
+ /** record.engine('pi' | 'zcode' | ...,缺省 = pi 由 extractEngineId 归一)。 */
45
+ engine?: unknown;
46
+ /** record.engineHandle(parseEngineHandle 守卫消费)。 */
47
+ engineHandle?: unknown;
48
+ }
49
+
50
+ /** 引擎 toolCall 投影到 GUI 消费形状前的最小消费面(core ToolCall 的结构子集)。 */
51
+ export interface EngineToolCallSource {
52
+ toolName: string;
53
+ args?: unknown;
54
+ result?: { content?: unknown[]; details?: unknown };
55
+ isError?: boolean;
56
+ }
57
+
58
+ /** GUI 工具调用视图(结构兼容 shared ToolCall 的消费子集;id/时间戳为展示占位)。 */
59
+ export interface HistoryToolCallView {
60
+ id: string;
61
+ toolName: string;
62
+ input: unknown;
63
+ output?: string;
64
+ details?: Record<string, unknown>;
65
+ status: "completed" | "error";
66
+ startTime: number;
67
+ endTime: number;
68
+ }
69
+
70
+ /** GUI thinking 块视图(结构兼容 shared ThinkingBlock)。 */
71
+ export interface HistoryThinkingView {
72
+ id: string;
73
+ content: string;
74
+ collapsed: boolean;
75
+ }
76
+
77
+ /** GUI usage 视图(结构兼容 shared Usage)。 */
78
+ export interface HistoryUsageView {
79
+ inputTokens: number;
80
+ outputTokens: number;
81
+ }
82
+
83
+ /** GUI 消息视图(结构兼容 shared Message 的消费子集——见文件头「为什么不 import shared」)。 */
84
+ export interface HistoryMessage {
85
+ id: string;
86
+ role: "user" | "assistant";
87
+ content: string;
88
+ status: "complete" | "error";
89
+ toolCalls?: HistoryToolCallView[];
90
+ thinking?: HistoryThinkingView[];
91
+ usage?: HistoryUsageView;
92
+ timestamp: number;
93
+ error?: string;
94
+ }
95
+
96
+ function isPlainRecord(v: unknown): v is Record<string, unknown> {
97
+ return typeof v === "object" && v !== null && !Array.isArray(v);
98
+ }
99
+
100
+ /**
101
+ * engineHandle 唯一守卫(D1 双守卫收敛点)。
102
+ * 语义取收敛前 extractor 侧的严格版(两份 guard 此前已在「sessionRef 含非 string 值」
103
+ * 维度分叉:extractor 整体拒绝、history 侧逐键过滤——收敛选整体拒绝,坏形状不进
104
+ * record,读侧按缺 handle 降级 outcome-only,两侧行为面等价落点都是降级):
105
+ * - poolKey 缺失 / 非 string / 空串 → undefined(定位符不完整,读侧降③级)
106
+ * - sessionRef 非 plain object 或含非 string 值 → undefined(整体拒绝)
107
+ * - journalPath 可选 string(空串视为缺省)
108
+ */
109
+ export function parseEngineHandle(raw: unknown): EngineHandleView | undefined {
110
+ if (!isPlainRecord(raw)) return undefined;
111
+ if (typeof raw.poolKey !== "string" || raw.poolKey.length === 0) return undefined;
112
+ if (!isPlainRecord(raw.sessionRef)) return undefined;
113
+ const sessionRef: Record<string, string> = {};
114
+ for (const [key, value] of Object.entries(raw.sessionRef)) {
115
+ if (typeof value !== "string") return undefined;
116
+ sessionRef[key] = value;
117
+ }
118
+ const journalPath =
119
+ typeof raw.journalPath === "string" && raw.journalPath.length > 0 ? raw.journalPath : undefined;
120
+ return {
121
+ sessionRef,
122
+ ...(journalPath !== undefined ? { journalPath } : {}),
123
+ poolKey: raw.poolKey,
124
+ };
125
+ }