@tea-agent/loop-agent 0.44.0-next.1 → 0.44.0-next.11

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 (245) hide show
  1. package/CHANGELOG.md +379 -416
  2. package/dist/application/evaluation/budget.js +21 -0
  3. package/dist/application/evaluation/corpus-hash.js +10 -15
  4. package/dist/application/evaluation/corpus.js +2 -1
  5. package/dist/application/evaluation/frontend-browser-acceptance.js +77 -0
  6. package/dist/application/evaluation/frontend-corpus-browser-acceptance.js +175 -0
  7. package/dist/application/evaluation/frontend-gateway-evidence.js +226 -0
  8. package/dist/application/evaluation/frontend-pair-registration.js +143 -0
  9. package/dist/application/evaluation/frontend-paired-summary.js +150 -0
  10. package/dist/application/evaluation/frontend-run-observation.js +144 -0
  11. package/dist/application/evaluation/frontend-shared-evidence.js +105 -0
  12. package/dist/application/evaluation/types.js +45 -12
  13. package/dist/application/task-lifecycle/observe.js +26 -1
  14. package/dist/build-stamp.json +3 -3
  15. package/dist/cli/command-definitions.js +11 -0
  16. package/dist/cli/program.js +4 -0
  17. package/dist/commands/task-advance.js +3 -5
  18. package/dist/commands/task-source-prepare.js +13 -1
  19. package/dist/executors/dag-pi/guards.js +4 -0
  20. package/dist/executors/dag-pi/model-config.js +30 -0
  21. package/dist/executors/dag-pi/plan/fact-adoption.js +55 -0
  22. package/dist/{workflows/dag/frontend-plan-completeness.js → executors/dag-pi/plan/facts.js} +22 -28
  23. package/dist/executors/dag-pi/plan/finalize-tools.js +259 -0
  24. package/dist/executors/dag-pi/plan/ledger-contract.js +55 -0
  25. package/dist/executors/dag-pi/plan/record-tools.js +861 -0
  26. package/dist/executors/dag-pi/plan/schema.js +129 -0
  27. package/dist/executors/dag-pi/plan/session.js +1 -0
  28. package/dist/executors/dag-pi/plan/tool-helpers.js +16 -0
  29. package/dist/executors/dag-pi/sessions/index.js +6 -0
  30. package/dist/executors/dag-pi/sessions/plan-batches.js +280 -0
  31. package/dist/executors/dag-pi/sessions/plan-prompts.js +367 -0
  32. package/dist/executors/dag-pi/sessions/scout-parallel.js +197 -0
  33. package/dist/executors/dag-pi/sessions/segmented-plan.js +1184 -0
  34. package/dist/executors/dag-pi/sessions/writer-evidence.js +60 -0
  35. package/dist/executors/dag-pi/tools/contract-tools.js +515 -0
  36. package/dist/executors/dag-pi/tools/design-terminal-tools.js +159 -0
  37. package/dist/executors/dag-pi/tools/plan-decision-tools.js +529 -0
  38. package/dist/executors/dag-pi/tools/review-terminal-tools.js +159 -0
  39. package/dist/executors/dag-pi/tools/scout-evidence-tools.js +270 -0
  40. package/dist/executors/dag-pi-executor.js +733 -5782
  41. package/dist/executors/pi-executor.js +6 -1
  42. package/dist/executors/pi-sdk-executor.js +112 -19
  43. package/dist/executors/shell-executor.js +88 -12
  44. package/dist/executors/shell-presets.js +1 -1
  45. package/dist/executors/shell-write-guard.js +26 -3
  46. package/dist/infrastructure/console/operation-store.js +48 -14
  47. package/dist/infrastructure/evaluation/corpus-store.js +37 -12
  48. package/dist/shared/file-identity.js +23 -0
  49. package/dist/shared/git-workspace-status.js +482 -0
  50. package/dist/shared/operator/capabilities.js +10 -5
  51. package/dist/shared/path-safety.js +2 -2
  52. package/dist/shared/wizard-local-telemetry.js +51 -0
  53. package/dist/task/config-types.js +22 -8
  54. package/dist/task/contract/project.js +13 -0
  55. package/dist/task/contract/schema.js +2 -7
  56. package/dist/task/frontend-preflight.js +1 -1
  57. package/dist/task/source-prepare/parse-intent.js +124 -5
  58. package/dist/task/source-prepare/prepare.js +6 -1
  59. package/dist/task/source-prepare/semantic-intake.js +18 -3
  60. package/dist/task/source-prepare/source-execution.js +65 -0
  61. package/dist/task/source-prepare/source-fidelity-pi.js +22 -9
  62. package/dist/task/source-prepare/source-provider-budget.js +290 -0
  63. package/dist/worker/console/chat/assistant-content.js +5 -34
  64. package/dist/worker/console/chat/chat-event-store.js +62 -10
  65. package/dist/worker/console/chat/context-insights.js +723 -0
  66. package/dist/worker/console/chat/conversation-nodes.js +383 -0
  67. package/dist/worker/console/chat/db-connections.js +854 -0
  68. package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +1 -1
  69. package/dist/worker/console/chat/pi-runtime/custom-tools/sql-tools.js +655 -0
  70. package/dist/worker/console/chat/pi-runtime.js +445 -36
  71. package/dist/worker/console/chat/provider-error.js +0 -12
  72. package/dist/worker/console/chat/repo-browser.js +52 -4
  73. package/dist/worker/console/chat/routes.js +577 -72
  74. package/dist/worker/console/chat/sdd-data-alignment.js +8 -31
  75. package/dist/worker/console/chat/session-store.js +147 -19
  76. package/dist/worker/console/chat/shortcuts.js +7 -0
  77. package/dist/worker/console/chat/timeline-message-order.js +22 -0
  78. package/dist/worker/console/chat/tools.js +34 -0
  79. package/dist/worker/console/chat/turn-process.js +237 -66
  80. package/dist/worker/console/chat/user-turn-outline.js +19 -0
  81. package/dist/worker/console/console-update-runtime.js +2 -2
  82. package/dist/worker/console/dag-confirmation.js +3 -0
  83. package/dist/worker/console/dag-execution-receipt.js +3 -0
  84. package/dist/worker/console/operator-actions.js +32 -3
  85. package/dist/worker/console/operator-user-error.js +28 -1
  86. package/dist/worker/console/pi-readiness.js +4 -4
  87. package/dist/worker/console/prd-intake-bridge.js +5 -12
  88. package/dist/worker/console/recovery-cta.js +14 -14
  89. package/dist/worker/console/server.js +5 -1
  90. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-8-j6y-sd.js → abnfDiagram-N423BO3Z-r1NAPU_5.js} +1 -1
  91. package/dist/worker/console/static/assets/{arc-eoQiMvuk.js → arc-dT5T4sVL.js} +1 -1
  92. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-C4A3uMcI.js → architectureDiagram-T3A2C74G-CP_cOq46.js} +1 -1
  93. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-D4zD2F-Q.js → blockDiagram-VBNYF7ZC-sToEZxEf.js} +1 -1
  94. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-j1RkJziL.js → c4Diagram-5PPSVZJV-DSxwwi2m.js} +1 -1
  95. package/dist/worker/console/static/assets/channel-CyBY_yGk.js +1 -0
  96. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-YBHmhik1.js → chunk-2GRJ4B5K-B9fh0IkF.js} +1 -1
  97. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-COfWyo9P.js → chunk-2Q5K7J3B-CAUNl-A6.js} +1 -1
  98. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-I99OUkHY.js → chunk-5RXB4S5H-BomeqbNX.js} +1 -1
  99. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-XKxoJNJ4.js → chunk-5VM5RSS4-BNAuTOLE.js} +1 -1
  100. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DLT_cYx1.js → chunk-6Q2QTUOP-DfzjRD5y.js} +1 -1
  101. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CxcKZ9mV.js → chunk-GF5L2VYU-C3uE-yc2.js} +1 -1
  102. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-V1EqXdjY.js → chunk-JWPE2WC7-C3sQMMYr.js} +1 -1
  103. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DebTtdFp.js → chunk-KBJHAD2P-D_AtEYQL.js} +1 -1
  104. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-B-ivNRDf.js → chunk-RYQCIY6F-DW4TwhKv.js} +1 -1
  105. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-DC_Ds11b.js → chunk-XXDRQBXY-CTQDmJcp.js} +1 -1
  106. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-D5lN4E_E.js +1 -0
  107. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-D5lN4E_E.js +1 -0
  108. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-sWEqKwIb.js → cose-bilkent-JH36ORCC-iMqPuBsL.js} +1 -1
  109. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BXa_dcu4.js → cynefin-VYW2F7L2-DktIuDWs.js} +1 -1
  110. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-C-Mle84F.js → cynefinDiagram-MW4NZA55-BgVnjyEs.js} +1 -1
  111. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-CXPDBITe.js → dagre-VZM6K2ZE-CR25E4bu.js} +1 -1
  112. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-CC-WJQfa.js → diagram-7IWD3JNH-CPM2h5HY.js} +1 -1
  113. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-CDAV5Vs4.js → diagram-B4RE2ZJO-DqF0x2g1.js} +1 -1
  114. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-CmFiAcNz.js → diagram-LBJQPF4R-G8BYp2eb.js} +1 -1
  115. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-DPBZHuyn.js → diagram-Q27KOJAE-BbC4kT_D.js} +1 -1
  116. package/dist/worker/console/static/assets/{diagram-UB23O5K3-jUlm_Ds3.js → diagram-UB23O5K3-CKZwZ-G5.js} +1 -1
  117. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-DWhQ3mfY.js → ebnfDiagram-BXEA7PRR-kJDmheia.js} +1 -1
  118. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-Tr2gMqet.js → erDiagram-JOGREHBK-DFTVHyxB.js} +1 -1
  119. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-DJjVQHPA.js → flowDiagram-UKHOOZJN-BqdN5_os.js} +1 -1
  120. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-D74dQ4u0.js → ganttDiagram-PKOTCBZU-SYDjVakh.js} +1 -1
  121. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-DwW0tZ0X.js → gitGraphDiagram-DS77QQ5N-Bf8bNpGA.js} +1 -1
  122. package/dist/worker/console/static/assets/index-B28Onmfy.css +1 -0
  123. package/dist/worker/console/static/assets/index-CTMZsDmh.js +486 -0
  124. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-ILCbxJyb.js → infoDiagram-6WML65LV-DIeAmJ45.js} +1 -1
  125. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-DeuWBQ89.js → ishikawaDiagram-WSZJBQD7-oikqUAlo.js} +1 -1
  126. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-CF5ih8Fk.js → journeyDiagram-NVQOT4AX-mKEF_xYT.js} +1 -1
  127. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-C7yOSuRO.js → kanban-definition-27J2QSJJ-BdWJHPnN.js} +1 -1
  128. package/dist/worker/console/static/assets/{linear-BDZ9riWi.js → linear-DGRlieMH.js} +1 -1
  129. package/dist/worker/console/static/assets/{mermaid.core-7pKqYtpZ.js → mermaid.core-4P9yPC9c.js} +5 -5
  130. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-LeJDybSU.js → mindmap-definition-FAOFIHXS-5PTSkos6.js} +1 -1
  131. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-BJvT3pMD.js → pegDiagram-VL7TDLO6-DONIFpG5.js} +1 -1
  132. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-_rGqpMan.js → pieDiagram-7S7Q4E2Y-D_Z4S70M.js} +1 -1
  133. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-DPcSv5aA.js → quadrantDiagram-CIZ2JOQS-CAsjh8iY.js} +1 -1
  134. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-Drxx4hkJ.js → railroadDiagram-AXF67PYL-Cx4Dd6ac.js} +1 -1
  135. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BCTUdU4z.js → requirementDiagram-LRYGKXZP-cQb7mwyH.js} +1 -1
  136. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-B6wzbZmB.js → sankeyDiagram-W5VNT64P-Cd-DhUdf.js} +1 -1
  137. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-BGt8d3QQ.js → sequenceDiagram-SI44F4Z6-AlKYRgIk.js} +1 -1
  138. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-7nlhJKo7.js → sizeCapture-X5ZJPWSS-CUy_ET4e.js} +1 -1
  139. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-Cv2stqMA.js → stateDiagram-OKZ733FA-CTuVe6Sa.js} +1 -1
  140. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BsWhs8O7.js +1 -0
  141. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-qDAo4Yc1.js → swimlanes-SLNWSIFB-ChFLJb-v.js} +2 -2
  142. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CJcioYGH.js +8 -0
  143. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CKbDNKTr.js → timeline-definition-Z64GVDOM-DZZeiAPr.js} +1 -1
  144. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DI-9EHic.js → vennDiagram-T6HMQDX7-t4O91cZU.js} +1 -1
  145. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-BrzzRDpX.js → wardleyDiagram-T6FBY63Y-CV5qGHZu.js} +1 -1
  146. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-BclH5hGh.js → xychartDiagram-ELKLHX3M-DyXbytUI.js} +1 -1
  147. package/dist/worker/console/static/index.html +2 -2
  148. package/dist/worker/console/static-src/app/console-types.js +9 -1
  149. package/dist/worker/console/static-src/operator-chat/animation-frame-batcher.js +38 -0
  150. package/dist/worker/console/static-src/operator-chat/chat-link.js +20 -0
  151. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +186 -5
  152. package/dist/worker/console/static-src/operator-chat/chat-stream-continuity.js +101 -0
  153. package/dist/worker/console/static-src/operator-chat/compaction-message.js +18 -3
  154. package/dist/worker/console/static-src/operator-chat/context-insights-store.js +64 -0
  155. package/dist/worker/console/static-src/operator-chat/details-rail-surfaces.js +98 -0
  156. package/dist/worker/console/static-src/operator-chat/file-palette-nav.js +81 -0
  157. package/dist/worker/console/static-src/operator-chat/pending-user-message.js +17 -3
  158. package/dist/worker/console/static-src/operator-chat/process-label.js +27 -5
  159. package/dist/worker/console/static-src/operator-chat/tools-catalog.js +16 -7
  160. package/dist/worker/console/static-src/operator-chat/transcript-mode.js +21 -0
  161. package/dist/worker/console/static-src/operator-chat/turn-group-equality.js +4 -1
  162. package/dist/worker/console/static-src/operator-chat/turn-process-disclosure.js +13 -5
  163. package/dist/worker/console/static-src/operator-chat/turn-state-projection.js +166 -0
  164. package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +56 -2
  165. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +211 -40
  166. package/dist/worker/console/static-src/operator-chat/useChatStream.js +124 -27
  167. package/dist/worker/console/static-src/operator-chat/useChatThread.js +88 -20
  168. package/dist/worker/console/static-src/operator-chat/useComposer.js +80 -6
  169. package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +13 -3
  170. package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +36 -17
  171. package/dist/worker/console/static-src/operator-chat/useRuntimeSnapshot.js +18 -0
  172. package/dist/worker/console/static-src/operator-chat/useWorkspaceBrowserGate.js +4 -0
  173. package/dist/worker/console/static-src/shell/console-update-reload.js +1 -1
  174. package/dist/worker/console/workspace-context.js +2 -0
  175. package/dist/worker/console/workspace-initialization.js +3 -3
  176. package/dist/worker/observability/read-model.js +23 -2
  177. package/dist/worker/observe/node-context-insights.js +479 -0
  178. package/dist/worker/observe/static/console-theme.css +174 -0
  179. package/dist/worker/observe/static/console-theme.js +36 -0
  180. package/dist/worker/observe/static/operator-chrome.css +85 -0
  181. package/dist/worker/observe/static/operator-chrome.js +51 -0
  182. package/dist/worker/scheduler/scheduled-goal-dispatch.js +3 -2
  183. package/dist/worker/scheduler/scheduled-goal-evidence.js +66 -3
  184. package/dist/worker/scheduler/scheduled-goal-store.js +10 -0
  185. package/dist/workflows/dag/budget-enforcement.js +31 -2
  186. package/dist/workflows/dag/checkpoint.js +686 -0
  187. package/dist/workflows/dag/frontend-closeout.js +3 -1
  188. package/dist/workflows/dag/frontend-contract-facts.js +11 -8
  189. package/dist/workflows/dag/frontend-design-policy.js +6 -6
  190. package/dist/workflows/dag/frontend-durable-tools.js +90 -70
  191. package/dist/workflows/dag/frontend-implementation-contract.js +146 -57
  192. package/dist/workflows/dag/frontend-plan-canary.js +66 -16
  193. package/dist/workflows/dag/frontend-plan-decision-contract.js +13 -21
  194. package/dist/workflows/dag/frontend-plan-progress.js +92 -0
  195. package/dist/workflows/dag/frontend-recovery-plan.js +10 -5
  196. package/dist/workflows/dag/frontend-recovery-run.js +51 -46
  197. package/dist/workflows/dag/frontend-repair-assertions.js +36 -0
  198. package/dist/workflows/dag/frontend-review-context.js +29 -1
  199. package/dist/workflows/dag/frontend-review-scopes.js +92 -2
  200. package/dist/workflows/dag/frontend-risk.js +8 -3
  201. package/dist/workflows/dag/frontend-root-observation.js +261 -0
  202. package/dist/workflows/dag/frontend-session-budget.js +52 -39
  203. package/dist/workflows/dag/frontend-session-context.js +10 -0
  204. package/dist/workflows/dag/frontend-test-execution-evidence.js +206 -48
  205. package/dist/workflows/dag/frontend-typed-event-store.js +11 -1
  206. package/dist/workflows/dag/frontend-verification-trace.js +6 -0
  207. package/dist/workflows/dag/frontend-writer-admission.js +3 -1
  208. package/dist/workflows/dag/hybrid/sources.js +1812 -0
  209. package/dist/workflows/dag/hybrid/templates/backend-test.js +1807 -0
  210. package/dist/workflows/dag/hybrid/templates/frontend-test.js +702 -0
  211. package/dist/workflows/dag/hybrid/templates/frontend.js +1529 -0
  212. package/dist/workflows/dag/hybrid/templates/index.js +8 -0
  213. package/dist/workflows/dag/hybrid/templates/kg-bootstrap.js +449 -0
  214. package/dist/workflows/dag/hybrid/templates/knowledge-sync.js +495 -0
  215. package/dist/workflows/dag/hybrid/templates/shared.js +101 -0
  216. package/dist/workflows/dag/hybrid/templates/standard.js +265 -0
  217. package/dist/workflows/dag/hybrid/types.js +32 -0
  218. package/dist/workflows/dag/init-hybrid.js +57 -7106
  219. package/dist/workflows/dag/node-execution.js +11 -11
  220. package/dist/workflows/dag/output-protocol.js +1 -0
  221. package/dist/workflows/dag/rerun-feedback.js +35 -4
  222. package/dist/workflows/dag/rerun-task.js +62 -66
  223. package/dist/workflows/dag/runner.js +38 -1159
  224. package/dist/workflows/dag/terminal-status.js +502 -0
  225. package/dist/workflows/dag/types.js +15 -8
  226. package/dist/workflows/loop/benchmark.js +11 -8
  227. package/docs/README.md +1 -1
  228. package/docs/architecture/dag-execution.md +1 -1
  229. package/docs/architecture/runtime-boundaries.md +1 -1
  230. package/docs/governance/harness-methodology-verification.md +11 -0
  231. package/docs/templates/backend-test-dag.json +5 -4
  232. package/docs/templates/frontend-implementation-contract.schema.json +31 -11
  233. package/package.json +6 -4
  234. package/skills/frontend-design-review/SKILL.md +8 -11
  235. package/skills/frontend-design-review/references/review-checklist.md +3 -4
  236. package/skills/frontend-review/SKILL.md +5 -1
  237. package/skills/loop-agent/references/command-reference.md +8 -0
  238. package/skills/loop-agent/references/hybrid-dag.md +1 -1
  239. package/dist/worker/console/static/assets/channel-ChE7y-cx.js +0 -1
  240. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C01TCf2X.js +0 -1
  241. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C01TCf2X.js +0 -1
  242. package/dist/worker/console/static/assets/index-BWkIfcrK.css +0 -1
  243. package/dist/worker/console/static/assets/index-Cdkvw_H6.js +0 -469
  244. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DC7V5vcq.js +0 -1
  245. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Bwy4QUTO.js +0 -8
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Composer `@` file palette helpers: 1-column movement, crumbs, row labels,
3
+ * and keyboard decisions. DOM-free so keyboard/AT behavior can be unit-tested.
4
+ */
5
+ export const FILE_PALETTE_AVAILABLE_HEIGHT_VAR = "--oc-file-palette-available-height";
6
+ export const FILE_PALETTE_MAX_HEIGHT_PX = 400;
7
+ export function fileOptionId(index) {
8
+ return `oc-file-option-${index}`;
9
+ }
10
+ export function filePaletteBasename(path) {
11
+ const trimmed = path.endsWith("/") ? path.slice(0, -1) : path;
12
+ const slash = trimmed.lastIndexOf("/");
13
+ const name = slash < 0 ? trimmed : trimmed.slice(slash + 1);
14
+ return path.endsWith("/") ? `${name}/` : name;
15
+ }
16
+ export function filePaletteParent(path) {
17
+ const trimmed = path.endsWith("/") ? path.slice(0, -1) : path;
18
+ const slash = trimmed.lastIndexOf("/");
19
+ return slash < 0 ? "" : trimmed.slice(0, slash);
20
+ }
21
+ export function moveFilePaletteIndex(current, length, direction) {
22
+ if (!Number.isFinite(length) || length <= 0)
23
+ return 0;
24
+ if (!Number.isFinite(current) || current < 0)
25
+ return 0;
26
+ if (direction === "up")
27
+ return current <= 0 ? 0 : current - 1;
28
+ return current >= length - 1 ? length - 1 : current + 1;
29
+ }
30
+ /**
31
+ * Breadcrumbs exist only after a Tab/chevron drill. A path the user typed
32
+ * already shows its context in the draft, so it gets no header.
33
+ */
34
+ export function filePaletteCrumbs(query, drilled) {
35
+ if (!drilled)
36
+ return undefined;
37
+ const slash = query.lastIndexOf("/");
38
+ if (slash < 0)
39
+ return undefined;
40
+ const segments = query
41
+ .slice(0, slash)
42
+ .split("/")
43
+ .filter((segment) => segment !== "");
44
+ if (segments.length === 0)
45
+ return undefined;
46
+ const crumbs = [
47
+ { label: "工作区", value: "", current: false },
48
+ ];
49
+ for (const [index, segment] of segments.entries()) {
50
+ crumbs.push({
51
+ label: segment,
52
+ value: `${segments.slice(0, index + 1).join("/")}/`,
53
+ current: index === segments.length - 1,
54
+ });
55
+ }
56
+ return crumbs;
57
+ }
58
+ export function decideFilePaletteKey(input) {
59
+ if (input.shortcutOpen || input.composing || input.optionCount <= 0) {
60
+ return { type: "none" };
61
+ }
62
+ if (input.key === "ArrowUp") {
63
+ return {
64
+ type: "move",
65
+ index: moveFilePaletteIndex(input.activeIndex, input.optionCount, "up"),
66
+ };
67
+ }
68
+ if (input.key === "ArrowDown") {
69
+ return {
70
+ type: "move",
71
+ index: moveFilePaletteIndex(input.activeIndex, input.optionCount, "down"),
72
+ };
73
+ }
74
+ if (input.key === "Escape")
75
+ return { type: "dismiss" };
76
+ if (input.key === "Tab")
77
+ return input.activeIsDir ? { type: "drill" } : { type: "pick" };
78
+ if (input.key === "Enter" && !input.shiftKey)
79
+ return { type: "pick" };
80
+ return { type: "none" };
81
+ }
@@ -6,7 +6,11 @@
6
6
  export function appendPendingSubmission(messages, pending) {
7
7
  if (messages.some((message) => message.clientRequestId === pending.clientRequestId))
8
8
  return [...messages];
9
- return [...messages, { ...pending.user, pending: true }, pending.assistant];
9
+ return [
10
+ ...messages,
11
+ { ...pending.user, pending: true },
12
+ { ...pending.assistant, clientRequestId: pending.clientRequestId },
13
+ ];
10
14
  }
