@tea-agent/loop-agent 0.39.0-beta.0 → 0.39.0-beta.10

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 (331) hide show
  1. package/AGENTS.md +4 -1
  2. package/CHANGELOG.md +248 -95
  3. package/README.md +9 -5
  4. package/bin/loop-agent.js +7 -3
  5. package/dist/application/task-lifecycle/advance.js +12 -0
  6. package/dist/application/task-lifecycle/recommendations.js +13 -2
  7. package/dist/build-stamp.json +3 -3
  8. package/dist/cli/command-definitions.js +23 -5
  9. package/dist/cli/program.js +21 -2
  10. package/dist/cli/update/notifier.js +2 -2
  11. package/dist/cli/update/runtime-activity.js +1 -29
  12. package/dist/cli.js +2 -1
  13. package/dist/commands/client-recovery.js +3 -0
  14. package/dist/commands/dag-follow-up.js +138 -0
  15. package/dist/commands/dag-rerun.js +55 -1
  16. package/dist/commands/init-model-catalog.js +464 -0
  17. package/dist/commands/init-upgrade.js +265 -97
  18. package/dist/commands/init.js +455 -28
  19. package/dist/commands/inspect-next.js +8 -0
  20. package/dist/commands/task-advance.js +19 -0
  21. package/dist/executors/dag-pi-executor.js +2306 -61
  22. package/dist/executors/pi-executor.js +7 -0
  23. package/dist/executors/pi-extension-resolver.js +233 -0
  24. package/dist/executors/pi-playwright-cli-tool.js +74 -28
  25. package/dist/executors/pi-read-budget-policy.js +239 -0
  26. package/dist/executors/pi-sdk-executor.js +180 -33
  27. package/dist/executors/shell-executor.js +1249 -224
  28. package/dist/executors/shell-write-guard.js +14 -0
  29. package/dist/executors/workspace-write-snapshot.js +68 -0
  30. package/dist/infrastructure/harness/atomic-write.js +23 -0
  31. package/dist/shared/dag-failure-category.js +150 -0
  32. package/dist/shared/dag-prompt-override.js +27 -0
  33. package/dist/shared/openspec-spec.js +70 -4
  34. package/dist/shared/operator/capabilities.js +39 -0
  35. package/dist/shared/playwright-cli-command-policy.js +15 -0
  36. package/dist/shared/update/console-notifier.js +100 -0
  37. package/dist/{cli → shared}/update/npm-client.js +70 -15
  38. package/dist/{cli → shared}/update/state.js +41 -13
  39. package/dist/task/config-types.js +50 -5
  40. package/dist/task/contract/apply.js +11 -1
  41. package/dist/task/contract/constants.js +2 -0
  42. package/dist/task/contract/hash.js +3 -0
  43. package/dist/task/contract/observe.js +25 -4
  44. package/dist/task/contract/paths.js +2 -1
  45. package/dist/task/contract/project.js +18 -1
  46. package/dist/task/contract/schema.js +4 -1
  47. package/dist/task/contract/transaction.js +12 -0
  48. package/dist/task/frontend-project-capability.js +199 -18
  49. package/dist/task/source-prepare/completeness.js +188 -0
  50. package/dist/task/source-prepare/fragment-inventory.js +477 -0
  51. package/dist/task/source-prepare/index.js +3 -0
  52. package/dist/task/source-prepare/ledger-reconciliation.js +127 -0
  53. package/dist/task/source-prepare/ledger-review.js +214 -0
  54. package/dist/task/source-prepare/ledger.js +545 -0
  55. package/dist/task/source-prepare/parse-intent.js +24 -4
  56. package/dist/task/source-prepare/prepare.js +298 -1
  57. package/dist/task/source-prepare/semantic-intake.js +25 -5
  58. package/dist/task/source-prepare/source-fidelity-pi.js +384 -0
  59. package/dist/task/source-prepare/types.js +22 -0
  60. package/dist/task/source-references.js +22 -1
  61. package/dist/worker/cli.js +18 -2
  62. package/dist/worker/console/chat/chat-event-store.js +62 -4
  63. package/dist/worker/console/chat/context-panel.js +7 -0
  64. package/dist/worker/console/chat/deferred-turn.js +12 -0
  65. package/dist/worker/console/chat/operation-card.js +8 -1
  66. package/dist/worker/console/chat/pi-console-config.js +81 -10
  67. package/dist/worker/console/chat/pi-runtime.js +264 -16
  68. package/dist/worker/console/chat/provider-error.js +98 -0
  69. package/dist/worker/console/chat/routes.js +298 -32
  70. package/dist/worker/console/chat/session-stats.js +179 -0
  71. package/dist/worker/console/chat/session-store.js +93 -63
  72. package/dist/worker/console/chat/todos.js +115 -0
  73. package/dist/worker/console/chat/tool-preview.js +42 -0
  74. package/dist/worker/console/chat/turn-process.js +20 -55
  75. package/dist/worker/console/chat/user-questions.js +266 -0
  76. package/dist/worker/console/chat/workspace-landing.js +14 -0
  77. package/dist/worker/console/console-handoff.js +82 -0
  78. package/dist/worker/console/console-update-and-init.js +115 -0
  79. package/dist/worker/console/console-update-runtime.js +84 -0
  80. package/dist/worker/console/dag-execution-receipt.js +33 -0
  81. package/dist/worker/console/draft-store.js +49 -0
  82. package/dist/worker/console/frontend-human-decision-adapter.js +19 -0
  83. package/dist/worker/console/frontend-split-operation-adapter.js +20 -0
  84. package/dist/worker/console/index.js +3 -0
  85. package/dist/worker/console/inspect-split.js +18 -0
  86. package/dist/worker/console/native-directory-picker.js +13 -0
  87. package/dist/worker/console/operation-run-facts.js +19 -3
  88. package/dist/worker/console/operation-store.js +227 -7
  89. package/dist/worker/console/operator-actions.js +388 -0
  90. package/dist/worker/console/operator-surface-health.js +1 -0
  91. package/dist/worker/console/operator-user-error.js +2 -2
  92. package/dist/worker/console/prd-intake-bridge.js +13 -0
  93. package/dist/worker/console/routes.js +355 -3
  94. package/dist/worker/console/security.js +67 -13
  95. package/dist/worker/console/server.js +609 -164
  96. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-C4kVYweA.js → abnfDiagram-N423BO3Z-BAsjg7ew.js} +1 -1
  97. package/dist/worker/console/static/assets/{arc-Bj2M8iO5.js → arc-CyIlrwZw.js} +1 -1
  98. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-CLlXe4-6.js → architectureDiagram-T3A2C74G-Bo4tobhH.js} +1 -1
  99. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-psEp5xH0.js → blockDiagram-VBNYF7ZC-Dfpow9gu.js} +1 -1
  100. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-DeKcOCGJ.js → c4Diagram-5PPSVZJV-DPmzG_B4.js} +1 -1
  101. package/dist/worker/console/static/assets/channel-DSrJAn0-.js +1 -0
  102. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-K0C744p1.js → chunk-2GRJ4B5K-pKQpB1UW.js} +1 -1
  103. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-xbNw4J9-.js → chunk-2Q5K7J3B-5n9YYquZ.js} +1 -1
  104. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DjLaSDUO.js → chunk-5RXB4S5H-DP3CtA2a.js} +1 -1
  105. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-CtiPlKel.js → chunk-5VM5RSS4-DYxMJPUy.js} +1 -1
  106. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DZtolir7.js → chunk-6Q2QTUOP-CS3D50Io.js} +1 -1
  107. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CPcdNeew.js → chunk-GF5L2VYU-gSdDfo5_.js} +1 -1
  108. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-NgHc6V37.js → chunk-JWPE2WC7-A48q0ZNt.js} +1 -1
  109. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DQ_T-hg8.js → chunk-KBJHAD2P-ow8Mm3DY.js} +1 -1
  110. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DgLsxcVP.js → chunk-RYQCIY6F-CMKfLWYE.js} +1 -1
  111. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-UrVoM9z1.js → chunk-XXDRQBXY-BiTBdQPX.js} +1 -1
  112. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DeMmPl0_.js +1 -0
  113. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DeMmPl0_.js +1 -0
  114. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CLkYvTb3.js → cose-bilkent-JH36ORCC-Cm7exRz_.js} +1 -1
  115. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BwT_xKrE.js → cynefin-VYW2F7L2-D9O5qGOu.js} +1 -1
  116. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-Bi9tuzif.js → cynefinDiagram-MW4NZA55-CkvQnako.js} +1 -1
  117. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BCIqkWBV.js → dagre-VZM6K2ZE-B1rzp7CB.js} +1 -1
  118. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-Dip6l9_Z.js → diagram-7IWD3JNH-BP07Ipcc.js} +1 -1
  119. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-B-xkh_wK.js → diagram-B4RE2ZJO-BlPzweQb.js} +1 -1
  120. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-DZO0kTt_.js → diagram-LBJQPF4R-CxPa7n0S.js} +1 -1
  121. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-D6ZplNbZ.js → diagram-Q27KOJAE-CMTZs53A.js} +1 -1
  122. package/dist/worker/console/static/assets/{diagram-UB23O5K3-BPekbhoS.js → diagram-UB23O5K3-CxG_X52r.js} +1 -1
  123. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-BtmaJpK5.js → ebnfDiagram-BXEA7PRR-D8axtJM0.js} +1 -1
  124. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-6DS0Xc44.js → erDiagram-JOGREHBK-DIsGzn7b.js} +1 -1
  125. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CihnROSm.js → flowDiagram-UKHOOZJN-CU9zkDG0.js} +1 -1
  126. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-CZC4zOE2.js → ganttDiagram-PKOTCBZU-DCjTmz5P.js} +1 -1
  127. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Dq1fhzGN.js → gitGraphDiagram-DS77QQ5N-BksdmFzg.js} +1 -1
  128. package/dist/worker/console/static/assets/index-B-O5ChYq.css +1 -0
  129. package/dist/worker/console/static/assets/index-CfnY8AQx.js +407 -0
  130. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DlSl4BGx.js → infoDiagram-6WML65LV-CGzzzJtL.js} +1 -1
  131. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-snnzFl_U.js → ishikawaDiagram-WSZJBQD7-BdseB80N.js} +1 -1
  132. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-BDE7qpMx.js → journeyDiagram-NVQOT4AX-DM9gsgha.js} +1 -1
  133. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-CD2Ci04G.js → kanban-definition-27J2QSJJ-3q-_9R2b.js} +1 -1
  134. package/dist/worker/console/static/assets/{linear-DdnapKIH.js → linear-B8N-Mxsd.js} +1 -1
  135. package/dist/worker/console/static/assets/{mermaid.core-BVjAT9b8.js → mermaid.core-EPIHUUsu.js} +5 -5
  136. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-D0yJk-zA.js → mindmap-definition-FAOFIHXS-CxwO12aa.js} +1 -1
  137. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-BVo9tFP-.js → pegDiagram-VL7TDLO6-bPqbVX6Y.js} +1 -1
  138. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-DnOV-mZ_.js → pieDiagram-7S7Q4E2Y-KzqIvzeX.js} +1 -1
  139. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-CzUJo58i.js → quadrantDiagram-CIZ2JOQS-CyofpWiV.js} +1 -1
  140. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-Bvikrolh.js → railroadDiagram-AXF67PYL-cTWJvLTP.js} +1 -1
  141. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-DtaSVCap.js → requirementDiagram-LRYGKXZP-BK--q27B.js} +1 -1
  142. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-C2c9A0wW.js → sankeyDiagram-W5VNT64P-C0SDOHXK.js} +1 -1
  143. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DmXJcU7r.js → sequenceDiagram-SI44F4Z6-Cong6YIo.js} +1 -1
  144. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-B4GUFW92.js → sizeCapture-X5ZJPWSS-DUVkgZx8.js} +1 -1
  145. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-Dsad2MXf.js → stateDiagram-OKZ733FA-C7XgxuZg.js} +1 -1
  146. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Dzbnd5oX.js +1 -0
  147. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DGq48Fbi.js → swimlanes-SLNWSIFB-D9Ayvwcy.js} +2 -2
  148. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BY0hHk6G.js +8 -0
  149. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CSSi6OFf.js → timeline-definition-Z64GVDOM-Byb000cH.js} +1 -1
  150. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-BqyzPrWv.js → vennDiagram-T6HMQDX7-DMLegPt4.js} +1 -1
  151. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DlznVb6S.js → wardleyDiagram-T6FBY63Y-ChMMeOsP.js} +1 -1
  152. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CfBcgJ_K.js → xychartDiagram-ELKLHX3M-bEMEPisW.js} +1 -1
  153. package/dist/worker/console/static/index.html +2 -2
  154. package/dist/worker/console/static-src/active-run-badge.js +17 -0
  155. package/dist/worker/console/static-src/app/console-types.js +68 -4
  156. package/dist/worker/console/static-src/app/useConsoleShell.js +30 -12
  157. package/dist/worker/console/static-src/app/useOperatorActions.js +41 -6
  158. package/dist/worker/console/static-src/app/useRecoveryConsole.js +45 -10
  159. package/dist/worker/console/static-src/app/useRunProgress.js +47 -0
  160. package/dist/worker/console/static-src/app/useTaskWizard.js +74 -2
  161. package/dist/worker/console/static-src/night/useNightBoard.js +8 -5
  162. package/dist/worker/console/static-src/operator-chat/cards/failure-category-advice.js +25 -0
  163. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +140 -8
  164. package/dist/worker/console/static-src/operator-chat/details-dag-actions.js +122 -0
  165. package/dist/worker/console/static-src/operator-chat/input-history.js +76 -0
  166. package/dist/worker/console/static-src/operator-chat/mutation-gate.js +1 -1
  167. package/dist/worker/console/static-src/operator-chat/refs.js +3 -0
  168. package/dist/worker/console/static-src/operator-chat/runtime-selection-labels.js +27 -0
  169. package/dist/worker/console/static-src/operator-chat/turn-submission.js +16 -3
  170. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +168 -72
  171. package/dist/worker/console/static-src/operator-chat/useChatStream.js +102 -21
  172. package/dist/worker/console/static-src/operator-chat/useChatThread.js +184 -4
  173. package/dist/worker/console/static-src/operator-chat/useComposer.js +32 -0
  174. package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +63 -9
  175. package/dist/worker/console/static-src/operator-chat/useWorkspaceBrowserGate.js +4 -0
  176. package/dist/worker/console/static-src/operator-chat/workspace-layout-mode.js +3 -3
  177. package/dist/worker/console/static-src/pages/tasks/run-id-resolution.js +79 -0
  178. package/dist/worker/console/static-src/pages/tasks/run-ownership-verify.js +23 -0
  179. package/dist/worker/console/static-src/pages/tasks/run-panel-progress.js +110 -0
  180. package/dist/worker/console/static-src/shell/useWorkspaces.js +299 -0
  181. package/dist/worker/console/static-src/shell/workspace-route.js +337 -0
  182. package/dist/worker/console/workspace-context.js +344 -0
  183. package/dist/worker/console/workspace-registry.js +214 -0
  184. package/dist/worker/loop-agent/loop-agent-client.js +7 -3
  185. package/dist/worker/materialize/frontend-split-task-materializer.js +72 -0
  186. package/dist/worker/materialize/harness-task-lineage.js +5 -2
  187. package/dist/worker/observability/init-runtime-activity.js +26 -0
  188. package/dist/worker/observability/read-model.js +22 -0
  189. package/dist/worker/observe/node-input.js +160 -3
  190. package/dist/worker/observe/node-process.js +377 -0
  191. package/dist/worker/observe/routes.js +224 -3
  192. package/dist/worker/observe/server.js +4 -0
  193. package/dist/worker/observe/shell-handler-keys.js +34 -0
  194. package/dist/worker/observe/static/api.js +90 -4
  195. package/dist/worker/observe/static/app.js +18 -70
  196. package/dist/worker/observe/static/constants.js +8 -1
  197. package/dist/worker/observe/static/dag-history-labels.js +4 -0
  198. package/dist/worker/observe/static/dag-node-purpose.d.ts +6 -0
  199. package/dist/worker/observe/static/dag-node-purpose.js +208 -0
  200. package/dist/worker/observe/static/format.js +60 -0
  201. package/dist/worker/observe/static/index.html +6 -1
  202. package/dist/worker/observe/static/inspect-workspace.js +307 -0
  203. package/dist/worker/observe/static/markdown-render.js +20 -1
  204. package/dist/worker/observe/static/operator-chrome.css +145 -20
  205. package/dist/worker/observe/static/operator-chrome.d.ts +20 -3
  206. package/dist/worker/observe/static/operator-chrome.js +330 -96
  207. package/dist/worker/observe/static/prompt-restart-candidates.d.ts +18 -0
  208. package/dist/worker/observe/static/prompt-restart-candidates.js +36 -0
  209. package/dist/worker/observe/static/router.d.ts +46 -0
  210. package/dist/worker/observe/static/router.js +25 -1
  211. package/dist/worker/observe/static/state.d.ts +50 -0
  212. package/dist/worker/observe/static/state.js +184 -1
  213. package/dist/worker/observe/static/styles.css +395 -0
  214. package/dist/worker/observe/static/views/dag-graph.js +4 -2
  215. package/dist/worker/observe/static/views/dag-inspector.js +1067 -9
  216. package/dist/worker/observe/static/views/dag.d.ts +13 -0
  217. package/dist/worker/observe/static/views/dag.js +14 -5
  218. package/dist/worker/observe/static/views/dashboard.js +6 -4
  219. package/dist/worker/observe/static/views/failures.js +5 -2
  220. package/dist/worker/observe/static/views/night.js +2 -2
  221. package/dist/worker/observe/static/views/pool.js +1 -0
  222. package/dist/worker/observe/static/views/run.js +3 -1
  223. package/dist/worker/observe/static/views/session-timeline.js +78 -9
  224. package/dist/worker/observe/static/views/task.js +56 -1
  225. package/dist/workflows/dag/backend-test-case-coverage-analysis.js +49 -3
  226. package/dist/workflows/dag/backend-test-markdown-workflow.js +176 -1
  227. package/dist/workflows/dag/backend-test-pytest-collection.js +98 -14
  228. package/dist/workflows/dag/backend-test-writer-completeness.js +10 -5
  229. package/dist/workflows/dag/contract-output-registry.js +15 -0
  230. package/dist/workflows/dag/contract-validator-registrations.js +1 -2
  231. package/dist/workflows/dag/dynamic-runtime/loop-until.js +1 -1
  232. package/dist/workflows/dag/dynamic-runtime/map.js +1 -1
  233. package/dist/workflows/dag/failure-category.js +7 -116
  234. package/dist/workflows/dag/frontend-closeout.js +221 -0
  235. package/dist/workflows/dag/frontend-design-policy.js +400 -0
  236. package/dist/workflows/dag/frontend-human-decision.js +182 -0
  237. package/dist/workflows/dag/frontend-implementation-contract.js +534 -178
  238. package/dist/workflows/dag/frontend-plan-render.js +24 -0
  239. package/dist/workflows/dag/frontend-prewrite-gate.js +371 -393
  240. package/dist/workflows/dag/frontend-provider-capability-matrix.js +159 -0
  241. package/dist/workflows/dag/frontend-recovery-capsule.js +455 -0
  242. package/dist/workflows/dag/frontend-recovery-controller.js +202 -0
  243. package/dist/workflows/dag/frontend-recovery-lineage.js +178 -0
  244. package/dist/workflows/dag/frontend-recovery-plan.js +17 -10
  245. package/dist/workflows/dag/frontend-recovery-run.js +33 -20
  246. package/dist/workflows/dag/frontend-repair.js +7 -424
  247. package/dist/workflows/dag/frontend-review-context.js +288 -14
  248. package/dist/workflows/dag/frontend-review-findings.js +270 -0
  249. package/dist/workflows/dag/frontend-risk.js +15 -2
  250. package/dist/workflows/dag/frontend-shadow-dual-write.js +814 -0
  251. package/dist/workflows/dag/frontend-shape-capsule-store.js +191 -0
  252. package/dist/workflows/dag/frontend-shape-facts.js +409 -0
  253. package/dist/workflows/dag/frontend-shape.js +427 -0
  254. package/dist/workflows/dag/frontend-source-fidelity-ledger.js +108 -0
  255. package/dist/workflows/dag/frontend-split-application-service.js +203 -0
  256. package/dist/workflows/dag/frontend-split-orchestrator.js +899 -0
  257. package/dist/workflows/dag/frontend-test-case-checklist.js +30 -4
  258. package/dist/workflows/dag/frontend-test-case-manifest.js +11 -4
  259. package/dist/workflows/dag/frontend-test-case-quality.js +11 -16
  260. package/dist/workflows/dag/frontend-test-environment-probe.js +230 -0
  261. package/dist/workflows/dag/frontend-test-html-report.js +3 -1
  262. package/dist/workflows/dag/frontend-test-l5-report.js +3 -1
  263. package/dist/workflows/dag/frontend-test-layout.js +159 -0
  264. package/dist/workflows/dag/frontend-test-markdown.js +61 -0
  265. package/dist/workflows/dag/frontend-test-result-contract.js +188 -42
  266. package/dist/workflows/dag/frontend-test-standard-scenarios.js +70 -0
  267. package/dist/workflows/dag/frontend-typed-event-store.js +452 -0
  268. package/dist/workflows/dag/frontend-typed-event-transaction.js +180 -0
  269. package/dist/workflows/dag/frontend-verification-trace.js +52 -17
  270. package/dist/workflows/dag/frontend-worktree-diff.js +250 -17
  271. package/dist/workflows/dag/frontend-writer-admission.js +272 -0
  272. package/dist/workflows/dag/frontend-writer-status.js +244 -0
  273. package/dist/workflows/dag/init-hybrid.js +984 -618
  274. package/dist/workflows/dag/interrupt-request.js +10 -3
  275. package/dist/workflows/dag/lifecycle.js +3 -3
  276. package/dist/workflows/dag/node-execution.js +468 -34
  277. package/dist/workflows/dag/prompt.js +44 -19
  278. package/dist/workflows/dag/recovery-lease.js +80 -0
  279. package/dist/workflows/dag/report.js +37 -1
  280. package/dist/workflows/dag/rerun-feedback.js +124 -1
  281. package/dist/workflows/dag/rerun-plan.js +144 -5
  282. package/dist/workflows/dag/rerun-run.js +81 -6
  283. package/dist/workflows/dag/rerun-task.js +29 -0
  284. package/dist/workflows/dag/retry-policy.js +318 -8
  285. package/dist/workflows/dag/runner.js +429 -122
  286. package/dist/workflows/dag/scheduler.js +114 -16
  287. package/dist/workflows/dag/structured-output-repair.js +712 -0
  288. package/dist/workflows/dag/types.js +321 -31
  289. package/dist/workflows/dag/upstream-artifacts.js +0 -4
  290. package/dist/workflows/dag/validate.js +92 -32
  291. package/docs/README.md +2 -0
  292. package/docs/architecture/evolution.md +45 -0
  293. package/docs/init-surface.manifest.json +9 -0
  294. package/docs/operations/README.md +1 -1
  295. package/docs/operations/local-development-environment.md +21 -0
  296. package/docs/templates/README.md +2 -1
  297. package/docs/templates/agent-dag-report.schema.json +8 -2
  298. package/docs/templates/agent-dag.schema.json +45 -1
  299. package/docs/templates/frontend-implementation-contract.schema.json +684 -24
  300. package/docs/templates/frontend-test-case-checklist.md +2 -2
  301. package/docs/templates/frontend-test-dag.json +8 -10
  302. package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +1 -1
  303. package/docs/templates/init-managed-agents.md +13 -3
  304. package/docs/templates/spec-registry.schema.json +45 -0
  305. package/harness.json +3 -3
  306. package/package.json +7 -1
  307. package/scripts/next-info.mjs +356 -0
  308. package/scripts/next-publish-gate.mjs +238 -0
  309. package/scripts/release-source-binding.mjs +251 -0
  310. package/skills/codebase-scout/SKILL.md +1 -1
  311. package/skills/fe-test-ui-scout/SKILL.md +65 -0
  312. package/skills/fe-test-ui-scout/references/ledger-schema.md +62 -0
  313. package/skills/fe-test-ui-scout/references/recon-protocol.md +54 -0
  314. package/skills/frontend-bounded-implement/SKILL.md +8 -14
  315. package/skills/frontend-design-review/SKILL.md +20 -41
  316. package/skills/frontend-implementation/SKILL.md +3 -4
  317. package/skills/frontend-implementation/references/design-spec.md +15 -10
  318. package/skills/frontend-implementation/references/node-contracts.md +23 -13
  319. package/skills/frontend-review/SKILL.md +22 -14
  320. package/skills/frontend-review/references/review-findings.md +6 -7
  321. package/skills/loop-agent/references/command-reference.md +12 -4
  322. package/skills/loop-agent/references/hybrid-dag.md +8 -1
  323. package/skills/playwright-cli/SKILL.md +23 -1
  324. package/skills/playwright-cli-case-generator/SKILL.md +29 -8
  325. package/dist/worker/console/static/assets/channel-CPF4N7pf.js +0 -1
  326. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C2DwA_Y1.js +0 -1
  327. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C2DwA_Y1.js +0 -1
  328. package/dist/worker/console/static/assets/index-DTZOKgAn.js +0 -404
  329. package/dist/worker/console/static/assets/index-Ya5FE7cD.css +0 -1
  330. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-B8FB_cNk.js +0 -1
  331. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CrZYaWfx.js +0 -8
