@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
package/README.md CHANGED
@@ -47,12 +47,14 @@ npm install -g @tea-agent/loop-agent@0.37.5 # 精确、可复现
47
47
 
48
48
  ```bash
49
49
  loop-agent init instructions --repo-root .
50
- loop-agent init --repo-root . --profile full --merge
50
+ loop-agent init model-catalog --repo-root . --json
51
+ loop-agent init --repo-root . --profile full --merge \
52
+ --low-model <provider/model> --med-model <provider/model> --high-model <provider/model>
51
53
  loop-agent init doctor --repo-root .
52
54
  loop-agent inspect --repo-root .
53
55
  ```
54
56
 
55
- 初始化会保留已有用户内容,并补充 `AGENTS.md`、`harness.json`、`ai_workspace/loop-agent/`、`.agents/skills/`、`.harness/` 和验证脚本等治理入口。
57
+ `init model-catalog` 会通过 Pi runtime 与 OpenCode 的非 verbose 列表发现本机可用模型,只输出白名单模型元数据、Pi setup 状态和 provider 凭据就绪状态,不输出原始配置或凭据。已有 LOW/MED/HIGH 只要仍存在于 Pi 就保持不变;只有已移除或缺失的档位才由模型结合项目、能力、成本和上下文窗口重选。如果 Pi 没有模型定义,初始化模型会先向用户补齐 provider/model、API/base URL、上下文窗口、最大输出等无法推断的信息并协助配置;如果只是凭据缺失,则保留 harness 选择并修复认证。初始化会保留已有用户内容,并补充 `AGENTS.md`、`harness.json`、`ai_workspace/loop-agent/`、`.agents/skills/`、`.harness/` 和验证脚本等治理入口。
56
58
 
57
59
  控制器升级后,旧项目可能仍使用过期的 repo-local skills、模板、managed blocks 和治理说明。普通安全仓库命令结束时会自动检测目标项目是否需要对齐:非 TTY 只向 stderr 输出提示且不写入目标;TTY 且无 human decisions、无活跃 DAG/Worker 时,可经明确 `y/yes` 同意后应用 deterministic safe actions;也可手动运行统一入口:
58
60
 
@@ -66,11 +68,11 @@ loop-agent init reconcile --repo-root .
66
68
 
67
69
  ```bash
68
70
  loop-agent init upgrade --repo-root . --json
69
- # controller 返回单文件 merge task 后:
71
+ # controller 返回当前单文件 merge task 后(其余任务已在同一次计划中排队):
70
72
  loop-agent init upgrade --repo-root . --run-id <run-id> --continue --json
71
73
  ```
72
74
 
73
- 它在 `.harness/init-upgrades/<run-id>/` 保存身份、扫描、动作收据、合并任务、验证与报告;`--status` / `--report` 只读。默认管理项目 `.opencode/plugins/`、`.pi/extensions/` 和 `.pi/settings.json`,不会默认写 `~/.pi/agent/settings.json`。旧项目首次执行后需 reload 宿主会话,以加载更新后的 AGENTS、skills 与 recovery 产物。明确「检查初始化更新」「只检查,不要修改」仍只运行 `init check-update`。
75
+ 它在 `.harness/init-upgrades/<run-id>/` 保存身份、一次性模型目录与 surface 计划、动作收据、合并队列、验证与报告。固定投影文件按 recorded ownership 确定性新增、更新或安全删除;用户改过的文件和项目自适应内容才进入模型合并。多个合并仍逐文件限制 `allowedPaths`,但接受后直接激活下一项,不重复版本发现和全量规划;全部处理完只执行一次最终验证。`harness.json` 按属性结构新增/删除字段并保留项目值,同时同步 schema。已完成的 `--status` / `--report` 只读取控制器哈希锚定的证据,不重新执行项目脚本。默认管理项目 `.opencode/plugins/`、`.pi/extensions/` 和 `.pi/settings.json`,不会默认写 `~/.pi/agent/settings.json`。旧项目首次执行后需 reload 宿主会话。明确「检查初始化更新」「只检查,不要修改」仍只运行 `init check-update`。
74
76
 
75
77
  完整说明见[初始化目标项目](website/docs/quick-start/init-target-project.md)。
76
78
 
@@ -114,7 +116,7 @@ loop-agent dag report --run-id <run-id>
114
116
  | --- | --- | --- |
115
117
  | 受治理 CLI | `loop-agent …` / `agent-worker …` | 权威写入与诊断 |
116
118
  | Loop Operator Console | `agent-worker console` | Official 本地控制面(默认 repo=当前目录、`127.0.0.1:8790`,含 Operate 与 Inspect) |
