@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
|
@@ -5,6 +5,9 @@ import { ContractMutationError, applyTaskContract, logicalRevisionForState, obse
|
|
|
5
5
|
import { TASK_CONTRACT_DRAFT_SCHEMA_VERSION } from "../contract/constants.js";
|
|
6
6
|
import { getTaskContractPaths } from "../contract/paths.js";
|
|
7
7
|
import { loadTaskConfig } from "../runtime.js";
|
|
8
|
+
import { discoverFrontendProjectCapability, resolveFrontendSpecRootAliases, } from "../frontend-project-capability.js";
|
|
9
|
+
import { classifyTaskDemand } from "../task-demand-routing.js";
|
|
10
|
+
import { DEFAULT_FRONTEND_SPEC_ROOTS, extractDeclaredFrontendSpecRoots, } from "../../shared/openspec-spec.js";
|
|
8
11
|
import { buildPrepareDraft } from "./build-draft.js";
|
|
9
12
|
import { hasBlockingGaps, hasBlockingRisks, isFreshLegacyUnversioned, listPrepareGaps, appendLedgerGaps, } from "./completeness.js";
|
|
10
13
|
import { detectProductArtifactMeta, isIntakeSoftGapCode, } from "./artifact-meta.js";
|
|
@@ -681,7 +684,7 @@ export async function prepareTaskSource(input) {
|
|
|
681
684
|
facts = importedFacts ?? mergedSupplemental;
|
|
682
685
|
}
|
|
683
686
|
}
|
|
684
|
-
|
|
687
|
+
let built = buildPrepareDraft({
|
|
685
688
|
taskId,
|
|
686
689
|
existingTaskConfig,
|
|
687
690
|
baseDraft,
|
|
@@ -689,6 +692,91 @@ export async function prepareTaskSource(input) {
|
|
|
689
692
|
flags: input.flags,
|
|
690
693
|
references,
|
|
691
694
|
});
|
|
695
|
+
// Resolve an implicit frontend workflow before the first managed contract is
|
|
696
|
+
// projected. Explicit taskKind (including explicit standard) remains a hard
|
|
697
|
+
// contract; only a standard task with strong source/path/project evidence may
|
|
698
|
+
// be promoted here. This keeps task.json, contract.json, and the first DAG
|
|
699
|
+
// generation on the same workflow without a later hash-changing re-projection.
|
|
700
|
+
if (built.draft.taskKind === "standard" &&
|
|
701
|
+
!built.draft.taskKindExplicit) {
|
|
702
|
+
const routingRequirement = [
|
|
703
|
+
...(sourceIntegrity?.documents ?? [])
|
|
704
|
+
.map((document) => document.content)
|
|
705
|
+
.filter((content) => Boolean(content?.trim())),
|
|
706
|
+
...(input.intent.kind === "facts" && input.intent.text
|
|
707
|
+
? [input.intent.text]
|
|
708
|
+
: []),
|
|
709
|
+
built.draft.requirement.objective,
|
|
710
|
+
...built.draft.requirement.scope,
|
|
711
|
+
...built.draft.requirement.acceptanceCriteria.map((item) => item.text),
|
|
712
|
+
].join("\n");
|
|
713
|
+
let frontendProject;
|
|
714
|
+
try {
|
|
715
|
+
frontendProject = await discoverFrontendProjectCapability(repoRoot);
|
|
716
|
+
}
|
|
717
|
+
catch {
|
|
718
|
+
// Capability discovery is advisory for routing. A failed probe must not
|
|
719
|
+
// turn an otherwise valid standard contract preparation into an error.
|
|
720
|
+
}
|
|
721
|
+
const classification = classifyTaskDemand({
|
|
722
|
+
title: built.draft.title,
|
|
723
|
+
requirementMarkdown: routingRequirement,
|
|
724
|
+
allowedPaths: built.draft.constraints.allowedPaths,
|
|
725
|
+
frontendProject: frontendProject
|
|
726
|
+
? {
|
|
727
|
+
framework: frontendProject.framework,
|
|
728
|
+
evidencePaths: frontendProject.evidencePaths,
|
|
729
|
+
}
|
|
730
|
+
: undefined,
|
|
731
|
+
});
|
|
732
|
+
if (classification.kind === "frontend") {
|
|
733
|
+
built = buildPrepareDraft({
|
|
734
|
+
taskId,
|
|
735
|
+
existingTaskConfig,
|
|
736
|
+
baseDraft,
|
|
737
|
+
facts,
|
|
738
|
+
flags: {
|
|
739
|
+
...input.flags,
|
|
740
|
+
taskKind: "frontend-implementation",
|
|
741
|
+
},
|
|
742
|
+
references,
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
// A user can explicitly name a non-default normative directory in the task
|
|
747
|
+
// prompt (for example “规范目录 `design-system`”). Freeze that root into
|
|
748
|
+
// the managed task config before the DAG exists; normal DAG selection consumes
|
|
749
|
+
// the already-resolved task kind instead of mutating task.json later.
|
|
750
|
+
if (built.draft.taskKind === "frontend-implementation") {
|
|
751
|
+
// An imported PRD is materialized under sourceIntegrity rather than copied
|
|
752
|
+
// into intent.text. Use both inputs so a `--prd` invocation can declare a
|
|
753
|
+
// task-owned spec root just like supplemental free-form text can.
|
|
754
|
+
const sourceText = [
|
|
755
|
+
...(sourceIntegrity?.documents ?? []).flatMap((document) => document.content ? [document.content] : []),
|
|
756
|
+
...(input.intent.kind === "facts" && input.intent.text
|
|
757
|
+
? [input.intent.text]
|
|
758
|
+
: []),
|
|
759
|
+
].join("\n");
|
|
760
|
+
const inferredRoots = extractDeclaredFrontendSpecRoots(sourceText);
|
|
761
|
+
if (inferredRoots.length > 0) {
|
|
762
|
+
const current = existingTaskConfig?.frontendOpenspec;
|
|
763
|
+
const configuredRoots = current?.specRoots ?? [...DEFAULT_FRONTEND_SPEC_ROOTS];
|
|
764
|
+
// Include roots declared by this source before resolving physical-target
|
|
765
|
+
// aliases. A newly declared root may itself be a symlink (for example
|
|
766
|
+
// `project-specs -> .../ai_doc`), so resolving aliases against only the
|
|
767
|
+
// previous config cannot map `ai_doc/rules.md` back to project-specs.
|
|
768
|
+
const provisionalRoots = [
|
|
769
|
+
...new Set([...configuredRoots, ...inferredRoots]),
|
|
770
|
+
].sort();
|
|
771
|
+
const aliases = await resolveFrontendSpecRootAliases(repoRoot, provisionalRoots);
|
|
772
|
+
const aliasMap = new Map(aliases.map(({ alias, logicalRoot }) => [alias, logicalRoot]));
|
|
773
|
+
built.draft.frontendOpenspec = {
|
|
774
|
+
policy: current?.policy ?? "cited",
|
|
775
|
+
specRoots: [...new Set([...configuredRoots, ...inferredRoots.map((root) => aliasMap.get(root) ?? root)])].sort(),
|
|
776
|
+
requiredReadPaths: current?.requiredReadPaths ?? [],
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
}
|
|
692
780
|
const { gaps, risks } = listPrepareGaps({
|
|
693
781
|
draft: built.draft,
|
|
694
782
|
state,
|
|
@@ -708,29 +796,46 @@ export async function prepareTaskSource(input) {
|
|
|
708
796
|
// -------------------------------------------------------------------
|
|
709
797
|
let ledger;
|
|
710
798
|
let ledgerSummary;
|
|
711
|
-
|
|
712
|
-
sourceIntegrity
|
|
713
|
-
|
|
799
|
+
const hasAuthoritativeImportedDocs = Boolean(hasImportedPrd &&
|
|
800
|
+
sourceIntegrity?.parseableDocuments.some((doc) => doc.role === "requirement" || doc.role === "acceptance"));
|
|
801
|
+
// Frontend tasks created from text still need the same source-fidelity
|
|
802
|
+
// contract as imported-PRD tasks. In that case the projected requirement
|
|
803
|
+
// document is the canonical, task-owned source that the DAG can bind to;
|
|
804
|
+
// without it init-hybrid would silently emit a v1 binding and the first
|
|
805
|
+
// frontend-contract node would fail before making a model call.
|
|
806
|
+
if (built.draft.taskKind === "frontend-implementation" &&
|
|
807
|
+
(hasAuthoritativeImportedDocs ||
|
|
808
|
+
(input.intent.kind === "facts" && Boolean(input.intent.text)))) {
|
|
714
809
|
try {
|
|
715
|
-
const authoritativeDocs = sourceIntegrity
|
|
810
|
+
const authoritativeDocs = sourceIntegrity?.parseableDocuments.filter((doc) => (doc.role === "requirement" || doc.role === "acceptance") &&
|
|
716
811
|
typeof doc.content === "string" &&
|
|
717
|
-
doc.content.trim().length > 0);
|
|
718
|
-
const
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
path
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
812
|
+
doc.content.trim().length > 0) ?? [];
|
|
813
|
+
const requirementProjection = projectRequirementMarkdown(built.draft);
|
|
814
|
+
const sourceDocuments = authoritativeDocs.length > 0
|
|
815
|
+
? authoritativeDocs.map((doc) => {
|
|
816
|
+
// Canonical source identity 单一边界(AC-001 / AC-FIDELITY-REPAIR-001):
|
|
817
|
+
// ledger sourceDocuments[].path 与 DAG 侧 serializeDagTaskSourcePath /
|
|
818
|
+
// resolveDagTaskSourcePath 一致(repo-root relative POSIX),路径转换只
|
|
819
|
+
// 发生在该边界,不再二次转换进入 digest 计算。
|
|
820
|
+
const absolute = path.resolve(contractPaths.sourceDir, doc.materializedPath);
|
|
821
|
+
return {
|
|
822
|
+
path: path
|
|
823
|
+
.relative(repoRoot, absolute)
|
|
824
|
+
.split(path.sep)
|
|
825
|
+
.join("/"),
|
|
826
|
+
content: doc.content,
|
|
827
|
+
};
|
|
828
|
+
})
|
|
829
|
+
: [
|
|
830
|
+
{
|
|
831
|
+
path: path
|
|
832
|
+
.relative(repoRoot, contractPaths.requirementPath)
|
|
833
|
+
.split(path.sep)
|
|
834
|
+
.join("/"),
|
|
835
|
+
content: requirementProjection,
|
|
836
|
+
},
|
|
837
|
+
];
|
|
732
838
|
if (sourceDocuments.length > 0) {
|
|
733
|
-
const requirementProjection = projectRequirementMarkdown(built.draft);
|
|
734
839
|
ledger = await buildRequirementLedger({
|
|
735
840
|
taskId,
|
|
736
841
|
requirementSha256: sha256Utf8(requirementProjection),
|
|
@@ -457,8 +457,12 @@ async function buildPrompt(input) {
|
|
|
457
457
|
"Do NOT invent product behavior that is not supported by the documents.",
|
|
458
458
|
"You MAY recommend an optional engineering block when the repo layout hint supports it:",
|
|
459
459
|
"- allowedPaths / forbiddenPaths as minimal precise globs (e.g. source/packages/**/*.test.ts)",
|
|
460
|
-
"- verifyCommands as real package scripts (e.g. pnpm -C source test)",
|
|
461
|
-
"- taskKind when clearly implied
|
|
460
|
+
"- verifyCommands as real package scripts (e.g. pnpm -C source test); when acceptance criteria name a specific test file to run (e.g. 定向 vitest(test/.../xxx.test.ts)), emit the corresponding targeted command as its own entry (e.g. npx vitest run test/.../xxx.test.ts) instead of only the full-suite script — targeted commands are what a frontend implementation plan maps to behavior verification targets",
|
|
461
|
+
"- taskKind when clearly implied, choosing from {standard / frontend-implementation / frontend-test / backend-test / knowledge-sync}:",
|
|
462
|
+
" - frontend-implementation: the deliverable is a frontend component/page/UI feature (even when it ships with its own tests)",
|
|
463
|
+
" - frontend-test: the deliverable is a browser/UI automation test suite for EXISTING functionality (no implementation work)",
|
|
464
|
+
" - backend-test: pytest/backend test suite; standard: general repo implementation",
|
|
465
|
+
" A task that IMPLEMENTS a component and adds tests for it is frontend-implementation, never frontend-test.",
|
|
462
466
|
"Prefer smallest correct write boundary; do not invent product paths that are not in the layout hint.",
|
|
463
467
|
"Do NOT rewrite or suggest editing the original PRD files.",
|
|
464
468
|
"Prefer explicit text; use provenance derived for rephrasing; use inferred only when clearly implied — if you must invent ACs, leave acceptanceCriteria empty so the system can stop for clarification.",
|
|
@@ -22,6 +22,18 @@ function slugifyName(value) {
|
|
|
22
22
|
.replace(/-{2,}/g, "-");
|
|
23
23
|
return slug || "requirement";
|
|
24
24
|
}
|
|
25
|
+
/** Stable identity of a manifest document for change detection. Timestamps and
|
|
26
|
+
* byte sizes are excluded: identical content re-imported later must not appear
|
|
27
|
+
* "changed" (the canonical hash includes manifest bytes). */
|
|
28
|
+
function documentIdentity(doc) {
|
|
29
|
+
return `${doc.role}|${doc.name}|${doc.materializedPath}|${doc.sha256}`;
|
|
30
|
+
}
|
|
31
|
+
function sameDocumentSet(left, right) {
|
|
32
|
+
if (left.length !== right.length)
|
|
33
|
+
return false;
|
|
34
|
+
const rightIds = new Set(right.map(documentIdentity));
|
|
35
|
+
return left.every((doc) => rightIds.has(documentIdentity(doc)));
|
|
36
|
+
}
|
|
25
37
|
function ensureUniqueReferenceName(existing, baseName, extension) {
|
|
26
38
|
const used = new Set(existing);
|
|
27
39
|
const candidate = `${baseName}${extension}`;
|
|
@@ -149,10 +161,19 @@ export async function importPrdDocument(input) {
|
|
|
149
161
|
const documents = [...(existingManifest?.documents ?? [])].filter((entry) => entry.materializedPath !== materializedRelativePath);
|
|
150
162
|
documents.push(document);
|
|
151
163
|
documents.sort((left, right) => left.materializedPath.localeCompare(right.materializedPath));
|
|
164
|
+
// Keep `updatedAt` stable across re-imports of the same content: the
|
|
165
|
+
// canonical contract hash includes the manifest bytes, so a fresh
|
|
166
|
+
// timestamp on every identical re-import would make the observed
|
|
167
|
+
// canonical hash drift and fail task verification. Only bump it when the
|
|
168
|
+
// document set actually changed (a new/changed materialized file).
|
|
169
|
+
const documentSetChanged = !existingManifest ||
|
|
170
|
+
!sameDocumentSet(existingManifest.documents, documents);
|
|
152
171
|
const manifest = {
|
|
153
172
|
schemaVersion: 1,
|
|
154
173
|
taskId: input.taskId,
|
|
155
|
-
updatedAt:
|
|
174
|
+
updatedAt: documentSetChanged
|
|
175
|
+
? importedAt
|
|
176
|
+
: (existingManifest?.updatedAt ?? importedAt),
|
|
156
177
|
documents,
|
|
157
178
|
};
|
|
158
179
|
await writeSourceManifest(paths.sourceDir, manifest);
|
|
@@ -76,6 +76,7 @@ const SPECIAL_TEMPLATE_BY_TASK_KIND = {
|
|
|
76
76
|
"frontend-implementation": "frontend-implementation",
|
|
77
77
|
"frontend-test": "frontend-test-dag",
|
|
78
78
|
"backend-test": "backend-test-dag",
|
|
79
|
+
"backend-test-analysis": "backend-test-analysis-dag",
|
|
79
80
|
"knowledge-sync": "knowledge-sync-dag",
|
|
80
81
|
"knowledge-graph-bootstrap": "knowledge-graph-bootstrap-dag",
|
|
81
82
|
};
|
|
@@ -83,6 +84,7 @@ const TASK_KIND_ROUTING_REASON = {
|
|
|
83
84
|
"frontend-implementation": 'taskKind "frontend-implementation" selects the dedicated frontend DAG template',
|
|
84
85
|
"frontend-test": 'taskKind "frontend-test" selects the dedicated frontend test DAG template',
|
|
85
86
|
"backend-test": 'taskKind "backend-test" selects the dedicated backend test DAG template',
|
|
87
|
+
"backend-test-analysis": 'taskKind "backend-test-analysis" selects the read-only backend test analysis DAG template',
|
|
86
88
|
"knowledge-sync": 'taskKind "knowledge-sync" selects the dedicated knowledge-sync DAG template',
|
|
87
89
|
"knowledge-graph-bootstrap": 'taskKind "knowledge-graph-bootstrap" selects the dedicated knowledge-graph bootstrap DAG template',
|
|
88
90
|
};
|
|
@@ -90,6 +92,7 @@ const SPECIAL_REQUESTED_TEMPLATES = new Set([
|
|
|
90
92
|
"frontend-implementation",
|
|
91
93
|
"frontend-test-dag",
|
|
92
94
|
"backend-test-dag",
|
|
95
|
+
"backend-test-analysis-dag",
|
|
93
96
|
"knowledge-sync-dag",
|
|
94
97
|
"knowledge-graph-bootstrap-dag",
|
|
95
98
|
]);
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
import { createHash } from "node:crypto";
|
|
20
20
|
import { existsSync, readFileSync, rmSync } from "node:fs";
|
|
21
21
|
import path from "node:path";
|
|
22
|
-
import { ensureSecureDir, writeSecureJsonSync, } from "
|
|
23
|
-
import { isTerminalOperationState, } from "
|
|
22
|
+
import { ensureSecureDir, writeSecureJsonSync, } from "../../../infrastructure/console/app-data.js";
|
|
23
|
+
import { isTerminalOperationState, } from "../../../infrastructure/console/operation-store.js";
|
|
24
24
|
import { scrubSecrets } from "./explore-tools.js";
|
|
25
25
|
const OPERATION_PREVIEW_MAX_CHARS = 1200;
|
|
26
26
|
function boundedRedactedText(value, maxChars = OPERATION_PREVIEW_MAX_CHARS) {
|
|
@@ -125,11 +125,14 @@ function resolveTierDescriptor(selection, available) {
|
|
|
125
125
|
});
|
|
126
126
|
return {
|
|
127
127
|
provider: selection.provider,
|
|
128
|
-
resolved: Boolean(entry),
|
|
128
|
+
resolved: Boolean(entry && entry.hasCredentials !== false),
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
131
|
const entry = findProviderForModelId(selection.modelId, available);
|
|
132
|
-
return {
|
|
132
|
+
return {
|
|
133
|
+
provider: entry?.provider,
|
|
134
|
+
resolved: Boolean(entry && entry.hasCredentials !== false),
|
|
135
|
+
};
|
|
133
136
|
}
|
|
134
137
|
/**
|
|
135
138
|
* Resolve harness executors.pi tiers (LOW/MED/HIGH) to provider descriptors.
|
|
@@ -196,7 +199,7 @@ export async function resolveDefaultChatModel(repoRoot, available, options) {
|
|
|
196
199
|
const entry = findProviderForModelId(selection.modelId, available, {
|
|
197
200
|
preferredProvider: selection.provider,
|
|
198
201
|
});
|
|
199
|
-
if (!entry)
|
|
202
|
+
if (!entry || entry.hasCredentials === false)
|
|
200
203
|
return undefined;
|
|
201
204
|
return {
|
|
202
205
|
provider: selection.provider,
|
|
@@ -205,7 +208,7 @@ export async function resolveDefaultChatModel(repoRoot, available, options) {
|
|
|
205
208
|
};
|
|
206
209
|
}
|
|
207
210
|
const entry = findProviderForModelId(selection.modelId, available);
|
|
208
|
-
if (!entry)
|
|
211
|
+
if (!entry || entry.hasCredentials === false)
|
|
209
212
|
return undefined;
|
|
210
213
|
return {
|
|
211
214
|
provider: entry.provider,
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* `createDefaultPiSdkBindings()`.
|
|
27
27
|
*/
|
|
28
28
|
import { createHash, randomBytes } from "node:crypto";
|
|
29
|
-
import { access, stat } from "node:fs/promises";
|
|
29
|
+
import { access, mkdir, rm, stat, writeFile } from "node:fs/promises";
|
|
30
30
|
import path from "node:path";
|
|
31
31
|
import { extractAssistantContentBlocks, extractAssistantText, isAssistantSdkMessage, } from "./assistant-content.js";
|
|
32
32
|
import { parseProviderError, } from "./provider-error.js";
|
|
@@ -43,6 +43,7 @@ import { filterActiveInterviewTools } from "../interview/tools.js";
|
|
|
43
43
|
import { RUNTIME_CONTEXT_TEXT_MAX, redactRuntimeText, } from "./runtime-context.js";
|
|
44
44
|
import { buildTodoContinuationContext, } from "./todos.js";
|
|
45
45
|
import { buildGoalContinuationContext, } from "./goals.js";
|
|
46
|
+
import { injectWizardLocalHeaders, } from "./sdd-data-alignment.js";
|
|
46
47
|
/**
|
|
47
48
|
* Base system prompt fragment every General Operator Chat session receives.
|
|
48
49
|
*
|
|
@@ -298,6 +299,24 @@ export function createGoalCompactionContextExtension(options) {
|
|
|
298
299
|
},
|
|
299
300
|
};
|
|
300
301
|
}
|
|
302
|
+
export function createWizardLocalHeadersExtension(options) {
|
|
303
|
+
return {
|
|
304
|
+
name: "operator-chat-wizard-local-headers",
|
|
305
|
+
hidden: true,
|
|
306
|
+
factory: (api) => {
|
|
307
|
+
api.on("before_provider_headers", async (rawEvent, context) => {
|
|
308
|
+
if (!context || !rawEvent.headers || typeof rawEvent.headers !== "object")
|
|
309
|
+
return;
|
|
310
|
+
await injectWizardLocalHeaders({
|
|
311
|
+
headers: rawEvent.headers,
|
|
312
|
+
context,
|
|
313
|
+
sessionId: options.sessionId,
|
|
314
|
+
service: options.service,
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
},
|
|
318
|
+
};
|
|
319
|
+
}
|
|
301
320
|
/**
|
|
302
321
|
* Build Pi custom ToolDefinition objects for every whitelisted operator action.
|
|
303
322
|
* Each tool's execute() routes into the operator action dispatcher (Gate 3).
|
|
@@ -1061,10 +1080,17 @@ export class ConsolePiRuntime {
|
|
|
1061
1080
|
registry: this.options.goalRegistry,
|
|
1062
1081
|
})
|
|
1063
1082
|
: undefined;
|
|
1083
|
+
const wizardLocalHeadersExtension = sessionId && this.options.sddDataAlignment
|
|
1084
|
+
? createWizardLocalHeadersExtension({
|
|
1085
|
+
sessionId,
|
|
1086
|
+
service: this.options.sddDataAlignment,
|
|
1087
|
+
})
|
|
1088
|
+
: undefined;
|
|
1064
1089
|
const extraFactories = [
|
|
1065
1090
|
todoContextExtension,
|
|
1066
1091
|
goalContextExtension,
|
|
1067
1092
|
pressureExtension,
|
|
1093
|
+
wizardLocalHeadersExtension,
|
|
1068
1094
|
].filter((item) => Boolean(item));
|
|
1069
1095
|
return {
|
|
1070
1096
|
...base,
|
|
@@ -1305,6 +1331,15 @@ export class ConsolePiRuntime {
|
|
|
1305
1331
|
if (!sessionFile) {
|
|
1306
1332
|
throw new Error(`chat session shell missing sessionFile for ${sessionId}`);
|
|
1307
1333
|
}
|
|
1334
|
+
// Pi's SessionManager.create deliberately postpones writing a JSONL until
|
|
1335
|
+
// an assistant response. Materialize a valid header now, otherwise Console
|
|
1336
|
+
// could persist a path that disappears on a restart before first reply.
|
|
1337
|
+
await this.bindings.materializeSessionShell({
|
|
1338
|
+
sessionManager,
|
|
1339
|
+
sessionId,
|
|
1340
|
+
sessionFile,
|
|
1341
|
+
cwd: this.options.cwd,
|
|
1342
|
+
});
|
|
1308
1343
|
this.sessionManagers.set(sessionId, sessionManager);
|
|
1309
1344
|
this.thinkingSelections.set(sessionId, "auto");
|
|
1310
1345
|
// Detached single-flight materialization; dependent routes await the same promise.
|
|
@@ -2312,6 +2347,16 @@ export class ConsolePiRuntime {
|
|
|
2312
2347
|
});
|
|
2313
2348
|
}
|
|
2314
2349
|
catch (error) {
|
|
2350
|
+
const code = error && typeof error === "object" && "code" in error
|
|
2351
|
+
? String(error.code ?? "")
|
|
2352
|
+
: "";
|
|
2353
|
+
if (code === "SESSION_FILE_MISSING" || code === "ENOENT") {
|
|
2354
|
+
return {
|
|
2355
|
+
ok: false,
|
|
2356
|
+
code: "NO_SESSION_FILE",
|
|
2357
|
+
message: `Pi session file missing or not openable: ${init.sessionFile}`,
|
|
2358
|
+
};
|
|
2359
|
+
}
|
|
2315
2360
|
return {
|
|
2316
2361
|
ok: false,
|
|
2317
2362
|
code: "REOPEN_FAILED",
|
|
@@ -3147,6 +3192,36 @@ export function createDefaultPiSdkBindings() {
|
|
|
3147
3192
|
id: opts.sessionId,
|
|
3148
3193
|
});
|
|
3149
3194
|
},
|
|
3195
|
+
materializeSessionShell: async (opts) => {
|
|
3196
|
+
const sdk = (await loadSdk());
|
|
3197
|
+
const manager = opts.sessionManager;
|
|
3198
|
+
if (typeof manager.setSessionFile !== "function") {
|
|
3199
|
+
throw new Error("Pi SessionManager cannot materialize a session file");
|
|
3200
|
+
}
|
|
3201
|
+
let created = false;
|
|
3202
|
+
try {
|
|
3203
|
+
await mkdir(path.dirname(opts.sessionFile), { recursive: true });
|
|
3204
|
+
// Match Pi's documented session header. Rebinding through the public
|
|
3205
|
+
// SessionManager API marks it flushed, so Pi appends the first user
|
|
3206
|
+
// entry instead of trying to create the already-present file later.
|
|
3207
|
+
await writeFile(opts.sessionFile, `${JSON.stringify({
|
|
3208
|
+
type: "session",
|
|
3209
|
+
version: typeof sdk.CURRENT_SESSION_VERSION === "number"
|
|
3210
|
+
? sdk.CURRENT_SESSION_VERSION
|
|
3211
|
+
: 3,
|
|
3212
|
+
id: opts.sessionId,
|
|
3213
|
+
timestamp: new Date().toISOString(),
|
|
3214
|
+
cwd: opts.cwd,
|
|
3215
|
+
})}\n`, { encoding: "utf8", flag: "wx", mode: 0o600 });
|
|
3216
|
+
created = true;
|
|
3217
|
+
manager.setSessionFile(opts.sessionFile);
|
|
3218
|
+
}
|
|
3219
|
+
catch (error) {
|
|
3220
|
+
if (created)
|
|
3221
|
+
await rm(opts.sessionFile, { force: true }).catch(() => undefined);
|
|
3222
|
+
throw error;
|
|
3223
|
+
}
|
|
3224
|
+
},
|
|
3150
3225
|
createInMemorySessionManager: async (opts) => {
|
|
3151
3226
|
const sdk = (await loadSdk());
|
|
3152
3227
|
return sdk.SessionManager.inMemory(opts.cwd);
|
|
@@ -3163,13 +3238,19 @@ export function createDefaultPiSdkBindings() {
|
|
|
3163
3238
|
// wrong conversation under the durable Console sessionId. Fail closed
|
|
3164
3239
|
// before open when the persisted file is absent.
|
|
3165
3240
|
await access(opts.sessionFile);
|
|
3166
|
-
return sdk.SessionManager.open(opts.sessionFile);
|
|
3167
3241
|
}
|
|
3168
|
-
catch {
|
|
3169
|
-
|
|
3170
|
-
|
|
3242
|
+
catch (error) {
|
|
3243
|
+
const code = error && typeof error === "object" && "code" in error
|
|
3244
|
+
? String(error.code ?? "")
|
|
3245
|
+
: "";
|
|
3246
|
+
if (code === "ENOENT") {
|
|
3247
|
+
throw Object.assign(new Error(`SESSION_FILE_MISSING: ${opts.sessionFile}`), { code: "SESSION_FILE_MISSING", cause: error });
|
|
3248
|
+
}
|
|
3249
|
+
// File exists but is unreadable (permissions / I/O) — caller maps
|
|
3250
|
+
// undefined to 503 rather than silently creating a fresh session.
|
|
3171
3251
|
return undefined;
|
|
3172
3252
|
}
|
|
3253
|
+
return sdk.SessionManager.open(opts.sessionFile);
|
|
3173
3254
|
},
|
|
3174
3255
|
resolveModel: (opts) => {
|
|
3175
3256
|
const rt = opts.modelRuntime;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { createHash } from "node:crypto";
|
|
9
9
|
import { existsSync, lstatSync } from "node:fs";
|
|
10
|
-
import { readJsonIfExists, writeSecureJson, } from "
|
|
10
|
+
import { readJsonIfExists, writeSecureJson, } from "../../../infrastructure/console/app-data.js";
|
|
11
11
|
export const RESOURCE_PREFERENCES_SCHEMA_VERSION = 1;
|
|
12
12
|
export class ResourcePreferencesError extends Error {
|
|
13
13
|
code;
|