@tea-agent/loop-agent 0.43.0-next.8 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +41 -2312
  3. package/README.md +7 -0
  4. package/dist/application/dag/args.js +8 -0
  5. package/dist/application/task-lifecycle/advance.js +38 -7
  6. package/dist/build-stamp.json +3 -3
  7. package/dist/cli/command-definitions.js +2 -0
  8. package/dist/cli/program.js +3 -1
  9. package/dist/cli/update/init-surface-notifier.js +2 -0
  10. package/dist/cli/update/policy.js +2 -0
  11. package/dist/commands/client-recovery.js +20 -55
  12. package/dist/commands/cursor-prompt.js +2 -0
  13. package/dist/commands/dag-approve.js +2 -0
  14. package/dist/commands/dag-final-verification.js +2 -0
  15. package/dist/commands/dag-init-hybrid.js +2 -0
  16. package/dist/commands/dag-reconcile-tasks.js +2 -0
  17. package/dist/commands/dag-reject.js +2 -0
  18. package/dist/commands/dag-report.js +2 -0
  19. package/dist/commands/dag-rerun.js +2 -0
  20. package/dist/commands/dag-resume.js +2 -0
  21. package/dist/commands/dag-workflow-compile.js +2 -0
  22. package/dist/commands/dag-workflow-plan.js +2 -0
  23. package/dist/commands/dag-workflow-validate.js +2 -0
  24. package/dist/commands/delegate.js +2 -0
  25. package/dist/commands/examples.js +2 -0
  26. package/dist/commands/import-prd.js +2 -0
  27. package/dist/commands/init-model-catalog.js +2 -0
  28. package/dist/commands/init.js +19 -13
  29. package/dist/commands/instructions.js +2 -0
  30. package/dist/commands/knowledge.js +2 -0
  31. package/dist/commands/loop-benchmark.js +2 -0
  32. package/dist/commands/pi-prompt.js +2 -0
  33. package/dist/commands/pi-reuse-benchmark.js +2 -0
  34. package/dist/commands/promote-run.js +2 -0
  35. package/dist/commands/stats.js +1 -1
  36. package/dist/commands/study-init.js +2 -0
  37. package/dist/commands/task-advance.js +34 -0
  38. package/dist/commands/task-source-prepare.js +2 -0
  39. package/dist/commands/worktree-create.js +2 -0
  40. package/dist/commands/worktree-remove.js +2 -0
  41. package/dist/executors/dag-pi-executor.js +1650 -198
  42. package/dist/executors/pi-executor.js +85 -3
  43. package/dist/executors/pi-sdk-executor.js +18 -0
  44. package/dist/executors/shell-executor.js +93 -7
  45. package/dist/executors/shell-verification.js +3 -0
  46. package/dist/executors/shell-write-guard.js +27 -32
  47. package/dist/governance/exec-plans.js +6 -3
  48. package/dist/infrastructure/console/app-data.js +6 -0
  49. package/dist/shared/artifacts-core.js +2 -0
  50. package/dist/shared/backend-dogfood-preflight.js +47 -0
  51. package/dist/shared/dag-failure-category.js +3 -0
  52. package/dist/shared/git-progress.js +2 -0
  53. package/dist/shared/one-shot-prompt-args.js +2 -0
  54. package/dist/shared/operator/capabilities.js +180 -0
  55. package/dist/shared/package-metadata.js +6 -4
  56. package/dist/shared/pi-context-pressure/extension.js +26 -16
  57. package/dist/shared/pi-context-pressure/sift-bridge.js +1 -1
  58. package/dist/shared/pi-provider-recovery.js +182 -0
  59. package/dist/shared/pi-retry-settings.js +40 -0
  60. package/dist/shared/reference-context.js +2 -0
  61. package/dist/task/config-types.js +29 -0
  62. package/dist/task/contract/project.js +9 -0
  63. package/dist/task/contract/recover.js +6 -0
  64. package/dist/task/contract/schema.js +17 -0
  65. package/dist/task/source-prepare/artifact-meta.js +9 -2
  66. package/dist/task/source-prepare/build-draft.js +60 -0
  67. package/dist/task/source-prepare/fragment-inventory.js +4 -1
  68. package/dist/task/source-prepare/parse-intent.js +36 -11
  69. package/dist/task/task-demand-routing.js +5 -2
  70. package/dist/worker/console/chat/browser-automation.js +523 -0
  71. package/dist/worker/console/chat/browser-policy.js +6 -36
  72. package/dist/worker/console/chat/browser-routes.js +188 -56
  73. package/dist/worker/console/chat/explore-tools.js +5 -2
  74. package/dist/worker/console/chat/pi-mode-loop-isolation.js +155 -0
  75. package/dist/worker/console/chat/pi-runtime/custom-tools/ask-user-question.js +44 -0
  76. package/dist/worker/console/chat/pi-runtime/custom-tools/browser-tools.js +184 -0
  77. package/dist/worker/console/chat/pi-runtime/custom-tools/explore-tools.js +202 -0
  78. package/dist/worker/console/chat/pi-runtime/custom-tools/goal-tools.js +79 -0
  79. package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +94 -0
  80. package/dist/worker/console/chat/pi-runtime/custom-tools/scheduled-goal-tools.js +22 -0
  81. package/dist/worker/console/chat/pi-runtime/custom-tools/todo-write.js +38 -0
  82. package/dist/worker/console/chat/pi-runtime/inspection-types.js +28 -0
  83. package/dist/worker/console/chat/pi-runtime/inspection.js +439 -0
  84. package/dist/worker/console/chat/pi-runtime/progressive-tools.js +195 -0
  85. package/dist/worker/console/chat/pi-runtime/sdk-bindings.js +153 -0
  86. package/dist/worker/console/chat/pi-runtime/sdk-session.js +5 -0
  87. package/dist/worker/console/chat/pi-runtime.js +208 -1138
  88. package/dist/worker/console/chat/routes.js +59 -24
  89. package/dist/worker/console/chat/scheduled-goal-booking.js +59 -0
  90. package/dist/worker/console/chat/scheduled-goal-delivery.js +27 -0
  91. package/dist/worker/console/chat/scheduled-goal-request.js +190 -0
  92. package/dist/worker/console/chat/sdd-data-alignment.js +1 -1
  93. package/dist/worker/console/chat/session-mode-view.js +5 -4
  94. package/dist/worker/console/chat/session-mode.js +18 -12
  95. package/dist/worker/console/chat/session-store.js +42 -9
  96. package/dist/worker/console/chat/terminal-sessions.js +65 -1
  97. package/dist/worker/console/chat/terminal-tools.js +17 -5
  98. package/dist/worker/console/chat/tool-preview.js +115 -0
  99. package/dist/worker/console/chat/tools.js +10 -0
  100. package/dist/worker/console/chat/turn-order.js +13 -0
  101. package/dist/worker/console/chat/turn-process.js +32 -30
  102. package/dist/worker/console/console-update-and-init.js +1 -19
  103. package/dist/worker/console/console-update-runtime.js +5 -20
  104. package/dist/worker/console/operator-actions.js +63 -1
  105. package/dist/worker/console/prd-intake-bridge.js +54 -1
  106. package/dist/worker/console/routes.js +8 -0
  107. package/dist/worker/console/scheduled-goal-host.js +98 -0
  108. package/dist/worker/console/scheduled-goal-operation-adapter.js +127 -0
  109. package/dist/worker/console/server.js +24 -1
  110. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-CwAxHSAM.js → abnfDiagram-N423BO3Z-8-j6y-sd.js} +1 -1
  111. package/dist/worker/console/static/assets/{arc-Bozf-oeF.js → arc-eoQiMvuk.js} +1 -1
  112. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-DEypbEQv.js → architectureDiagram-T3A2C74G-C4A3uMcI.js} +1 -1
  113. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-B1BQWCbE.js → blockDiagram-VBNYF7ZC-D4zD2F-Q.js} +1 -1
  114. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-B3u5-yZz.js → c4Diagram-5PPSVZJV-j1RkJziL.js} +1 -1
  115. package/dist/worker/console/static/assets/channel-ChE7y-cx.js +1 -0
  116. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-DSUc2NTh.js → chunk-2GRJ4B5K-YBHmhik1.js} +1 -1
  117. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DZouMIvT.js → chunk-2Q5K7J3B-COfWyo9P.js} +1 -1
  118. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-B3bhB5hh.js → chunk-5RXB4S5H-I99OUkHY.js} +1 -1
  119. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-CZFP_BOz.js → chunk-5VM5RSS4-XKxoJNJ4.js} +1 -1
  120. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DnE_wb-X.js → chunk-6Q2QTUOP-DLT_cYx1.js} +1 -1
  121. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-C2OfoiWm.js → chunk-GF5L2VYU-CxcKZ9mV.js} +1 -1
  122. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BKUTL8mm.js → chunk-JWPE2WC7-V1EqXdjY.js} +1 -1
  123. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-BT5oz0tg.js → chunk-KBJHAD2P-DebTtdFp.js} +1 -1
  124. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-D8vk-GJi.js → chunk-RYQCIY6F-B-ivNRDf.js} +1 -1
  125. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CkUIm3zu.js → chunk-XXDRQBXY-DC_Ds11b.js} +1 -1
  126. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C01TCf2X.js +1 -0
  127. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C01TCf2X.js +1 -0
  128. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CO9QNHmR.js → cose-bilkent-JH36ORCC-sWEqKwIb.js} +1 -1
  129. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-s52EPl2Z.js → cynefin-VYW2F7L2-BXa_dcu4.js} +1 -1
  130. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-BHaseJfW.js → cynefinDiagram-MW4NZA55-C-Mle84F.js} +1 -1
  131. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-CTVhRG_R.js → dagre-VZM6K2ZE-CXPDBITe.js} +1 -1
  132. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-B6pYeOMR.js → diagram-7IWD3JNH-CC-WJQfa.js} +1 -1
  133. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-CXXRzw5j.js → diagram-B4RE2ZJO-CDAV5Vs4.js} +1 -1
  134. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-BOeJHiLA.js → diagram-LBJQPF4R-CmFiAcNz.js} +1 -1
  135. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-DbEg6h_l.js → diagram-Q27KOJAE-DPBZHuyn.js} +1 -1
  136. package/dist/worker/console/static/assets/{diagram-UB23O5K3-CjlEcbX6.js → diagram-UB23O5K3-jUlm_Ds3.js} +1 -1
  137. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-BcqMPbD_.js → ebnfDiagram-BXEA7PRR-DWhQ3mfY.js} +1 -1
  138. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DWfRyHe5.js → erDiagram-JOGREHBK-Tr2gMqet.js} +1 -1
  139. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-Bz7TeIc8.js → flowDiagram-UKHOOZJN-DJjVQHPA.js} +1 -1
  140. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-BD-JxYjU.js → ganttDiagram-PKOTCBZU-D74dQ4u0.js} +1 -1
  141. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Cv16vMHK.js → gitGraphDiagram-DS77QQ5N-DwW0tZ0X.js} +1 -1
  142. package/dist/worker/console/static/assets/index-BWkIfcrK.css +1 -0
  143. package/dist/worker/console/static/assets/index-Cdkvw_H6.js +469 -0
  144. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-BlWO0HQQ.js → infoDiagram-6WML65LV-ILCbxJyb.js} +1 -1
  145. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-C4mbsn97.js → ishikawaDiagram-WSZJBQD7-DeuWBQ89.js} +1 -1
  146. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-CBPvVKjw.js → journeyDiagram-NVQOT4AX-CF5ih8Fk.js} +1 -1
  147. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-DPHLp54K.js → kanban-definition-27J2QSJJ-C7yOSuRO.js} +1 -1
  148. package/dist/worker/console/static/assets/{linear-CXx_9o6k.js → linear-BDZ9riWi.js} +1 -1
  149. package/dist/worker/console/static/assets/{mermaid.core-DU3IxMq9.js → mermaid.core-7pKqYtpZ.js} +5 -5
  150. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-COm4a2ud.js → mindmap-definition-FAOFIHXS-LeJDybSU.js} +1 -1
  151. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-Cbt7OA5d.js → pegDiagram-VL7TDLO6-BJvT3pMD.js} +1 -1
  152. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BiYV_4Wl.js → pieDiagram-7S7Q4E2Y-_rGqpMan.js} +1 -1
  153. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-lg2zhvbp.js → quadrantDiagram-CIZ2JOQS-DPcSv5aA.js} +1 -1
  154. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-cBLvtf0p.js → railroadDiagram-AXF67PYL-Drxx4hkJ.js} +1 -1
  155. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BoekU3Bg.js → requirementDiagram-LRYGKXZP-BCTUdU4z.js} +1 -1
  156. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-D_DMZYga.js → sankeyDiagram-W5VNT64P-B6wzbZmB.js} +1 -1
  157. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-Lzmzn8lz.js → sequenceDiagram-SI44F4Z6-BGt8d3QQ.js} +1 -1
  158. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-Cos3HpIe.js → sizeCapture-X5ZJPWSS-7nlhJKo7.js} +1 -1
  159. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-D-hFBGsx.js → stateDiagram-OKZ733FA-Cv2stqMA.js} +1 -1
  160. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DC7V5vcq.js +1 -0
  161. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-BY95sCVI.js → swimlanes-SLNWSIFB-qDAo4Yc1.js} +2 -2
  162. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Bwy4QUTO.js +8 -0
  163. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-D1iCgWHS.js → timeline-definition-Z64GVDOM-CKbDNKTr.js} +1 -1
  164. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-D9IYy4WK.js → vennDiagram-T6HMQDX7-DI-9EHic.js} +1 -1
  165. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-C9yJwO-R.js → wardleyDiagram-T6FBY63Y-BrzzRDpX.js} +1 -1
  166. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CC2llyou.js → xychartDiagram-ELKLHX3M-BclH5hGh.js} +1 -1
  167. package/dist/worker/console/static/index.html +2 -2
  168. package/dist/worker/console/static-src/operator-chat/active-turn-tail.js +10 -0
  169. package/dist/worker/console/static-src/operator-chat/chat-scroll-position.js +24 -0
  170. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +41 -11
  171. package/dist/worker/console/static-src/operator-chat/compaction-message.js +10 -17
  172. package/dist/worker/console/static-src/operator-chat/composer-session-ledger.js +192 -0
  173. package/dist/worker/console/static-src/operator-chat/pending-user-message.js +9 -1
  174. package/dist/worker/console/static-src/operator-chat/slash-palette-nav.js +15 -5
  175. package/dist/worker/console/static-src/operator-chat/timeline-merge.js +29 -0
  176. package/dist/worker/console/static-src/operator-chat/turn-process-disclosure.js +10 -0
  177. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +105 -44
  178. package/dist/worker/console/static-src/operator-chat/useChatStream.js +145 -70
  179. package/dist/worker/console/static-src/operator-chat/useChatThread.js +38 -57
  180. package/dist/worker/console/static-src/operator-chat/useComposer.js +195 -73
  181. package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +2 -0
  182. package/dist/worker/console/static-src/prd-file-import.js +3 -1
  183. package/dist/worker/console/workspace-context.js +22 -0
  184. package/dist/worker/console/workspace-initialization.js +209 -0
  185. package/dist/worker/delivery/git-transaction.js +2 -0
  186. package/dist/worker/feature/fullstack-validate.js +2 -0
  187. package/dist/worker/loop-agent/loop-agent-client.js +8 -2
  188. package/dist/worker/materialize/harness-task-materializer.js +4 -1
  189. package/dist/worker/metrics/projector.js +1 -1
  190. package/dist/worker/observability/event-store.js +4 -1
  191. package/dist/worker/observability/read-model.js +4 -1
  192. package/dist/worker/observe/node-transparency.js +23 -1
  193. package/dist/worker/observe/routes.js +4 -0
  194. package/dist/worker/observe/static/operator-chrome.js +3 -1
  195. package/dist/worker/observe/static/styles.css +7 -4
  196. package/dist/worker/observe/static/views/dag-inspector.js +5 -19
  197. package/dist/worker/outcomes/declared-artifacts.js +2 -0
  198. package/dist/worker/preflight.js +3 -0
  199. package/dist/worker/scheduler/scheduled-goal-dispatch.js +117 -0
  200. package/dist/worker/scheduler/scheduled-goal-evidence.js +167 -0
  201. package/dist/worker/scheduler/scheduled-goal-recovery.js +62 -0
  202. package/dist/worker/scheduler/scheduled-goal-store.js +699 -0
  203. package/dist/worker/scheduler/scheduled-goal-supervisor.js +132 -0
  204. package/dist/worker/scheduler/scheduled-goal-time.js +102 -0
  205. package/dist/worker/scheduler/scheduled-goal-types.js +95 -0
  206. package/dist/worker/task-spec/validate.js +4 -1
  207. package/dist/workflows/dag/backend-test-markdown-workflow.js +6 -24
  208. package/dist/workflows/dag/backend-test-plan-protocol.js +82 -5
  209. package/dist/workflows/dag/dag-retry-schema.js +11 -0
  210. package/dist/workflows/dag/decision-envelope.js +2 -0
  211. package/dist/workflows/dag/dynamic-runtime/shared.js +2 -2
  212. package/dist/workflows/dag/frontend-closeout.js +3 -1
  213. package/dist/workflows/dag/frontend-committed-facts.js +461 -0
  214. package/dist/workflows/dag/frontend-durable-tools.js +15 -3
  215. package/dist/workflows/dag/frontend-implementation-contract.js +369 -12
  216. package/dist/workflows/dag/frontend-plan-canary.js +53 -0
  217. package/dist/workflows/dag/frontend-plan-decision-contract.js +803 -0
  218. package/dist/workflows/dag/frontend-plan-render.js +0 -2
  219. package/dist/workflows/dag/frontend-provider-capability-matrix.js +8 -61
  220. package/dist/workflows/dag/frontend-recovery-run.js +57 -0
  221. package/dist/workflows/dag/frontend-repair.js +55 -76
  222. package/dist/workflows/dag/frontend-review-context.js +42 -68
  223. package/dist/workflows/dag/frontend-review-scopes.js +2 -2
  224. package/dist/workflows/dag/frontend-risk.js +92 -10
  225. package/dist/workflows/dag/frontend-session-budget.js +117 -3
  226. package/dist/workflows/dag/frontend-shape.js +11 -55
  227. package/dist/workflows/dag/frontend-test-execution-evidence.js +35 -10
  228. package/dist/workflows/dag/frontend-typed-event-store.js +32 -25
  229. package/dist/workflows/dag/frontend-verification-trace.js +33 -54
  230. package/dist/workflows/dag/frontend-writer-admission.js +3 -47
  231. package/dist/workflows/dag/frontend-writer-status.js +0 -23
  232. package/dist/workflows/dag/init-hybrid.js +47 -19
  233. package/dist/workflows/dag/interrupt-request.js +2 -0
  234. package/dist/workflows/dag/lifecycle.js +11 -2
  235. package/dist/workflows/dag/node-execution.js +50 -13
  236. package/dist/workflows/dag/reconcile-run.js +2 -0
  237. package/dist/workflows/dag/repair-artifact.js +3 -1
  238. package/dist/workflows/dag/report.js +2 -0
  239. package/dist/workflows/dag/rerun-plan.js +10 -0
  240. package/dist/workflows/dag/rerun-task.js +79 -1
  241. package/dist/workflows/dag/retry-policy.js +18 -0
  242. package/dist/workflows/dag/scheduler.js +2 -4
  243. package/dist/workflows/dag/types.js +44 -6
  244. package/dist/workflows/dag/validate.js +4 -0
  245. package/docs/README.md +1 -0
  246. package/docs/architecture/runtime-boundaries.md +3 -3
  247. package/docs/governance/README.md +1 -0
  248. package/docs/init-surface.manifest.json +1 -0
  249. package/docs/operations/README.md +2 -0
  250. package/docs/templates/README.md +1 -1
  251. package/docs/templates/agent-dag.schema.json +2 -2
  252. package/docs/templates/backend-test-dag.json +14 -10
  253. package/docs/templates/frontend-implementation-contract.schema.json +0 -7
  254. package/package.json +9 -3
  255. package/skills/frontend-bounded-implement/references/code-standards.md +3 -3
  256. package/skills/frontend-contract/references/contract-protocol.md +3 -1
  257. package/skills/frontend-plan/SKILL.md +8 -6
  258. package/skills/frontend-plan/references/decision-contract.md +3 -3
  259. package/skills/frontend-review/SKILL.md +18 -28
  260. package/skills/frontend-review/references/review-findings.md +8 -3
  261. package/dist/commands/new-task.js +0 -5
  262. package/dist/commands/status.js +0 -57
  263. package/dist/commands/task-contract.js +0 -269
  264. package/dist/shared/prompts.js +0 -26
  265. package/dist/task/config.js +0 -2
  266. package/dist/task/contract/validate-draft.js +0 -106
  267. package/dist/task/goal.js +0 -3
  268. package/dist/task/index.js +0 -12
  269. package/dist/task/lifecycle.js +0 -1
  270. package/dist/task/operator/capabilities.js +0 -6
  271. package/dist/task/operator/envelope.js +0 -2
  272. package/dist/task/operator/index.js +0 -5
  273. package/dist/task/operator/registry.js +0 -2
  274. package/dist/task/operator/types.js +0 -1
  275. package/dist/task/paths.js +0 -1
  276. package/dist/task/source-state.js +0 -1
  277. package/dist/task/subagent-guidance.js +0 -1
  278. package/dist/worker/console/chat/sift-bridge.js +0 -1
  279. package/dist/worker/console/index.js +0 -20
  280. package/dist/worker/console/static/assets/channel-JM-I_b0s.js +0 -1
  281. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DuQQAYEg.js +0 -1
  282. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DuQQAYEg.js +0 -1
  283. package/dist/worker/console/static/assets/index-B5H-giS2.js +0 -468
  284. package/dist/worker/console/static/assets/index-Bf7dxfm-.css +0 -1
  285. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-img0hVJ4.js +0 -1
  286. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-B4acZJvk.js +0 -8
  287. package/dist/worker/scheduler/index.js +0 -25
  288. package/dist/workflows/dag/facts.js +0 -4
  289. package/dist/workflows/dag/frontend-shadow-dual-write.js +0 -975
  290. package/dist/workflows/dag/index.js +0 -6
  291. package/dist/workflows/dynamic/index.js +0 -7
