@tea-agent/loop-agent 0.43.0-next.9 → 0.43.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 (287) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +31 -2309
  3. package/README.md +7 -0
  4. package/dist/application/dag/args.js +8 -0
  5. package/dist/application/task-lifecycle/advance.js +38 -7
  6. package/dist/build-stamp.json +3 -3
  7. package/dist/cli/command-definitions.js +2 -0
  8. package/dist/cli/program.js +3 -1
  9. package/dist/cli/update/init-surface-notifier.js +2 -0
  10. package/dist/cli/update/policy.js +2 -0
  11. package/dist/commands/client-recovery.js +20 -55
  12. package/dist/commands/cursor-prompt.js +2 -0
  13. package/dist/commands/dag-approve.js +2 -0
  14. package/dist/commands/dag-final-verification.js +2 -0
  15. package/dist/commands/dag-init-hybrid.js +2 -0
  16. package/dist/commands/dag-reconcile-tasks.js +2 -0
  17. package/dist/commands/dag-reject.js +2 -0
  18. package/dist/commands/dag-report.js +2 -0
  19. package/dist/commands/dag-rerun.js +2 -0
  20. package/dist/commands/dag-resume.js +2 -0
  21. package/dist/commands/dag-workflow-compile.js +2 -0
  22. package/dist/commands/dag-workflow-plan.js +2 -0
  23. package/dist/commands/dag-workflow-validate.js +2 -0
  24. package/dist/commands/delegate.js +2 -0
  25. package/dist/commands/examples.js +2 -0
  26. package/dist/commands/import-prd.js +2 -0
  27. package/dist/commands/init-model-catalog.js +2 -0
  28. package/dist/commands/init.js +19 -13
  29. package/dist/commands/instructions.js +2 -0
  30. package/dist/commands/knowledge.js +2 -0
  31. package/dist/commands/loop-benchmark.js +2 -0
  32. package/dist/commands/pi-prompt.js +2 -0
  33. package/dist/commands/pi-reuse-benchmark.js +2 -0
  34. package/dist/commands/promote-run.js +2 -0
  35. package/dist/commands/stats.js +1 -1
  36. package/dist/commands/study-init.js +2 -0
  37. package/dist/commands/task-advance.js +34 -0
  38. package/dist/commands/task-source-prepare.js +2 -0
  39. package/dist/commands/worktree-create.js +2 -0
  40. package/dist/commands/worktree-remove.js +2 -0
  41. package/dist/executors/dag-pi-executor.js +1650 -198
  42. package/dist/executors/pi-executor.js +85 -3
  43. package/dist/executors/pi-sdk-executor.js +18 -0
  44. package/dist/executors/shell-executor.js +93 -7
  45. package/dist/executors/shell-verification.js +3 -0
  46. package/dist/executors/shell-write-guard.js +27 -32
  47. package/dist/governance/exec-plans.js +6 -3
  48. package/dist/infrastructure/console/app-data.js +6 -0
  49. package/dist/shared/artifacts-core.js +2 -0
  50. package/dist/shared/backend-dogfood-preflight.js +47 -0
  51. package/dist/shared/dag-failure-category.js +3 -0
  52. package/dist/shared/git-progress.js +2 -0
  53. package/dist/shared/one-shot-prompt-args.js +2 -0
  54. package/dist/shared/operator/capabilities.js +180 -0
  55. package/dist/shared/package-metadata.js +6 -4
  56. package/dist/shared/pi-context-pressure/extension.js +26 -16
  57. package/dist/shared/pi-context-pressure/sift-bridge.js +1 -1
  58. package/dist/shared/pi-provider-recovery.js +182 -0
  59. package/dist/shared/pi-retry-settings.js +40 -0
  60. package/dist/shared/reference-context.js +2 -0
  61. package/dist/task/config-types.js +29 -0
  62. package/dist/task/contract/project.js +9 -0
  63. package/dist/task/contract/recover.js +6 -0
  64. package/dist/task/contract/schema.js +17 -0
  65. package/dist/task/source-prepare/artifact-meta.js +9 -2
  66. package/dist/task/source-prepare/build-draft.js +60 -0
  67. package/dist/task/source-prepare/fragment-inventory.js +4 -1
  68. package/dist/task/source-prepare/parse-intent.js +36 -11
  69. package/dist/task/task-demand-routing.js +5 -2
  70. package/dist/worker/console/chat/browser-automation.js +523 -0
  71. package/dist/worker/console/chat/browser-policy.js +6 -36
  72. package/dist/worker/console/chat/browser-routes.js +188 -56
  73. package/dist/worker/console/chat/explore-tools.js +5 -2
  74. package/dist/worker/console/chat/pi-mode-loop-isolation.js +155 -0
  75. package/dist/worker/console/chat/pi-runtime/custom-tools/ask-user-question.js +44 -0
  76. package/dist/worker/console/chat/pi-runtime/custom-tools/browser-tools.js +184 -0
  77. package/dist/worker/console/chat/pi-runtime/custom-tools/explore-tools.js +202 -0
  78. package/dist/worker/console/chat/pi-runtime/custom-tools/goal-tools.js +79 -0
  79. package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +94 -0
  80. package/dist/worker/console/chat/pi-runtime/custom-tools/scheduled-goal-tools.js +22 -0
  81. package/dist/worker/console/chat/pi-runtime/custom-tools/todo-write.js +38 -0
  82. package/dist/worker/console/chat/pi-runtime/inspection-types.js +28 -0
  83. package/dist/worker/console/chat/pi-runtime/inspection.js +439 -0
  84. package/dist/worker/console/chat/pi-runtime/progressive-tools.js +195 -0
  85. package/dist/worker/console/chat/pi-runtime/sdk-bindings.js +153 -0
  86. package/dist/worker/console/chat/pi-runtime/sdk-session.js +5 -0
  87. package/dist/worker/console/chat/pi-runtime.js +208 -1138
  88. package/dist/worker/console/chat/routes.js +27 -7
  89. package/dist/worker/console/chat/scheduled-goal-booking.js +59 -0
  90. package/dist/worker/console/chat/scheduled-goal-delivery.js +27 -0
  91. package/dist/worker/console/chat/scheduled-goal-request.js +190 -0
  92. package/dist/worker/console/chat/sdd-data-alignment.js +1 -1
  93. package/dist/worker/console/chat/session-mode-view.js +5 -4
  94. package/dist/worker/console/chat/session-mode.js +18 -12
  95. package/dist/worker/console/chat/session-store.js +42 -9
  96. package/dist/worker/console/chat/tool-preview.js +115 -0
  97. package/dist/worker/console/chat/tools.js +10 -0
  98. package/dist/worker/console/chat/turn-order.js +13 -0
  99. package/dist/worker/console/chat/turn-process.js +32 -30
  100. package/dist/worker/console/console-update-and-init.js +1 -19
  101. package/dist/worker/console/console-update-runtime.js +5 -20
  102. package/dist/worker/console/operator-actions.js +63 -1
  103. package/dist/worker/console/prd-intake-bridge.js +54 -1
  104. package/dist/worker/console/routes.js +8 -0
  105. package/dist/worker/console/scheduled-goal-host.js +98 -0
  106. package/dist/worker/console/scheduled-goal-operation-adapter.js +127 -0
  107. package/dist/worker/console/server.js +24 -1
  108. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-D_fNbWc_.js → abnfDiagram-N423BO3Z-8-j6y-sd.js} +1 -1
  109. package/dist/worker/console/static/assets/{arc-_HuqLW6m.js → arc-eoQiMvuk.js} +1 -1
  110. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-Djy2qY1m.js → architectureDiagram-T3A2C74G-C4A3uMcI.js} +1 -1
  111. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-bB-1TSyY.js → blockDiagram-VBNYF7ZC-D4zD2F-Q.js} +1 -1
  112. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-C5Hmghrz.js → c4Diagram-5PPSVZJV-j1RkJziL.js} +1 -1
  113. package/dist/worker/console/static/assets/channel-ChE7y-cx.js +1 -0
  114. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-Duyl39oy.js → chunk-2GRJ4B5K-YBHmhik1.js} +1 -1
  115. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-x6mdnSyf.js → chunk-2Q5K7J3B-COfWyo9P.js} +1 -1
  116. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-WlBuFj7W.js → chunk-5RXB4S5H-I99OUkHY.js} +1 -1
  117. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-CTF429HX.js → chunk-5VM5RSS4-XKxoJNJ4.js} +1 -1
  118. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-Dwd6r-SF.js → chunk-6Q2QTUOP-DLT_cYx1.js} +1 -1
  119. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-C-Br82D1.js → chunk-GF5L2VYU-CxcKZ9mV.js} +1 -1
  120. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-CuGp0DeE.js → chunk-JWPE2WC7-V1EqXdjY.js} +1 -1
  121. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-CJhFX6Lh.js → chunk-KBJHAD2P-DebTtdFp.js} +1 -1
  122. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DpGOa_jT.js → chunk-RYQCIY6F-B-ivNRDf.js} +1 -1
  123. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-DXJaTynd.js → chunk-XXDRQBXY-DC_Ds11b.js} +1 -1
  124. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C01TCf2X.js +1 -0
  125. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C01TCf2X.js +1 -0
  126. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CRBZWjE4.js → cose-bilkent-JH36ORCC-sWEqKwIb.js} +1 -1
  127. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BdXcxtlb.js → cynefin-VYW2F7L2-BXa_dcu4.js} +1 -1
  128. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-07UKsOts.js → cynefinDiagram-MW4NZA55-C-Mle84F.js} +1 -1
  129. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-D38p9__S.js → dagre-VZM6K2ZE-CXPDBITe.js} +1 -1
  130. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-nSiBNNjH.js → diagram-7IWD3JNH-CC-WJQfa.js} +1 -1
  131. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-BFOTot5D.js → diagram-B4RE2ZJO-CDAV5Vs4.js} +1 -1
  132. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-DypKaZ6k.js → diagram-LBJQPF4R-CmFiAcNz.js} +1 -1
  133. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-B6yoOQeW.js → diagram-Q27KOJAE-DPBZHuyn.js} +1 -1
  134. package/dist/worker/console/static/assets/{diagram-UB23O5K3-BHYS6viX.js → diagram-UB23O5K3-jUlm_Ds3.js} +1 -1
  135. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-D2VD5Snj.js → ebnfDiagram-BXEA7PRR-DWhQ3mfY.js} +1 -1
  136. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-E98mWxN1.js → erDiagram-JOGREHBK-Tr2gMqet.js} +1 -1
  137. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CT1zxhqP.js → flowDiagram-UKHOOZJN-DJjVQHPA.js} +1 -1
  138. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-6GcngNcy.js → ganttDiagram-PKOTCBZU-D74dQ4u0.js} +1 -1
  139. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-DCL6NvKe.js → gitGraphDiagram-DS77QQ5N-DwW0tZ0X.js} +1 -1
  140. package/dist/worker/console/static/assets/index-BWkIfcrK.css +1 -0
  141. package/dist/worker/console/static/assets/index-Cdkvw_H6.js +469 -0
  142. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-C0627e-9.js → infoDiagram-6WML65LV-ILCbxJyb.js} +1 -1
  143. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-C_u3P6Ik.js → ishikawaDiagram-WSZJBQD7-DeuWBQ89.js} +1 -1
  144. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DPDPv9HL.js → journeyDiagram-NVQOT4AX-CF5ih8Fk.js} +1 -1
  145. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-D3OHdWiO.js → kanban-definition-27J2QSJJ-C7yOSuRO.js} +1 -1
  146. package/dist/worker/console/static/assets/{linear-DI88zD7n.js → linear-BDZ9riWi.js} +1 -1
  147. package/dist/worker/console/static/assets/{mermaid.core-p2l8IrWY.js → mermaid.core-7pKqYtpZ.js} +5 -5
  148. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-B1bAX-oS.js → mindmap-definition-FAOFIHXS-LeJDybSU.js} +1 -1
  149. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-DwOnWxdD.js → pegDiagram-VL7TDLO6-BJvT3pMD.js} +1 -1
  150. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-xRkTXnJC.js → pieDiagram-7S7Q4E2Y-_rGqpMan.js} +1 -1
  151. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-_9UC5Zio.js → quadrantDiagram-CIZ2JOQS-DPcSv5aA.js} +1 -1
  152. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-CgEUirWJ.js → railroadDiagram-AXF67PYL-Drxx4hkJ.js} +1 -1
  153. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-Czbpwiyz.js → requirementDiagram-LRYGKXZP-BCTUdU4z.js} +1 -1
  154. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-_j7_KiqY.js → sankeyDiagram-W5VNT64P-B6wzbZmB.js} +1 -1
  155. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-BNJa6Hyi.js → sequenceDiagram-SI44F4Z6-BGt8d3QQ.js} +1 -1
  156. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-DedpKtOc.js → sizeCapture-X5ZJPWSS-7nlhJKo7.js} +1 -1
  157. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-BBvthr7c.js → stateDiagram-OKZ733FA-Cv2stqMA.js} +1 -1
  158. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DC7V5vcq.js +1 -0
  159. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-Ds7umgEM.js → swimlanes-SLNWSIFB-qDAo4Yc1.js} +2 -2
  160. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Bwy4QUTO.js +8 -0
  161. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CKa-p1nF.js → timeline-definition-Z64GVDOM-CKbDNKTr.js} +1 -1
  162. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-LoUNR56o.js → vennDiagram-T6HMQDX7-DI-9EHic.js} +1 -1
  163. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-Bqbl6ym7.js → wardleyDiagram-T6FBY63Y-BrzzRDpX.js} +1 -1
  164. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-B8dUg4lf.js → xychartDiagram-ELKLHX3M-BclH5hGh.js} +1 -1
  165. package/dist/worker/console/static/index.html +2 -2
  166. package/dist/worker/console/static-src/operator-chat/chat-scroll-position.js +24 -0
  167. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +41 -11
  168. package/dist/worker/console/static-src/operator-chat/compaction-message.js +3 -17
  169. package/dist/worker/console/static-src/operator-chat/composer-session-ledger.js +192 -0
  170. package/dist/worker/console/static-src/operator-chat/pending-user-message.js +9 -1
  171. package/dist/worker/console/static-src/operator-chat/slash-palette-nav.js +15 -5
  172. package/dist/worker/console/static-src/operator-chat/timeline-merge.js +29 -0
  173. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +92 -38
  174. package/dist/worker/console/static-src/operator-chat/useChatStream.js +145 -70
  175. package/dist/worker/console/static-src/operator-chat/useChatThread.js +38 -55
  176. package/dist/worker/console/static-src/operator-chat/useComposer.js +182 -69
  177. package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +2 -0
  178. package/dist/worker/console/static-src/prd-file-import.js +3 -1
  179. package/dist/worker/console/workspace-context.js +22 -0
  180. package/dist/worker/console/workspace-initialization.js +209 -0
  181. package/dist/worker/delivery/git-transaction.js +2 -0
  182. package/dist/worker/feature/fullstack-validate.js +2 -0
  183. package/dist/worker/loop-agent/loop-agent-client.js +8 -2
  184. package/dist/worker/materialize/harness-task-materializer.js +4 -1
  185. package/dist/worker/metrics/projector.js +1 -1
  186. package/dist/worker/observability/event-store.js +4 -1
  187. package/dist/worker/observability/read-model.js +4 -1
  188. package/dist/worker/observe/node-transparency.js +23 -1
  189. package/dist/worker/observe/routes.js +4 -0
  190. package/dist/worker/observe/static/operator-chrome.js +3 -1
  191. package/dist/worker/observe/static/styles.css +7 -4
  192. package/dist/worker/observe/static/views/dag-inspector.js +5 -19
  193. package/dist/worker/outcomes/declared-artifacts.js +2 -0
  194. package/dist/worker/preflight.js +3 -0
  195. package/dist/worker/scheduler/scheduled-goal-dispatch.js +117 -0
  196. package/dist/worker/scheduler/scheduled-goal-evidence.js +167 -0
  197. package/dist/worker/scheduler/scheduled-goal-recovery.js +62 -0
  198. package/dist/worker/scheduler/scheduled-goal-store.js +699 -0
  199. package/dist/worker/scheduler/scheduled-goal-supervisor.js +132 -0
  200. package/dist/worker/scheduler/scheduled-goal-time.js +102 -0
  201. package/dist/worker/scheduler/scheduled-goal-types.js +95 -0
  202. package/dist/worker/task-spec/validate.js +4 -1
  203. package/dist/workflows/dag/backend-test-markdown-workflow.js +6 -24
  204. package/dist/workflows/dag/backend-test-plan-protocol.js +82 -5
  205. package/dist/workflows/dag/dag-retry-schema.js +11 -0
  206. package/dist/workflows/dag/decision-envelope.js +2 -0
  207. package/dist/workflows/dag/dynamic-runtime/shared.js +2 -2
  208. package/dist/workflows/dag/frontend-closeout.js +3 -1
  209. package/dist/workflows/dag/frontend-committed-facts.js +461 -0
  210. package/dist/workflows/dag/frontend-durable-tools.js +15 -3
  211. package/dist/workflows/dag/frontend-implementation-contract.js +369 -12
  212. package/dist/workflows/dag/frontend-plan-canary.js +53 -0
  213. package/dist/workflows/dag/frontend-plan-decision-contract.js +803 -0
  214. package/dist/workflows/dag/frontend-plan-render.js +0 -2
  215. package/dist/workflows/dag/frontend-provider-capability-matrix.js +8 -61
  216. package/dist/workflows/dag/frontend-recovery-run.js +57 -0
  217. package/dist/workflows/dag/frontend-repair.js +55 -76
  218. package/dist/workflows/dag/frontend-review-context.js +42 -68
  219. package/dist/workflows/dag/frontend-review-scopes.js +2 -2
  220. package/dist/workflows/dag/frontend-risk.js +92 -10
  221. package/dist/workflows/dag/frontend-session-budget.js +117 -3
  222. package/dist/workflows/dag/frontend-shape.js +11 -55
  223. package/dist/workflows/dag/frontend-test-execution-evidence.js +35 -10
  224. package/dist/workflows/dag/frontend-typed-event-store.js +32 -25
  225. package/dist/workflows/dag/frontend-verification-trace.js +33 -54
  226. package/dist/workflows/dag/frontend-writer-admission.js +3 -47
  227. package/dist/workflows/dag/frontend-writer-status.js +0 -23
  228. package/dist/workflows/dag/init-hybrid.js +47 -19
  229. package/dist/workflows/dag/interrupt-request.js +2 -0
  230. package/dist/workflows/dag/lifecycle.js +11 -2
  231. package/dist/workflows/dag/node-execution.js +50 -13
  232. package/dist/workflows/dag/reconcile-run.js +2 -0
  233. package/dist/workflows/dag/repair-artifact.js +3 -1
  234. package/dist/workflows/dag/report.js +2 -0
  235. package/dist/workflows/dag/rerun-plan.js +10 -0
  236. package/dist/workflows/dag/rerun-task.js +79 -1
  237. package/dist/workflows/dag/retry-policy.js +18 -0
  238. package/dist/workflows/dag/scheduler.js +2 -4
  239. package/dist/workflows/dag/types.js +44 -6
  240. package/dist/workflows/dag/validate.js +4 -0
  241. package/docs/README.md +1 -0
  242. package/docs/architecture/runtime-boundaries.md +3 -3
  243. package/docs/governance/README.md +1 -0
  244. package/docs/init-surface.manifest.json +1 -0
  245. package/docs/operations/README.md +2 -0
  246. package/docs/templates/README.md +1 -1
  247. package/docs/templates/agent-dag.schema.json +2 -2
  248. package/docs/templates/backend-test-dag.json +14 -10
  249. package/docs/templates/frontend-implementation-contract.schema.json +0 -7
  250. package/package.json +9 -3
  251. package/skills/frontend-bounded-implement/references/code-standards.md +3 -3
  252. package/skills/frontend-contract/references/contract-protocol.md +3 -1
  253. package/skills/frontend-plan/SKILL.md +8 -6
  254. package/skills/frontend-plan/references/decision-contract.md +3 -3
  255. package/skills/frontend-review/SKILL.md +18 -28
  256. package/skills/frontend-review/references/review-findings.md +8 -3
  257. package/dist/commands/new-task.js +0 -5
  258. package/dist/commands/status.js +0 -57
  259. package/dist/commands/task-contract.js +0 -269
  260. package/dist/shared/prompts.js +0 -26
  261. package/dist/task/config.js +0 -2
  262. package/dist/task/contract/validate-draft.js +0 -106
  263. package/dist/task/goal.js +0 -3
  264. package/dist/task/index.js +0 -12
  265. package/dist/task/lifecycle.js +0 -1
  266. package/dist/task/operator/capabilities.js +0 -6
  267. package/dist/task/operator/envelope.js +0 -2
  268. package/dist/task/operator/index.js +0 -5
  269. package/dist/task/operator/registry.js +0 -2
  270. package/dist/task/operator/types.js +0 -1
  271. package/dist/task/paths.js +0 -1
  272. package/dist/task/source-state.js +0 -1
  273. package/dist/task/subagent-guidance.js +0 -1
  274. package/dist/worker/console/chat/sift-bridge.js +0 -1
  275. package/dist/worker/console/index.js +0 -20
  276. package/dist/worker/console/static/assets/channel-C0A6UEIa.js +0 -1
  277. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DzguNppy.js +0 -1
  278. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DzguNppy.js +0 -1
  279. package/dist/worker/console/static/assets/index-24jp3aBh.js +0 -468
  280. package/dist/worker/console/static/assets/index-CY6y6I8M.css +0 -1
  281. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BABVQnfM.js +0 -1
  282. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-D0qsLaxR.js +0 -8
  283. package/dist/worker/scheduler/index.js +0 -25
  284. package/dist/workflows/dag/facts.js +0 -4
  285. package/dist/workflows/dag/frontend-shadow-dual-write.js +0 -975
  286. package/dist/workflows/dag/index.js +0 -6
  287. package/dist/workflows/dynamic/index.js +0 -7