11
15
  /** Merge a durable user message into its optimistic or snapshot row in place.
12
16
  *
@@ -18,7 +22,8 @@ export function replacePendingUserMessage(messages, clientRequestId, durable) {
18
22
  let replaced = false;
19
23
  const next = [];
20
24
  for (const message of messages) {
21
- const matches = message.clientRequestId === clientRequestId || message.id === durable.id;
25
+ const matches = message.role === "user" &&
26
+ (message.clientRequestId === clientRequestId || message.id === durable.id);
22
27
  if (!matches) {
23
28
  next.push(message);
24
29
  continue;
@@ -37,7 +42,16 @@ export function replacePendingUserMessage(messages, clientRequestId, durable) {
37
42
  clientRequestId,
38
43
  });
39
44
  }
40
- return replaced ? next : [...next, durable];
45
+ if (replaced)
46
+ return next;
47
+ const assistantIndex = next.findIndex((message) => message.role === "assistant" && message.clientRequestId === clientRequestId);
48
+ if (assistantIndex < 0)
49
+ return [...next, durable];
50
+ return [
51
+ ...next.slice(0, assistantIndex),
52
+ durable,
53
+ ...next.slice(assistantIndex),
54
+ ];
41
55
  }
42
56
  /** Keep an unconfirmed optimistic bubble when a recovery snapshot lacks it. */