117
- | Inspect(只读) | `agent-worker console` → `/inspect/`;`observe snapshot` | 统一 Console 内只读检视;`observe serve` 已下线(REMOVED / exit 2) |
119
+ | Inspect(只读) | `agent-worker console` → `/inspect/`;`observe snapshot` | 统一 Console 内只读检视;`observe serve` 已下线(REMOVED / exit 2)。实验例外:节点 inspector 默认显示失败节点「提示词重启」tab;紧急回退可设置 `HARNESS_DAG_RERUN_PROMPT_OVERRIDE=0`(也接受 `false` / `off`),关闭后不注入任何 mutation token |
118
120
 
119
121
  ```bash
120
122
  # 终端 A:Console(任务/运行操作面;canonical mutation 只经 sibling loop-agent)
@@ -124,6 +126,8 @@ agent-worker console doctor --repo .
124
126
 
125
127
  ```
126
128
 
129
+ 裸 `agent-worker console` 不在终端询问升级。Operate 右上角提供非阻塞的更新入口,默认选择 npm `latest` 稳定版,也可由操作者显式选择 `next` 预发布版;更新前会先检查活跃运行和全局安装来源。`console doctor`、帮助和版本命令均不触发更新检查。
130
+
127
131
  访问 Console <http://127.0.0.1:8790/>;**Operator Chat Official** 是 Console 内的主引导交互,默认打开「对话」工作区。构建时设置 `VITE_OPERATOR_CHAT_DEFAULT_LANDING=tasks` 可改回 Tasks;URL hash(`#/tasks`)与 localStorage 仍优先于默认值。顶部「检视」以及 `/inspect/` 提供只读 Dashboard、DAG、时间线与 artifacts;`loop-agent …` / `agent-worker …` CLI direct path 仍是受治理 fallback。当前状态为 **code ready, dogfood pending/unmet**,不宣称已替代 openCode 或其他外部主会话。
128
132
 
129
133
  ## 核心边界