@@ -1023,7 +1023,74 @@ export function shouldRetryWithFallback(stderr, stdout) {
1023
1023
  stdout,
1024
1024
  timedOut: false,
1025
1025
  });
1026
- return ["quota", "rate-limit", "unavailable", "network"].includes(category);
1026
+ return [
1027
+ "quota",
1028
+ "rate-limit",
1029
+ "unavailable",
1030
+ "upstream-unavailable",
1031
+ "network",
1032
+ ].includes(category);
1033
+ }
1034
+ /**
1035
+ * Provider/transport failure text, with model-authored content excluded.
1036
+ *
1037
+ * The captured stdout is a JSONL session transcript: it carries assistant text,
1038
+ * tool arguments and saved findings verbatim. Matching provider vocabulary
1039
+ * against that whole stream let model content drive the verdict (smoke r28: the
1040
+ * reviewer's own finding id `FDR-R28-UNAUTHORIZED-APP-CSS` was read as an auth
1041
+ * failure, which is not retryable, so a completed review was reported as a node
1042
+ * error). Only error-shaped channels may classify a transport failure:
1043
+ * stderr, error events, and the error fields of a message record.
1044
+ */
1045
+ export function extractProviderFailureText(stdout) {
1046
+ const parts = [];
1047
+ for (const rawLine of stdout.split(/\r?\n/)) {
1048
+ const line = rawLine.trim();
1049
+ if (!line)
1050
+ continue;
1051
+ if (!line.startsWith("{")) {
1052
+ // Non-JSON child output (warnings, CLI errors) is not model-authored.
1053
+ parts.push(line);
1054
+ continue;
1055
+ }
1056
+ let record;
1057
+ try {
1058
+ const parsed = JSON.parse(line);
1059
+ if (!isRecord(parsed))
1060
+ continue;
1061
+ record = parsed;
1062
+ }
1063
+ catch {
1064
+ // An unparseable line may be truncated model content: skip it.
1065
+ continue;
1066
+ }
1067
+ const type = typeof record.type === "string" ? record.type : "";
1068
+ const isErrorEvent = type === "error" || type === "agent_error" || type.endsWith("_error");
1069
+ const errorMessage = typeof record.errorMessage === "string" ? record.errorMessage : "";
1070
+ const errorField = record.error;
1071
+ const message = isRecord(record.message) ? record.message : undefined;
1072
+ const messageErrorMessage = typeof message?.errorMessage === "string" ? message.errorMessage : "";
1073
+ const messageErrored = message?.stopReason === "error";
1074
+ if (!isErrorEvent &&
1075
+ !errorMessage &&
1076
+ errorField === undefined &&
1077
+ !messageErrorMessage) {
1078
+ continue;
1079
+ }
1080
+ parts.push([type, errorMessage, messageErrorMessage, messageErrored ? "stopReason error" : ""]
1081
+ .filter(Boolean)
1082
+ .join(" "));
1083
+ if (typeof errorField === "string") {
1084
+ parts.push(errorField);
1085
+ }
1086
+ else if (isRecord(errorField)) {
1087
+ parts.push(["message", "errorMessage", "reason", "code", "status", "type"]
1088
+ .map((key) => (errorField[key] === undefined ? "" : String(errorField[key])))
1089
+ .filter(Boolean)
1090
+ .join(" "));
1091
+ }
1092
+ }
1093
+ return parts.join("\n");
1027
1094
  }