@@ -0,0 +1,439 @@
1
+ /**
2
+ * Runtime inspection: browser-safe snapshot projection, slash-command
3
+ * inventory, and ResourceLoader/package/MCP collection. Does not own
4
+ * session lifecycle, preference-file cache, or prompt/reload locks.
5
+ */
6
+ import { RUNTIME_CONTEXT_TEXT_MAX, redactRuntimeText, } from "../runtime-context.js";
7
+ import { isAutoInvocationEnabled, skillResourceId, } from "../resource-preferences-store.js";
8
+ /**
9
+ * Browser-safe projection of a live runtime snapshot (design §2.2 / RF-03).
10
+ *
11
+ * Every browser-visible string runs the shared secret-scrub chain
12
+ * (scrubSecrets + ghp_/Bearer redaction via redactRuntimeText) and a fixed
13
+ * per-field length limit: 200 (names/spec/source/origin), 400 (paths/errors/
14
+ * diagnostic messages), 600 (skill descriptions), 80 (package versions);
15
+ * truncation uses the fixed `…[truncated N chars …]` marker. The server-only
16
+ * `raw` prompt and the RAW-based `sha256`/`characters` pass through untouched,
17
+ * and real empty lists stay empty.
18
+ *
19
+ * Pure + deterministic and exported so the route harness reuses the exact
20
+ * production implementation (same code path as getRuntimeSnapshot).
21
+ */
22
+ export function projectRuntimeSnapshot(input) {
23
+ const field = (value, max) => value === undefined ? undefined : redactRuntimeText(value, max);
24
+ const projectSkill = (skill) => ({
25
+ name: field(skill.name, 200) ?? "",
26
+ description: field(skill.description, 600) ?? "",
27
+ path: field(skill.path, 400) ?? "",
28
+ ...(skill.baseDir ? { baseDir: field(skill.baseDir, 400) } : {}),
29
+ scope: skill.scope,
30
+ source: field(skill.source, 200) ?? "",
31
+ resourceId: field(skill.resourceId, 200) ?? "",
32
+ autoInvocationEnabled: skill.autoInvocationEnabled,
33
+ diagnostics: skill.diagnostics.map((diag) => field(diag, 400) ?? ""),
34
+ });
35
+ const projectExtension = (ext) => ({
36
+ name: field(ext.name, 200) ?? "",
37
+ path: field(ext.path, 400) ?? "",
38
+ ...(ext.resolvedPath
39
+ ? { resolvedPath: field(ext.resolvedPath, 400) }
40
+ : {}),
41
+ source: field(ext.source, 200) ?? "",
42
+ scope: ext.scope,
43
+ ...(ext.origin ? { origin: field(ext.origin, 200) } : {}),
44
+ enabled: ext.enabled,
45
+ ...(ext.error ? { error: field(ext.error, 400) } : {}),
46
+ });
47
+ const projectPackage = (pkg) => ({
48
+ spec: field(pkg.spec, 200) ?? "",
49
+ scope: pkg.scope,
50
+ enabled: pkg.enabled,
51
+ ...(pkg.version ? { version: field(pkg.version, 80) } : {}),
52
+ ...(pkg.configuredVersion
53
+ ? { configuredVersion: field(pkg.configuredVersion, 80) }
54
+ : {}),
55
+ ...(pkg.packageName ? { packageName: field(pkg.packageName, 200) } : {}),
56
+ ...(pkg.path ? { path: field(pkg.path, 400) } : {}),
57
+ ...(pkg.installedPath ? { installedPath: field(pkg.installedPath, 400) } : {}),
58
+ ...(pkg.cwd ? { cwd: field(pkg.cwd, 400) } : {}),
59
+ resolved: pkg.resolved.map((resource) => ({
60
+ type: resource.type,
61
+ name: field(resource.name, 200) ?? "",
62
+ path: field(resource.path, 400) ?? "",
63
+ source: field(resource.source, 200) ?? "",
64
+ scope: resource.scope,
65
+ })),
66
+ diagnostics: pkg.diagnostics.map((diag) => field(diag, 400) ?? ""),
67
+ });
68
+ const projectMcpTool = (tool) => ({
69
+ name: field(tool.name, 200) ?? "",
70
+ description: field(tool.description, 600) ?? "",
71
+ ...(tool.server ? { server: field(tool.server, 200) } : {}),
72
+ source: field(tool.source, 200) ?? "",
73
+ scope: tool.scope,
74
+ ...(tool.path ? { path: field(tool.path, 400) } : {}),
75
+ active: tool.active,
76
+ });
77
+ const projectMcp = (mcp) => ({
78
+ servers: mcp.servers.map((server) => ({
79
+ name: field(server.name, 200) ?? "",
80
+ scope: server.scope,
81
+ status: server.status,
82
+ enabled: server.enabled,
83
+ ...(server.transport ? { transport: field(server.transport, 80) } : {}),
84
+ ...(server.command ? { command: field(server.command, 400) } : {}),
85
+ ...(server.url ? { url: field(server.url, 400) } : {}),
86
+ ...(server.configPath ? { configPath: field(server.configPath, 400) } : {}),
87
+ tools: server.tools.map(projectMcpTool),
88
+ })),
89
+ unassignedTools: mcp.unassignedTools.map(projectMcpTool),
90
+ });
91
+ const projectDiagnostic = (diag) => ({
92
+ type: diag.type,
93
+ ...(diag.code ? { code: diag.code } : {}),
94
+ message: field(diag.message, 400) ?? "",
95
+ ...(diag.path ? { path: field(diag.path, 400) } : {}),
96
+ ...(diag.retryable !== undefined
97
+ ? { retryable: diag.retryable }
98
+ : {}),
99
+ });
100
+ return {
101
+ sessionId: input.sessionId,
102
+ revision: input.revision,
103
+ loadedAt: input.loadedAt,
104
+ selection: {
105
+ ...(input.selection.model
106
+ ? {
107
+ model: {
108
+ provider: input.selection.model.provider,
109
+ id: input.selection.model.id,
110
+ ...(input.selection.model.name
111
+ ? { name: field(input.selection.model.name, 200) }
112
+ : {}),
113
+ },
114
+ }
115
+ : {}),
116
+ thinkingSelection: input.selection.thinkingSelection,
117
+ ...(input.selection.effectiveThinkingLevel
118
+ ? { effectiveThinkingLevel: input.selection.effectiveThinkingLevel }
119
+ : {}),
120
+ },
121
+ models: input.models.map((model) => ({
122
+ provider: model.provider,
123
+ id: model.id,
124
+ ...(model.name ? { name: field(model.name, 200) } : {}),
125
+ ...(model.hasCredentials !== undefined
126
+ ? { hasCredentials: model.hasCredentials }
127
+ : {}),
128
+ })),
129
+ thinkingLevels: input.thinkingLevels.map((option) => ({ ...option })),
130
+ systemPrompt: {
131
+ ...(input.systemPrompt.raw !== undefined
132
+ ? { raw: input.systemPrompt.raw }
133
+ : {}),
134
+ text: redactRuntimeText(input.systemPrompt.text, RUNTIME_CONTEXT_TEXT_MAX),
135
+ sha256: input.systemPrompt.sha256,
136
+ characters: input.systemPrompt.characters,
137
+ },
138
+ activeTools: [...input.activeTools],
139
+ contextFiles: input.contextFiles.map((file) => ({
140
+ path: field(file.path, 400) ?? "",
141
+ characters: file.characters,
142
+ })),
143
+ skills: input.skills.map(projectSkill),
144
+ extensions: input.extensions.map(projectExtension),
145
+ packages: input.packages.map(projectPackage),
146
+ mcp: projectMcp(input.mcp ?? { servers: [], unassignedTools: [] }),
147
+ diagnostics: input.diagnostics.map(projectDiagnostic),
148
+ hasBash: input.hasBash,
149
+ };
150
+ }
151
+ /**
152
+ * Browser-safe slash command projection for UI-11.
153
+ * Sources: current Session extension commands, prompt templates, skills.
154
+ * Never returns prompt/skill file bodies. Same-name conflict priority:
155
+ * extension > skill > prompt.
156
+ */
157
+ export function collectSlashCommands(input) {
158
+ const scrub = (value) => {
159
+ const raw = String(value ?? "");
160
+ return raw
161
+ .replace(/\/Users\/[^\s]+/gi, "~")
162
+ .replace(/[A-Za-z]:\\Users\\[^\s]+/gi, "~")
163
+ .slice(0, 240);
164
+ };
165
+ const session = input.session;
166
+ if (!session)
167
+ return { commands: [] };
168
+ const SOURCE_RANK = {
169
+ extension: 0,
170
+ skill: 1,
171
+ prompt: 2,
172
+ };
173
+ const byKey = new Map();
174
+ const sourceWarnings = [];
175
+ const push = (command, label, description, source) => {
176
+ const name = command.startsWith("/") ? command : `/${command}`;
177
+ const key = name.toLowerCase();
178
+ if (!key || key === "/")
179
+ return;
180
+ const next = {
181
+ command: name,
182
+ label: (label || name).slice(0, 80),
183
+ description: scrub(description),
184
+ source,
185
+ };
186
+ const existing = byKey.get(key);
187
+ if (!existing || SOURCE_RANK[source] < SOURCE_RANK[existing.source]) {
188
+ byKey.set(key, next);
189
+ }
190
+ };
191
+ try {
192
+ const cmds = session.extensionRunner?.getRegisteredCommands?.() ?? [];
193
+ for (const cmd of cmds) {
194
+ const name = cmd.invocationName || cmd.name;
195
+ if (!name)
196
+ continue;
197
+ push(String(name), String(cmd.name || name), String(cmd.description || ""), "extension");
198
+ }
199
+ }
200
+ catch (error) {
201
+ sourceWarnings.push(`extension: ${scrub(error instanceof Error ? error.message : String(error))}`);
202
+ }
203
+ try {
204
+ for (const tpl of session.promptTemplates ?? []) {
205
+ if (!tpl?.name)
206
+ continue;
207
+ push(String(tpl.name), String(tpl.name), String(tpl.description || ""), "prompt");
208
+ }
209
+ }
210
+ catch (error) {
211
+ sourceWarnings.push(`prompt: ${scrub(error instanceof Error ? error.message : String(error))}`);
212
+ }
213
+ try {
214
+ const skills = input.resourceLoader?.getSkills?.()?.skills ?? [];
215
+ for (const skill of skills) {
216
+ if (!skill?.name)
217
+ continue;
218
+ const command = skill.name.startsWith("skill:")
219
+ ? `/${skill.name}`
220
+ : `/skill:${skill.name}`;
221
+ push(command, skill.name, String(skill.description || ""), "skill");
222
+ }
223
+ }
224
+ catch (error) {
225
+ sourceWarnings.push(`skill: ${scrub(error instanceof Error ? error.message : String(error))}`);
226
+ }
227
+ const warning = sourceWarnings.length > 0
228
+ ? sourceWarnings.join("; ").slice(0, 160)
229
+ : undefined;
230
+ return {
231
+ commands: [...byKey.values()],
232
+ ...(warning ? { warning } : {}),
233
+ };
234
+ }
235
+ /**
236
+ * Collect ResourceLoader / package / MCP inventories for a live session.
237
+ * Preference-file loading stays with ConsolePiRuntime; this function only
238
+ * consumes already-loaded prefs (or a captured load error).
239
+ */
240
+ export async function collectRuntimeInventories(input) {
241
+ const contextFiles = [];
242
+ const skills = [];
243
+ const extensions = [];
244
+ const diagnostics = [];
245
+ const resolvedResources = [];
246
+ const resourceFailure = (subface, error) => {
247
+ diagnostics.push({
248
+ type: "error",
249
+ code: "RESOURCE_LOAD_FAILED",
250
+ message: `${subface} inventory failed: ${error instanceof Error ? error.message : String(error)}`,
251
+ retryable: true,
252
+ });
253
+ };
254
+ if (input.skillPrefsError !== undefined) {
255
+ diagnostics.push({
256
+ type: "error",
257
+ code: "PI_RESOURCE_PREFERENCES_MALFORMED",
258
+ message: input.skillPrefsError instanceof Error
259
+ ? input.skillPrefsError.message
260
+ : String(input.skillPrefsError),
261
+ retryable: true,
262
+ });
263
+ }
264
+ const resourceLoader = input.resourceLoader;
265
+ if (resourceLoader) {
266
+ try {
267
+ const agentsFiles = resourceLoader.getAgentsFiles?.();
268
+ for (const file of agentsFiles?.agentsFiles ?? []) {
269
+ if (!file.path)
270
+ continue;
271
+ contextFiles.push({
272
+ path: file.path,
273
+ characters: file.content?.length ?? 0,
274
+ });
275
+ }
276
+ }
277
+ catch (error) {
278
+ resourceFailure("context files", error);
279
+ }
280
+ try {
281
+ const skillsResult = resourceLoader.getSkills?.();
282
+ for (const skill of skillsResult?.skills ?? []) {
283
+ const resourceId = skillResourceId({
284
+ name: skill.name,
285
+ filePath: skill.filePath,
286
+ });
287
+ const prefEnabled = isAutoInvocationEnabled(input.skillPrefs, resourceId);
288
+ const autoInvocationEnabled = prefEnabled && skill.disableModelInvocation !== true;
289
+ skills.push({
290
+ name: skill.name,
291
+ description: skill.description ?? "",
292
+ path: skill.filePath,
293
+ ...(skill.baseDir ? { baseDir: skill.baseDir } : {}),
294
+ scope: skill.sourceInfo?.scope ?? "unknown",
295
+ source: skill.sourceInfo?.source ?? "",
296
+ resourceId,
297
+ autoInvocationEnabled,
298
+ diagnostics: [],
299
+ });
300
+ resolvedResources.push({
301
+ type: "skill",
302
+ name: skill.name,
303
+ path: skill.filePath,
304
+ source: skill.sourceInfo?.source ?? "",
305
+ scope: skill.sourceInfo?.scope ?? "unknown",
306
+ });
307
+ }
308
+ for (const diag of skillsResult?.diagnostics ?? []) {
309
+ if (!diag?.message)
310
+ continue;
311
+ diagnostics.push({
312
+ type: diag.type ?? "warning",
313
+ message: diag.message,
314
+ ...(diag.path ? { path: diag.path } : {}),
315
+ });
316
+ }
317
+ }
318
+ catch (error) {
319
+ resourceFailure("skills", error);
320
+ }
321
+ try {
322
+ const extResult = resourceLoader.getExtensions?.();
323
+ for (const ext of extResult?.extensions ?? []) {
324
+ const path = ext.resolvedPath ?? ext.path ?? "";
325
+ extensions.push({
326
+ name: ext.sourceInfo?.source ?? ext.path ?? "extension",
327
+ path,
328
+ ...(ext.resolvedPath ? { resolvedPath: ext.resolvedPath } : {}),
329
+ source: ext.sourceInfo?.source ?? "",
330
+ scope: ext.sourceInfo?.scope ?? "unknown",
331
+ ...(ext.sourceInfo?.origin ? { origin: ext.sourceInfo.origin } : {}),
332
+ enabled: true,
333
+ });
334
+ resolvedResources.push({
335
+ type: "extension",
336
+ name: ext.sourceInfo?.source ?? ext.path ?? "extension",
337
+ path,
338
+ source: ext.sourceInfo?.source ?? "",
339
+ scope: ext.sourceInfo?.scope ?? "unknown",
340
+ });
341
+ }
342
+ for (const err of extResult?.errors ?? []) {
343
+ if (!err?.error)
344
+ continue;
345
+ diagnostics.push({
346
+ type: "error",
347
+ message: err.error,
348
+ ...(err.path ? { path: err.path } : {}),
349
+ });
350
+ }
351
+ }
352
+ catch (error) {
353
+ resourceFailure("extensions", error);
354
+ }
355
+ try {
356
+ const promptsResult = resourceLoader.getPrompts?.();
357
+ for (const prompt of promptsResult?.prompts ?? []) {
358
+ resolvedResources.push({
359
+ type: "prompt",
360
+ name: prompt.name,
361
+ path: prompt.filePath,
362
+ source: prompt.sourceInfo?.source ?? "",
363
+ scope: prompt.sourceInfo?.scope ?? "unknown",
364
+ });
365
+ }
366
+ for (const diag of promptsResult?.diagnostics ?? []) {
367
+ if (!diag?.message)
368
+ continue;
369
+ diagnostics.push({
370
+ type: diag.type ?? "warning",
371
+ message: diag.message,
372
+ ...(diag.path ? { path: diag.path } : {}),
373
+ });
374
+ }
375
+ }
376
+ catch (error) {
377
+ resourceFailure("prompts", error);
378
+ }
379
+ try {
380
+ const themesResult = resourceLoader.getThemes?.();
381
+ for (const theme of themesResult?.themes ?? []) {
382
+ if (!theme.path)
383
+ continue;
384
+ resolvedResources.push({
385
+ type: "theme",
386
+ name: theme.name ?? theme.path,
387
+ path: theme.path,
388
+ source: "",
389
+ scope: "unknown",
390
+ });
391
+ }
392
+ for (const diag of themesResult?.diagnostics ?? []) {
393
+ if (!diag?.message)
394
+ continue;
395
+ diagnostics.push({
396
+ type: diag.type ?? "warning",
397
+ message: diag.message,
398
+ ...(diag.path ? { path: diag.path } : {}),
399
+ });
400
+ }
401
+ }
402
+ catch (error) {
403
+ resourceFailure("themes", error);
404
+ }
405
+ }
406
+ const { readPackageInventory } = await import("../pi-console-config.js");
407
+ let packages = [];
408
+ try {
409
+ packages = (await readPackageInventory(input.agentDir, input.cwd, resolvedResources));
410
+ }
411
+ catch (error) {
412
+ packages = [];
413
+ diagnostics.push({
414
+ type: "error",
415
+ code: "PACKAGE_INVENTORY_FAILED",
416
+ message: error instanceof Error ? error.message : String(error),
417
+ retryable: true,
418
+ });
419
+ }
420
+ const { readMcpInventory } = await import("../mcp-inventory.js");
421
+ let mcp = { servers: [], unassignedTools: [] };
422
+ try {
423
+ mcp = await readMcpInventory({
424
+ agentDir: input.agentDir,
425
+ cwd: input.cwd,
426
+ tools: (Array.isArray(input.tools) ? input.tools : []),
427
+ activeToolNames: input.activeToolNames,
428
+ });
429
+ }
430
+ catch (error) {
431
+ diagnostics.push({
432
+ type: "error",
433
+ code: "MCP_INVENTORY_FAILED",
434
+ message: error instanceof Error ? error.message : String(error),
435
+ retryable: true,
436
+ });
437
+ }
438
+ return { contextFiles, skills, extensions, packages, mcp, diagnostics };
439
+ }
@@ -0,0 +1,195 @@
1
+ /** Model exposure only. Capability registry and dispatch remain the authority. */
2
+ import { Type } from "typebox";
3
+ import { buildModelCallableToolSchemas } from "../tool-adapter.js";
4
+ import { computeChatActiveToolNames } from "../session-mode.js";
5
+ import { filterActiveInterviewTools } from "../../interview/tools.js";
6
+ export const TOOL_EXPOSURE_ENTRY = "console-tool-exposure";
7
+ export const TOOL_CATALOG_VERSION = 1;
8
+ export const CORE_WORKFLOW_TOOLS = Object.freeze(`prepareScheduledTask scheduledGoalGet scheduledGoalList newTask importPrd sourceInstructions contractDraftSave contractShow contractValidate contractDiff taskAdvance prepareDagConfirmation prepareDagExecution runDag operationGet operationList operationEventSummary operationWait observeLink dagReport dagDoctor dagRerunPlan dagRerun prepareMutationGate standaloneTaskRerun workerTaskRetry status planList operatorCapabilities`.split(" "));
9
+ const SCHEDULED_BOOKING_READ_TOOLS = new Set(["read", "find", "ls", "grep"]);
10
+ export function isScheduledBookingTurn(text) {
11
+ return /(?:预约|定时|稍后|分钟后|小时后|schedule(?:d)?|\blater\b)/i.test(text);
12
+ }
13
+ /** Keep booking turns on typed workflow actions and local read-only inspection. */
14
+ export function pinScheduledBookingTurnTools(session) {
15
+ const allowed = session.getActiveToolNames().filter(name => CORE_WORKFLOW_TOOLS.includes(name) || SCHEDULED_BOOKING_READ_TOOLS.has(name));
16
+ session.setActiveToolsByName(allowed);
17
+ return allowed;
18
+ }
19
+ export const WORKFLOW_TOOL_GROUPS = [
20
+ { id: "scheduling", examples: ["prepareScheduledGoal"], description: "高级预约:已有 DAG/Task 的冻结预约", tools: ["prepareScheduledGoal"] },
21
+ { id: "diagnostics", examples: ["inspect", "doctor", "dagValidate"], description: "DAG 深度诊断、校验、决策、上下文与初始化检查", tools: ["inspect", "doctor", "statsContext", "spineCheck", "dagRunTask", "dagValidate", "dagPromptOverrideConfig", "dagInterruptEligibility", "dagStatus", "dagDecisionInspect", "dagDecisionValidate"] },
22
+ { id: "governance", examples: ["planCreate", "docsAudit", "closeoutTask"], description: "计划管理、文档审计、交接覆盖与任务收口", tools: ["planCreate", "planComplete", "planCheck", "docsAudit", "handoffCheck", "handoffCoverage", "coverageReport", "stats", "promoteRun", "closeoutTask", "dagCloseoutDraft"] },
23
+ { id: "knowledge", examples: ["knowledgeQuery"], description: "查询项目知识", tools: ["knowledgeQuery"] },
24
+ { id: "worker", examples: ["workerSchedulerStatus", "workerPoolDoctor", "workerReportMorning"], description: "Worker 任务池、功能审查、调度诊断与报表", tools: ["workerPoolDoctor", "workerFeatureReview", "workerFeatureDoctor", "workerTaskValidate", "workerBatchPlanReady", "workerReportMorning", "workerReportMetrics", "workerAdmissionShow", "workerSchedulerList", "workerSchedulerStatus", "workerSchedulerLedger", "workerSchedulerDoctor"] },
25
+ ];
26
+ export function configuredToolExposure(value) {
27
+ if (value === undefined || value === "")
28
+ return undefined;
29
+ if (value === "full" || value === "progressive")
30
+ return value;
31
+ throw new Error("CONSOLE_CHAT_TOOL_EXPOSURE must be full or progressive");
32
+ }
33
+ /** Fail closed on catalog drift, including duplicate or human-only entries. */
34
+ export function validateWorkflowToolCatalog() {
35
+ const expected = new Set(buildModelCallableToolSchemas().map(t => t.toolId));
36
+ const names = [...CORE_WORKFLOW_TOOLS, ...WORKFLOW_TOOL_GROUPS.flatMap(g => [...g.tools])];
37
+ if (names.length !== new Set(names).size || names.length !== expected.size || names.some(n => !expected.has(n)))
38
+ throw new Error("WORKFLOW_TOOL_CATALOG_DRIFT");
39
+ }
40
+ export const TOOL_DISCOVERY_DESCRIPTION = "Load a workflow capability missing from the visible tools. Choose target by the user's intent from the capability directory, even when no tool name was mentioned. Pass a group ID or exact tool name; omit target if unsure. After loading, call the matching typed tool in the NEXT model response. Discovery alone does not fulfill the request, execute work or grant approval. Prefer discovery over recreating a workflow with shell or file edits.";
41
+ export class WorkflowToolExposure {
42
+ override;
43
+ state;
44
+ session;
45
+ interview = false;
46
+ manager;
47
+ // Failed persistence must not let the next turn silently undo full fallback.
48
+ // The active branch must still contain this ancestor; sibling branches do not inherit it.
49
+ volatileFallback;
50
+ constructor(manager, override) {
51
+ this.override = override;
52
+ this.manager = (manager ?? {});
53
+ this.state = { version: TOOL_CATALOG_VERSION, mode: override ?? "full", groups: [] };
54
+ try {
55
+ this.restore();
56
+ }
57
+ catch {
58
+ this.state = { version: TOOL_CATALOG_VERSION, mode: "full", groups: [], fallbackReason: "TOOL_EXPOSURE_STATE_READ_FAILED" };
59
+ }
60
+ }
61
+ get mode() { return this.state.mode; }
62
+ get snapshot() { return { ...this.state, groups: [...this.state.groups] }; }
63
+ restore() {
64
+ const entries = this.manager.getBranch?.() ?? [];
65
+ const latest = entries.filter(e => e.type === "custom" && e.customType === TOOL_EXPOSURE_ENTRY).at(-1);
66
+ if (!latest) {
67
+ this.state = { version: TOOL_CATALOG_VERSION, mode: this.override ?? "full", groups: [] };
68
+ return;
69
+ }
70
+ const raw = latest.data;
71
+ if (raw?.version !== TOOL_CATALOG_VERSION || !["full", "progressive"].includes(raw.mode ?? "") || !Array.isArray(raw.groups) || raw.groups.some(id => !WORKFLOW_TOOL_GROUPS.some(g => g.id === id))) {
72
+ this.state = { version: TOOL_CATALOG_VERSION, mode: "full", groups: [], fallbackReason: "INVALID_SAVED_TOOL_EXPOSURE" };
73
+ return;
74
+ }
75
+ const mode = raw.mode === "full" && raw.fallbackReason ? "full" : (this.override ?? raw.mode);
76
+ this.state = { version: TOOL_CATALOG_VERSION, mode, groups: [...new Set(raw.groups)], ...(mode === "full" && raw.fallbackReason ? { fallbackReason: raw.fallbackReason } : {}) };
77
+ }
78
+ persist() {
79
+ if (!this.manager.appendCustomEntry || !this.manager.getBranch)
80
+ throw new Error("TOOL_EXPOSURE_PERSISTENCE_UNAVAILABLE");
81
+ const previous = this.manager.getBranch().filter(e => e.type === "custom" && e.customType === TOOL_EXPOSURE_ENTRY).at(-1)?.data;
82
+ if (JSON.stringify(previous) !== JSON.stringify(this.state))
83
+ this.manager.appendCustomEntry(TOOL_EXPOSURE_ENTRY, this.snapshot);
84
+ }
85
+ exposed() {
86
+ if (this.state.mode === "full")
87
+ return undefined;
88
+ return [...CORE_WORKFLOW_TOOLS, ...WORKFLOW_TOOL_GROUPS.filter(g => this.state.groups.includes(g.id)).flatMap(g => [...g.tools])];
89
+ }
90
+ apply() {
91
+ if (!this.session)
92
+ throw new Error("TOOL_EXPOSURE_SESSION_UNAVAILABLE");
93
+ const names = computeChatActiveToolNames(this.session, "workflow", this.exposed());
94
+ const allowed = this.interview ? filterActiveInterviewTools(names).allowed : names;
95
+ this.session.setActiveToolsByName(allowed);
96
+ // SDK silently ignores unknown names: verify actual registration, not intent.
97
+ if (this.session.getAllTools) {
98
+ const registered = new Set(this.session.getAllTools().map(t => t.name));
99
+ const actual = new Set(this.session.getActiveToolNames());
100
+ const required = this.interview ? [] : (this.exposed() ?? CORE_WORKFLOW_TOOLS);
101
+ if (required.some(name => !registered.has(name) || !actual.has(name)))
102
+ throw new Error("TOOL_EXPOSURE_REQUIRED_TOOL_MISSING");
103
+ if (allowed.some(n => registered.has(n) && !actual.has(n)) || [...actual].some(n => !allowed.includes(n)))
104
+ throw new Error("TOOL_EXPOSURE_ACTIVATION_MISMATCH");
105
+ }
106
+ }
107
+ fallback(reason) {
108
+ this.state = { version: TOOL_CATALOG_VERSION, mode: "full", groups: [], fallbackReason: reason };
109
+ this.apply(); // A failure here is fatal; never pretend full mode is active.
110
+ try {
111
+ this.persist();
112
+ this.volatileFallback = undefined;
113
+ }
114
+ catch {
115
+ let anchor;
116
+ try {
117
+ anchor = this.manager.getBranch?.().at(-1);
118
+ }
119
+ catch { /* Conservatively keep full when branch cannot be read. */ }
120
+ this.volatileFallback = { anchor, state: this.snapshot };
121
+ }
122
+ }
123
+ pin(session, interview = false) {
124
+ this.session = session;
125
+ this.interview = interview;
126
+ // Reconstruct from the active branch, including after compaction/reopen.
127
+ try {
128
+ const pending = this.volatileFallback;
129
+ const branch = this.manager.getBranch?.() ?? [];
130
+ if (pending && (!pending.anchor || branch.some(entry => entry === pending.anchor ||
131
+ (pending.anchor?.id !== undefined && entry.id === pending.anchor.id)))) {
132
+ this.state = { ...pending.state, groups: [...pending.state.groups] };
133
+ }
134
+ else {
135
+ this.volatileFallback = undefined;
136
+ this.restore();
137
+ }
138
+ validateWorkflowToolCatalog();
139
+ this.apply();
140
+ // Full mode also records the session policy when supported.
141
+ if (this.mode === "progressive" || this.manager.appendCustomEntry) {
142
+ this.persist();
143
+ this.volatileFallback = undefined;
144
+ }
145
+ }
146
+ catch {
147
+ this.fallback(this.state.fallbackReason ?? "TOOL_EXPOSURE_RESTORE_OR_ACTIVATION_FAILED");
148
+ }
149
+ }
150
+ discover(target) {
151
+ if (this.interview)
152
+ return { ok: false, code: "TOOL_DISCOVERY_INTERVIEW_DENIED" };
153
+ const catalog = WORKFLOW_TOOL_GROUPS.map(g => ({ id: g.id, description: g.description, examples: [...g.examples], active: this.mode === "full" || this.state.groups.includes(g.id) }));
154
+ if (!target)
155
+ return { ok: true, ...this.snapshot, catalog };
156
+ if (CORE_WORKFLOW_TOOLS.includes(target)) {
157
+ if (!this.session?.getActiveToolNames().includes(target))
158
+ return { ok: false, code: "TOOL_EXPOSURE_REQUIRED_TOOL_MISSING" };
159
+ return { ok: true, alreadyActive: true, tools: [target] };
160
+ }
161
+ const group = WORKFLOW_TOOL_GROUPS.find(g => g.id === target || g.tools.includes(target));
162
+ if (!group)
163
+ return { ok: false, code: "TOOL_DISCOVERY_NOT_FOUND", catalog };
164
+ if (!this.session)
165
+ return { ok: false, code: "TOOL_EXPOSURE_SESSION_UNAVAILABLE" };
166
+ const registered = new Set(this.session.getAllTools?.().map(t => t.name) ?? []);
167
+ if (group.tools.some(n => !registered.has(n))) {
168
+ this.fallback("TOOL_EXPOSURE_GROUP_UNAVAILABLE");
169
+ return { ok: false, code: "TOOL_EXPOSURE_GROUP_UNAVAILABLE", ...this.snapshot };
170
+ }
171
+ try {
172
+ this.state = { ...this.state, groups: [...new Set([...this.state.groups, group.id])] };
173
+ this.apply();
174
+ this.persist();
175
+ }
176
+ catch {
177
+ this.fallback("TOOL_EXPOSURE_LOAD_FAILED");
178
+ }
179
+ return { ok: true, ...this.snapshot, group: group.id, tools: [...group.tools], effective: "next-model-response", guidance: "Use the activated typed tools in your next response. Loading has not executed any business action." };
180
+ }
181
+ buildTool(fullTool) {
182
+ return { name: "operatorCapabilities", label: "发现工作流工具", description: TOOL_DISCOVERY_DESCRIPTION,
183
+ // One short navigation line; detailed semantics live in schema description.
184
+ promptSnippet: "工作流能力目录:按用户意图选组;所需能力未显示时先调用 operatorCapabilities(target=组ID),再调用加载后的业务工具完成请求:" + WORKFLOW_TOOL_GROUPS.map(g => `${g.id}: ${g.description} (${g.examples.join(", ")})`).join("; "),
185
+ parameters: Type.Object({ target: Type.Optional(Type.String({ maxLength: 80, description: "Group ID or exact tool name; omit to list groups." })) }, { additionalProperties: false }),
186
+ execute: async (_id, params, signal) => {
187
+ if (signal?.aborted)
188
+ throw new Error("Tool discovery aborted");
189
+ if (this.mode === "full" && !this.interview && !params.target && fullTool)
190
+ return fullTool.execute(_id, {});
191
+ const result = this.discover(params.target);
192
+ return { isError: result.ok === false, content: [{ type: "text", text: JSON.stringify(result) }], details: result };
193
+ } };
194
+ }
195
+ }