package/bin/loop-agent.js CHANGED
@@ -18,11 +18,15 @@ if (!existsSync(cliEntry)) {
18
18
  * to silently execute a dist/ that predates the latest source edit. The
19
19
  * classic failure mode is editing src/** and running the bin without
20
20
  * `npm run build`, which executes the previous build. Suppress with
21
- * --ignore-stale-dist when intentionally running a stale build.
21
+ * --ignore-stale-dist (or LOOP_AGENT_IGNORE_STALE_DIST=1, which sibling
22
+ * processes such as a Console-spawned CLI inherit automatically) when
23
+ * intentionally running a stale build.
22
24
  */
23
25
  const srcDir = join(packageRoot, "src");
24
- const ignoreStale = process.argv.includes("--ignore-stale-dist");
25
- if (ignoreStale) {
26
+ const ignoreStale =
27
+ process.argv.includes("--ignore-stale-dist") ||
28
+ process.env.LOOP_AGENT_IGNORE_STALE_DIST === "1";
29
+ if (process.argv.includes("--ignore-stale-dist")) {
26
30
  process.argv = process.argv.filter((arg) => arg !== "--ignore-stale-dist");
27
31
  }
28
32
  if (!ignoreStale && existsSync(srcDir)) {
@@ -3,6 +3,7 @@ import path from "node:path";
3
3
  import { createTask, getTaskPaths, loadTaskConfig, } from "../../task/runtime.js";
4
4
  import { importPrdDocument } from "../../task/source-references.js";
5
5
  import { prepareTaskSource } from "../../task/source-prepare/index.js";
6
+ import { resolveProductionSourceFidelityPi } from "../../task/source-prepare/source-fidelity-pi.js";
6
7
  import { isIntakeSoftGapCode, resolvePrdImportRole, } from "../../task/source-prepare/artifact-meta.js";
7
8
  import { sanitizeDraftPlaceholders } from "../../task/source-prepare/placeholder-paths.js";
8
9
  import { evaluateSemanticIntakeEligibility, isSemanticIntakeDisabled, readSemanticIntakeAttempted, runSemanticIntake, } from "../../task/source-prepare/semantic-intake.js";
@@ -585,6 +586,15 @@ export async function advanceTaskLifecycle(input) {
585
586
  continue;
586
587
  }
587
588
  if (action.type === "prepare-contract") {
589
+ // 生产 source fidelity Pi 接线(AC-PROD-001/005):仅 frontend-implementation
590
+ // 任务注入 reconcile executor + 独立 reviewer;ineligible 返回 undefined 不接线。
591
+ // 主路径与 semantic-intake retry 路径共用同一接线,保证任意一条生产路径都实际
592
+ // 触发 reconciliation executor(修复前两处均缺省导致生产路径从不调用 Pi)。
593
+ const sourceFidelity = await resolveProductionSourceFidelityPi({
594
+ repoRoot: input.repoRoot,
595
+ taskId: input.taskId,
596
+ taskKind: input.taskKind,
597
+ });
588
598
  let draftIntent = null;
589
599
  if (input.fromDraftPath) {
590
600
  try {
@@ -635,6 +645,7 @@ export async function advanceTaskLifecycle(input) {
635
645
  verifyCommands: effectiveInput.verifyCommands,
636
646
  backendTest: input.backendTest,
637
647
  },
648
+ ...(sourceFidelity ? { sourceFidelity } : {}),
638
649
  });
639
650
  if (!prepareResult.ok) {
640
651
  const gapCodes = (prepareResult.gaps ?? [])
@@ -712,6 +723,7 @@ export async function advanceTaskLifecycle(input) {
712
723
  verifyCommands: effectiveInput.verifyCommands,
713
724
  backendTest: input.backendTest,
714
725
  },
726
+ ...(sourceFidelity ? { sourceFidelity } : {}),
715
727
  });
716
728
  if (retry.ok) {
717
729
  warnings.push({
@@ -42,6 +42,7 @@ export async function buildTaskLifecycleRecommendations(input) {
42
42
  const allowedPaths = [];
43
43
  const verifyCommands = [];
44
44
  // 1) managed task config
45
+ let hasDeclaredManagedVerify = false;
45
46
  try {
46
47
  const config = await loadTaskConfig(input.repoRoot, input.taskId);
47
48
  for (const glob of config.allowedPaths ?? []) {
@@ -53,7 +54,9 @@ export async function buildTaskLifecycleRecommendations(input) {
53
54
  source: "managed-task-config",
54
55
  });
55
56
  }
56
- for (const cmd of config.verifyCommands ?? []) {
57
+ const managedVerify = (config.verifyCommands ?? []).filter((cmd) => Boolean(cmd.command?.trim()));
58
+ hasDeclaredManagedVerify = managedVerify.length > 0;
59
+ for (const cmd of managedVerify) {
57
60
  const label = cmd.label?.trim() || "verify";
58
61
  const command = cmd.command?.trim();
59
62
  if (!command)
@@ -70,14 +73,22 @@ export async function buildTaskLifecycleRecommendations(input) {
70
73
  // task may not exist yet
71
74
  }
72
75
  // 2) package.json scripts (only if not already covered by managed config)
76
+ // The full-suite `test` script is recommended only when the task declares
77
+ // NO managed verifyCommands at all. Once a task configures a targeted
78
+ // verify set (e.g. per-change typecheck + a scoped vitest run), the full
79
+ // `npm run test` must never be auto-added: it validates the whole repo,
80
+ // costs far more than the change under review, and can fail on unrelated
81
+ // pre-existing breakage, turning a targeted verify green into a hard fail.
73
82
  const scripts = await readPackageScripts(input.repoRoot);
74
83
  const hasVerifyLabel = (label) => verifyCommands.some((entry) => entry.label === label);
75
84
  const scriptCandidates = [
76
85
  { label: "typecheck", script: "typecheck" },
77
- { label: "test", script: "test" },
78
86
  { label: "check-repo", script: "check:repo" },
79
87
  { label: "check-repo", script: "check-repo" },
80
88
  ];
89
+ if (!hasDeclaredManagedVerify) {
90
+ scriptCandidates.push({ label: "test", script: "test" });
91
+ }
81
92
  for (const candidate of scriptCandidates) {
82
93
  const scriptBody = scripts[candidate.script];
83
94
  if (!scriptBody)
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "0.39.0-beta.0",
4
- "gitSha": "cf0cf7e8e996da8d1c727ccc7cb8f4c52f8d5319",
5
- "builtAt": "2026-08-21T03:47:18.913Z"
3
+ "version": "0.39.0-beta.10",
4
+ "gitSha": "f6ea22730a28e6556983394e41560c0d8d18a852",
5
+ "builtAt": "2026-08-27T07:03:53.753Z"
6
6
  }
@@ -7,6 +7,7 @@ import { runCoverageReport } from "../commands/coverage-report.js";
7
7
  import { runExamples } from "../commands/examples.js";
8
8
  import { runHandoffCheck } from "../commands/handoff-check.js";
9
9
  import { runInspect } from "../commands/inspect.js";
10
+ import { runInspectNext } from "../commands/inspect-next.js";
10
11
  import { runInstructions } from "../commands/instructions.js";
11
12
  import { runTaskAdvance } from "../commands/task-advance.js";
12
13
  import { runTaskStatus } from "../commands/task-status.js";
@@ -34,6 +35,7 @@ import { runDagReconcileTasks } from "../commands/dag-reconcile-tasks.js";
34
35
  import { runDagReconcileRun } from "../commands/dag-reconcile-run.js";
35
36
  import { runDagRequestInterrupt } from "../commands/dag-request-interrupt.js";
36
37
  import { runDagRerunTask } from "../commands/dag-rerun-task.js";
38
+ import { runDagFollowUp } from "../commands/dag-follow-up.js";
37
39
  import { runDagRerun } from "../commands/dag-rerun.js";
38
40
  import { runDagResume } from "../commands/dag-resume.js";
39
41
  import { runDagDecisionInspect, runDagDecisionValidate, } from "../workflows/dag/decision-envelope.js";
@@ -74,6 +76,7 @@ export function parseSummaryFlag(tokens) {
74
76
  const DOCS_SUBCOMMANDS = ["audit", "archive"];
75
77
  const INIT_SUBCOMMANDS = [
76
78
  "instructions",
79
+ "model-catalog",
77
80
  "doctor",
78
81
  "check-update",
79
82
  "update",
@@ -133,6 +136,7 @@ const DAG_SUBCOMMANDS = [
133
136
  "request-interrupt",
134
137
  "rerun",
135
138
  "rerun-task",
139
+ "follow-up",
136
140
  "reconcile-tasks",
137
141
  "final-verification",
138
142
  "decision",
@@ -162,10 +166,19 @@ export const COMMAND_DEFINITIONS = [
162
166
  name: "inspect",
163
167
  adapter: "required",
164
168
  tier: "operator",
165
- intent: "Inspect the target repo harness manifest.",
166
- usage: "inspect",
167
- handler: async ({ adapter, repoRoot }) => {
168
- await runInspect(adapter, repoRoot);
169
+ intent: "Inspect the target repo harness manifest, or report the current npm next binding.",
170
+ usage: "inspect | inspect next [--json]",
171
+ subcommands: ["next"],
172
+ handler: async ({ adapter, repoRoot, subcommand, rest }) => {
173
+ if (subcommand === "next") {
174
+ await runInspectNext(repoRoot, rest.filter((arg) => Boolean(arg)));
175
+ return;
176
+ }
177
+ if (subcommand === undefined || subcommand.startsWith("-")) {
178
+ await runInspect(adapter, repoRoot);
179
+ return;
180
+ }
181
+ throw new Error("usage: inspect | inspect next [--json]");
169
182
  },
170
183
  },
171
184
  {
@@ -205,7 +218,7 @@ export const COMMAND_DEFINITIONS = [
205
218
  adapter: "none",
206
219
  tier: "primary",
207
220
  intent: "Initialize a target repository with loop-agent harness capabilities.",
208
- usage: "init [instructions|doctor|check-update|update|reconcile|upgrade] [--profile full|minimal] [--merge] [--json|--markdown] [--bootstrap-surface|--apply-safe] [--client-recovery=auto|project|user|off] [--run-id <id> --status|--continue|--report]",
221
+ usage: "init [instructions|model-catalog|doctor|check-update|update|reconcile|upgrade] [--profile full|minimal] [--merge] [--model provider/model | --low-model provider/model --med-model provider/model --high-model provider/model] [--json|--markdown] [--bootstrap-surface|--apply-safe] [--client-recovery=auto|project|user|off] [--run-id <id> --status|--continue|--report]",
209
222
  subcommands: [...INIT_SUBCOMMANDS],
210
223
  handler: async ({ repoRoot, subcommand, rest }) => {
211
224
  await runInit(repoRoot, [subcommand, ...rest].filter(Boolean), { readRuntimeActivity: readInitRuntimeActivity });
@@ -566,6 +579,11 @@ export const COMMAND_DEFINITIONS = [
566
579
  await runDagRerunTask(repoRoot, rerunTaskArgs);
567
580
  return;
568
581
  }
582
+ if (subcommand === "follow-up") {
583
+ const followUpArgs = rest.filter((arg) => Boolean(arg));
584
+ await runDagFollowUp(repoRoot, followUpArgs);
585
+ return;
586
+ }
569
587
  if (subcommand === "reconcile-tasks") {
570
588
  const reconcileArgs = rest.filter((arg) => Boolean(arg));
571
589
  await runDagReconcileTasks(repoRoot, reconcileArgs);
@@ -13,6 +13,7 @@ import { runDagReconcileTasks } from "../commands/dag-reconcile-tasks.js";
13
13
  import { runDagReconcileRun } from "../commands/dag-reconcile-run.js";
14
14
  import { runDagRequestInterrupt } from "../commands/dag-request-interrupt.js";
15
15
  import { runDagRerunTask } from "../commands/dag-rerun-task.js";
16
+ import { runDagFollowUp } from "../commands/dag-follow-up.js";
16
17
  import { runDagRerun } from "../commands/dag-rerun.js";
17
18
  import { runDagReject } from "../commands/dag-reject.js";
18
19
  import { runDagCloseoutDraft, runDagReport } from "../commands/dag-report.js";
@@ -33,6 +34,7 @@ import { runHarvest } from "../commands/harvest.js";
33
34
  import { runInit } from "../commands/init.js";
34
35
  import { readInitRuntimeActivity } from "./update/runtime-activity.js";
35
36
  import { runInspect } from "../commands/inspect.js";
37
+ import { runInspectNext } from "../commands/inspect-next.js";
36
38
  import { runInstructions } from "../commands/instructions.js";
37
39
  import { runKnowledge } from "../commands/knowledge.js";
38
40
  import { runLoop } from "../commands/loop.js";
@@ -97,6 +99,9 @@ async function dispatchRegisteredCommand(commandObject, defaultRepoRoot, rawArgs
97
99
  [...rest, ...rawArgs].some((token) => token === "--json")) ||
98
100
  (command === "stats" &&
99
101
  subcommand === "context" &&
102
+ [...rest, ...rawArgs].some((token) => token === "--json")) ||
103
+ (command === "inspect" &&
104
+ subcommand === "next" &&
100
105
  [...rest, ...rawArgs].some((token) => token === "--json"));
101
106
  const repoRoot = resolveRepoRootOnly(commandObject, defaultRepoRoot, {
102
107
  quiet,
@@ -125,8 +130,15 @@ async function runTaskCommand(repoRoot, subcommand, rest) {
125
130
  async function runCommanderAction(ctx, command, subcommand, rest) {
126
131
  switch (command) {
127
132
  case "inspect":
128
- await runInspect(ctx.adapter, ctx.repoRoot);
129
- return;
133
+ if (subcommand === "next") {
134
+ await runInspectNext(ctx.repoRoot, rest);
135
+ return;
136
+ }
137
+ if (subcommand === undefined || subcommand.startsWith("-")) {
138
+ await runInspect(ctx.adapter, ctx.repoRoot);
139
+ return;
140
+ }
141
+ throw new Error("usage: inspect | inspect next [--json]");
130
142
  case "doctor":
131
143
  await runDoctor(ctx.adapter, ctx.repoRoot, compactArgs([subcommand, ...rest]));
132
144
  return;
@@ -341,6 +353,9 @@ async function runDagAction(repoRoot, subcommand, rest) {
341
353
  case "rerun-task":
342
354
  await runDagRerunTask(repoRoot, args);
343
355
  return;
356
+ case "follow-up":
357
+ await runDagFollowUp(repoRoot, args);
358
+ return;
344
359
  case "reconcile-tasks":
345
360
  await runDagReconcileTasks(repoRoot, args);
346
361
  return;
@@ -500,6 +515,7 @@ function addDagCommand(program, defaultRepoRoot) {
500
515
  "request-interrupt",
501
516
  "rerun",
502
517
  "rerun-task",
518
+ "follow-up",
503
519
  "reconcile-tasks",
504
520
  "final-verification",
505
521
  ], defaultRepoRoot);
@@ -595,6 +611,9 @@ export function buildLoopAgentProgram(options) {
595
611
  .option("--no-merge", "skip existing files")
596
612
  .option("--provider <provider>", "provider paired with a bare --model (otherwise use provider/model)")
597
613
  .option("--model <model>", "qualified provider/model, or a bare model paired with --provider")
614
+ .option("--low-model <provider/model>", "credential-ready Pi model for LOW")
615
+ .option("--med-model <provider/model>", "credential-ready Pi model for MED")
616
+ .option("--high-model <provider/model>", "credential-ready Pi model for HIGH")
598
617
  .option("--json", "print JSON")
599
618
  .option("--markdown", "print Markdown")
600
619
  .option("--bootstrap-surface", "write an inferred .harness/init-surface.json baseline")
@@ -1,6 +1,6 @@
1
1
  import { createInterface } from "node:readline/promises";
2
2
  import { evaluateLatestVersion, shouldCheckForUpdates } from "./policy.js";
3
- import { acquireUpdateLock, readUpdateState, updateLockPath, updateStatePath, writeUpdateState, } from "./state.js";
3
+ import { acquireUpdateLock, readUpdateState, updateLockPath, updateStatePath, writeUpdateState, } from "../../shared/update/state.js";
4
4
  const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
5
5
  const FAILURE_COOLDOWN_MS = 10 * 60 * 1000;
6
6
  export async function runSelfUpdateNotifier(options) {
@@ -69,7 +69,7 @@ export async function runSelfUpdateNotifier(options) {
69
69
  }
70
70
  writeStderr(`loop-agent 已更新到 ${decision.targetVersion};新版本将在下一次调用时生效。\n`);
71
71
  await safeWriteState(statePath, {
72
- schemaVersion: 1,
72
+ ...state,
73
73
  lastCheckedAt: now().toISOString(),
74
74
  latestVersion: decision.targetVersion,
75
75
  });
@@ -1,29 +1 @@
1
- import { readdir } from "node:fs/promises";
2
- import path from "node:path";
3
- import { buildGlobalSnapshot } from "../../worker/observability/read-model.js";
4
- /**
5
- * Read-only runtime guard for init-surface writes.
6
- *
7
- * DAG activeness is anchored to real directories in the canonical active
8
- * lifecycle root. Worker activeness reuses the Observe read model so Task Pool
9
- * status precedence and composite identity stay owned by the Worker adapter.
10
- * Projection failures block writes because liveness cannot be proven safely.
11
- */
12
- export async function readInitRuntimeActivity(repoRoot) {
13
- const resolvedRoot = path.resolve(repoRoot);
14
- const activeDagRoot = path.join(resolvedRoot, ".harness", "dag-runs", "active");
15
- const entries = await readdir(activeDagRoot, { withFileTypes: true }).catch(() => []);
16
- const activeDagRunIds = entries
17
- .filter((entry) => entry.isDirectory() && entry.name !== ".gitkeep")
18
- .map((entry) => entry.name)
19
- .sort();
20
- const snapshot = await buildGlobalSnapshot({ repoRoot: resolvedRoot });
21
- return {
22
- activeDagRunIds,
23
- activeWorkerBatches: snapshot.health.worker.activeBatches,
24
- activeWorkerTasks: snapshot.health.worker.activeTasks,
25
- ...(snapshot.projectionError
26
- ? { workerProjectionError: snapshot.projectionError.message }
27
- : {}),
28
- };
29
- }
1
+ export { readInitRuntimeActivity } from "../../worker/observability/init-runtime-activity.js";
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import os from "node:os";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { buildLoopAgentProgram } from "./cli/program.js";
7
- import { createNpmUpdateClient } from "./cli/update/npm-client.js";
7
+ import { createNpmUpdateClient } from "./shared/update/npm-client.js";
8
8
  import { runSelfUpdateNotifier } from "./cli/update/notifier.js";
9
9
  import { resolveInitSurfaceRepoRoot, runInitSurfaceNotifier, } from "./cli/update/init-surface-notifier.js";
10
10
  async function main() {
@@ -29,6 +29,7 @@ async function main() {
29
29
  client: createNpmUpdateClient({
30
30
  currentVersion,
31
31
  packageRoot,
32
+ cwd: defaultRepoRoot,
32
33
  env: process.env,
33
34
  }),
34
35
  });
@@ -1356,12 +1356,15 @@ export async function runClientRecovery(input) {
1356
1356
  }
1357
1357
  const plugin = await installProjectOpenCodePlugin({
1358
1358
  repoRoot: input.repoRoot,
1359
+ onlyIfMissing: true,
1359
1360
  });
1360
1361
  const overflowPlugin = await installProjectOpenCodeOverflowCompactPlugin({
1361
1362
  repoRoot: input.repoRoot,
1363
+ onlyIfMissing: true,
1362
1364
  });
1363
1365
  const piExtension = await installProjectPiContextOverflowExtension({
1364
1366
  repoRoot: input.repoRoot,
1367
+ onlyIfMissing: true,
1365
1368
  });
1366
1369
  const pi = await applyProjectPiSettingsMerge({ repoRoot: input.repoRoot });
1367
1370
  if (mode !== "user") {
@@ -0,0 +1,138 @@
1
+ import { mkdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { FRONTEND_REVIEW_FINDINGS_PRD_REL, readFrontendReviewFindingsPrd, } from "../workflows/dag/frontend-review-findings.js";
4
+ import { locateDagRun } from "../workflows/dag/lifecycle.js";
5
+ import { createTask, getTaskPaths } from "../task/runtime.js";
6
+ import { importPrdDocument } from "../task/source-references.js";
7
+ function parseFlagValue(rawArgs, flag) {
8
+ const index = rawArgs.indexOf(flag);
9
+ if (index < 0 || index + 1 >= rawArgs.length)
10
+ return undefined;
11
+ return rawArgs[index + 1];
12
+ }
13
+ export function parseDagFollowUpArgs(rawArgs) {
14
+ const positional = rawArgs.filter((arg) => !arg.startsWith("-"));
15
+ const parentRunId = positional[0];
16
+ if (!parentRunId) {
17
+ throw new Error("usage: dag follow-up <parent-run-id> [--task-id <id>] [--execute] [--profile <profile>]");
18
+ }
19
+ return {
20
+ parentRunId,
21
+ taskId: parseFlagValue(rawArgs, "--task-id"),
22
+ execute: rawArgs.includes("--execute"),
23
+ profile: parseFlagValue(rawArgs, "--profile"),
24
+ };
25
+ }
26
+ export function deriveFollowUpTaskId(parentRunId) {
27
+ // Deterministic, valid task id derived from the parent run id.
28
+ return `${parentRunId}-followup`;
29
+ }
30
+ /** CLI entry: parse raw args and run the follow-up flow. */
31
+ export async function runDagFollowUp(repoRoot, rawArgs) {
32
+ const parsed = parseDagFollowUpArgs(rawArgs);
33
+ const result = await runDagFollowUpInternal(repoRoot, parsed.parentRunId, {
34
+ taskId: parsed.taskId,
35
+ execute: parsed.execute,
36
+ profile: parsed.profile,
37
+ });
38
+ console.log(JSON.stringify(result, null, 2));
39
+ if (!result.ok) {
40
+ process.exitCode = result.mode === "blocked" ? 2 : 1;
41
+ }
42
+ }
43
+ export async function runDagFollowUpInternal(repoRoot, parentRunId, options = {}) {
44
+ const located = await locateDagRun(repoRoot, parentRunId);
45
+ if (!located) {
46
+ return {
47
+ ok: false,
48
+ mode: "invalid",
49
+ reason: `dag run not found: ${parentRunId}`,
50
+ };
51
+ }
52
+ const prd = await readFrontendReviewFindingsPrd(located.runDir);
53
+ if (!prd) {
54
+ return {
55
+ ok: false,
56
+ mode: "invalid",
57
+ reason: `no frontend review findings PRD found in run ${parentRunId} (${FRONTEND_REVIEW_FINDINGS_PRD_REL}); the review must have committed request_review_changes`,
58
+ };
59
+ }
60
+ const taskId = options.taskId ?? deriveFollowUpTaskId(parentRunId);
61
+ try {
62
+ await createTask(repoRoot, taskId, `修复 review 发现(parent ${parentRunId})`);
63
+ }
64
+ catch (error) {
65
+ return {
66
+ ok: false,
67
+ mode: "blocked",
68
+ reason: `failed to create task ${taskId}: ${error instanceof Error ? error.message : String(error)}`,
69
+ };
70
+ }
71
+ // Materialize the PRD draft into the task's source directory so the task
72
+ // lifecycle can import it as its requirement.
73
+ const prdMaterialized = path.join(getTaskPaths(repoRoot, taskId).sourceDir, "review-findings-prd.md");
74
+ try {
75
+ await mkdir(path.dirname(prdMaterialized), { recursive: true });
76
+ await importPrdDocument({
77
+ repoRoot,
78
+ taskId,
79
+ filePath: path.join(located.runDir, FRONTEND_REVIEW_FINDINGS_PRD_REL),
80
+ name: "review-findings-prd",
81
+ });
82
+ }
83
+ catch (error) {
84
+ return {
85
+ ok: false,
86
+ mode: "blocked",
87
+ reason: `failed to import PRD into task ${taskId}: ${error instanceof Error ? error.message : String(error)}`,
88
+ };
89
+ }
90
+ if (!options.execute) {
91
+ return {
92
+ ok: true,
93
+ mode: "created",
94
+ taskId,
95
+ prdPath: prdMaterialized,
96
+ next: {
97
+ kind: "advance",
98
+ command: `loop-agent task advance ${taskId} --task-kind frontend-implementation --json`,
99
+ },
100
+ };
101
+ }
102
+ // Execute: advance through the frontend DAG.
103
+ const { advanceTaskLifecycle } = await import("../application/task-lifecycle/advance.js");
104
+ const profile = options.profile === "auto" ||
105
+ options.profile === "minimal" ||
106
+ options.profile === "standard" ||
107
+ options.profile === "reviewed" ||
108
+ options.profile === "supervised"
109
+ ? options.profile
110
+ : undefined;
111
+ const result = await advanceTaskLifecycle({
112
+ repoRoot,
113
+ taskId,
114
+ taskKind: "frontend-implementation",
115
+ taskKindExplicit: true,
116
+ ...(profile ? { profile, profileExplicit: true } : {}),
117
+ observer: undefined,
118
+ });
119
+ const ok = result.lifecycleState === "run-succeeded" ||
120
+ result.lifecycleState === "awaiting-write-set-approval";
121
+ return {
122
+ ok,
123
+ mode: ok ? "created" : "blocked",
124
+ taskId,
125
+ prdPath: prdMaterialized,
126
+ reason: ok
127
+ ? undefined
128
+ : `advance lifecycleState: ${result.lifecycleState}${result.blockers.length > 0
129
+ ? `; blockers: ${result.blockers.map((b) => b.code).join(", ")}`
130
+ : ""}`,
131
+ next: ok
132
+ ? undefined
133
+ : {
134
+ kind: "advance",
135
+ command: `loop-agent task advance ${taskId} --task-kind frontend-implementation --json`,
136
+ },
137
+ };
138
+ }
@@ -1,3 +1,5 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { isDagRerunPromptOverrideEnabled } from "../shared/dag-prompt-override.js";
1
3
  import { executeDagRerun, planDagRerun, } from "../workflows/dag/rerun-run.js";
2
4
  export function parseDagRerunArgs(args) {
3
5
  if (args.length === 0) {
@@ -9,6 +11,8 @@ export function parseDagRerunArgs(args) {
9
11
  let planHash;
10
12
  let requestId;
11
13
  let reason;
14
+ const promptOverrideSpecs = [];
15
+ const promptOverrideAppendSpecs = [];
12
16
  for (let index = 0; index < args.length; index += 1) {
13
17
  const arg = args[index];
14
18
  if (arg === "--run-id")
@@ -33,6 +37,14 @@ export function parseDagRerunArgs(args) {
33
37
  reason = args[++index];
34
38
  else if (arg.startsWith("--reason="))
35
39
  reason = arg.slice("--reason=".length);
40
+ else if (arg === "--prompt-override")
41
+ promptOverrideSpecs.push(args[++index] ?? "");
42
+ else if (arg.startsWith("--prompt-override="))
43
+ promptOverrideSpecs.push(arg.slice("--prompt-override=".length));
44
+ else if (arg === "--prompt-override-append")
45
+ promptOverrideAppendSpecs.push(args[++index] ?? "");
46
+ else if (arg.startsWith("--prompt-override-append="))
47
+ promptOverrideAppendSpecs.push(arg.slice("--prompt-override-append=".length));
36
48
  else if (arg === "--json")
37
49
  continue;
38
50
  else if (arg.startsWith("-"))
@@ -50,7 +62,13 @@ export function parseDagRerunArgs(args) {
50
62
  if (planHash || requestId || reason) {
51
63
  throw new Error("dag rerun --plan cannot be combined with execute flags");
52
64
  }
53
- return { parentRunId, selectedNodeId, planOnly: true };
65
+ return {
66
+ parentRunId,
67
+ selectedNodeId,
68
+ planOnly: true,
69
+ promptOverrideSpecs,
70
+ promptOverrideAppendSpecs,
71
+ };
54
72
  }
55
73
  if (!planHash?.trim()) {
56
74
  throw new Error("dag rerun execute requires --plan-hash <hash>");
@@ -68,15 +86,50 @@ export function parseDagRerunArgs(args) {
68
86
  planHash: planHash.trim(),
69
87
  requestId: requestId.trim(),
70
88
  reason: reason.trim(),
89
+ promptOverrideSpecs,
90
+ promptOverrideAppendSpecs,
71
91
  };
72
92
  }
93
+ async function loadPromptOverrides(specs, mode) {
94
+ const overrides = [];
95
+ for (const spec of specs) {
96
+ const separator = spec.indexOf("@");
97
+ if (separator <= 0 || separator >= spec.length - 1) {
98
+ throw new Error(`dag rerun --prompt-override${mode === "append" ? "-append" : ""} expects <nodeId>@<filePath>, got: ${spec}`);
99
+ }
100
+ const nodeId = spec.slice(0, separator);
101
+ const filePath = spec.slice(separator + 1);
102
+ let prompt;
103
+ try {
104
+ prompt = await readFile(filePath, "utf-8");
105
+ }
106
+ catch (error) {
107
+ throw new Error(`cannot read prompt override file for node ${nodeId} (${filePath}): ${error instanceof Error ? error.message : String(error)}`);
108
+ }
109
+ overrides.push(mode === "append" ? { nodeId, prompt, mode } : { nodeId, prompt });
110
+ }
111
+ return overrides;
112
+ }
73
113
  export async function runDagRerun(repoRoot, rawArgs) {
74
114
  const parsed = parseDagRerunArgs(rawArgs);
115
+ let promptOverrides;
116
+ const hasOverrides = parsed.promptOverrideSpecs.length > 0 ||
117
+ parsed.promptOverrideAppendSpecs.length > 0;
118
+ if (hasOverrides) {
119
+ if (!isDagRerunPromptOverrideEnabled()) {
120
+ throw new Error("prompt override rerun is disabled by HARNESS_DAG_RERUN_PROMPT_OVERRIDE; unset it or use a value other than 0, false, or off to enable this experimental capability");
121
+ }
122
+ promptOverrides = [
123
+ ...(await loadPromptOverrides(parsed.promptOverrideSpecs, "replace")),
124
+ ...(await loadPromptOverrides(parsed.promptOverrideAppendSpecs, "append")),
125
+ ];
126
+ }
75
127
  if (parsed.planOnly) {
76
128
  const plan = await planDagRerun({
77
129
  cwd: repoRoot,
78
130
  parentRunId: parsed.parentRunId,
79
131
  selectedNodeId: parsed.selectedNodeId,
132
+ promptOverrides,
80
133
  });
81
134
  const result = {
82
135
  ok: plan.eligible,
@@ -95,6 +148,7 @@ export async function runDagRerun(repoRoot, rawArgs) {
95
148
  planHash: parsed.planHash,
96
149
  requestId: parsed.requestId,
97
150
  reason: parsed.reason,
151
+ promptOverrides,
98
152
  });
99
153
  console.log(JSON.stringify(result, null, 2));
100
154
  if (!result.ok) {