@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
|
@@ -12,12 +12,21 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import path from "node:path";
|
|
14
14
|
import { readdir, rm } from "node:fs/promises";
|
|
15
|
-
import { readJsonIfExists, writeSecureJson, } from "
|
|
15
|
+
import { readJsonIfExists, writeSecureJson, } from "../../../infrastructure/console/app-data.js";
|
|
16
16
|
import { dispatchOperatorAction } from "../operator-actions.js";
|
|
17
17
|
import { authorizeOperatorChatTool } from "./tools.js";
|
|
18
18
|
import { projectOperationForChat } from "./chat-event-store.js";
|
|
19
19
|
import { scrubSecrets } from "./explore-tools.js";
|
|
20
20
|
import { hashDeferredTurnPayload, parseDeferredTurns, } from "./deferred-turn.js";
|
|
21
|
+
/** True only for a durable session that has never received user work. */
|
|
22
|
+
export function isBlankChatSession(record) {
|
|
23
|
+
return (record.state === "active" &&
|
|
24
|
+
!record.title &&
|
|
25
|
+
!record.displayTitle &&
|
|
26
|
+
record.messages.length === 0 &&
|
|
27
|
+
record.toolInvocations.length === 0 &&
|
|
28
|
+
(record.deferredTurns?.length ?? 0) === 0);
|
|
29
|
+
}
|
|
21
30
|
const CHAT_TITLE_MAX_CHARS = 80;
|
|
22
31
|
/** Safe, one-line bounded title used for placeholders and model output. */
|
|
23
32
|
export function cleanChatTitle(value) {
|
|
@@ -38,6 +47,16 @@ export function cleanChatTitle(value) {
|
|
|
38
47
|
function recordPath(appData, sessionId) {
|
|
39
48
|
return path.join(appData.chats, `${sessionId}.json`);
|
|
40
49
|
}
|
|
50
|
+
/** True when `sessionFile` lives inside this store's dedicated Pi JSONL dir. */
|
|
51
|
+
export function isConsoleOwnedSessionFile(appData, sessionFile) {
|
|
52
|
+
const value = sessionFile?.trim();
|
|
53
|
+
if (!value)
|
|
54
|
+
return false;
|
|
55
|
+
const root = path.resolve(appData.chatSessions);
|
|
56
|
+
const target = path.resolve(value);
|
|
57
|
+
const relative = path.relative(root, target);
|
|
58
|
+
return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
59
|
+
}
|
|
41
60
|
export class ChatSessionStore {
|
|
42
61
|
appData;
|
|
43
62
|
options;
|
|
@@ -81,6 +100,9 @@ export class ChatSessionStore {
|
|
|
81
100
|
...(typeof raw.modelProvider === "string" ? { modelProvider: raw.modelProvider } : {}),
|
|
82
101
|
...(typeof raw.modelId === "string" ? { modelId: raw.modelId } : {}),
|
|
83
102
|
...(typeof raw.thinkingLevel === "string" ? { thinkingLevel: raw.thinkingLevel } : {}),
|
|
103
|
+
...(typeof raw.telemetrySessionId === "string" && raw.telemetrySessionId
|
|
104
|
+
? { telemetrySessionId: raw.telemetrySessionId }
|
|
105
|
+
: {}),
|
|
84
106
|
...(typeof raw.workspaceId === "string" && raw.workspaceId
|
|
85
107
|
? { workspaceId: raw.workspaceId }
|
|
86
108
|
: {}),
|
|
@@ -165,6 +187,7 @@ export class ChatSessionStore {
|
|
|
165
187
|
const now = new Date().toISOString();
|
|
166
188
|
const record = {
|
|
167
189
|
...source,
|
|
190
|
+
telemetrySessionId: undefined,
|
|
168
191
|
sessionId: input.targetSessionId,
|
|
169
192
|
state: "active",
|
|
170
193
|
...(input.targetSessionFile ? { sessionFile: input.targetSessionFile } : { sessionFile: undefined }),
|
|
@@ -179,6 +202,19 @@ export class ChatSessionStore {
|
|
|
179
202
|
return record;
|
|
180
203
|
});
|
|
181
204
|
}
|
|
205
|
+
/** Atomically backfill the per-conversation simulated identity on first use. */
|
|
206
|
+
async ensureTelemetrySessionId(sessionId, createId) {
|
|
207
|
+
return this.serialize(sessionId, async () => {
|
|
208
|
+
const record = await this.get(sessionId);
|
|
209
|
+
if (!record)
|
|
210
|
+
return undefined;
|
|
211
|
+
if (record.telemetrySessionId)
|
|
212
|
+
return record.telemetrySessionId;
|
|
213
|
+
record.telemetrySessionId = createId();
|
|
214
|
+
await this.persist(record);
|
|
215
|
+
return record.telemetrySessionId;
|
|
216
|
+
});
|
|
217
|
+
}
|
|
182
218
|
async rename(sessionId, title) {
|
|
183
219
|
return this.serialize(sessionId, async () => {
|
|
184
220
|
const record = await this.get(sessionId);
|
|
@@ -237,8 +273,14 @@ export class ChatSessionStore {
|
|
|
237
273
|
const record = await this.get(sessionId);
|
|
238
274
|
if (!record)
|
|
239
275
|
return false;
|
|
276
|
+
const sessionFile = record.sessionFile;
|
|
240
277
|
await rm(recordPath(this.appData, sessionId), { force: true });
|
|
241
278
|
this.options.onRecordChange?.(sessionId, undefined);
|
|
279
|
+
// Record first, then best-effort JSONL unlink. Final consistency is
|
|
280
|
+
// "both gone" — a leftover JSONL is harmless, a leftover record is not.
|
|
281
|
+
if (isConsoleOwnedSessionFile(this.appData, sessionFile) && sessionFile) {
|
|
282
|
+
await rm(sessionFile, { force: true }).catch(() => undefined);
|
|
283
|
+
}
|
|
242
284
|
return true;
|
|
243
285
|
});
|
|
244
286
|
}
|
|
@@ -42,6 +42,13 @@ export const SHORTCUTS = [
|
|
|
42
42
|
source: "operator",
|
|
43
43
|
},
|
|
44
44
|
];
|
|
45
|
+
export const SDD_BINGO_SHORTCUT = {
|
|
46
|
+
command: "/sdd-bingo",
|
|
47
|
+
label: "sdd-bingo",
|
|
48
|
+
description: "SDD数据对齐",
|
|
49
|
+
action: "sdd-bingo",
|
|
50
|
+
source: "operator",
|
|
51
|
+
};
|
|
45
52
|
/** Pi Web commands with real browser-equivalent behavior (UI-11). */
|
|
46
53
|
export const WEB_SLASH_COMMANDS = [
|
|
47
54
|
{
|
|
@@ -98,7 +105,7 @@ export function resolveShortcut(input) {
|
|
|
98
105
|
const token = input.trim().split(/\s+/, 1)[0]?.toLowerCase();
|
|
99
106
|
if (!token?.startsWith("/"))
|
|
100
107
|
return undefined;
|
|
101
|
-
const local = [...SHORTCUTS, ...WEB_SLASH_COMMANDS].find((shortcut) => shortcut.command === token);
|
|
108
|
+
const local = [...SHORTCUTS, ...WEB_SLASH_COMMANDS, SDD_BINGO_SHORTCUT].find((shortcut) => shortcut.command === token);
|
|
102
109
|
if (local)
|
|
103
110
|
return { command: local.command, action: local.action };
|
|
104
111
|
return { command: token, action: "unknown" };
|
|
@@ -116,7 +123,7 @@ export function workspaceForShortcut(action) {
|
|
|
116
123
|
* Merge Operator, Web, and dynamic Session commands with conflict dedupe.
|
|
117
124
|
* Priority: operator/web > extension > skill > prompt. /reload is single-card.
|
|
118
125
|
*/
|
|
119
|
-
export function mergeSlashCommands(dynamic = []) {
|
|
126
|
+
export function mergeSlashCommands(dynamic = [], capabilities = {}) {
|
|
120
127
|
const byName = new Map();
|
|
121
128
|
const upsert = (item) => {
|
|
122
129
|
const key = normalizeCommandName(item.command);
|
|
@@ -149,6 +156,15 @@ export function mergeSlashCommands(dynamic = []) {
|
|
|
149
156
|
action: item.action,
|
|
150
157
|
});
|
|
151
158
|
}
|
|
159
|
+
if (capabilities.sddBingo) {
|
|
160
|
+
upsert({
|
|
161
|
+
command: SDD_BINGO_SHORTCUT.command,
|
|
162
|
+
label: SDD_BINGO_SHORTCUT.label,
|
|
163
|
+
description: SDD_BINGO_SHORTCUT.description,
|
|
164
|
+
source: SDD_BINGO_SHORTCUT.source,
|
|
165
|
+
action: SDD_BINGO_SHORTCUT.action,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
152
168
|
for (const item of dynamic) {
|
|
153
169
|
const command = normalizeCommandName(item.command);
|
|
154
170
|
if (!command)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { readJsonIfExists, writeSecureJson } from "
|
|
3
|
+
import { readJsonIfExists, writeSecureJson, } from "../../../infrastructure/console/app-data.js";
|
|
4
4
|
function questionFile(root, sessionId) {
|
|
5
5
|
const safe = sessionId.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 180);
|
|
6
6
|
return path.join(root, `${safe}.json`);
|
|
@@ -4,7 +4,7 @@ import { createNpmUpdateClient } from "../../shared/update/npm-client.js";
|
|
|
4
4
|
import { acquireUpdateLock, updateLockPath } from "../../shared/update/state.js";
|
|
5
5
|
import { readInitRuntimeActivity } from "../observability/init-runtime-activity.js";
|
|
6
6
|
import { performConsoleUpdateAndInit, } from "./console-update-and-init.js";
|
|
7
|
-
import { TERMINAL_OPERATION_STATES } from "
|
|
7
|
+
import { TERMINAL_OPERATION_STATES } from "../../infrastructure/console/operation-store.js";
|
|
8
8
|
export function createConsoleUpdateExecutor(input) {
|
|
9
9
|
return async (channel) => {
|
|
10
10
|
const currentVersion = readPackageVersion(input.packageRoot);
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { appendFile, chmod, mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
|
+
import { randomBytes } from "node:crypto";
|
|
4
|
+
import { assertSafeAppDataPath, readJsonIfExists, writeSecureJson, } from "../../infrastructure/console/app-data.js";
|
|
5
|
+
const diagnosticWriteChains = new Map();
|
|
6
|
+
function serializeDiagnostic(filePath, operation) {
|
|
7
|
+
const previous = diagnosticWriteChains.get(filePath) ?? Promise.resolve();
|
|
8
|
+
const next = previous.then(operation, operation);
|
|
9
|
+
diagnosticWriteChains.set(filePath, next.then(() => undefined, () => undefined));
|
|
10
|
+
return next;
|
|
11
|
+
}
|
|
12
|
+
function diagnosticsPath(appData) {
|
|
13
|
+
const repoNamespace = path.dirname(appData.operations);
|
|
14
|
+
return assertSafeAppDataPath(repoNamespace, path.join(repoNamespace, "context-transfer-diagnostics.json"));
|
|
15
|
+
}
|
|
16
|
+
function safeNonNegative(value) {
|
|
17
|
+
return Number.isFinite(value) && (value ?? 0) >= 0 ? Math.round(value ?? 0) : 0;
|
|
18
|
+
}
|
|
19
|
+
function safeReasonCode(value) {
|
|
20
|
+
if (!value)
|
|
21
|
+
return undefined;
|
|
22
|
+
const normalized = value.trim().slice(0, 96);
|
|
23
|
+
return /^[A-Za-z0-9_.-]+$/.test(normalized) ? normalized : "UNCLASSIFIED";
|
|
24
|
+
}
|
|
25
|
+
export async function recordContextTransferDiagnostic(input) {
|
|
26
|
+
const filePath = diagnosticsPath(input.appData);
|
|
27
|
+
return serializeDiagnostic(filePath, async () => {
|
|
28
|
+
const current = (await readJsonIfExists(filePath)) ?? {
|
|
29
|
+
schemaVersion: 1,
|
|
30
|
+
updatedAt: (input.now ?? new Date()).toISOString(),
|
|
31
|
+
counters: [],
|
|
32
|
+
};
|
|
33
|
+
const dimensions = {
|
|
34
|
+
outcome: input.dimensions.outcome,
|
|
35
|
+
...(input.dimensions.target ? { target: input.dimensions.target } : {}),
|
|
36
|
+
...(input.dimensions.profile ? { profile: input.dimensions.profile } : {}),
|
|
37
|
+
...(input.dimensions.diffKind ? { diffKind: input.dimensions.diffKind } : {}),
|
|
38
|
+
...(safeReasonCode(input.dimensions.reasonCode)
|
|
39
|
+
? { reasonCode: safeReasonCode(input.dimensions.reasonCode) }
|
|
40
|
+
: {}),
|
|
41
|
+
};
|
|
42
|
+
const key = JSON.stringify({ event: input.event, ...dimensions });
|
|
43
|
+
const existing = current.counters.find((counter) => JSON.stringify({ event: counter.event, ...dimensionsFromCounter(counter) }) === key);
|
|
44
|
+
if (existing) {
|
|
45
|
+
existing.count += 1;
|
|
46
|
+
existing.bytes += safeNonNegative(input.dimensions.bytes);
|
|
47
|
+
existing.durationMs += safeNonNegative(input.dimensions.durationMs);
|
|
48
|
+
existing.affectedNodeCount += safeNonNegative(input.dimensions.affectedNodeCount);
|
|
49
|
+
existing.importedNodeCount += safeNonNegative(input.dimensions.importedNodeCount);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
current.counters.push({
|
|
53
|
+
event: input.event,
|
|
54
|
+
...dimensions,
|
|
55
|
+
count: 1,
|
|
56
|
+
bytes: safeNonNegative(input.dimensions.bytes),
|
|
57
|
+
durationMs: safeNonNegative(input.dimensions.durationMs),
|
|
58
|
+
affectedNodeCount: safeNonNegative(input.dimensions.affectedNodeCount),
|
|
59
|
+
importedNodeCount: safeNonNegative(input.dimensions.importedNodeCount),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
current.updatedAt = (input.now ?? new Date()).toISOString();
|
|
63
|
+
await writeSecureJson(filePath, current);
|
|
64
|
+
return current;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function dimensionsFromCounter(counter) {
|
|
68
|
+
return {
|
|
69
|
+
outcome: counter.outcome,
|
|
70
|
+
...(counter.target ? { target: counter.target } : {}),
|
|
71
|
+
...(counter.profile ? { profile: counter.profile } : {}),
|
|
72
|
+
...(counter.diffKind ? { diffKind: counter.diffKind } : {}),
|
|
73
|
+
...(counter.reasonCode ? { reasonCode: counter.reasonCode } : {}),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export async function readContextTransferDiagnostics(appData) {
|
|
77
|
+
return readJsonIfExists(diagnosticsPath(appData));
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Append-only lifecycle event log for context-transfer mutations
|
|
81
|
+
* (exec-plan observability: context_export.* / artifact_revision.* /
|
|
82
|
+
* artifact_rerun.*). Events carry ids, counts, bytes, duration and reason
|
|
83
|
+
* codes only — never prompt text, artifact content, secret finding values or
|
|
84
|
+
* host absolute paths. The Console emits only stages it truly observes;
|
|
85
|
+
* CLI-kernel-internal stages (capture, secret scan, adapters) stay in the
|
|
86
|
+
* kernel's own evidence.
|
|
87
|
+
*/
|
|
88
|
+
export const CONTEXT_TRANSFER_EVENT_LOG_LIMIT = 512;
|
|
89
|
+
const CONTEXT_TRANSFER_EVENT_NAME_PATTERN = /^(?:context_export|artifact_revision|artifact_rerun)\.[a-z][a-z_]{0,47}$/;
|
|
90
|
+
const CONTEXT_TRANSFER_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
|
91
|
+
export async function recordContextTransferEvent(input) {
|
|
92
|
+
const at = (input.now ?? new Date()).toISOString();
|
|
93
|
+
if (!CONTEXT_TRANSFER_EVENT_NAME_PATTERN.test(input.event)) {
|
|
94
|
+
return { recorded: false, total: 0 };
|
|
95
|
+
}
|
|
96
|
+
const fields = input.fields ?? {};
|
|
97
|
+
const entry = {
|
|
98
|
+
schemaVersion: 1,
|
|
99
|
+
at,
|
|
100
|
+
event: input.event,
|
|
101
|
+
...sanitizeLifecycleFields(fields),
|
|
102
|
+
};
|
|
103
|
+
const filePath = lifecycleEventsPath(input.appData);
|
|
104
|
+
return serializeDiagnostic(filePath, async () => {
|
|
105
|
+
await appendLifecycleEvent(filePath, entry);
|
|
106
|
+
const total = await countLifecycleEvents(filePath);
|
|
107
|
+
if (total > CONTEXT_TRANSFER_EVENT_LOG_LIMIT) {
|
|
108
|
+
await trimLifecycleEvents(filePath, CONTEXT_TRANSFER_EVENT_LOG_LIMIT);
|
|
109
|
+
return { recorded: true, total: CONTEXT_TRANSFER_EVENT_LOG_LIMIT };
|
|
110
|
+
}
|
|
111
|
+
return { recorded: true, total };
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
export async function readContextTransferEvents(appData) {
|
|
115
|
+
const filePath = lifecycleEventsPath(appData);
|
|
116
|
+
const raw = await readFile(filePath, "utf8").catch(() => "");
|
|
117
|
+
const events = [];
|
|
118
|
+
for (const line of raw.split("\n")) {
|
|
119
|
+
if (!line.trim())
|
|
120
|
+
continue;
|
|
121
|
+
try {
|
|
122
|
+
const parsed = JSON.parse(line);
|
|
123
|
+
if (parsed &&
|
|
124
|
+
typeof parsed === "object" &&
|
|
125
|
+
parsed.schemaVersion === 1 &&
|
|
126
|
+
typeof parsed.event === "string") {
|
|
127
|
+
events.push(parsed);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// A torn final line after a crash must not break readers.
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return events;
|
|
135
|
+
}
|
|
136
|
+
function lifecycleEventsPath(appData) {
|
|
137
|
+
const repoNamespace = path.dirname(appData.operations);
|
|
138
|
+
return assertSafeAppDataPath(repoNamespace, path.join(repoNamespace, "context-transfer-events.jsonl"));
|
|
139
|
+
}
|
|
140
|
+
function safeLifecycleId(value) {
|
|
141
|
+
if (!value)
|
|
142
|
+
return undefined;
|
|
143
|
+
return CONTEXT_TRANSFER_ID_PATTERN.test(value) ? value : undefined;
|
|
144
|
+
}
|
|
145
|
+
function sanitizeLifecycleFields(fields) {
|
|
146
|
+
return {
|
|
147
|
+
...(safeLifecycleId(fields.runId) ? { runId: fields.runId } : {}),
|
|
148
|
+
...(safeLifecycleId(fields.nodeId) ? { nodeId: fields.nodeId } : {}),
|
|
149
|
+
...(safeLifecycleId(fields.exportId) ? { exportId: fields.exportId } : {}),
|
|
150
|
+
...(safeLifecycleId(fields.revisionId)
|
|
151
|
+
? { revisionId: fields.revisionId }
|
|
152
|
+
: {}),
|
|
153
|
+
...(safeLifecycleId(fields.operationId)
|
|
154
|
+
? { operationId: fields.operationId }
|
|
155
|
+
: {}),
|
|
156
|
+
...(fields.profile === "redacted" || fields.profile === "raw"
|
|
157
|
+
? { profile: fields.profile }
|
|
158
|
+
: {}),
|
|
159
|
+
...(fields.target === "generic" ||
|
|
160
|
+
fields.target === "pi-session" ||
|
|
161
|
+
fields.target === "pi-handoff" ||
|
|
162
|
+
fields.target === "readable"
|
|
163
|
+
? { target: fields.target }
|
|
164
|
+
: {}),
|
|
165
|
+
...(fields.bytes !== undefined
|
|
166
|
+
? { bytes: safeNonNegative(fields.bytes) }
|
|
167
|
+
: {}),
|
|
168
|
+
...(fields.durationMs !== undefined
|
|
169
|
+
? { durationMs: safeNonNegative(fields.durationMs) }
|
|
170
|
+
: {}),
|
|
171
|
+
...(safeReasonCode(fields.reasonCode)
|
|
172
|
+
? { reasonCode: safeReasonCode(fields.reasonCode) }
|
|
173
|
+
: {}),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
async function appendLifecycleEvent(filePath, entry) {
|
|
177
|
+
await mkdir(path.dirname(filePath), { recursive: true, mode: 0o700 });
|
|
178
|
+
await appendFile(filePath, `${JSON.stringify(entry)}\n`, { mode: 0o600 });
|
|
179
|
+
await chmod(filePath, 0o600).catch(() => undefined);
|
|
180
|
+
}
|
|
181
|
+
async function countLifecycleEvents(filePath) {
|
|
182
|
+
const raw = await readFile(filePath, "utf8").catch(() => "");
|
|
183
|
+
let total = 0;
|
|
184
|
+
for (const line of raw.split("\n")) {
|
|
185
|
+
if (line.trim())
|
|
186
|
+
total += 1;
|
|
187
|
+
}
|
|
188
|
+
return total;
|
|
189
|
+
}
|
|
190
|
+
async function trimLifecycleEvents(filePath, limit) {
|
|
191
|
+
const raw = await readFile(filePath, "utf8").catch(() => "");
|
|
192
|
+
const lines = raw.split("\n").filter((line) => line.trim());
|
|
193
|
+
const kept = lines.slice(-limit);
|
|
194
|
+
const tmp = `${filePath}.${randomBytes(8).toString("hex")}.tmp`;
|
|
195
|
+
await writeFile(tmp, `${kept.join("\n")}\n`, { mode: 0o600, flag: "wx" });
|
|
196
|
+
await rename(tmp, filePath);
|
|
197
|
+
await chmod(filePath, 0o600).catch(() => undefined);
|
|
198
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash, randomBytes } from "node:crypto";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { readJsonIfExists, sha256Utf8, writeSecureJson, } from "
|
|
3
|
+
import { readJsonIfExists, sha256Utf8, writeSecureJson, } from "../../infrastructure/console/app-data.js";
|
|
4
4
|
import { confirmationPayloadHash, issueHumanGateToken, verifyHumanGateToken, } from "./human-gate-token.js";
|
|
5
5
|
export const ALL_CONFIRMATION_CHALLENGES = [
|
|
6
6
|
"source",
|
|
@@ -20,7 +20,7 @@ import { randomBytes } from "node:crypto";
|
|
|
20
20
|
import { readFile } from "node:fs/promises";
|
|
21
21
|
import path from "node:path";
|
|
22
22
|
import { pathMatchesPattern } from "../../shared/git-progress.js";
|
|
23
|
-
import { readJsonIfExists, sha256Utf8, writeSecureJson, } from "
|
|
23
|
+
import { readJsonIfExists, sha256Utf8, writeSecureJson, } from "../../infrastructure/console/app-data.js";
|
|
24
24
|
import { hashDagBytes, } from "./dag-confirmation.js";
|
|
25
25
|
/**
|
|
26
26
|
* Structured verification command patterns for the G2 autonomous-execution
|
|
@@ -6,7 +6,7 @@ import { LoopAgentClient } from "../loop-agent/loop-agent-client.js";
|
|
|
6
6
|
import { preflightTargetRepo } from "../preflight.js";
|
|
7
7
|
import { probePiReadiness, } from "./pi-readiness.js";
|
|
8
8
|
import { DEFAULT_OBSERVE_BASE_URL, OBSERVE_START_COMMAND, probeAndClassifyObserve, } from "./observe-health-match.js";
|
|
9
|
-
import { repoFingerprintV1 } from "
|
|
9
|
+
import { repoFingerprintV1 } from "../../infrastructure/console/repo-fingerprint.js";
|
|
10
10
|
import { resolveSiblingLoopAgentBin } from "./sibling-controller.js";
|
|
11
11
|
import { defaultObserveStaticDir, ROUTES } from "../observe/routes.js";
|
|
12
12
|
import { deriveObserveRouteCapabilities } from "../observe/health.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { readJsonIfExists, sha256Json, writeSecureJson, } from "
|
|
2
|
+
import { readJsonIfExists, sha256Json, writeSecureJson, } from "../../infrastructure/console/app-data.js";
|
|
3
3
|
/**
|
|
4
4
|
* 从任意上游载荷安全投影 ledger 摘要(未知形状丢弃,绝不抛错、绝不信任字段外的数据)。
|
|
5
5
|
* 供 DraftStore / prd-intake-bridge 把 prepare/advance 结果中的 ledger 摘要带入草稿。
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { parseFrontendHumanDecisionProjection } from "../../workflows/dag/frontend-human-decision.js";
|
|
2
|
+
/** Worker/Console persistence seam. Canonical validation and freshness remain in the workflow service. */
|
|
3
|
+
export function createFrontendHumanDecisionAdapter(store) {
|
|
4
|
+
return {
|
|
5
|
+
async load(operationId) {
|
|
6
|
+
const record = await store.get(operationId);
|
|
7
|
+
if (!record || record.revision === undefined || !record.frontendHumanDecision)
|
|
8
|
+
return undefined;
|
|
9
|
+
return { revision: record.revision, projection: parseFrontendHumanDecisionProjection(record.frontendHumanDecision) };
|
|
10
|
+
},
|
|
11
|
+
materialize(input) {
|
|
12
|
+
return store.materializeFrontendHumanDecision(input);
|
|
13
|
+
},
|
|
14
|
+
consume(input) {
|
|
15
|
+
return store.consumeFrontendHumanDecision(input);
|
|
16
|
+
},
|
|
17
|
+
initializeSplit: store.initializeFrontendHumanApprovedSplit.bind(store),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { FrontendSplitOrchestrator, frontendSplitProjectionSchema, } from "../../workflows/dag/frontend-split-application-service.js";
|
|
2
|
+
/** Worker/Console boundary adapter. All orchestration policy remains canonical. */
|
|
3
|
+
export function createFrontendSplitOperationAdapter(dependencies) {
|
|
4
|
+
const ports = {
|
|
5
|
+
load: async (operationId) => {
|
|
6
|
+
const record = await dependencies.store.get(operationId);
|
|
7
|
+
return record?.frontendSplit === undefined ? undefined : frontendSplitProjectionSchema.parse(record.frontendSplit);
|
|
8
|
+
},
|
|
9
|
+
compareAndSwap: (input) => dependencies.store.compareAndSwapFrontendSplit(input),
|
|
10
|
+
materialize: async (request) => {
|
|
11
|
+
const result = await dependencies.materializer.materialize(request);
|
|
12
|
+
return { taskId: result.taskId, operationId: result.operationId };
|
|
13
|
+
},
|
|
14
|
+
schedule: dependencies.schedule,
|
|
15
|
+
auditStale: dependencies.auditStale,
|
|
16
|
+
loadChildCloseoutFacts: (input) => dependencies.store.loadChildCloseoutFacts(input),
|
|
17
|
+
settleAggregate: (input) => dependencies.store.settleFrontendSplitAggregate({ ...input, prepareAggregate: dependencies.prepareAggregate }),
|
|
18
|
+
};
|
|
19
|
+
return new FrontendSplitOrchestrator(ports);
|
|
20
|
+
}
|
|
@@ -85,7 +85,7 @@ export function verifyHumanGateToken(presented, expected, secret, now = new Date
|
|
|
85
85
|
* invalidates the token (defense against drift-then-confirm).
|
|
86
86
|
*/
|
|
87
87
|
import { createHash } from "node:crypto";
|
|
88
|
-
import { sha256Utf8 } from "
|
|
88
|
+
import { sha256Utf8 } from "../../infrastructure/console/app-data.js";
|
|
89
89
|
export function confirmationPayloadHash(b) {
|
|
90
90
|
const canonical = [
|
|
91
91
|
`dag=${b.dagSha256}`,
|
|
@@ -3,14 +3,17 @@ export { buildOperatorSurfaceHealthV1 } from "./operator-surface-health.js";
|
|
|
3
3
|
export { runConsoleDoctor, formatConsoleDoctorHuman } from "./doctor.js";
|
|
4
4
|
export { isLoopbackHost } from "./loopback.js";
|
|
5
5
|
export { shouldOpenConsoleBrowser, normalizeConsoleBrowserUrl, openSystemBrowser, maybeOpenConsoleBrowser, } from "./open-browser.js";
|
|
6
|
-
export { repoFingerprintV1, normalizeWorktreeRealpath, } from "
|
|
6
|
+
export { repoFingerprintV1, normalizeWorktreeRealpath, } from "../../infrastructure/console/repo-fingerprint.js";
|
|
7
7
|
export { buildObserveDeepLink } from "./observe-link.js";
|
|
8
8
|
export { classifyObserveHealth, probeAndClassifyObserve, capabilityForObserveTarget, OBSERVE_START_COMMAND, DEFAULT_OBSERVE_BASE_URL, } from "./observe-health-match.js";
|
|
9
9
|
export { allowedRecoveryCtas, classifyRecoveryFact, partitionRecoveryCtas, recoveryMatrixInvariants, } from "./recovery-cta.js";
|
|
10
10
|
export { createClosedResourceLoader, createInterviewResourceLoader, tryActivateTool, assertOfficialToolAllowed, listOfficialTools, OFFICIAL_DENIED_TOOL_IDS, INTERVIEW_ALLOWED_TOOLS, INTERVIEW_DENIED_TOOLS, authorizeInterviewTool, } from "./resource-loader.js";
|
|
11
11
|
export { resolveSiblingLoopAgentBin } from "./sibling-controller.js";
|
|
12
|
-
export { openConsoleAppData, defaultConsoleAppDataRoot } from "
|
|
13
|
-
export { OperationStore } from "
|
|
12
|
+
export { openConsoleAppData, defaultConsoleAppDataRoot } from "../../infrastructure/console/app-data.js";
|
|
13
|
+
export { OperationStore } from "../../infrastructure/console/operation-store.js";
|
|
14
|
+
export { createFrontendSplitOperationAdapter } from "./frontend-split-operation-adapter.js";
|
|
15
|
+
export { createFrontendHumanDecisionAdapter } from "./frontend-human-decision-adapter.js";
|
|
16
|
+
export { FrontendSplitTaskMaterializer } from "../materialize/frontend-split-task-materializer.js";
|
|
14
17
|
export { createOperationEventStore } from "./operation-sse.js";
|
|
15
18
|
export { DagConfirmationStore } from "./dag-confirmation.js";
|
|
16
19
|
export { DraftStore } from "./draft-store.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { readJsonIfExists, writeSecureJson, } from "
|
|
3
|
+
import { readJsonIfExists, writeSecureJson, } from "../../../infrastructure/console/app-data.js";
|
|
4
4
|
import { computeDraftSha256, } from "../draft-store.js";
|
|
5
5
|
function assessmentPath(appData, assessmentId) {
|
|
6
6
|
return path.join(appData.assessments, `${assessmentId}.json`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { readJsonIfExists, writeSecureJson, } from "
|
|
3
|
+
import { readJsonIfExists, writeSecureJson, } from "../../../infrastructure/console/app-data.js";
|
|
4
4
|
import { createInterviewResourceLoader, } from "./tools.js";
|
|
5
5
|
function sessionPath(appData, sessionId) {
|
|
6
6
|
return path.join(appData.interviews, `${sessionId}.json`);
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
import { clipPreview, } from "
|
|
1
|
+
import { clipPreview, } from "../../infrastructure/console/operation-store.js";
|
|
2
2
|
import { stateEvent } from "./operation-sse.js";
|
|
3
3
|
import { extractTrustedRunFacts } from "./operation-run-facts.js";
|
|
4
|
+
/** Swallow-all invoker so observers can never break the state path. */
|
|
5
|
+
function notifySettled(deps, operation, state, info) {
|
|
6
|
+
if (!deps.onSettled)
|
|
7
|
+
return;
|
|
8
|
+
void Promise.resolve()
|
|
9
|
+
.then(() => deps.onSettled?.(operation, state, info))
|
|
10
|
+
.catch(() => undefined);
|
|
11
|
+
}
|
|
4
12
|
/**
|
|
5
13
|
* Execute a queued operation via LoopAgentClient (or inject).
|
|
6
14
|
* Timeout without proven exit → needs-reconcile (never Cancel).
|
|
@@ -42,6 +50,7 @@ export async function runOperation(operationId, deps) {
|
|
|
42
50
|
artifactName: `operation-${operationId}`,
|
|
43
51
|
expectJson: true,
|
|
44
52
|
timeoutMs: deps.defaultTimeoutMs,
|
|
53
|
+
env: deps.env,
|
|
45
54
|
onSpawn: (info) => {
|
|
46
55
|
// Chain onto the per-operation write lock; never fire-and-forget a
|
|
47
56
|
// rejected update (unhandled rejection can crash Console on Windows).
|
|
@@ -119,6 +128,10 @@ export async function runOperation(operationId, deps) {
|
|
|
119
128
|
message: finished.errorMessage,
|
|
120
129
|
state: "needs-reconcile",
|
|
121
130
|
});
|
|
131
|
+
notifySettled(deps, finished, "needs-reconcile", {
|
|
132
|
+
ok: false,
|
|
133
|
+
errorCode: finished.errorCode,
|
|
134
|
+
});
|
|
122
135
|
}
|
|
123
136
|
return finished;
|
|
124
137
|
}
|
|
@@ -169,9 +182,10 @@ async function finalizeFromWorkerResult(operationId, result, deps) {
|
|
|
169
182
|
// Supervisory timeout without classified CLI timeout → needs-reconcile
|
|
170
183
|
// Only mark timed-out when we have a machine timeout result after exit.
|
|
171
184
|
const state = result.exitCode !== null ? "timed-out" : "needs-reconcile";
|
|
172
|
-
const
|
|
185
|
+
const finishedAt = new Date().toISOString();
|
|
186
|
+
const patch = {
|
|
173
187
|
state,
|
|
174
|
-
finishedAt
|
|
188
|
+
finishedAt,
|
|
175
189
|
artifactRefs,
|
|
176
190
|
stdoutPreview: previewStdout,
|
|
177
191
|
stderrPreview: previewStderr,
|
|
@@ -186,7 +200,15 @@ async function finalizeFromWorkerResult(operationId, result, deps) {
|
|
|
186
200
|
...(runFacts.runSummary ? { runSummary: runFacts.runSummary } : {}),
|
|
187
201
|
}
|
|
188
202
|
: {}),
|
|
203
|
+
};
|
|
204
|
+
const current = await deps.store.get(operationId);
|
|
205
|
+
if (!current)
|
|
206
|
+
throw new Error(`operation not found: ${operationId}`);
|
|
207
|
+
await deps.beforeTerminal?.({ ...current, ...patch }, state, {
|
|
208
|
+
ok: false,
|
|
209
|
+
errorCode: patch.errorCode,
|
|
189
210
|
});
|
|
211
|
+
const updated = await deps.store.update(operationId, patch);
|
|
190
212
|
stateEvent(deps.events, updated, state, updated.errorMessage);
|
|
191
213
|
if (runFacts) {
|
|
192
214
|
appendSafeResultEvent(deps, operationId, state, {
|
|
@@ -202,6 +224,10 @@ async function finalizeFromWorkerResult(operationId, result, deps) {
|
|
|
202
224
|
data: { ok: false, exitCode: result.exitCode },
|
|
203
225
|
});
|
|
204
226
|
}
|
|
227
|
+
notifySettled(deps, updated, state, {
|
|
228
|
+
ok: false,
|
|
229
|
+
errorCode: updated.errorCode,
|
|
230
|
+
});
|
|
205
231
|
return updated;
|
|
206
232
|
}
|
|
207
233
|
const envelope = coerceEnvelope(result);
|
|
@@ -210,7 +236,7 @@ async function finalizeFromWorkerResult(operationId, result, deps) {
|
|
|
210
236
|
const processOk = envelope?.ok === true || (result.ok && result.exitCode === 0);
|
|
211
237
|
const ok = processOk && !businessBlock;
|
|
212
238
|
const state = ok ? "succeeded" : "failed";
|
|
213
|
-
const
|
|
239
|
+
const patch = {
|
|
214
240
|
state,
|
|
215
241
|
finishedAt: new Date().toISOString(),
|
|
216
242
|
artifactRefs,
|
|
@@ -238,9 +264,20 @@ async function finalizeFromWorkerResult(operationId, result, deps) {
|
|
|
238
264
|
...(runFacts.runSummary ? { runSummary: runFacts.runSummary } : {}),
|
|
239
265
|
}
|
|
240
266
|
: {}),
|
|
267
|
+
};
|
|
268
|
+
if (!operation)
|
|
269
|
+
throw new Error(`operation not found: ${operationId}`);
|
|
270
|
+
await deps.beforeTerminal?.({ ...operation, ...patch }, state, {
|
|
271
|
+
ok,
|
|
272
|
+
errorCode: patch.errorCode,
|
|
241
273
|
});
|
|
274
|
+
const updated = await deps.store.update(operationId, patch);
|
|
242
275
|
stateEvent(deps.events, updated, state, updated.errorMessage);
|
|
243
276
|
appendSafeResultEvent(deps, operationId, state, { ok, exitCode: result.exitCode }, runFacts);
|
|
277
|
+
notifySettled(deps, updated, state, {
|
|
278
|
+
ok,
|
|
279
|
+
errorCode: updated.errorCode,
|
|
280
|
+
});
|
|
244
281
|
if (ok && operation?.action === "dagRequestInterrupt") {
|
|
245
282
|
await projectInterruptRequestOntoTarget(operation, result.json, deps);
|
|
246
283
|
}
|
|
@@ -300,6 +337,10 @@ export function scheduleOperation(operationId, deps) {
|
|
|
300
337
|
})
|
|
301
338
|
.then((updated) => {
|
|
302
339
|
stateEvent(deps.events, updated, "needs-reconcile", message);
|
|
340
|
+
notifySettled(deps, updated, "needs-reconcile", {
|
|
341
|
+
ok: false,
|
|
342
|
+
errorCode: updated.errorCode,
|
|
343
|
+
});
|
|
303
344
|
})
|
|
304
345
|
.catch(() => {
|
|
305
346
|
// A failed canonical store update cannot be represented safely.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync, rmSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { ensureSecureDir, writeSecureJsonSync } from "
|
|
3
|
+
import { ensureSecureDir, writeSecureJsonSync } from "../../infrastructure/console/app-data.js";
|
|
4
4
|
const DEFAULT_MAX_EVENTS = 1000;
|
|
5
5
|
function safeOperationId(operationId) {
|
|
6
6
|
return operationId.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 180);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { projectOperationEventSummary, projectOperationForChat, } from "./chat/chat-event-store.js";
|
|
2
|
-
import { isTerminalOperationState, } from "
|
|
2
|
+
import { isTerminalOperationState, } from "../../infrastructure/console/operation-store.js";
|
|
3
3
|
/**
|
|
4
4
|
* P2: read-only event-driven long poll on the canonical operation event ring
|
|
5
5
|
* (2026-08-13 Operator Chat long-run supervision). Server contract bounds:
|