43
57
  export function mergePendingSubmissionOnHydration(canonical, pending) {
@@ -1,18 +1,25 @@
1
1
  import { isSubagentTool } from "../../chat/tool-preview.js";
2
2
  /**
3
3
  * Count the collapsed-turn disclosure buckets exactly like DSH
4
- * `TurnProcessNodeView`: tool calls, process messages and subagents, in that
5
- * order. Built-in subagent delegations (`Agent` tool) count as subagents, not
6
- * as ordinary tool calls (2026-09-08 alignment).
4
+ * `TurnProcessNodeView`: tool calls, durable assistant replies and subagents,
5
+ * in that order. Built-in subagent delegations (`Agent` tool) count as
6
+ * subagents, not as ordinary tool calls (2026-09-08 alignment).
7
7
  *
8
8
  * @param items - ordered process nodes of one turn.
9
9
  * @returns the three bucket counts.
10
10
  */
11
11
  export function countTurnProcessItems(items) {
12
+ return countEntries(items.map((item) => ({ source: "process", item })));
13
+ }
14
+ function countEntries(entries) {
12
15
  let toolCalls = 0;
13
16
  let messages = 0;
14
17
  let subagents = 0;
15
- for (const item of items) {
18
+ const assistantMessageIds = new Set();
19
+ for (const entry of entries) {
20
+ if (entry.source !== "process")
21
+ continue;
22
+ const item = entry.item;
16
23
  if (item.kind === "tool") {
17
24
  if (isSubagentTool(item.tool.toolName))
18
25
  subagents += 1;
@@ -20,10 +27,25 @@ export function countTurnProcessItems(items) {
20
27
  toolCalls += 1;
21
28
  continue;
22
29
  }
23
- messages += 1;
30
+ if (item.kind === "activity" || item.kind === "dag-progress") {
31
+ toolCalls += item.toolCallCount ?? 0;
32
+ continue;
33
+ }
34
+ if (item.kind !== "text" || item.text.trim() === "")
35
+ continue;
36
+ if (item.assistantMessageId)
37
+ assistantMessageIds.add(item.assistantMessageId);
38
+ else
39
+ messages += 1;
24
40
  }
41
+ messages += assistantMessageIds.size;
25
42
  return { toolCalls, messages, subagents };
26
43
  }
44
+ /** Count only the ordered process window; prelude/post-answer nodes are kept
45
+ * visible but do not inflate the DSH compact disclosure summary. */
46
+ export function countTurnFlowItems(entries) {
47
+ return countEntries(entries);
48
+ }
27
49
  /**
28
50
  * Summary label for a completed turn's process disclosure.
29
51
  *
@@ -70,13 +70,22 @@ const FALLBACK_AGENT_ENTRY = {
70
70
  export function buildToolCatalog(capabilities) {
71
71
  if (!capabilities)
72
72
  return null;
73
- const operatorTools = (capabilities.tools ?? []).map((t) => ({
74
- toolId: t.toolId,
75
- action: t.action,
76
- description: t.description,
77
- kind: t.kind ?? "read",
78
- cli: t.cli,
79
- }));
73
+ const operatorToolsById = new Map();
74
+ for (const tool of [
75
+ ...(capabilities.tools ?? []),
76
+ ...(capabilities.builtinCustomTools ?? []),
77
+ ]) {
78
+ if (operatorToolsById.has(tool.toolId))
79
+ continue;
80
+ operatorToolsById.set(tool.toolId, {
81
+ toolId: tool.toolId,
82
+ action: tool.action,
83
+ description: tool.description,
84
+ kind: tool.kind ?? "read",
85
+ cli: tool.cli,
86
+ });
87
+ }
88
+ const operatorTools = [...operatorToolsById.values()];
80
89
  // ADR 0022: subagents come from the server's builtinSubagents field;
81
90
  // static entries never duplicate a server-advertised toolId.
82
91
  const subagentTools = (capabilities.builtinSubagents ?? []).map((s) => ({
@@ -0,0 +1,21 @@
1
+ export const TRANSCRIPT_MODE_STORAGE_KEY = "loop-console.operator-chat.transcript-mode.v1";
2
+ export function parseTranscriptMode(value) {
3
+ return value === "compact" || value === "full" ? value : null;
4
+ }
5
+ export function loadTranscriptMode(storage) {
6
+ try {
7
+ return parseTranscriptMode(storage?.getItem(TRANSCRIPT_MODE_STORAGE_KEY)) ?? "compact";
8
+ }
9
+ catch {
10
+ return "compact";
11
+ }
12
+ }
13
+ export function saveTranscriptMode(mode, storage) {
14
+ try {
15
+ storage?.setItem(TRANSCRIPT_MODE_STORAGE_KEY, mode);
16
+ }
17
+ catch {
18
+ // Preference storage is optional.
19
+ }
20
+ return mode;
21
+ }
@@ -7,7 +7,10 @@ function sameReferences(previous, next) {
7
7
  export function sameTurnGroupInputs(previous, next) {
8
8
  return (previous.key === next.key &&
9
9
  previous.user === next.user &&
10
+ previous.turnState === next.turnState &&
11
+ previous.turnClosed === next.turnClosed &&
10
12
  previous.live === next.live &&
11
13
  sameReferences(previous.assistants, next.assistants) &&
12
- sameReferences(previous.tools, next.tools));
14
+ sameReferences(previous.tools, next.tools) &&
15
+ sameReferences(previous.conversationItems ?? [], next.conversationItems ?? []));
13
16
  }
@@ -2,9 +2,17 @@ export function turnProcessDisclosureKey(groupKey, answerId) {
2
2
  return `${groupKey}:generation-${answerId ?? "none"}`;
3
3
  }
4
4
  export function isTurnProcessCompact(input) {
5
- return (!input.historyHasMore &&
6
- !input.live &&
7
- !input.hasError &&
8
- input.processItemCount > 0 &&
9
- !input.expanded);
5
+ const eligible = !input.historyHasMore &&
6
+ input.turnClosed &&
7
+ input.hasFinalAnswer &&
8
+ input.processItemCount > 0;
9
+ if (!eligible)
10
+ return false;
11
+ if (input.manualOpen)
12
+ return false;
13
+ if (input.manualClosed)
14
+ return true;
15
+ if (input.mode === "full")
16
+ return false;
17
+ return true;
10
18
  }
@@ -0,0 +1,166 @@
1
+ export const TURN_STATE_RECONCILE_DELAYS_MS = [0, 75, 200, 500];
2
+ export const TURN_STATE_QUEUE_RETRY_DELAYS_MS = [0, 75, 200, 500, 2_000];
3
+ const MAX_TURN_STATE_QUERY_BATCH = 8;
4
+ /** Normalize server turn facts. Queued is externally still an open/running Turn. */
5
+ export function normalizeDurableTurnState(state) {
6
+ if (state === "queued" || state === "running")
7
+ return "running";
8
+ if (state === "settled" || state === "aborted" || state === "failed") {
9
+ return state;
10
+ }
11
+ return undefined;
12
+ }
13
+ /** Merge authoritative summaries without deleting older paginated Turn facts. */
14
+ export function mergeTurnStateSummaries(current, summaries) {
15
+ if (!summaries?.length)
16
+ return current;
17
+ let next;
18
+ for (const summary of summaries) {
19
+ if (typeof summary.turnId !== "string" || !summary.turnId)
20
+ continue;
21
+ const state = normalizeDurableTurnState(summary.state);
22
+ const previous = next?.[summary.turnId] ?? current[summary.turnId];
23
+ const merged = mergeDurableTurnState(previous, state);
24
+ if (!merged || previous === merged)
25
+ continue;
26
+ next ??= { ...current };
27
+ next[summary.turnId] = merged;
28
+ }
29
+ return next ?? current;
30
+ }
31
+ export function setProjectedTurnState(current, turnId, state) {
32
+ if (!turnId)
33
+ return current;
34
+ const normalized = normalizeDurableTurnState(state);
35
+ const merged = mergeDurableTurnState(current[turnId], normalized);
36
+ if (!merged || current[turnId] === merged) {
37
+ return current;
38
+ }
39
+ return { ...current, [turnId]: merged };
40
+ }
41
+ function mergeDurableTurnState(current, incoming) {
42
+ if (!incoming)
43
+ return current;
44
+ if (!current)
45
+ return incoming;
46
+ if (current === "failed" || current === "aborted")
47
+ return current;
48
+ if (current === "settled" && incoming === "running")
49
+ return current;
50
+ return incoming;
51
+ }
52
+ export function turnStateReconcileTrigger(replay, eventName) {
53
+ if (eventName !== "agent_settled")
54
+ return undefined;
55
+ return replay ? "after-replay" : "immediate";
56
+ }
57
+ export async function reconcileTurnStateWithBackoff(input) {
58
+ const delays = input.delaysMs ?? TURN_STATE_RECONCILE_DELAYS_MS;
59
+ const wait = input.wait ??
60
+ ((delayMs) => new Promise((resolve) => globalThis.setTimeout(resolve, delayMs)));
61
+ for (const delayMs of delays) {
62
+ if (delayMs > 0)
63
+ await wait(delayMs);
64
+ if (input.isCancelled?.())
65
+ return "cancelled";
66
+ let snapshot = null;
67
+ try {
68
+ snapshot = await input.read();
69
+ }
70
+ catch {
71
+ // A transport failure consumes one bounded attempt; later attempts or an
72
+ // SSE reconnect retain ownership of the pending reconciliation.
73
+ }
74
+ if (input.isCancelled?.())
75
+ return "cancelled";
76
+ if (!snapshot?.turnStates)
77
+ continue;
78
+ input.apply(snapshot.turnStates);
79
+ const state = snapshot.turnStates
80
+ .filter((summary) => summary.turnId === input.turnId)
81
+ .map((summary) => normalizeDurableTurnState(summary.state))
82
+ .find((candidate) => candidate !== undefined);
83
+ if (state && state !== "running")
84
+ return "terminal";
85
+ }
86
+ return "pending";
87
+ }
88
+ /** Serialize targeted Turn-state reads, batching replay work and retaining
89
+ * unresolved Turns until durable terminal truth arrives or the owner ends. */
90
+ export function createTurnStateReconcileQueue(input) {
91
+ const pending = new Set();
92
+ const wait = input.wait ??
93
+ ((delayMs) => new Promise((resolve) => globalThis.setTimeout(resolve, delayMs)));
94
+ const retryDelays = input.retryDelaysMs?.length
95
+ ? input.retryDelaysMs
96
+ : TURN_STATE_QUEUE_RETRY_DELAYS_MS;
97
+ let worker = null;
98
+ const run = async () => {
99
+ let retryIndex = 0;
100
+ while (pending.size > 0 && !input.isCancelled?.()) {
101
+ const delayMs = retryDelays[Math.min(retryIndex, retryDelays.length - 1)] ?? 0;
102
+ if (delayMs > 0) {
103
+ try {
104
+ await wait(delayMs);
105
+ }
106
+ catch {
107
+ if (input.isCancelled?.())
108
+ return;
109
+ }
110
+ }
111
+ if (input.isCancelled?.())
112
+ return;
113
+ const batch = [...pending].slice(0, MAX_TURN_STATE_QUERY_BATCH);
114
+ let snapshot = null;
115
+ try {
116
+ snapshot = await input.read(batch);
117
+ }
118
+ catch {
119
+ // The queue owns retry cadence; a transient read failure keeps the batch pending.
120
+ }
121
+ if (input.isCancelled?.())
122
+ return;
123
+ const summaries = snapshot?.turnStates;
124
+ if (summaries?.length)
125
+ input.apply(summaries);
126
+ let completed = 0;
127
+ for (const turnId of batch) {
128
+ const state = summaries
129
+ ?.filter((summary) => summary.turnId === turnId)
130
+ .map((summary) => normalizeDurableTurnState(summary.state))
131
+ .find((candidate) => candidate !== undefined);
132
+ if (state && state !== "running") {
133
+ pending.delete(turnId);
134
+ completed += 1;
135
+ continue;
136
+ }
137
+ // Rotate unresolved ids so batches larger than the server query cap cannot starve.
138
+ pending.delete(turnId);
139
+ pending.add(turnId);
140
+ }
141
+ retryIndex = completed > 0 ? 0 : retryIndex + 1;
142
+ }
143
+ };
144
+ const start = () => {
145
+ if (worker)
146
+ return worker;
147
+ if (pending.size === 0 || input.isCancelled?.())
148
+ return Promise.resolve();
149
+ worker = run().finally(() => {
150
+ worker = null;
151
+ if (pending.size > 0 && !input.isCancelled?.())
152
+ void start();
153
+ });
154
+ return worker;
155
+ };
156
+ return {
157
+ enqueue: (turnId, options) => {
158
+ if (!turnId || input.isCancelled?.())
159
+ return;
160
+ pending.add(turnId);
161
+ if (!options?.defer)
162
+ void start();
163
+ },
164
+ start,
165
+ };
166
+ }
@@ -19,11 +19,65 @@ export const OPERATOR_CHAT_REAL_PATHS = {
19
19
  events: "/api/operator/v1/chat/sessions/:sessionId/events",
20
20
  abort: "/api/operator/v1/chat/sessions/:sessionId/turns/:turnId/abort",
21
21
  };
22
+ const MAX_STATE_TURN_IDS = 8;
23
+ const MAX_STATE_TURN_ID_CHARS = 240;
24
+ function boundedStateTurnIds(turnIds) {
25
+ const result = [];
26
+ const seen = new Set();
27
+ for (const raw of turnIds ?? []) {
28
+ const turnId = raw.trim();
29
+ if (!turnId ||
30
+ turnId.length > MAX_STATE_TURN_ID_CHARS ||
31
+ seen.has(turnId)) {
32
+ continue;
33
+ }
34
+ seen.add(turnId);
35
+ result.push(turnId);
36
+ if (result.length >= MAX_STATE_TURN_IDS)
37
+ break;
38
+ }
39
+ return result;
40
+ }
22
41
  export function operatorChatTurnsUrl(origin, sessionId) {
23
42
  return `${origin}/api/operator/v1/chat/sessions/${encodeURIComponent(sessionId)}/turns`;
24
43
  }
25
- export function operatorChatStateUrl(origin, sessionId) {
26
- return `${origin}/api/operator/v1/chat/sessions/${encodeURIComponent(sessionId)}/state`;
44
+ export function operatorChatStateUrl(origin, sessionId, turnIds) {
45
+ const base = `${origin}/api/operator/v1/chat/sessions/${encodeURIComponent(sessionId)}/state`;
46
+ const bounded = boundedStateTurnIds(turnIds);
47
+ if (bounded.length === 0)
48
+ return base;
49
+ const query = new URLSearchParams();
50
+ for (const turnId of bounded)
51
+ query.append("turnId", turnId);
52
+ return `${base}?${query.toString()}`;
53
+ }
54
+ /** Compose session ownership with a short request timeout and explicit cleanup. */
55
+ export function createBoundedOwnerSignal(input) {
56
+ const controller = new AbortController();
57
+ const abortFromOwner = () => controller.abort(input.ownerSignal?.reason);
58
+ if (input.ownerSignal?.aborted)
59
+ abortFromOwner();
60
+ else
61
+ input.ownerSignal?.addEventListener("abort", abortFromOwner, { once: true });
62
+ const schedule = input.schedule ??
63
+ ((callback, delayMs) => globalThis.setTimeout(callback, delayMs));
64
+ const cancel = input.cancel ??
65
+ ((handle) => globalThis.clearTimeout(handle));
66
+ const timer = controller.signal.aborted
67
+ ? undefined
68
+ : schedule(() => controller.abort(new Error("Operator Chat state request timed out")), input.timeoutMs);
69
+ let disposed = false;
70
+ return {
71
+ signal: controller.signal,
72
+ dispose: () => {
73
+ if (disposed)
74
+ return;
75
+ disposed = true;
76
+ if (timer !== undefined)
77
+ cancel(timer);
78
+ input.ownerSignal?.removeEventListener("abort", abortFromOwner);
79
+ },
80
+ };
27
81
  }
28
82
  export function operatorChatEventsUrl(origin, sessionId) {
29
83
  return `${origin}/api/operator/v1/chat/sessions/${encodeURIComponent(sessionId)}/events`;