@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 @@
|
|
|
1
|
+
export { assertReadableRegularFile, assertRealPathInsideBoundary, readFileBoundarySafe, } from "../../shared/path-safety.js";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import { DEFAULT_DAG_OUTPUT_LANGUAGE, } from "./types.js";
|
|
2
3
|
import { formatStdoutPreview, formatUpstreamArtifactPointerMap, } from "./upstream-artifacts.js";
|
|
3
4
|
export const MAX_UPSTREAM_CHARS = 2_000;
|
|
@@ -18,6 +19,40 @@ const RERUN_FEEDBACK_ROLES = new Set([
|
|
|
18
19
|
"verifier",
|
|
19
20
|
"reviewer",
|
|
20
21
|
]);
|
|
22
|
+
function globPatternToRegExp(pattern) {
|
|
23
|
+
const normalized = pattern.replace(/\\/g, "/");
|
|
24
|
+
let source = "";
|
|
25
|
+
for (let index = 0; index < normalized.length; index += 1) {
|
|
26
|
+
const char = normalized[index];
|
|
27
|
+
if (char === "*" && normalized[index + 1] === "*") {
|
|
28
|
+
source += ".*";
|
|
29
|
+
index += 1;
|
|
30
|
+
}
|
|
31
|
+
else if (char === "*") {
|
|
32
|
+
source += "[^/]*";
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
source += char.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return new RegExp(`^${source}$`);
|
|
39
|
+
}
|
|
40
|
+
function readSetAllowsArtifactPath(task, artifactPath) {
|
|
41
|
+
const readSet = task.readSet ?? [];
|
|
42
|
+
if (readSet.length === 0)
|
|
43
|
+
return true;
|
|
44
|
+
const candidate = artifactPath.replace(/\\/g, "/");
|
|
45
|
+
const candidates = [candidate];
|
|
46
|
+
for (const marker of ["/.harness/", "/source/", "/testcase/"]) {
|
|
47
|
+
const index = candidate.indexOf(marker);
|
|
48
|
+
if (index >= 0)
|
|
49
|
+
candidates.push(candidate.slice(index + 1));
|
|
50
|
+
}
|
|
51
|
+
return readSet.some((pattern) => {
|
|
52
|
+
const regex = globPatternToRegExp(pattern);
|
|
53
|
+
return candidates.some((value) => regex.test(value));
|
|
54
|
+
});
|
|
55
|
+
}
|
|
21
56
|
function formatBulletList(items, emptyLabel) {
|
|
22
57
|
if (!items || items.length === 0)
|
|
23
58
|
return emptyLabel;
|
|
@@ -45,9 +80,42 @@ function formatResolvedSkillInstructions(instructions) {
|
|
|
45
80
|
if (!instructions || instructions.length === 0)
|
|
46
81
|
return "(none)";
|
|
47
82
|
return instructions
|
|
48
|
-
.map((instruction) => instruction
|
|
83
|
+
.map((instruction) => formatSkillChecklist(instruction))
|
|
49
84
|
.join("\n\n---\n\n");
|
|
50
85
|
}
|
|
86
|
+
/** Keep skill provenance, but turn bounded inline manuals into a small action list. */
|
|
87
|
+
function formatSkillChecklist(instruction) {
|
|
88
|
+
const metadata = [
|
|
89
|
+
`Skill: ${instruction.name}`,
|
|
90
|
+
`Resolution: ${instruction.resolution}`,
|
|
91
|
+
...(instruction.path ? [`Path: ${instruction.path}`] : []),
|
|
92
|
+
...(instruction.sha256 ? [`Sha256: ${instruction.sha256}`] : []),
|
|
93
|
+
"Injection mode: checklist",
|
|
94
|
+
];
|
|
95
|
+
if (instruction.resolution !== "resolved")
|
|
96
|
+
return [...metadata, instruction.promptText].join("\n");
|
|
97
|
+
const source = instruction.promptText.split("Instructions:\n")[1] ?? "";
|
|
98
|
+
const candidates = source
|
|
99
|
+
.split(/\r?\n/)
|
|
100
|
+
.map((line) => line.trim())
|
|
101
|
+
.filter((line) => /^(?:#{1,3}\s+|[-*]\s+|\d+[.)]\s+)/.test(line) || line.length > 0)
|
|
102
|
+
.map((line) => line.replace(/^#{1,3}\s+/, "").replace(/^[-*]\s+/, "").replace(/^\d+[.)]\s+/, ""))
|
|
103
|
+
.filter((line) => line.length > 0);
|
|
104
|
+
const checklist = [];
|
|
105
|
+
let chars = 0;
|
|
106
|
+
for (const item of candidates) {
|
|
107
|
+
const bounded = item.slice(0, 240);
|
|
108
|
+
if (checklist.length >= 10 || chars + bounded.length > 1_600)
|
|
109
|
+
break;
|
|
110
|
+
checklist.push(`- ${bounded}`);
|
|
111
|
+
chars += bounded.length;
|
|
112
|
+
}
|
|
113
|
+
return [
|
|
114
|
+
...metadata,
|
|
115
|
+
"Checklist (apply these actions; consult the immutable resolved file only when a listed action requires detail):",
|
|
116
|
+
...(checklist.length > 0 ? checklist : ["- Follow the resolved skill's declared workflow."]),
|
|
117
|
+
].join("\n");
|
|
118
|
+
}
|
|
51
119
|
export function formatOutputLanguageBlock(language = DEFAULT_DAG_OUTPUT_LANGUAGE) {
|
|
52
120
|
if (language === "en") {
|
|
53
121
|
return [
|
|
@@ -62,9 +130,10 @@ export function formatOutputLanguageBlock(language = DEFAULT_DAG_OUTPUT_LANGUAGE
|
|
|
62
130
|
"如果当前节点任务明确要求其他语言,以节点的明确要求为准。",
|
|
63
131
|
].join("\n");
|
|
64
132
|
}
|
|
65
|
-
export function buildUpstreamContext(task, upstream, maxChars = MAX_UPSTREAM_CHARS) {
|
|
133
|
+
export function buildUpstreamContext(task, upstream, maxChars = MAX_UPSTREAM_CHARS, runDir) {
|
|
66
134
|
const sections = [];
|
|
67
135
|
const toleratedFailures = new Set(task.failureAwareDependsOn ?? []);
|
|
136
|
+
const consumedArtifactIds = new Set((task.consumesArtifacts ?? []).map((binding) => binding.artifactId));
|
|
68
137
|
for (const depId of task.depends_on) {
|
|
69
138
|
const record = upstream[depId];
|
|
70
139
|
const stdout = record?.stdout?.trim() ? record.stdout : "";
|
|
@@ -94,7 +163,7 @@ export function buildUpstreamContext(task, upstream, maxChars = MAX_UPSTREAM_CHA
|
|
|
94
163
|
: artifactKind === "assistant"
|
|
95
164
|
? record.assistantArtifactPath
|
|
96
165
|
: undefined;
|
|
97
|
-
if (truncated && artifactPath) {
|
|
166
|
+
if (truncated && artifactPath && readSetAllowsArtifactPath(task, artifactPath)) {
|
|
98
167
|
section += formatUpstreamArtifactPointerMap(record, artifactKind === "stdout" ? "stdout" : "assistant");
|
|
99
168
|
}
|
|
100
169
|
else if (truncated && record.nodeRecordPath) {
|
|
@@ -118,6 +187,22 @@ export function buildUpstreamContext(task, upstream, maxChars = MAX_UPSTREAM_CHA
|
|
|
118
187
|
}
|
|
119
188
|
if (!record || record.status !== "FINISHED")
|
|
120
189
|
continue;
|
|
190
|
+
const consumedArtifacts = (record.declaredArtifacts ?? []).filter((artifact) => consumedArtifactIds.has(artifact.artifactId));
|
|
191
|
+
const consumedArtifactSection = runDir && consumedArtifacts.length > 0
|
|
192
|
+
? [
|
|
193
|
+
"Declared artifact bindings (read-only run evidence — use the exact paths below; do not edit):",
|
|
194
|
+
...consumedArtifacts.flatMap((artifact) => {
|
|
195
|
+
const absolutePath = path.resolve(runDir, ...artifact.path.split("/"));
|
|
196
|
+
return [
|
|
197
|
+
`- artifactId: ${artifact.artifactId}`,
|
|
198
|
+
` path: ${absolutePath}`,
|
|
199
|
+
` status: ${artifact.status}`,
|
|
200
|
+
` sha256: ${artifact.sha256 ?? "unknown"}`,
|
|
201
|
+
` mediaType: ${artifact.mediaType}`,
|
|
202
|
+
];
|
|
203
|
+
}),
|
|
204
|
+
].join("\n")
|
|
205
|
+
: "";
|
|
121
206
|
if (record.structuredArtifactPath &&
|
|
122
207
|
record.structuredArtifactSchemaId ===
|
|
123
208
|
"frontend-implementation-contract-v1") {
|
|
@@ -130,8 +215,12 @@ export function buildUpstreamContext(task, upstream, maxChars = MAX_UPSTREAM_CHA
|
|
|
130
215
|
].join("\n"));
|
|
131
216
|
continue;
|
|
132
217
|
}
|
|
133
|
-
if (!upstreamText)
|
|
218
|
+
if (!upstreamText) {
|
|
219
|
+
if (consumedArtifactSection) {
|
|
220
|
+
sections.push(`## Upstream output: ${depId}\n${consumedArtifactSection}`);
|
|
221
|
+
}
|
|
134
222
|
continue;
|
|
223
|
+
}
|
|
135
224
|
const artifactKind = stdout ? "stdout" : "assistant";
|
|
136
225
|
const artifactPath = stdout
|
|
137
226
|
? record.stdoutArtifactPath
|
|
@@ -147,7 +236,10 @@ export function buildUpstreamContext(task, upstream, maxChars = MAX_UPSTREAM_CHA
|
|
|
147
236
|
`- sha256: ${record.structuredArtifactSha256 ?? "unknown"}`,
|
|
148
237
|
].join("\n");
|
|
149
238
|
}
|
|
150
|
-
if (
|
|
239
|
+
if (consumedArtifactSection) {
|
|
240
|
+
section += `\n\n${consumedArtifactSection}`;
|
|
241
|
+
}
|
|
242
|
+
if (truncated && artifactPath && readSetAllowsArtifactPath(task, artifactPath)) {
|
|
151
243
|
section += formatUpstreamArtifactPointerMap(record, artifactKind);
|
|
152
244
|
}
|
|
153
245
|
sections.push(section);
|
|
@@ -329,7 +421,7 @@ function formatProjectGovernanceContext(ctx) {
|
|
|
329
421
|
return lines.join("\n");
|
|
330
422
|
}
|
|
331
423
|
export function buildDagNodePromptEnvelope(input) {
|
|
332
|
-
const { spec, task, upstream, resolvedSkills = [], resolvedSkillInstructions = [], maxUpstreamChars = MAX_UPSTREAM_CHARS, projectGovernanceContext, convergenceFeedback, } = input;
|
|
424
|
+
const { spec, task, upstream, runDir, resolvedSkills = [], resolvedSkillInstructions = [], maxUpstreamChars = MAX_UPSTREAM_CHARS, projectGovernanceContext, convergenceFeedback, } = input;
|
|
333
425
|
const objective = spec.objective ?? spec.title;
|
|
334
426
|
const successCriteria = formatBulletList(spec.successCriteria, "(none specified)");
|
|
335
427
|
const globalConstraints = formatBulletList(spec.globalConstraints, "(none specified)");
|
|
@@ -339,7 +431,7 @@ export function buildDagNodePromptEnvelope(input) {
|
|
|
339
431
|
? resolvedSkills.map((skill) => `- ${skill}`).join("\n")
|
|
340
432
|
: "(none)";
|
|
341
433
|
const skillInstructionsSection = formatResolvedSkillInstructions(resolvedSkillInstructions);
|
|
342
|
-
const upstreamContext = buildUpstreamContext(task, upstream, maxUpstreamChars);
|
|
434
|
+
const upstreamContext = buildUpstreamContext(task, upstream, maxUpstreamChars, runDir);
|
|
343
435
|
const readOnlyBoundary = buildReadOnlyBoundary(writePolicy);
|
|
344
436
|
const sections = [
|
|
345
437
|
`<dag_objective>\n${objective}\n</dag_objective>`,
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { hostname as localHostname } from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
6
|
+
import { writeJsonAtomic } from "../../infrastructure/harness/atomic-write.js";
|
|
7
|
+
import { DAG_RUNS_DIR } from "./lifecycle.js";
|
|
8
|
+
function recoveryLeasePath(cwd, parentRunId) {
|
|
9
|
+
// Never derive a filesystem name directly from an externally supplied legacy
|
|
10
|
+
// run id. The content remains auditable while the filename is traversal-safe.
|
|
11
|
+
const key = createHash("sha256").update(parentRunId).digest("hex");
|
|
12
|
+
return path.join(cwd, DAG_RUNS_DIR, ".recovery-leases", `${key}.json`);
|
|
13
|
+
}
|
|
14
|
+
function parseLease(raw, parentRunId) {
|
|
15
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
16
|
+
throw new Error("invalid dag recovery lease: expected object");
|
|
17
|
+
}
|
|
18
|
+
const record = raw;
|
|
19
|
+
if (record.schemaVersion !== 1 ||
|
|
20
|
+
record.parentRunId !== parentRunId ||
|
|
21
|
+
typeof record.requestId !== "string" ||
|
|
22
|
+
record.requestId.length === 0 ||
|
|
23
|
+
(record.kind !== "auto-frontend-recovery" &&
|
|
24
|
+
record.kind !== "rerun-from-node" &&
|
|
25
|
+
record.kind !== "standalone-task-rerun") ||
|
|
26
|
+
typeof record.leaseToken !== "string" ||
|
|
27
|
+
record.leaseToken.length === 0 ||
|
|
28
|
+
typeof record.ownerPid !== "number" ||
|
|
29
|
+
!Number.isInteger(record.ownerPid) ||
|
|
30
|
+
record.ownerPid <= 0 ||
|
|
31
|
+
typeof record.ownerHostname !== "string" ||
|
|
32
|
+
record.ownerHostname.length === 0 ||
|
|
33
|
+
typeof record.acquiredAt !== "string" ||
|
|
34
|
+
typeof record.executionRef !== "undefined" &&
|
|
35
|
+
typeof record.executionRef !== "string") {
|
|
36
|
+
throw new Error("invalid dag recovery lease: schema mismatch");
|
|
37
|
+
}
|
|
38
|
+
return record;
|
|
39
|
+
}
|
|
40
|
+
const LEASE_MUTATION_LOCK_STALE_MS = 60_000;
|
|
41
|
+
const LEASE_MUTATION_LOCK_RETRIES = 200;
|
|
42
|
+
async function withLeaseMutationLock(leasePath, operation) {
|
|
43
|
+
const lockPath = `${leasePath}.mutation-lock`;
|
|
44
|
+
for (let attempt = 0; attempt < LEASE_MUTATION_LOCK_RETRIES; attempt += 1) {
|
|
45
|
+
try {
|
|
46
|
+
await mkdir(lockPath);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (!(error && typeof error === "object" && "code" in error && error.code === "EEXIST")) {
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const lockStat = await stat(lockPath);
|
|
54
|
+
if (Date.now() - lockStat.mtimeMs >= LEASE_MUTATION_LOCK_STALE_MS) {
|
|
55
|
+
await rm(lockPath, { recursive: true, force: true });
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (statError) {
|
|
60
|
+
if (statError &&
|
|
61
|
+
typeof statError === "object" &&
|
|
62
|
+
"code" in statError &&
|
|
63
|
+
statError.code === "ENOENT") {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
throw statError;
|
|
67
|
+
}
|
|
68
|
+
await delay(10);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
return await operation();
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
await rm(lockPath, { recursive: true, force: true });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
throw new Error("dag recovery lease mutation lock is busy");
|
|
79
|
+
}
|
|
80
|
+
function defaultIsProcessAlive(pid) {
|
|
81
|
+
try {
|
|
82
|
+
process.kill(pid, 0);
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function leaseOwnerIsAlive(input) {
|
|
90
|
+
if (input.lease.ownerHostname !== input.hostname)
|
|
91
|
+
return true;
|
|
92
|
+
return input.isProcessAlive(input.lease.ownerPid);
|
|
93
|
+
}
|
|
94
|
+
export async function acquireDagRecoveryLease(input) {
|
|
95
|
+
const leasePath = recoveryLeasePath(input.cwd, input.parentRunId);
|
|
96
|
+
const lease = {
|
|
97
|
+
schemaVersion: 1,
|
|
98
|
+
parentRunId: input.parentRunId,
|
|
99
|
+
requestId: input.requestId,
|
|
100
|
+
kind: input.kind,
|
|
101
|
+
leaseToken: randomBytes(16).toString("hex"),
|
|
102
|
+
ownerPid: process.pid,
|
|
103
|
+
ownerHostname: localHostname(),
|
|
104
|
+
acquiredAt: (input.now ?? (() => new Date()))().toISOString(),
|
|
105
|
+
};
|
|
106
|
+
await mkdir(path.dirname(leasePath), { recursive: true });
|
|
107
|
+
try {
|
|
108
|
+
// `wx` is the cross-process compare-and-create primitive. The lease is
|
|
109
|
+
// parent-scoped for the full recovery lineage. Ownership may only be
|
|
110
|
+
// replaced by claimDagRecoveryLease after the recorded owner is proven dead.
|
|
111
|
+
await writeFile(leasePath, `${JSON.stringify(lease, null, 2)}\n`, {
|
|
112
|
+
encoding: "utf8",
|
|
113
|
+
flag: "wx",
|
|
114
|
+
});
|
|
115
|
+
return { kind: "acquired", leasePath, lease };
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
if (!(error && typeof error === "object" && "code" in error && error.code === "EEXIST")) {
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
const existing = parseLease(JSON.parse(await readFile(leasePath, "utf8")), input.parentRunId);
|
|
122
|
+
return { kind: "held", leasePath, lease: existing };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Reclaim a lease only after its recorded same-host owner is proven dead.
|
|
127
|
+
* The mutation lock serializes reclaim with execution binding, so a live owner
|
|
128
|
+
* can never race a stale-owner takeover and launch a second recovery.
|
|
129
|
+
*/
|
|
130
|
+
export async function claimDagRecoveryLease(input) {
|
|
131
|
+
const hostname = input.hostname ?? localHostname();
|
|
132
|
+
const isProcessAlive = input.isProcessAlive ?? defaultIsProcessAlive;
|
|
133
|
+
return withLeaseMutationLock(input.leasePath, async () => {
|
|
134
|
+
const existing = parseLease(JSON.parse(await readFile(input.leasePath, "utf8")), input.lease.parentRunId);
|
|
135
|
+
if (existing.leaseToken !== input.lease.leaseToken ||
|
|
136
|
+
leaseOwnerIsAlive({ lease: existing, hostname, isProcessAlive })) {
|
|
137
|
+
return { kind: "held", leasePath: input.leasePath, lease: existing };
|
|
138
|
+
}
|
|
139
|
+
const claimed = {
|
|
140
|
+
...existing,
|
|
141
|
+
leaseToken: randomBytes(16).toString("hex"),
|
|
142
|
+
ownerPid: process.pid,
|
|
143
|
+
ownerHostname: hostname,
|
|
144
|
+
acquiredAt: (input.now ?? (() => new Date()))().toISOString(),
|
|
145
|
+
};
|
|
146
|
+
await writeJsonAtomic(input.leasePath, claimed);
|
|
147
|
+
return { kind: "acquired", leasePath: input.leasePath, lease: claimed };
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/** Persist the operation/run identity before the caller is allowed to execute it. */
|
|
151
|
+
export async function bindDagRecoveryLeaseExecution(input) {
|
|
152
|
+
if (!input.executionRef.trim()) {
|
|
153
|
+
throw new Error("dag recovery lease executionRef is required");
|
|
154
|
+
}
|
|
155
|
+
return withLeaseMutationLock(input.leasePath, async () => {
|
|
156
|
+
const existing = parseLease(JSON.parse(await readFile(input.leasePath, "utf8")), input.lease.parentRunId);
|
|
157
|
+
if (existing.leaseToken !== input.lease.leaseToken) {
|
|
158
|
+
throw new Error("dag recovery lease ownership drift");
|
|
159
|
+
}
|
|
160
|
+
if (existing.executionRef && existing.executionRef !== input.executionRef) {
|
|
161
|
+
throw new Error("dag recovery lease execution identity drift");
|
|
162
|
+
}
|
|
163
|
+
const bound = {
|
|
164
|
+
...existing,
|
|
165
|
+
executionRef: input.executionRef,
|
|
166
|
+
};
|
|
167
|
+
await writeJsonAtomic(input.leasePath, bound);
|
|
168
|
+
return bound;
|
|
169
|
+
});
|
|
170
|
+
}
|
|
@@ -125,6 +125,8 @@ const dagNodeArtifactsReportSchema = z
|
|
|
125
125
|
humanEscalationMd: dagArtifactRefSchema,
|
|
126
126
|
humanApproval: dagArtifactRefSchema,
|
|
127
127
|
humanRejection: dagArtifactRefSchema,
|
|
128
|
+
changeManifest: dagArtifactRefSchema,
|
|
129
|
+
changeManifestChangedFiles: z.array(z.string()).optional(),
|
|
128
130
|
})
|
|
129
131
|
.strict();
|
|
130
132
|
const dagNodeReportRowSchema = z
|
|
@@ -259,6 +261,20 @@ export async function probeArtifact(filePath) {
|
|
|
259
261
|
export async function buildNodeArtifactsReport(runDir, nodeId) {
|
|
260
262
|
const nodeDir = path.join(runDir, nodeId);
|
|
261
263
|
const artifact = (name) => probeArtifact(path.join(nodeDir, name));
|
|
264
|
+
const changeManifestRef = await artifact("change-manifest.json");
|
|
265
|
+
let changeManifestChangedFiles;
|
|
266
|
+
if (changeManifestRef.exists) {
|
|
267
|
+
try {
|
|
268
|
+
const manifest = JSON.parse(await readFile(path.join(nodeDir, "change-manifest.json"), "utf-8"));
|
|
269
|
+
changeManifestChangedFiles = Array.isArray(manifest.changedFiles)
|
|
270
|
+
? manifest.changedFiles
|
|
271
|
+
.filter((item) => typeof item === "string")
|
|
272
|
+
: undefined;
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
// unreadable manifest → leave undefined
|
|
276
|
+
}
|
|
277
|
+
}
|
|
262
278
|
return {
|
|
263
279
|
resultSummary: await artifact("result.summary.md"),
|
|
264
280
|
promptRedacted: await artifact("prompt.redacted.md"),
|
|
@@ -270,6 +286,8 @@ export async function buildNodeArtifactsReport(runDir, nodeId) {
|
|
|
270
286
|
humanEscalationMd: await artifact("human-escalation.md"),
|
|
271
287
|
humanApproval: await artifact("human-approval.json"),
|
|
272
288
|
humanRejection: await artifact("human-rejection.json"),
|
|
289
|
+
changeManifest: changeManifestRef,
|
|
290
|
+
changeManifestChangedFiles,
|
|
273
291
|
};
|
|
274
292
|
}
|
|
275
293
|
function taskById(spec) {
|
|
@@ -726,6 +744,12 @@ function formatArtifactFlags(artifacts) {
|
|
|
726
744
|
flags.push("approval");
|
|
727
745
|
if (artifacts.humanRejection.exists)
|
|
728
746
|
flags.push("rejection");
|
|
747
|
+
if (artifacts.changeManifest.exists) {
|
|
748
|
+
const count = artifacts.changeManifestChangedFiles?.length;
|
|
749
|
+
flags.push(count !== undefined
|
|
750
|
+
? `changed:${count}`
|
|
751
|
+
: "change-manifest");
|
|
752
|
+
}
|
|
729
753
|
return flags.length > 0 ? flags.join(",") : "-";
|
|
730
754
|
}
|
|
731
755
|
function formatTimestamp(value) {
|
|
@@ -749,7 +773,19 @@ function summarizeNodeStatuses(nodes) {
|
|
|
749
773
|
return `${total} total / ${finished} finished / ${failed} failed / ${skipped} skipped / ${pending} pending`;
|
|
750
774
|
}
|
|
751
775
|
function hasArtifact(artifacts) {
|
|
752
|
-
return
|
|
776
|
+
return [
|
|
777
|
+
artifacts.resultSummary,
|
|
778
|
+
artifacts.promptRedacted,
|
|
779
|
+
artifacts.skills,
|
|
780
|
+
artifacts.nodeRecord,
|
|
781
|
+
artifacts.decisionEnvelope,
|
|
782
|
+
artifacts.decisionEnvelopeValidation,
|
|
783
|
+
artifacts.humanEscalationJson,
|
|
784
|
+
artifacts.humanEscalationMd,
|
|
785
|
+
artifacts.humanApproval,
|
|
786
|
+
artifacts.humanRejection,
|
|
787
|
+
artifacts.changeManifest,
|
|
788
|
+
].some((artifact) => artifact.exists);
|
|
753
789
|
}
|
|
754
790
|
function failureRows(run) {
|
|
755
791
|
return run.nodes.filter((node) => node.status === "ERROR" ||
|