@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
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { link, lstat, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { buildContextBundle } from "../workflows/dag/context-transfer/context-bundle.js";
|
|
5
|
+
import { effectiveNodeContextV1Schema } from "../shared/context-transfer.js";
|
|
6
|
+
import { locateDagRun } from "../workflows/dag/lifecycle.js";
|
|
7
|
+
function parseContextArgs(args) {
|
|
8
|
+
const action = args[0];
|
|
9
|
+
if (action !== "show" && action !== "export") {
|
|
10
|
+
throw new Error("usage: dag context <show|export> --run-id <id> --node-id <id> --attempt <n> [--json]");
|
|
11
|
+
}
|
|
12
|
+
let runId = "";
|
|
13
|
+
let nodeId = "";
|
|
14
|
+
let attempt = 0;
|
|
15
|
+
let json = false;
|
|
16
|
+
let target = "generic";
|
|
17
|
+
let profile = "redacted";
|
|
18
|
+
let output;
|
|
19
|
+
let acknowledgeSensitiveData = false;
|
|
20
|
+
for (let index = 1; index < args.length; index += 1) {
|
|
21
|
+
const arg = args[index];
|
|
22
|
+
if (arg === "--run-id")
|
|
23
|
+
runId = args[++index] ?? "";
|
|
24
|
+
else if (arg.startsWith("--run-id="))
|
|
25
|
+
runId = arg.slice(9);
|
|
26
|
+
else if (arg === "--node-id")
|
|
27
|
+
nodeId = args[++index] ?? "";
|
|
28
|
+
else if (arg.startsWith("--node-id="))
|
|
29
|
+
nodeId = arg.slice(10);
|
|
30
|
+
else if (arg === "--attempt")
|
|
31
|
+
attempt = Number(args[++index]);
|
|
32
|
+
else if (arg.startsWith("--attempt="))
|
|
33
|
+
attempt = Number(arg.slice(10));
|
|
34
|
+
else if (arg === "--target")
|
|
35
|
+
target = (args[++index] ?? "");
|
|
36
|
+
else if (arg.startsWith("--target="))
|
|
37
|
+
target = arg.slice(9);
|
|
38
|
+
else if (arg === "--redaction")
|
|
39
|
+
profile = (args[++index] ?? "");
|
|
40
|
+
else if (arg.startsWith("--redaction="))
|
|
41
|
+
profile = arg.slice(12);
|
|
42
|
+
else if (arg === "--output")
|
|
43
|
+
output = args[++index];
|
|
44
|
+
else if (arg.startsWith("--output="))
|
|
45
|
+
output = arg.slice(9);
|
|
46
|
+
else if (arg === "--acknowledge-sensitive-data")
|
|
47
|
+
acknowledgeSensitiveData = true;
|
|
48
|
+
else if (arg === "--json")
|
|
49
|
+
json = true;
|
|
50
|
+
else
|
|
51
|
+
throw new Error(`unknown dag context flag: ${arg}`);
|
|
52
|
+
}
|
|
53
|
+
if (!runId || !nodeId || !Number.isSafeInteger(attempt) || attempt < 1) {
|
|
54
|
+
throw new Error("dag context requires --run-id, --node-id, and positive --attempt");
|
|
55
|
+
}
|
|
56
|
+
if (!["generic", "pi-session", "pi-handoff", "readable"].includes(target)) {
|
|
57
|
+
throw new Error(`unsupported context target: ${target}`);
|
|
58
|
+
}
|
|
59
|
+
if (profile !== "redacted" && profile !== "raw") {
|
|
60
|
+
throw new Error(`unsupported redaction profile: ${profile}`);
|
|
61
|
+
}
|
|
62
|
+
if (action === "export" && !output) {
|
|
63
|
+
throw new Error("dag context export requires --output <path>");
|
|
64
|
+
}
|
|
65
|
+
if (action === "export" && profile === "raw" && !acknowledgeSensitiveData) {
|
|
66
|
+
throw new Error("raw context export requires --acknowledge-sensitive-data");
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
action,
|
|
70
|
+
runId,
|
|
71
|
+
nodeId,
|
|
72
|
+
attempt,
|
|
73
|
+
json,
|
|
74
|
+
target,
|
|
75
|
+
profile,
|
|
76
|
+
...(output ? { output } : {}),
|
|
77
|
+
acknowledgeSensitiveData,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function receiptPath(runDir, nodeId, attempt) {
|
|
81
|
+
return path.join(runDir, nodeId, "context-receipts", `attempt-${attempt}.json`);
|
|
82
|
+
}
|
|
83
|
+
function outputLabel(repoRoot, outputPath) {
|
|
84
|
+
const relative = path
|
|
85
|
+
.relative(repoRoot, outputPath)
|
|
86
|
+
.split(path.sep)
|
|
87
|
+
.join("/");
|
|
88
|
+
return relative && !relative.startsWith("../") && relative !== ".."
|
|
89
|
+
? relative
|
|
90
|
+
: path.basename(outputPath);
|
|
91
|
+
}
|
|
92
|
+
export async function runDagContextCore(repoRoot, args) {
|
|
93
|
+
const input = parseContextArgs(args);
|
|
94
|
+
const located = await locateDagRun(repoRoot, input.runId);
|
|
95
|
+
if (!located)
|
|
96
|
+
throw new Error(`dag run not found: ${input.runId}`);
|
|
97
|
+
if (input.action === "show") {
|
|
98
|
+
let receipt;
|
|
99
|
+
try {
|
|
100
|
+
receipt = effectiveNodeContextV1Schema.parse(JSON.parse(await readFile(receiptPath(located.runDir, input.nodeId, input.attempt), "utf8")));
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
throw new Error("CONTEXT_RECEIPT_MISSING");
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
schemaVersion: 1,
|
|
107
|
+
runId: input.runId,
|
|
108
|
+
nodeId: input.nodeId,
|
|
109
|
+
attempt: input.attempt,
|
|
110
|
+
capturedAt: receipt.identity.capturedAt,
|
|
111
|
+
contextDigest: receipt.contextDigest,
|
|
112
|
+
componentCount: receipt.orderedComponents.length,
|
|
113
|
+
truncationCount: receipt.promptAssembly.truncations.length,
|
|
114
|
+
runtime: {
|
|
115
|
+
executor: receipt.runtime.executor,
|
|
116
|
+
model: receipt.runtime.resolvedModel ?? receipt.runtime.modelHint ?? null,
|
|
117
|
+
skills: receipt.runtime.skills,
|
|
118
|
+
extensions: receipt.runtime.extensions,
|
|
119
|
+
tools: receipt.runtime.activeTools,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const outputPath = path.resolve(repoRoot, input.output);
|
|
124
|
+
const parent = path.dirname(outputPath);
|
|
125
|
+
const parentStat = await lstat(parent).catch(() => undefined);
|
|
126
|
+
if (parentStat?.isSymbolicLink())
|
|
127
|
+
throw new Error("unsafe output parent symlink");
|
|
128
|
+
const existing = await lstat(outputPath).catch(() => undefined);
|
|
129
|
+
if (existing)
|
|
130
|
+
throw new Error("context export output already exists");
|
|
131
|
+
const bundle = await buildContextBundle({
|
|
132
|
+
runDir: located.runDir,
|
|
133
|
+
runId: input.runId,
|
|
134
|
+
nodeId: input.nodeId,
|
|
135
|
+
attempt: input.attempt,
|
|
136
|
+
profile: input.profile,
|
|
137
|
+
target: input.target,
|
|
138
|
+
...(input.profile === "raw" && input.acknowledgeSensitiveData
|
|
139
|
+
? {
|
|
140
|
+
rawAcknowledgement: {
|
|
141
|
+
requestId: `cli-${bundleRequestIdentity(input)}`,
|
|
142
|
+
acknowledgedAt: new Date().toISOString(),
|
|
143
|
+
},
|
|
144
|
+
}
|
|
145
|
+
: {}),
|
|
146
|
+
});
|
|
147
|
+
const temporaryPath = `${outputPath}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
|
|
148
|
+
try {
|
|
149
|
+
await writeFile(temporaryPath, bundle.zipBytes, { flag: "wx", mode: 0o600 });
|
|
150
|
+
await link(temporaryPath, outputPath);
|
|
151
|
+
await rm(temporaryPath, { force: true });
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
await rm(temporaryPath, { force: true }).catch(() => undefined);
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
schemaVersion: 1,
|
|
159
|
+
bundleId: bundle.manifest.bundleId,
|
|
160
|
+
bundleSha256: bundle.manifest.bundleSha256,
|
|
161
|
+
profile: bundle.manifest.profile,
|
|
162
|
+
target: bundle.manifest.target,
|
|
163
|
+
bytes: bundle.zipBytes.byteLength,
|
|
164
|
+
output: outputLabel(repoRoot, outputPath),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
export async function runDagContext(repoRoot, args) {
|
|
168
|
+
const input = parseContextArgs(args);
|
|
169
|
+
const result = await runDagContextCore(repoRoot, args);
|
|
170
|
+
if (input.action === "show") {
|
|
171
|
+
const summary = result;
|
|
172
|
+
process.stdout.write(input.json
|
|
173
|
+
? `${JSON.stringify(result, null, 2)}\n`
|
|
174
|
+
: `Context ${summary.runId}/${summary.nodeId} attempt ${summary.attempt}\nDigest: ${summary.contextDigest}\nComponents: ${summary.componentCount}\n`);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const exported = result;
|
|
178
|
+
process.stdout.write(input.json
|
|
179
|
+
? `${JSON.stringify(result, null, 2)}\n`
|
|
180
|
+
: `Exported ${exported.bundleId} to ${exported.output} (${exported.bytes} bytes)\n`);
|
|
181
|
+
}
|
|
182
|
+
function bundleRequestIdentity(input) {
|
|
183
|
+
return `${input.runId}-${input.nodeId}-${input.attempt}`.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
184
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { mkdir } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { FRONTEND_REVIEW_FINDINGS_PRD_REL, readFrontendReviewFindingsPrd, } from "../workflows/dag/frontend-review-findings.js";
|
|
4
|
+
import { locateDagRun } from "../workflows/dag/lifecycle.js";
|
|
5
|
+
import { createTask, getTaskPaths } from "../task/runtime.js";
|
|
6
|
+
import { importPrdDocument } from "../task/source-references.js";
|
|
7
|
+
function parseFlagValue(rawArgs, flag) {
|
|
8
|
+
const index = rawArgs.indexOf(flag);
|
|
9
|
+
if (index < 0 || index + 1 >= rawArgs.length)
|
|
10
|
+
return undefined;
|
|
11
|
+
return rawArgs[index + 1];
|
|
12
|
+
}
|
|
13
|
+
export function parseDagFollowUpArgs(rawArgs) {
|
|
14
|
+
const positional = rawArgs.filter((arg) => !arg.startsWith("-"));
|
|
15
|
+
const parentRunId = positional[0];
|
|
16
|
+
if (!parentRunId) {
|
|
17
|
+
throw new Error("usage: dag follow-up <parent-run-id> [--task-id <id>] [--execute] [--profile <profile>]");
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
parentRunId,
|
|
21
|
+
taskId: parseFlagValue(rawArgs, "--task-id"),
|
|
22
|
+
execute: rawArgs.includes("--execute"),
|
|
23
|
+
profile: parseFlagValue(rawArgs, "--profile"),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function deriveFollowUpTaskId(parentRunId) {
|
|
27
|
+
// Deterministic, valid task id derived from the parent run id.
|
|
28
|
+
return `${parentRunId}-followup`;
|
|
29
|
+
}
|
|
30
|
+
/** CLI entry: parse raw args and run the follow-up flow. */
|
|
31
|
+
export async function runDagFollowUp(repoRoot, rawArgs) {
|
|
32
|
+
const parsed = parseDagFollowUpArgs(rawArgs);
|
|
33
|
+
const result = await runDagFollowUpInternal(repoRoot, parsed.parentRunId, {
|
|
34
|
+
taskId: parsed.taskId,
|
|
35
|
+
execute: parsed.execute,
|
|
36
|
+
profile: parsed.profile,
|
|
37
|
+
});
|
|
38
|
+
console.log(JSON.stringify(result, null, 2));
|
|
39
|
+
if (!result.ok) {
|
|
40
|
+
process.exitCode = result.mode === "blocked" ? 2 : 1;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export async function runDagFollowUpInternal(repoRoot, parentRunId, options = {}) {
|
|
44
|
+
const located = await locateDagRun(repoRoot, parentRunId);
|
|
45
|
+
if (!located) {
|
|
46
|
+
return {
|
|
47
|
+
ok: false,
|
|
48
|
+
mode: "invalid",
|
|
49
|
+
reason: `dag run not found: ${parentRunId}`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const prd = await readFrontendReviewFindingsPrd(located.runDir);
|
|
53
|
+
if (!prd) {
|
|
54
|
+
return {
|
|
55
|
+
ok: false,
|
|
56
|
+
mode: "invalid",
|
|
57
|
+
reason: `no frontend review findings PRD found in run ${parentRunId} (${FRONTEND_REVIEW_FINDINGS_PRD_REL}); the review must have committed request_review_changes`,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const taskId = options.taskId ?? deriveFollowUpTaskId(parentRunId);
|
|
61
|
+
try {
|
|
62
|
+
await createTask(repoRoot, taskId, `修复 review 发现(parent ${parentRunId})`);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
return {
|
|
66
|
+
ok: false,
|
|
67
|
+
mode: "blocked",
|
|
68
|
+
reason: `failed to create task ${taskId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// Materialize the PRD draft into the task's source directory so the task
|
|
72
|
+
// lifecycle can import it as its requirement.
|
|
73
|
+
const prdMaterialized = path.join(getTaskPaths(repoRoot, taskId).sourceDir, "review-findings-prd.md");
|
|
74
|
+
try {
|
|
75
|
+
await mkdir(path.dirname(prdMaterialized), { recursive: true });
|
|
76
|
+
await importPrdDocument({
|
|
77
|
+
repoRoot,
|
|
78
|
+
taskId,
|
|
79
|
+
filePath: path.join(located.runDir, FRONTEND_REVIEW_FINDINGS_PRD_REL),
|
|
80
|
+
name: "review-findings-prd",
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return {
|
|
85
|
+
ok: false,
|
|
86
|
+
mode: "blocked",
|
|
87
|
+
reason: `failed to import PRD into task ${taskId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (!options.execute) {
|
|
91
|
+
return {
|
|
92
|
+
ok: true,
|
|
93
|
+
mode: "created",
|
|
94
|
+
taskId,
|
|
95
|
+
prdPath: prdMaterialized,
|
|
96
|
+
next: {
|
|
97
|
+
kind: "advance",
|
|
98
|
+
command: `loop-agent task advance ${taskId} --task-kind frontend-implementation --json`,
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
// Execute: advance through the frontend DAG.
|
|
103
|
+
const { advanceTaskLifecycle } = await import("../application/task-lifecycle/advance.js");
|
|
104
|
+
const profile = options.profile === "auto" ||
|
|
105
|
+
options.profile === "minimal" ||
|
|
106
|
+
options.profile === "standard" ||
|
|
107
|
+
options.profile === "reviewed" ||
|
|
108
|
+
options.profile === "supervised"
|
|
109
|
+
? options.profile
|
|
110
|
+
: undefined;
|
|
111
|
+
const result = await advanceTaskLifecycle({
|
|
112
|
+
repoRoot,
|
|
113
|
+
taskId,
|
|
114
|
+
taskKind: "frontend-implementation",
|
|
115
|
+
taskKindExplicit: true,
|
|
116
|
+
...(profile ? { profile, profileExplicit: true } : {}),
|
|
117
|
+
observer: undefined,
|
|
118
|
+
});
|
|
119
|
+
const ok = result.lifecycleState === "run-succeeded" ||
|
|
120
|
+
result.lifecycleState === "awaiting-write-set-approval";
|
|
121
|
+
return {
|
|
122
|
+
ok,
|
|
123
|
+
mode: ok ? "created" : "blocked",
|
|
124
|
+
taskId,
|
|
125
|
+
prdPath: prdMaterialized,
|
|
126
|
+
reason: ok
|
|
127
|
+
? undefined
|
|
128
|
+
: `advance lifecycleState: ${result.lifecycleState}${result.blockers.length > 0
|
|
129
|
+
? `; blockers: ${result.blockers.map((b) => b.code).join(", ")}`
|
|
130
|
+
: ""}`,
|
|
131
|
+
next: ok
|
|
132
|
+
? undefined
|
|
133
|
+
: {
|
|
134
|
+
kind: "advance",
|
|
135
|
+
command: `loop-agent task advance ${taskId} --task-kind frontend-implementation --json`,
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
@@ -11,6 +11,8 @@ export async function runDagRerunTask(repoRoot, rawArgs) {
|
|
|
11
11
|
profileExplicit: parsed.profileExplicit,
|
|
12
12
|
taskIdOverride: parsed.taskIdOverride,
|
|
13
13
|
execute: parsed.execute,
|
|
14
|
+
frontendRecovery: parsed.frontendRecovery,
|
|
15
|
+
recoveryOperationId: parsed.recoveryOperationId,
|
|
14
16
|
});
|
|
15
17
|
console.log(JSON.stringify(result, null, 2));
|
|
16
18
|
if (!result.ok) {
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
1
2
|
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { executeArtifactRevisionContinuation, planArtifactRevisionContinuation, } from "../workflows/dag/context-transfer/operator-actions.js";
|
|
2
4
|
import { isDagRerunPromptOverrideEnabled } from "../shared/dag-prompt-override.js";
|
|
3
|
-
import {
|
|
5
|
+
import { workerContinuationAuthorityV1Schema, } from "../shared/context-transfer.js";
|
|
6
|
+
import { openConsoleAppData } from "../infrastructure/console/app-data.js";
|
|
7
|
+
import { buildArtifactOverrideSet, consumeArtifactRevision, readArtifactRevision, readArtifactRevisionCandidate, acquireArtifactRevisionLease, releaseArtifactRevisionLease, EXECUTE_REVISION_LEASE_TTL_MS, } from "../infrastructure/console/artifact-revision-store.js";
|
|
8
|
+
import { buildArtifactBindingGraph } from "../workflows/dag/artifact-bindings.js";
|
|
9
|
+
import { locateDagRun, readDagRunSpec } from "../workflows/dag/lifecycle.js";
|
|
10
|
+
import { executeDagRerun, planDagRerun, readOperatorRequestReplay, } from "../workflows/dag/rerun-run.js";
|
|
4
11
|
export function parseDagRerunArgs(args) {
|
|
5
12
|
if (args.length === 0) {
|
|
6
13
|
throw new Error("usage: dag rerun --run-id <id> --from-node <node-id> --plan [--json] | dag rerun --run-id <id> --from-node <node-id> --plan-hash <hash> --request-id <key> --reason <text> [--json]");
|
|
@@ -111,6 +118,10 @@ async function loadPromptOverrides(specs, mode) {
|
|
|
111
118
|
return overrides;
|
|
112
119
|
}
|
|
113
120
|
export async function runDagRerun(repoRoot, rawArgs) {
|
|
121
|
+
if (rawArgs.some((arg) => arg === "--artifact-revision" || arg.startsWith("--artifact-revision="))) {
|
|
122
|
+
await runArtifactRevisionRerun(repoRoot, rawArgs);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
114
125
|
const parsed = parseDagRerunArgs(rawArgs);
|
|
115
126
|
let promptOverrides;
|
|
116
127
|
const hasOverrides = parsed.promptOverrideSpecs.length > 0 ||
|
|
@@ -163,3 +174,197 @@ export async function runDagRerun(repoRoot, rawArgs) {
|
|
|
163
174
|
}
|
|
164
175
|
}
|
|
165
176
|
}
|
|
177
|
+
function readFlag(args, name) {
|
|
178
|
+
const exact = args.indexOf(name);
|
|
179
|
+
if (exact >= 0)
|
|
180
|
+
return args[exact + 1];
|
|
181
|
+
const prefix = `${name}=`;
|
|
182
|
+
return args.find((arg) => arg.startsWith(prefix))?.slice(prefix.length);
|
|
183
|
+
}
|
|
184
|
+
function parseWorkerContinuationAuthority(raw) {
|
|
185
|
+
if (raw === undefined)
|
|
186
|
+
return undefined;
|
|
187
|
+
let parsed;
|
|
188
|
+
try {
|
|
189
|
+
parsed = JSON.parse(raw);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
throw new Error("dag rerun --worker-continuation must be valid JSON");
|
|
193
|
+
}
|
|
194
|
+
const result = workerContinuationAuthorityV1Schema.safeParse(parsed);
|
|
195
|
+
if (!result.success) {
|
|
196
|
+
throw new Error(`dag rerun --worker-continuation is invalid: ${result.error.issues[0]?.message ?? "schema mismatch"}`);
|
|
197
|
+
}
|
|
198
|
+
return result.data;
|
|
199
|
+
}
|
|
200
|
+
function executeLeaseHolder(requestId) {
|
|
201
|
+
// The request id identifies the idempotency envelope, not a live process.
|
|
202
|
+
// A unique invocation holder prevents two concurrent direct CLI invocations
|
|
203
|
+
// with the same request id from treating each other as a lease renewal.
|
|
204
|
+
return `cli-execute:${requestId}:${randomBytes(12).toString("hex")}`;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Hold the staging lease across candidate read + continuation execution so a
|
|
208
|
+
* concurrent discard/second execute fails with LEASE_HELD and a crashed
|
|
209
|
+
* process leaves a stale, TTL-takeover-able lease instead of silent races.
|
|
210
|
+
* The acquire/renew here also refreshes the sliding window before the long
|
|
211
|
+
* child run starts.
|
|
212
|
+
*/
|
|
213
|
+
async function withExecuteRevisionLease(appData, requestId, revisionId, operation) {
|
|
214
|
+
const holder = executeLeaseHolder(requestId);
|
|
215
|
+
await acquireArtifactRevisionLease({
|
|
216
|
+
appData,
|
|
217
|
+
revisionId,
|
|
218
|
+
holder,
|
|
219
|
+
ttlMs: EXECUTE_REVISION_LEASE_TTL_MS,
|
|
220
|
+
});
|
|
221
|
+
try {
|
|
222
|
+
return await operation(holder);
|
|
223
|
+
}
|
|
224
|
+
finally {
|
|
225
|
+
await releaseArtifactRevisionLease({
|
|
226
|
+
appData,
|
|
227
|
+
revisionId,
|
|
228
|
+
holder,
|
|
229
|
+
}).catch(() => { });
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
export async function runArtifactRevisionRerunCore(repoRoot, rawArgs, cliOptions) {
|
|
233
|
+
const allowed = new Set([
|
|
234
|
+
"--run-id",
|
|
235
|
+
"--artifact-revision",
|
|
236
|
+
"--plan-hash",
|
|
237
|
+
"--request-id",
|
|
238
|
+
"--reason",
|
|
239
|
+
"--worker-continuation",
|
|
240
|
+
]);
|
|
241
|
+
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
242
|
+
const arg = rawArgs[index];
|
|
243
|
+
if (arg === "--plan" || arg === "--json")
|
|
244
|
+
continue;
|
|
245
|
+
const name = arg.split("=", 1)[0];
|
|
246
|
+
if (!allowed.has(name))
|
|
247
|
+
throw new Error(`unknown artifact revision rerun flag: ${arg}`);
|
|
248
|
+
if (!arg.includes("="))
|
|
249
|
+
index += 1;
|
|
250
|
+
}
|
|
251
|
+
const parentRunId = readFlag(rawArgs, "--run-id")?.trim();
|
|
252
|
+
const revisionId = readFlag(rawArgs, "--artifact-revision")?.trim();
|
|
253
|
+
const planOnly = rawArgs.includes("--plan");
|
|
254
|
+
if (!parentRunId || !revisionId) {
|
|
255
|
+
throw new Error("dag rerun artifact revision requires --run-id and --artifact-revision");
|
|
256
|
+
}
|
|
257
|
+
const appData = openConsoleAppData({
|
|
258
|
+
repoRoot,
|
|
259
|
+
...(cliOptions?.appDataRoot ? { appDataRoot: cliOptions.appDataRoot } : {}),
|
|
260
|
+
});
|
|
261
|
+
const planHash = readFlag(rawArgs, "--plan-hash")?.trim();
|
|
262
|
+
const requestId = readFlag(rawArgs, "--request-id")?.trim();
|
|
263
|
+
const reason = readFlag(rawArgs, "--reason")?.trim();
|
|
264
|
+
const workerContinuation = parseWorkerContinuationAuthority(readFlag(rawArgs, "--worker-continuation"));
|
|
265
|
+
if (!planOnly && (!planHash || !requestId || !reason)) {
|
|
266
|
+
throw new Error("dag rerun artifact revision execute requires --plan-hash, --request-id, and --reason");
|
|
267
|
+
}
|
|
268
|
+
if (!planOnly) {
|
|
269
|
+
// Replay-first (B4): a prior execute may have consumed the revision and
|
|
270
|
+
// the staging record may already have been reconciled away. The persisted
|
|
271
|
+
// operator request is the authoritative idempotent result and must be
|
|
272
|
+
// honored before any dependency on the revision metadata. A replay that
|
|
273
|
+
// does not match the requested parent/planHash is a reuse conflict, not a
|
|
274
|
+
// valid idempotent answer (SF2).
|
|
275
|
+
const replay = await readOperatorRequestReplay(repoRoot, requestId, {
|
|
276
|
+
parentRunId,
|
|
277
|
+
planHash,
|
|
278
|
+
});
|
|
279
|
+
if (replay) {
|
|
280
|
+
return {
|
|
281
|
+
payload: replay,
|
|
282
|
+
exitCode: replay.ok
|
|
283
|
+
? 0
|
|
284
|
+
: replay.errorCode === "RERUN_PLAN_DRIFT"
|
|
285
|
+
? 3
|
|
286
|
+
: replay.errorCode === "INELIGIBLE"
|
|
287
|
+
? 2
|
|
288
|
+
: 1,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
const revision = await readArtifactRevision(appData, revisionId);
|
|
293
|
+
if (!revision || revision.parent.runId !== parentRunId) {
|
|
294
|
+
throw new Error("ARTIFACT_REVISION_EXPIRED");
|
|
295
|
+
}
|
|
296
|
+
const located = await locateDagRun(repoRoot, parentRunId);
|
|
297
|
+
if (!located)
|
|
298
|
+
throw new Error(`dag run not found: ${parentRunId}`);
|
|
299
|
+
const declaration = buildArtifactBindingGraph(await readDagRunSpec(located.runDir)).artifacts.find((item) => item.producerNodeId === revision.parent.nodeId &&
|
|
300
|
+
item.path === revision.parent.artifactPath);
|
|
301
|
+
if (!declaration)
|
|
302
|
+
throw new Error("ARTIFACT_BINDING_UNAVAILABLE");
|
|
303
|
+
const artifactOverrides = buildArtifactOverrideSet(revision);
|
|
304
|
+
if (planOnly) {
|
|
305
|
+
if (planHash || requestId || reason) {
|
|
306
|
+
throw new Error("dag rerun --plan cannot be combined with execute flags");
|
|
307
|
+
}
|
|
308
|
+
const plan = await planArtifactRevisionContinuation({
|
|
309
|
+
cwd: repoRoot,
|
|
310
|
+
parentRunId,
|
|
311
|
+
artifactId: declaration.artifactId,
|
|
312
|
+
artifactOverrides,
|
|
313
|
+
stagingRevisionSha256: revision.candidate.sha256,
|
|
314
|
+
...(workerContinuation
|
|
315
|
+
? { workerContinuationAuthority: workerContinuation }
|
|
316
|
+
: {}),
|
|
317
|
+
});
|
|
318
|
+
return { payload: { ok: plan.eligible, plan }, exitCode: plan.eligible ? 0 : 2 };
|
|
319
|
+
}
|
|
320
|
+
if (revision.state === "consumed") {
|
|
321
|
+
// Replay was not found above, so this is a crashed consume without a
|
|
322
|
+
// persisted result — refuse rather than re-execute a consumed revision.
|
|
323
|
+
throw new Error("ARTIFACT_REVISION_EXPIRED: revision already consumed and no operator replay exists for this request");
|
|
324
|
+
}
|
|
325
|
+
const result = await withExecuteRevisionLease(appData, requestId, revision.revisionId, async (leaseHolder) => {
|
|
326
|
+
const candidateBytes = await readArtifactRevisionCandidate({ appData, revision });
|
|
327
|
+
return executeArtifactRevisionContinuation({
|
|
328
|
+
cwd: repoRoot,
|
|
329
|
+
parentRunId,
|
|
330
|
+
artifactId: declaration.artifactId,
|
|
331
|
+
artifactOverrides,
|
|
332
|
+
stagingRevisionSha256: revision.candidate.sha256,
|
|
333
|
+
candidateBytes,
|
|
334
|
+
planHash: planHash,
|
|
335
|
+
requestId: requestId,
|
|
336
|
+
reason: reason,
|
|
337
|
+
...(workerContinuation
|
|
338
|
+
? { workerContinuationAuthority: workerContinuation }
|
|
339
|
+
: {}),
|
|
340
|
+
consumeRevision: async ({ revisionId: consumedId, expectedSha256 }) => {
|
|
341
|
+
await consumeArtifactRevision({
|
|
342
|
+
appData,
|
|
343
|
+
revisionId: consumedId,
|
|
344
|
+
expectedSha256,
|
|
345
|
+
holder: leaseHolder,
|
|
346
|
+
});
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
return {
|
|
351
|
+
payload: result,
|
|
352
|
+
exitCode: result.ok
|
|
353
|
+
? 0
|
|
354
|
+
: result.errorCode === "RERUN_PLAN_DRIFT"
|
|
355
|
+
? 3
|
|
356
|
+
: result.errorCode === "INELIGIBLE"
|
|
357
|
+
? 2
|
|
358
|
+
: 1,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
async function runArtifactRevisionRerun(repoRoot, rawArgs) {
|
|
362
|
+
const { payload, exitCode } = await runArtifactRevisionRerunCore(repoRoot, rawArgs);
|
|
363
|
+
process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
364
|
+
if (exitCode !== 0) {
|
|
365
|
+
const failure = payload;
|
|
366
|
+
const message = failure.message ?? failure.errorCode ?? `artifact rerun failed with exit ${exitCode}`;
|
|
367
|
+
process.stderr.write(`${message}\n`);
|
|
368
|
+
process.exitCode = exitCode;
|
|
369
|
+
}
|
|
370
|
+
}
|
package/dist/commands/init.js
CHANGED
|
@@ -14,6 +14,19 @@ const GITIGNORE_BLOCK_START = "# LOOP_AGENT_INIT_START";
|
|
|
14
14
|
const GITIGNORE_BLOCK_END = "# LOOP_AGENT_INIT_END";
|
|
15
15
|
const INIT_SURFACE_STATE_PATH = ".harness/init-surface.json";
|
|
16
16
|
const DEFAULT_GOVERNANCE_ROOT = "ai_workspace/loop-agent";
|
|
17
|
+
function buildSpecRegistry() {
|
|
18
|
+
return `${JSON.stringify({
|
|
19
|
+
version: 1,
|
|
20
|
+
roots: [],
|
|
21
|
+
discovery: {
|
|
22
|
+
enabled: true,
|
|
23
|
+
maxDepth: 3,
|
|
24
|
+
maxFiles: 100,
|
|
25
|
+
maxBytes: 1048576,
|
|
26
|
+
timeoutMs: 2000,
|
|
27
|
+
},
|
|
28
|
+
}, null, 2)}\n`;
|
|
29
|
+
}
|
|
17
30
|
const CORE_DOC_FILES = [
|
|
18
31
|
{ source: "README.md", target: "README.md" },
|
|
19
32
|
{
|
|
@@ -610,7 +623,7 @@ if (
|
|
|
610
623
|
(assessment.status === "passed" && assessment.currentExitCode !== 0) ||
|
|
611
624
|
(assessment.status === "baseline-debt" && assessment.currentExitCode === 0)
|
|
612
625
|
) fail();
|
|
613
|
-
if (!assessment.baselineRef || assessment.baselineRef.nodeId !== "frontend-
|
|
626
|
+
if (!assessment.baselineRef || assessment.baselineRef.nodeId !== "frontend-writer-admission-shell") fail();
|
|
614
627
|
const baselineRaw = readContained(assessment.baselineRef.path);
|
|
615
628
|
if (sha256(baselineRaw) !== assessment.baselineRef.sha256) fail();
|
|
616
629
|
let baseline;
|
|
@@ -1312,6 +1325,9 @@ async function buildDesiredSurfaceContent(input) {
|
|
|
1312
1325
|
}), null, 2)}\n`,
|
|
1313
1326
|
};
|
|
1314
1327
|
}
|
|
1328
|
+
if (manifestPath === "docs/spec-registry.json") {
|
|
1329
|
+
return { content: buildSpecRegistry() };
|
|
1330
|
+
}
|
|
1315
1331
|
if (manifestPath === OPENCODE_TRANSIENT_RETRY_PLUGIN_PATH) {
|
|
1316
1332
|
return { content: buildOpenCodeTransientRetryPluginSource() };
|
|
1317
1333
|
}
|
|
@@ -1709,6 +1725,8 @@ async function listRelativeFiles(rootPath) {
|
|
|
1709
1725
|
async function expectedLegacyInitFileSha(input) {
|
|
1710
1726
|
if (input.legacyPath.startsWith("docs/")) {
|
|
1711
1727
|
const doc = input.legacyPath.slice("docs/".length);
|
|
1728
|
+
if (doc === "spec-registry.json")
|
|
1729
|
+
return sha256Text(buildSpecRegistry());
|
|
1712
1730
|
const generated = buildGeneratedCoreDoc({
|
|
1713
1731
|
doc,
|
|
1714
1732
|
projectName: input.projectName,
|
|
@@ -2707,6 +2725,14 @@ export async function initializeLoopAgentProject(options) {
|
|
|
2707
2725
|
targetRelativePath: path.join(governanceRoot, "templates"),
|
|
2708
2726
|
written,
|
|
2709
2727
|
});
|
|
2728
|
+
await writeTextIfMissing({
|
|
2729
|
+
repoRoot,
|
|
2730
|
+
relativePath: path.join(governanceRoot, "spec-registry.json"),
|
|
2731
|
+
content: buildSpecRegistry(),
|
|
2732
|
+
merge,
|
|
2733
|
+
written,
|
|
2734
|
+
skipped,
|
|
2735
|
+
});
|
|
2710
2736
|
if (profile === "full") {
|
|
2711
2737
|
// Project repo-local skills live only under `.agents/skills/`.
|
|
2712
2738
|
// The package still ships `skills/` as the built-in fallback source.
|
|
@@ -377,6 +377,25 @@ export async function runTaskAdvance(repoRoot, args) {
|
|
|
377
377
|
intervalMs: options.progressIntervalMs,
|
|
378
378
|
});
|
|
379
379
|
}
|
|
380
|
+
// Idempotent client-recovery surface install before any DAG run: the Pi
|
|
381
|
+
// context-overflow extension / OpenCode plugins / project .pi settings
|
|
382
|
+
// are normally installed by `loop-agent init`, but an upgraded or
|
|
383
|
+
// non-init-created project may lack them. Installing here (missing-only)
|
|
384
|
+
// ensures the overflow compact+retry recovery path is always present,
|
|
385
|
+
// independent of how the project was created. Best-effort: a failure to
|
|
386
|
+
// install never blocks the run.
|
|
387
|
+
if (options.approveGate && !options.dryRun) {
|
|
388
|
+
try {
|
|
389
|
+
const { runClientRecovery } = await import("./client-recovery.js");
|
|
390
|
+
// mode "project" installs only project-owned surfaces
|
|
391
|
+
// (.pi/extensions + .opencode/plugins + .pi/settings.json),
|
|
392
|
+
// never the user home; installs are missing-only.
|
|
393
|
+
await runClientRecovery({ repoRoot, mode: "project" });
|
|
394
|
+
}
|
|
395
|
+
catch {
|
|
396
|
+
// best-effort; do not fail the run over a recovery-surface install
|
|
397
|
+
}
|
|
398
|
+
}
|
|
380
399
|
const result = await advanceTaskLifecycle(toUseCaseInput(repoRoot, taskId, options, progress?.observer));
|
|
381
400
|
const outcome = mapOutcome(result);
|
|
382
401
|
const gateStop = result.lifecycleState === "awaiting-write-set-approval" &&
|