@tea-agent/loop-agent 0.43.0-next.9 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +31 -2309
- package/README.md +7 -0
- package/dist/application/dag/args.js +8 -0
- package/dist/application/task-lifecycle/advance.js +38 -7
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +2 -0
- package/dist/cli/program.js +3 -1
- package/dist/cli/update/init-surface-notifier.js +2 -0
- package/dist/cli/update/policy.js +2 -0
- package/dist/commands/client-recovery.js +20 -55
- package/dist/commands/cursor-prompt.js +2 -0
- package/dist/commands/dag-approve.js +2 -0
- package/dist/commands/dag-final-verification.js +2 -0
- package/dist/commands/dag-init-hybrid.js +2 -0
- package/dist/commands/dag-reconcile-tasks.js +2 -0
- package/dist/commands/dag-reject.js +2 -0
- package/dist/commands/dag-report.js +2 -0
- package/dist/commands/dag-rerun.js +2 -0
- package/dist/commands/dag-resume.js +2 -0
- package/dist/commands/dag-workflow-compile.js +2 -0
- package/dist/commands/dag-workflow-plan.js +2 -0
- package/dist/commands/dag-workflow-validate.js +2 -0
- package/dist/commands/delegate.js +2 -0
- package/dist/commands/examples.js +2 -0
- package/dist/commands/import-prd.js +2 -0
- package/dist/commands/init-model-catalog.js +2 -0
- package/dist/commands/init.js +19 -13
- package/dist/commands/instructions.js +2 -0
- package/dist/commands/knowledge.js +2 -0
- package/dist/commands/loop-benchmark.js +2 -0
- package/dist/commands/pi-prompt.js +2 -0
- package/dist/commands/pi-reuse-benchmark.js +2 -0
- package/dist/commands/promote-run.js +2 -0
- package/dist/commands/stats.js +1 -1
- package/dist/commands/study-init.js +2 -0
- package/dist/commands/task-advance.js +34 -0
- package/dist/commands/task-source-prepare.js +2 -0
- package/dist/commands/worktree-create.js +2 -0
- package/dist/commands/worktree-remove.js +2 -0
- package/dist/executors/dag-pi-executor.js +1650 -198
- package/dist/executors/pi-executor.js +85 -3
- package/dist/executors/pi-sdk-executor.js +18 -0
- package/dist/executors/shell-executor.js +93 -7
- package/dist/executors/shell-verification.js +3 -0
- package/dist/executors/shell-write-guard.js +27 -32
- package/dist/governance/exec-plans.js +6 -3
- package/dist/infrastructure/console/app-data.js +6 -0
- package/dist/shared/artifacts-core.js +2 -0
- package/dist/shared/backend-dogfood-preflight.js +47 -0
- package/dist/shared/dag-failure-category.js +3 -0
- package/dist/shared/git-progress.js +2 -0
- package/dist/shared/one-shot-prompt-args.js +2 -0
- package/dist/shared/operator/capabilities.js +180 -0
- package/dist/shared/package-metadata.js +6 -4
- package/dist/shared/pi-context-pressure/extension.js +26 -16
- package/dist/shared/pi-context-pressure/sift-bridge.js +1 -1
- package/dist/shared/pi-provider-recovery.js +182 -0
- package/dist/shared/pi-retry-settings.js +40 -0
- package/dist/shared/reference-context.js +2 -0
- package/dist/task/config-types.js +29 -0
- package/dist/task/contract/project.js +9 -0
- package/dist/task/contract/recover.js +6 -0
- package/dist/task/contract/schema.js +17 -0
- package/dist/task/source-prepare/artifact-meta.js +9 -2
- package/dist/task/source-prepare/build-draft.js +60 -0
- package/dist/task/source-prepare/fragment-inventory.js +4 -1
- package/dist/task/source-prepare/parse-intent.js +36 -11
- package/dist/task/task-demand-routing.js +5 -2
- package/dist/worker/console/chat/browser-automation.js +523 -0
- package/dist/worker/console/chat/browser-policy.js +6 -36
- package/dist/worker/console/chat/browser-routes.js +188 -56
- package/dist/worker/console/chat/explore-tools.js +5 -2
- package/dist/worker/console/chat/pi-mode-loop-isolation.js +155 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/ask-user-question.js +44 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/browser-tools.js +184 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/explore-tools.js +202 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/goal-tools.js +79 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +94 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/scheduled-goal-tools.js +22 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/todo-write.js +38 -0
- package/dist/worker/console/chat/pi-runtime/inspection-types.js +28 -0
- package/dist/worker/console/chat/pi-runtime/inspection.js +439 -0
- package/dist/worker/console/chat/pi-runtime/progressive-tools.js +195 -0
- package/dist/worker/console/chat/pi-runtime/sdk-bindings.js +153 -0
- package/dist/worker/console/chat/pi-runtime/sdk-session.js +5 -0
- package/dist/worker/console/chat/pi-runtime.js +208 -1138
- package/dist/worker/console/chat/routes.js +27 -7
- package/dist/worker/console/chat/scheduled-goal-booking.js +59 -0
- package/dist/worker/console/chat/scheduled-goal-delivery.js +27 -0
- package/dist/worker/console/chat/scheduled-goal-request.js +190 -0
- package/dist/worker/console/chat/sdd-data-alignment.js +1 -1
- package/dist/worker/console/chat/session-mode-view.js +5 -4
- package/dist/worker/console/chat/session-mode.js +18 -12
- package/dist/worker/console/chat/session-store.js +42 -9
- package/dist/worker/console/chat/tool-preview.js +115 -0
- package/dist/worker/console/chat/tools.js +10 -0
- package/dist/worker/console/chat/turn-order.js +13 -0
- package/dist/worker/console/chat/turn-process.js +32 -30
- package/dist/worker/console/console-update-and-init.js +1 -19
- package/dist/worker/console/console-update-runtime.js +5 -20
- package/dist/worker/console/operator-actions.js +63 -1
- package/dist/worker/console/prd-intake-bridge.js +54 -1
- package/dist/worker/console/routes.js +8 -0
- package/dist/worker/console/scheduled-goal-host.js +98 -0
- package/dist/worker/console/scheduled-goal-operation-adapter.js +127 -0
- package/dist/worker/console/server.js +24 -1
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-D_fNbWc_.js → abnfDiagram-N423BO3Z-8-j6y-sd.js} +1 -1
- package/dist/worker/console/static/assets/{arc-_HuqLW6m.js → arc-eoQiMvuk.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-Djy2qY1m.js → architectureDiagram-T3A2C74G-C4A3uMcI.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-bB-1TSyY.js → blockDiagram-VBNYF7ZC-D4zD2F-Q.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-C5Hmghrz.js → c4Diagram-5PPSVZJV-j1RkJziL.js} +1 -1
- package/dist/worker/console/static/assets/channel-ChE7y-cx.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-Duyl39oy.js → chunk-2GRJ4B5K-YBHmhik1.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-x6mdnSyf.js → chunk-2Q5K7J3B-COfWyo9P.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-WlBuFj7W.js → chunk-5RXB4S5H-I99OUkHY.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-CTF429HX.js → chunk-5VM5RSS4-XKxoJNJ4.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-Dwd6r-SF.js → chunk-6Q2QTUOP-DLT_cYx1.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-C-Br82D1.js → chunk-GF5L2VYU-CxcKZ9mV.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-CuGp0DeE.js → chunk-JWPE2WC7-V1EqXdjY.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-CJhFX6Lh.js → chunk-KBJHAD2P-DebTtdFp.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DpGOa_jT.js → chunk-RYQCIY6F-B-ivNRDf.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-DXJaTynd.js → chunk-XXDRQBXY-DC_Ds11b.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C01TCf2X.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C01TCf2X.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CRBZWjE4.js → cose-bilkent-JH36ORCC-sWEqKwIb.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BdXcxtlb.js → cynefin-VYW2F7L2-BXa_dcu4.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-07UKsOts.js → cynefinDiagram-MW4NZA55-C-Mle84F.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-D38p9__S.js → dagre-VZM6K2ZE-CXPDBITe.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-nSiBNNjH.js → diagram-7IWD3JNH-CC-WJQfa.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-BFOTot5D.js → diagram-B4RE2ZJO-CDAV5Vs4.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-DypKaZ6k.js → diagram-LBJQPF4R-CmFiAcNz.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-B6yoOQeW.js → diagram-Q27KOJAE-DPBZHuyn.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-BHYS6viX.js → diagram-UB23O5K3-jUlm_Ds3.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-D2VD5Snj.js → ebnfDiagram-BXEA7PRR-DWhQ3mfY.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-E98mWxN1.js → erDiagram-JOGREHBK-Tr2gMqet.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CT1zxhqP.js → flowDiagram-UKHOOZJN-DJjVQHPA.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-6GcngNcy.js → ganttDiagram-PKOTCBZU-D74dQ4u0.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-DCL6NvKe.js → gitGraphDiagram-DS77QQ5N-DwW0tZ0X.js} +1 -1
- package/dist/worker/console/static/assets/index-BWkIfcrK.css +1 -0
- package/dist/worker/console/static/assets/index-Cdkvw_H6.js +469 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-C0627e-9.js → infoDiagram-6WML65LV-ILCbxJyb.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-C_u3P6Ik.js → ishikawaDiagram-WSZJBQD7-DeuWBQ89.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DPDPv9HL.js → journeyDiagram-NVQOT4AX-CF5ih8Fk.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-D3OHdWiO.js → kanban-definition-27J2QSJJ-C7yOSuRO.js} +1 -1
- package/dist/worker/console/static/assets/{linear-DI88zD7n.js → linear-BDZ9riWi.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-p2l8IrWY.js → mermaid.core-7pKqYtpZ.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-B1bAX-oS.js → mindmap-definition-FAOFIHXS-LeJDybSU.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-DwOnWxdD.js → pegDiagram-VL7TDLO6-BJvT3pMD.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-xRkTXnJC.js → pieDiagram-7S7Q4E2Y-_rGqpMan.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-_9UC5Zio.js → quadrantDiagram-CIZ2JOQS-DPcSv5aA.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-CgEUirWJ.js → railroadDiagram-AXF67PYL-Drxx4hkJ.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-Czbpwiyz.js → requirementDiagram-LRYGKXZP-BCTUdU4z.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-_j7_KiqY.js → sankeyDiagram-W5VNT64P-B6wzbZmB.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-BNJa6Hyi.js → sequenceDiagram-SI44F4Z6-BGt8d3QQ.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-DedpKtOc.js → sizeCapture-X5ZJPWSS-7nlhJKo7.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-BBvthr7c.js → stateDiagram-OKZ733FA-Cv2stqMA.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DC7V5vcq.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-Ds7umgEM.js → swimlanes-SLNWSIFB-qDAo4Yc1.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Bwy4QUTO.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CKa-p1nF.js → timeline-definition-Z64GVDOM-CKbDNKTr.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-LoUNR56o.js → vennDiagram-T6HMQDX7-DI-9EHic.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-Bqbl6ym7.js → wardleyDiagram-T6FBY63Y-BrzzRDpX.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-B8dUg4lf.js → xychartDiagram-ELKLHX3M-BclH5hGh.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/operator-chat/chat-scroll-position.js +24 -0
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +41 -11
- package/dist/worker/console/static-src/operator-chat/compaction-message.js +3 -17
- package/dist/worker/console/static-src/operator-chat/composer-session-ledger.js +192 -0
- package/dist/worker/console/static-src/operator-chat/pending-user-message.js +9 -1
- package/dist/worker/console/static-src/operator-chat/slash-palette-nav.js +15 -5
- package/dist/worker/console/static-src/operator-chat/timeline-merge.js +29 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +92 -38
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +145 -70
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +38 -55
- package/dist/worker/console/static-src/operator-chat/useComposer.js +182 -69
- package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +2 -0
- package/dist/worker/console/static-src/prd-file-import.js +3 -1
- package/dist/worker/console/workspace-context.js +22 -0
- package/dist/worker/console/workspace-initialization.js +209 -0
- package/dist/worker/delivery/git-transaction.js +2 -0
- package/dist/worker/feature/fullstack-validate.js +2 -0
- package/dist/worker/loop-agent/loop-agent-client.js +8 -2
- package/dist/worker/materialize/harness-task-materializer.js +4 -1
- package/dist/worker/metrics/projector.js +1 -1
- package/dist/worker/observability/event-store.js +4 -1
- package/dist/worker/observability/read-model.js +4 -1
- package/dist/worker/observe/node-transparency.js +23 -1
- package/dist/worker/observe/routes.js +4 -0
- package/dist/worker/observe/static/operator-chrome.js +3 -1
- package/dist/worker/observe/static/styles.css +7 -4
- package/dist/worker/observe/static/views/dag-inspector.js +5 -19
- package/dist/worker/outcomes/declared-artifacts.js +2 -0
- package/dist/worker/preflight.js +3 -0
- package/dist/worker/scheduler/scheduled-goal-dispatch.js +117 -0
- package/dist/worker/scheduler/scheduled-goal-evidence.js +167 -0
- package/dist/worker/scheduler/scheduled-goal-recovery.js +62 -0
- package/dist/worker/scheduler/scheduled-goal-store.js +699 -0
- package/dist/worker/scheduler/scheduled-goal-supervisor.js +132 -0
- package/dist/worker/scheduler/scheduled-goal-time.js +102 -0
- package/dist/worker/scheduler/scheduled-goal-types.js +95 -0
- package/dist/worker/task-spec/validate.js +4 -1
- package/dist/workflows/dag/backend-test-markdown-workflow.js +6 -24
- package/dist/workflows/dag/backend-test-plan-protocol.js +82 -5
- package/dist/workflows/dag/dag-retry-schema.js +11 -0
- package/dist/workflows/dag/decision-envelope.js +2 -0
- package/dist/workflows/dag/dynamic-runtime/shared.js +2 -2
- package/dist/workflows/dag/frontend-closeout.js +3 -1
- package/dist/workflows/dag/frontend-committed-facts.js +461 -0
- package/dist/workflows/dag/frontend-durable-tools.js +15 -3
- package/dist/workflows/dag/frontend-implementation-contract.js +369 -12
- package/dist/workflows/dag/frontend-plan-canary.js +53 -0
- package/dist/workflows/dag/frontend-plan-decision-contract.js +803 -0
- package/dist/workflows/dag/frontend-plan-render.js +0 -2
- package/dist/workflows/dag/frontend-provider-capability-matrix.js +8 -61
- package/dist/workflows/dag/frontend-recovery-run.js +57 -0
- package/dist/workflows/dag/frontend-repair.js +55 -76
- package/dist/workflows/dag/frontend-review-context.js +42 -68
- package/dist/workflows/dag/frontend-review-scopes.js +2 -2
- package/dist/workflows/dag/frontend-risk.js +92 -10
- package/dist/workflows/dag/frontend-session-budget.js +117 -3
- package/dist/workflows/dag/frontend-shape.js +11 -55
- package/dist/workflows/dag/frontend-test-execution-evidence.js +35 -10
- package/dist/workflows/dag/frontend-typed-event-store.js +32 -25
- package/dist/workflows/dag/frontend-verification-trace.js +33 -54
- package/dist/workflows/dag/frontend-writer-admission.js +3 -47
- package/dist/workflows/dag/frontend-writer-status.js +0 -23
- package/dist/workflows/dag/init-hybrid.js +47 -19
- package/dist/workflows/dag/interrupt-request.js +2 -0
- package/dist/workflows/dag/lifecycle.js +11 -2
- package/dist/workflows/dag/node-execution.js +50 -13
- package/dist/workflows/dag/reconcile-run.js +2 -0
- package/dist/workflows/dag/repair-artifact.js +3 -1
- package/dist/workflows/dag/report.js +2 -0
- package/dist/workflows/dag/rerun-plan.js +10 -0
- package/dist/workflows/dag/rerun-task.js +79 -1
- package/dist/workflows/dag/retry-policy.js +18 -0
- package/dist/workflows/dag/scheduler.js +2 -4
- package/dist/workflows/dag/types.js +44 -6
- package/dist/workflows/dag/validate.js +4 -0
- package/docs/README.md +1 -0
- package/docs/architecture/runtime-boundaries.md +3 -3
- package/docs/governance/README.md +1 -0
- package/docs/init-surface.manifest.json +1 -0
- package/docs/operations/README.md +2 -0
- package/docs/templates/README.md +1 -1
- package/docs/templates/agent-dag.schema.json +2 -2
- package/docs/templates/backend-test-dag.json +14 -10
- package/docs/templates/frontend-implementation-contract.schema.json +0 -7
- package/package.json +9 -3
- package/skills/frontend-bounded-implement/references/code-standards.md +3 -3
- package/skills/frontend-contract/references/contract-protocol.md +3 -1
- package/skills/frontend-plan/SKILL.md +8 -6
- package/skills/frontend-plan/references/decision-contract.md +3 -3
- package/skills/frontend-review/SKILL.md +18 -28
- package/skills/frontend-review/references/review-findings.md +8 -3
- package/dist/commands/new-task.js +0 -5
- package/dist/commands/status.js +0 -57
- package/dist/commands/task-contract.js +0 -269
- package/dist/shared/prompts.js +0 -26
- package/dist/task/config.js +0 -2
- package/dist/task/contract/validate-draft.js +0 -106
- package/dist/task/goal.js +0 -3
- package/dist/task/index.js +0 -12
- package/dist/task/lifecycle.js +0 -1
- package/dist/task/operator/capabilities.js +0 -6
- package/dist/task/operator/envelope.js +0 -2
- package/dist/task/operator/index.js +0 -5
- package/dist/task/operator/registry.js +0 -2
- package/dist/task/operator/types.js +0 -1
- package/dist/task/paths.js +0 -1
- package/dist/task/source-state.js +0 -1
- package/dist/task/subagent-guidance.js +0 -1
- package/dist/worker/console/chat/sift-bridge.js +0 -1
- package/dist/worker/console/index.js +0 -20
- package/dist/worker/console/static/assets/channel-C0A6UEIa.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DzguNppy.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DzguNppy.js +0 -1
- package/dist/worker/console/static/assets/index-24jp3aBh.js +0 -468
- package/dist/worker/console/static/assets/index-CY6y6I8M.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BABVQnfM.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-D0qsLaxR.js +0 -8
- package/dist/worker/scheduler/index.js +0 -25
- package/dist/workflows/dag/facts.js +0 -4
- package/dist/workflows/dag/frontend-shadow-dual-write.js +0 -975
- package/dist/workflows/dag/index.js +0 -6
- package/dist/workflows/dynamic/index.js +0 -7
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HTTP
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* refuses to embed a site). The probe is display-only (headers back to the
|
|
6
|
-
* caller), restricted to http(s) non-loopback URLs, with a hard timeout.
|
|
2
|
+
* HTTP API for the Console Browser panel. The panel renders screenshots from
|
|
3
|
+
* the controlled browser and sends pointer/keyboard input back to the same
|
|
4
|
+
* Playwright page used by Operator Chat tools.
|
|
7
5
|
*/
|
|
8
|
-
import { embeddabilityOf, extractFrameAncestors,
|
|
6
|
+
import { embeddabilityOf, extractFrameAncestors, normalizeBrowserUrl, } from "./browser-policy.js";
|
|
9
7
|
function workspaceIdOf(req) {
|
|
10
8
|
try {
|
|
11
9
|
return new URL(req.url ?? "/", "http://localhost").searchParams.get("workspaceId") ?? undefined;
|
|
@@ -21,7 +19,38 @@ function sendJson(res, status, body) {
|
|
|
21
19
|
});
|
|
22
20
|
res.end(JSON.stringify(body));
|
|
23
21
|
}
|
|
24
|
-
|
|
22
|
+
function errorPayload(error) {
|
|
23
|
+
return {
|
|
24
|
+
code: error instanceof Error && "code" in error
|
|
25
|
+
? String(error.code)
|
|
26
|
+
: "BROWSER_OPERATION_FAILED",
|
|
27
|
+
message: error instanceof Error ? error.message : String(error),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function requireScope(req, deps) {
|
|
31
|
+
const ws = workspaceIdOf(req);
|
|
32
|
+
if (!ws) {
|
|
33
|
+
return { ok: false, status: 400, code: "WORKSPACE_REQUIRED", message: "workspaceId is required" };
|
|
34
|
+
}
|
|
35
|
+
if (deps.requireWorkspace && !deps.requireWorkspace(req).ok) {
|
|
36
|
+
return { ok: false, status: 403, code: "WORKSPACE_DENIED", message: "workspace scope mismatch" };
|
|
37
|
+
}
|
|
38
|
+
return { ok: true };
|
|
39
|
+
}
|
|
40
|
+
async function readJson(req) {
|
|
41
|
+
const chunks = [];
|
|
42
|
+
let size = 0;
|
|
43
|
+
for await (const chunk of req) {
|
|
44
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
45
|
+
size += buffer.byteLength;
|
|
46
|
+
if (size > 1024 * 1024)
|
|
47
|
+
throw new Error("request body exceeds 1MB");
|
|
48
|
+
chunks.push(buffer);
|
|
49
|
+
}
|
|
50
|
+
if (chunks.length === 0)
|
|
51
|
+
return {};
|
|
52
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
53
|
+
}
|
|
25
54
|
export async function handleBrowserRequest(req, res, deps, pathname) {
|
|
26
55
|
if (!pathname.startsWith("/api/operator/v1/chat/browser"))
|
|
27
56
|
return false;
|
|
@@ -30,73 +59,62 @@ export async function handleBrowserRequest(req, res, deps, pathname) {
|
|
|
30
59
|
const parts = rest.split("/").filter(Boolean);
|
|
31
60
|
const sub = parts[0] ?? "";
|
|
32
61
|
try {
|
|
33
|
-
if (method === "GET" && sub === "
|
|
34
|
-
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
if (!ws.ok) {
|
|
38
|
-
sendJson(res, 400, {
|
|
39
|
-
ok: false,
|
|
40
|
-
error: { code: "WORKSPACE_REQUIRED", message: "workspaceId is required" },
|
|
41
|
-
});
|
|
42
|
-
return true;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
else if (!workspaceIdOf(req)) {
|
|
46
|
-
sendJson(res, 400, {
|
|
62
|
+
if (method === "GET" && sub === "state" && parts.length === 1) {
|
|
63
|
+
const scope = requireScope(req, deps);
|
|
64
|
+
if (!scope.ok) {
|
|
65
|
+
sendJson(res, scope.status, {
|
|
47
66
|
ok: false,
|
|
48
|
-
error: { code:
|
|
67
|
+
error: { code: scope.code, message: scope.message },
|
|
49
68
|
});
|
|
50
69
|
return true;
|
|
51
70
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
let parsed;
|
|
55
|
-
try {
|
|
56
|
-
parsed = new URL(raw);
|
|
57
|
-
}
|
|
58
|
-
catch {
|
|
59
|
-
sendJson(res, 400, {
|
|
60
|
-
ok: false,
|
|
61
|
-
error: { code: "INVALID_URL", message: "invalid url" },
|
|
62
|
-
});
|
|
71
|
+
if (!deps.automation) {
|
|
72
|
+
sendJson(res, 200, { ok: true, data: { page: null } });
|
|
63
73
|
return true;
|
|
64
74
|
}
|
|
65
|
-
|
|
66
|
-
|
|
75
|
+
const page = await deps.automation.state();
|
|
76
|
+
sendJson(res, 200, { ok: true, data: { page } });
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
if (method === "GET" && sub === "probe" && parts.length === 1) {
|
|
80
|
+
const scope = requireScope(req, deps);
|
|
81
|
+
if (!scope.ok) {
|
|
82
|
+
sendJson(res, scope.status, {
|
|
67
83
|
ok: false,
|
|
68
|
-
error: { code:
|
|
84
|
+
error: { code: scope.code, message: scope.message },
|
|
69
85
|
});
|
|
70
86
|
return true;
|
|
71
87
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (
|
|
88
|
+
const raw = new URL(req.url ?? "/", "http://localhost").searchParams.get("url") ?? "";
|
|
89
|
+
const normalized = normalizeBrowserUrl(raw);
|
|
90
|
+
if (normalized.kind !== "ok") {
|
|
75
91
|
sendJson(res, 400, {
|
|
76
92
|
ok: false,
|
|
77
|
-
error: {
|
|
93
|
+
error: {
|
|
94
|
+
code: normalized.kind === "blocked" ? "BAD_SCHEME" : "INVALID_URL",
|
|
95
|
+
message: normalized.kind === "blocked"
|
|
96
|
+
? "only http/https urls can be probed"
|
|
97
|
+
: "invalid url",
|
|
98
|
+
},
|
|
78
99
|
});
|
|
79
100
|
return true;
|
|
80
101
|
}
|
|
81
102
|
const controller = new AbortController();
|
|
82
103
|
const timer = setTimeout(() => controller.abort(), 8000);
|
|
83
104
|
try {
|
|
84
|
-
let response = await fetch(
|
|
105
|
+
let response = await fetch(normalized.url, {
|
|
85
106
|
method: "HEAD",
|
|
86
107
|
redirect: "follow",
|
|
87
108
|
signal: controller.signal,
|
|
88
109
|
});
|
|
89
|
-
// Some servers answer HEAD with 405/501; retry once as GET
|
|
90
|
-
// (the body is discarded — only the headers matter).
|
|
91
110
|
if (response.status === 405 || response.status === 501) {
|
|
92
|
-
response = await fetch(
|
|
111
|
+
response = await fetch(normalized.url, {
|
|
93
112
|
method: "GET",
|
|
94
113
|
redirect: "follow",
|
|
95
114
|
signal: controller.signal,
|
|
96
115
|
});
|
|
97
116
|
}
|
|
98
|
-
const
|
|
99
|
-
const frameAncestors = extractFrameAncestors(csp);
|
|
117
|
+
const frameAncestors = extractFrameAncestors(response.headers.get("content-security-policy"));
|
|
100
118
|
const xFrameOptions = response.headers.get("x-frame-options");
|
|
101
119
|
const probe = {
|
|
102
120
|
reachable: true,
|
|
@@ -112,11 +130,12 @@ export async function handleBrowserRequest(req, res, deps, pathname) {
|
|
|
112
130
|
return true;
|
|
113
131
|
}
|
|
114
132
|
catch {
|
|
115
|
-
// DNS / TLS / connection / timeout: nothing to judge — the
|
|
116
|
-
// client keeps the plain iframe.
|
|
117
133
|
sendJson(res, 200, {
|
|
118
134
|
ok: true,
|
|
119
|
-
data: {
|
|
135
|
+
data: {
|
|
136
|
+
probe: { reachable: false },
|
|
137
|
+
verdict: "unknown",
|
|
138
|
+
},
|
|
120
139
|
});
|
|
121
140
|
return true;
|
|
122
141
|
}
|
|
@@ -124,6 +143,27 @@ export async function handleBrowserRequest(req, res, deps, pathname) {
|
|
|
124
143
|
clearTimeout(timer);
|
|
125
144
|
}
|
|
126
145
|
}
|
|
146
|
+
if (method === "POST" && parts.length >= 1) {
|
|
147
|
+
const scope = requireScope(req, deps);
|
|
148
|
+
if (!scope.ok) {
|
|
149
|
+
sendJson(res, scope.status, {
|
|
150
|
+
ok: false,
|
|
151
|
+
error: { code: scope.code, message: scope.message },
|
|
152
|
+
});
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
if (!deps.automation) {
|
|
156
|
+
sendJson(res, 503, {
|
|
157
|
+
ok: false,
|
|
158
|
+
error: { code: "BROWSER_UNAVAILABLE", message: "browser service unavailable" },
|
|
159
|
+
});
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
const body = await readJson(req);
|
|
163
|
+
const result = await dispatchBrowserPost(deps.automation, sub, body);
|
|
164
|
+
sendJson(res, 200, { ok: true, data: result });
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
127
167
|
sendJson(res, 404, {
|
|
128
168
|
ok: false,
|
|
129
169
|
error: { code: "NOT_FOUND", message: `unknown browser route: ${method} ${pathname}` },
|
|
@@ -132,13 +172,7 @@ export async function handleBrowserRequest(req, res, deps, pathname) {
|
|
|
132
172
|
}
|
|
133
173
|
catch (error) {
|
|
134
174
|
if (!res.headersSent) {
|
|
135
|
-
sendJson(res, 500, {
|
|
136
|
-
ok: false,
|
|
137
|
-
error: {
|
|
138
|
-
code: "BROWSER_INTERNAL",
|
|
139
|
-
message: error instanceof Error ? error.message : String(error),
|
|
140
|
-
},
|
|
141
|
-
});
|
|
175
|
+
sendJson(res, 500, { ok: false, error: errorPayload(error) });
|
|
142
176
|
}
|
|
143
177
|
else {
|
|
144
178
|
res.end();
|
|
@@ -146,3 +180,101 @@ export async function handleBrowserRequest(req, res, deps, pathname) {
|
|
|
146
180
|
return true;
|
|
147
181
|
}
|
|
148
182
|
}
|
|
183
|
+
async function dispatchBrowserPost(automation, action, body) {
|
|
184
|
+
switch (action) {
|
|
185
|
+
case "navigate": {
|
|
186
|
+
const result = await automation.navigate(string(body.url));
|
|
187
|
+
if (!result.ok)
|
|
188
|
+
throw new BrowserRouteError(result.code, result.error);
|
|
189
|
+
return result.page;
|
|
190
|
+
}
|
|
191
|
+
case "focus":
|
|
192
|
+
return automation.focus();
|
|
193
|
+
case "reload":
|
|
194
|
+
return automation.reload();
|
|
195
|
+
case "back":
|
|
196
|
+
return automation.goBack();
|
|
197
|
+
case "forward":
|
|
198
|
+
return automation.goForward();
|
|
199
|
+
case "scroll":
|
|
200
|
+
return automation.scroll({
|
|
201
|
+
direction: body.direction === "up" ? "up" : "down",
|
|
202
|
+
amount: numberOrUndefined(body.amount),
|
|
203
|
+
});
|
|
204
|
+
case "tab":
|
|
205
|
+
if (body.mode === "new")
|
|
206
|
+
return automation.newTab(optionalString(body.url));
|
|
207
|
+
if (body.mode === "close")
|
|
208
|
+
return automation.closeTab(numberOrUndefined(body.tabId));
|
|
209
|
+
return automation.selectTab(number(body.tabId));
|
|
210
|
+
case "dialog":
|
|
211
|
+
return automation.handleDialog(body.action === "dismiss" ? "dismiss" : "accept", optionalString(body.promptText));
|
|
212
|
+
case "pointer": {
|
|
213
|
+
const type = string(body.type);
|
|
214
|
+
if (!["mousemove", "mousedown", "mouseup", "wheel"].includes(type)) {
|
|
215
|
+
throw new Error("invalid pointer event type");
|
|
216
|
+
}
|
|
217
|
+
const event = type === "wheel"
|
|
218
|
+
? {
|
|
219
|
+
type,
|
|
220
|
+
x: number(body.x),
|
|
221
|
+
y: number(body.y),
|
|
222
|
+
deltaX: number(body.deltaX ?? 0),
|
|
223
|
+
deltaY: number(body.deltaY ?? 0),
|
|
224
|
+
}
|
|
225
|
+
: {
|
|
226
|
+
type,
|
|
227
|
+
x: number(body.x),
|
|
228
|
+
y: number(body.y),
|
|
229
|
+
...(body.button === "middle" || body.button === "right"
|
|
230
|
+
? { button: body.button }
|
|
231
|
+
: {}),
|
|
232
|
+
};
|
|
233
|
+
return automation.dispatchPointer(event);
|
|
234
|
+
}
|
|
235
|
+
case "keyboard": {
|
|
236
|
+
const type = string(body.type);
|
|
237
|
+
if (type !== "keydown" && type !== "keyup")
|
|
238
|
+
throw new Error("invalid keyboard event type");
|
|
239
|
+
const key = string(body.key);
|
|
240
|
+
if (!isPanelKeyboardKey(key)) {
|
|
241
|
+
throw new Error("invalid keyboard key; use the text action for printable characters");
|
|
242
|
+
}
|
|
243
|
+
return automation.dispatchKeyboard({ type, key });
|
|
244
|
+
}
|
|
245
|
+
case "text":
|
|
246
|
+
return automation.inputText(string(body.text));
|
|
247
|
+
case "wait":
|
|
248
|
+
return automation.waitFor(number(body.ms ?? 500));
|
|
249
|
+
default:
|
|
250
|
+
throw new Error(`unknown browser action: ${action}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
class BrowserRouteError extends Error {
|
|
254
|
+
code;
|
|
255
|
+
constructor(code, message) {
|
|
256
|
+
super(message);
|
|
257
|
+
this.code = code;
|
|
258
|
+
this.name = "BrowserRouteError";
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
function string(value) {
|
|
262
|
+
if (typeof value !== "string")
|
|
263
|
+
throw new Error("expected string");
|
|
264
|
+
return value;
|
|
265
|
+
}
|
|
266
|
+
function optionalString(value) {
|
|
267
|
+
return typeof value === "string" ? value : undefined;
|
|
268
|
+
}
|
|
269
|
+
function number(value) {
|
|
270
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
271
|
+
throw new Error("expected finite number");
|
|
272
|
+
return value;
|
|
273
|
+
}
|
|
274
|
+
function numberOrUndefined(value) {
|
|
275
|
+
return value === undefined || value === null ? undefined : number(value);
|
|
276
|
+
}
|
|
277
|
+
function isPanelKeyboardKey(key) {
|
|
278
|
+
return /^(Control|Meta|Alt|Shift)(\+[A-Za-z0-9][A-Za-z0-9]*)?$/.test(key)
|
|
279
|
+
|| (key.length > 1 && /^[A-Za-z][A-Za-z0-9]*$/.test(key));
|
|
280
|
+
}
|
|
@@ -279,8 +279,11 @@ export async function safeGrep(repoRoot, pattern, options) {
|
|
|
279
279
|
for (let i = 0; i < lines.length; i++) {
|
|
280
280
|
if (matches.length >= GREP_MATCH_LIMIT)
|
|
281
281
|
break;
|
|
282
|
-
|
|
283
|
-
|
|
282
|
+
const line = lines[i];
|
|
283
|
+
if (line === undefined)
|
|
284
|
+
continue;
|
|
285
|
+
if (re.test(line)) {
|
|
286
|
+
const { scrubbed, redactions } = scrubSecrets(line);
|
|
284
287
|
if (redactions.length > 0) {
|
|
285
288
|
for (const r of redactions) {
|
|
286
289
|
const found = totalRedactions.find((t) => t.name === r.name);
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pi-mode loop isolation for loop-agent init projections.
|
|
3
|
+
*
|
|
4
|
+
* Pi mode ("自由对话") should not auto-load the governance AGENTS.md managed
|
|
5
|
+
* block that `loop-agent init` writes into a target project, nor the loop-agent
|
|
6
|
+
* built-in skills it mirrors into `<cwd>/.agents/skills/`. Manual `/skills:name`
|
|
7
|
+
* invocation and third-party/custom project skills must stay available; the
|
|
8
|
+
* Workflow mode is untouched (isolation applied only for `sessionMode ===
|
|
9
|
+
* "pi"`).
|
|
10
|
+
*
|
|
11
|
+
* Everything here is a pure function over discovered resources + persisted
|
|
12
|
+
* auto-invocation prefs, so it is trivially unit-testable.
|
|
13
|
+
*/
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import { skillResourceId, } from "./resource-preferences-store.js";
|
|
16
|
+
/** init.ts `MANAGED_BLOCK_START` / `MANAGED_BLOCK_END` (docs/templates/init-managed-agents.md). */
|
|
17
|
+
export const LOOP_AGENTS_MANAGED_BLOCK_START = "<!-- LOOP_AGENT_INIT_START -->";
|
|
18
|
+
export const LOOP_AGENTS_MANAGED_BLOCK_END = "<!-- LOOP_AGENT_INIT_END -->";
|
|
19
|
+
/**
|
|
20
|
+
* Built-in skill directory names that `loop-agent init` mirrors from the
|
|
21
|
+
* package's `skills/` into a target project's `.agents/skills/`.
|
|
22
|
+
*
|
|
23
|
+
* MUST be kept in sync with the repo-root `skills/` directory; a CI check
|
|
24
|
+
* asserts they match (see `scripts/check-loop-builtin-skills.sh`).
|
|
25
|
+
*/
|
|
26
|
+
export const LOOP_BUILTIN_SKILL_DIR_NAMES = [
|
|
27
|
+
"agent-worker",
|
|
28
|
+
"ai-engineering-context",
|
|
29
|
+
"analyze-product-dependencies",
|
|
30
|
+
"analyze-product-requirements",
|
|
31
|
+
"browser-tools",
|
|
32
|
+
"code-review-core",
|
|
33
|
+
"codebase-scout",
|
|
34
|
+
"fe-test-ui-scout",
|
|
35
|
+
"frontend-bounded-implement",
|
|
36
|
+
"frontend-contract",
|
|
37
|
+
"frontend-design-review",
|
|
38
|
+
"frontend-plan",
|
|
39
|
+
"frontend-review",
|
|
40
|
+
"frontend-scout",
|
|
41
|
+
"frontend-verification",
|
|
42
|
+
"grill-me",
|
|
43
|
+
"grill-with-docs",
|
|
44
|
+
"improve-codebase-architecture",
|
|
45
|
+
"init-capability-evolution",
|
|
46
|
+
"local-jacoco-coverage",
|
|
47
|
+
"loop-agent",
|
|
48
|
+
"playwright-cli",
|
|
49
|
+
"playwright-cli-case-generator",
|
|
50
|
+
"requesting-code-review",
|
|
51
|
+
"systematic-debugging",
|
|
52
|
+
"test-driven-development",
|
|
53
|
+
"using-git-worktrees",
|
|
54
|
+
"verification-before-completion",
|
|
55
|
+
"webapp-testing",
|
|
56
|
+
];
|
|
57
|
+
/* Case-insensitive set for fast membership (paths are compared lower-cased). */
|
|
58
|
+
const LOOP_BUILTIN_SKILL_NAMES_LOWER = new Set(LOOP_BUILTIN_SKILL_DIR_NAMES.map((name) => name.toLowerCase()));
|
|
59
|
+
/** Normalize to forward slashes + lower case for Windows/macOS path compares. */
|
|
60
|
+
function normalizeForCompare(value) {
|
|
61
|
+
return value.replace(/\\/g, "/").toLowerCase();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Strip the loop-agent init managed block (inclusive of both markers) from an
|
|
65
|
+
* AGENTS.md content string.
|
|
66
|
+
*
|
|
67
|
+
* Returns the content unchanged when no valid marker pair is present (missing
|
|
68
|
+
* either marker, or END before START), so user-authored AGENTS.md and non-loop
|
|
69
|
+
* roots are never touched.
|
|
70
|
+
*/
|
|
71
|
+
export function stripLoopManagedBlock(content) {
|
|
72
|
+
const start = content.indexOf(LOOP_AGENTS_MANAGED_BLOCK_START);
|
|
73
|
+
if (start < 0)
|
|
74
|
+
return content;
|
|
75
|
+
const end = content.indexOf(LOOP_AGENTS_MANAGED_BLOCK_END, start + LOOP_AGENTS_MANAGED_BLOCK_START.length);
|
|
76
|
+
if (end < 0)
|
|
77
|
+
return content;
|
|
78
|
+
const endPos = end + LOOP_AGENTS_MANAGED_BLOCK_END.length;
|
|
79
|
+
const before = content.slice(0, start).trimEnd();
|
|
80
|
+
const after = content.slice(endPos).trimStart();
|
|
81
|
+
return `${before}${before && after ? "\n\n" : ""}${after}`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* True when a discovered skill is a loop-agent init projection: its file path
|
|
85
|
+
* is under `<cwd>/.agents/skills/<builtin-name>/` for a name in the builtin
|
|
86
|
+
* whitelist. Global user skills (`~/.agents/skills`, `~/.pi/agent/skills`) and
|
|
87
|
+
* third-party project skills outside the whitelist return false.
|
|
88
|
+
*/
|
|
89
|
+
export function isLoopInitProjectedSkill(skill, cwd) {
|
|
90
|
+
if (!skill?.filePath)
|
|
91
|
+
return false;
|
|
92
|
+
const cwdNorm = normalizeForCompare(path.resolve(cwd));
|
|
93
|
+
const fileNorm = normalizeForCompare(path.resolve(skill.filePath));
|
|
94
|
+
const prefix = `${cwdNorm}/.agents/skills/`;
|
|
95
|
+
if (!fileNorm.startsWith(prefix))
|
|
96
|
+
return false;
|
|
97
|
+
const rest = fileNorm.slice(prefix.length);
|
|
98
|
+
const topSeg = rest.split("/")[0];
|
|
99
|
+
if (!topSeg)
|
|
100
|
+
return false;
|
|
101
|
+
return LOOP_BUILTIN_SKILL_NAMES_LOWER.has(topSeg);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Pi-mode default isolation over skills: for skills that are loop init
|
|
105
|
+
* projections, default `disableModelInvocation` to true UNLESS the user has
|
|
106
|
+
* EXPLICITLY tuned auto-invocation ON for that resource id in the persisted
|
|
107
|
+
* prefs. Explicitly ON wins over the Pi default; explicit OFF is treated as the
|
|
108
|
+
* Pi default. Non-loop skills pass through untouched.
|
|
109
|
+
*/
|
|
110
|
+
export function applyPiModeSkillIsolation(skills, prefs, cwd) {
|
|
111
|
+
return skills.map((skill) => {
|
|
112
|
+
if (!isLoopInitProjectedSkill(skill, cwd))
|
|
113
|
+
return skill;
|
|
114
|
+
const id = skillResourceId(skill);
|
|
115
|
+
const pref = prefs.skills[id];
|
|
116
|
+
if (pref?.autoInvocationEnabled === true)
|
|
117
|
+
return skill;
|
|
118
|
+
if (skill.disableModelInvocation === true)
|
|
119
|
+
return skill;
|
|
120
|
+
return { ...skill, disableModelInvocation: true };
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Build the pi-mode loop isolation resource-loader option fragments.
|
|
125
|
+
*
|
|
126
|
+
* - When `enabled` (session mode pi): returns an `agentsFilesOverride` that
|
|
127
|
+
* strips the loop-agent managed AGENTS.md block, and wraps the given
|
|
128
|
+
* `skillsOverride` so it ALSO applies Pi-mode default isolation after the
|
|
129
|
+
* persisted auto-invocation prefs.
|
|
130
|
+
* - When disabled (workflow): returns ONLY the provided `skillsOverride`
|
|
131
|
+
* unchanged, so workflow session behavior is byte-for-byte identical to today.
|
|
132
|
+
*/
|
|
133
|
+
export function buildPiModeLoopIsolationOptions(options) {
|
|
134
|
+
if (!options.enabled) {
|
|
135
|
+
return { skillsOverride: options.skillsOverride };
|
|
136
|
+
}
|
|
137
|
+
const { cwd, readPreferences } = options;
|
|
138
|
+
const agentsFilesOverride = (current) => ({
|
|
139
|
+
agentsFiles: current.agentsFiles.map((file) => ({
|
|
140
|
+
...file,
|
|
141
|
+
content: stripLoopManagedBlock(file.content),
|
|
142
|
+
})),
|
|
143
|
+
});
|
|
144
|
+
return {
|
|
145
|
+
agentsFilesOverride,
|
|
146
|
+
skillsOverride: (current) => {
|
|
147
|
+
const prefs = readPreferences() ?? { schemaVersion: 1, skills: {} };
|
|
148
|
+
const withPrefs = options.skillsOverride(current);
|
|
149
|
+
return {
|
|
150
|
+
skills: applyPiModeSkillIsolation(withPrefs.skills, prefs, cwd),
|
|
151
|
+
diagnostics: current.diagnostics,
|
|
152
|
+
};
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-bound ask_user_question custom tool.
|
|
3
|
+
* ConsolePiRuntime supplies the sessionId and UserQuestionRegistry.
|
|
4
|
+
*/
|
|
5
|
+
const ASK_USER_QUESTION_DESCRIPTION = "Ask the user concise questions when a confirmation, choice, or missing detail is required before proceeding. " +
|
|
6
|
+
"The tool pauses until the user answers. Use it instead of writing questions as ordinary assistant text. " +
|
|
7
|
+
"Send one or more questions with stable ids; recommended options should be first and end with (Recommended).";
|
|
8
|
+
export async function buildAskUserQuestionTool(options) {
|
|
9
|
+
const [{ Type }, { defineTool }] = await Promise.all([
|
|
10
|
+
import("typebox"),
|
|
11
|
+
import("@earendil-works/pi-coding-agent"),
|
|
12
|
+
]);
|
|
13
|
+
return defineTool({
|
|
14
|
+
name: "ask_user_question",
|
|
15
|
+
label: "Ask user",
|
|
16
|
+
description: ASK_USER_QUESTION_DESCRIPTION,
|
|
17
|
+
promptSnippet: ASK_USER_QUESTION_DESCRIPTION,
|
|
18
|
+
parameters: Type.Object({
|
|
19
|
+
questions: Type.Array(Type.Object({
|
|
20
|
+
id: Type.String({ description: "Stable question id echoed in the answer." }),
|
|
21
|
+
question: Type.String({ description: "Specific user-facing question." }),
|
|
22
|
+
header: Type.Optional(Type.String({ description: "Optional short heading." })),
|
|
23
|
+
detail: Type.Optional(Type.String({ description: "Optional Markdown context shown below the question." })),
|
|
24
|
+
options: Type.Optional(Type.Array(Type.Object({
|
|
25
|
+
label: Type.String({ description: "Short user-facing option label." }),
|
|
26
|
+
description: Type.Optional(Type.String({ description: "One sentence explaining impact or tradeoff." })),
|
|
27
|
+
}, { additionalProperties: false }))),
|
|
28
|
+
multi_select: Type.Optional(Type.Boolean({ description: "Allow more than one option." })),
|
|
29
|
+
}, { additionalProperties: false }), { minItems: 1, maxItems: 20 }),
|
|
30
|
+
}, { additionalProperties: false }),
|
|
31
|
+
async execute(toolCallId, params, signal) {
|
|
32
|
+
const answer = await options.registry.ask({
|
|
33
|
+
sessionId: options.sessionId,
|
|
34
|
+
toolCallId,
|
|
35
|
+
questions: params.questions,
|
|
36
|
+
signal,
|
|
37
|
+
});
|
|
38
|
+
return {
|
|
39
|
+
content: [{ type: "text", text: JSON.stringify(answer) }],
|
|
40
|
+
details: answer,
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|