1028
1095
  export function classifyPiFailure(input) {
1029
1096
  if (input.exitCode === 0 && input.assistantText.trim())
@@ -1034,7 +1101,9 @@ export function classifyPiFailure(input) {
1034
1101
  return "timeout";
1035
1102
  if (input.outputTooLarge)
1036
1103
  return "output-too-large";
1037
- const combined = `${input.stderr}\n${input.stdout}`.toLowerCase();
1104
+ // Provider/transport verdicts read error-shaped channels only; the raw stdout
1105
+ // stream embeds assistant text, tool arguments and findings verbatim.
1106
+ const combined = `${input.stderr}\n${extractProviderFailureText(input.stdout)}`.toLowerCase();
1038
1107
  // Context overflow (400 request-too-large / context window exceeded).
1039
1108
  // Must be detected BEFORE the generic rate-limit/quota phrases: an overflow
1040
1109
  // error often contains "too many tokens" / "maximum context" which would
@@ -1052,8 +1121,21 @@ export function classifyPiFailure(input) {
1052
1121
  return "rate-limit";
1053
1122
  if (/quota|usage limit|reached[^\n.]{0,60}limit|5\s*小时|5小时|insufficient_quota|billing/.test(combined))
1054
1123
  return "quota";
1055
- if (/\bunauthorized\b|\bhttp\s*40[13]\b|invalid api key|authentication (?:failed|required|error)|auth(?:entication)? failed/.test(combined))
1124
+ // Error words must stand alone: the captured stream also contains
1125
+ // model-authored identifiers, and smoke r28 lost a whole run because the
1126
+ // reviewer's own finding id `FDR-R28-UNAUTHORIZED-APP-CSS` matched a bare
1127
+ // `\bunauthorized\b`, turning a retryable empty-output into a terminal
1128
+ // `auth`. Identifier delimiters (`-`/`_`/alphanumerics) disqualify a match.
1129
+ if (/(?<![\w-])unauthorized(?![\w-])|\bhttp\s*40[13]\b|invalid api key|(?<![\w-])authentication (?:failed|required|error)(?![\w-])|(?<![\w-])auth(?:entication)? failed(?![\w-])/.test(combined))
1056
1130
  return "auth";
1131
+ // Gateway reachability first: a 502/503 body means the provider was
1132
+ // unreachable, not that the request lacked a capability. Reporting the
1133
+ // generic category here previously let an upstream outage surface as the
1134
+ // plan ladder's `unsupported-provider-capability`, which reads as a model
1135
+ // capability mismatch and sent the incident diagnosis in the wrong
1136
+ // direction (2026-09-11).
1137
+ if (/\bhttp\s*50[23]\b|(?:^|\D)50[23](?:\D|$)|service temporarily unavailable|bad gateway|upstream (?:is )?(?:unavailable|down|unreachable)|网关(?:暂时)?不可用/.test(combined))
1138
+ return "upstream-unavailable";
1057
1139
  if (/unknown provider|unknown model|(?:provider|model|service|gateway)\s+(?:is\s+)?unavailable|overloaded|at capacity|temporarily unavailable/.test(combined))
1058
1140
  return "unavailable";
1059
1141
  if (/network\s*(?:error|failure|issue|timeout|unreachable|reset|abort)|networkerror|connection (?:reset|error|refused|closed|timed\s*out)|request timed out|socket hang up|econn\w*|etimedout|fetch failed|dns (?:error|failure|lookup failed)/.test(combined))
@@ -322,6 +322,21 @@ async function createSdkSession(sdk, input, shared) {
322
322
  extensionToolExtras.push(...computeExtensionToolAllowlistExtras([{ name: SIFT_RETRIEVE_TOOL_NAME }], input.toolNames));
323
323
  }
324
324
  const sessionToolNames = [...input.toolNames, ...extensionToolExtras];
325
+ // Pre-session protocol self-check: createAgentSession silently drops a
326
+ // custom tool whose name is absent from this allowlist (the post-create
327
+ // mismatch check cannot see the omission either — expected and actual are
328
+ // both false). The model would then be prompted to call tools that do not
329
+ // exist and burn attempts discovering it (smoke r10/r14 class of failure),
330
+ // so fail before any model call, naming the dropped tools.
331
+ if (input.requireAllowlistedCustomTools && Array.isArray(input.customTools) && input.customTools.length > 0) {
332
+ const allowlist = new Set(sessionToolNames);
333
+ const dropped = input.customTools
334
+ .map((tool) => (isRecord(tool) && typeof tool.name === "string" ? tool.name : undefined))
335
+ .filter((name) => typeof name === "string" && !allowlist.has(name));
336
+ if (dropped.length > 0) {
337
+ throw new Error(`pi session custom tools would be silently dropped (absent from the activation allowlist): ${dropped.join(", ")}; allowlist: [${sessionToolNames.join(", ")}]`);
338
+ }
339
+ }
325
340
  if (input.requireWriterCustomTools) {
326
341
  if (!Array.isArray(input.customTools) || input.customTools.length === 0) {
327
342
  throw new Error("pi writer tool policy missing customTools; refusing to create uncontrolled writer session");
@@ -707,6 +722,9 @@ async function executeSingleSdkAttemptInternal(options) {
707
722
  ? { customTools: writerCustomTools }
708
723
  : {}),
709
724
  ...(requireWriterCustomTools ? { requireWriterCustomTools: true } : {}),
725
+ ...(options.writerToolPolicy?.requireAllowlistedCustomTools
726
+ ? { requireAllowlistedCustomTools: true }
727
+ : {}),
710
728
  ...(options.piExtensionPaths && options.piExtensionPaths.length > 0
711
729
  ? { additionalExtensionPaths: options.piExtensionPaths }
712
730
  : {}),
@@ -470,6 +470,54 @@ function parseCheckRepoSubcheckDurations(result) {
470
470
  }
471
471
  return durations;
472
472
  }
473
+ /**
474
+ * Frozen-command evidence for the review node: which commandId/label/lane each
475
+ * executed command belongs to, its exit status, and the lint lane's status
476
+ * (explicitly `not-configured` when the task declares no lint commands).
477
+ *
478
+ * The review protocol requires exit evidence ("typecheck, build, and test are
479
+ * required successful final exits") while the verification trace only proves
480
+ * command/file/target binding, so this artifact is what makes that requirement
481
+ * satisfiable at all (smoke r31: the reviewer had to request changes for a
482
+ * check no context could support).
483
+ */
484
+ export function buildFrontendVerificationEvidence(input) {
485
+ const directory = buildFrontendVerifyCommandDirectory({
486
+ staticLabels: input.bundle.staticEvidence?.commandLabels ?? [],
487
+ staticCommandTexts: input.bundle.staticEvidence?.commandTexts ?? [],
488
+ behaviorLabels: input.bundle.behaviorEvidence?.commandLabels ?? [],
489
+ behaviorCommandTexts: input.bundle.behaviorEvidence?.commandTexts ?? [],
490
+ mockLabels: input.bundle.mockEvidence?.commandLabels ?? [],
491
+ mockCommandTexts: input.bundle.mockEvidence?.commandTexts ?? [],
492
+ lintLabels: input.bundle.lintEvidence?.commandLabels ?? [],
493
+ lintCommandTexts: input.bundle.lintEvidence?.commandTexts ?? [],
494
+ });
495
+ const entryByCommand = new Map(directory.map((entry) => [entry.command.trim(), entry]));
496
+ return {
497
+ schemaVersion: 1,
498
+ schemaId: "frontend-verification-evidence-v1",
499
+ nodeId: input.nodeId,
500
+ runId: input.runId,
501
+ capturedAt: new Date().toISOString(),
502
+ allPassed: input.results.every((result) => result.ok),
503
+ lintStatus: input.lintStatus,
504
+ lintConfigured: input.lintConfigured,
505
+ commands: input.results.map((result, index) => {
506
+ const entry = entryByCommand.get(result.command.trim());
507
+ return {
508
+ index: index + 1,
509
+ commandId: entry?.commandId ?? null,
510
+ label: entry?.label ?? null,
511
+ lane: entry?.lane ?? null,
512
+ command: result.command,
513
+ ok: result.ok,
514
+ exitCode: result.exitCode,
515
+ failureCategory: result.failureCategory,
516
+ reused: result.reused === true,
517
+ };
518
+ }),
519
+ };
520
+ }
473
521
  export function buildShellResultSummaryMarkdown(input) {
474
522
  const lines = [
475
523
  "# Shell execution summary",
@@ -1915,7 +1963,7 @@ async function executePipelineCommands(input, meta, overrideCommands) {
1915
1963
  * of inventing refs. */
1916
1964
  async function deriveUnresolvedVerificationEntrypointRefs(runDir, frozenCommandIds) {
1917
1965
  try {
1918
- const { restorePlanPatchFromCommittedFacts } = await import("../workflows/dag/frontend-shadow-dual-write.js");
1966
+ const { restorePlanPatchFromCommittedFacts } = await import("../workflows/dag/frontend-implementation-contract.js");
1919
1967
  const records = await readTypedEventStoreFromJsonl(path.join(runDir, "frontend-plan-pi", "plan-typed-facts.jsonl"));
1920
1968
  const patch = restorePlanPatchFromCommittedFacts(records);
1921
1969
  const targets = patch
@@ -2127,6 +2175,27 @@ async function executeFrontendVerificationBundle(input, meta) {
2127
2175
  command: result.command,
2128
2176
  reused: result.reused === true,
2129
2177
  }));
2178
+ // Auditable per-command evidence for the review node (smoke r31): the review
2179
+ // protocol treats shell exit status as authoritative, but the review context
2180
+ // only carried the verification trace's command/file/target *binding*
2181
+ // status, so a reviewer could not confirm the frozen commands actually
2182
+ // exited 0 and had to request changes for missing evidence. Written before
2183
+ // either the failure or the success path returns.
2184
+ const lintConfigured = (bundle.lintCommands?.length ?? 0) > 0;
2185
+ await writeDagRunJsonArtifact(meta.runDir, "contracts/frontend-verification-evidence.json", buildFrontendVerificationEvidence({
2186
+ nodeId: input.task.id,
2187
+ runId: meta.runId,
2188
+ bundle,
2189
+ results,
2190
+ // The review protocol's lint vocabulary is
2191
+ // passed | baseline-debt | failed | unavailable; a task that declares
2192
+ // no lint commands reports `unavailable` plus lintConfigured:false
2193
+ // rather than inventing a value outside that catalog (smoke r33).
2194
+ lintStatus: lintConfigured
2195
+ ? (lintAssessment?.status ?? "unavailable")
2196
+ : "unavailable",
2197
+ lintConfigured,
2198
+ }));
2130
2199
  // Lint baseline-debt is tolerated, so a lint-only failure must not become the
2131
2200
  // verification failure. A shared lint/static or lint/behavior command is
2132
2201
  // different: once reused by a non-lint lane, its failure belongs to that lane
@@ -2320,16 +2389,22 @@ async function readRunDirJson(runDir, relativePath) {
2320
2389
  }
2321
2390
  /** Committed typed review terminal kinds from the review node's typed event
2322
2391
  * store (AC-003: typed terminal tools are the only authoritative verdict). */
2323
- async function collectReviewTerminalKinds(runDir, reviewNodeId) {
2392
+ export async function collectReviewTerminalKinds(runDir, reviewNodeId) {
2324
2393
  try {
2325
2394
  const records = await readTypedEventStoreFromJsonl(path.join(runDir, reviewNodeId, "review-typed-facts.jsonl"));
2395
+ // The store also holds findings and scope checkpoints; only the verdict
2396
+ // kinds decide "missing or ambiguous" (fail closed on 0 or 2+).
2397
+ const terminalKinds = new Set([
2398
+ "approve_review",
2399
+ "request_review_changes",
2400
+ ]);
2326
2401
  return records
2327
2402
  .filter((record) => record.phase === "committed")
2328
2403
  .map((record) => {
2329
2404
  const kind = record.fact.kind;
2330
2405
  return typeof kind === "string" ? kind : "";
2331
2406
  })
2332
- .filter(Boolean);
2407
+ .filter((kind) => terminalKinds.has(kind));
2333
2408
  }
2334
2409
  catch {
2335
2410
  return [];
@@ -2339,16 +2414,24 @@ async function collectReviewTerminalKinds(runDir, reviewNodeId) {
2339
2414
  * event store (M8: the committed approve_design / request_design_changes fact
2340
2415
  * is the only authoritative verdict; the legacy first-line VERDICT text is
2341
2416
  * never read for writer admission). Fail-closed on a missing/unreadable store. */
2342
- async function collectDesignTerminalKinds(runDir, designNodeId) {
2417
+ export async function collectDesignTerminalKinds(runDir, designNodeId) {
2343
2418
  try {
2344
2419
  const records = await readTypedEventStoreFromJsonl(path.join(runDir, designNodeId, "design-typed-facts.jsonl"));
2420
+ // The store also holds findings and scope checkpoints; only the verdict
2421
+ // kinds decide "missing or ambiguous" (fail closed on 0 or 2+). Without
2422
+ // this filter any recorded finding makes admission read the committed
2423
+ // verdict as ambiguous and blocks the writer (r11 decision-path smoke).
2424
+ const terminalKinds = new Set([
2425
+ "approve_design",
2426
+ "request_design_changes",
2427
+ ]);
2345
2428
  return records
2346
2429
  .filter((record) => record.phase === "committed")
2347
2430
  .map((record) => {
2348
2431
  const kind = record.fact.kind;
2349
2432
  return typeof kind === "string" ? kind : "";
2350
2433
  })
2351
- .filter(Boolean);
2434
+ .filter((kind) => terminalKinds.has(kind));
2352
2435
  }
2353
2436
  catch {
2354
2437
  return [];
@@ -2511,7 +2594,7 @@ async function executeFrontendDesignPolicy(input, meta) {
2511
2594
  // M9a the plan node's assistantText is a pure Markdown narrative; the
2512
2595
  // compile authority is the committed plan ledger ⊕ runtime skeleton.
2513
2596
  // Fail closed on missing committed facts — never fall back to text.
2514
- const { readCommittedOriginFacts, checkCommittedOriginFacts } = await import("../workflows/dag/frontend-shadow-dual-write.js");
2597
+ const { readCommittedOriginFacts, checkCommittedOriginFacts } = await import("../workflows/dag/frontend-committed-facts.js");
2515
2598
  // A+B (AC-001/003): fail-closed committed contract/scout typed facts.
2516
2599
  // Missing/uncommitted facts block here; never fall back to text parsing.
2517
2600
  const committedContractFacts = await readCommittedOriginFacts(meta.runDir, "frontend-contract-pi", "contract-typed-facts.jsonl");
@@ -2630,7 +2713,7 @@ async function executeFrontendDesignPolicy(input, meta) {
2630
2713
  });
2631
2714
  }
2632
2715
  // Byte freshness is necessary but not sufficient: require the same ledger
2633
- // semantic checks as the shadow prewrite gate before production writer
2716
+ // semantic checks as the canonical admission policy before production writer
2634
2717
  // admission can be materialized.
2635
2718
  if (meta.spec.sourceBinding) {
2636
2719
  const ledgerCheck = await checkFrontendSourceFidelityLedger({
@@ -2974,6 +3057,7 @@ async function executeFrontendCloseout(input, meta) {
2974
3057
  const contract = frontendImplementationContractSchema.parse(JSON.parse(contractRaw));
2975
3058
  const trace = context.verificationTrace;
2976
3059
  const verificationTargets = (trace?.targets ?? []).map((target) => ({
3060
+ mode: contract.verificationTargets.find((entry) => entry.id === target.id)?.mode ?? "static",
2977
3061
  status: target.status === "ok" ? "ok" : "failed",
2978
3062
  }));
2979
3063
  const mockEvidenceBound = contract.mockApi.strategy !== "not-needed" &&
@@ -3015,6 +3099,8 @@ async function executeFrontendCloseout(input, meta) {
3015
3099
  coverageMatrix: verificationTargets.map((target, index) => ({
3016
3100
  verificationTargetId: trace?.targets?.[index]?.id ?? `vt-${index}`,
3017
3101
  status: target.status === "ok" ? "passed" : "failed",
3102
+ evidence: trace?.targets?.[index]?.evidence ?? "unavailable",
3103
+ behaviorCoverage: "unconfirmed",
3018
3104
  })),
3019
3105
  lintStatus: "unavailable",
3020
3106
  integrationFacts,
@@ -138,6 +138,9 @@ export function renderVerifyReport(results) {
138
138
  export async function executeCommand(command, defaultTimeoutMs = DEFAULT_VERIFY_TIMEOUT_MS) {
139
139
  return new Promise((resolve, reject) => {
140
140
  const [binary, ...args] = command.args;
141
+ if (binary === undefined) {
142
+ throw new Error("verify command requires a non-empty args array");
143
+ }
141
144
  const timeoutMs = command.timeoutMs ?? defaultTimeoutMs;
142
145
  const startedAt = Date.now();
143
146
  const child = spawn(binary, args, {
@@ -94,48 +94,43 @@ const DAG_RUNS_PREFIX = ".harness/dag-runs/";
94
94
  * They are not product evidence and must not fail exclusive write guards.
95
95
  * Intentional report/product writes remain governed by writePolicy/writeSet.
96
96
  */
97
- export function isEphemeralToolCachePath(filePath) {
98
- const normalized = normalizePath(filePath);
99
- if (!normalized)
100
- return false;
97
+ const EPHEMERAL_CACHE_DIRS = [
101
98
  // CodeGraph extension sync side effect (plan 2026-08-21 D7): a loaded
102
99
  // pi-codegraph extension keeps an existing .codegraph/ index fresh at
103
100
  // session start; those index files are extension-owned run state, not
104
101
  // writer output, so they never count as write-guard violations.
105
- if (normalized === ".codegraph" || normalized.startsWith(".codegraph/")) {
106
- return true;
107
- }
108
- if (normalized === ".pytest_cache" ||
109
- normalized.startsWith(".pytest_cache/")) {
110
- return true;
111
- }
112
- if (normalized === ".mypy_cache" || normalized.startsWith(".mypy_cache/")) {
113
- return true;
114
- }
115
- if (normalized === ".ruff_cache" || normalized.startsWith(".ruff_cache/")) {
116
- return true;
117
- }
102
+ ".codegraph",
103
+ ".pytest_cache",
104
+ ".mypy_cache",
105
+ ".ruff_cache",
118
106
  // playwright-cli default session dumps (console/page/network) under repo cwd.
119
107
  // Real browser case evidence must still be written under testcase/** explicitly.
120
- if (normalized === ".playwright-cli" ||
121
- normalized.startsWith(".playwright-cli/")) {
122
- return true;
123
- }
124
- if (normalized === ".coverage" || normalized.startsWith(".coverage.")) {
125
- return true;
126
- }
108
+ ".playwright-cli",
109
+ ];
110
+ const EPHEMERAL_CACHE_DIR_PREFIXES = [
127
111
  // vite/vitest runtime caches live under node_modules/.vite (e.g.
128
112
  // node_modules/.vite/vitest/results.json). node_modules is the gitignored
129
113
  // dependency tree — tool cache writes there are never a writer's product
130
114
  // change and must not trip the write guard.
131
- if (normalized.startsWith("node_modules/.vite/")) {
132
- return true;
133
- }
134
- if (/(?:^|\/)__pycache__(?:\/|$)/.test(normalized))
135
- return true;
136
- if (/\.(?:pyc|pyo)$/.test(normalized))
137
- return true;
138
- return false;
115
+ "node_modules/.vite",
116
+ ];
117
+ const EPHEMERAL_CACHE_FILES = new Set([".coverage"]);
118
+ const EPHEMERAL_CACHE_PATH_PATTERNS = [
119
+ /(?:^|\/)__pycache__(?:\/|$)/,
120
+ /\.(?:pyc|pyo)$/,
121
+ ];
122
+ function isExactOrChildPath(value, names) {
123
+ return names.some((name) => value === name || value.startsWith(`${name}/`));
124
+ }
125
+ export function isEphemeralToolCachePath(filePath) {
126
+ const normalized = normalizePath(filePath);
127
+ if (!normalized)
128
+ return false;
129
+ return (isExactOrChildPath(normalized, EPHEMERAL_CACHE_DIRS) ||
130
+ EPHEMERAL_CACHE_DIR_PREFIXES.some((prefix) => normalized.startsWith(`${prefix}/`)) ||
131
+ EPHEMERAL_CACHE_FILES.has(normalized) ||
132
+ normalized.startsWith(".coverage.") ||
133
+ EPHEMERAL_CACHE_PATH_PATTERNS.some((pattern) => pattern.test(normalized)));
139
134
  }
140
135
  /** MVP post-run guard: only paths that changed during the shell node are checked. */
141
136
  export function validateShellWriteGuard(input) {
@@ -174,7 +174,7 @@ function localIndexReference(rawReference) {
174
174
  .trim()
175
175
  .replace(/^<|>$/g, "")
176
176
  .split(/[?#]/, 1)[0]
177
- .replaceAll("\\", "/");
177
+ ?.replaceAll("\\", "/") ?? "";
178
178
  if (!normalized.endsWith(".md") || normalized.includes("/"))
179
179
  return null;
180
180
  // Naming-convention placeholders (e.g. `YYYY-MM-DD-<topic>.md`) and other
@@ -332,6 +332,8 @@ function findInsertionPointForActiveEntry(lines) {
332
332
  // trailing section (blank-line separated context), or at the end.
333
333
  for (let i = 0; i < lines.length; i += 1) {
334
334
  const line = lines[i];
335
+ if (line === undefined)
336
+ break;
335
337
  if (/^[-*]\s+已归档/.test(line))
336
338
  return i;
337
339
  if (/^[-*]\s+`[^`]+\.md`/.test(line)) {
@@ -357,7 +359,8 @@ function removeIndexEntries(indexContent, file) {
357
359
  const lines = indexContent.split(/\r?\n/);
358
360
  const filtered = lines.filter((line) => {
359
361
  const linkMatch = line.match(/\[[^\]]*\]\(([^)]+)\)/);
360
- if (linkMatch && path.basename(linkMatch[1]) === file)
362
+ const linkTarget = linkMatch?.[1];
363
+ if (linkTarget !== undefined && path.basename(linkTarget) === file)
361
364
  return false;
362
365
  if (line.includes(`\`${file}\``))
363
366
  return false;
@@ -375,7 +378,7 @@ function collapseBlankRuns(lines) {
375
378
  result.push(line);
376
379
  prevBlank = isBlank;
377
380
  }
378
- while (result.length > 0 && result[result.length - 1].trim() === "") {
381
+ while (result.length > 0 && result[result.length - 1]?.trim() === "") {
379
382
  result.pop();
380
383
  }
381
384
  return result;
@@ -45,6 +45,9 @@ export function openConsoleAppData(options) {
45
45
  chats: path.join(repoNamespace, "chats"),
46
46
  chatSessions: path.join(repoNamespace, "chat-sessions"),
47
47
  chatEvents: path.join(repoNamespace, "chat-events"),
48
+ browserProfile: path.join(repoNamespace, "browser-profile"),
49
+ browserDownloads: path.join(repoNamespace, "browser-downloads"),
50
+ browserScreenshots: path.join(repoNamespace, "browser-screenshots"),
48
51
  resourcePreferences: path.join(repoNamespace, "resource-preferences.json"),
49
52
  };
50
53
  for (const dir of [
@@ -60,6 +63,9 @@ export function openConsoleAppData(options) {
60
63
  paths.chats,
61
64
  paths.chatSessions,
62
65
  paths.chatEvents,
66
+ paths.browserProfile,
67
+ paths.browserDownloads,
68
+ paths.browserScreenshots,
63
69
  path.dirname(paths.resourcePreferences),
64
70
  ]) {
65
71
  ensureSecureDir(dir);
@@ -81,6 +81,8 @@ function isUnchangedNewTaskTemplate(step, content) {
81
81
  }
82
82
  function firstRequiredSectionIsEmpty(step, content) {
83
83
  const [, firstSectionHeading] = REQUIRED_HEADINGS[step];
84
+ if (!firstSectionHeading)
85
+ return false;
84
86
  const headingIndex = content.indexOf(firstSectionHeading);
85
87
  if (headingIndex < 0) {
86
88
  return false;
@@ -0,0 +1,47 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFileSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { buildControllerIdentityFromEntry, readBuildStamp } from "./package-metadata.js";
5
+ export function sha256File(file) {
6
+ return `sha256:${createHash("sha256").update(readFileSync(file)).digest("hex")}`;
7
+ }
8
+ export function classifyBackendDogfoodProvenance(input) {
9
+ if (input.tarballPath)
10
+ return { kind: "local-tarball", version: input.identity.packageVersion, tarballSha256: sha256File(input.tarballPath) };
11
+ if (input.distTag)
12
+ return { kind: "published-npm", version: input.identity.packageVersion, distTag: input.distTag };
13
+ return { kind: "local-candidate", version: input.identity.packageVersion };
14
+ }
15
+ export function buildBackendDogfoodIdentityEvidence(input) {
16
+ const controller = buildControllerIdentityFromEntry({ requested: input.controllerEntry, entry: path.resolve(input.controllerEntry) });
17
+ if (!controller)
18
+ throw new Error("BACKEND_DOGFOOD_IDENTITY_UNRESOLVED");
19
+ const fingerprint = controller.packageFingerprint.value;
20
+ if (fingerprint !== input.expectedFingerprint)
21
+ throw new Error(`BACKEND_DOGFOOD_CONTROLLER_MISMATCH: expected ${input.expectedFingerprint}, got ${fingerprint}`);
22
+ const consoleIdentity = input.consoleHost
23
+ ? undefined
24
+ : buildControllerIdentityFromEntry({
25
+ requested: input.consoleControllerEntry ?? path.join(controller.packageRoot, "bin", "agent-worker.js"),
26
+ entry: input.consoleControllerEntry ?? path.join(controller.packageRoot, "bin", "agent-worker.js"),
27
+ });
28
+ if (!input.consoleHost && !consoleIdentity)
29
+ throw new Error("BACKEND_DOGFOOD_CONSOLE_IDENTITY_UNRESOLVED");
30
+ const consoleHost = {
31
+ packageName: String(input.consoleHost?.packageName ?? consoleIdentity?.packageName),
32
+ packageVersion: String(input.consoleHost?.packageVersion ?? consoleIdentity?.packageVersion),
33
+ packageFingerprint: String(input.consoleHost?.packageFingerprint ?? consoleIdentity?.packageFingerprint.value),
34
+ };
35
+ const expected = `${controller.packageName}@${controller.packageVersion}@${fingerprint}`;
36
+ const actual = `${consoleHost.packageName}@${consoleHost.packageVersion}@${consoleHost.packageFingerprint}`;
37
+ if (actual !== expected)
38
+ throw new Error(`BACKEND_DOGFOOD_CONSOLE_IDENTITY_MISMATCH: expected ${expected}, got ${actual}`);
39
+ return {
40
+ schemaVersion: 1,
41
+ controller,
42
+ provenance: classifyBackendDogfoodProvenance({ identity: controller, distTag: input.distTag, tarballPath: input.tarballPath }),
43
+ buildCommitSha: readBuildStamp(controller.packageRoot)?.gitSha ?? null,
44
+ consoleHost,
45
+ dagController: { packageName: controller.packageName, packageVersion: controller.packageVersion, packageFingerprint: fingerprint },
46
+ };
47
+ }
@@ -59,6 +59,9 @@ const RAW_TO_NORMALIZED = {
59
59
  quota: "executor",
60
60
  "rate-limit": "executor",
61
61
  unavailable: "executor",
62
+ // Gateway reachability outage: still an executor-class failure, but named so
63
+ // reports do not read as a capability mismatch.
64
+ "upstream-unavailable": "executor",
62
65
  // Context window overflow (400 request-too-large): the session needs
63
66
  // compaction / fresh context before retrying — an executor-side
64
67
  // environment condition, not a plan-quality defect.
@@ -112,6 +112,8 @@ function globToRegExp(pattern) {
112
112
  let regex = '^';
113
113
  for (let i = 0; i < normalized.length; i += 1) {
114
114
  const char = normalized[i];
115
+ if (char === undefined)
116
+ continue;
115
117
  const next = normalized[i + 1];
116
118
  if (char === '*' && next === '*') {
117
119
  const afterGlobstar = normalized[i + 2];
@@ -8,6 +8,8 @@ export function createOneShotPromptParseAccum() {
8
8
  }
9
9
  export function parseOneShotCommonFlag(args, index, accum) {
10
10
  const arg = args[index];
11
+ if (arg === undefined)
12
+ return { kind: "not-common" };
11
13
  if (arg === "--stdin") {
12
14
  accum.fromStdin = true;
13
15
  return { kind: "consumed", nextIndex: index };