@tea-agent/loop-agent 0.41.1-beta.0 → 0.42.0-next.2

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 (277) hide show
  1. package/CHANGELOG.md +78 -206
  2. package/dist/adapters/context-transfer/optional-pi-handoff.js +31 -0
  3. package/dist/adapters/context-transfer/pi-session.js +61 -0
  4. package/dist/application/dag/generate-task-dag.js +19 -75
  5. package/dist/application/task-lifecycle/advance.js +5 -24
  6. package/dist/application/task-lifecycle/observe.js +17 -171
  7. package/dist/application/task-lifecycle/plan-transitions.js +7 -42
  8. package/dist/application/task-lifecycle/recommendations.js +2 -13
  9. package/dist/build-stamp.json +3 -3
  10. package/dist/cli/command-definitions.js +12 -7
  11. package/dist/cli/program.js +23 -6
  12. package/dist/commands/client-recovery.js +0 -3
  13. package/dist/commands/dag-artifact.js +284 -0
  14. package/dist/commands/dag-context.js +184 -0
  15. package/dist/commands/dag-rerun.js +206 -1
  16. package/dist/commands/init.js +1 -27
  17. package/dist/commands/task-advance.js +0 -19
  18. package/dist/executors/dag-pi-executor.js +266 -3792
  19. package/dist/executors/pi-executor.js +4 -15
  20. package/dist/executors/pi-sdk-executor.js +3 -0
  21. package/dist/executors/shell-executor.js +217 -945
  22. package/dist/executors/shell-write-guard.js +0 -7
  23. package/dist/{worker → infrastructure}/console/app-data.js +4 -0
  24. package/dist/infrastructure/console/artifact-revision-store.js +430 -0
  25. package/dist/infrastructure/console/context-export-store.js +160 -0
  26. package/dist/infrastructure/console/dir-lock.js +132 -0
  27. package/dist/infrastructure/console/operation-store.js +197 -0
  28. package/dist/infrastructure/harness/artifact-store.js +10 -1
  29. package/dist/infrastructure/harness/atomic-write.js +12 -2
  30. package/dist/shared/context-transfer/artifact-revision.js +172 -0
  31. package/dist/shared/context-transfer.js +418 -0
  32. package/dist/shared/dag-failure-category.js +0 -12
  33. package/dist/shared/openspec-spec.js +4 -70
  34. package/dist/shared/operator/capabilities.js +14 -7
  35. package/dist/shared/operator/safe-run-summary.js +1 -0
  36. package/dist/shared/path-safety.js +93 -0
  37. package/dist/shared/preview.js +28 -4
  38. package/dist/task/config-types.js +80 -35
  39. package/dist/task/contract/adopt.js +0 -4
  40. package/dist/task/contract/import-revision.js +0 -4
  41. package/dist/task/contract/project.js +0 -3
  42. package/dist/task/contract/schema.js +1 -2
  43. package/dist/task/frontend-project-capability.js +20 -203
  44. package/dist/task/runtime.js +2 -5
  45. package/dist/task/source-prepare/build-draft.js +3 -3
  46. package/dist/task/source-prepare/fragment-inventory.js +9 -15
  47. package/dist/task/source-prepare/prepare.js +1 -89
  48. package/dist/task/source-prepare/semantic-intake.js +2 -6
  49. package/dist/task/source-references.js +1 -22
  50. package/dist/task/task-demand-routing.js +3 -0
  51. package/dist/worker/console/chat/chat-event-store.js +2 -2
  52. package/dist/worker/console/chat/pi-runtime.js +3 -2
  53. package/dist/worker/console/chat/resource-preferences-store.js +1 -1
  54. package/dist/worker/console/chat/routes.js +13 -4
  55. package/dist/worker/console/chat/semantic-activity.js +12 -11
  56. package/dist/worker/console/chat/session-stats.js +96 -0
  57. package/dist/worker/console/chat/session-store.js +1 -1
  58. package/dist/worker/console/chat/turn-process.js +28 -4
  59. package/dist/worker/console/chat/user-questions.js +1 -1
  60. package/dist/worker/console/console-update-runtime.js +1 -1
  61. package/dist/worker/console/context-transfer-diagnostics.js +198 -0
  62. package/dist/worker/console/dag-confirmation.js +1 -1
  63. package/dist/worker/console/dag-execution-receipt.js +1 -1
  64. package/dist/worker/console/doctor.js +1 -1
  65. package/dist/worker/console/draft-store.js +1 -1
  66. package/dist/worker/console/human-gate-token.js +1 -1
  67. package/dist/worker/console/index.js +3 -6
  68. package/dist/worker/console/interview/assessment.js +1 -1
  69. package/dist/worker/console/interview/session.js +1 -1
  70. package/dist/worker/console/operation-runner.js +45 -4
  71. package/dist/worker/console/operation-sse.js +1 -1
  72. package/dist/worker/console/operation-wait.js +1 -1
  73. package/dist/worker/console/operator-actions.js +107 -168
  74. package/dist/worker/console/operator-surface-health.js +1 -1
  75. package/dist/worker/console/operator-user-error.js +169 -0
  76. package/dist/worker/console/pi-plugins.js +60 -1
  77. package/dist/worker/console/routes.js +637 -8
  78. package/dist/worker/console/security.js +35 -0
  79. package/dist/worker/console/server.js +6 -6
  80. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-Bho4we4c.js → abnfDiagram-N423BO3Z-DZZ8m3PO.js} +1 -1
  81. package/dist/worker/console/static/assets/{arc-TBDkTeK0.js → arc-D6PvaVd-.js} +1 -1
  82. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-BF_fZrn2.js → architectureDiagram-T3A2C74G-B_OTOiI8.js} +1 -1
  83. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-CCnPgUe2.js → blockDiagram-VBNYF7ZC-Bv6rqHBg.js} +1 -1
  84. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BCYZJLAT.js → c4Diagram-5PPSVZJV-B8eHr0oz.js} +1 -1
  85. package/dist/worker/console/static/assets/channel-BU5gOilw.js +1 -0
  86. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-D8K6adhU.js → chunk-2GRJ4B5K-DYwR0im2.js} +1 -1
  87. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DkT1Q78b.js → chunk-2Q5K7J3B-D2WPGqXt.js} +1 -1
  88. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DuhvpIr7.js → chunk-5RXB4S5H-CQISJ_I7.js} +1 -1
  89. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BnK6dC49.js → chunk-5VM5RSS4-C0o2Du1e.js} +1 -1
  90. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DPz__z7r.js → chunk-6Q2QTUOP-4f8kr-U7.js} +1 -1
  91. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-0kkppM2j.js → chunk-GF5L2VYU-D_OWvXzX.js} +1 -1
  92. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BB41iK5t.js → chunk-JWPE2WC7-CasdPz5X.js} +1 -1
  93. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-CiVrxKHU.js → chunk-KBJHAD2P-Cj8lRrla.js} +1 -1
  94. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-C2h9Xje1.js → chunk-RYQCIY6F-CUvD1FSd.js} +1 -1
  95. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-3iOSHdbM.js → chunk-XXDRQBXY-CqLw_eqB.js} +1 -1
  96. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DIzKJGHr.js +1 -0
  97. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DIzKJGHr.js +1 -0
  98. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BN3A7tkk.js → cose-bilkent-JH36ORCC-ku-WqJPx.js} +1 -1
  99. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-CTuBy0Or.js → cynefin-VYW2F7L2-Bq_PYDhl.js} +1 -1
  100. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-wb6tUlMN.js → cynefinDiagram-MW4NZA55-BiGZV641.js} +1 -1
  101. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-GP1Ivx8B.js → dagre-VZM6K2ZE-C4JRlglF.js} +1 -1
  102. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-ejrcK6L0.js → diagram-7IWD3JNH-B0dNeWYG.js} +1 -1
  103. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-YFkCCvUU.js → diagram-B4RE2ZJO-Cj35YvYM.js} +1 -1
  104. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-B4rrvIaL.js → diagram-LBJQPF4R-uzQoJ2-8.js} +1 -1
  105. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-C-YIZcUf.js → diagram-Q27KOJAE-D1a-Buoz.js} +1 -1
  106. package/dist/worker/console/static/assets/{diagram-UB23O5K3-BPF5wcL1.js → diagram-UB23O5K3-XjRrLRSs.js} +1 -1
  107. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-CU5SzXjO.js → ebnfDiagram-BXEA7PRR-Da_O24cW.js} +1 -1
  108. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-CpL414DE.js → erDiagram-JOGREHBK-BLJ8jrYU.js} +1 -1
  109. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-MrhLzNau.js → flowDiagram-UKHOOZJN-B9GrLjM0.js} +1 -1
  110. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-Bg4qFuUo.js → ganttDiagram-PKOTCBZU-CeJ0TqiK.js} +1 -1
  111. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-ColxSXLR.js → gitGraphDiagram-DS77QQ5N-Bm2eNNFX.js} +1 -1
  112. package/dist/worker/console/static/assets/index-H9rFJiGL.css +1 -0
  113. package/dist/worker/console/static/assets/index-xwu9GxEc.js +451 -0
  114. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-Czvtm6gc.js → infoDiagram-6WML65LV-DB26i3d8.js} +1 -1
  115. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-B7Xp8HyJ.js → ishikawaDiagram-WSZJBQD7-BOGRyeZT.js} +1 -1
  116. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DWYZcvph.js → journeyDiagram-NVQOT4AX-CZRoBO_6.js} +1 -1
  117. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-KTLZRUjx.js → kanban-definition-27J2QSJJ-qlWhJyoB.js} +1 -1
  118. package/dist/worker/console/static/assets/{linear-_Exn7bfl.js → linear-CfUiDDB3.js} +1 -1
  119. package/dist/worker/console/static/assets/{mermaid.core-Cxg8kX8V.js → mermaid.core-BQe6fpqj.js} +5 -5
  120. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-oKrlo2Bt.js → mindmap-definition-FAOFIHXS-zFzWHw64.js} +1 -1
  121. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-XAeteiNd.js → pegDiagram-VL7TDLO6-DFGUqjZO.js} +1 -1
  122. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BTf1K-lp.js → pieDiagram-7S7Q4E2Y-BB5i0l8Z.js} +1 -1
  123. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-C0IlY0Jf.js → quadrantDiagram-CIZ2JOQS-obbVZ_X5.js} +1 -1
  124. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BVbKtZhW.js → railroadDiagram-AXF67PYL-BwdaNzc1.js} +1 -1
  125. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-C5e4JFcr.js → requirementDiagram-LRYGKXZP-CkTJaugh.js} +1 -1
  126. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Cz30hc29.js → sankeyDiagram-W5VNT64P-BwJ-hIgq.js} +1 -1
  127. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DS33n6d0.js → sequenceDiagram-SI44F4Z6-BzSgmm7w.js} +1 -1
  128. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-46w7v-9T.js → sizeCapture-X5ZJPWSS-Bn3oj5Q1.js} +1 -1
  129. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-pbcD5SsZ.js → stateDiagram-OKZ733FA-dxhGtL8K.js} +1 -1
  130. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Cld2qK9v.js +1 -0
  131. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DuivYBSj.js → swimlanes-SLNWSIFB-BLpEInya.js} +2 -2
  132. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-TIHpiT7w.js +8 -0
  133. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-Cb9VZVIl.js → timeline-definition-Z64GVDOM-ChJGYcXy.js} +1 -1
  134. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-D2-mfOgR.js → vennDiagram-T6HMQDX7-DK-qjRer.js} +1 -1
  135. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DeS2aC76.js → wardleyDiagram-T6FBY63Y-3qeaWAg-.js} +1 -1
  136. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-WGsrFjxH.js → xychartDiagram-ELKLHX3M-CootlyP9.js} +1 -1
  137. package/dist/worker/console/static/index.html +7 -2
  138. package/dist/worker/console/static-src/app/useOperatorActions.js +3 -2
  139. package/dist/worker/console/static-src/app/useRunProgress.js +9 -2
  140. package/dist/worker/console/static-src/operator-chat/dag-progress-link.js +22 -0
  141. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +2 -0
  142. package/dist/worker/console/static-src/operator-chat/useChatThread.js +6 -0
  143. package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +28 -3
  144. package/dist/worker/console/static-src/pages/tasks/run-panel-progress.js +106 -0
  145. package/dist/worker/console/static-src/shell/console-update-reload.js +25 -0
  146. package/dist/worker/console/workspace-context.js +28 -112
  147. package/dist/worker/console/workspace-registry.js +2 -2
  148. package/dist/worker/continuation/worker-continuation.js +278 -0
  149. package/dist/worker/observability/read-model.js +4 -0
  150. package/dist/worker/observe/health.js +1 -1
  151. package/dist/worker/observe/node-transparency.js +572 -0
  152. package/dist/worker/observe/routes.js +51 -1
  153. package/dist/worker/observe/static/api.js +69 -5
  154. package/dist/worker/observe/static/dag-context-reason-labels.d.ts +9 -0
  155. package/dist/worker/observe/static/dag-context-reason-labels.js +120 -0
  156. package/dist/worker/observe/static/dag-node-purpose.js +0 -5
  157. package/dist/worker/observe/static/state.js +3 -1
  158. package/dist/worker/observe/static/styles.css +1037 -126
  159. package/dist/worker/observe/static/views/dag-inspector.js +1217 -65
  160. package/dist/worker/observe/static/views/session-timeline.js +121 -25
  161. package/dist/worker/outcomes/adapters.js +19 -0
  162. package/dist/worker/outcomes/types.js +1 -0
  163. package/dist/worker/pool/attempt-lease.js +97 -66
  164. package/dist/worker/pool/begin-attempt-with-lease.js +1 -0
  165. package/dist/worker/pool/reconcile.js +46 -1
  166. package/dist/worker/pool/run-store.js +2 -0
  167. package/dist/worker/pool/state-projection.js +2 -0
  168. package/dist/worker/task-spec/workflow-routing.js +8 -3
  169. package/dist/workflows/dag/artifact-bindings.js +149 -0
  170. package/dist/workflows/dag/artifact-revision-schema-registry.js +31 -0
  171. package/dist/workflows/dag/backend-test-case-coverage-analysis.js +99 -4
  172. package/dist/workflows/dag/backend-test-markdown-workflow.js +13 -1
  173. package/dist/workflows/dag/backend-test-result-contract.js +1 -1
  174. package/dist/workflows/dag/backend-test-writer-completeness.js +45 -3
  175. package/dist/workflows/dag/budget-enforcement.js +10 -0
  176. package/dist/workflows/dag/context-receipt.js +305 -0
  177. package/dist/workflows/dag/context-transfer/context-bundle.js +423 -0
  178. package/dist/workflows/dag/context-transfer/operator-actions.js +61 -0
  179. package/dist/workflows/dag/context-transfer/renderers.js +93 -0
  180. package/dist/workflows/dag/contract-validator-registrations.js +2 -1
  181. package/dist/workflows/dag/frontend-implementation-contract.js +162 -932
  182. package/dist/workflows/dag/frontend-plan-render.js +1 -2
  183. package/dist/workflows/dag/frontend-prewrite-gate.js +349 -255
  184. package/dist/workflows/dag/frontend-recovery-plan.js +10 -17
  185. package/dist/workflows/dag/frontend-recovery-run.js +20 -33
  186. package/dist/workflows/dag/frontend-repair.js +432 -1
  187. package/dist/workflows/dag/frontend-review-context.js +15 -261
  188. package/dist/workflows/dag/frontend-verification-trace.js +24 -249
  189. package/dist/workflows/dag/frontend-worktree-diff.js +17 -250
  190. package/dist/workflows/dag/frontend-writer-rollback.js +32 -0
  191. package/dist/workflows/dag/init-hybrid.js +740 -718
  192. package/dist/workflows/dag/interrupt-request.js +0 -7
  193. package/dist/workflows/dag/node-execution.js +136 -759
  194. package/dist/workflows/dag/path-safety.js +1 -0
  195. package/dist/workflows/dag/prompt.js +30 -38
  196. package/dist/workflows/dag/report.js +1 -37
  197. package/dist/workflows/dag/rerun-feedback.js +1 -256
  198. package/dist/workflows/dag/rerun-plan.js +557 -11
  199. package/dist/workflows/dag/rerun-run.js +601 -38
  200. package/dist/workflows/dag/rerun-task.js +0 -29
  201. package/dist/workflows/dag/retry-policy.js +109 -214
  202. package/dist/workflows/dag/runner.js +142 -430
  203. package/dist/workflows/dag/scheduler.js +16 -114
  204. package/dist/workflows/dag/skill-snapshot.js +17 -0
  205. package/dist/workflows/dag/types.js +195 -246
  206. package/dist/workflows/dag/validate.js +12 -28
  207. package/docs/architecture/runtime-boundaries.md +6 -6
  208. package/docs/architecture/worker-and-feature.md +1 -1
  209. package/docs/init-surface.manifest.json +12 -30
  210. package/docs/skills/vetted-skill-registry.md +2 -4
  211. package/docs/templates/README.md +0 -2
  212. package/docs/templates/agent-dag-report.schema.json +2 -8
  213. package/docs/templates/agent-dag.schema.json +33 -1
  214. package/docs/templates/backend-test-dag.json +18 -18
  215. package/docs/templates/frontend-implementation-contract.schema.json +1 -4
  216. package/docs/templates/product-line/task.yaml +1 -1
  217. package/harness.json +3 -3
  218. package/package.json +3 -1
  219. package/skills/frontend-bounded-implement/SKILL.md +14 -15
  220. package/skills/frontend-design-review/SKILL.md +41 -22
  221. package/skills/frontend-implementation/SKILL.md +52 -0
  222. package/skills/frontend-implementation/references/code-standards.md +33 -0
  223. package/skills/frontend-implementation/references/design-spec.md +56 -0
  224. package/skills/frontend-implementation/references/node-contracts.md +31 -0
  225. package/skills/frontend-review/SKILL.md +15 -20
  226. package/skills/frontend-review/references/review-findings.md +7 -6
  227. package/skills/frontend-verification/SKILL.md +1 -1
  228. package/skills/loop-agent/references/command-reference.md +6 -1
  229. package/skills/loop-agent/references/hybrid-dag.md +2 -2
  230. package/dist/commands/dag-follow-up.js +0 -138
  231. package/dist/executors/pi-read-budget-policy.js +0 -239
  232. package/dist/worker/console/frontend-human-decision-adapter.js +0 -19
  233. package/dist/worker/console/frontend-split-operation-adapter.js +0 -20
  234. package/dist/worker/console/operation-store.js +0 -389
  235. package/dist/worker/console/static/assets/channel-bnXW0U3C.js +0 -1
  236. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-rZpq_twR.js +0 -1
  237. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-rZpq_twR.js +0 -1
  238. package/dist/worker/console/static/assets/index-D3CC4eUz.css +0 -1
  239. package/dist/worker/console/static/assets/index-DLt4ZFvD.js +0 -437
  240. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-zBMYiUyi.js +0 -1
  241. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-d_rms-5i.js +0 -8
  242. package/dist/worker/console/static-src/active-run-badge.js +0 -17
  243. package/dist/worker/materialize/frontend-split-task-materializer.js +0 -72
  244. package/dist/workflows/dag/dag-retry-schema.js +0 -138
  245. package/dist/workflows/dag/frontend-closeout.js +0 -221
  246. package/dist/workflows/dag/frontend-design-policy.js +0 -400
  247. package/dist/workflows/dag/frontend-human-decision.js +0 -182
  248. package/dist/workflows/dag/frontend-provider-capability-matrix.js +0 -159
  249. package/dist/workflows/dag/frontend-read-budgets.js +0 -12
  250. package/dist/workflows/dag/frontend-recovery-capsule.js +0 -455
  251. package/dist/workflows/dag/frontend-recovery-controller.js +0 -202
  252. package/dist/workflows/dag/frontend-recovery-lineage.js +0 -178
  253. package/dist/workflows/dag/frontend-review-findings.js +0 -270
  254. package/dist/workflows/dag/frontend-shadow-dual-write.js +0 -914
  255. package/dist/workflows/dag/frontend-shape-capsule-store.js +0 -191
  256. package/dist/workflows/dag/frontend-shape-facts.js +0 -409
  257. package/dist/workflows/dag/frontend-shape.js +0 -427
  258. package/dist/workflows/dag/frontend-source-fidelity-ledger.js +0 -108
  259. package/dist/workflows/dag/frontend-split-application-service.js +0 -203
  260. package/dist/workflows/dag/frontend-split-orchestrator.js +0 -899
  261. package/dist/workflows/dag/frontend-typed-event-store.js +0 -452
  262. package/dist/workflows/dag/frontend-typed-event-transaction.js +0 -180
  263. package/dist/workflows/dag/frontend-writer-admission.js +0 -285
  264. package/dist/workflows/dag/frontend-writer-status.js +0 -256
  265. package/dist/workflows/dag/recovery-lease.js +0 -80
  266. package/docs/templates/frontend-implementation-dag.json +0 -89
  267. package/docs/templates/spec-registry.schema.json +0 -45
  268. package/skills/frontend-bounded-implement/references/code-standards.md +0 -19
  269. package/skills/frontend-contract/SKILL.md +0 -23
  270. package/skills/frontend-contract/references/contract-protocol.md +0 -34
  271. package/skills/frontend-plan/SKILL.md +0 -26
  272. package/skills/frontend-plan/references/decision-contract.md +0 -37
  273. package/skills/frontend-plan/references/design-decisions.md +0 -17
  274. package/skills/frontend-scout/SKILL.md +0 -25
  275. package/skills/frontend-scout/references/design-evidence.md +0 -16
  276. package/skills/frontend-scout/references/scout-evidence.md +0 -23
  277. /package/dist/{worker → infrastructure}/console/repo-fingerprint.js +0 -0
