@tea-agent/loop-agent 0.41.1-beta.0 → 0.42.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +78 -206
- 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 +19 -75
- package/dist/application/task-lifecycle/advance.js +5 -24
- package/dist/application/task-lifecycle/observe.js +17 -171
- package/dist/application/task-lifecycle/plan-transitions.js +7 -42
- package/dist/application/task-lifecycle/recommendations.js +2 -13
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +12 -7
- package/dist/cli/program.js +23 -6
- package/dist/commands/client-recovery.js +0 -3
- package/dist/commands/dag-artifact.js +284 -0
- package/dist/commands/dag-context.js +184 -0
- package/dist/commands/dag-rerun.js +206 -1
- package/dist/commands/init.js +1 -27
- package/dist/commands/task-advance.js +0 -19
- package/dist/executors/dag-pi-executor.js +266 -3792
- package/dist/executors/pi-executor.js +4 -15
- package/dist/executors/pi-sdk-executor.js +3 -0
- package/dist/executors/shell-executor.js +217 -945
- package/dist/executors/shell-write-guard.js +0 -7
- 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 +197 -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 +0 -12
- package/dist/shared/openspec-spec.js +4 -70
- package/dist/shared/operator/capabilities.js +14 -7
- 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 +80 -35
- package/dist/task/contract/adopt.js +0 -4
- package/dist/task/contract/import-revision.js +0 -4
- package/dist/task/contract/project.js +0 -3
- package/dist/task/contract/schema.js +1 -2
- package/dist/task/frontend-project-capability.js +20 -203
- package/dist/task/runtime.js +2 -5
- package/dist/task/source-prepare/build-draft.js +3 -3
- package/dist/task/source-prepare/fragment-inventory.js +9 -15
- package/dist/task/source-prepare/prepare.js +1 -89
- package/dist/task/source-prepare/semantic-intake.js +2 -6
- package/dist/task/source-references.js +1 -22
- 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/pi-runtime.js +3 -2
- package/dist/worker/console/chat/resource-preferences-store.js +1 -1
- package/dist/worker/console/chat/routes.js +13 -4
- package/dist/worker/console/chat/semantic-activity.js +12 -11
- package/dist/worker/console/chat/session-stats.js +96 -0
- package/dist/worker/console/chat/session-store.js +1 -1
- package/dist/worker/console/chat/turn-process.js +28 -4
- 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/human-gate-token.js +1 -1
- package/dist/worker/console/index.js +3 -6
- 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 +107 -168
- 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 +60 -1
- package/dist/worker/console/routes.js +637 -8
- package/dist/worker/console/security.js +35 -0
- package/dist/worker/console/server.js +6 -6
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-Bho4we4c.js → abnfDiagram-N423BO3Z-DZZ8m3PO.js} +1 -1
- package/dist/worker/console/static/assets/{arc-TBDkTeK0.js → arc-D6PvaVd-.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-BF_fZrn2.js → architectureDiagram-T3A2C74G-B_OTOiI8.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-CCnPgUe2.js → blockDiagram-VBNYF7ZC-Bv6rqHBg.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BCYZJLAT.js → c4Diagram-5PPSVZJV-B8eHr0oz.js} +1 -1
- package/dist/worker/console/static/assets/channel-BU5gOilw.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-D8K6adhU.js → chunk-2GRJ4B5K-DYwR0im2.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DkT1Q78b.js → chunk-2Q5K7J3B-D2WPGqXt.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DuhvpIr7.js → chunk-5RXB4S5H-CQISJ_I7.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BnK6dC49.js → chunk-5VM5RSS4-C0o2Du1e.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DPz__z7r.js → chunk-6Q2QTUOP-4f8kr-U7.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-0kkppM2j.js → chunk-GF5L2VYU-D_OWvXzX.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BB41iK5t.js → chunk-JWPE2WC7-CasdPz5X.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-CiVrxKHU.js → chunk-KBJHAD2P-Cj8lRrla.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-C2h9Xje1.js → chunk-RYQCIY6F-CUvD1FSd.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-3iOSHdbM.js → chunk-XXDRQBXY-CqLw_eqB.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DIzKJGHr.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DIzKJGHr.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BN3A7tkk.js → cose-bilkent-JH36ORCC-ku-WqJPx.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-CTuBy0Or.js → cynefin-VYW2F7L2-Bq_PYDhl.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-wb6tUlMN.js → cynefinDiagram-MW4NZA55-BiGZV641.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-GP1Ivx8B.js → dagre-VZM6K2ZE-C4JRlglF.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-ejrcK6L0.js → diagram-7IWD3JNH-B0dNeWYG.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-YFkCCvUU.js → diagram-B4RE2ZJO-Cj35YvYM.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-B4rrvIaL.js → diagram-LBJQPF4R-uzQoJ2-8.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-C-YIZcUf.js → diagram-Q27KOJAE-D1a-Buoz.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-BPF5wcL1.js → diagram-UB23O5K3-XjRrLRSs.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-CU5SzXjO.js → ebnfDiagram-BXEA7PRR-Da_O24cW.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-CpL414DE.js → erDiagram-JOGREHBK-BLJ8jrYU.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-MrhLzNau.js → flowDiagram-UKHOOZJN-B9GrLjM0.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-Bg4qFuUo.js → ganttDiagram-PKOTCBZU-CeJ0TqiK.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-ColxSXLR.js → gitGraphDiagram-DS77QQ5N-Bm2eNNFX.js} +1 -1
- package/dist/worker/console/static/assets/index-H9rFJiGL.css +1 -0
- package/dist/worker/console/static/assets/index-xwu9GxEc.js +451 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-Czvtm6gc.js → infoDiagram-6WML65LV-DB26i3d8.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-B7Xp8HyJ.js → ishikawaDiagram-WSZJBQD7-BOGRyeZT.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DWYZcvph.js → journeyDiagram-NVQOT4AX-CZRoBO_6.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-KTLZRUjx.js → kanban-definition-27J2QSJJ-qlWhJyoB.js} +1 -1
- package/dist/worker/console/static/assets/{linear-_Exn7bfl.js → linear-CfUiDDB3.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-Cxg8kX8V.js → mermaid.core-BQe6fpqj.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-oKrlo2Bt.js → mindmap-definition-FAOFIHXS-zFzWHw64.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-XAeteiNd.js → pegDiagram-VL7TDLO6-DFGUqjZO.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BTf1K-lp.js → pieDiagram-7S7Q4E2Y-BB5i0l8Z.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-C0IlY0Jf.js → quadrantDiagram-CIZ2JOQS-obbVZ_X5.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BVbKtZhW.js → railroadDiagram-AXF67PYL-BwdaNzc1.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-C5e4JFcr.js → requirementDiagram-LRYGKXZP-CkTJaugh.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Cz30hc29.js → sankeyDiagram-W5VNT64P-BwJ-hIgq.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DS33n6d0.js → sequenceDiagram-SI44F4Z6-BzSgmm7w.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-46w7v-9T.js → sizeCapture-X5ZJPWSS-Bn3oj5Q1.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-pbcD5SsZ.js → stateDiagram-OKZ733FA-dxhGtL8K.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Cld2qK9v.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DuivYBSj.js → swimlanes-SLNWSIFB-BLpEInya.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-TIHpiT7w.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-Cb9VZVIl.js → timeline-definition-Z64GVDOM-ChJGYcXy.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-D2-mfOgR.js → vennDiagram-T6HMQDX7-DK-qjRer.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DeS2aC76.js → wardleyDiagram-T6FBY63Y-3qeaWAg-.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-WGsrFjxH.js → xychartDiagram-ELKLHX3M-CootlyP9.js} +1 -1
- package/dist/worker/console/static/index.html +7 -2
- package/dist/worker/console/static-src/app/useOperatorActions.js +3 -2
- package/dist/worker/console/static-src/app/useRunProgress.js +9 -2
- package/dist/worker/console/static-src/operator-chat/dag-progress-link.js +22 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +2 -0
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +6 -0
- package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +28 -3
- package/dist/worker/console/static-src/pages/tasks/run-panel-progress.js +106 -0
- package/dist/worker/console/static-src/shell/console-update-reload.js +25 -0
- package/dist/worker/console/workspace-context.js +28 -112
- package/dist/worker/console/workspace-registry.js +2 -2
- package/dist/worker/continuation/worker-continuation.js +278 -0
- package/dist/worker/observability/read-model.js +4 -0
- package/dist/worker/observe/health.js +1 -1
- package/dist/worker/observe/node-transparency.js +572 -0
- package/dist/worker/observe/routes.js +51 -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-node-purpose.js +0 -5
- package/dist/worker/observe/static/state.js +3 -1
- package/dist/worker/observe/static/styles.css +1037 -126
- package/dist/worker/observe/static/views/dag-inspector.js +1217 -65
- package/dist/worker/observe/static/views/session-timeline.js +121 -25
- 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 +99 -4
- package/dist/workflows/dag/backend-test-markdown-workflow.js +13 -1
- package/dist/workflows/dag/backend-test-result-contract.js +1 -1
- package/dist/workflows/dag/backend-test-writer-completeness.js +45 -3
- 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 +2 -1
- package/dist/workflows/dag/frontend-implementation-contract.js +162 -932
- package/dist/workflows/dag/frontend-plan-render.js +1 -2
- package/dist/workflows/dag/frontend-prewrite-gate.js +349 -255
- package/dist/workflows/dag/frontend-recovery-plan.js +10 -17
- package/dist/workflows/dag/frontend-recovery-run.js +20 -33
- package/dist/workflows/dag/frontend-repair.js +432 -1
- package/dist/workflows/dag/frontend-review-context.js +15 -261
- package/dist/workflows/dag/frontend-verification-trace.js +24 -249
- package/dist/workflows/dag/frontend-worktree-diff.js +17 -250
- package/dist/workflows/dag/frontend-writer-rollback.js +32 -0
- package/dist/workflows/dag/init-hybrid.js +740 -718
- package/dist/workflows/dag/interrupt-request.js +0 -7
- package/dist/workflows/dag/node-execution.js +136 -759
- package/dist/workflows/dag/path-safety.js +1 -0
- package/dist/workflows/dag/prompt.js +30 -38
- package/dist/workflows/dag/report.js +1 -37
- package/dist/workflows/dag/rerun-feedback.js +1 -256
- package/dist/workflows/dag/rerun-plan.js +557 -11
- package/dist/workflows/dag/rerun-run.js +601 -38
- package/dist/workflows/dag/rerun-task.js +0 -29
- package/dist/workflows/dag/retry-policy.js +109 -214
- package/dist/workflows/dag/runner.js +142 -430
- package/dist/workflows/dag/scheduler.js +16 -114
- package/dist/workflows/dag/skill-snapshot.js +17 -0
- package/dist/workflows/dag/types.js +195 -246
- package/dist/workflows/dag/validate.js +12 -28
- package/docs/architecture/runtime-boundaries.md +6 -6
- package/docs/architecture/worker-and-feature.md +1 -1
- package/docs/init-surface.manifest.json +12 -30
- package/docs/skills/vetted-skill-registry.md +2 -4
- package/docs/templates/README.md +0 -2
- package/docs/templates/agent-dag-report.schema.json +2 -8
- package/docs/templates/agent-dag.schema.json +33 -1
- package/docs/templates/backend-test-dag.json +18 -18
- package/docs/templates/frontend-implementation-contract.schema.json +1 -4
- package/docs/templates/product-line/task.yaml +1 -1
- package/harness.json +3 -3
- package/package.json +3 -1
- package/skills/frontend-bounded-implement/SKILL.md +14 -15
- package/skills/frontend-design-review/SKILL.md +41 -22
- package/skills/frontend-implementation/SKILL.md +52 -0
- package/skills/frontend-implementation/references/code-standards.md +33 -0
- package/skills/frontend-implementation/references/design-spec.md +56 -0
- package/skills/frontend-implementation/references/node-contracts.md +31 -0
- package/skills/frontend-review/SKILL.md +15 -20
- package/skills/frontend-review/references/review-findings.md +7 -6
- package/skills/frontend-verification/SKILL.md +1 -1
- package/skills/loop-agent/references/command-reference.md +6 -1
- package/skills/loop-agent/references/hybrid-dag.md +2 -2
- package/dist/commands/dag-follow-up.js +0 -138
- package/dist/executors/pi-read-budget-policy.js +0 -239
- package/dist/worker/console/frontend-human-decision-adapter.js +0 -19
- package/dist/worker/console/frontend-split-operation-adapter.js +0 -20
- package/dist/worker/console/operation-store.js +0 -389
- package/dist/worker/console/static/assets/channel-bnXW0U3C.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-rZpq_twR.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-rZpq_twR.js +0 -1
- package/dist/worker/console/static/assets/index-D3CC4eUz.css +0 -1
- package/dist/worker/console/static/assets/index-DLt4ZFvD.js +0 -437
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-zBMYiUyi.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-d_rms-5i.js +0 -8
- package/dist/worker/console/static-src/active-run-badge.js +0 -17
- package/dist/worker/materialize/frontend-split-task-materializer.js +0 -72
- package/dist/workflows/dag/dag-retry-schema.js +0 -138
- package/dist/workflows/dag/frontend-closeout.js +0 -221
- package/dist/workflows/dag/frontend-design-policy.js +0 -400
- package/dist/workflows/dag/frontend-human-decision.js +0 -182
- package/dist/workflows/dag/frontend-provider-capability-matrix.js +0 -159
- package/dist/workflows/dag/frontend-read-budgets.js +0 -12
- package/dist/workflows/dag/frontend-recovery-capsule.js +0 -455
- package/dist/workflows/dag/frontend-recovery-controller.js +0 -202
- package/dist/workflows/dag/frontend-recovery-lineage.js +0 -178
- package/dist/workflows/dag/frontend-review-findings.js +0 -270
- package/dist/workflows/dag/frontend-shadow-dual-write.js +0 -914
- package/dist/workflows/dag/frontend-shape-capsule-store.js +0 -191
- package/dist/workflows/dag/frontend-shape-facts.js +0 -409
- package/dist/workflows/dag/frontend-shape.js +0 -427
- package/dist/workflows/dag/frontend-source-fidelity-ledger.js +0 -108
- package/dist/workflows/dag/frontend-split-application-service.js +0 -203
- package/dist/workflows/dag/frontend-split-orchestrator.js +0 -899
- package/dist/workflows/dag/frontend-typed-event-store.js +0 -452
- package/dist/workflows/dag/frontend-typed-event-transaction.js +0 -180
- package/dist/workflows/dag/frontend-writer-admission.js +0 -285
- package/dist/workflows/dag/frontend-writer-status.js +0 -256
- package/dist/workflows/dag/recovery-lease.js +0 -80
- package/docs/templates/frontend-implementation-dag.json +0 -89
- package/docs/templates/spec-registry.schema.json +0 -45
- package/skills/frontend-bounded-implement/references/code-standards.md +0 -19
- package/skills/frontend-contract/SKILL.md +0 -23
- package/skills/frontend-contract/references/contract-protocol.md +0 -34
- package/skills/frontend-plan/SKILL.md +0 -26
- package/skills/frontend-plan/references/decision-contract.md +0 -37
- package/skills/frontend-plan/references/design-decisions.md +0 -17
- package/skills/frontend-scout/SKILL.md +0 -25
- package/skills/frontend-scout/references/design-evidence.md +0 -16
- package/skills/frontend-scout/references/scout-evidence.md +0 -23
- /package/dist/{worker → infrastructure}/console/repo-fingerprint.js +0 -0
|
@@ -5,152 +5,25 @@ import { runResilientGitCommand } from "../../shared/resilient-git.js";
|
|
|
5
5
|
import { writeDagRunJsonArtifact } from "../../infrastructure/harness/artifact-store.js";
|
|
6
6
|
import { pathMatchesPattern } from "../../shared/git-progress.js";
|
|
7
7
|
export const FRONTEND_WORKTREE_DIFF_SCHEMA_ID = "frontend-worktree-diff-v1";
|
|
8
|
-
export const FRONTEND_REVIEW_DIFF_INDEX_SCHEMA_ID = "frontend-review-diff-index-v1";
|
|
9
|
-
const MAX_REVIEW_DIFF_SUMMARY_ENTRIES = 48;
|
|
10
|
-
/** Maximum diff payload per review artifact; metadata adds a small fixed header. */
|
|
11
|
-
const MAX_REVIEW_DIFF_FRAGMENT_BYTES = 20 * 1024;
|
|
12
8
|
export const FRONTEND_WORKTREE_BASELINE_SCHEMA_ID = "frontend-worktree-baseline-v1";
|
|
13
9
|
async function runGit(cwd, args) {
|
|
14
10
|
const result = await runResilientGitCommand({ cwd, args, readOnly: true });
|
|
15
11
|
return { code: result.code, stdout: result.stdout, stderr: result.stderr };
|
|
16
12
|
}
|
|
17
|
-
/**
|
|
18
|
-
* Ephemeral interpreter/tool caches that writers may create while drafting
|
|
19
|
-
* tests (kept in sync with `isEphemeralToolCachePath` in
|
|
20
|
-
* src/executors/shell-write-guard.ts). They are not product evidence: tool
|
|
21
|
-
* cache writes must neither fail the write guard nor appear in the review
|
|
22
|
-
* diff as pre-existing changes.
|
|
23
|
-
*/
|
|
24
|
-
export function isEphemeralToolCachePath(filePath) {
|
|
25
|
-
const normalized = filePath.replace(/\\/g, "/");
|
|
26
|
-
if (!normalized)
|
|
27
|
-
return false;
|
|
28
|
-
if (normalized === ".pytest_cache" ||
|
|
29
|
-
normalized.startsWith(".pytest_cache/")) {
|
|
30
|
-
return true;
|
|
31
|
-
}
|
|
32
|
-
if (normalized === ".mypy_cache" || normalized.startsWith(".mypy_cache/")) {
|
|
33
|
-
return true;
|
|
34
|
-
}
|
|
35
|
-
if (normalized === ".ruff_cache" || normalized.startsWith(".ruff_cache/")) {
|
|
36
|
-
return true;
|
|
37
|
-
}
|
|
38
|
-
if (normalized === ".playwright-cli" ||
|
|
39
|
-
normalized.startsWith(".playwright-cli/")) {
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
if (normalized === ".coverage" || normalized.startsWith(".coverage.")) {
|
|
43
|
-
return true;
|
|
44
|
-
}
|
|
45
|
-
// vite/vitest runtime caches live under node_modules/.vite (e.g.
|
|
46
|
-
// node_modules/.vite/vitest/results.json). node_modules is the gitignored
|
|
47
|
-
// dependency tree — tool cache writes there are never a product change.
|
|
48
|
-
if (normalized.startsWith("node_modules/.vite/")) {
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
if (/(?:^|\/)__pycache__(?:\/|$)/.test(normalized))
|
|
52
|
-
return true;
|
|
53
|
-
if (/\.(?:pyc|pyo)$/.test(normalized))
|
|
54
|
-
return true;
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
13
|
function splitLines(text) {
|
|
58
14
|
return text
|
|
59
15
|
.split(/\r?\n/)
|
|
60
16
|
.map((line) => line.trim())
|
|
61
17
|
.filter(Boolean);
|
|
62
18
|
}
|
|
63
|
-
function
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
grouped.set(hunk.path, {
|
|
72
|
-
path: hunk.path,
|
|
73
|
-
bytes: hunk.bytes,
|
|
74
|
-
parts: hunk.parts,
|
|
75
|
-
firstPatchPath: hunk.patchPath,
|
|
76
|
-
lastPatchPath: hunk.patchPath,
|
|
77
|
-
});
|
|
78
|
-
return grouped;
|
|
79
|
-
}, new Map()).values()];
|
|
80
|
-
const listedFiles = files.slice(0, MAX_REVIEW_DIFF_SUMMARY_ENTRIES);
|
|
81
|
-
const remainingFiles = files.length - listedFiles.length;
|
|
82
|
-
const listedUntracked = input.untrackedFiles.slice(0, MAX_REVIEW_DIFF_SUMMARY_ENTRIES);
|
|
83
|
-
const remainingUntracked = input.untrackedFiles.length - listedUntracked.length;
|
|
84
|
-
return [
|
|
85
|
-
"# Frontend review diff summary",
|
|
86
|
-
"",
|
|
87
|
-
"Read this bounded summary first. Do not read artifacts/diff_patch.patch in full; it is retained only as the canonical audit artifact.",
|
|
88
|
-
"For a semantic finding, read only the matching per-file diff fragment below and then the current source file when necessary. Read fragments in part order when a file has more than one.",
|
|
89
|
-
"",
|
|
90
|
-
`Canonical patch SHA-256: ${input.patchSha256}`,
|
|
91
|
-
`Canonical patch bytes: ${input.patchBytes}`,
|
|
92
|
-
`Tracked changed files: ${files.length}`,
|
|
93
|
-
`Review diff fragments: ${input.hunks.length}`,
|
|
94
|
-
`Untracked files (inventory only): ${input.untrackedFiles.length}`,
|
|
95
|
-
"",
|
|
96
|
-
"## Tracked file diff fragment references",
|
|
97
|
-
...(listedFiles.length > 0
|
|
98
|
-
? listedFiles.map((file) => file.parts === 1
|
|
99
|
-
? `- ${file.path} — ${file.bytes} bytes — read ${file.firstPatchPath} only if this file needs review`
|
|
100
|
-
: `- ${file.path} — ${file.bytes} bytes across ${file.parts} ordered fragments — read ${file.firstPatchPath} through ${file.lastPatchPath} only if this file needs review`)
|
|
101
|
-
: ["- (none)"]),
|
|
102
|
-
...(remainingFiles > 0
|
|
103
|
-
? [`- … ${remainingFiles} additional tracked files are recorded in contracts/frontend-review-diff-index.json; do not bulk-read them.`]
|
|
104
|
-
: []),
|
|
105
|
-
"",
|
|
106
|
-
"## Untracked inventory",
|
|
107
|
-
...(listedUntracked.length > 0
|
|
108
|
-
? listedUntracked.map((file) => `- ${file}`)
|
|
109
|
-
: ["- (none)"]),
|
|
110
|
-
...(remainingUntracked > 0
|
|
111
|
-
? [`- … ${remainingUntracked} additional untracked files are recorded in contracts/frontend-review-diff-index.json.`]
|
|
112
|
-
: []),
|
|
113
|
-
"",
|
|
114
|
-
].join("\n");
|
|
115
|
-
}
|
|
116
|
-
function splitReviewDiffFragments(text) {
|
|
117
|
-
const fragments = [];
|
|
118
|
-
let current = "";
|
|
119
|
-
for (const line of text.match(/[^\n]*\n|[^\n]+/g) ?? []) {
|
|
120
|
-
const lineBytes = Buffer.byteLength(line);
|
|
121
|
-
if (current.length > 0 &&
|
|
122
|
-
Buffer.byteLength(current) + lineBytes >
|
|
123
|
-
MAX_REVIEW_DIFF_FRAGMENT_BYTES) {
|
|
124
|
-
fragments.push(current);
|
|
125
|
-
current = "";
|
|
126
|
-
}
|
|
127
|
-
if (lineBytes <= MAX_REVIEW_DIFF_FRAGMENT_BYTES) {
|
|
128
|
-
current += line;
|
|
129
|
-
continue;
|
|
130
|
-
}
|
|
131
|
-
// Generated/minified files can produce a single diff line larger than the
|
|
132
|
-
// review budget. Split by Unicode code point so no fragment exceeds the
|
|
133
|
-
// byte limit while preserving the original patch bytes when concatenated.
|
|
134
|
-
let oversizedLineFragment = "";
|
|
135
|
-
let oversizedLineFragmentBytes = 0;
|
|
136
|
-
for (const codePoint of line) {
|
|
137
|
-
const codePointBytes = Buffer.byteLength(codePoint);
|
|
138
|
-
if (oversizedLineFragmentBytes > 0 &&
|
|
139
|
-
oversizedLineFragmentBytes + codePointBytes >
|
|
140
|
-
MAX_REVIEW_DIFF_FRAGMENT_BYTES) {
|
|
141
|
-
fragments.push(oversizedLineFragment);
|
|
142
|
-
oversizedLineFragment = "";
|
|
143
|
-
oversizedLineFragmentBytes = 0;
|
|
144
|
-
}
|
|
145
|
-
oversizedLineFragment += codePoint;
|
|
146
|
-
oversizedLineFragmentBytes += codePointBytes;
|
|
147
|
-
}
|
|
148
|
-
if (oversizedLineFragment)
|
|
149
|
-
fragments.push(oversizedLineFragment);
|
|
150
|
-
}
|
|
151
|
-
if (current.length > 0)
|
|
152
|
-
fragments.push(current);
|
|
153
|
-
return fragments.length > 0 ? fragments : [""];
|
|
19
|
+
function statusPaths(status) {
|
|
20
|
+
return status
|
|
21
|
+
.split(/\r?\n/)
|
|
22
|
+
.map((line) => line.trimEnd())
|
|
23
|
+
.filter((line) => line.length >= 4)
|
|
24
|
+
.map((line) => line.slice(3).split(" -> ").at(-1) ?? "")
|
|
25
|
+
.filter(Boolean)
|
|
26
|
+
.sort();
|
|
154
27
|
}
|
|
155
28
|
async function sha256File(filePath) {
|
|
156
29
|
try {
|
|
@@ -164,26 +37,15 @@ async function sha256File(filePath) {
|
|
|
164
37
|
export async function captureFrontendWorktreeBaseline(input) {
|
|
165
38
|
const run = input.dependencies?.runGit ?? runGit;
|
|
166
39
|
const root = path.resolve(input.workspaceRoot);
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
// writer admission with baseline-empty.
|
|
172
|
-
const ls = await run(root, [
|
|
173
|
-
"ls-files",
|
|
174
|
-
"-co",
|
|
175
|
-
"--exclude-standard",
|
|
176
|
-
"-z",
|
|
40
|
+
const status = await run(root, [
|
|
41
|
+
"status",
|
|
42
|
+
"--porcelain=v1",
|
|
43
|
+
"--untracked-files=all",
|
|
177
44
|
]);
|
|
178
|
-
if (
|
|
179
|
-
throw new Error(`frontend worktree baseline failed: ${
|
|
45
|
+
if (status.code !== 0) {
|
|
46
|
+
throw new Error(`frontend worktree baseline failed: ${status.stderr.trim() || status.stdout.trim()}`);
|
|
180
47
|
}
|
|
181
|
-
const files =
|
|
182
|
-
.split("\0")
|
|
183
|
-
.map((line) => line.trim())
|
|
184
|
-
.filter(Boolean)
|
|
185
|
-
.filter((file) => !isEphemeralToolCachePath(file))
|
|
186
|
-
.sort();
|
|
48
|
+
const files = statusPaths(status.stdout);
|
|
187
49
|
const hashes = {};
|
|
188
50
|
for (const file of files)
|
|
189
51
|
hashes[file] = await sha256File(path.join(root, file));
|
|
@@ -250,12 +112,8 @@ export async function runFrontendWorktreeDiffGate(input) {
|
|
|
250
112
|
if (untracked.code !== 0) {
|
|
251
113
|
throw new Error(`frontend worktree diff gate ls-files failed: ${untracked.stderr.trim() || untracked.stdout.trim()}`);
|
|
252
114
|
}
|
|
253
|
-
const changedFilesAll = splitLines(nameOnly.stdout)
|
|
254
|
-
|
|
255
|
-
.sort();
|
|
256
|
-
const untrackedFilesAll = splitLines(untracked.stdout)
|
|
257
|
-
.filter((file) => !isEphemeralToolCachePath(file))
|
|
258
|
-
.sort();
|
|
115
|
+
const changedFilesAll = splitLines(nameOnly.stdout).sort();
|
|
116
|
+
const untrackedFilesAll = splitLines(untracked.stdout).sort();
|
|
259
117
|
const authorizedChangedPaths = input.authorizedChangedPaths ?? [];
|
|
260
118
|
if (baseline) {
|
|
261
119
|
for (const file of baseline.files) {
|
|
@@ -302,65 +160,11 @@ export async function runFrontendWorktreeDiffGate(input) {
|
|
|
302
160
|
const absolutePatch = path.join(input.runDir, ...relativePatch.split("/"));
|
|
303
161
|
await mkdir(path.dirname(absolutePatch), { recursive: true });
|
|
304
162
|
await writeFile(absolutePatch, patchText, "utf8");
|
|
305
|
-
// Keep the complete patch as immutable audit evidence, but create a bounded
|
|
306
|
-
// reviewer entrypoint plus one file-scoped artifact per tracked change. This
|
|
307
|
-
// prevents final review from loading a multi-thousand-line patch into a
|
|
308
|
-
// single Pi session merely to inspect one or two relevant files.
|
|
309
|
-
const reviewHunks = [];
|
|
310
|
-
const reviewHunksDir = path.join(input.runDir, "artifacts", "diff-hunks");
|
|
311
|
-
await mkdir(reviewHunksDir, { recursive: true });
|
|
312
|
-
for (const [index, file] of changedFiles.entries()) {
|
|
313
|
-
const filePatch = await run(root, ["diff", "--binary", "HEAD", "--", file]);
|
|
314
|
-
if (filePatch.code !== 0) {
|
|
315
|
-
throw new Error(`frontend worktree diff hunk failed for ${file}: ${filePatch.stderr.trim() || filePatch.stdout.trim()}`);
|
|
316
|
-
}
|
|
317
|
-
const text = filePatch.stdout.endsWith("\n") || filePatch.stdout.length === 0
|
|
318
|
-
? filePatch.stdout
|
|
319
|
-
: `${filePatch.stdout}\n`;
|
|
320
|
-
const fragments = splitReviewDiffFragments(text);
|
|
321
|
-
for (const [partIndex, fragment] of fragments.entries()) {
|
|
322
|
-
const part = partIndex + 1;
|
|
323
|
-
const patchPath = `artifacts/diff-hunks/${String(index + 1).padStart(3, "0")}-${String(part).padStart(3, "0")}.patch`;
|
|
324
|
-
const artifact = [
|
|
325
|
-
"# Frontend review diff fragment",
|
|
326
|
-
`# path: ${file}`,
|
|
327
|
-
`# part: ${part}/${fragments.length}`,
|
|
328
|
-
"",
|
|
329
|
-
fragment,
|
|
330
|
-
].join("\n");
|
|
331
|
-
await writeFile(path.join(input.runDir, ...patchPath.split("/")), artifact, "utf8");
|
|
332
|
-
reviewHunks.push({
|
|
333
|
-
path: file,
|
|
334
|
-
patchPath,
|
|
335
|
-
sha256: createHash("sha256").update(artifact).digest("hex"),
|
|
336
|
-
bytes: Buffer.byteLength(artifact),
|
|
337
|
-
part,
|
|
338
|
-
parts: fragments.length,
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
const reviewIndexPath = "contracts/frontend-review-diff-index.json";
|
|
343
|
-
await writeDagRunJsonArtifact(input.runDir, reviewIndexPath, {
|
|
344
|
-
schemaVersion: 1,
|
|
345
|
-
schemaId: FRONTEND_REVIEW_DIFF_INDEX_SCHEMA_ID,
|
|
346
|
-
patchSha256,
|
|
347
|
-
hunks: reviewHunks,
|
|
348
|
-
untrackedFiles,
|
|
349
|
-
});
|
|
350
|
-
const reviewSummaryPath = "artifacts/diff_summary.md";
|
|
351
|
-
await writeFile(path.join(input.runDir, ...reviewSummaryPath.split("/")), buildReviewDiffSummary({
|
|
352
|
-
patchSha256,
|
|
353
|
-
patchBytes: Buffer.byteLength(patchText),
|
|
354
|
-
hunks: reviewHunks,
|
|
355
|
-
untrackedFiles,
|
|
356
|
-
}), "utf8");
|
|
357
163
|
const payload = {
|
|
358
164
|
schemaVersion: 1,
|
|
359
165
|
schemaId: FRONTEND_WORKTREE_DIFF_SCHEMA_ID,
|
|
360
166
|
patchPath: relativePatch,
|
|
361
167
|
patchSha256,
|
|
362
|
-
reviewSummaryPath,
|
|
363
|
-
reviewIndexPath,
|
|
364
168
|
changedFiles,
|
|
365
169
|
untrackedFiles,
|
|
366
170
|
empty: changedFiles.length === 0 && untrackedFiles.length === 0,
|
|
@@ -373,8 +177,6 @@ export async function runFrontendWorktreeDiffGate(input) {
|
|
|
373
177
|
patchPath: relativePatch,
|
|
374
178
|
patchAbsolutePath: absolutePatch,
|
|
375
179
|
patchSha256,
|
|
376
|
-
reviewSummaryPath,
|
|
377
|
-
reviewIndexPath,
|
|
378
180
|
changedFiles,
|
|
379
181
|
untrackedFiles,
|
|
380
182
|
empty: payload.empty,
|
|
@@ -387,8 +189,6 @@ export function formatFrontendWorktreeDiffStdout(result) {
|
|
|
387
189
|
`schemaId=${result.schemaId}`,
|
|
388
190
|
`patchPath=${result.patchPath}`,
|
|
389
191
|
`patchSha256=${result.patchSha256}`,
|
|
390
|
-
`reviewSummaryPath=${result.reviewSummaryPath}`,
|
|
391
|
-
`reviewIndexPath=${result.reviewIndexPath}`,
|
|
392
192
|
`changedFiles=${result.changedFiles.length}`,
|
|
393
193
|
`untrackedFiles=${result.untrackedFiles.length}`,
|
|
394
194
|
`empty=${result.empty ? "true" : "false"}`,
|
|
@@ -399,36 +199,3 @@ export function formatFrontendWorktreeDiffStdout(result) {
|
|
|
399
199
|
.filter(Boolean)
|
|
400
200
|
.join("\n");
|
|
401
201
|
}
|
|
402
|
-
/**
|
|
403
|
-
* Expand glob-shaped contract paths into concrete workspace file paths.
|
|
404
|
-
*
|
|
405
|
-
* The frontend contract schema allows `targets.files` entries such as
|
|
406
|
-
* `src/**` (skeleton inherits the task allowedPaths), but writer admission
|
|
407
|
-
* derives the concrete writeSet and requires real file paths. This helper
|
|
408
|
-
* matches every candidate against the enumerated workspace files and returns
|
|
409
|
-
* the concrete paths. Candidates that are already concrete are kept as-is;
|
|
410
|
-
* globs that match nothing are dropped (the derived writeSet only contains
|
|
411
|
-
* paths the writer can actually touch).
|
|
412
|
-
*/
|
|
413
|
-
export function expandFrontendGlobPaths(input) {
|
|
414
|
-
const concrete = new Set();
|
|
415
|
-
const patterns = [];
|
|
416
|
-
for (const candidate of input.candidates) {
|
|
417
|
-
const normalized = candidate.replace(/\\/g, "/");
|
|
418
|
-
if (normalized.includes("*")) {
|
|
419
|
-
patterns.push(normalized);
|
|
420
|
-
}
|
|
421
|
-
else {
|
|
422
|
-
concrete.add(normalized);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
if (patterns.length === 0)
|
|
426
|
-
return [...concrete].sort();
|
|
427
|
-
const workspace = [...new Set(input.workspaceFiles.map((f) => f.replace(/\\/g, "/")))];
|
|
428
|
-
for (const file of workspace) {
|
|
429
|
-
if (patterns.some((pattern) => pathMatchesPattern(file, pattern))) {
|
|
430
|
-
concrete.add(file);
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
return [...concrete].sort();
|
|
434
|
-
}
|
|
@@ -370,6 +370,38 @@ async function inspectPath(repoRoot, relPath, deps) {
|
|
|
370
370
|
throw error;
|
|
371
371
|
}
|
|
372
372
|
}
|
|
373
|
+
/**
|
|
374
|
+
* Build the CAS attempt side of a rollback journal from the current worktree.
|
|
375
|
+
* This is used by high-risk artifact continuations, where the baseline is
|
|
376
|
+
* captured before the child starts and the complete attempt inventory is
|
|
377
|
+
* derived after the child settles (including changes from dynamic writers).
|
|
378
|
+
*/
|
|
379
|
+
export async function recordWriterAttemptFromCurrent(snapshot, options) {
|
|
380
|
+
const deps = resolveDeps(options.dependencies);
|
|
381
|
+
const working = structuredClone(snapshot);
|
|
382
|
+
const baselineByPath = new Map(working.existingFiles.map((file) => [file.path, file]));
|
|
383
|
+
const currentMatches = [];
|
|
384
|
+
await walkMatchingEntries(options.repoRoot, "", working.writeSet, deps, (match) => currentMatches.push(match));
|
|
385
|
+
const candidatePaths = new Set([
|
|
386
|
+
...baselineByPath.keys(),
|
|
387
|
+
...currentMatches.map((match) => match.relPath),
|
|
388
|
+
]);
|
|
389
|
+
const attemptChangedPaths = [];
|
|
390
|
+
const attemptFileHashes = {};
|
|
391
|
+
for (const relPath of [...candidatePaths].sort((left, right) => left.localeCompare(right))) {
|
|
392
|
+
const baseline = baselineByPath.get(relPath);
|
|
393
|
+
const current = await inspectPath(options.repoRoot, relPath, deps);
|
|
394
|
+
const currentHash = current.kind === "absent" ? "absent" : current.hash;
|
|
395
|
+
const baselineHash = baseline?.baselineSha256 ?? "absent";
|
|
396
|
+
if (currentHash === baselineHash)
|
|
397
|
+
continue;
|
|
398
|
+
attemptChangedPaths.push(relPath);
|
|
399
|
+
attemptFileHashes[relPath] = currentHash;
|
|
400
|
+
}
|
|
401
|
+
working.attemptChangedPaths = attemptChangedPaths;
|
|
402
|
+
working.attemptFileHashes = attemptFileHashes;
|
|
403
|
+
return frontendWriterRollbackV1Schema.parse(working);
|
|
404
|
+
}
|
|
373
405
|
function ensureJournalFile(working, relPath, baselineSha256, attemptSha256) {
|
|
374
406
|
let file = working.journal.files[relPath];
|
|
375
407
|
if (!file) {
|