@tea-agent/loop-agent 0.43.0-next.9 → 0.43.0
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 +31 -2309
- package/README.md +7 -0
- package/dist/application/dag/args.js +8 -0
- package/dist/application/task-lifecycle/advance.js +38 -7
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +2 -0
- package/dist/cli/program.js +3 -1
- package/dist/cli/update/init-surface-notifier.js +2 -0
- package/dist/cli/update/policy.js +2 -0
- package/dist/commands/client-recovery.js +20 -55
- package/dist/commands/cursor-prompt.js +2 -0
- package/dist/commands/dag-approve.js +2 -0
- package/dist/commands/dag-final-verification.js +2 -0
- package/dist/commands/dag-init-hybrid.js +2 -0
- package/dist/commands/dag-reconcile-tasks.js +2 -0
- package/dist/commands/dag-reject.js +2 -0
- package/dist/commands/dag-report.js +2 -0
- package/dist/commands/dag-rerun.js +2 -0
- package/dist/commands/dag-resume.js +2 -0
- package/dist/commands/dag-workflow-compile.js +2 -0
- package/dist/commands/dag-workflow-plan.js +2 -0
- package/dist/commands/dag-workflow-validate.js +2 -0
- package/dist/commands/delegate.js +2 -0
- package/dist/commands/examples.js +2 -0
- package/dist/commands/import-prd.js +2 -0
- package/dist/commands/init-model-catalog.js +2 -0
- package/dist/commands/init.js +19 -13
- package/dist/commands/instructions.js +2 -0
- package/dist/commands/knowledge.js +2 -0
- package/dist/commands/loop-benchmark.js +2 -0
- package/dist/commands/pi-prompt.js +2 -0
- package/dist/commands/pi-reuse-benchmark.js +2 -0
- package/dist/commands/promote-run.js +2 -0
- package/dist/commands/stats.js +1 -1
- package/dist/commands/study-init.js +2 -0
- package/dist/commands/task-advance.js +34 -0
- package/dist/commands/task-source-prepare.js +2 -0
- package/dist/commands/worktree-create.js +2 -0
- package/dist/commands/worktree-remove.js +2 -0
- package/dist/executors/dag-pi-executor.js +1650 -198
- package/dist/executors/pi-executor.js +85 -3
- package/dist/executors/pi-sdk-executor.js +18 -0
- package/dist/executors/shell-executor.js +93 -7
- package/dist/executors/shell-verification.js +3 -0
- package/dist/executors/shell-write-guard.js +27 -32
- package/dist/governance/exec-plans.js +6 -3
- package/dist/infrastructure/console/app-data.js +6 -0
- package/dist/shared/artifacts-core.js +2 -0
- package/dist/shared/backend-dogfood-preflight.js +47 -0
- package/dist/shared/dag-failure-category.js +3 -0
- package/dist/shared/git-progress.js +2 -0
- package/dist/shared/one-shot-prompt-args.js +2 -0
- package/dist/shared/operator/capabilities.js +180 -0
- package/dist/shared/package-metadata.js +6 -4
- package/dist/shared/pi-context-pressure/extension.js +26 -16
- package/dist/shared/pi-context-pressure/sift-bridge.js +1 -1
- package/dist/shared/pi-provider-recovery.js +182 -0
- package/dist/shared/pi-retry-settings.js +40 -0
- package/dist/shared/reference-context.js +2 -0
- package/dist/task/config-types.js +29 -0
- package/dist/task/contract/project.js +9 -0
- package/dist/task/contract/recover.js +6 -0
- package/dist/task/contract/schema.js +17 -0
- package/dist/task/source-prepare/artifact-meta.js +9 -2
- package/dist/task/source-prepare/build-draft.js +60 -0
- package/dist/task/source-prepare/fragment-inventory.js +4 -1
- package/dist/task/source-prepare/parse-intent.js +36 -11
- package/dist/task/task-demand-routing.js +5 -2
- package/dist/worker/console/chat/browser-automation.js +523 -0
- package/dist/worker/console/chat/browser-policy.js +6 -36
- package/dist/worker/console/chat/browser-routes.js +188 -56
- package/dist/worker/console/chat/explore-tools.js +5 -2
- package/dist/worker/console/chat/pi-mode-loop-isolation.js +155 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/ask-user-question.js +44 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/browser-tools.js +184 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/explore-tools.js +202 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/goal-tools.js +79 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +94 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/scheduled-goal-tools.js +22 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/todo-write.js +38 -0
- package/dist/worker/console/chat/pi-runtime/inspection-types.js +28 -0
- package/dist/worker/console/chat/pi-runtime/inspection.js +439 -0
- package/dist/worker/console/chat/pi-runtime/progressive-tools.js +195 -0
- package/dist/worker/console/chat/pi-runtime/sdk-bindings.js +153 -0
- package/dist/worker/console/chat/pi-runtime/sdk-session.js +5 -0
- package/dist/worker/console/chat/pi-runtime.js +208 -1138
- package/dist/worker/console/chat/routes.js +27 -7
- package/dist/worker/console/chat/scheduled-goal-booking.js +59 -0
- package/dist/worker/console/chat/scheduled-goal-delivery.js +27 -0
- package/dist/worker/console/chat/scheduled-goal-request.js +190 -0
- package/dist/worker/console/chat/sdd-data-alignment.js +1 -1
- package/dist/worker/console/chat/session-mode-view.js +5 -4
- package/dist/worker/console/chat/session-mode.js +18 -12
- package/dist/worker/console/chat/session-store.js +42 -9
- package/dist/worker/console/chat/tool-preview.js +115 -0
- package/dist/worker/console/chat/tools.js +10 -0
- package/dist/worker/console/chat/turn-order.js +13 -0
- package/dist/worker/console/chat/turn-process.js +32 -30
- package/dist/worker/console/console-update-and-init.js +1 -19
- package/dist/worker/console/console-update-runtime.js +5 -20
- package/dist/worker/console/operator-actions.js +63 -1
- package/dist/worker/console/prd-intake-bridge.js +54 -1
- package/dist/worker/console/routes.js +8 -0
- package/dist/worker/console/scheduled-goal-host.js +98 -0
- package/dist/worker/console/scheduled-goal-operation-adapter.js +127 -0
- package/dist/worker/console/server.js +24 -1
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-D_fNbWc_.js → abnfDiagram-N423BO3Z-8-j6y-sd.js} +1 -1
- package/dist/worker/console/static/assets/{arc-_HuqLW6m.js → arc-eoQiMvuk.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-Djy2qY1m.js → architectureDiagram-T3A2C74G-C4A3uMcI.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-bB-1TSyY.js → blockDiagram-VBNYF7ZC-D4zD2F-Q.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-C5Hmghrz.js → c4Diagram-5PPSVZJV-j1RkJziL.js} +1 -1
- package/dist/worker/console/static/assets/channel-ChE7y-cx.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-Duyl39oy.js → chunk-2GRJ4B5K-YBHmhik1.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-x6mdnSyf.js → chunk-2Q5K7J3B-COfWyo9P.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-WlBuFj7W.js → chunk-5RXB4S5H-I99OUkHY.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-CTF429HX.js → chunk-5VM5RSS4-XKxoJNJ4.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-Dwd6r-SF.js → chunk-6Q2QTUOP-DLT_cYx1.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-C-Br82D1.js → chunk-GF5L2VYU-CxcKZ9mV.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-CuGp0DeE.js → chunk-JWPE2WC7-V1EqXdjY.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-CJhFX6Lh.js → chunk-KBJHAD2P-DebTtdFp.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DpGOa_jT.js → chunk-RYQCIY6F-B-ivNRDf.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-DXJaTynd.js → chunk-XXDRQBXY-DC_Ds11b.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C01TCf2X.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C01TCf2X.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CRBZWjE4.js → cose-bilkent-JH36ORCC-sWEqKwIb.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BdXcxtlb.js → cynefin-VYW2F7L2-BXa_dcu4.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-07UKsOts.js → cynefinDiagram-MW4NZA55-C-Mle84F.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-D38p9__S.js → dagre-VZM6K2ZE-CXPDBITe.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-nSiBNNjH.js → diagram-7IWD3JNH-CC-WJQfa.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-BFOTot5D.js → diagram-B4RE2ZJO-CDAV5Vs4.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-DypKaZ6k.js → diagram-LBJQPF4R-CmFiAcNz.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-B6yoOQeW.js → diagram-Q27KOJAE-DPBZHuyn.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-BHYS6viX.js → diagram-UB23O5K3-jUlm_Ds3.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-D2VD5Snj.js → ebnfDiagram-BXEA7PRR-DWhQ3mfY.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-E98mWxN1.js → erDiagram-JOGREHBK-Tr2gMqet.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CT1zxhqP.js → flowDiagram-UKHOOZJN-DJjVQHPA.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-6GcngNcy.js → ganttDiagram-PKOTCBZU-D74dQ4u0.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-DCL6NvKe.js → gitGraphDiagram-DS77QQ5N-DwW0tZ0X.js} +1 -1
- package/dist/worker/console/static/assets/index-BWkIfcrK.css +1 -0
- package/dist/worker/console/static/assets/index-Cdkvw_H6.js +469 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-C0627e-9.js → infoDiagram-6WML65LV-ILCbxJyb.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-C_u3P6Ik.js → ishikawaDiagram-WSZJBQD7-DeuWBQ89.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DPDPv9HL.js → journeyDiagram-NVQOT4AX-CF5ih8Fk.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-D3OHdWiO.js → kanban-definition-27J2QSJJ-C7yOSuRO.js} +1 -1
- package/dist/worker/console/static/assets/{linear-DI88zD7n.js → linear-BDZ9riWi.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-p2l8IrWY.js → mermaid.core-7pKqYtpZ.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-B1bAX-oS.js → mindmap-definition-FAOFIHXS-LeJDybSU.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-DwOnWxdD.js → pegDiagram-VL7TDLO6-BJvT3pMD.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-xRkTXnJC.js → pieDiagram-7S7Q4E2Y-_rGqpMan.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-_9UC5Zio.js → quadrantDiagram-CIZ2JOQS-DPcSv5aA.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-CgEUirWJ.js → railroadDiagram-AXF67PYL-Drxx4hkJ.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-Czbpwiyz.js → requirementDiagram-LRYGKXZP-BCTUdU4z.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-_j7_KiqY.js → sankeyDiagram-W5VNT64P-B6wzbZmB.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-BNJa6Hyi.js → sequenceDiagram-SI44F4Z6-BGt8d3QQ.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-DedpKtOc.js → sizeCapture-X5ZJPWSS-7nlhJKo7.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-BBvthr7c.js → stateDiagram-OKZ733FA-Cv2stqMA.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DC7V5vcq.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-Ds7umgEM.js → swimlanes-SLNWSIFB-qDAo4Yc1.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Bwy4QUTO.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CKa-p1nF.js → timeline-definition-Z64GVDOM-CKbDNKTr.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-LoUNR56o.js → vennDiagram-T6HMQDX7-DI-9EHic.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-Bqbl6ym7.js → wardleyDiagram-T6FBY63Y-BrzzRDpX.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-B8dUg4lf.js → xychartDiagram-ELKLHX3M-BclH5hGh.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/operator-chat/chat-scroll-position.js +24 -0
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +41 -11
- package/dist/worker/console/static-src/operator-chat/compaction-message.js +3 -17
- package/dist/worker/console/static-src/operator-chat/composer-session-ledger.js +192 -0
- package/dist/worker/console/static-src/operator-chat/pending-user-message.js +9 -1
- package/dist/worker/console/static-src/operator-chat/slash-palette-nav.js +15 -5
- package/dist/worker/console/static-src/operator-chat/timeline-merge.js +29 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +92 -38
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +145 -70
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +38 -55
- package/dist/worker/console/static-src/operator-chat/useComposer.js +182 -69
- package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +2 -0
- package/dist/worker/console/static-src/prd-file-import.js +3 -1
- package/dist/worker/console/workspace-context.js +22 -0
- package/dist/worker/console/workspace-initialization.js +209 -0
- package/dist/worker/delivery/git-transaction.js +2 -0
- package/dist/worker/feature/fullstack-validate.js +2 -0
- package/dist/worker/loop-agent/loop-agent-client.js +8 -2
- package/dist/worker/materialize/harness-task-materializer.js +4 -1
- package/dist/worker/metrics/projector.js +1 -1
- package/dist/worker/observability/event-store.js +4 -1
- package/dist/worker/observability/read-model.js +4 -1
- package/dist/worker/observe/node-transparency.js +23 -1
- package/dist/worker/observe/routes.js +4 -0
- package/dist/worker/observe/static/operator-chrome.js +3 -1
- package/dist/worker/observe/static/styles.css +7 -4
- package/dist/worker/observe/static/views/dag-inspector.js +5 -19
- package/dist/worker/outcomes/declared-artifacts.js +2 -0
- package/dist/worker/preflight.js +3 -0
- package/dist/worker/scheduler/scheduled-goal-dispatch.js +117 -0
- package/dist/worker/scheduler/scheduled-goal-evidence.js +167 -0
- package/dist/worker/scheduler/scheduled-goal-recovery.js +62 -0
- package/dist/worker/scheduler/scheduled-goal-store.js +699 -0
- package/dist/worker/scheduler/scheduled-goal-supervisor.js +132 -0
- package/dist/worker/scheduler/scheduled-goal-time.js +102 -0
- package/dist/worker/scheduler/scheduled-goal-types.js +95 -0
- package/dist/worker/task-spec/validate.js +4 -1
- package/dist/workflows/dag/backend-test-markdown-workflow.js +6 -24
- package/dist/workflows/dag/backend-test-plan-protocol.js +82 -5
- package/dist/workflows/dag/dag-retry-schema.js +11 -0
- package/dist/workflows/dag/decision-envelope.js +2 -0
- package/dist/workflows/dag/dynamic-runtime/shared.js +2 -2
- package/dist/workflows/dag/frontend-closeout.js +3 -1
- package/dist/workflows/dag/frontend-committed-facts.js +461 -0
- package/dist/workflows/dag/frontend-durable-tools.js +15 -3
- package/dist/workflows/dag/frontend-implementation-contract.js +369 -12
- package/dist/workflows/dag/frontend-plan-canary.js +53 -0
- package/dist/workflows/dag/frontend-plan-decision-contract.js +803 -0
- package/dist/workflows/dag/frontend-plan-render.js +0 -2
- package/dist/workflows/dag/frontend-provider-capability-matrix.js +8 -61
- package/dist/workflows/dag/frontend-recovery-run.js +57 -0
- package/dist/workflows/dag/frontend-repair.js +55 -76
- package/dist/workflows/dag/frontend-review-context.js +42 -68
- package/dist/workflows/dag/frontend-review-scopes.js +2 -2
- package/dist/workflows/dag/frontend-risk.js +92 -10
- package/dist/workflows/dag/frontend-session-budget.js +117 -3
- package/dist/workflows/dag/frontend-shape.js +11 -55
- package/dist/workflows/dag/frontend-test-execution-evidence.js +35 -10
- package/dist/workflows/dag/frontend-typed-event-store.js +32 -25
- package/dist/workflows/dag/frontend-verification-trace.js +33 -54
- package/dist/workflows/dag/frontend-writer-admission.js +3 -47
- package/dist/workflows/dag/frontend-writer-status.js +0 -23
- package/dist/workflows/dag/init-hybrid.js +47 -19
- package/dist/workflows/dag/interrupt-request.js +2 -0
- package/dist/workflows/dag/lifecycle.js +11 -2
- package/dist/workflows/dag/node-execution.js +50 -13
- package/dist/workflows/dag/reconcile-run.js +2 -0
- package/dist/workflows/dag/repair-artifact.js +3 -1
- package/dist/workflows/dag/report.js +2 -0
- package/dist/workflows/dag/rerun-plan.js +10 -0
- package/dist/workflows/dag/rerun-task.js +79 -1
- package/dist/workflows/dag/retry-policy.js +18 -0
- package/dist/workflows/dag/scheduler.js +2 -4
- package/dist/workflows/dag/types.js +44 -6
- package/dist/workflows/dag/validate.js +4 -0
- package/docs/README.md +1 -0
- package/docs/architecture/runtime-boundaries.md +3 -3
- package/docs/governance/README.md +1 -0
- package/docs/init-surface.manifest.json +1 -0
- package/docs/operations/README.md +2 -0
- package/docs/templates/README.md +1 -1
- package/docs/templates/agent-dag.schema.json +2 -2
- package/docs/templates/backend-test-dag.json +14 -10
- package/docs/templates/frontend-implementation-contract.schema.json +0 -7
- package/package.json +9 -3
- package/skills/frontend-bounded-implement/references/code-standards.md +3 -3
- package/skills/frontend-contract/references/contract-protocol.md +3 -1
- package/skills/frontend-plan/SKILL.md +8 -6
- package/skills/frontend-plan/references/decision-contract.md +3 -3
- package/skills/frontend-review/SKILL.md +18 -28
- package/skills/frontend-review/references/review-findings.md +8 -3
- package/dist/commands/new-task.js +0 -5
- package/dist/commands/status.js +0 -57
- package/dist/commands/task-contract.js +0 -269
- package/dist/shared/prompts.js +0 -26
- package/dist/task/config.js +0 -2
- package/dist/task/contract/validate-draft.js +0 -106
- package/dist/task/goal.js +0 -3
- package/dist/task/index.js +0 -12
- package/dist/task/lifecycle.js +0 -1
- package/dist/task/operator/capabilities.js +0 -6
- package/dist/task/operator/envelope.js +0 -2
- package/dist/task/operator/index.js +0 -5
- package/dist/task/operator/registry.js +0 -2
- package/dist/task/operator/types.js +0 -1
- package/dist/task/paths.js +0 -1
- package/dist/task/source-state.js +0 -1
- package/dist/task/subagent-guidance.js +0 -1
- package/dist/worker/console/chat/sift-bridge.js +0 -1
- package/dist/worker/console/index.js +0 -20
- package/dist/worker/console/static/assets/channel-C0A6UEIa.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DzguNppy.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DzguNppy.js +0 -1
- package/dist/worker/console/static/assets/index-24jp3aBh.js +0 -468
- package/dist/worker/console/static/assets/index-CY6y6I8M.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BABVQnfM.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-D0qsLaxR.js +0 -8
- package/dist/worker/scheduler/index.js +0 -25
- package/dist/workflows/dag/facts.js +0 -4
- package/dist/workflows/dag/frontend-shadow-dual-write.js +0 -975
- package/dist/workflows/dag/index.js +0 -6
- package/dist/workflows/dynamic/index.js +0 -7
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { deliverScheduledGoalResult } from "./chat/scheduled-goal-delivery.js";
|
|
2
|
+
import { ScheduledGoalHost } from "./scheduled-goal-host.js";
|
|
3
|
+
import { ScheduledGoalStore } from "../scheduler/scheduled-goal-store.js";
|
|
1
4
|
/**
|
|
2
5
|
* Repo-scoped Workspace Context (2026-08-22 multi-workspace foundation, W1).
|
|
3
6
|
*
|
|
@@ -39,6 +42,7 @@ import { GoalRegistry } from "./chat/goals.js";
|
|
|
39
42
|
import { GoalRoundDriver } from "./chat/goal-round-driver.js";
|
|
40
43
|
import { TerminalSessionRegistry } from "./chat/terminal-sessions.js";
|
|
41
44
|
import { ScmService } from "./chat/scm-service.js";
|
|
45
|
+
import { BrowserAutomationService } from "./chat/browser-automation.js";
|
|
42
46
|
import { driveGoalRound, recoverDeferredTurns } from "./chat/routes.js";
|
|
43
47
|
import { createOperationEventStore, } from "./operation-sse.js";
|
|
44
48
|
import { OperationStore } from "../../infrastructure/console/operation-store.js";
|
|
@@ -52,6 +56,7 @@ import { probePiReadiness, } from "./pi-readiness.js";
|
|
|
52
56
|
import { resolveSiblingLoopAgentBin } from "./sibling-controller.js";
|
|
53
57
|
import { NightAuxTicker } from "./night-aux-ticker.js";
|
|
54
58
|
import { createObserveRouteContext, } from "../observe/routes.js";
|
|
59
|
+
import { WorkspaceInitializationService } from "./workspace-initialization.js";
|
|
55
60
|
import { WorkspaceRegistry } from "./workspace-registry.js";
|
|
56
61
|
import { resolveConsoleDefaultTimeoutMs } from "./server.js";
|
|
57
62
|
/**
|
|
@@ -242,6 +247,7 @@ export async function createWorkspaceContext(record, deps) {
|
|
|
242
247
|
readiness: readinessCache,
|
|
243
248
|
getReadiness,
|
|
244
249
|
refreshReadiness,
|
|
250
|
+
workspaceInitialization: new WorkspaceInitializationService({ workspaceId: record.workspaceId, name: record.name, repoRoot, client, operations, events, activeChatTurnCount: () => chatTurnExecutions.size() }),
|
|
245
251
|
observeBaseUrl: deps.observeBaseUrl,
|
|
246
252
|
fetchImpl: deps.fetchImpl,
|
|
247
253
|
getConsoleOrigin: deps.getConsoleOrigin,
|
|
@@ -295,6 +301,11 @@ export async function createWorkspaceContext(record, deps) {
|
|
|
295
301
|
// Workspace-scoped git source control shared by the model tool (scm) and
|
|
296
302
|
// the Console UI SCM panel (HTTP API).
|
|
297
303
|
const scmService = new ScmService(repoRoot);
|
|
304
|
+
const browserAutomation = new BrowserAutomationService({
|
|
305
|
+
profileDir: appData.browserProfile,
|
|
306
|
+
downloadsDir: appData.browserDownloads,
|
|
307
|
+
screenshotsDir: appData.browserScreenshots,
|
|
308
|
+
});
|
|
298
309
|
const chatRuntime = new ConsolePiRuntime({
|
|
299
310
|
cwd: repoRoot,
|
|
300
311
|
sessionDir: appData.chatSessions,
|
|
@@ -306,6 +317,7 @@ export async function createWorkspaceContext(record, deps) {
|
|
|
306
317
|
sddDataAlignment,
|
|
307
318
|
terminalRegistry,
|
|
308
319
|
scmService,
|
|
320
|
+
browserAutomation,
|
|
309
321
|
});
|
|
310
322
|
let chatRouteDeps;
|
|
311
323
|
const goalRoundDriver = new GoalRoundDriver((sessionId) => driveGoalRound(chatRouteDeps, sessionId));
|
|
@@ -322,6 +334,7 @@ export async function createWorkspaceContext(record, deps) {
|
|
|
322
334
|
operationLinker: chatOperationLinker,
|
|
323
335
|
terminals: terminalRegistry,
|
|
324
336
|
scm: scmService,
|
|
337
|
+
browserAutomation,
|
|
325
338
|
appData,
|
|
326
339
|
bootToken: deps.bootToken,
|
|
327
340
|
getConsoleOrigin: deps.getConsoleOrigin,
|
|
@@ -330,6 +343,12 @@ export async function createWorkspaceContext(record, deps) {
|
|
|
330
343
|
detachSession: (sessionId) => registry.detachSession(record.workspaceId, sessionId),
|
|
331
344
|
};
|
|
332
345
|
const nightAuxTicker = new NightAuxTicker({ repoRoot, client });
|
|
346
|
+
const scheduledGoals = new ScheduledGoalStore(repoRoot);
|
|
347
|
+
const scheduledGoalHost = new ScheduledGoalHost({
|
|
348
|
+
goals: scheduledGoals, client, operations, events,
|
|
349
|
+
deliver: (goal) => deliverScheduledGoalResult(goal, scheduledGoals, chatStore),
|
|
350
|
+
onError: (goalId, error) => process.stderr.write(`[scheduled-goal] ${goalId ?? "wake"}: ${error instanceof Error ? error.message : String(error)}\n`),
|
|
351
|
+
});
|
|
333
352
|
const observeRouteContext = createObserveRouteContext(repoRoot, {
|
|
334
353
|
staticDir: deps.inspectStaticDir,
|
|
335
354
|
});
|
|
@@ -364,6 +383,7 @@ export async function createWorkspaceContext(record, deps) {
|
|
|
364
383
|
if (disposed)
|
|
365
384
|
return;
|
|
366
385
|
disposed = true;
|
|
386
|
+
scheduledGoalHost.stop();
|
|
367
387
|
try {
|
|
368
388
|
goalRoundDriver.dispose();
|
|
369
389
|
}
|
|
@@ -382,6 +402,7 @@ export async function createWorkspaceContext(record, deps) {
|
|
|
382
402
|
catch {
|
|
383
403
|
// best-effort
|
|
384
404
|
}
|
|
405
|
+
void browserAutomation.dispose();
|
|
385
406
|
try {
|
|
386
407
|
nightAuxTicker.dispose();
|
|
387
408
|
}
|
|
@@ -390,6 +411,7 @@ export async function createWorkspaceContext(record, deps) {
|
|
|
390
411
|
}
|
|
391
412
|
},
|
|
392
413
|
};
|
|
414
|
+
scheduledGoalHost.start();
|
|
393
415
|
return context;
|
|
394
416
|
}
|
|
395
417
|
/** Inspect-facing readiness/capability summary for a registry record. */
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { lstat, readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { acquireUpdateLock, updateLockPath } from "../../shared/update/state.js";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import { TERMINAL_OPERATION_STATES } from "../../infrastructure/console/operation-store.js";
|
|
6
|
+
import { readInitRuntimeActivity } from "../observability/init-runtime-activity.js";
|
|
7
|
+
const record = (value) => {
|
|
8
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
9
|
+
throw new Error("初始化检查返回了无效数据");
|
|
10
|
+
return value;
|
|
11
|
+
};
|
|
12
|
+
const entries = (value) => {
|
|
13
|
+
if (!Array.isArray(value))
|
|
14
|
+
throw new Error("初始化检查缺少状态清单");
|
|
15
|
+
return value.map(record);
|
|
16
|
+
};
|
|
17
|
+
/** A single registered workspace owns checks, CLI cwd and durable operations. */
|
|
18
|
+
export class WorkspaceInitializationService {
|
|
19
|
+
options;
|
|
20
|
+
cached;
|
|
21
|
+
pending;
|
|
22
|
+
activeOperationId;
|
|
23
|
+
generation = 0;
|
|
24
|
+
constructor(options) {
|
|
25
|
+
this.options = options;
|
|
26
|
+
}
|
|
27
|
+
snapshot(state, message, pendingPaths = []) {
|
|
28
|
+
const { workspaceId, name, repoRoot } = this.options;
|
|
29
|
+
return { workspaceId, name, displayPath: repoRoot, state, message, pendingPaths, canUpdate: false, pendingItems: [] };
|
|
30
|
+
}
|
|
31
|
+
async jsonFile(relative) {
|
|
32
|
+
const file = path.join(this.options.repoRoot, relative);
|
|
33
|
+
try {
|
|
34
|
+
const stat = await lstat(file);
|
|
35
|
+
if (!stat.isFile() || stat.isSymbolicLink())
|
|
36
|
+
throw new Error(`${relative} 不是普通配置文件`);
|
|
37
|
+
return record(JSON.parse(await readFile(file, "utf8")));
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error.code === "ENOENT")
|
|
41
|
+
return undefined;
|
|
42
|
+
throw new Error(`${relative} 无法读取,请检查文件内容与权限`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async command(args, name) {
|
|
46
|
+
const result = await this.options.client.run(args, {
|
|
47
|
+
cwd: this.options.repoRoot, artifactName: `workspace-init-${name}`,
|
|
48
|
+
expectJson: true, timeoutMs: 120_000,
|
|
49
|
+
});
|
|
50
|
+
if (!result.ok || result.exitCode !== 0 || result.timedOut || result.parseFailure) {
|
|
51
|
+
throw new Error(`工作区配置${name === "check" ? "检查" : "操作"}失败,请查看操作记录或检查模型与初始化配置`);
|
|
52
|
+
}
|
|
53
|
+
return record(result.json);
|
|
54
|
+
}
|
|
55
|
+
async catalog() {
|
|
56
|
+
const catalog = await this.command(["init", "model-catalog", "--json"], "models");
|
|
57
|
+
return entries(catalog.models).filter(item => item.eligibleForHarness === true && typeof item.reference === "string")
|
|
58
|
+
.map(item => ({ reference: item.reference, name: typeof item.name === "string" ? item.name : item.reference }));
|
|
59
|
+
}
|
|
60
|
+
async inspect() {
|
|
61
|
+
try {
|
|
62
|
+
try {
|
|
63
|
+
const harnessDir = await lstat(path.join(this.options.repoRoot, ".harness"));
|
|
64
|
+
if (!harnessDir.isDirectory() || harnessDir.isSymbolicLink())
|
|
65
|
+
throw new Error(".harness 必须是仓库内的普通目录");
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (error.code !== "ENOENT")
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
const surface = await this.jsonFile(".harness/init-surface.json");
|
|
72
|
+
const harness = await this.jsonFile("harness.json");
|
|
73
|
+
if (surface && (surface.schemaVersion !== 1 || !surface.files || typeof surface.files !== "object" || Array.isArray(surface.files))) {
|
|
74
|
+
throw new Error("初始化记录不完整,请检查 .harness/init-surface.json");
|
|
75
|
+
}
|
|
76
|
+
if (!surface && !harness) {
|
|
77
|
+
const snapshot = this.snapshot("uninitialized", "此仓库尚未初始化。初始化后可使用项目任务与工作流配置。");
|
|
78
|
+
try {
|
|
79
|
+
snapshot.models = await this.catalog();
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
snapshot.message = "此仓库尚未初始化;可用模型读取失败,请检查模型设置后重新检查。";
|
|
83
|
+
}
|
|
84
|
+
return snapshot;
|
|
85
|
+
}
|
|
86
|
+
const report = await this.command(["init", "check-update", "--json"], "check");
|
|
87
|
+
if (!["recorded", "inferred-baseline", "missing"].includes(String(report.surfaceState)) || typeof report.ok !== "boolean") {
|
|
88
|
+
throw new Error("初始化检查返回了未知状态");
|
|
89
|
+
}
|
|
90
|
+
const actions = entries(report.deterministicActions);
|
|
91
|
+
const merges = entries(report.modelMergeTasks);
|
|
92
|
+
const decisions = entries(report.humanDecisions);
|
|
93
|
+
const pendingItems = [];
|
|
94
|
+
for (const [kind, list] of [["safe-update", actions], ["merge", merges], ["confirmation", decisions]]) {
|
|
95
|
+
for (const item of list) {
|
|
96
|
+
if (typeof item.path !== "string")
|
|
97
|
+
continue;
|
|
98
|
+
const detail = typeof item.reason === "string" ? item.reason : undefined;
|
|
99
|
+
const baseline = item.type === "bootstrap-surface";
|
|
100
|
+
const itemKind = baseline ? "confirmation" : kind;
|
|
101
|
+
const reason = baseline ? "缺少可靠的初始化记录,不能直接判断哪些内容可覆盖。"
|
|
102
|
+
: kind === "safe-update" ? "此项可由程序安全更新,保留项目自定义内容。"
|
|
103
|
+
: kind === "merge" ? "现有内容与新版初始化模板不同,需要保留项目配置后合并。"
|
|
104
|
+
: /not a directory/.test(detail ?? "") ? "这里需要一个目录,但当前路径被文件占用。"
|
|
105
|
+
: /removed.*local changes/.test(detail ?? "") ? "新版不再使用此文件,但它包含本地修改,需要决定保留还是删除。"
|
|
106
|
+
: /target path.*already exists/.test(detail ?? "") ? "迁移目标已有不同内容,需要确认两份文件如何保留。"
|
|
107
|
+
: "此项无法安全自动处理,请先核对检查详情,再确定处理方式。";
|
|
108
|
+
pendingItems.push({ path: item.path, kind: itemKind, reason,
|
|
109
|
+
nextStep: itemKind === "safe-update" ? "点击更新按钮即可处理。"
|
|
110
|
+
: itemKind === "merge" ? "可将下方处理说明交给智能体合并;只有需求冲突时才需你确认。"
|
|
111
|
+
: "将处理说明交给智能体检查;需要取舍时确认方案,处理后重新检查。",
|
|
112
|
+
...(detail ? { detail } : {}) });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const modelsReady = record(report.modelReadiness).status === "ready";
|
|
116
|
+
if (!modelsReady)
|
|
117
|
+
pendingItems.push({ path: "模型配置", kind: "model",
|
|
118
|
+
reason: "当前模型配置或认证尚未就绪,更新文件不能解决此问题。",
|
|
119
|
+
nextStep: "检查模型定义及提供商认证,保留仍可用的模型配置,完成后重新检查。" });
|
|
120
|
+
const canUpdate = pendingItems.some(item => item.kind === "safe-update");
|
|
121
|
+
const needsAttention = pendingItems.some(item => item.kind !== "safe-update") || !report.ok || report.surfaceState !== "recorded" && !canUpdate;
|
|
122
|
+
if (needsAttention || canUpdate) {
|
|
123
|
+
const safeCount = pendingItems.filter(item => item.kind === "safe-update").length;
|
|
124
|
+
const message = canUpdate
|
|
125
|
+
? `有 ${safeCount} 项可在此更新。${needsAttention ? "其余待处理项的原因和下一步见下方。" : "更新会保留项目自定义内容。"}`
|
|
126
|
+
: "暂无可直接更新的内容。请按下方原因处理,完成后重新检查。";
|
|
127
|
+
if (!pendingItems.length)
|
|
128
|
+
pendingItems.push({ path: "初始化配置", kind: "confirmation",
|
|
129
|
+
reason: "检查尚未通过,但没有返回可自动更新的项目。",
|
|
130
|
+
nextStep: "复制处理说明交给智能体检查初始化记录,完成后重新检查。" });
|
|
131
|
+
return { ...this.snapshot(needsAttention ? "needs-attention" : "update-available", message, [...new Set(pendingItems.map(item => item.path))]), canUpdate, pendingItems };
|
|
132
|
+
}
|
|
133
|
+
return this.snapshot("ready", "工作区配置已就绪");
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
return this.snapshot("error", error instanceof Error ? error.message : "初始化状态检查失败");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async check(refresh = false) {
|
|
140
|
+
const latest = (await this.options.operations.list()).filter(op => op.action === "workspaceInitialize").at(-1);
|
|
141
|
+
const running = latest && !TERMINAL_OPERATION_STATES.has(latest.state) && latest.state !== "needs-reconcile";
|
|
142
|
+
if (!running && (refresh || !this.cached || Date.now() - this.cached.at > 30_000)) {
|
|
143
|
+
const generation = this.generation;
|
|
144
|
+
this.pending ??= this.inspect().then(value => { if (generation === this.generation)
|
|
145
|
+
this.cached = { value, at: Date.now() }; return value; }).finally(() => { this.pending = undefined; });
|
|
146
|
+
await this.pending;
|
|
147
|
+
}
|
|
148
|
+
const value = this.cached?.value ?? this.snapshot("uninitialized", "正在初始化工作区…");
|
|
149
|
+
return { ...value, ...(latest ? { operation: { operationId: latest.operationId, state: latest.state, ...(latest.errorMessage ? { message: latest.errorMessage } : {}) } } : {}) };
|
|
150
|
+
}
|
|
151
|
+
async start(clientRequestId, model) {
|
|
152
|
+
const created = await this.options.operations.create({ clientRequestId, action: "workspaceInitialize", actionParams: { ...(model ? { model } : {}) } });
|
|
153
|
+
if (created.kind !== "created")
|
|
154
|
+
return created;
|
|
155
|
+
const operationId = created.operation.operationId;
|
|
156
|
+
if (this.activeOperationId) {
|
|
157
|
+
await this.options.operations.update(operationId, { state: "failed", finishedAt: new Date().toISOString(), errorCode: "WORKSPACE_INIT_BUSY", errorMessage: "此工作区已有初始化操作正在运行" });
|
|
158
|
+
return created;
|
|
159
|
+
}
|
|
160
|
+
this.activeOperationId = operationId;
|
|
161
|
+
this.generation += 1;
|
|
162
|
+
queueMicrotask(() => { void this.execute(operationId, model); });
|
|
163
|
+
return created;
|
|
164
|
+
}
|
|
165
|
+
async execute(operationId, model) {
|
|
166
|
+
let release;
|
|
167
|
+
try {
|
|
168
|
+
await this.options.operations.update(operationId, { state: "running", startedAt: new Date().toISOString() });
|
|
169
|
+
this.options.events.append(operationId, { at: new Date().toISOString(), kind: "state", state: "running", message: `正在检查并配置 ${this.options.name}` });
|
|
170
|
+
release = await (this.options.acquireLock ?? (() => acquireUpdateLock(updateLockPath(os.homedir()))))();
|
|
171
|
+
if (!release)
|
|
172
|
+
throw new Error("程序更新或其他初始化操作正在进行,请稍后重试");
|
|
173
|
+
const activity = await (this.options.readActivity ?? readInitRuntimeActivity)(this.options.repoRoot);
|
|
174
|
+
if (activity.workerProjectionError || activity.activeDagRunIds.length || activity.activeWorkerTasks || activity.activeWorkerBatches || this.options.activeChatTurnCount())
|
|
175
|
+
throw new Error("当前工作区有任务或对话正在运行,请结束后重试");
|
|
176
|
+
const operations = await this.options.operations.list();
|
|
177
|
+
if (operations.some(op => op.operationId !== operationId && !TERMINAL_OPERATION_STATES.has(op.state) && op.state !== "needs-reconcile"))
|
|
178
|
+
throw new Error("当前工作区有其他操作正在运行,请稍后重试");
|
|
179
|
+
const before = await this.inspect();
|
|
180
|
+
if (before.state === "error")
|
|
181
|
+
throw new Error(before.message);
|
|
182
|
+
if (before.state === "uninitialized") {
|
|
183
|
+
if (!model || !before.models?.some(item => item.reference === model))
|
|
184
|
+
throw new Error("请选择一个可用的初始模型;可在模型设置中完成认证后重新检查");
|
|
185
|
+
await this.command(["init", "--profile", "full", "--merge", "--client-recovery", "project", "--model", model, "--json"], "apply");
|
|
186
|
+
}
|
|
187
|
+
else if (before.canUpdate) {
|
|
188
|
+
await this.command(["init", "update", "--apply-safe", "--client-recovery", "project", "--json"], "apply");
|
|
189
|
+
}
|
|
190
|
+
else if (before.state !== "ready")
|
|
191
|
+
throw new Error("没有可安全更新的内容;请查看待处理项的原因和下一步。");
|
|
192
|
+
const after = await this.inspect();
|
|
193
|
+
this.cached = { value: after, at: Date.now() };
|
|
194
|
+
const state = after.state === "ready" ? "succeeded" : "needs-reconcile";
|
|
195
|
+
await this.options.operations.update(operationId, { state, finishedAt: new Date().toISOString(), result: { initialization: after }, ...(state !== "succeeded" ? { errorCode: "INIT_NEEDS_RECONCILE", errorMessage: after.message } : {}) });
|
|
196
|
+
this.options.events.append(operationId, { at: new Date().toISOString(), kind: "state", state, message: after.message });
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
this.cached = undefined;
|
|
200
|
+
const message = error instanceof Error ? error.message : "工作区初始化失败";
|
|
201
|
+
await this.options.operations.update(operationId, { state: "failed", finishedAt: new Date().toISOString(), errorCode: "WORKSPACE_INIT_FAILED", errorMessage: message });
|
|
202
|
+
this.options.events.append(operationId, { at: new Date().toISOString(), kind: "error", state: "failed", message });
|
|
203
|
+
}
|
|
204
|
+
finally {
|
|
205
|
+
this.activeOperationId = undefined;
|
|
206
|
+
await release?.().catch(() => undefined);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -360,6 +360,8 @@ function matchesGlob(filePath, glob) {
|
|
|
360
360
|
let pattern = "^";
|
|
361
361
|
for (let index = 0; index < normalizedGlob.length; index += 1) {
|
|
362
362
|
const char = normalizedGlob[index];
|
|
363
|
+
if (char === undefined)
|
|
364
|
+
continue;
|
|
363
365
|
if (char === "*" && normalizedGlob[index + 1] === "*") {
|
|
364
366
|
pattern += ".*";
|
|
365
367
|
index += 1;
|
|
@@ -204,6 +204,8 @@ export function validateFullstackStructure(input) {
|
|
|
204
204
|
for (let j = i + 1; j < writerNodes.length; j++) {
|
|
205
205
|
const a = writerNodes[i];
|
|
206
206
|
const b = writerNodes[j];
|
|
207
|
+
if (!a || !b)
|
|
208
|
+
continue;
|
|
207
209
|
const aPaths = collectWritePaths(taskSpecs.get(a.id));
|
|
208
210
|
const bPaths = collectWritePaths(taskSpecs.get(b.id));
|
|
209
211
|
if (!writeSetsOverlap(aPaths, bPaths))
|
|
@@ -310,7 +310,10 @@ function findSourceScript(baseArgs, cwd) {
|
|
|
310
310
|
// Look for the last .ts/.js/.mjs/.cjs file in baseArgs
|
|
311
311
|
let scriptIdx = -1;
|
|
312
312
|
for (let i = baseArgs.length - 1; i >= 0; i--) {
|
|
313
|
-
const
|
|
313
|
+
const candidate = baseArgs[i];
|
|
314
|
+
if (candidate === undefined)
|
|
315
|
+
continue;
|
|
316
|
+
const ext = path.extname(candidate).toLowerCase();
|
|
314
317
|
if (ext === ".ts" || ext === ".js" || ext === ".mjs" || ext === ".cjs") {
|
|
315
318
|
scriptIdx = i;
|
|
316
319
|
break;
|
|
@@ -318,7 +321,10 @@ function findSourceScript(baseArgs, cwd) {
|
|
|
318
321
|
}
|
|
319
322
|
if (scriptIdx < 0)
|
|
320
323
|
return undefined;
|
|
321
|
-
const
|
|
324
|
+
const scriptArg = baseArgs[scriptIdx];
|
|
325
|
+
if (scriptArg === undefined)
|
|
326
|
+
return undefined;
|
|
327
|
+
const scriptPath = path.resolve(cwd, scriptArg);
|
|
322
328
|
try {
|
|
323
329
|
const s = statSync(scriptPath);
|
|
324
330
|
if (s.isFile())
|
|
@@ -551,7 +551,10 @@ export function indexAcceptanceItems(raw) {
|
|
|
551
551
|
if (!match)
|
|
552
552
|
continue;
|
|
553
553
|
const id = match[1];
|
|
554
|
-
const
|
|
554
|
+
const body = match[2];
|
|
555
|
+
if (id === undefined || body === undefined)
|
|
556
|
+
continue;
|
|
557
|
+
const summary = compactSummary(body);
|
|
555
558
|
if (!map.has(id))
|
|
556
559
|
map.set(id, summary);
|
|
557
560
|
}
|
|
@@ -110,7 +110,7 @@ export async function projectMonthlyMetrics(input) {
|
|
|
110
110
|
}
|
|
111
111
|
function ratio(numerator, denominator, missingData) { return { numerator, denominator, value: denominator ? numerator / denominator : null, sampleSize: denominator, missingData }; }
|
|
112
112
|
function median(values) { if (!values.length)
|
|
113
|
-
return null; const middle = Math.floor(values.length / 2); return values.length % 2 ? values[middle] : (values[middle - 1] + values[middle]) / 2; }
|
|
113
|
+
return null; const middle = Math.floor(values.length / 2); return values.length % 2 ? (values[middle] ?? 0) : ((values[middle - 1] ?? 0) + (values[middle] ?? 0)) / 2; }
|
|
114
114
|
function inWindow(value, start, end) { const time = new Date(value).getTime(); return time >= start.getTime() && time < end.getTime(); }
|
|
115
115
|
function dedupeRuns(runs) { return [...new Map(runs.map((run) => [run.workerRunId, run])).values()]; }
|
|
116
116
|
async function countBoundaryInterceptions(root, start, end) { let interceptions = 0; let audited = 0; try {
|
|
@@ -11,7 +11,10 @@ function serializeEvent(event) {
|
|
|
11
11
|
}
|
|
12
12
|
/** Identifiers used as event-store path segments must not alter the route. */
|
|
13
13
|
export function isSafeObservabilityIdentifier(value) {
|
|
14
|
-
return
|
|
14
|
+
return (typeof value === "string" &&
|
|
15
|
+
value !== "." &&
|
|
16
|
+
value !== ".." &&
|
|
17
|
+
!/[\\/\0]/.test(value));
|
|
15
18
|
}
|
|
16
19
|
export function createWorkerEventStore(jsonlPath) {
|
|
17
20
|
return {
|
|
@@ -1444,8 +1444,11 @@ async function loadFailureHandoffs(repoRoot) {
|
|
|
1444
1444
|
const match = /^(.+)-failure-closeout-draft\.md$/.exec(entry.name);
|
|
1445
1445
|
if (!match)
|
|
1446
1446
|
continue;
|
|
1447
|
+
const workerRunId = match[1];
|
|
1448
|
+
if (workerRunId === undefined)
|
|
1449
|
+
continue;
|
|
1447
1450
|
handoffs.push({
|
|
1448
|
-
workerRunId
|
|
1451
|
+
workerRunId,
|
|
1449
1452
|
closeoutDraftPath: path.join(handoffDir, entry.name),
|
|
1450
1453
|
});
|
|
1451
1454
|
}
|
|
@@ -106,6 +106,12 @@ export async function loadDagNodeContextSummary(repoRoot, dagRunId, nodeId, atte
|
|
|
106
106
|
body: { error: "Invalid node identifier", reason: "invalid-id" },
|
|
107
107
|
};
|
|
108
108
|
}
|
|
109
|
+
if (!isSafeObservabilityIdentifier(dagRunId)) {
|
|
110
|
+
return {
|
|
111
|
+
status: 400,
|
|
112
|
+
body: { error: "Invalid DAG run identifier", reason: "invalid-id" },
|
|
113
|
+
};
|
|
114
|
+
}
|
|
109
115
|
const loaded = await loadRunFacts(repoRoot, dagRunId);
|
|
110
116
|
if (!loaded.ok)
|
|
111
117
|
return loaded.failure;
|
|
@@ -242,6 +248,12 @@ export async function loadDagNodeArtifactInventory(repoRoot, dagRunId, nodeId) {
|
|
|
242
248
|
body: { error: "Invalid node identifier", reason: "invalid-id" },
|
|
243
249
|
};
|
|
244
250
|
}
|
|
251
|
+
if (!isSafeObservabilityIdentifier(dagRunId)) {
|
|
252
|
+
return {
|
|
253
|
+
status: 400,
|
|
254
|
+
body: { error: "Invalid DAG run identifier", reason: "invalid-id" },
|
|
255
|
+
};
|
|
256
|
+
}
|
|
245
257
|
const loaded = await loadRunFacts(repoRoot, dagRunId);
|
|
246
258
|
if (!loaded.ok)
|
|
247
259
|
return loaded.failure;
|
|
@@ -436,6 +448,8 @@ async function loadVerifiedArtifactBytes(repoRoot, dagRunId, nodeId, artifactId)
|
|
|
436
448
|
}
|
|
437
449
|
}
|
|
438
450
|
export async function loadDagNodeArtifactPreview(repoRoot, dagRunId, nodeId, artifactId) {
|
|
451
|
+
if (!isSafeObservabilityIdentifier(dagRunId) || !isSafeObservabilityIdentifier(nodeId))
|
|
452
|
+
return { status: 400, body: { error: "Invalid DAG run or node identifier", reason: "invalid-id" } };
|
|
439
453
|
const verified = await loadVerifiedArtifactBytes(repoRoot, dagRunId, nodeId, artifactId);
|
|
440
454
|
if (verified.status !== 200)
|
|
441
455
|
return verified;
|
|
@@ -448,6 +462,8 @@ export async function loadDagNodeArtifactPreview(repoRoot, dagRunId, nodeId, art
|
|
|
448
462
|
}
|
|
449
463
|
/** Full text uses the same binding and safety checks as the bounded preview. */
|
|
450
464
|
export async function loadDagNodeArtifactDownload(repoRoot, dagRunId, nodeId, artifactId) {
|
|
465
|
+
if (!isSafeObservabilityIdentifier(dagRunId) || !isSafeObservabilityIdentifier(nodeId))
|
|
466
|
+
return { status: 400, body: { error: "Invalid DAG run or node identifier", reason: "invalid-id" } };
|
|
451
467
|
const verified = await loadVerifiedArtifactBytes(repoRoot, dagRunId, nodeId, artifactId);
|
|
452
468
|
if (verified.status !== 200)
|
|
453
469
|
return verified;
|
|
@@ -469,7 +485,7 @@ async function readValidatedContextReceipt(boundaryRoot, targetPath) {
|
|
|
469
485
|
return effectiveNodeContextV1Schema.safeParse(null);
|
|
470
486
|
}
|
|
471
487
|
export async function loadDagNodeContextComponent(repoRoot, dagRunId, nodeId, attempt, componentIndex) {
|
|
472
|
-
if (!isSafeObservabilityIdentifier(nodeId) || !Number.isSafeInteger(attempt) || attempt < 1 || !Number.isSafeInteger(componentIndex) || componentIndex < 0)
|
|
488
|
+
if (!isSafeObservabilityIdentifier(dagRunId) || !isSafeObservabilityIdentifier(nodeId) || !Number.isSafeInteger(attempt) || attempt < 1 || !Number.isSafeInteger(componentIndex) || componentIndex < 0)
|
|
473
489
|
return { status: 400, body: { error: "Invalid context selection", reason: "invalid-id" } };
|
|
474
490
|
const loaded = await loadRunFacts(repoRoot, dagRunId);
|
|
475
491
|
if (!loaded.ok)
|
|
@@ -502,6 +518,12 @@ function stringField(value, key) {
|
|
|
502
518
|
return typeof value?.[key] === "string" ? value[key] : undefined;
|
|
503
519
|
}
|
|
504
520
|
export async function loadDagRunLineage(repoRoot, dagRunId) {
|
|
521
|
+
if (!isSafeObservabilityIdentifier(dagRunId)) {
|
|
522
|
+
return {
|
|
523
|
+
status: 400,
|
|
524
|
+
body: { error: "Invalid DAG run identifier", reason: "invalid-id" },
|
|
525
|
+
};
|
|
526
|
+
}
|
|
505
527
|
const loaded = await loadRunFacts(repoRoot, dagRunId);
|
|
506
528
|
if (!loaded.ok)
|
|
507
529
|
return loaded.failure;
|
|
@@ -835,6 +835,10 @@ async function handleDagNodeExecutionOutput(_req, res, match, ctx) {
|
|
|
835
835
|
const dagRunId = match.params.id;
|
|
836
836
|
const nodeId = match.params.sub;
|
|
837
837
|
const key = match.query.get("key");
|
|
838
|
+
if (dagRunId === undefined || nodeId === undefined) {
|
|
839
|
+
sendJson(res, 400, { error: "Invalid DAG node execution output selection", reason: "invalid-id" });
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
838
842
|
// Reject path-shaped inputs even if smuggled via key/query aliases.
|
|
839
843
|
if (match.query.has("path") || match.query.has("artifactPath")) {
|
|
840
844
|
sendJson(res, 400, {
|
|
@@ -26,6 +26,7 @@ export const INSPECT_TABS = Object.freeze([
|
|
|
26
26
|
{ id: "dashboard", label: "总览", href: "/#/inspect" },
|
|
27
27
|
{ id: "pool", label: "资源池", href: "/#/inspect/pool" },
|
|
28
28
|
{ id: "failures", label: "异常 Task", href: "/#/inspect/failures" },
|
|
29
|
+
{ id: "scheduled-goals", label: "定时任务", href: "/#/inspect/scheduled-goals" },
|
|
29
30
|
]);
|
|
30
31
|
|
|
31
32
|
export const READINESS_LABELS = Object.freeze({
|
|
@@ -92,7 +93,7 @@ export function parseInspectObjectView(hashValue) {
|
|
|
92
93
|
|
|
93
94
|
/**
|
|
94
95
|
* Inspect 当前 hash 应高亮的工作区 tab href。
|
|
95
|
-
*
|
|
96
|
+
* 一级集合视图映射到各自 tab;下钻/对象页(dag/dags/run/night 等)
|
|
96
97
|
* 不高亮任何 tab——位置由面包屑与上下文 chip 表达(`#/dags` 自 0.33.0
|
|
97
98
|
* 起是独立历史分页页,不再是总览滚动别名)。
|
|
98
99
|
*/
|
|
@@ -106,6 +107,7 @@ export function activeInspectTabHref(hashValue) {
|
|
|
106
107
|
return "/#/inspect/pool";
|
|
107
108
|
}
|
|
108
109
|
if (internal === "/failures") return "/#/inspect/failures";
|
|
110
|
+
if (internal === "/scheduled-goals") return "/#/inspect/scheduled-goals";
|
|
109
111
|
if (internal.startsWith("/feature/")) return "/#/inspect";
|
|
110
112
|
return null;
|
|
111
113
|
}
|
|
@@ -1281,6 +1281,9 @@ body.is-resizing-dag-graph {
|
|
|
1281
1281
|
user-select: none;
|
|
1282
1282
|
}
|
|
1283
1283
|
.dag-inspector-header {
|
|
1284
|
+
/* Keep the attempt menu above the content's sticky timeline toolbar. */
|
|
1285
|
+
position: relative;
|
|
1286
|
+
z-index: 6;
|
|
1284
1287
|
display: grid;
|
|
1285
1288
|
grid-template-columns: minmax(0, 1fr) auto;
|
|
1286
1289
|
gap: var(--space-3);
|
|
@@ -5401,10 +5404,10 @@ button.copy-command:focus-visible {
|
|
|
5401
5404
|
.risk-dag-items { display: grid; gap: 6px; padding-top: 8px; }
|
|
5402
5405
|
/* The hosted Console also has .panel styles; keep the reader shell flush. */
|
|
5403
5406
|
#dag-inspector { padding: 0; gap: 0; }
|
|
5404
|
-
.dag-inspector-header .dag-inspector-attempt-bar { flex-wrap:
|
|
5405
|
-
.dag-inspector-header .dag-inspector-attempt-select { min-width:
|
|
5406
|
-
.dag-inspector-header .dag-inspector-attempt-preview { flex: 1 1
|
|
5407
|
-
.dag-inspector-header .dag-inspector-attempt-category
|
|
5407
|
+
.dag-inspector-header .dag-inspector-attempt-bar { flex-wrap: wrap; gap: 8px; background: transparent; }
|
|
5408
|
+
.dag-inspector-header .dag-inspector-attempt-select { min-width: 112px; flex: 0 0 126px; }
|
|
5409
|
+
.dag-inspector-header .dag-inspector-attempt-preview { flex: 1 1 100px; flex-wrap: wrap; padding: 0; }
|
|
5410
|
+
.dag-inspector-header .dag-inspector-attempt-category { display: inline; white-space: normal; overflow-wrap: anywhere; }
|
|
5408
5411
|
.dag-inspector-header .dag-inspector-attempt-duration { display: none; }
|
|
5409
5412
|
@container (max-width: 560px) {
|
|
5410
5413
|
.process-timeline-toolbar { display: grid; grid-template-columns: minmax(80px, 1fr) 32px 32px 32px; gap: 4px; }
|
|
@@ -3590,21 +3590,13 @@ function buildAttemptBar(dagRunId, node) {
|
|
|
3590
3590
|
|
|
3591
3591
|
const bar = el("div", "dag-inspector-attempt-bar");
|
|
3592
3592
|
bar.appendChild(el("label", "dag-inspector-attempt-label", "执行分次"));
|
|
3593
|
-
const choose = (nextKey
|
|
3593
|
+
const choose = (nextKey) => {
|
|
3594
3594
|
uiState.dagInspectorAttempt = { dagRunId, nodeId: node.nodeId, key: String(nextKey) };
|
|
3595
3595
|
inspectorNodeSelections.set(`${dagRunId}:${node.nodeId}`, uiState.dagInspectorAttempt);
|
|
3596
3596
|
renderDagInspectorForCurrent();
|
|
3597
3597
|
const nextBar = document.querySelector(".dag-inspector-header .dag-inspector-attempt-bar");
|
|
3598
|
-
|
|
3599
|
-
(control && !control.disabled ? control : nextBar?.querySelector(".custom-select-trigger"))?.focus({ preventScroll: true });
|
|
3598
|
+
nextBar?.querySelector(".custom-select-trigger")?.focus({ preventScroll: true });
|
|
3600
3599
|
};
|
|
3601
|
-
const selectedIndex = options.findIndex((option) => option.key === selectedKey);
|
|
3602
|
-
const previous = iconButton("上一次尝试", "ri-arrow-left-s-line");
|
|
3603
|
-
previous.type = "button";
|
|
3604
|
-
previous.dataset.attemptAction = "previous";
|
|
3605
|
-
previous.disabled = selectedIndex <= 0;
|
|
3606
|
-
previous.addEventListener("click", () => choose(options[selectedIndex - 1].key, "previous"));
|
|
3607
|
-
bar.appendChild(previous);
|
|
3608
3600
|
const select = createCustomSelect({
|
|
3609
3601
|
ariaLabel: "选择执行分次",
|
|
3610
3602
|
className: "dag-inspector-attempt-select",
|
|
@@ -3619,12 +3611,6 @@ function buildAttemptBar(dagRunId, node) {
|
|
|
3619
3611
|
// `.value` after assign + change (StubNode handler contract).
|
|
3620
3612
|
select.value = selectedKey;
|
|
3621
3613
|
bar.appendChild(select);
|
|
3622
|
-
const next = iconButton("下一次尝试", "ri-arrow-right-s-line");
|
|
3623
|
-
next.type = "button";
|
|
3624
|
-
next.dataset.attemptAction = "next";
|
|
3625
|
-
next.disabled = selectedIndex >= options.length - 1;
|
|
3626
|
-
next.addEventListener("click", () => choose(options[selectedIndex + 1].key, "next"));
|
|
3627
|
-
bar.appendChild(next);
|
|
3628
3614
|
|
|
3629
3615
|
const selected =
|
|
3630
3616
|
options.find((option) => option.key === selectedKey) ??
|
|
@@ -3636,16 +3622,16 @@ function buildAttemptBar(dagRunId, node) {
|
|
|
3636
3622
|
if (status) {
|
|
3637
3623
|
preview.appendChild(el("span", `badge badge-${status.cls}`, status.label));
|
|
3638
3624
|
}
|
|
3639
|
-
if (status?.cls === "failed"
|
|
3625
|
+
if (status?.cls === "failed") {
|
|
3640
3626
|
// 仅失败尝试显示原因;部分 runtime 会在成功尝试保留
|
|
3641
3627
|
// failureCategory="success",不能将其误映射为「其他失败原因」。
|
|
3642
3628
|
// 未知失败分类仍 fail-closed,raw token 仅保留在 title 诊断中。
|
|
3643
3629
|
const reason = el(
|
|
3644
3630
|
"span",
|
|
3645
3631
|
"dag-inspector-attempt-category",
|
|
3646
|
-
`原因 ${attemptFailureLabel(data.failureCategory)}
|
|
3632
|
+
data.failureCategory ? `原因 ${attemptFailureLabel(data.failureCategory)}` : "未记录失败原因",
|
|
3647
3633
|
);
|
|
3648
|
-
reason.setAttribute("title", `failureCategory ${data.failureCategory}`);
|
|
3634
|
+
if (data.failureCategory) reason.setAttribute("title", `failureCategory ${data.failureCategory}`);
|
|
3649
3635
|
preview.appendChild(reason);
|
|
3650
3636
|
}
|
|
3651
3637
|
if (data.durationMs !== undefined) {
|
|
@@ -12,6 +12,8 @@ export function matchesPathGlob(filePath, glob) {
|
|
|
12
12
|
let pattern = "^";
|
|
13
13
|
for (let index = 0; index < normalizedGlob.length; index += 1) {
|
|
14
14
|
const char = normalizedGlob[index];
|
|
15
|
+
if (char === undefined)
|
|
16
|
+
continue;
|
|
15
17
|
if (char === "*" && normalizedGlob[index + 1] === "*") {
|
|
16
18
|
pattern += ".*";
|
|
17
19
|
index += 1;
|
package/dist/worker/preflight.js
CHANGED
|
@@ -120,6 +120,9 @@ export async function preflightTargetRepo(input) {
|
|
|
120
120
|
}
|
|
121
121
|
if (input.runCheckRepo) {
|
|
122
122
|
const [command, ...args] = input.checkRepoCommand ?? ["bash", "scripts/check-repo.sh"];
|
|
123
|
+
if (command === undefined) {
|
|
124
|
+
throw new Error("check-repo command requires a binary");
|
|
125
|
+
}
|
|
123
126
|
const checkRepo = await input.client.runExternal(command, args, {
|
|
124
127
|
cwd: input.repoRoot,
|
|
125
128
|
artifactName: "check-repo",
|