@@ -0,0 +1,337 @@
1
+ export function resolveRouteWorkspaceSelection(workspaceId, knownWorkspaceIds) {
2
+ const id = workspaceId?.trim();
3
+ if (!id)
4
+ return { status: "ok", workspaceId: undefined };
5
+ if (knownWorkspaceIds.includes(id))
6
+ return { status: "ok", workspaceId: id };
7
+ return { status: "unknown-workspace", workspaceId: id };
8
+ }
9
+ export const OPERATE_TAB_IDS = [
10
+ "tasks",
11
+ "recovery",
12
+ "night",
13
+ "models",
14
+ "settings",
15
+ ];
16
+ export const LAST_OPERATE_TAB_STORAGE_KEY = "loop-console.operator-shell.last-operate-tab.v1";
17
+ export const LAST_INSPECT_HASH_STORAGE_KEY = "loop-console.operator-shell.last-inspect-hash.v1";
18
+ export const DEFAULT_OPERATE_TAB = "tasks";
19
+ export const CHAT_HREF = "/#/chat";
20
+ export const DEFAULT_INSPECT_HREF = "/#/inspect";
21
+ export const DEFAULT_OPERATE_HREF = "/#/operate/tasks";
22
+ const INSPECT_COLLECTION_OR_OBJECT = /^(dag|run|task|feature|batch|night|pool|failures|dags)(\/|$)/;
23
+ export function splitHash(hashValue) {
24
+ const raw = String(hashValue ?? "").replace(/^#/, "");
25
+ const qIndex = raw.indexOf("?");
26
+ const pathPart = qIndex >= 0 ? raw.slice(0, qIndex) : raw;
27
+ const path = pathPart
28
+ ? pathPart.startsWith("/")
29
+ ? pathPart
30
+ : `/${pathPart}`
31
+ : "/";
32
+ const query = new URLSearchParams(qIndex >= 0 ? raw.slice(qIndex + 1) : "");
33
+ return { path, query };
34
+ }
35
+ export function stripInspectPrefix(path) {
36
+ if (path === "/inspect" || path === "/inspect/")
37
+ return "/";
38
+ if (path.startsWith("/inspect/"))
39
+ return path.slice("/inspect".length) || "/";
40
+ return path;
41
+ }
42
+ function isOperateTab(value) {
43
+ return (value === "tasks" ||
44
+ value === "recovery" ||
45
+ value === "night" ||
46
+ value === "models" ||
47
+ value === "settings");
48
+ }
49
+ function readParam(query, key) {
50
+ const value = query.get(key)?.trim();
51
+ return value || undefined;
52
+ }
53
+ function readWorkspaceParams(query) {
54
+ return {
55
+ ...(readParam(query, "taskId") ? { taskId: readParam(query, "taskId") } : {}),
56
+ ...(readParam(query, "dagRunId")
57
+ ? { dagRunId: readParam(query, "dagRunId") }
58
+ : {}),
59
+ ...(readParam(query, "fromNodeId")
60
+ ? { fromNodeId: readParam(query, "fromNodeId") }
61
+ : {}),
62
+ ...(readParam(query, "featureId")
63
+ ? { featureId: readParam(query, "featureId") }
64
+ : {}),
65
+ ...(readParam(query, "intent") ? { intent: readParam(query, "intent") } : {}),
66
+ ...(readParam(query, "workspaceId")
67
+ ? { workspaceId: readParam(query, "workspaceId") }
68
+ : {}),
69
+ ...(readParam(query, "sessionId")
70
+ ? { sessionId: readParam(query, "sessionId") }
71
+ : {}),
72
+ };
73
+ }
74
+ function paramsQuery(params) {
75
+ const query = new URLSearchParams();
76
+ for (const key of [
77
+ "taskId",
78
+ "dagRunId",
79
+ "fromNodeId",
80
+ "featureId",
81
+ "intent",
82
+ "workspaceId",
83
+ "sessionId",
84
+ ]) {
85
+ const value = params[key]?.trim();
86
+ if (value)
87
+ query.set(key, value);
88
+ }
89
+ return query.toString();
90
+ }
91
+ export function readLastOperateTab(storage) {
92
+ try {
93
+ const raw = storage?.getItem(LAST_OPERATE_TAB_STORAGE_KEY);
94
+ if (isOperateTab(raw))
95
+ return raw;
96
+ }
97
+ catch {
98
+ /* ignore */
99
+ }
100
+ return DEFAULT_OPERATE_TAB;
101
+ }
102
+ export function rememberOperateTab(tab, storage) {
103
+ try {
104
+ storage?.setItem(LAST_OPERATE_TAB_STORAGE_KEY, tab);
105
+ }
106
+ catch {
107
+ /* ignore */
108
+ }
109
+ }
110
+ export function readLastInspectHref(storage) {
111
+ try {
112
+ const raw = storage?.getItem(LAST_INSPECT_HASH_STORAGE_KEY)?.trim();
113
+ if (raw?.startsWith("/#/inspect"))
114
+ return raw;
115
+ }
116
+ catch {
117
+ /* ignore */
118
+ }
119
+ return DEFAULT_INSPECT_HREF;
120
+ }
121
+ export function rememberInspectHref(href, storage) {
122
+ const canonical = href.startsWith("/#/inspect")
123
+ ? href
124
+ : rewriteInspectHrefToCanonical(href);
125
+ if (!canonical.startsWith("/#/inspect"))
126
+ return;
127
+ try {
128
+ storage?.setItem(LAST_INSPECT_HASH_STORAGE_KEY, canonical);
129
+ }
130
+ catch {
131
+ /* ignore */
132
+ }
133
+ }
134
+ export function buildOperateHref(tab = DEFAULT_OPERATE_TAB, params = {}) {
135
+ const qs = paramsQuery(params);
136
+ return `/#/operate/${tab}${qs ? `?${qs}` : ""}`;
137
+ }
138
+ export function buildInspectHref(inspectPath = "/", query) {
139
+ const normalized = stripInspectPrefix(inspectPath.startsWith("/") ? inspectPath : `/${inspectPath}`);
140
+ const path = normalized === "/" || normalized === ""
141
+ ? "/inspect"
142
+ : `/inspect${normalized}`;
143
+ const qs = typeof query === "string"
144
+ ? query.replace(/^\?/, "")
145
+ : query?.toString() ?? "";
146
+ return `/#${path}${qs ? `?${qs}` : ""}`;
147
+ }
148
+ export function buildChatHref(params = {}) {
149
+ const qs = paramsQuery(params);
150
+ return qs ? `${CHAT_HREF}?${qs}` : CHAT_HREF;
151
+ }
152
+ /** Keep the selected Workspace on any canonical Console destination without
153
+ * changing its page-specific path or query state. */
154
+ export function withWorkspaceId(href, workspaceId) {
155
+ const canonical = href.startsWith("/#")
156
+ ? href
157
+ : href.startsWith("#")
158
+ ? `/${href}`
159
+ : rewriteInspectHrefToCanonical(href);
160
+ const { path, query } = splitHash(canonical.slice(2));
161
+ const id = workspaceId?.trim();
162
+ if (id)
163
+ query.set("workspaceId", id);
164
+ else
165
+ query.delete("workspaceId");
166
+ const qs = query.toString();
167
+ return `/#${path}${qs ? `?${qs}` : ""}`;
168
+ }
169
+ export function buildCanonicalHref(input) {
170
+ if (input.workspace === "chat")
171
+ return buildChatHref(input);
172
+ if (input.workspace === "operate") {
173
+ return buildOperateHref(input.operateTab ?? DEFAULT_OPERATE_TAB, input);
174
+ }
175
+ return buildInspectHref(input.inspectPath ?? "/", input.inspectQuery);
176
+ }
177
+ function finishInspect(inspectPath, query, replace) {
178
+ const qs = query.toString();
179
+ const canonicalHref = buildInspectHref(inspectPath, qs);
180
+ return {
181
+ workspace: "inspect",
182
+ operateTab: DEFAULT_OPERATE_TAB,
183
+ inspectPath: stripInspectPrefix(inspectPath),
184
+ canonicalHash: canonicalHref.slice(2),
185
+ canonicalHref,
186
+ replace,
187
+ ...readWorkspaceParams(query),
188
+ };
189
+ }
190
+ function finishOperate(tab, query, replace) {
191
+ const canonicalHref = buildOperateHref(tab, readWorkspaceParams(query));
192
+ return {
193
+ workspace: "operate",
194
+ operateTab: tab,
195
+ inspectPath: "/",
196
+ canonicalHash: canonicalHref.slice(2),
197
+ canonicalHref,
198
+ replace,
199
+ ...readWorkspaceParams(query),
200
+ };
201
+ }
202
+ function finishChat(replace, params) {
203
+ const effective = params ?? {};
204
+ const canonicalHref = buildChatHref(effective);
205
+ return {
206
+ workspace: "chat",
207
+ operateTab: DEFAULT_OPERATE_TAB,
208
+ inspectPath: "/",
209
+ canonicalHash: canonicalHref.slice(2),
210
+ canonicalHref,
211
+ replace,
212
+ ...effective,
213
+ };
214
+ }
215
+ export function parseWorkspaceRoute(location, options = {}) {
216
+ const pathname = String(location.pathname ?? "/").replace(/\/+$/, "") || "/";
217
+ const lastTab = options.lastOperateTab ?? DEFAULT_OPERATE_TAB;
218
+ if (pathname === "/inspect") {
219
+ const { path, query } = splitHash(location.hash ?? "#/");
220
+ return finishInspect(path, query, true);
221
+ }
222
+ const { path, query } = splitHash(location.hash ?? "");
223
+ if (!location.hash || path === "/")
224
+ return null;
225
+ if (path === "/inspect" || path.startsWith("/inspect/")) {
226
+ return finishInspect(stripInspectPrefix(path), query, false);
227
+ }
228
+ if (path === "/chat")
229
+ return finishChat(false, readWorkspaceParams(query));
230
+ if (path === "/operate") {
231
+ return finishOperate(lastTab, query, true);
232
+ }
233
+ if (path.startsWith("/operate/")) {
234
+ const tab = path.slice("/operate/".length).split("/")[0] ?? "";
235
+ if (isOperateTab(tab))
236
+ return finishOperate(tab, query, false);
237
+ return finishOperate(lastTab, query, true);
238
+ }
239
+ if (isOperateTab(path.replace(/^\//, "").split("/")[0] ?? "")) {
240
+ const tab = path.replace(/^\//, "").split("/")[0];
241
+ return finishOperate(tab, query, true);
242
+ }
243
+ const inspectInternal = stripInspectPrefix(path).replace(/^\//, "");
244
+ if (INSPECT_COLLECTION_OR_OBJECT.test(inspectInternal)) {
245
+ return finishInspect(path, query, true);
246
+ }
247
+ return null;
248
+ }
249
+ export function rewriteInspectHrefToCanonical(href, base = typeof globalThis.location?.href === "string"
250
+ ? globalThis.location.href
251
+ : "http://local.invalid/") {
252
+ const raw = String(href ?? "").trim();
253
+ if (!raw)
254
+ return DEFAULT_INSPECT_HREF;
255
+ if (raw.startsWith("/#/inspect"))
256
+ return raw;
257
+ if (raw.startsWith("#/inspect"))
258
+ return `/${raw}`;
259
+ if (raw.startsWith("/#/operate") || raw.startsWith("/#/chat"))
260
+ return raw;
261
+ if (raw.startsWith("#/operate") || raw.startsWith("#/chat"))
262
+ return `/${raw}`;
263
+ try {
264
+ const url = new URL(raw, base);
265
+ const pathname = url.pathname.replace(/\/+$/, "") || "/";
266
+ if (pathname === "/inspect") {
267
+ const { path, query } = splitHash(url.hash || "#/");
268
+ const merged = new URLSearchParams(url.search);
269
+ for (const [key, value] of query)
270
+ merged.set(key, value);
271
+ return buildInspectHref(path, merged);
272
+ }
273
+ const { path, query } = splitHash(url.hash || "");
274
+ if (path === "/inspect" || path.startsWith("/inspect/")) {
275
+ return buildInspectHref(stripInspectPrefix(path), query);
276
+ }
277
+ const internal = path.replace(/^\//, "");
278
+ if (INSPECT_COLLECTION_OR_OBJECT.test(internal)) {
279
+ return buildInspectHref(path, query);
280
+ }
281
+ }
282
+ catch {
283
+ /* fall through */
284
+ }
285
+ if (raw.startsWith("#/") && INSPECT_COLLECTION_OR_OBJECT.test(raw.slice(2))) {
286
+ return buildInspectHref(raw.slice(1));
287
+ }
288
+ return DEFAULT_INSPECT_HREF;
289
+ }
290
+ export function isInspectDocumentHref(href, base = typeof globalThis.location?.href === "string"
291
+ ? globalThis.location.href
292
+ : "http://local.invalid/") {
293
+ try {
294
+ const url = new URL(String(href ?? ""), base);
295
+ const pathname = url.pathname.replace(/\/+$/, "") || "/";
296
+ if (pathname !== "/inspect")
297
+ return false;
298
+ return !/\.[a-z0-9]+$/i.test(url.pathname);
299
+ }
300
+ catch {
301
+ return false;
302
+ }
303
+ }
304
+ export function hrefToLocationHash(href) {
305
+ const canonical = href.startsWith("/#")
306
+ ? href
307
+ : href.startsWith("#")
308
+ ? `/${href}`
309
+ : rewriteInspectHrefToCanonical(href);
310
+ return canonical.startsWith("/#") ? canonical.slice(1) : canonical;
311
+ }
312
+ export function applyCanonicalHref(href) {
313
+ const hash = hrefToLocationHash(href);
314
+ if (typeof window === "undefined")
315
+ return hash;
316
+ const current = window.location.hash || "";
317
+ const normalizedCurrent = current.startsWith("#") ? current : `#${current}`;
318
+ const normalizedNext = hash.startsWith("#") ? hash : `#${hash}`;
319
+ if (normalizedCurrent !== normalizedNext) {
320
+ window.location.hash = normalizedNext;
321
+ }
322
+ return normalizedNext;
323
+ }
324
+ export function shouldCanonicalizeInspectDocument(location) {
325
+ const pathname = String(location.pathname ?? "/").replace(/\/+$/, "") || "/";
326
+ return pathname === "/inspect";
327
+ }
328
+ export function canonicalConsoleInspectHref(location) {
329
+ const { path, query } = splitHash(location.hash ?? "#/");
330
+ return buildInspectHref(path, query);
331
+ }
332
+ export function inspectInternalHash(hashValue) {
333
+ const { path, query } = splitHash(hashValue);
334
+ const internal = stripInspectPrefix(path);
335
+ const qs = query.toString();
336
+ return `${internal}${qs ? `?${qs}` : ""}`;
337
+ }
@@ -0,0 +1,344 @@
1
+ /**
2
+ * Repo-scoped Workspace Context (2026-08-22 multi-workspace foundation, W1).
3
+ *
4
+ * One lazily-created ConsoleContext per workspaceId. Each context INDEPENDENTLY
5
+ * owns the full operator runtime for its repo root: fingerprint-isolated
6
+ * appData (via openConsoleAppData), operation/event stores, draft /
7
+ * confirmation / receipt / interview / assessment stores, Chat session store +
8
+ * events + deferred Turn registry + ConsolePiRuntime(cwd=repoRoot),
9
+ * OperatorActionContext, Observe route context, and readiness.
10
+ *
11
+ * Invariants:
12
+ * - Selecting (viewing) another workspace NEVER disposes a context; running
13
+ * Turns / Operations / DAGs continue in the background.
14
+ * - dispose() is invoked exactly once per context by the owning server's
15
+ * close().
16
+ * - bootToken is shared per Console boot: it binds the startup fingerprint
17
+ * and bind host, and its confirmationToken signs human-gate tokens for all
18
+ * workspaces in this process (single Console security domain).
19
+ */
20
+ import { randomBytes } from "node:crypto";
21
+ import { existsSync } from "node:fs";
22
+ import { rm } from "node:fs/promises";
23
+ import path from "node:path";
24
+ import { LoopAgentClient } from "../loop-agent/loop-agent-client.js";
25
+ import { openConsoleAppData, sha256Json, writeSecureJson, } from "./app-data.js";
26
+ import { DagConfirmationStore } from "./dag-confirmation.js";
27
+ import { DagExecutionReceiptStore } from "./dag-execution-receipt.js";
28
+ import { DraftStore } from "./draft-store.js";
29
+ import { AssessmentStore } from "./interview/assessment.js";
30
+ import { InterviewSessionStore } from "./interview/session.js";
31
+ import { ChatSessionStore } from "./chat/session-store.js";
32
+ import { createChatEventStore, createChatOperationLinker, } from "./chat/chat-event-store.js";
33
+ import { createChatTurnExecutionRegistry } from "./chat/turn-execution-registry.js";
34
+ import { ConsolePiRuntime } from "./chat/pi-runtime.js";
35
+ import { UserQuestionRegistry } from "./chat/user-questions.js";
36
+ import { TodoListRegistry } from "./chat/todos.js";
37
+ import { createOperationEventStore, } from "./operation-sse.js";
38
+ import { OperationStore } from "./operation-store.js";
39
+ import { createFrontendSplitOperationAdapter, } from "./frontend-split-operation-adapter.js";
40
+ import { createFrontendHumanDecisionAdapter } from "./frontend-human-decision-adapter.js";
41
+ import { FrontendSplitTaskMaterializer, } from "../materialize/frontend-split-task-materializer.js";
42
+ import { probePiReadiness, } from "./pi-readiness.js";
43
+ import { resolveSiblingLoopAgentBin } from "./sibling-controller.js";
44
+ import { NightAuxTicker } from "./night-aux-ticker.js";
45
+ import { createObserveRouteContext, } from "../observe/routes.js";
46
+ import { WorkspaceRegistry } from "./workspace-registry.js";
47
+ import { resolveConsoleDefaultTimeoutMs } from "./server.js";
48
+ /**
49
+ * Lazily create the full repo-scoped Console context for a registered
50
+ * workspace record. Pure factory — no global registry; the caller owns
51
+ * lifecycle (single creation per workspaceId, dispose on server close).
52
+ */
53
+ export async function createWorkspaceContext(record, deps) {
54
+ const repoRoot = record.repoRoot;
55
+ const appData = openConsoleAppData({
56
+ repoRoot,
57
+ ...(deps.appDataRoot ? { appDataRoot: deps.appDataRoot } : {}),
58
+ });
59
+ const registry = new WorkspaceRegistry(appData);
60
+ const readiness = await probePiReadiness({
61
+ override: deps.piReadinessProbe,
62
+ repoRoot,
63
+ });
64
+ let readinessCache = readiness;
65
+ const artifactRoot = path.join(appData.root, "client-artifacts", appData.fingerprint);
66
+ const client = deps.createClient?.(artifactRoot) ??
67
+ new LoopAgentClient({
68
+ loopAgentBin: resolveSiblingLoopAgentBin(),
69
+ artifactRoot,
70
+ resolveIdentity: true,
71
+ defaultTimeoutMs: resolveConsoleDefaultTimeoutMs(deps.defaultTimeoutMs),
72
+ });
73
+ const operations = new OperationStore(appData);
74
+ const events = createOperationEventStore({
75
+ persistenceDir: path.join(appData.operations, "events"),
76
+ });
77
+ // Frontend split runtime is repo-scoped: materialization, durable schedule
78
+ // intents, and aggregate closeout must use this workspace's app-data and
79
+ // OperationStore rather than the process startup workspace.
80
+ const splitScheduleDir = path.join(appData.root, "frontend-split-schedule");
81
+ const splitAuditDir = path.join(appData.root, "frontend-split-audit");
82
+ const splitAggregateDir = path.join(appData.root, "frontend-split-aggregate");
83
+ const splitMaterializationBackend = {
84
+ async ensureTask({ taskId }) {
85
+ return { taskId, complete: true };
86
+ },
87
+ async ensureOperation({ taskId, operationId, payloadDigest, request }) {
88
+ const action = request.kind === "child"
89
+ ? "frontendSplitChild"
90
+ : "frontendSplitIntegration";
91
+ const { operation } = await operations.ensureSplitMaterializedOperation({
92
+ operationId,
93
+ taskId,
94
+ action,
95
+ actionParams: request,
96
+ payloadHash: payloadDigest,
97
+ });
98
+ return {
99
+ taskId: operation.taskId ?? taskId,
100
+ operationId: operation.operationId,
101
+ complete: true,
102
+ };
103
+ },
104
+ };
105
+ const materializer = new FrontendSplitTaskMaterializer(splitMaterializationBackend);
106
+ const schedule = async (input) => {
107
+ const fact = {
108
+ schemaVersion: 1,
109
+ kind: "frontend-split-schedule-intent",
110
+ operationId: input.operationId,
111
+ generation: input.generation,
112
+ bindingDigest: input.bindingDigest,
113
+ recordedAt: new Date().toISOString(),
114
+ };
115
+ const name = `${sha256Json({
116
+ operationId: input.operationId,
117
+ generation: input.generation,
118
+ bindingDigest: input.bindingDigest,
119
+ })}.json`;
120
+ await writeSecureJson(path.join(splitScheduleDir, name), fact);
121
+ };
122
+ const auditStale = async (input) => {
123
+ const fact = {
124
+ schemaVersion: 1,
125
+ kind: "frontend-split-stale-audit",
126
+ operationId: input.operationId,
127
+ reason: input.reason,
128
+ fact: input.fact,
129
+ recordedAt: new Date().toISOString(),
130
+ };
131
+ await writeSecureJson(path.join(splitAuditDir, `${sha256Json(fact)}.json`), fact);
132
+ };
133
+ const prepareAggregate = async ({ operationId, aggregate, }) => {
134
+ const before = await operations.get(operationId);
135
+ if (!before) {
136
+ throw new Error(`cannot prepare aggregate: parent operation not found: ${operationId}`);
137
+ }
138
+ const aggregateFile = path.join(splitAggregateDir, `${aggregate.digest}.json`);
139
+ let parentRecordPath = "";
140
+ let wroteAggregate = false;
141
+ let wroteParent = false;
142
+ return {
143
+ committedRef: {
144
+ ref: aggregateFile,
145
+ digest: aggregate.digest,
146
+ commitState: "committed",
147
+ },
148
+ async commit(input) {
149
+ parentRecordPath = input.parentRecordPath;
150
+ await writeSecureJson(aggregateFile, {
151
+ schemaVersion: 1,
152
+ kind: "frontend-split-aggregate-closeout",
153
+ operationId,
154
+ aggregate,
155
+ });
156
+ wroteAggregate = true;
157
+ await writeSecureJson(input.parentRecordPath, input.parentRecord);
158
+ wroteParent = true;
159
+ },
160
+ async rollback() {
161
+ if (wroteAggregate)
162
+ await rm(aggregateFile, { force: true });
163
+ if (wroteParent && parentRecordPath) {
164
+ await writeSecureJson(parentRecordPath, before);
165
+ }
166
+ },
167
+ };
168
+ };
169
+ const splitOrchestrator = createFrontendSplitOperationAdapter({
170
+ store: operations,
171
+ materializer,
172
+ schedule,
173
+ auditStale,
174
+ prepareAggregate,
175
+ });
176
+ const humanDecisionAdapter = createFrontendHumanDecisionAdapter(operations);
177
+ const drafts = new DraftStore(appData);
178
+ const confirmations = new DagConfirmationStore(appData, deps.bootToken.confirmationToken);
179
+ const dagExecutionReceipts = new DagExecutionReceiptStore(appData);
180
+ const interviews = new InterviewSessionStore(appData);
181
+ const assessments = new AssessmentStore(appData);
182
+ if (!deps.skipReconcile) {
183
+ await operations.reconcileOnBoot();
184
+ }
185
+ const getReadiness = () => readinessCache;
186
+ const refreshReadiness = async () => {
187
+ readinessCache = await probePiReadiness({
188
+ override: deps.piReadinessProbe,
189
+ repoRoot,
190
+ });
191
+ actionContext.readiness = readinessCache;
192
+ return readinessCache;
193
+ };
194
+ const actionContext = {
195
+ repoRoot,
196
+ appData,
197
+ operatorSessionId: deps.operatorSessionId,
198
+ client,
199
+ operations,
200
+ events,
201
+ splitOrchestrator,
202
+ humanDecisionAdapter,
203
+ materializer,
204
+ drafts,
205
+ confirmations,
206
+ dagExecutionReceipts,
207
+ humanGateSecret: deps.bootToken.confirmationToken,
208
+ interviews,
209
+ assessments,
210
+ readiness: readinessCache,
211
+ getReadiness,
212
+ refreshReadiness,
213
+ observeBaseUrl: deps.observeBaseUrl,
214
+ fetchImpl: deps.fetchImpl,
215
+ getConsoleOrigin: deps.getConsoleOrigin,
216
+ };
217
+ const chatStore = new ChatSessionStore(appData);
218
+ const chatEventEpoch = randomBytes(12).toString("hex");
219
+ const chatEvents = createChatEventStore({
220
+ appData,
221
+ epoch: chatEventEpoch,
222
+ });
223
+ const chatTurnExecutions = createChatTurnExecutionRegistry();
224
+ const questionRegistry = new UserQuestionRegistry(path.join(appData.chats, "user-questions"));
225
+ const todoRegistry = new TodoListRegistry();
226
+ questionRegistry.subscribe((change) => {
227
+ const question = change.question;
228
+ chatEvents.append(question.sessionId, question.turnId ?? `${question.sessionId}:question`, {
229
+ kind: `question_${change.type}`,
230
+ data: { question },
231
+ });
232
+ });
233
+ todoRegistry.subscribe((change) => {
234
+ chatEvents.append(change.sessionId, change.turnId ?? `${change.sessionId}:todo`, {
235
+ kind: change.type === "updated" ? "todo_updated" : "todo_cleared",
236
+ data: {
237
+ todos: change.todos,
238
+ ...(change.toolCallId ? { toolCallId: change.toolCallId } : {}),
239
+ },
240
+ });
241
+ });
242
+ const chatOperationLinker = createChatOperationLinker({
243
+ chatEvents,
244
+ operations,
245
+ operationEvents: events,
246
+ });
247
+ const chatRuntime = new ConsolePiRuntime({
248
+ cwd: repoRoot,
249
+ sessionDir: appData.chatSessions,
250
+ resourcePreferencesPath: appData.resourcePreferences,
251
+ actionContext,
252
+ questionRegistry,
253
+ todoRegistry,
254
+ });
255
+ const chatRouteDeps = {
256
+ runtime: chatRuntime,
257
+ store: chatStore,
258
+ events: chatEvents,
259
+ turnExecutions: chatTurnExecutions,
260
+ questionRegistry,
261
+ todoRegistry,
262
+ operationLinker: chatOperationLinker,
263
+ appData,
264
+ bootToken: deps.bootToken,
265
+ getConsoleOrigin: deps.getConsoleOrigin,
266
+ allowNonLoopbackAccess: deps.allowNonLoopbackAccess,
267
+ };
268
+ const { recoverDeferredTurns } = await import("./chat/routes.js");
269
+ const nightAuxTicker = new NightAuxTicker({ repoRoot, client });
270
+ const observeRouteContext = createObserveRouteContext(repoRoot, {
271
+ staticDir: deps.inspectStaticDir,
272
+ });
273
+ let disposed = false;
274
+ const context = {
275
+ workspaceId: record.workspaceId,
276
+ record,
277
+ repoRoot,
278
+ appData,
279
+ registry,
280
+ client,
281
+ operations,
282
+ events,
283
+ splitOrchestrator,
284
+ humanDecisionAdapter,
285
+ materializer,
286
+ drafts,
287
+ confirmations,
288
+ dagExecutionReceipts,
289
+ interviews,
290
+ assessments,
291
+ chatRouteDeps,
292
+ chatOperationLinker,
293
+ chatRuntime,
294
+ nightAuxTicker,
295
+ actionContext,
296
+ observeRouteContext,
297
+ getReadiness,
298
+ refreshReadiness,
299
+ recoverDeferredTurns: () => recoverDeferredTurns(chatRouteDeps),
300
+ dispose: () => {
301
+ if (disposed)
302
+ return;
303
+ disposed = true;
304
+ try {
305
+ chatOperationLinker.dispose();
306
+ }
307
+ catch {
308
+ // best-effort
309
+ }
310
+ try {
311
+ chatRuntime.disposeAll();
312
+ }
313
+ catch {
314
+ // best-effort
315
+ }
316
+ try {
317
+ nightAuxTicker.dispose();
318
+ }
319
+ catch {
320
+ // best-effort
321
+ }
322
+ },
323
+ };
324
+ return context;
325
+ }
326
+ /** Inspect-facing readiness/capability summary for a registry record. */
327
+ export async function summarizeWorkspaceRecord(record, deps) {
328
+ let state;
329
+ try {
330
+ const report = await probePiReadiness({
331
+ override: deps.piReadinessProbe,
332
+ repoRoot: record.repoRoot,
333
+ });
334
+ state = report.state;
335
+ }
336
+ catch {
337
+ state = "setup-required";
338
+ }
339
+ return {
340
+ state,
341
+ summary: `pi=${state}; inspect=${deps.inspectReady ? "ready" : "unavailable"}`,
342
+ };
343
+ }
344
+ void existsSync;