@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
package/dist/cli/program.js
CHANGED
|
@@ -7,13 +7,14 @@ import { runCoverageAudit } from "../commands/coverage-audit.js";
|
|
|
7
7
|
import { runCoverageReport } from "../commands/coverage-report.js";
|
|
8
8
|
import { parseCursorPromptArgs, printCursorPromptUsage, runCursorPrompt, } from "../commands/cursor-prompt.js";
|
|
9
9
|
import { runDagApprove } from "../commands/dag-approve.js";
|
|
10
|
+
import { runDagArtifact } from "../commands/dag-artifact.js";
|
|
10
11
|
import { runDagFinalVerification } from "../commands/dag-final-verification.js";
|
|
12
|
+
import { runDagContext } from "../commands/dag-context.js";
|
|
11
13
|
import { runDagInitHybrid } from "../commands/dag-init-hybrid.js";
|
|
12
14
|
import { runDagReconcileTasks } from "../commands/dag-reconcile-tasks.js";
|
|
13
15
|
import { runDagReconcileRun } from "../commands/dag-reconcile-run.js";
|
|
14
16
|
import { runDagRequestInterrupt } from "../commands/dag-request-interrupt.js";
|
|
15
17
|
import { runDagRerunTask } from "../commands/dag-rerun-task.js";
|
|
16
|
-
import { runDagFollowUp } from "../commands/dag-follow-up.js";
|
|
17
18
|
import { runDagRerun } from "../commands/dag-rerun.js";
|
|
18
19
|
import { runDagReject } from "../commands/dag-reject.js";
|
|
19
20
|
import { runDagCloseoutDraft, runDagReport } from "../commands/dag-report.js";
|
|
@@ -358,15 +359,18 @@ async function runDagAction(repoRoot, subcommand, rest) {
|
|
|
358
359
|
case "rerun-task":
|
|
359
360
|
await runDagRerunTask(repoRoot, args);
|
|
360
361
|
return;
|
|
361
|
-
case "follow-up":
|
|
362
|
-
await runDagFollowUp(repoRoot, args);
|
|
363
|
-
return;
|
|
364
362
|
case "reconcile-tasks":
|
|
365
363
|
await runDagReconcileTasks(repoRoot, args);
|
|
366
364
|
return;
|
|
367
365
|
case "final-verification":
|
|
368
366
|
await runDagFinalVerification(repoRoot, args);
|
|
369
367
|
return;
|
|
368
|
+
case "context":
|
|
369
|
+
await runDagContext(repoRoot, args);
|
|
370
|
+
return;
|
|
371
|
+
case "artifact":
|
|
372
|
+
await runDagArtifact(repoRoot, args);
|
|
373
|
+
return;
|
|
370
374
|
case "decision": {
|
|
371
375
|
const [decisionSubcommand, ...decisionArgs] = args;
|
|
372
376
|
if (decisionSubcommand === "inspect") {
|
|
@@ -380,7 +384,7 @@ async function runDagAction(repoRoot, subcommand, rest) {
|
|
|
380
384
|
throw new Error("usage: dag decision <inspect|validate> --run-id <id> [--node-id <node-id>]");
|
|
381
385
|
}
|
|
382
386
|
default:
|
|
383
|
-
throw new Error("usage: dag <init-hybrid|execute|validate|workflow-plan|workflow-validate|workflow-compile|approve|reject|resume|status|doctor|report|closeout-draft|reconcile-run|request-interrupt|rerun|rerun-task|reconcile-tasks|final-verification|decision> ...");
|
|
387
|
+
throw new Error("usage: dag <init-hybrid|execute|validate|workflow-plan|workflow-validate|workflow-compile|approve|reject|resume|status|doctor|report|closeout-draft|reconcile-run|request-interrupt|rerun|rerun-task|reconcile-tasks|final-verification|context|artifact|decision> ...");
|
|
384
388
|
}
|
|
385
389
|
}
|
|
386
390
|
function compactArgs(args) {
|
|
@@ -549,10 +553,23 @@ function addDagCommand(program, defaultRepoRoot) {
|
|
|
549
553
|
"request-interrupt",
|
|
550
554
|
"rerun",
|
|
551
555
|
"rerun-task",
|
|
552
|
-
"follow-up",
|
|
553
556
|
"reconcile-tasks",
|
|
554
557
|
"final-verification",
|
|
558
|
+
"context",
|
|
559
|
+
"artifact",
|
|
555
560
|
], defaultRepoRoot);
|
|
561
|
+
const context = dag.commands.find((command) => command.name() === "context");
|
|
562
|
+
if (!context)
|
|
563
|
+
throw new Error("dag context command registration failed");
|
|
564
|
+
context
|
|
565
|
+
.description("Inspect or export a captured effective node context")
|
|
566
|
+
.addHelpText("after", "\nActions:\n show --run-id <id> --node-id <id> --attempt <n> [--json]\n export --run-id <id> --node-id <id> --attempt <n> --output <zip> [--target <generic|pi-session|pi-handoff|readable>] [--redaction <redacted|raw>] [--acknowledge-sensitive-data] [--json]");
|
|
567
|
+
const artifact = dag.commands.find((command) => command.name() === "artifact");
|
|
568
|
+
if (!artifact)
|
|
569
|
+
throw new Error("dag artifact command registration failed");
|
|
570
|
+
artifact
|
|
571
|
+
.description("Inspect artifact consumers or manage staged artifact revisions")
|
|
572
|
+
.addHelpText("after", "\nActions:\n consumers --run-id <id> --node-id <producer> --artifact <path> [--json]\n revision stage --run-id <id> --node-id <producer> --artifact <path> --file <replacement> --request-id <id> [--json]\n revision discard --revision-id <id> --request-id <id> [--json]");
|
|
556
573
|
const validate = createRawArgsCommand("validate", "Validate an Agent DAG spec", defaultRepoRoot);
|
|
557
574
|
configureDagValidate(validate);
|
|
558
575
|
replaceActionWithOptionAwareDispatch(validate, defaultRepoRoot);
|
|
@@ -1328,15 +1328,12 @@ export async function runClientRecovery(input) {
|
|
|
1328
1328
|
}
|
|
1329
1329
|
const plugin = await installProjectOpenCodePlugin({
|
|
1330
1330
|
repoRoot: input.repoRoot,
|
|
1331
|
-
onlyIfMissing: true,
|
|
1332
1331
|
});
|
|
1333
1332
|
const overflowPlugin = await installProjectOpenCodeOverflowCompactPlugin({
|
|
1334
1333
|
repoRoot: input.repoRoot,
|
|
1335
|
-
onlyIfMissing: true,
|
|
1336
1334
|
});
|
|
1337
1335
|
const piExtension = await installProjectPiContextOverflowExtension({
|
|
1338
1336
|
repoRoot: input.repoRoot,
|
|
1339
|
-
onlyIfMissing: true,
|
|
1340
1337
|
});
|
|
1341
1338
|
const pi = await applyProjectPiSettingsMerge({ repoRoot: input.repoRoot });
|
|
1342
1339
|
if (mode !== "user") {
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { lstat, readFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { readRevisionParentArtifact } from "../workflows/dag/context-transfer/operator-actions.js";
|
|
5
|
+
import { readFileBoundarySafe } from "../shared/path-safety.js";
|
|
6
|
+
import { openConsoleAppData } from "../infrastructure/console/app-data.js";
|
|
7
|
+
import { artifactRevisionUploadPath, createArtifactRevision, discardArtifactRevision, acquireArtifactRevisionLease, releaseArtifactRevisionLease, } from "../infrastructure/console/artifact-revision-store.js";
|
|
8
|
+
import { OperationStore } from "../infrastructure/console/operation-store.js";
|
|
9
|
+
import { buildArtifactBindingGraph } from "../workflows/dag/artifact-bindings.js";
|
|
10
|
+
import { resolveArtifactRevisionSchema } from "../workflows/dag/artifact-revision-schema-registry.js";
|
|
11
|
+
import { locateDagRun, readDagRunSpec } from "../workflows/dag/lifecycle.js";
|
|
12
|
+
function parseArtifactArgs(args) {
|
|
13
|
+
const [first, second] = args;
|
|
14
|
+
const action = first === "consumers"
|
|
15
|
+
? "consumers"
|
|
16
|
+
: first === "revision" && second === "stage"
|
|
17
|
+
? "stage"
|
|
18
|
+
: first === "revision" && second === "discard"
|
|
19
|
+
? "discard"
|
|
20
|
+
: undefined;
|
|
21
|
+
if (!action) {
|
|
22
|
+
throw new Error("usage: dag artifact consumers --run-id <run> --node-id <producer> --artifact <path> [--json] | dag artifact revision <stage|discard> ...");
|
|
23
|
+
}
|
|
24
|
+
let runId;
|
|
25
|
+
let nodeId;
|
|
26
|
+
let artifactPath;
|
|
27
|
+
let artifactId;
|
|
28
|
+
let file;
|
|
29
|
+
let candidateUpload;
|
|
30
|
+
let revisionId;
|
|
31
|
+
let requestId;
|
|
32
|
+
let json = false;
|
|
33
|
+
for (let index = action === "consumers" ? 1 : 2; index < args.length; index += 1) {
|
|
34
|
+
const arg = args[index];
|
|
35
|
+
const next = () => args[++index];
|
|
36
|
+
if (arg === "--run-id")
|
|
37
|
+
runId = next();
|
|
38
|
+
else if (arg.startsWith("--run-id="))
|
|
39
|
+
runId = arg.slice(9);
|
|
40
|
+
else if (arg === "--node-id")
|
|
41
|
+
nodeId = next();
|
|
42
|
+
else if (arg.startsWith("--node-id="))
|
|
43
|
+
nodeId = arg.slice(10);
|
|
44
|
+
else if (arg === "--artifact")
|
|
45
|
+
artifactPath = next();
|
|
46
|
+
else if (arg.startsWith("--artifact="))
|
|
47
|
+
artifactPath = arg.slice(11);
|
|
48
|
+
else if (arg === "--artifact-id")
|
|
49
|
+
artifactId = next();
|
|
50
|
+
else if (arg.startsWith("--artifact-id="))
|
|
51
|
+
artifactId = arg.slice(14);
|
|
52
|
+
else if (arg === "--file")
|
|
53
|
+
file = next();
|
|
54
|
+
else if (arg.startsWith("--file="))
|
|
55
|
+
file = arg.slice(7);
|
|
56
|
+
else if (arg === "--candidate-upload")
|
|
57
|
+
candidateUpload = next();
|
|
58
|
+
else if (arg.startsWith("--candidate-upload="))
|
|
59
|
+
candidateUpload = arg.slice(19);
|
|
60
|
+
else if (arg === "--revision-id")
|
|
61
|
+
revisionId = next();
|
|
62
|
+
else if (arg.startsWith("--revision-id="))
|
|
63
|
+
revisionId = arg.slice(14);
|
|
64
|
+
else if (arg === "--request-id")
|
|
65
|
+
requestId = next();
|
|
66
|
+
else if (arg.startsWith("--request-id="))
|
|
67
|
+
requestId = arg.slice(13);
|
|
68
|
+
else if (arg === "--json")
|
|
69
|
+
json = true;
|
|
70
|
+
else
|
|
71
|
+
throw new Error(`unknown dag artifact flag: ${arg}`);
|
|
72
|
+
}
|
|
73
|
+
return { action, runId, nodeId, artifactPath, artifactId, file, candidateUpload, revisionId, requestId, json };
|
|
74
|
+
}
|
|
75
|
+
function sha256(bytes) {
|
|
76
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
77
|
+
}
|
|
78
|
+
function print(value, json, fallback) {
|
|
79
|
+
process.stdout.write(json ? `${JSON.stringify(value, null, 2)}\n` : `${fallback}\n`);
|
|
80
|
+
}
|
|
81
|
+
export async function runDagArtifactCore(repoRoot, args, cliOptions) {
|
|
82
|
+
const input = parseArtifactArgs(args);
|
|
83
|
+
if (input.action === "discard") {
|
|
84
|
+
if (!input.revisionId || !input.requestId) {
|
|
85
|
+
throw new Error("dag artifact revision discard requires --revision-id and --request-id");
|
|
86
|
+
}
|
|
87
|
+
const appData = openConsoleAppData({ repoRoot, ...(cliOptions?.appDataRoot ? { appDataRoot: cliOptions.appDataRoot } : {}) });
|
|
88
|
+
const operations = new OperationStore(appData);
|
|
89
|
+
const created = await operations.create({
|
|
90
|
+
clientRequestId: input.requestId,
|
|
91
|
+
action: "cliArtifactRevisionDiscard",
|
|
92
|
+
actionParams: { revisionId: input.revisionId },
|
|
93
|
+
});
|
|
94
|
+
if (created.kind === "conflict")
|
|
95
|
+
throw new Error(created.code);
|
|
96
|
+
if (created.kind === "idempotent" && created.operation.state === "succeeded") {
|
|
97
|
+
return asRecord(created.operation.result);
|
|
98
|
+
}
|
|
99
|
+
const leaseHolder = `cli-discard:${input.requestId}`;
|
|
100
|
+
const revision = await acquireArtifactRevisionLease({
|
|
101
|
+
appData,
|
|
102
|
+
revisionId: input.revisionId,
|
|
103
|
+
holder: leaseHolder,
|
|
104
|
+
})
|
|
105
|
+
.then(() => discardArtifactRevision({
|
|
106
|
+
appData,
|
|
107
|
+
revisionId: input.revisionId,
|
|
108
|
+
holder: leaseHolder,
|
|
109
|
+
}))
|
|
110
|
+
.finally(() => releaseArtifactRevisionLease({
|
|
111
|
+
appData,
|
|
112
|
+
revisionId: input.revisionId,
|
|
113
|
+
holder: leaseHolder,
|
|
114
|
+
}).catch(() => { }));
|
|
115
|
+
const result = { ok: true, revisionId: revision.revisionId, state: revision.state };
|
|
116
|
+
await operations.update(created.operation.operationId, {
|
|
117
|
+
state: "succeeded",
|
|
118
|
+
startedAt: created.operation.createdAt,
|
|
119
|
+
finishedAt: new Date().toISOString(),
|
|
120
|
+
result,
|
|
121
|
+
});
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
if (!input.runId || !input.nodeId || (!input.artifactPath && !input.artifactId)) {
|
|
125
|
+
throw new Error("dag artifact requires --run-id, --node-id, and --artifact <relative-path> or --artifact-id <id>");
|
|
126
|
+
}
|
|
127
|
+
const located = await locateDagRun(repoRoot, input.runId);
|
|
128
|
+
if (!located)
|
|
129
|
+
throw new Error(`dag run not found: ${input.runId}`);
|
|
130
|
+
const graph = buildArtifactBindingGraph(await readDagRunSpec(located.runDir));
|
|
131
|
+
const declaration = graph.artifacts.find((item) => item.producerNodeId === input.nodeId &&
|
|
132
|
+
(input.artifactId
|
|
133
|
+
? item.artifactId === input.artifactId
|
|
134
|
+
: item.path === input.artifactPath));
|
|
135
|
+
if (!declaration)
|
|
136
|
+
throw new Error("ARTIFACT_BINDING_UNAVAILABLE");
|
|
137
|
+
if (input.action === "consumers") {
|
|
138
|
+
return {
|
|
139
|
+
schemaVersion: 1,
|
|
140
|
+
runId: input.runId,
|
|
141
|
+
nodeId: input.nodeId,
|
|
142
|
+
artifactId: declaration.artifactId,
|
|
143
|
+
artifactPath: declaration.path,
|
|
144
|
+
directConsumerNodeIds: declaration.directConsumerNodeIds,
|
|
145
|
+
graphSha256: graph.artifactGraphSha256,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (!input.requestId || (!input.file && !input.candidateUpload)) {
|
|
149
|
+
throw new Error("dag artifact revision stage requires --file or --candidate-upload, and --request-id");
|
|
150
|
+
}
|
|
151
|
+
const appData = openConsoleAppData({
|
|
152
|
+
repoRoot,
|
|
153
|
+
...(cliOptions?.appDataRoot ? { appDataRoot: cliOptions.appDataRoot } : {}),
|
|
154
|
+
});
|
|
155
|
+
// The candidate upload lives in app-data and is cross-process mutable;
|
|
156
|
+
// resolve + read it TOCTOU-safe (O_NOFOLLOW fd read) instead of
|
|
157
|
+
// lstat-then-readFile, so a swapped symlink can never feed an unintended
|
|
158
|
+
// file into the stage. Both the path resolution (assertSafeAppDataPath
|
|
159
|
+
// rejects symlinks/hardlinks) and the fd read map to the stable
|
|
160
|
+
// ARTIFACT_REVISION_PATH_INVALID code.
|
|
161
|
+
let candidateBytes;
|
|
162
|
+
if (input.candidateUpload) {
|
|
163
|
+
try {
|
|
164
|
+
if (!/^[a-f0-9]{64}$/.test(input.candidateUpload)) {
|
|
165
|
+
throw new Error("invalid --candidate-upload hash");
|
|
166
|
+
}
|
|
167
|
+
const candidatePath = artifactRevisionUploadPath(appData, input.candidateUpload);
|
|
168
|
+
candidateBytes = await readFileBoundarySafe({
|
|
169
|
+
boundaryRoot: path.dirname(candidatePath),
|
|
170
|
+
targetPath: candidatePath,
|
|
171
|
+
label: "candidate upload",
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
176
|
+
if (/symlink|hardlink|single-link|regular|boundary|escap|app-data/i.test(message)) {
|
|
177
|
+
throw new Error("ARTIFACT_REVISION_PATH_INVALID");
|
|
178
|
+
}
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
const candidatePath = path.resolve(repoRoot, input.file);
|
|
184
|
+
const stat = await lstat(candidatePath);
|
|
185
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1) {
|
|
186
|
+
throw new Error("candidate must be an owned regular file");
|
|
187
|
+
}
|
|
188
|
+
candidateBytes = await readFile(candidatePath);
|
|
189
|
+
}
|
|
190
|
+
if (candidateBytes.byteLength > 10 * 1024 * 1024)
|
|
191
|
+
throw new Error("candidate exceeds 10 MiB");
|
|
192
|
+
const operations = new OperationStore(appData);
|
|
193
|
+
const actionParams = {
|
|
194
|
+
runId: input.runId,
|
|
195
|
+
nodeId: input.nodeId,
|
|
196
|
+
artifactPath: declaration.path,
|
|
197
|
+
candidateSha256: sha256(candidateBytes),
|
|
198
|
+
candidateBytes: candidateBytes.byteLength,
|
|
199
|
+
};
|
|
200
|
+
const created = await operations.create({
|
|
201
|
+
clientRequestId: input.requestId,
|
|
202
|
+
action: "cliArtifactRevisionStage",
|
|
203
|
+
actionParams,
|
|
204
|
+
});
|
|
205
|
+
if (created.kind === "conflict")
|
|
206
|
+
throw new Error(created.code);
|
|
207
|
+
if (created.kind === "idempotent" && created.operation.state === "succeeded") {
|
|
208
|
+
return asRecord(created.operation.result);
|
|
209
|
+
}
|
|
210
|
+
const parent = await readRevisionParentArtifact({
|
|
211
|
+
cwd: repoRoot,
|
|
212
|
+
runId: input.runId,
|
|
213
|
+
producerNodeId: input.nodeId,
|
|
214
|
+
artifactId: declaration.artifactId,
|
|
215
|
+
});
|
|
216
|
+
const revision = await createArtifactRevision({
|
|
217
|
+
appData,
|
|
218
|
+
parentRunId: input.runId,
|
|
219
|
+
producerNodeId: input.nodeId,
|
|
220
|
+
declaration: parent.declaration,
|
|
221
|
+
parentSha256: parent.parentSha256,
|
|
222
|
+
parentBytes: parent.parentBytes,
|
|
223
|
+
candidateBytes,
|
|
224
|
+
mediaType: declaration.mediaType,
|
|
225
|
+
artifactSchemaResolver: resolveArtifactRevisionSchema,
|
|
226
|
+
});
|
|
227
|
+
const projected = {
|
|
228
|
+
revisionId: revision.revisionId,
|
|
229
|
+
state: revision.state,
|
|
230
|
+
parent: revision.parent,
|
|
231
|
+
candidate: {
|
|
232
|
+
sha256: revision.candidate.sha256,
|
|
233
|
+
bytes: revision.candidate.bytes,
|
|
234
|
+
mediaType: revision.candidate.mediaType,
|
|
235
|
+
uploadedAt: revision.candidate.uploadedAt,
|
|
236
|
+
},
|
|
237
|
+
validation: revision.validation,
|
|
238
|
+
diff: {
|
|
239
|
+
kind: revision.diff.kind,
|
|
240
|
+
summary: revision.diff.summary,
|
|
241
|
+
truncated: revision.diff.truncated,
|
|
242
|
+
},
|
|
243
|
+
expiresAt: revision.expiresAt,
|
|
244
|
+
};
|
|
245
|
+
const result = { ok: true, revision: projected };
|
|
246
|
+
await operations.update(created.operation.operationId, {
|
|
247
|
+
state: "succeeded",
|
|
248
|
+
startedAt: created.operation.createdAt,
|
|
249
|
+
finishedAt: new Date().toISOString(),
|
|
250
|
+
result,
|
|
251
|
+
});
|
|
252
|
+
return result;
|
|
253
|
+
}
|
|
254
|
+
function asRecord(value) {
|
|
255
|
+
return value && typeof value === "object" ? value : { ok: true };
|
|
256
|
+
}
|
|
257
|
+
export async function runDagArtifact(repoRoot, args) {
|
|
258
|
+
const input = parseArtifactArgs(args);
|
|
259
|
+
try {
|
|
260
|
+
const result = await runDagArtifactCore(repoRoot, args);
|
|
261
|
+
if (input.action === "discard") {
|
|
262
|
+
print(result, input.json, `Discarded ${String(result.revisionId ?? "")}`);
|
|
263
|
+
}
|
|
264
|
+
else if (input.action === "consumers") {
|
|
265
|
+
const consumers = result;
|
|
266
|
+
print(result, input.json, `${consumers.artifactPath}: ${(consumers.directConsumerNodeIds ?? []).join(", ") || "no consumers"}`);
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
print(result, input.json, `Staged revision ${String(result.revisionId ?? "")}`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
catch (error) {
|
|
273
|
+
if (!input.json)
|
|
274
|
+
throw error;
|
|
275
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
276
|
+
const candidateCode = message.split(":", 1)[0]?.trim() ?? "";
|
|
277
|
+
const code = /^[A-Z][A-Z0-9_]+$/.test(candidateCode)
|
|
278
|
+
? candidateCode
|
|
279
|
+
: "INTERNAL_ERROR";
|
|
280
|
+
process.stdout.write(`${JSON.stringify({ schemaVersion: 1, ok: false, error: { code, message } }, null, 2)}\n`);
|
|
281
|
+
process.stderr.write(`${message}\n`);
|
|
282
|
+
process.exitCode = 1;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
@@ -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
|
+
}
|