@@ -0,0 +1 @@
1
+ export { assertReadableRegularFile, assertRealPathInsideBoundary, readFileBoundarySafe, } from "../../shared/path-safety.js";
@@ -1,3 +1,4 @@
1
+ import path from "node:path";
1
2
  import { DEFAULT_DAG_OUTPUT_LANGUAGE, } from "./types.js";
2
3
  import { formatStdoutPreview, formatUpstreamArtifactPointerMap, } from "./upstream-artifacts.js";
3
4
  export const MAX_UPSTREAM_CHARS = 2_000;
@@ -45,42 +46,9 @@ function formatResolvedSkillInstructions(instructions) {
45
46
  if (!instructions || instructions.length === 0)
46
47
  return "(none)";
47
48
  return instructions
48
- .map((instruction) => formatSkillChecklist(instruction))
49
+ .map((instruction) => instruction.promptText)
49
50
  .join("\n\n---\n\n");
50
51
  }
51
- /** Keep skill provenance, but turn bounded inline manuals into a small action list. */
52
- function formatSkillChecklist(instruction) {
53
- const metadata = [
54
- `Skill: ${instruction.name}`,
55
- `Resolution: ${instruction.resolution}`,
56
- ...(instruction.path ? [`Path: ${instruction.path}`] : []),
57
- ...(instruction.sha256 ? [`Sha256: ${instruction.sha256}`] : []),
58
- "Injection mode: checklist",
59
- ];
60
- if (instruction.resolution !== "resolved")
61
- return [...metadata, instruction.promptText].join("\n");
62
- const source = instruction.promptText.split("Instructions:\n")[1] ?? "";
63
- const candidates = source
64
- .split(/\r?\n/)
65
- .map((line) => line.trim())
66
- .filter((line) => /^(?:#{1,3}\s+|[-*]\s+|\d+[.)]\s+)/.test(line) || line.length > 0)
67
- .map((line) => line.replace(/^#{1,3}\s+/, "").replace(/^[-*]\s+/, "").replace(/^\d+[.)]\s+/, ""))
68
- .filter((line) => line.length > 0);
69
- const checklist = [];
70
- let chars = 0;
71
- for (const item of candidates) {
72
- const bounded = item.slice(0, 240);
73
- if (checklist.length >= 10 || chars + bounded.length > 1_600)
74
- break;
75
- checklist.push(`- ${bounded}`);
76
- chars += bounded.length;
77
- }
78
- return [
79
- ...metadata,
80
- "Checklist (apply these actions; consult the immutable resolved file only when a listed action requires detail):",
81
- ...(checklist.length > 0 ? checklist : ["- Follow the resolved skill's declared workflow."]),
82
- ].join("\n");
83
- }
84
52
  export function formatOutputLanguageBlock(language = DEFAULT_DAG_OUTPUT_LANGUAGE) {
85
53
  if (language === "en") {
86
54
  return [
@@ -95,9 +63,10 @@ export function formatOutputLanguageBlock(language = DEFAULT_DAG_OUTPUT_LANGUAGE
95
63
  "如果当前节点任务明确要求其他语言,以节点的明确要求为准。",
96
64
  ].join("\n");
97
65
  }
98
- export function buildUpstreamContext(task, upstream, maxChars = MAX_UPSTREAM_CHARS) {
66
+ export function buildUpstreamContext(task, upstream, maxChars = MAX_UPSTREAM_CHARS, runDir) {
99
67
  const sections = [];
100
68
  const toleratedFailures = new Set(task.failureAwareDependsOn ?? []);
69
+ const consumedArtifactIds = new Set((task.consumesArtifacts ?? []).map((binding) => binding.artifactId));
101
70
  for (const depId of task.depends_on) {
102
71
  const record = upstream[depId];
103
72
  const stdout = record?.stdout?.trim() ? record.stdout : "";
@@ -151,6 +120,22 @@ export function buildUpstreamContext(task, upstream, maxChars = MAX_UPSTREAM_CHA
151
120
  }
152
121
  if (!record || record.status !== "FINISHED")
153
122
  continue;
123
+ const consumedArtifacts = (record.declaredArtifacts ?? []).filter((artifact) => consumedArtifactIds.has(artifact.artifactId));
124
+ const consumedArtifactSection = runDir && consumedArtifacts.length > 0
125
+ ? [
126
+ "Declared artifact bindings (read-only run evidence — use the exact paths below; do not edit):",
127
+ ...consumedArtifacts.flatMap((artifact) => {
128
+ const absolutePath = path.resolve(runDir, ...artifact.path.split("/"));
129
+ return [
130
+ `- artifactId: ${artifact.artifactId}`,
131
+ ` path: ${absolutePath}`,
132
+ ` status: ${artifact.status}`,
133
+ ` sha256: ${artifact.sha256 ?? "unknown"}`,
134
+ ` mediaType: ${artifact.mediaType}`,
135
+ ];
136
+ }),
137
+ ].join("\n")
138
+ : "";
154
139
  if (record.structuredArtifactPath &&
155
140
  record.structuredArtifactSchemaId ===
156
141
  "frontend-implementation-contract-v1") {
@@ -163,8 +148,12 @@ export function buildUpstreamContext(task, upstream, maxChars = MAX_UPSTREAM_CHA
163
148
  ].join("\n"));
164
149
  continue;
165
150
  }
166
- if (!upstreamText)
151
+ if (!upstreamText) {
152
+ if (consumedArtifactSection) {
153
+ sections.push(`## Upstream output: ${depId}\n${consumedArtifactSection}`);
154
+ }
167
155
  continue;
156
+ }
168
157
  const artifactKind = stdout ? "stdout" : "assistant";
169
158
  const artifactPath = stdout
170
159
  ? record.stdoutArtifactPath
@@ -180,6 +169,9 @@ export function buildUpstreamContext(task, upstream, maxChars = MAX_UPSTREAM_CHA
180
169
  `- sha256: ${record.structuredArtifactSha256 ?? "unknown"}`,
181
170
  ].join("\n");
182
171
  }
172
+ if (consumedArtifactSection) {
173
+ section += `\n\n${consumedArtifactSection}`;
174
+ }
183
175
  if (truncated && artifactPath) {
184
176
  section += formatUpstreamArtifactPointerMap(record, artifactKind);
185
177
  }
@@ -362,7 +354,7 @@ function formatProjectGovernanceContext(ctx) {
362
354
  return lines.join("\n");
363
355
  }
364
356
  export function buildDagNodePromptEnvelope(input) {
365
- const { spec, task, upstream, resolvedSkills = [], resolvedSkillInstructions = [], maxUpstreamChars = MAX_UPSTREAM_CHARS, projectGovernanceContext, convergenceFeedback, } = input;
357
+ const { spec, task, upstream, runDir, resolvedSkills = [], resolvedSkillInstructions = [], maxUpstreamChars = MAX_UPSTREAM_CHARS, projectGovernanceContext, convergenceFeedback, } = input;
366
358
  const objective = spec.objective ?? spec.title;
367
359
  const successCriteria = formatBulletList(spec.successCriteria, "(none specified)");
368
360
  const globalConstraints = formatBulletList(spec.globalConstraints, "(none specified)");
@@ -372,7 +364,7 @@ export function buildDagNodePromptEnvelope(input) {
372
364
  ? resolvedSkills.map((skill) => `- ${skill}`).join("\n")
373
365
  : "(none)";
374
366
  const skillInstructionsSection = formatResolvedSkillInstructions(resolvedSkillInstructions);
375
- const upstreamContext = buildUpstreamContext(task, upstream, maxUpstreamChars);
367
+ const upstreamContext = buildUpstreamContext(task, upstream, maxUpstreamChars, runDir);
376
368
  const readOnlyBoundary = buildReadOnlyBoundary(writePolicy);
377
369
  const sections = [
378
370
  `<dag_objective>\n${objective}\n</dag_objective>`,
@@ -125,8 +125,6 @@ const dagNodeArtifactsReportSchema = z
125
125
  humanEscalationMd: dagArtifactRefSchema,
126
126
  humanApproval: dagArtifactRefSchema,
127
127
  humanRejection: dagArtifactRefSchema,
128
- changeManifest: dagArtifactRefSchema,
129
- changeManifestChangedFiles: z.array(z.string()).optional(),
130
128
  })
131
129
  .strict();
132
130
  const dagNodeReportRowSchema = z
@@ -261,20 +259,6 @@ export async function probeArtifact(filePath) {
261
259
  export async function buildNodeArtifactsReport(runDir, nodeId) {
262
260
  const nodeDir = path.join(runDir, nodeId);
263
261
  const artifact = (name) => probeArtifact(path.join(nodeDir, name));
264
- const changeManifestRef = await artifact("change-manifest.json");
265
- let changeManifestChangedFiles;
266
- if (changeManifestRef.exists) {
267
- try {
268
- const manifest = JSON.parse(await readFile(path.join(nodeDir, "change-manifest.json"), "utf-8"));
269
- changeManifestChangedFiles = Array.isArray(manifest.changedFiles)
270
- ? manifest.changedFiles
271
- .filter((item) => typeof item === "string")
272
- : undefined;
273
- }
274
- catch {
275
- // unreadable manifest → leave undefined
276
- }
277
- }
278
262
  return {
279
263
  resultSummary: await artifact("result.summary.md"),
280
264
  promptRedacted: await artifact("prompt.redacted.md"),
@@ -286,8 +270,6 @@ export async function buildNodeArtifactsReport(runDir, nodeId) {
286
270
  humanEscalationMd: await artifact("human-escalation.md"),
287
271
  humanApproval: await artifact("human-approval.json"),
288
272
  humanRejection: await artifact("human-rejection.json"),
289
- changeManifest: changeManifestRef,
290
- changeManifestChangedFiles,
291
273
  };
292
274
  }
293
275
  function taskById(spec) {
@@ -744,12 +726,6 @@ function formatArtifactFlags(artifacts) {
744
726
  flags.push("approval");
745
727
  if (artifacts.humanRejection.exists)
746
728
  flags.push("rejection");
747
- if (artifacts.changeManifest.exists) {
748
- const count = artifacts.changeManifestChangedFiles?.length;
749
- flags.push(count !== undefined
750
- ? `changed:${count}`
751
- : "change-manifest");
752
- }
753
729
  return flags.length > 0 ? flags.join(",") : "-";
754
730
  }
755
731
  function formatTimestamp(value) {
@@ -773,19 +749,7 @@ function summarizeNodeStatuses(nodes) {
773
749
  return `${total} total / ${finished} finished / ${failed} failed / ${skipped} skipped / ${pending} pending`;
774
750
  }
775
751
  function hasArtifact(artifacts) {
776
- return [
777
- artifacts.resultSummary,
778
- artifacts.promptRedacted,
779
- artifacts.skills,
780
- artifacts.nodeRecord,
781
- artifacts.decisionEnvelope,
782
- artifacts.decisionEnvelopeValidation,
783
- artifacts.humanEscalationJson,
784
- artifacts.humanEscalationMd,
785
- artifacts.humanApproval,
786
- artifacts.humanRejection,
787
- artifacts.changeManifest,
788
- ].some((artifact) => artifact.exists);
752
+ return Object.values(artifacts).some((artifact) => artifact.exists);
789
753
  }
790
754
  function failureRows(run) {
791
755
  return run.nodes.filter((node) => node.status === "ERROR" ||
@@ -2,8 +2,6 @@ import { createHash } from "node:crypto";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { parseJsonReviewVerdict } from "./output-protocol.js";
5
- import { FRONTEND_DESIGN_REVIEW_NODE_ID, FRONTEND_REVIEW_NODE_ID, readCommittedDesignRequestFact, readCommittedReviewRequestFact, } from "./frontend-review-findings.js";
6
- import { readTypedEventStoreFromJsonl } from "./frontend-typed-event-store.js";
7
5
  export const MAX_RERUN_FEEDBACK_CHARS = 12_000;
8
6
  const RERUN_FEEDBACK_TRUNCATION_MARKER = "\n\n...[上一轮反馈已按长度上限截断]...\n\n";
9
7
  const MAX_EVIDENCE_REFS = 8;
@@ -37,44 +35,6 @@ function requestRevision(text) {
37
35
  return (emphasized?.[1] ?? trimmed).trim() === "VERDICT: request-revision";
38
36
  });
39
37
  }
40
- /**
41
- * Deterministically render a typed `request_review_changes` fact into feedback
42
- * text. Unlike the legacy text channel (VERDICT: request-revision), the
43
- * frontend review terminal is a committed typed fact; the findings are the
44
- * actionable body the next round must consume.
45
- */
46
- export function formatTypedReviewRequestFeedback(fact) {
47
- const lines = [];
48
- lines.push(`frontend review committed request_review_changes (issueCategory=${typeof fact.issueCategory === "string" ? fact.issueCategory : "unknown"})`);
49
- if (Array.isArray(fact.findings) && fact.findings.length > 0) {
50
- lines.push("review findings:");
51
- for (const finding of fact.findings) {
52
- if (!finding || typeof finding !== "object")
53
- continue;
54
- const record = finding;
55
- const severity = typeof record.severity === "string" ? record.severity : "";
56
- const issue = typeof record.issue === "string" ? record.issue : "";
57
- const location = [
58
- typeof record.file === "string" ? record.file : "",
59
- typeof record.line === "number" ? String(record.line) : "",
60
- ]
61
- .filter(Boolean)
62
- .join(":");
63
- const prefix = location ? `[${location}] ` : "";
64
- const requiredChange = typeof record.requiredChange === "string" &&
65
- record.requiredChange.length > 0
66
- ? ` (requiredChange: ${record.requiredChange})`
67
- : "";
68
- lines.push(`- ${prefix}${severity}: ${issue}${requiredChange}`);
69
- }
70
- }
71
- if (Array.isArray(fact.evidenceRefs) && fact.evidenceRefs.length > 0) {
72
- lines.push(`evidenceRefs: ${fact.evidenceRefs
73
- .filter((ref) => typeof ref === "string")
74
- .join(", ")}`);
75
- }
76
- return lines.join("\n");
77
- }
78
38
  function pathInside(root, candidate) {
79
39
  const relative = path.relative(root, candidate);
80
40
  return (relative === "" ||
@@ -167,162 +127,6 @@ function evidenceRefs(repoRoot, runDir, pass, sourceNodeId) {
167
127
  }
168
128
  return result;
169
129
  }
170
- /**
171
- * Read the committed frontend review request fact (typed terminal channel).
172
- * Returns { nodeId, fact } when the review node committed `request_review_changes`.
173
- */
174
- async function readTypedReviewRequestFact(runDir) {
175
- const fact = await readCommittedReviewRequestFact({ runDir });
176
- if (!fact)
177
- return undefined;
178
- return {
179
- nodeId: FRONTEND_REVIEW_NODE_ID,
180
- fact: {
181
- issueCategory: fact.issueCategory,
182
- evidenceRefs: fact.evidenceRefs,
183
- findings: fact.findings,
184
- },
185
- };
186
- }
187
- /**
188
- * Read the committed frontend design request fact (typed terminal channel).
189
- * Returns { nodeId, fact } when the design review node committed
190
- * `request_design_changes` — the design analog of request_review_changes.
191
- */
192
- async function readTypedDesignRequestFact(runDir) {
193
- const fact = await readCommittedDesignRequestFact({ runDir });
194
- if (!fact)
195
- return undefined;
196
- return {
197
- nodeId: FRONTEND_DESIGN_REVIEW_NODE_ID,
198
- fact: {
199
- issueCategory: fact.issueCategory,
200
- evidenceRefs: fact.evidenceRefs,
201
- findings: fact.findings,
202
- },
203
- };
204
- }
205
- const RERUN_FEEDBACK_LINEAGE_MAX_DEPTH = 5;
206
- const RERUN_FEEDBACK_LINEAGE_LIFECYCLES = [
207
- "active",
208
- "paused",
209
- "completed",
210
- ];
211
- function safeLineageRunId(value) {
212
- if (typeof value !== "string" || !value || value !== value.trim())
213
- return undefined;
214
- if (value === "." ||
215
- value === ".." ||
216
- value.includes("/") ||
217
- value.includes("\\") ||
218
- value.includes("\0"))
219
- return undefined;
220
- return value;
221
- }
222
- async function readCommittedTerminalKind(input) {
223
- try {
224
- const records = await readTypedEventStoreFromJsonl(path.join(input.runDir, input.nodeId, input.factsFile));
225
- for (const record of records) {
226
- if (record.phase !== "committed")
227
- continue;
228
- const kind = record.fact.kind;
229
- if (typeof kind === "string" && input.kinds.includes(kind))
230
- return kind;
231
- }
232
- }
233
- catch {
234
- // A missing/unreadable terminal store means this run did not establish a
235
- // usable resolution barrier; lineage lookup may continue.
236
- }
237
- return undefined;
238
- }
239
- async function readReviewTerminalKind(runDir) {
240
- return readCommittedTerminalKind({
241
- runDir,
242
- nodeId: FRONTEND_REVIEW_NODE_ID,
243
- factsFile: "review-typed-facts.jsonl",
244
- kinds: ["request_review_changes", "approve_review"],
245
- });
246
- }
247
- async function readDesignTerminalKind(runDir) {
248
- return readCommittedTerminalKind({
249
- runDir,
250
- nodeId: FRONTEND_DESIGN_REVIEW_NODE_ID,
251
- factsFile: "design-typed-facts.jsonl",
252
- kinds: ["request_design_changes", "approve_design"],
253
- });
254
- }
255
- /**
256
- * Walk the rerun-task lineage chain (`<runDir>/.runtime/rerun-task-lineage.json`
257
- * → parentRunId) looking for the nearest ancestor run with a committed review
258
- * or design request fact. A nearer final-review approval resolves all older
259
- * findings; a nearer design approval resolves older design findings while
260
- * still allowing an older final-review request to survive. Bounded depth;
261
- * unsafe ids, mismatched state identities, cycles, and unreadable lineage
262
- * files terminate the walk with undefined.
263
- */
264
- async function readAncestorTypedRequestFact(runDir) {
265
- let currentRunDir = runDir;
266
- let currentRunId;
267
- let designResolved = false;
268
- const dagRunsRoot = path.resolve(runDir, "..", "..");
269
- const visitedRunDirs = new Set([path.resolve(runDir)]);
270
- for (let depth = 0; depth <= RERUN_FEEDBACK_LINEAGE_MAX_DEPTH; depth += 1) {
271
- const reviewTerminalKind = await readReviewTerminalKind(currentRunDir);
272
- if (currentRunId && reviewTerminalKind === "request_review_changes") {
273
- const fact = await readTypedReviewRequestFact(currentRunDir);
274
- if (fact)
275
- return { ...fact, parentRunId: currentRunId };
276
- }
277
- if (reviewTerminalKind === "approve_review")
278
- return undefined;
279
- const designTerminalKind = await readDesignTerminalKind(currentRunDir);
280
- if (currentRunId &&
281
- !designResolved &&
282
- designTerminalKind === "request_design_changes") {
283
- const fact = await readTypedDesignRequestFact(currentRunDir);
284
- if (fact)
285
- return { ...fact, parentRunId: currentRunId };
286
- }
287
- if (designTerminalKind === "approve_design")
288
- designResolved = true;
289
- if (depth === RERUN_FEEDBACK_LINEAGE_MAX_DEPTH)
290
- return undefined;
291
- let parentRunId;
292
- try {
293
- const lineage = JSON.parse(await readFile(path.join(currentRunDir, ".runtime", "rerun-task-lineage.json"), "utf8"));
294
- parentRunId = safeLineageRunId(lineage.parentRunId);
295
- }
296
- catch {
297
- return undefined;
298
- }
299
- if (!parentRunId)
300
- return undefined;
301
- let ancestorRunDir;
302
- for (const lifecycle of RERUN_FEEDBACK_LINEAGE_LIFECYCLES) {
303
- const candidate = path.join(dagRunsRoot, lifecycle, parentRunId);
304
- try {
305
- const ancestorState = JSON.parse(await readFile(path.join(candidate, "state.json"), "utf8"));
306
- if (ancestorState.runId === parentRunId) {
307
- ancestorRunDir = candidate;
308
- break;
309
- }
310
- }
311
- catch {
312
- // try next lifecycle
313
- }
314
- }
315
- if (!ancestorRunDir)
316
- return undefined;
317
- const resolvedAncestorRunDir = path.resolve(ancestorRunDir);
318
- if (visitedRunDirs.has(resolvedAncestorRunDir))
319
- return undefined;
320
- visitedRunDirs.add(resolvedAncestorRunDir);
321
- currentRunDir = ancestorRunDir;
322
- currentRunId = parentRunId;
323
- }
324
- return undefined;
325
- }
326
130
  /**
327
131
  * Derive only the latest unresolved verify/review feedback from canonical
328
132
  * parent-run facts. Provider-only failures intentionally return undefined.
@@ -340,67 +144,8 @@ export async function deriveDagRerunFeedback(input) {
340
144
  break;
341
145
  }
342
146
  }
343
- if (!sourceNodeId || !sourceNode) {
344
- // Typed terminal channel: the frontend review/design review commit their
345
- // verdicts as typed facts (request_review_changes / request_design_changes)
346
- // instead of VERDICT text, and the frontend DAG has no convergence
347
- // passHistory. Fall back to reading the typed event stores so findings
348
- // still flow into the next round as unresolved feedback. Prefer review;
349
- // if absent, fall through to the design review (a design rejection also
350
- // carries actionable findings the next plan round must consume). When
351
- // the direct parent has neither because it failed before review, walk the
352
- // rerun-task lineage chain — chained
353
- // reruns otherwise lose the grandparent's code-review findings and the
354
- // reviewer re-flags them as "unresolved previous-round feedback" (r18).
355
- // A committed approval is a resolution barrier and prevents older
356
- // findings from being resurrected.
357
- const typedFact = (await readTypedReviewRequestFact(input.runDir)) ??
358
- (await readTypedDesignRequestFact(input.runDir)) ??
359
- (await readAncestorTypedRequestFact(input.runDir));
360
- if (typedFact) {
361
- const parentSourceBindingHash = sourceBindingHash(input.spec);
362
- return withDigest({
363
- schemaVersion: 1,
364
- kind: "unresolved-terminal-feedback",
365
- parentRunId: "parentRunId" in typedFact &&
366
- typeof typedFact.parentRunId === "string"
367
- ? typedFact.parentRunId
368
- : input.parentRunId,
369
- taskId: input.taskId,
370
- sourceNodeId: typedFact.nodeId,
371
- verdict: "request-revision",
372
- failureCategory: typedFact.nodeId === FRONTEND_REVIEW_NODE_ID
373
- ? "review-request-changes"
374
- : "design-request-changes",
375
- feedbackText: scrubAndBoundFeedbackText(formatTypedReviewRequestFeedback(typedFact.fact), input.runDir, input.state.cwd),
376
- evidenceRefs: [
377
- {
378
- nodeId: typedFact.nodeId,
379
- preservedNodeRecordPath: `${typedFact.nodeId}.json`,
380
- },
381
- ],
382
- attemptSummary: {
383
- completedPasses: 1,
384
- maxPasses: 1,
385
- ...(input.state.terminalReason
386
- ? { terminalReason: input.state.terminalReason }
387
- : {}),
388
- },
389
- binding: {
390
- ...(parentSourceBindingHash
391
- ? { sourceCanonicalHash: parentSourceBindingHash }
392
- : {}),
393
- ...(input.spec.taskContractBinding?.canonicalHash
394
- ? {
395
- taskContractCanonicalHash: input.spec.taskContractBinding.canonicalHash,
396
- }
397
- : {}),
398
- status: "unknown",
399
- },
400
- });
401
- }
147
+ if (!sourceNodeId || !sourceNode)
402
148
  return undefined;
403
- }
404
149
  const completedPasses = pass?.pass ?? Math.max(1, input.state.convergence?.currentPass ?? 1);
405
150
  const maxPasses = Math.max(completedPasses, input.state.convergence?.maxPasses ?? 1);
406
151
  const parentSourceBindingHash = sourceBindingHash(input.spec);