@tea-agent/loop-agent 0.41.1 → 0.42.0-next.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +397 -5
- package/dist/adapters/context-transfer/optional-pi-handoff.js +31 -0
- package/dist/adapters/context-transfer/pi-session.js +61 -0
- package/dist/application/dag/generate-task-dag.js +75 -19
- package/dist/application/dag/run-dag.js +41 -0
- package/dist/application/task-lifecycle/advance.js +24 -5
- package/dist/application/task-lifecycle/observe.js +171 -17
- package/dist/application/task-lifecycle/plan-transitions.js +42 -7
- package/dist/application/task-lifecycle/recommendations.js +13 -2
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +19 -0
- package/dist/cli/program.js +29 -2
- package/dist/commands/client-recovery.js +3 -0
- package/dist/commands/dag-artifact.js +284 -0
- package/dist/commands/dag-context.js +184 -0
- package/dist/commands/dag-follow-up.js +138 -0
- package/dist/commands/dag-rerun-task.js +2 -0
- package/dist/commands/dag-rerun.js +206 -1
- package/dist/commands/init.js +27 -1
- package/dist/commands/task-advance.js +19 -0
- package/dist/executors/dag-pi-executor.js +4013 -86
- package/dist/executors/pi-executor.js +15 -4
- package/dist/executors/pi-read-budget-policy.js +239 -0
- package/dist/executors/pi-sdk-executor.js +3 -0
- package/dist/executors/shell-executor.js +978 -188
- package/dist/executors/shell-write-guard.js +7 -0
- package/dist/{worker → infrastructure}/console/app-data.js +4 -0
- package/dist/infrastructure/console/artifact-revision-store.js +430 -0
- package/dist/infrastructure/console/context-export-store.js +160 -0
- package/dist/infrastructure/console/dir-lock.js +132 -0
- package/dist/infrastructure/console/operation-store.js +417 -0
- package/dist/infrastructure/harness/artifact-store.js +10 -1
- package/dist/infrastructure/harness/atomic-write.js +12 -2
- package/dist/shared/context-transfer/artifact-revision.js +172 -0
- package/dist/shared/context-transfer.js +418 -0
- package/dist/shared/dag-failure-category.js +12 -0
- package/dist/shared/openspec-spec.js +70 -4
- package/dist/shared/operator/capabilities.js +21 -0
- package/dist/shared/operator/safe-run-summary.js +1 -0
- package/dist/shared/path-safety.js +93 -0
- package/dist/shared/preview.js +28 -4
- package/dist/task/config-types.js +107 -6
- package/dist/task/contract/adopt.js +4 -0
- package/dist/task/contract/import-revision.js +4 -0
- package/dist/task/contract/project.js +3 -0
- package/dist/task/contract/schema.js +2 -1
- package/dist/task/frontend-project-capability.js +203 -20
- package/dist/task/runtime.js +5 -2
- package/dist/task/source-prepare/build-draft.js +3 -3
- package/dist/task/source-prepare/fragment-inventory.js +64 -25
- package/dist/task/source-prepare/prepare.js +126 -21
- package/dist/task/source-prepare/semantic-intake.js +6 -2
- package/dist/task/source-references.js +22 -1
- package/dist/task/task-demand-routing.js +3 -0
- package/dist/worker/console/chat/chat-event-store.js +2 -2
- package/dist/worker/console/chat/model-resolver.js +7 -4
- package/dist/worker/console/chat/pi-runtime.js +86 -5
- package/dist/worker/console/chat/resource-preferences-store.js +1 -1
- package/dist/worker/console/chat/routes.js +136 -53
- package/dist/worker/console/chat/sdd-data-alignment.js +222 -0
- package/dist/worker/console/chat/session-catalog.js +2 -0
- package/dist/worker/console/chat/session-store.js +43 -1
- package/dist/worker/console/chat/shortcuts.js +18 -2
- package/dist/worker/console/chat/user-questions.js +1 -1
- package/dist/worker/console/console-update-runtime.js +1 -1
- package/dist/worker/console/context-transfer-diagnostics.js +198 -0
- package/dist/worker/console/dag-confirmation.js +1 -1
- package/dist/worker/console/dag-execution-receipt.js +1 -1
- package/dist/worker/console/doctor.js +1 -1
- package/dist/worker/console/draft-store.js +1 -1
- package/dist/worker/console/frontend-human-decision-adapter.js +19 -0
- package/dist/worker/console/frontend-split-operation-adapter.js +20 -0
- package/dist/worker/console/human-gate-token.js +1 -1
- package/dist/worker/console/index.js +6 -3
- package/dist/worker/console/interview/assessment.js +1 -1
- package/dist/worker/console/interview/session.js +1 -1
- package/dist/worker/console/operation-runner.js +45 -4
- package/dist/worker/console/operation-sse.js +1 -1
- package/dist/worker/console/operation-wait.js +1 -1
- package/dist/worker/console/operator-actions.js +273 -10
- package/dist/worker/console/operator-surface-health.js +1 -1
- package/dist/worker/console/operator-user-error.js +169 -0
- package/dist/worker/console/pi-plugins.js +57 -0
- package/dist/worker/console/pi-readiness.js +3 -2
- package/dist/worker/console/routes.js +637 -8
- package/dist/worker/console/security.js +35 -0
- package/dist/worker/console/server.js +29 -4
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-D7oU983t.js → abnfDiagram-N423BO3Z-CcS17TBr.js} +1 -1
- package/dist/worker/console/static/assets/{arc-BrKSRdFS.js → arc-COptKq2S.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-CiXV7L56.js → architectureDiagram-T3A2C74G-h4LKMHjP.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-D_Hs_gIG.js → blockDiagram-VBNYF7ZC-COA1MOH0.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-DbM-Lqqh.js → c4Diagram-5PPSVZJV-DJUf0QPm.js} +1 -1
- package/dist/worker/console/static/assets/channel-DdBCaOJ6.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-D1M8uqJw.js → chunk-2GRJ4B5K-mtWfKrUX.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-4D3RFHT6.js → chunk-2Q5K7J3B-B8pXsxDQ.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-CdwpY_n9.js → chunk-5RXB4S5H-ipKzByl1.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BLeLZ9PG.js → chunk-5VM5RSS4-DYi3Ald_.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-CeRNEMvc.js → chunk-6Q2QTUOP-DQtGYoty.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CjkHP8Vy.js → chunk-GF5L2VYU-BU0qS2YV.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-B54ZUQY-.js → chunk-JWPE2WC7-DVH9dIGE.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-4bKaMVmx.js → chunk-KBJHAD2P-Dt60SmgM.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-Cyjfznu_.js → chunk-RYQCIY6F-BoaUGuEY.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CDN-zGFV.js → chunk-XXDRQBXY-_WHFDTp2.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DZFra1GO.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DZFra1GO.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-HxJmz411.js → cose-bilkent-JH36ORCC-BxkbTIRd.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-DtSt5K2w.js → cynefin-VYW2F7L2-Bf2UVnoG.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-VtkSpRmG.js → cynefinDiagram-MW4NZA55-Bo23q1J_.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-Bj4DT4du.js → dagre-VZM6K2ZE-Dd_UU49i.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-Bpuk6BmP.js → diagram-7IWD3JNH-ebUa1a9y.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-BHYGv_yO.js → diagram-B4RE2ZJO-BucthU8r.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-DEx3WwnT.js → diagram-LBJQPF4R-BgqNpAkm.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-Cj0dS5e8.js → diagram-Q27KOJAE-DC4q5NGa.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-B97h8l21.js → diagram-UB23O5K3-CBqCaMeb.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-DMSFAhBd.js → ebnfDiagram-BXEA7PRR-CGtnbQ3-.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DhVOCbt6.js → erDiagram-JOGREHBK-CG3LUao5.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-GlakITWL.js → flowDiagram-UKHOOZJN-D2ZVgoFS.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-VxPpu9eQ.js → ganttDiagram-PKOTCBZU-DoYFZiKt.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Bs_e5DRT.js → gitGraphDiagram-DS77QQ5N-CKoP1s6j.js} +1 -1
- package/dist/worker/console/static/assets/index-CAZ2fC_X.css +1 -0
- package/dist/worker/console/static/assets/index-vbTcFnFs.js +449 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-BXYuU4Uw.js → infoDiagram-6WML65LV-Duofv8p2.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-C34erCbU.js → ishikawaDiagram-WSZJBQD7-D2nlCkA1.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DZCAiOU3.js → journeyDiagram-NVQOT4AX-Dd4IHdus.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-C9gaTdUm.js → kanban-definition-27J2QSJJ-Bi20AOdt.js} +1 -1
- package/dist/worker/console/static/assets/{linear-CvI0Z17U.js → linear-D59YJ9kB.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-DMMSIx7j.js → mermaid.core-Bl13LpNa.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-BKKP0EO6.js → mindmap-definition-FAOFIHXS-C6DLP5eY.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-C3LiFbl5.js → pegDiagram-VL7TDLO6-BjO4cy64.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-Bb3Om2Dz.js → pieDiagram-7S7Q4E2Y-D7i2qZTG.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-DNthMjzc.js → quadrantDiagram-CIZ2JOQS-Dx8o_h0y.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-miFsr4Tv.js → railroadDiagram-AXF67PYL-B55orI_t.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-yXUncmn6.js → requirementDiagram-LRYGKXZP-zWaehp6f.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-DLeWKLak.js → sankeyDiagram-W5VNT64P-CcA-pjvD.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-CI3he1R3.js → sequenceDiagram-SI44F4Z6-BOFbzNHI.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-B7jfDkS5.js → sizeCapture-X5ZJPWSS-BjAejah1.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-BmrZod7J.js → stateDiagram-OKZ733FA-DXYwxJwZ.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Clg3V9t1.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-CDOlHVSY.js → swimlanes-SLNWSIFB-OYiOch8n.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DX1dxAAW.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-Cz-XX1gy.js → timeline-definition-Z64GVDOM-cZfH3nmU.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-caV4cI8C.js → vennDiagram-T6HMQDX7-BDE7b3E1.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-dImPlnIO.js → wardleyDiagram-T6FBY63Y-kyyGy9WJ.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CtRYVJcn.js → xychartDiagram-ELKLHX3M-CJj6VTog.js} +1 -1
- package/dist/worker/console/static/index.html +7 -2
- package/dist/worker/console/static-src/active-run-badge.js +17 -0
- package/dist/worker/console/static-src/app/useOperatorActions.js +3 -2
- package/dist/worker/console/static-src/app/useRecoveryConsole.js +5 -5
- package/dist/worker/console/static-src/operator-chat/input-history.js +8 -6
- package/dist/worker/console/static-src/operator-chat/runtime-snapshot-store.js +10 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +258 -23
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +112 -4
- package/dist/worker/console/static-src/operator-chat/useComposer.js +13 -4
- package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +29 -6
- package/dist/worker/console/static-src/operator-chat/useRuntimeSnapshot.js +8 -2
- package/dist/worker/console/static-src/shell/console-update-reload.js +52 -0
- package/dist/worker/console/static-src/shell/workspace-route.js +11 -0
- package/dist/worker/console/workspace-context.js +142 -2
- package/dist/worker/console/workspace-registry.js +2 -2
- package/dist/worker/continuation/worker-continuation.js +278 -0
- package/dist/worker/materialize/frontend-split-task-materializer.js +72 -0
- package/dist/worker/observe/health.js +1 -1
- package/dist/worker/observe/node-transparency.js +572 -0
- package/dist/worker/observe/routes.js +55 -1
- package/dist/worker/observe/static/api.js +69 -5
- package/dist/worker/observe/static/dag-context-reason-labels.d.ts +9 -0
- package/dist/worker/observe/static/dag-context-reason-labels.js +120 -0
- package/dist/worker/observe/static/dag-helpers.js +4 -2
- package/dist/worker/observe/static/dag-node-purpose.js +5 -0
- package/dist/worker/observe/static/inspect-workspace.js +23 -0
- package/dist/worker/observe/static/kpi.js +2 -2
- package/dist/worker/observe/static/operator-chrome.d.ts +10 -2
- package/dist/worker/observe/static/operator-chrome.js +37 -23
- package/dist/worker/observe/static/relations.js +2 -2
- package/dist/worker/observe/static/router.d.ts +12 -1
- package/dist/worker/observe/static/router.js +48 -6
- package/dist/worker/observe/static/run-processing.js +4 -2
- package/dist/worker/observe/static/shell-chrome.js +2 -2
- package/dist/worker/observe/static/state.js +8 -1
- package/dist/worker/observe/static/styles.css +1092 -86
- package/dist/worker/observe/static/views/dag-inspector.js +1228 -64
- package/dist/worker/observe/static/views/dag.js +10 -2
- package/dist/worker/observe/static/views/dags.js +3 -1
- package/dist/worker/observe/static/views/dashboard.js +14 -6
- package/dist/worker/observe/static/views/pool.js +7 -2
- package/dist/worker/observe/static/views/run.js +12 -3
- package/dist/worker/observe/static/views/session-timeline.js +142 -18
- package/dist/worker/observe/static/views/task.js +7 -2
- package/dist/worker/outcomes/adapters.js +19 -0
- package/dist/worker/outcomes/types.js +1 -0
- package/dist/worker/pool/attempt-lease.js +97 -66
- package/dist/worker/pool/begin-attempt-with-lease.js +1 -0
- package/dist/worker/pool/reconcile.js +46 -1
- package/dist/worker/pool/run-store.js +2 -0
- package/dist/worker/pool/state-projection.js +2 -0
- package/dist/worker/task-spec/workflow-routing.js +8 -3
- package/dist/workflows/dag/artifact-bindings.js +149 -0
- package/dist/workflows/dag/artifact-revision-schema-registry.js +31 -0
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +215 -28
- package/dist/workflows/dag/backend-test-markdown-workflow.js +13 -1
- package/dist/workflows/dag/backend-test-plan-protocol.js +106 -0
- package/dist/workflows/dag/backend-test-scenario-param.js +172 -25
- package/dist/workflows/dag/backend-test-scenario-partitions.js +62 -1
- package/dist/workflows/dag/backend-test-writer-completeness.js +104 -12
- package/dist/workflows/dag/budget-enforcement.js +10 -0
- package/dist/workflows/dag/context-receipt.js +305 -0
- package/dist/workflows/dag/context-transfer/context-bundle.js +423 -0
- package/dist/workflows/dag/context-transfer/operator-actions.js +61 -0
- package/dist/workflows/dag/context-transfer/renderers.js +93 -0
- package/dist/workflows/dag/contract-validator-registrations.js +1 -2
- package/dist/workflows/dag/dag-retry-schema.js +138 -0
- package/dist/workflows/dag/frontend-closeout.js +221 -0
- package/dist/workflows/dag/frontend-design-policy.js +400 -0
- package/dist/workflows/dag/frontend-human-decision.js +182 -0
- package/dist/workflows/dag/frontend-implementation-contract.js +1237 -192
- package/dist/workflows/dag/frontend-plan-render.js +2 -1
- package/dist/workflows/dag/frontend-prewrite-gate.js +256 -350
- package/dist/workflows/dag/frontend-provider-capability-matrix.js +159 -0
- package/dist/workflows/dag/frontend-recovery-capsule.js +455 -0
- package/dist/workflows/dag/frontend-recovery-controller.js +226 -0
- package/dist/workflows/dag/frontend-recovery-lineage.js +178 -0
- package/dist/workflows/dag/frontend-recovery-plan.js +21 -10
- package/dist/workflows/dag/frontend-recovery-run.js +166 -34
- package/dist/workflows/dag/frontend-repair.js +1 -432
- package/dist/workflows/dag/frontend-review-context.js +261 -15
- package/dist/workflows/dag/frontend-review-findings.js +270 -0
- package/dist/workflows/dag/frontend-shadow-dual-write.js +941 -0
- package/dist/workflows/dag/frontend-shape-capsule-store.js +191 -0
- package/dist/workflows/dag/frontend-shape-facts.js +419 -0
- package/dist/workflows/dag/frontend-shape.js +435 -0
- package/dist/workflows/dag/frontend-source-fidelity-ledger.js +108 -0
- package/dist/workflows/dag/frontend-split-application-service.js +203 -0
- package/dist/workflows/dag/frontend-split-orchestrator.js +899 -0
- package/dist/workflows/dag/frontend-typed-event-store.js +452 -0
- package/dist/workflows/dag/frontend-typed-event-transaction.js +180 -0
- package/dist/workflows/dag/frontend-verification-trace.js +252 -25
- package/dist/workflows/dag/frontend-worktree-diff.js +250 -17
- package/dist/workflows/dag/frontend-writer-admission.js +319 -0
- package/dist/workflows/dag/frontend-writer-rollback.js +32 -0
- package/dist/workflows/dag/frontend-writer-status.js +256 -0
- package/dist/workflows/dag/init-hybrid.js +1174 -562
- package/dist/workflows/dag/interrupt-request.js +7 -0
- package/dist/workflows/dag/node-execution.js +940 -31
- package/dist/workflows/dag/path-safety.js +1 -0
- package/dist/workflows/dag/prompt.js +99 -7
- package/dist/workflows/dag/recovery-lease.js +170 -0
- package/dist/workflows/dag/report.js +37 -1
- package/dist/workflows/dag/rerun-feedback.js +315 -1
- package/dist/workflows/dag/rerun-plan.js +568 -3
- package/dist/workflows/dag/rerun-run.js +642 -18
- package/dist/workflows/dag/rerun-task.js +251 -13
- package/dist/workflows/dag/retry-policy.js +219 -104
- package/dist/workflows/dag/runner.js +596 -121
- package/dist/workflows/dag/scheduler.js +133 -20
- package/dist/workflows/dag/skill-snapshot.js +17 -0
- package/dist/workflows/dag/types.js +426 -22
- package/dist/workflows/dag/validate.js +28 -12
- package/docs/architecture/runtime-boundaries.md +6 -6
- package/docs/architecture/worker-and-feature.md +1 -1
- package/docs/examples/README.md +5 -0
- package/docs/init-surface.manifest.json +30 -12
- package/docs/skills/vetted-skill-registry.md +4 -2
- package/docs/templates/README.md +2 -0
- package/docs/templates/agent-dag-report.schema.json +8 -2
- package/docs/templates/agent-dag.schema.json +33 -1
- package/docs/templates/backend-test-dag.json +23 -20
- package/docs/templates/frontend-implementation-contract.schema.json +4 -1
- package/docs/templates/frontend-implementation-dag.json +89 -0
- package/docs/templates/product-line/task.yaml +1 -1
- package/docs/templates/spec-registry.schema.json +45 -0
- package/harness.json +1 -1
- package/package.json +6 -3
- package/skills/frontend-bounded-implement/SKILL.md +15 -14
- package/skills/frontend-bounded-implement/references/code-standards.md +19 -0
- package/skills/frontend-contract/SKILL.md +23 -0
- package/skills/frontend-contract/references/contract-protocol.md +34 -0
- package/skills/frontend-design-review/SKILL.md +22 -41
- package/skills/frontend-plan/SKILL.md +26 -0
- package/skills/frontend-plan/references/decision-contract.md +37 -0
- package/skills/frontend-plan/references/design-decisions.md +17 -0
- package/skills/frontend-review/SKILL.md +20 -15
- package/skills/frontend-review/references/review-findings.md +6 -7
- package/skills/frontend-scout/SKILL.md +25 -0
- package/skills/frontend-scout/references/design-evidence.md +16 -0
- package/skills/frontend-scout/references/scout-evidence.md +23 -0
- package/skills/frontend-verification/SKILL.md +1 -1
- package/skills/loop-agent/references/command-reference.md +7 -0
- package/skills/loop-agent/references/hybrid-dag.md +2 -2
- package/dist/worker/console/operation-store.js +0 -169
- package/dist/worker/console/static/assets/channel-D1xajGpe.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BmuGTfRr.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BmuGTfRr.js +0 -1
- package/dist/worker/console/static/assets/index-BLzcAykx.js +0 -451
- package/dist/worker/console/static/assets/index-Cs9JUSPs.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-D9ykKEWP.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BvPOXALT.js +0 -8
- package/skills/frontend-implementation/SKILL.md +0 -52
- package/skills/frontend-implementation/references/code-standards.md +0 -33
- package/skills/frontend-implementation/references/design-spec.md +0 -56
- package/skills/frontend-implementation/references/node-contracts.md +0 -31
- /package/dist/{worker → infrastructure}/console/repo-fingerprint.js +0 -0
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { DEFAULT_FRONTEND_SPEC_ROOTS, isFrontendSpecFilePath, isValidFrontendSpecRoot, OPENSPEC_SPEC_EXT_RE, } from "../../shared/openspec-spec.js";
|
|
3
3
|
import { campaignBudgetSchema, } from "../../application/evaluation/budget.js";
|
|
4
4
|
import { assertDagPromptSourceRule } from "./prompt-source.js";
|
|
5
|
-
import
|
|
5
|
+
// Leaf-module import: dagRetryPolicySchema must be defined by a module that
|
|
6
|
+
// never transitively reaches types.ts during init (retry-policy does, via
|
|
7
|
+
// frontend-recovery-capsule → frontend-recovery-lineage →
|
|
8
|
+
// frontend-implementation-contract), or a run whose entry module initializes
|
|
9
|
+
// retry-policy first reads an undefined schema here.
|
|
10
|
+
import { dagRetryPolicySchema, TARGET_TEMPLATE_TRANSIENT_RETRY_PROFILE, } from "./dag-retry-schema.js";
|
|
6
11
|
import { dagLivenessPolicySchema, } from "./liveness-policy.js";
|
|
7
12
|
import { dagOutputProtocolSchema } from "./output-protocol.js";
|
|
8
13
|
export const dagComplexitySchema = z.enum(["HIGH", "MED", "LOW"]);
|
|
@@ -80,7 +85,10 @@ export const dagShellVerifyEvidenceSchema = z.object({
|
|
|
80
85
|
selectionReasons: z.array(z.string()).default([]),
|
|
81
86
|
/** Non-executing generation-time cwd/local-script validation evidence. */
|
|
82
87
|
preflight: z
|
|
83
|
-
.array(z.object({
|
|
88
|
+
.array(z.object({
|
|
89
|
+
label: z.string(),
|
|
90
|
+
status: z.enum(["ok", "future-delivery-script", "future-test-target"]),
|
|
91
|
+
}))
|
|
84
92
|
.default([]),
|
|
85
93
|
/** Effective timeout applied independently to each shell command. */
|
|
86
94
|
commandTimeoutMs: z.number().int().positive().optional(),
|
|
@@ -185,7 +193,16 @@ const dagFrontendNodeIdSchema = z
|
|
|
185
193
|
.regex(/^[a-z][a-z0-9-]*$/, "frontend node id must be kebab-case");
|
|
186
194
|
const openspecCandidatePathSchema = z
|
|
187
195
|
.string()
|
|
188
|
-
.refine((candidate) => !candidate.includes("\\") &&
|
|
196
|
+
.refine((candidate) => !candidate.includes("\\") &&
|
|
197
|
+
!candidate.startsWith("/") &&
|
|
198
|
+
!candidate.split("/").includes("..") &&
|
|
199
|
+
OPENSPEC_SPEC_EXT_RE.test(candidate), "openspec candidate must be a repo-relative supported specification file");
|
|
200
|
+
const openspecCandidateSnapshotSchema = z
|
|
201
|
+
.object({
|
|
202
|
+
path: openspecCandidatePathSchema,
|
|
203
|
+
sha256: z.string().regex(/^[a-f0-9]{64}$/),
|
|
204
|
+
})
|
|
205
|
+
.strict();
|
|
189
206
|
export const dagFrontendPrewriteGateSchema = z.object({
|
|
190
207
|
schemaVersion: z.literal(1),
|
|
191
208
|
planFromNodeId: dagFrontendNodeIdSchema,
|
|
@@ -204,7 +221,24 @@ export const dagFrontendPrewriteGateSchema = z.object({
|
|
|
204
221
|
outputDir: z.string().regex(/^[a-z0-9][a-z0-9._-]*$/),
|
|
205
222
|
requireSourceFreshness: z.literal(true),
|
|
206
223
|
implementationWriteSet: z.array(z.string().min(1)).min(1).optional(),
|
|
224
|
+
/**
|
|
225
|
+
* Generation-frozen roots that bound custom normative directories. Omitted
|
|
226
|
+
* legacy DAGs retain the canonical OpenSpec + ai_workspace roots.
|
|
227
|
+
*/
|
|
228
|
+
openspecSpecRoots: z
|
|
229
|
+
.array(z.string().refine((root) => isValidFrontendSpecRoot(root), "openspec spec root must be a normalized repo-relative directory"))
|
|
230
|
+
.optional(),
|
|
207
231
|
openspecCandidatePaths: z.array(openspecCandidatePathSchema).default([]),
|
|
232
|
+
/** Read-only selector output; omitted for scan-strict and legacy DAGs. */
|
|
233
|
+
openspecSelectionNodeId: dagFrontendNodeIdSchema.optional(),
|
|
234
|
+
/** Contract-declared and source-explicit paths that cannot be downgraded. */
|
|
235
|
+
openspecMandatoryPaths: z.array(openspecCandidatePathSchema).optional(),
|
|
236
|
+
/**
|
|
237
|
+
* Content fingerprints frozen with the generation-time OpenSpec scope. New
|
|
238
|
+
* DAGs use these to reject a plan whose cited specification changed after it
|
|
239
|
+
* was read; legacy DAGs without the field retain existence-only drift checks.
|
|
240
|
+
*/
|
|
241
|
+
openspecCandidateSnapshots: z.array(openspecCandidateSnapshotSchema).optional(),
|
|
208
242
|
/**
|
|
209
243
|
* Generation-frozen component/theme specification bucket. Derived from
|
|
210
244
|
* `designEvidence.classified.component ∪ theme ∪ rule.components` at DAG
|
|
@@ -249,14 +283,28 @@ export const dagFrontendPrewriteGateSchema = z.object({
|
|
|
249
283
|
scanStrict: z.array(openspecCandidatePathSchema).default([]),
|
|
250
284
|
})
|
|
251
285
|
.optional(),
|
|
286
|
+
}).superRefine((gate, context) => {
|
|
287
|
+
const roots = gate.openspecSpecRoots ?? DEFAULT_FRONTEND_SPEC_ROOTS;
|
|
288
|
+
const candidateGroups = [
|
|
289
|
+
["openspecCandidatePaths", gate.openspecCandidatePaths],
|
|
290
|
+
["openspecMandatoryPaths", gate.openspecMandatoryPaths],
|
|
291
|
+
["componentSpecCandidatePaths", gate.componentSpecCandidatePaths],
|
|
292
|
+
["openspecCandidateSources.declared", gate.openspecCandidateSources?.declared],
|
|
293
|
+
["openspecCandidateSources.taskSourceCited", gate.openspecCandidateSources?.taskSourceCited],
|
|
294
|
+
["openspecCandidateSources.scanStrict", gate.openspecCandidateSources?.scanStrict],
|
|
295
|
+
];
|
|
296
|
+
for (const [field, paths] of candidateGroups) {
|
|
297
|
+
for (const [index, candidate] of (paths ?? []).entries()) {
|
|
298
|
+
if (!isFrontendSpecFilePath(candidate, roots)) {
|
|
299
|
+
context.addIssue({
|
|
300
|
+
code: z.ZodIssueCode.custom,
|
|
301
|
+
path: [...field.split("."), index],
|
|
302
|
+
message: "openspec candidate must be a supported file under the generation-frozen openspec spec roots",
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
252
307
|
});
|
|
253
|
-
export const dagFrontendLintBaselineSchema = z
|
|
254
|
-
.object({
|
|
255
|
-
schemaVersion: z.literal(1),
|
|
256
|
-
lintCommands: z.array(z.string().min(1)).min(1),
|
|
257
|
-
lintEvidence: dagShellVerifyEvidenceSchema,
|
|
258
|
-
})
|
|
259
|
-
.strict();
|
|
260
308
|
export const dagFrontendVerificationBundleSchema = z
|
|
261
309
|
.object({
|
|
262
310
|
schemaVersion: z.literal(1),
|
|
@@ -270,6 +318,10 @@ export const dagFrontendVerificationBundleSchema = z
|
|
|
270
318
|
behaviorEvidence: dagShellVerifyEvidenceSchema,
|
|
271
319
|
lintBaselineNodeId: dagFrontendNodeIdSchema.optional(),
|
|
272
320
|
writerNodeIds: z.array(dagFrontendNodeIdSchema).optional(),
|
|
321
|
+
/** "initial" = first-pass assess bundle; "repair" = the convergence
|
|
322
|
+
* loop's post-repair reverify, which re-runs the same frozen commands
|
|
323
|
+
* and fails on any failure (still no same-run repair branch inside the
|
|
324
|
+
* node itself). */
|
|
273
325
|
mode: z.enum(["initial", "repair"]),
|
|
274
326
|
})
|
|
275
327
|
.superRefine((bundle, context) => {
|
|
@@ -345,6 +397,135 @@ export const dagFrontendReviewContextSchema = z.object({
|
|
|
345
397
|
schemaVersion: z.literal(1),
|
|
346
398
|
requireBaseline: z.literal(true),
|
|
347
399
|
});
|
|
400
|
+
/**
|
|
401
|
+
* Deterministic frontend contract-import shell (micro topology). Re-validates
|
|
402
|
+
* the generation-frozen managed Contract's source/binding/schema freshness and
|
|
403
|
+
* emits a digest. It never invokes a model and never rewrites requirements —
|
|
404
|
+
* micro requires a pre-validated managed Contract, not natural-language intake.
|
|
405
|
+
*/
|
|
406
|
+
export const dagFrontendContractImportSchema = z.object({
|
|
407
|
+
schemaVersion: z.literal(1),
|
|
408
|
+
artifactName: z.string().regex(/^[a-z0-9][a-z0-9._-]*\.json$/),
|
|
409
|
+
outputDir: z.string().regex(/^[a-z0-9][a-z0-9._-]*$/),
|
|
410
|
+
requireSourceFreshness: z.literal(true),
|
|
411
|
+
});
|
|
412
|
+
/**
|
|
413
|
+
* Deterministic frontend design-policy shell (M8). Materializes the canonical
|
|
414
|
+
* implementation contract from the plan node and evaluates the design policy
|
|
415
|
+
* (Mock strategy, source freshness, component spec candidates, writeSet
|
|
416
|
+
* patterns, allowed dependencies). Runs BEFORE frontend-design-review-pi, so it
|
|
417
|
+
* never consumes a design verdict; the verdict is enforced by the writer
|
|
418
|
+
* admission shell instead. Replaces the prewrite-gate authorization path.
|
|
419
|
+
*/
|
|
420
|
+
export const dagFrontendDesignPolicySchema = z
|
|
421
|
+
.object({
|
|
422
|
+
schemaVersion: z.literal(1),
|
|
423
|
+
planFromNodeId: dagFrontendNodeIdSchema,
|
|
424
|
+
requiredRequirementIds: z
|
|
425
|
+
.array(z.string().regex(/^(?:REQ|BR|AC)-[A-Z0-9]+(?:-[A-Z0-9]+)*$/))
|
|
426
|
+
.default([]),
|
|
427
|
+
allowedMockStrategies: z
|
|
428
|
+
.array(z.enum(["native", "browser-intercept", "request-adapter", "not-needed"]))
|
|
429
|
+
.min(1),
|
|
430
|
+
/** Frozen Mock verification command labels the DAG will actually execute. */
|
|
431
|
+
mockCommandLabels: z.array(z.string()).default([]),
|
|
432
|
+
artifactName: z.string().regex(/^[a-z0-9][a-z0-9._-]*\.json$/),
|
|
433
|
+
outputDir: z.string().regex(/^[a-z0-9][a-z0-9._-]*$/),
|
|
434
|
+
requireSourceFreshness: z.literal(true),
|
|
435
|
+
implementationWriteSet: z.array(z.string().min(1)).min(1).optional(),
|
|
436
|
+
/** Generation-frozen roots that bound custom normative directories. */
|
|
437
|
+
openspecSpecRoots: z
|
|
438
|
+
.array(z.string().refine((root) => isValidFrontendSpecRoot(root), "openspec spec root must be a normalized repo-relative directory"))
|
|
439
|
+
.optional(),
|
|
440
|
+
openspecCandidatePaths: z.array(openspecCandidatePathSchema).default([]),
|
|
441
|
+
/** Read-only selector output; omitted for scan-strict and legacy DAGs. */
|
|
442
|
+
openspecSelectionNodeId: dagFrontendNodeIdSchema.optional(),
|
|
443
|
+
/** Contract-declared and source-explicit paths that cannot be downgraded. */
|
|
444
|
+
openspecMandatoryPaths: z.array(openspecCandidatePathSchema).optional(),
|
|
445
|
+
openspecCandidateSnapshots: z
|
|
446
|
+
.array(openspecCandidateSnapshotSchema)
|
|
447
|
+
.optional(),
|
|
448
|
+
/**
|
|
449
|
+
* Generation-frozen component/theme specification bucket. Derived from
|
|
450
|
+
* `designEvidence.classified.component ∪ theme ∪ rule.components` at DAG
|
|
451
|
+
* generation. When non-empty and the canonical contract has UI-visible
|
|
452
|
+
* work, the design policy requires a non-empty `uiComponentChoices` and
|
|
453
|
+
* cross-checks each `specReference.path` against this set + the effective
|
|
454
|
+
* plan openspec-citations block.
|
|
455
|
+
*/
|
|
456
|
+
componentSpecCandidatePaths: z.array(openspecCandidatePathSchema).optional(),
|
|
457
|
+
/** OpenSpec gate policy (cited | scan-strict); generation always writes it. */
|
|
458
|
+
openspecPolicy: z.enum(["cited", "scan-strict"]).optional(),
|
|
459
|
+
/** Generation-frozen candidate source metadata (diagnostic). */
|
|
460
|
+
openspecCandidateSources: z
|
|
461
|
+
.object({
|
|
462
|
+
declared: z.array(openspecCandidatePathSchema).default([]),
|
|
463
|
+
taskSourceCited: z.array(openspecCandidatePathSchema).default([]),
|
|
464
|
+
scanStrict: z.array(openspecCandidatePathSchema).default([]),
|
|
465
|
+
})
|
|
466
|
+
.optional(),
|
|
467
|
+
/** Dependency identifiers authorized at generation time (empty = none). */
|
|
468
|
+
allowedDependencies: z.array(z.string()).default([]),
|
|
469
|
+
})
|
|
470
|
+
.superRefine((gate, context) => {
|
|
471
|
+
const roots = gate.openspecSpecRoots ?? DEFAULT_FRONTEND_SPEC_ROOTS;
|
|
472
|
+
const candidateGroups = [
|
|
473
|
+
["openspecCandidatePaths", gate.openspecCandidatePaths],
|
|
474
|
+
["openspecMandatoryPaths", gate.openspecMandatoryPaths],
|
|
475
|
+
["componentSpecCandidatePaths", gate.componentSpecCandidatePaths],
|
|
476
|
+
["openspecCandidateSources.declared", gate.openspecCandidateSources?.declared],
|
|
477
|
+
["openspecCandidateSources.taskSourceCited", gate.openspecCandidateSources?.taskSourceCited],
|
|
478
|
+
["openspecCandidateSources.scanStrict", gate.openspecCandidateSources?.scanStrict],
|
|
479
|
+
];
|
|
480
|
+
for (const [field, paths] of candidateGroups) {
|
|
481
|
+
for (const [index, candidate] of (paths ?? []).entries()) {
|
|
482
|
+
if (!isFrontendSpecFilePath(candidate, roots)) {
|
|
483
|
+
context.addIssue({
|
|
484
|
+
code: z.ZodIssueCode.custom,
|
|
485
|
+
path: [...field.split("."), index],
|
|
486
|
+
message: "openspec candidate must be a supported file under the generation-frozen openspec spec roots",
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
/**
|
|
493
|
+
* Deterministic frontend writer-admission shell (M8). Runs after
|
|
494
|
+
* frontend-design-review-pi: freezes the writer baseline, derives the concrete
|
|
495
|
+
* writeSet, folds the design-policy result + design verdict into admission,
|
|
496
|
+
* and writes contracts/frontend-writer-admission-result.json
|
|
497
|
+
* (schemaId frontend-writer-admission-shell-v1).
|
|
498
|
+
*/
|
|
499
|
+
export const dagFrontendWriterAdmissionShellSchema = z
|
|
500
|
+
.object({
|
|
501
|
+
schemaVersion: z.literal(1),
|
|
502
|
+
/** Design verdict source (frontend-design-review-pi); pass is enforced.
|
|
503
|
+
* Omitted in small topology, which has no design review node. */
|
|
504
|
+
designReviewFromNodeId: dagFrontendNodeIdSchema.optional(),
|
|
505
|
+
/** Frozen command labels the verification bundle will execute. */
|
|
506
|
+
frozenCommandLabels: z.array(z.string()).default([]),
|
|
507
|
+
allowedMockStrategies: z
|
|
508
|
+
.array(z.enum(["native", "browser-intercept", "request-adapter", "not-needed"]))
|
|
509
|
+
.min(1),
|
|
510
|
+
/** Writer-preceding lint commands; baseline is materialized here (R5). */
|
|
511
|
+
lintCommands: z.array(z.string().min(1)).optional(),
|
|
512
|
+
lintEvidence: dagShellVerifyEvidenceSchema.optional(),
|
|
513
|
+
})
|
|
514
|
+
.superRefine((admission, context) => {
|
|
515
|
+
if ((admission.lintCommands?.length ?? 0) > 0 && !admission.lintEvidence) {
|
|
516
|
+
context.addIssue({
|
|
517
|
+
code: z.ZodIssueCode.custom,
|
|
518
|
+
path: ["lintEvidence"],
|
|
519
|
+
message: "lintEvidence is required when lintCommands are present",
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
/** Deterministic frontend closeout shell (M8). Renders the closeout from
|
|
524
|
+
* committed facts only (review context + typed review terminal + trace). */
|
|
525
|
+
export const dagFrontendCloseoutSchema = z.object({
|
|
526
|
+
schemaVersion: z.literal(1),
|
|
527
|
+
reviewFromNodeId: dagFrontendNodeIdSchema,
|
|
528
|
+
});
|
|
348
529
|
export const ENV_VAR_NAME_PATTERN = /^[A-Z_][A-Z0-9_]*$/;
|
|
349
530
|
export const dagVersionSchema = z
|
|
350
531
|
.union([z.literal(1), z.literal(2), z.literal(3), z.literal(4)])
|
|
@@ -392,7 +573,14 @@ export const dagWriteGuardPolicySchema = z.enum(["full", "tools-only", "filesyst
|
|
|
392
573
|
*/
|
|
393
574
|
export const dagWriterOutcomePolicySchema = z
|
|
394
575
|
.object({
|
|
395
|
-
|
|
576
|
+
/**
|
|
577
|
+
* Protocol face: `implementation-outcome-v1` keeps the legacy
|
|
578
|
+
* IMPLEMENTATION_OUTCOME first-line protocol (backend/README/module
|
|
579
|
+
* writers + frontend-repair-pi); `frontend-facts-v1` derives the status
|
|
580
|
+
* from mechanical facts (write-tool events / run delta / write guard /
|
|
581
|
+
* requirement coverage / focused-check) and never reads the first line.
|
|
582
|
+
*/
|
|
583
|
+
type: z.enum(["implementation-outcome-v1", "frontend-facts-v1"]),
|
|
396
584
|
/** Generation writers may forbid already-satisfied/no-diff completion. */
|
|
397
585
|
requireChangedFiles: z.boolean().optional(),
|
|
398
586
|
})
|
|
@@ -525,10 +713,13 @@ export const dagShellConfigSchema = z.object({
|
|
|
525
713
|
.optional(),
|
|
526
714
|
requirementCoverageGate: dagRequirementCoverageGateSchema.optional(),
|
|
527
715
|
jsonArtifactGate: dagJsonArtifactGateSchema.optional(),
|
|
716
|
+
frontendDesignPolicy: dagFrontendDesignPolicySchema.optional(),
|
|
717
|
+
frontendWriterAdmission: dagFrontendWriterAdmissionShellSchema.optional(),
|
|
528
718
|
frontendPrewriteGate: dagFrontendPrewriteGateSchema.optional(),
|
|
529
|
-
frontendLintBaseline: dagFrontendLintBaselineSchema.optional(),
|
|
530
719
|
frontendVerificationBundle: dagFrontendVerificationBundleSchema.optional(),
|
|
531
720
|
frontendReviewContext: dagFrontendReviewContextSchema.optional(),
|
|
721
|
+
frontendContractImport: dagFrontendContractImportSchema.optional(),
|
|
722
|
+
frontendCloseout: dagFrontendCloseoutSchema.optional(),
|
|
532
723
|
frontendTestCaseChecklist: dagFrontendTestCaseChecklistSchema.optional(),
|
|
533
724
|
frontendBrowserToolPreflight: dagFrontendBrowserToolPreflightSchema.optional(),
|
|
534
725
|
frontendTestStandardScenarios: dagFrontendTestStandardScenariosSchema.optional(),
|
|
@@ -734,7 +925,58 @@ export const structuredContractOutputSchemaIds = [
|
|
|
734
925
|
"frontend-implementation-contract-plan-patch-v1",
|
|
735
926
|
"frontend-implementation-contract-revision-patch-v1",
|
|
736
927
|
];
|
|
737
|
-
export const
|
|
928
|
+
export const dagArtifactIdentitySchema = z
|
|
929
|
+
.string()
|
|
930
|
+
.regex(/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/, "artifact id must be stable lower-case dot/kebab syntax");
|
|
931
|
+
const dagArtifactRelativePathSchema = z
|
|
932
|
+
.string()
|
|
933
|
+
.min(1)
|
|
934
|
+
.refine((value) => !value.includes("\0"), "artifact path must not contain NUL")
|
|
935
|
+
.refine((value) => !value.includes("\\"), "artifact path must use POSIX separators")
|
|
936
|
+
.refine((value) => !value.startsWith("/") && !/^[A-Za-z]:/.test(value), "artifact path must be run-relative")
|
|
937
|
+
.refine((value) => value.split("/").every((segment) => segment !== "" && segment !== ".."), "artifact path must not escape the run");
|
|
938
|
+
export const dagProducedArtifactSchema = z
|
|
939
|
+
.object({
|
|
940
|
+
artifactId: dagArtifactIdentitySchema,
|
|
941
|
+
kind: z.enum(["structured", "assistant", "stdout"]),
|
|
942
|
+
path: dagArtifactRelativePathSchema,
|
|
943
|
+
mediaType: z.string().min(1),
|
|
944
|
+
schemaId: z.string().min(1).optional(),
|
|
945
|
+
revisionPolicy: z.enum(["immutable", "replace-file"]),
|
|
946
|
+
})
|
|
947
|
+
.strict()
|
|
948
|
+
.superRefine((value, ctx) => {
|
|
949
|
+
if (value.kind === "structured" && !value.schemaId) {
|
|
950
|
+
ctx.addIssue({
|
|
951
|
+
code: z.ZodIssueCode.custom,
|
|
952
|
+
path: ["schemaId"],
|
|
953
|
+
message: "structured artifact requires schemaId",
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
if (value.kind !== "structured" && value.schemaId) {
|
|
957
|
+
ctx.addIssue({
|
|
958
|
+
code: z.ZodIssueCode.custom,
|
|
959
|
+
path: ["schemaId"],
|
|
960
|
+
message: "only structured artifacts may declare schemaId",
|
|
961
|
+
});
|
|
962
|
+
}
|
|
963
|
+
if (value.revisionPolicy === "replace-file" &&
|
|
964
|
+
value.kind !== "structured") {
|
|
965
|
+
ctx.addIssue({
|
|
966
|
+
code: z.ZodIssueCode.custom,
|
|
967
|
+
path: ["revisionPolicy"],
|
|
968
|
+
message: "MVP revisions are limited to structured artifacts",
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
});
|
|
972
|
+
export const dagConsumedArtifactSchema = z
|
|
973
|
+
.object({
|
|
974
|
+
artifactId: dagArtifactIdentitySchema,
|
|
975
|
+
required: z.boolean().default(true),
|
|
976
|
+
})
|
|
977
|
+
.strict();
|
|
978
|
+
export const dagTaskSchema = z.object({
|
|
979
|
+
id: z.string().regex(/^[a-z][a-z0-9-]*$/, "task id must be kebab-case"),
|
|
738
980
|
depends_on: z.array(z.string()).default([]),
|
|
739
981
|
/**
|
|
740
982
|
* How SKIPPED upstreams affect readiness.
|
|
@@ -767,6 +1009,19 @@ export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/
|
|
|
767
1009
|
role: dagRoleSchema.optional(),
|
|
768
1010
|
skills: z.array(z.string()).optional(),
|
|
769
1011
|
toolProfile: dagToolProfileSchema.optional(),
|
|
1012
|
+
/** Bounded read-only discovery budget for nodes that inspect a repository. */
|
|
1013
|
+
readBudget: z
|
|
1014
|
+
.object({
|
|
1015
|
+
maxFiles: z.number().int().positive(),
|
|
1016
|
+
maxBytes: z.number().int().positive(),
|
|
1017
|
+
maxMs: z.number().int().positive().optional(),
|
|
1018
|
+
/** Maximum read/grep/find/ls calls. */
|
|
1019
|
+
maxOperations: z.number().int().positive().optional(),
|
|
1020
|
+
/** On any read budget exhaustion, return concise completion guidance instead of failing the node. */
|
|
1021
|
+
onExhaustion: z.enum(["return-guidance"]).optional(),
|
|
1022
|
+
})
|
|
1023
|
+
.strict()
|
|
1024
|
+
.optional(),
|
|
770
1025
|
/**
|
|
771
1026
|
* Explicit Pi extension allowlist (backend implementation DAGs only):
|
|
772
1027
|
* frozen short ids resolved at run time against the Pi settings package
|
|
@@ -797,6 +1052,15 @@ export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/
|
|
|
797
1052
|
shell: dagShellConfigSchema.optional(),
|
|
798
1053
|
static: dagStaticConfigSchema.optional(),
|
|
799
1054
|
outputContract: z.string().optional(),
|
|
1055
|
+
/**
|
|
1056
|
+
* Frozen producer declarations for run-owned artifacts. These declarations,
|
|
1057
|
+
* together with consumesArtifacts, are the only authority for artifact
|
|
1058
|
+
* lineage and impact analysis. Prompt/outputContract/path heuristics are
|
|
1059
|
+
* intentionally forbidden.
|
|
1060
|
+
*/
|
|
1061
|
+
producesArtifacts: z.array(dagProducedArtifactSchema).optional(),
|
|
1062
|
+
/** Frozen logical artifact inputs consumed by this node. */
|
|
1063
|
+
consumesArtifacts: z.array(dagConsumedArtifactSchema).optional(),
|
|
800
1064
|
outputMode: dagOutputModeSchema.optional(),
|
|
801
1065
|
firstProtocolLine: z.string().min(1).optional(),
|
|
802
1066
|
/**
|
|
@@ -825,8 +1089,7 @@ export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/
|
|
|
825
1089
|
})
|
|
826
1090
|
.strict()
|
|
827
1091
|
.superRefine((value, ctx) => {
|
|
828
|
-
if (value.schemaId ===
|
|
829
|
-
"frontend-implementation-contract-plan-patch-v1" &&
|
|
1092
|
+
if (value.schemaId === "frontend-implementation-contract-plan-patch-v1" &&
|
|
830
1093
|
!value.skeleton) {
|
|
831
1094
|
ctx.addIssue({
|
|
832
1095
|
code: "custom",
|
|
@@ -881,6 +1144,121 @@ export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/
|
|
|
881
1144
|
dynamicCondition: dagDynamicConditionSchema.optional(),
|
|
882
1145
|
dynamicLoopUntil: dagDynamicLoopUntilSchema.optional(),
|
|
883
1146
|
});
|
|
1147
|
+
function hasTransitiveDependency(tasksById, consumerNodeId, producerNodeId) {
|
|
1148
|
+
const queue = [...(tasksById.get(consumerNodeId)?.depends_on ?? [])];
|
|
1149
|
+
const seen = new Set();
|
|
1150
|
+
while (queue.length > 0) {
|
|
1151
|
+
const nodeId = queue.shift();
|
|
1152
|
+
if (nodeId === producerNodeId)
|
|
1153
|
+
return true;
|
|
1154
|
+
if (seen.has(nodeId))
|
|
1155
|
+
continue;
|
|
1156
|
+
seen.add(nodeId);
|
|
1157
|
+
queue.push(...(tasksById.get(nodeId)?.depends_on ?? []));
|
|
1158
|
+
}
|
|
1159
|
+
return false;
|
|
1160
|
+
}
|
|
1161
|
+
function validateFrozenArtifactBindings(tasks, ctx) {
|
|
1162
|
+
const tasksById = new Map(tasks.map((task) => [task.id, task]));
|
|
1163
|
+
const producers = new Map();
|
|
1164
|
+
const paths = new Map();
|
|
1165
|
+
for (const [taskIndex, task] of tasks.entries()) {
|
|
1166
|
+
const localIds = new Set();
|
|
1167
|
+
for (const [artifactIndex, artifact] of (task.producesArtifacts ?? []).entries()) {
|
|
1168
|
+
if (localIds.has(artifact.artifactId) ||
|
|
1169
|
+
producers.has(artifact.artifactId)) {
|
|
1170
|
+
ctx.addIssue({
|
|
1171
|
+
code: z.ZodIssueCode.custom,
|
|
1172
|
+
path: [
|
|
1173
|
+
"tasks",
|
|
1174
|
+
taskIndex,
|
|
1175
|
+
"producesArtifacts",
|
|
1176
|
+
artifactIndex,
|
|
1177
|
+
"artifactId",
|
|
1178
|
+
],
|
|
1179
|
+
message: `artifact ${artifact.artifactId} must have exactly one producer`,
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
else {
|
|
1183
|
+
producers.set(artifact.artifactId, {
|
|
1184
|
+
nodeId: task.id,
|
|
1185
|
+
taskIndex,
|
|
1186
|
+
artifactIndex,
|
|
1187
|
+
path: artifact.path,
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1190
|
+
localIds.add(artifact.artifactId);
|
|
1191
|
+
const foldedPath = artifact.path
|
|
1192
|
+
.normalize("NFC")
|
|
1193
|
+
.toLocaleLowerCase("en-US");
|
|
1194
|
+
const existingArtifactId = paths.get(foldedPath);
|
|
1195
|
+
if (existingArtifactId && existingArtifactId !== artifact.artifactId) {
|
|
1196
|
+
ctx.addIssue({
|
|
1197
|
+
code: z.ZodIssueCode.custom,
|
|
1198
|
+
path: [
|
|
1199
|
+
"tasks",
|
|
1200
|
+
taskIndex,
|
|
1201
|
+
"producesArtifacts",
|
|
1202
|
+
artifactIndex,
|
|
1203
|
+
"path",
|
|
1204
|
+
],
|
|
1205
|
+
message: `artifact path collides with ${existingArtifactId} under case folding`,
|
|
1206
|
+
});
|
|
1207
|
+
}
|
|
1208
|
+
else {
|
|
1209
|
+
paths.set(foldedPath, artifact.artifactId);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
for (const [taskIndex, task] of tasks.entries()) {
|
|
1214
|
+
const consumed = new Set();
|
|
1215
|
+
for (const [artifactIndex, binding] of (task.consumesArtifacts ?? []).entries()) {
|
|
1216
|
+
if (consumed.has(binding.artifactId)) {
|
|
1217
|
+
ctx.addIssue({
|
|
1218
|
+
code: z.ZodIssueCode.custom,
|
|
1219
|
+
path: [
|
|
1220
|
+
"tasks",
|
|
1221
|
+
taskIndex,
|
|
1222
|
+
"consumesArtifacts",
|
|
1223
|
+
artifactIndex,
|
|
1224
|
+
"artifactId",
|
|
1225
|
+
],
|
|
1226
|
+
message: `artifact ${binding.artifactId} is consumed more than once by ${task.id}`,
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
consumed.add(binding.artifactId);
|
|
1230
|
+
const producer = producers.get(binding.artifactId);
|
|
1231
|
+
if (!producer) {
|
|
1232
|
+
ctx.addIssue({
|
|
1233
|
+
code: z.ZodIssueCode.custom,
|
|
1234
|
+
path: [
|
|
1235
|
+
"tasks",
|
|
1236
|
+
taskIndex,
|
|
1237
|
+
"consumesArtifacts",
|
|
1238
|
+
artifactIndex,
|
|
1239
|
+
"artifactId",
|
|
1240
|
+
],
|
|
1241
|
+
message: `artifact ${binding.artifactId} has no declared producer`,
|
|
1242
|
+
});
|
|
1243
|
+
continue;
|
|
1244
|
+
}
|
|
1245
|
+
if (producer.nodeId === task.id ||
|
|
1246
|
+
!hasTransitiveDependency(tasksById, task.id, producer.nodeId)) {
|
|
1247
|
+
ctx.addIssue({
|
|
1248
|
+
code: z.ZodIssueCode.custom,
|
|
1249
|
+
path: [
|
|
1250
|
+
"tasks",
|
|
1251
|
+
taskIndex,
|
|
1252
|
+
"consumesArtifacts",
|
|
1253
|
+
artifactIndex,
|
|
1254
|
+
"artifactId",
|
|
1255
|
+
],
|
|
1256
|
+
message: `consumer ${task.id} must be downstream of producer ${producer.nodeId}`,
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
884
1262
|
export const dagModelsSchema = z
|
|
885
1263
|
.object({
|
|
886
1264
|
HIGH: z.string().optional(),
|
|
@@ -910,9 +1288,7 @@ export const dagBudgetSchema = campaignBudgetSchema;
|
|
|
910
1288
|
export const dagSourceBindingSourceSchema = z.object({
|
|
911
1289
|
kind: z.enum(["requirement", "constraint", "reference"]),
|
|
912
1290
|
path: z.string().min(1),
|
|
913
|
-
sha256: z
|
|
914
|
-
.string()
|
|
915
|
-
.regex(/^[a-f0-9]{64}$/, "sha256 must be lowercase hex"),
|
|
1291
|
+
sha256: z.string().regex(/^[a-f0-9]{64}$/, "sha256 must be lowercase hex"),
|
|
916
1292
|
});
|
|
917
1293
|
/**
|
|
918
1294
|
* DagSourceBinding v1:无 ledger 字段(schemaVersion=1,.strict() 拒绝 ledger
|
|
@@ -1014,6 +1390,22 @@ export const dagSpecSchema = z
|
|
|
1014
1390
|
taskContractBinding: dagTaskContractBindingSchema.optional(),
|
|
1015
1391
|
/** Optional unresolved parent-run feedback for a full task rerun. */
|
|
1016
1392
|
rerunFeedback: dagRerunFeedbackSchema.optional(),
|
|
1393
|
+
/** Frontend recovery continuation quota (frozen at generation time from
|
|
1394
|
+
* task.json frontendRecovery.maxContinuations). Bounds how many times a
|
|
1395
|
+
* failed frontend run may auto-recover via M6 recovery operations before
|
|
1396
|
+
* the run stays failed and needs human intervention. */
|
|
1397
|
+
frontendRecovery: z
|
|
1398
|
+
.object({
|
|
1399
|
+
maxContinuations: z
|
|
1400
|
+
.number()
|
|
1401
|
+
.int()
|
|
1402
|
+
.min(1)
|
|
1403
|
+
.max(5)
|
|
1404
|
+
.optional()
|
|
1405
|
+
.default(1),
|
|
1406
|
+
})
|
|
1407
|
+
.strict()
|
|
1408
|
+
.optional(),
|
|
1017
1409
|
/** Backend-test-only workspace mutation control; absent means Git. */
|
|
1018
1410
|
backendTestWorkspaceControl: z.enum(["git", "filesystem-only"]).optional(),
|
|
1019
1411
|
/** Frozen backend-test artifact layout (plan A); absent = historical default testcase/ layout. */
|
|
@@ -1063,6 +1455,7 @@ export const dagSpecSchema = z
|
|
|
1063
1455
|
})
|
|
1064
1456
|
.superRefine((spec, ctx) => {
|
|
1065
1457
|
const supportsV3Fields = spec.version === 3 || spec.version === 4;
|
|
1458
|
+
validateFrozenArtifactBindings(spec.tasks, ctx);
|
|
1066
1459
|
if (spec.evaluation && !supportsV3Fields) {
|
|
1067
1460
|
ctx.addIssue({
|
|
1068
1461
|
code: z.ZodIssueCode.custom,
|
|
@@ -1139,6 +1532,9 @@ export const FRONTEND_RECOVERY_RESULT_SCHEMA_VERSION = 1;
|
|
|
1139
1532
|
* Phase 3a parents converge first, so `rollback-pending` is not produced and
|
|
1140
1533
|
* was removed by AC-1; the phase starts at `child-staging` and ends at
|
|
1141
1534
|
* `settled`.
|
|
1535
|
+
*
|
|
1536
|
+
* @deprecated Read-only compatibility only; the M6 operation controller no
|
|
1537
|
+
* longer uses this phase as the authoritative recovery entry point.
|
|
1142
1538
|
*/
|
|
1143
1539
|
export const frontendRecoveryPhaseSchema = z.enum([
|
|
1144
1540
|
"child-staging",
|
|
@@ -1152,12 +1548,16 @@ export const frontendRecoveryPhaseSchema = z.enum([
|
|
|
1152
1548
|
* the child carries a frozen lineage snapshot so the activation gate can prove
|
|
1153
1549
|
* it is the reserved child of a child-running parent.
|
|
1154
1550
|
*
|
|
1155
|
-
* Invariants: `attemptIndex
|
|
1551
|
+
* Invariants: `attemptIndex` and `continuationCount` are bounded by the frozen
|
|
1552
|
+
* frontend recovery quota (currently 1-5); a child's
|
|
1156
1553
|
* `recoveryRootRunId` always equals the root runId; `revision` is the CAS
|
|
1157
1554
|
* pre-comparison counter. `revision` monotonicity is enforced at runtime by the
|
|
1158
1555
|
* runner's `(existing?.revision ?? 0) + 1` CAS write (the schema only bounds it
|
|
1159
1556
|
* non-negative). `childRunId` may be absent through `child-activating` and must
|
|
1160
1557
|
* be non-empty from `child-running` onward.
|
|
1558
|
+
*
|
|
1559
|
+
* @deprecated Read-only compatibility only; the runner no longer writes this
|
|
1560
|
+
* intent (the M6 operation controller supervises recovery instead).
|
|
1161
1561
|
*/
|
|
1162
1562
|
export const frontendRecoveryStateSchema = z
|
|
1163
1563
|
.object({
|
|
@@ -1168,8 +1568,8 @@ export const frontendRecoveryStateSchema = z
|
|
|
1168
1568
|
parentRunId: z.string().min(1),
|
|
1169
1569
|
childRunId: z.string().min(1).optional(),
|
|
1170
1570
|
attemptId: z.string().min(1),
|
|
1171
|
-
attemptIndex: z.number().int().min(0).max(
|
|
1172
|
-
continuationCount: z.number().int().min(0).max(
|
|
1571
|
+
attemptIndex: z.number().int().min(0).max(5),
|
|
1572
|
+
continuationCount: z.number().int().min(0).max(5),
|
|
1173
1573
|
/** Node id of the reset-closure root: frontend-plan-pi /
|
|
1174
1574
|
* frontend-plan-revision-pi / frontend-prewrite-gate-shell /
|
|
1175
1575
|
* frontend-implement-pi (writer partial write). */
|
|
@@ -1229,6 +1629,10 @@ export const frontendRecoveryEvidenceRefSchema = z
|
|
|
1229
1629
|
* stays permissive (failureClass optional, evidenceRefs may be empty) so it
|
|
1230
1630
|
* accepts the runner's actual phase-3a products, which do not always carry a
|
|
1231
1631
|
* failure class or evidence reference.
|
|
1632
|
+
*
|
|
1633
|
+
* @deprecated Read-only compatibility only; the M6 operation controller writes
|
|
1634
|
+
* `recovered`/`auto-recovery-blocked` results directly and never uses this
|
|
1635
|
+
* schema as the authoritative recovery settlement.
|
|
1232
1636
|
*/
|
|
1233
1637
|
export const frontendRecoveryResultSchema = z
|
|
1234
1638
|
.object({
|
|
@@ -3,7 +3,7 @@ import { resolveShellCommands } from "../../executors/shell-executor.js";
|
|
|
3
3
|
import { pathMatchesPattern } from "../../shared/git-progress.js";
|
|
4
4
|
import { resolveRepairTaskForGate } from "./repair-artifact.js";
|
|
5
5
|
import { topoSortToRanks } from "./topo.js";
|
|
6
|
-
import { isSafeReadOnlyPiRetryCandidate, isWriterEmptyDiffRetryCandidate, isWriterTransportRetryCandidate, INCOMPLETE_WRITE_SET_RETRY_CATEGORY, WRITER_CLEAN_TIMEOUT_RETRY_CATEGORY, WRITER_EMPTY_DIFF_RETRY_CATEGORY, } from "./retry-policy.js";
|
|
6
|
+
import { isSafeReadOnlyPiRetryCandidate, isWriterEmptyDiffRetryCandidate, isWriterTransportRetryCandidate, INCOMPLETE_WRITE_SET_RETRY_CATEGORY, WRITER_CLEAN_TIMEOUT_RETRY_CATEGORY, WRITER_EMPTY_DIFF_RETRY_CATEGORY, CONTEXT_OVERFLOW_RETRY_CATEGORY, } from "./retry-policy.js";
|
|
7
7
|
import { isBackendTestCompletenessRetryCandidate } from "./backend-test-writer-completeness.js";
|
|
8
8
|
import { defaultFrontendTestLayout, frontendTestLayoutFromSpec, } from "./frontend-test-layout.js";
|
|
9
9
|
const GOVERNANCE_WARNING_TYPES = new Set([
|
|
@@ -464,7 +464,9 @@ function validateShellTaskConfig(task, spec, issues) {
|
|
|
464
464
|
if (commands.length === 0 &&
|
|
465
465
|
!shell.jsonArtifactGate &&
|
|
466
466
|
!shell.backendTestPipeline &&
|
|
467
|
-
!shell.
|
|
467
|
+
!shell.frontendDesignPolicy &&
|
|
468
|
+
!shell.frontendWriterAdmission &&
|
|
469
|
+
!shell.frontendCloseout &&
|
|
468
470
|
!shell.frontendBrowserToolPreflight &&
|
|
469
471
|
!shell.frontendTestStandardScenarios &&
|
|
470
472
|
!shell.frontendTestEnvironmentProbe &&
|
|
@@ -537,18 +539,26 @@ function validateShellTaskConfig(task, spec, issues) {
|
|
|
537
539
|
}
|
|
538
540
|
}
|
|
539
541
|
}
|
|
540
|
-
if (shell.
|
|
541
|
-
const sourceNodeIds = [
|
|
542
|
-
shell.frontendPrewriteGate.planFromNodeId,
|
|
543
|
-
...shell.frontendPrewriteGate.planFallbackFromNodeIds,
|
|
544
|
-
shell.frontendPrewriteGate.reviewFromNodeId,
|
|
545
|
-
...shell.frontendPrewriteGate.reviewFallbackFromNodeIds,
|
|
546
|
-
];
|
|
542
|
+
if (shell.frontendDesignPolicy) {
|
|
543
|
+
const sourceNodeIds = [shell.frontendDesignPolicy.planFromNodeId];
|
|
547
544
|
for (const sourceNodeId of new Set(sourceNodeIds)) {
|
|
548
545
|
if (!task.depends_on.includes(sourceNodeId)) {
|
|
549
546
|
issues.push({
|
|
550
547
|
type: "missing-dependency",
|
|
551
|
-
message: `shell task ${task.id}
|
|
548
|
+
message: `shell task ${task.id} frontendDesignPolicy source ${sourceNodeId} must be a direct dependency`,
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if (shell.frontendWriterAdmission) {
|
|
554
|
+
const sourceNodeIds = shell.frontendWriterAdmission.designReviewFromNodeId
|
|
555
|
+
? [shell.frontendWriterAdmission.designReviewFromNodeId]
|
|
556
|
+
: [];
|
|
557
|
+
for (const sourceNodeId of new Set(sourceNodeIds)) {
|
|
558
|
+
if (!task.depends_on.includes(sourceNodeId)) {
|
|
559
|
+
issues.push({
|
|
560
|
+
type: "missing-dependency",
|
|
561
|
+
message: `shell task ${task.id} frontendWriterAdmission source ${sourceNodeId} must be a direct dependency`,
|
|
552
562
|
});
|
|
553
563
|
}
|
|
554
564
|
}
|
|
@@ -646,12 +656,18 @@ function validateRetryPolicyTaskConfig(task, issues) {
|
|
|
646
656
|
}
|
|
647
657
|
if (isWriterTransportCandidate) {
|
|
648
658
|
const categories = new Set(task.retryPolicy.retryCategories);
|
|
659
|
+
const allowedWriterTransportCategories = new Set([
|
|
660
|
+
WRITER_CLEAN_TIMEOUT_RETRY_CATEGORY,
|
|
661
|
+
CONTEXT_OVERFLOW_RETRY_CATEGORY,
|
|
662
|
+
]);
|
|
663
|
+
const allAllowed = [...categories].every((category) => allowedWriterTransportCategories.has(category));
|
|
649
664
|
if (task.retryPolicy.maxAttempts !== 2 ||
|
|
650
|
-
categories.size
|
|
665
|
+
categories.size === 0 ||
|
|
666
|
+
!allAllowed ||
|
|
651
667
|
!categories.has(WRITER_CLEAN_TIMEOUT_RETRY_CATEGORY)) {
|
|
652
668
|
issues.push({
|
|
653
669
|
type: "invalid-retry-policy",
|
|
654
|
-
message: `task ${task.id} writer transport retryPolicy must use exactly two total attempts and only
|
|
670
|
+
message: `task ${task.id} writer transport retryPolicy must use exactly two total attempts and only writer-clean-timeout (plus optional context-overflow)`,
|
|
655
671
|
});
|
|
656
672
|
}
|
|
657
673
|
}
|