@iowarp/clio-coder 0.3.3 → 0.3.6
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/CHANGELOG.md +74 -0
- package/CONTRIBUTING.md +7 -7
- package/README.md +3 -3
- package/dist/{acp-P2AQILE2.js → acp-2BEHC4DL.js} +9 -8
- package/dist/{agents-72W3BI7I.js → agents-LNNFTM53.js} +29 -24
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-5TWEIYDN.js → auth-KXXFI2VS.js} +14 -10
- package/dist/{chunk-GGXXDWE4.js → chunk-22NAGB7X.js} +2 -2
- package/dist/{chunk-YCWGATWI.js → chunk-24I7BN55.js} +2 -2
- package/dist/{chunk-EKMEHE4H.js → chunk-33YXPOE3.js} +2 -3
- package/dist/chunk-3BPUFZDL.js +37 -0
- package/dist/chunk-43AOLP7E.js +375 -0
- package/dist/{chunk-ZDOOVTXZ.js → chunk-4OC57DA6.js} +27 -4
- package/dist/{chunk-6SGHMWE3.js → chunk-5JGRAMKL.js} +5 -5
- package/dist/{chunk-V6RTAOC2.js → chunk-6US73PDB.js} +572 -51
- package/dist/{chunk-5UFT4SUX.js → chunk-6XXKFVSN.js} +3 -3
- package/dist/{chunk-A3CYT5EX.js → chunk-AD2SYQYC.js} +55 -2
- package/dist/chunk-AOCYTWAV.js +449 -0
- package/dist/chunk-CFGTUFWB.js +67 -0
- package/dist/chunk-CJUB2JJ2.js +1478 -0
- package/dist/{chunk-FNTMWMX5.js → chunk-CKXWIANG.js} +14 -12
- package/dist/{chunk-PIWWS5BL.js → chunk-CYQKWTG3.js} +63 -78
- package/dist/{chunk-LZSJBIVT.js → chunk-DJVECN66.js} +271 -762
- package/dist/{chunk-CBCAPZAA.js → chunk-E25LMLRW.js} +2 -2
- package/dist/{chunk-ZWMF7253.js → chunk-E2ER4LJF.js} +304 -9
- package/dist/{chunk-STBPMHSX.js → chunk-EKY57CSP.js} +51 -84
- package/dist/{chunk-DUYJ5IO6.js → chunk-EYPA3EGJ.js} +12 -4
- package/dist/{chunk-M6SHUN7Q.js → chunk-FO5ZOVUY.js} +2 -2
- package/dist/chunk-FYYLNIL5.js +313 -0
- package/dist/{chunk-OQ33BKR3.js → chunk-G7MUEIGA.js} +3 -60
- package/dist/chunk-GEYXPTRF.js +613 -0
- package/dist/chunk-GOXNB3AO.js +261 -0
- package/dist/{chunk-G4BMMOKF.js → chunk-HVDIIIQW.js} +2 -2
- package/dist/chunk-HWUFFB6L.js +83 -0
- package/dist/{chunk-4XUGQOHA.js → chunk-K7T3E2SR.js} +15 -8
- package/dist/chunk-K7VKOLQQ.js +15 -0
- package/dist/{chunk-UFIIWP2H.js → chunk-KHSFENX2.js} +8 -8
- package/dist/{chunk-BMEMKKIT.js → chunk-KOHPCX4K.js} +2 -2
- package/dist/chunk-LCGCVYZ4.js +57 -0
- package/dist/chunk-LL4KHSZI.js +22 -0
- package/dist/{chunk-PAJK6MAQ.js → chunk-LYF7OHWH.js} +42 -15
- package/dist/{chunk-POHLU5DW.js → chunk-M6L6IDJG.js} +3 -3
- package/dist/{chunk-5UUP6MWO.js → chunk-MV3K5QF2.js} +5 -436
- package/dist/{chunk-X4RCMKVQ.js → chunk-NDINPTJ4.js} +2 -2
- package/dist/{chunk-TZK7PACC.js → chunk-NILBFAPG.js} +14 -8
- package/dist/chunk-ODFEOB4F.js +1082 -0
- package/dist/{chunk-AGYYIBLL.js → chunk-OH3TOQTB.js} +6 -2
- package/dist/chunk-OZNBF4L3.js +23 -0
- package/dist/{chunk-DSELYM6W.js → chunk-PBTHKCPN.js} +30 -10
- package/dist/{verify-375KUB3Y.js → chunk-PCZJO5TI.js} +127 -42
- package/dist/{chunk-ED4KHGC3.js → chunk-PPAMZ32Z.js} +9 -2
- package/dist/{chunk-SRDMMSEP.js → chunk-QM3F2GKX.js} +1063 -1645
- package/dist/{chunk-X6IAEBZR.js → chunk-QNQHSOLF.js} +7 -7
- package/dist/{chunk-OC7FIQPC.js → chunk-R46L2BIR.js} +10 -7
- package/dist/{chunk-2TLUCQVG.js → chunk-RD5U66HV.js} +3 -3
- package/dist/{chunk-6N5PTWMY.js → chunk-RY3LY4J5.js} +50 -13
- package/dist/{chunk-OKGUZO2U.js → chunk-SPULKLCF.js} +4 -3
- package/dist/{chunk-OOJYHWRB.js → chunk-TSHXZTOQ.js} +6 -5
- package/dist/chunk-TZSKNMZG.js +434 -0
- package/dist/{chunk-7MNJORFF.js → chunk-UL3WSD3F.js} +6 -1
- package/dist/{chunk-VJWL6YS5.js → chunk-UUVG37B4.js} +2 -2
- package/dist/{chunk-COU2UHX6.js → chunk-VEZEGCGW.js} +170 -2
- package/dist/chunk-W6GROXXM.js +69 -0
- package/dist/{chunk-OAO4GE4M.js → chunk-WHGPSPT5.js} +2 -2
- package/dist/chunk-WHJYKASB.js +677 -0
- package/dist/{chunk-ORBHGJC5.js → chunk-WR67VIZY.js} +3 -3
- package/dist/{chunk-YHZX5GEU.js → chunk-XAKHZX5N.js} +2 -2
- package/dist/{chunk-TZTZS7QK.js → chunk-XE2VEJHX.js} +5 -3
- package/dist/{chunk-LM5TQCJZ.js → chunk-XF5N4U5A.js} +8 -7
- package/dist/{chunk-LWLEKMDQ.js → chunk-XXQNGV4M.js} +1073 -552
- package/dist/{chunk-KZWTDYJF.js → chunk-XYDYPRZI.js} +7 -7
- package/dist/chunk-ZGVHUX3M.js +66 -0
- package/dist/{chunk-LW6DSM3M.js → chunk-ZRGEBJ4T.js} +1192 -1119
- package/dist/{chunk-2DJ2KNFG.js → chunk-ZXF4XRKW.js} +202 -40
- package/dist/chunk-ZZMN5OM4.js +122 -0
- package/dist/cli/index.js +34 -30
- package/dist/{clio-JOU4FXVA.js → clio-M2KGYUFZ.js} +7 -6
- package/dist/{code-nav-7AX6FYE6.js → code-nav-GQNL7XA6.js} +8 -6
- package/dist/codewiki/build-worker.js +4 -4
- package/dist/{components-KELWS457.js → components-5TTYYX6G.js} +3 -3
- package/dist/{config-XCDVKR23.js → config-XUUYQIWO.js} +47 -35
- package/dist/{configure-4GAP54ZW.js → configure-IHJ7YOMV.js} +18 -15
- package/dist/{context-77FM5DV5.js → context-74JLXAWD.js} +18 -10
- package/dist/{context-4UOGGLQ5.js → context-75MIWW3U.js} +41 -29
- package/dist/{context-5VKGUVJJ.js → context-ZQ7SIFJV.js} +85 -9
- package/dist/{context-clear-XXJRLCJJ.js → context-clear-GYKWNUML.js} +41 -29
- package/dist/{context-index-BZ4UYMTC.js → context-index-SSR5ECNE.js} +3 -3
- package/dist/context-working-set-UX5KEP4J.js +1553 -0
- package/dist/{dispatch-runner-QPRDDBDX.js → dispatch-runner-GIJBHNFL.js} +47 -32
- package/dist/{docs-2C2LTVT2.js → docs-6FZSCG5B.js} +3 -3
- package/dist/{doctor-HR46URBJ.js → doctor-SVJ5BZCW.js} +12 -12
- package/dist/{eval-XSSNATB4.js → eval-CG6LLBLD.js} +54 -238
- package/dist/{evidence-6HG2PY2B.js → evidence-ZYFIEN42.js} +57 -28
- package/dist/{evolve-K7YU3NCY.js → evolve-QGEXEMDW.js} +36 -25
- package/dist/{extensions-QVDOHDGJ.js → extensions-ADGNCJJD.js} +3 -3
- package/dist/{fleet-VY3HHKN6.js → fleet-S5R4ZOQY.js} +73 -44
- package/dist/{fleet-preflight-DDN536IT.js → fleet-preflight-BHSNPBMH.js} +3 -3
- package/dist/{init-JYGXI3FK.js → init-5DRU55YR.js} +49 -37
- package/dist/memory-7YKKR6UC.js +467 -0
- package/dist/{models-I5QWSEOM.js → models-ZPOLRU2C.js} +24 -21
- package/dist/{monitor-GE4ID3IA.js → monitor-US5F5YGZ.js} +73 -46
- package/dist/{orchestrator-EM5MC3HM.js → orchestrator-E2AL4T5N.js} +1624 -1007
- package/dist/{paths-UXLN5YYZ.js → paths-E7KYAQWE.js} +3 -3
- package/dist/{reset-L2FQEE3E.js → reset-KZ652EK6.js} +6 -5
- package/dist/{run-ZU3QMZPZ.js → run-SRNBKDWD.js} +76 -54
- package/dist/{share-S5BZQC5I.js → share-CGZE33UP.js} +7 -6
- package/dist/{skills-X5VXCRNQ.js → skills-S2X4DLY5.js} +4 -4
- package/dist/{skills-eval-WKIHWTHR.js → skills-eval-W2GGIC4R.js} +40 -29
- package/dist/{targets-SNCPI2NR.js → targets-54SWINWB.js} +28 -23
- package/dist/{terminal-lease-BNAHVHBS.js → terminal-lease-SAIF2OGY.js} +6 -4
- package/dist/{uninstall-FZCQCDKC.js → uninstall-BVLWXKBT.js} +3 -3
- package/dist/{upgrade-JQHHPQ4K.js → upgrade-JKAR27XC.js} +20 -19
- package/dist/{usage-OR4O5SMZ.js → usage-MSAWCLX4.js} +79 -36
- package/dist/verifiers-NCBTHHN2.js +1220 -0
- package/dist/verify-X5HDROLA.js +25 -0
- package/dist/{wiki-generate-UEXP2ARI.js → wiki-generate-GUSOQ6ZP.js} +50 -37
- package/dist/worker/entry.js +90 -70
- package/dist/{workspace-G4ZWUIPR.js → workspace-ZJ6BFM3Q.js} +4 -4
- package/docs/README.md +8 -7
- package/docs/acp.md +1 -1
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/artifact-placement.md +1 -2
- package/docs/artifact-versions.md +1 -1
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +1 -1
- package/docs/commands-and-modes.md +60 -26
- package/docs/config-knobs-audit.md +1 -2
- package/docs/configuration-and-targets.md +26 -1
- package/docs/context-engine.md +67 -13
- package/docs/context-working-set.md +194 -0
- package/docs/development-pipeline.md +1 -1
- package/docs/documentation-coverage.md +6 -6
- package/docs/documentation-guide.md +7 -6
- package/docs/environment-variables.md +2 -1
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +4 -32
- package/docs/evidence-and-memory.md +139 -7
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +1 -1
- package/docs/extensions-and-sharing.md +2 -2
- package/docs/fleet-dispatch.md +49 -8
- package/docs/glossary.md +21 -1
- package/docs/installation-and-lifecycle.md +2 -2
- package/docs/middleware-and-components.md +19 -2
- package/docs/model-catalog.md +7 -9
- package/docs/observability.md +4 -4
- package/docs/proactive-memory.md +26 -16
- package/docs/prompt-envelope-and-tools.md +7 -5
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +43 -40
- package/docs/safety-model.md +49 -8
- package/docs/scientific-validation.md +21 -3
- package/docs/session-lifecycle.md +3 -3
- package/docs/skills-marketplace.md +1 -1
- package/docs/tool-usage.md +79 -12
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +1 -1
- package/docs/tui-design.md +38 -4
- package/docs/worker-dispatch-mechanics.md +11 -1
- package/package.json +13 -13
- package/skills/meta/clio-test/SKILL.md +20 -17
- package/skills/meta/clio-test/evals.md +3 -3
- package/skills/meta/clio-test/references/harness.md +35 -6
- package/skills/meta/clio-test/references/test-map.md +20 -10
- package/skills/registry.yaml +2 -2
- package/skills/skill-marketplace.json +1 -1
- package/src/cli/agents.ts +2 -3
- package/src/cli/argv.ts +14 -1
- package/src/cli/context-working-set.ts +513 -0
- package/src/cli/context.ts +8 -0
- package/src/cli/evidence.ts +20 -2
- package/src/cli/fleet.ts +15 -0
- package/src/cli/index.ts +5 -1
- package/src/cli/memory.ts +272 -10
- package/src/cli/modes/json-stream.ts +2 -2
- package/src/cli/modes/print.ts +12 -1
- package/src/cli/run.ts +22 -2
- package/src/cli/targets.ts +12 -3
- package/src/cli/usage.ts +55 -7
- package/src/cli/verifiers.ts +325 -0
- package/src/core/bash-exec.ts +39 -14
- package/src/core/bus-events.ts +22 -4
- package/src/core/config.ts +54 -0
- package/src/core/defaults.ts +50 -3
- package/src/core/response-model-id.ts +134 -0
- package/src/core/toml.ts +62 -0
- package/src/core/verification-scripts.ts +6 -0
- package/src/core/workspace-files.ts +0 -1
- package/src/domains/agents/builtins/architect.md +1 -1
- package/src/domains/agents/builtins/verifier.md +3 -0
- package/src/domains/agents/catalog.ts +5 -4
- package/src/domains/agents/recipe.ts +54 -14
- package/src/domains/agents/result-contract.ts +7 -4
- package/src/domains/config/classify.ts +1 -0
- package/src/domains/context/bootstrap.ts +36 -27
- package/src/domains/context/project-metadata.ts +19 -63
- package/src/domains/context/prompt-context.ts +8 -0
- package/src/domains/context/working-set/contract.ts +161 -0
- package/src/domains/context/working-set/defaults.ts +28 -0
- package/src/domains/context/working-set/engine.ts +203 -0
- package/src/domains/context/working-set/fold.ts +62 -0
- package/src/domains/context/working-set/horizon.ts +38 -0
- package/src/domains/context/working-set/marker.ts +103 -0
- package/src/domains/context/working-set/path-index.ts +436 -0
- package/src/domains/context/working-set/payload.ts +152 -0
- package/src/domains/context/working-set/policies/age-horizon.ts +55 -0
- package/src/domains/context/working-set/policies/index.ts +20 -0
- package/src/domains/context/working-set/policies/structural.ts +160 -0
- package/src/domains/context/working-set/project.ts +132 -0
- package/src/domains/context/working-set/protect.ts +109 -0
- package/src/domains/context/working-set/recall.ts +177 -0
- package/src/domains/context/working-set/replay/controls.ts +112 -0
- package/src/domains/context/working-set/replay/load-clio.ts +199 -0
- package/src/domains/context/working-set/replay/metrics.ts +185 -0
- package/src/domains/context/working-set/replay/reference-graph.ts +79 -0
- package/src/domains/context/working-set/replay/report.ts +139 -0
- package/src/domains/context/working-set/replay/runner.ts +325 -0
- package/src/domains/context/working-set/replay/synthetic.ts +422 -0
- package/src/domains/context/working-set/replay/trace.ts +21 -0
- package/src/domains/context/working-set/visible.ts +54 -0
- package/src/domains/dispatch/budget-envelope.ts +396 -0
- package/src/domains/dispatch/contract.ts +2 -0
- package/src/domains/dispatch/extension.ts +81 -27
- package/src/domains/dispatch/orphan-recovery.ts +1 -0
- package/src/domains/dispatch/receipt-integrity.ts +4 -0
- package/src/domains/dispatch/state.ts +1 -0
- package/src/domains/dispatch/types.ts +10 -3
- package/src/domains/dispatch/validation.ts +14 -0
- package/src/domains/dispatch/worker-spawn.ts +14 -3
- package/src/domains/eval/metrics/evidence.ts +0 -116
- package/src/domains/eval/metrics/invariants.ts +1 -1
- package/src/domains/eval/runners/clio-run.ts +1 -10
- package/src/domains/eval/runners/external-command.ts +2 -29
- package/src/domains/eval/schema/suite.ts +0 -7
- package/src/domains/eval/suites/run.ts +1 -7
- package/src/domains/evidence/build.ts +112 -45
- package/src/domains/evidence/eval.ts +24 -7
- package/src/domains/evidence/index.ts +53 -0
- package/src/domains/evidence/ordering.ts +12 -0
- package/src/domains/evidence/run-trust.ts +221 -0
- package/src/domains/evidence/store.ts +46 -6
- package/src/domains/evidence/trust-status.ts +854 -0
- package/src/domains/evidence/types.ts +26 -0
- package/src/domains/memory/index.ts +22 -0
- package/src/domains/memory/operations.ts +58 -1
- package/src/domains/memory/promotion.ts +281 -0
- package/src/domains/memory/prompt-section.ts +25 -5
- package/src/domains/memory/proposal.ts +51 -7
- package/src/domains/memory/task-bank.ts +3 -2
- package/src/domains/memory/task-memory-handoff.ts +181 -24
- package/src/domains/memory/task-memory-policy.ts +3 -1
- package/src/domains/memory/types.ts +37 -0
- package/src/domains/memory/validate.ts +178 -0
- package/src/domains/middleware/memory-intervention.ts +38 -25
- package/src/domains/middleware/runtime.ts +6 -0
- package/src/domains/middleware/skills-reminder.ts +19 -4
- package/src/domains/middleware/stalled-turn.ts +208 -5
- package/src/domains/middleware/types.ts +10 -0
- package/src/domains/observability/contract.ts +6 -1
- package/src/domains/observability/cost.ts +20 -4
- package/src/domains/observability/extension.ts +2 -2
- package/src/domains/providers/index.ts +3 -0
- package/src/domains/providers/model-discovery.ts +9 -0
- package/src/domains/providers/runtime-resolution.ts +38 -1
- package/src/domains/providers/runtimes/common/probe-helpers.ts +97 -16
- package/src/domains/providers/types/context-window-slots.ts +18 -0
- package/src/domains/providers/types/runtime-descriptor.ts +3 -1
- package/src/domains/safety/autonomy.ts +1 -1
- package/src/domains/safety/call-target.ts +211 -14
- package/src/domains/safety/decision-presentation.ts +268 -0
- package/src/domains/safety/default-path-policy.ts +8 -0
- package/src/domains/safety/finish-contract.ts +4 -3
- package/src/domains/safety/policy-engine.ts +48 -6
- package/src/domains/safety/redaction.ts +73 -0
- package/src/domains/session/compaction/compact.ts +23 -1
- package/src/domains/session/compaction/cut-point.ts +2 -0
- package/src/domains/session/compaction/tokens.ts +16 -1
- package/src/domains/session/context-ledger.ts +12 -1
- package/src/domains/session/decision-board.ts +4 -0
- package/src/domains/session/entries.ts +110 -1
- package/src/domains/session/history.ts +68 -19
- package/src/domains/session/manager.ts +9 -2
- package/src/domains/session/migrations/index.ts +22 -3
- package/src/domains/session/usage.ts +24 -7
- package/src/engine/acp/event-mapper.ts +7 -0
- package/src/engine/acp/server.ts +32 -2
- package/src/engine/agent.ts +18 -1
- package/src/engine/apis/lmstudio.ts +25 -4
- package/src/engine/apis/openai-completions.ts +147 -22
- package/src/engine/claude/sdk-runtime.ts +8 -2
- package/src/engine/claude/tool-safety.ts +13 -0
- package/src/engine/loop-guard.ts +27 -3
- package/src/engine/session.ts +9 -3
- package/src/engine/worker-events.ts +4 -3
- package/src/engine/worker-runtime.ts +59 -54
- package/src/entry/orchestrator.ts +34 -5
- package/src/interactive/chat-loop-messages.ts +40 -6
- package/src/interactive/chat-loop.ts +13 -0
- package/src/interactive/chat-panel.ts +17 -1
- package/src/interactive/chat-renderer.ts +49 -24
- package/src/interactive/clio-editor.ts +44 -7
- package/src/interactive/context-meter.ts +10 -0
- package/src/interactive/context-overlay.ts +120 -7
- package/src/interactive/context-recall-command.ts +110 -0
- package/src/interactive/cost-overlay.ts +39 -8
- package/src/interactive/dispatch-board.ts +212 -35
- package/src/interactive/footer/widgets.ts +13 -0
- package/src/interactive/interactive-application.ts +6 -1
- package/src/interactive/interactive-input-runtime.ts +11 -1
- package/src/interactive/interactive-presentation.ts +11 -1
- package/src/interactive/interactive-slash-runtime.ts +37 -1
- package/src/interactive/memory-overlay.ts +89 -4
- package/src/interactive/model-session-replay.ts +21 -0
- package/src/interactive/overlay-ask-user-lifecycle.ts +1 -1
- package/src/interactive/overlay-frame.ts +5 -2
- package/src/interactive/overlay-general-openers.ts +46 -1
- package/src/interactive/overlay-key-routing.ts +41 -1
- package/src/interactive/overlay-lifecycle.ts +11 -4
- package/src/interactive/overlay-permission-lifecycle.ts +23 -8
- package/src/interactive/overlay-session-lifecycle.ts +8 -4
- package/src/interactive/overlay-transitions.ts +11 -0
- package/src/interactive/overlays/ask-user.ts +74 -30
- package/src/interactive/overlays/decisions.ts +3 -1
- package/src/interactive/permission-hint.ts +35 -0
- package/src/interactive/permission-overlay.ts +95 -45
- package/src/interactive/renderers/tool-execution.ts +37 -51
- package/src/interactive/session-last-turn.ts +8 -1
- package/src/interactive/session-transcript.ts +2 -2
- package/src/interactive/session-usage-reseed.ts +36 -10
- package/src/interactive/slash-commands.ts +31 -4
- package/src/interactive/status/summary.ts +5 -0
- package/src/interactive/status/types.ts +5 -0
- package/src/interactive/terminal-lease.ts +1 -0
- package/src/interactive/turn-context.ts +333 -110
- package/src/interactive/turn-middleware.ts +7 -6
- package/src/interactive/turn-runtime.ts +37 -8
- package/src/interactive/turn-state.ts +3 -0
- package/src/interactive/worker-progress.ts +440 -0
- package/src/interactive/worker-stream.ts +51 -110
- package/src/tools/agent-tools.ts +39 -7
- package/src/tools/ask-user.ts +21 -1
- package/src/tools/bash.ts +144 -82
- package/src/tools/builtin-tool-catalog.ts +11 -5
- package/src/tools/context/index.ts +107 -5
- package/src/tools/context/surface.ts +3 -2
- package/src/tools/core-bootstrap.ts +21 -0
- package/src/tools/dispatch-arguments.ts +8 -0
- package/src/tools/dispatch-event-text.ts +19 -0
- package/src/tools/dispatch-runner.ts +9 -7
- package/src/tools/dispatch.ts +24 -1
- package/src/tools/monitor.ts +43 -20
- package/src/tools/registry.ts +72 -10
- package/src/tools/result-disposition.ts +706 -0
- package/src/tools/result-shaping.ts +321 -20
- package/src/tools/safe-exec.ts +2 -0
- package/src/tools/verify/authoring.ts +1120 -0
- package/src/tools/verify/catalog.ts +346 -0
- package/src/tools/verify/index.ts +13 -3
- package/src/tools/verify/scripts.ts +135 -37
- package/src/tools/verify/surface.ts +9 -5
- package/src/tools/worker-evidence.ts +54 -12
- package/src/worker/spec-contract.ts +43 -3
- package/dist/chunk-J7CWMCQD.js +0 -255
- package/dist/chunk-T6YILFSB.js +0 -80
- package/dist/chunk-VAKQQHWR.js +0 -434
- package/dist/chunk-VPAYEGVX.js +0 -184
- package/dist/chunk-XBXAASKX.js +0 -18
- package/dist/memory-WFZMGYHX.js +0 -236
- package/src/domains/eval/metrics/chaos-stream.ts +0 -93
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { createRequire as __clioCreateRequire } from "node:module"; const require = __clioCreateRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
|
-
DEFAULT_AUTONOMY_LEVEL,
|
|
4
|
-
autonomyAskRejection,
|
|
5
|
-
autonomyDenyRejection,
|
|
6
|
-
isAutonomyLevel,
|
|
7
|
-
mapAutonomy,
|
|
8
3
|
typedValidationSummary
|
|
9
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-EKY57CSP.js";
|
|
10
5
|
import {
|
|
11
6
|
ROUTE_POLICY_VERSION,
|
|
12
7
|
deriveExecutionRole,
|
|
@@ -15,36 +10,47 @@ import {
|
|
|
15
10
|
isRoutingIntent,
|
|
16
11
|
routePriorForLatencyClass,
|
|
17
12
|
sameRouteIdentity
|
|
18
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-22NAGB7X.js";
|
|
19
14
|
import {
|
|
20
15
|
AGENT_AUTOMATION_AUTHORITIES,
|
|
21
|
-
agentSpecFingerprint
|
|
16
|
+
agentSpecFingerprint
|
|
17
|
+
} from "./chunk-AOCYTWAV.js";
|
|
18
|
+
import {
|
|
22
19
|
detectValidationCommand,
|
|
23
20
|
extractCommandDeleteTargets,
|
|
24
21
|
extractCommandWriteTargets,
|
|
25
22
|
tokenizeShellLike,
|
|
26
23
|
toolMutationPaths
|
|
27
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-MV3K5QF2.js";
|
|
28
25
|
import {
|
|
26
|
+
expandPath,
|
|
29
27
|
resolveReadPath
|
|
30
28
|
} from "./chunk-OQE5J4C6.js";
|
|
31
29
|
import {
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
DEFAULT_AUTONOMY_LEVEL,
|
|
31
|
+
autonomyAskRejection,
|
|
32
|
+
autonomyDenyRejection,
|
|
33
|
+
isAutonomyLevel,
|
|
34
|
+
mapAutonomy
|
|
35
|
+
} from "./chunk-HWUFFB6L.js";
|
|
34
36
|
import {
|
|
35
37
|
DEFAULT_MAX_LINES,
|
|
36
38
|
OBSERVATION_POLICY_SLACK_BYTES,
|
|
37
39
|
OBSERVE_SELF_CAPS,
|
|
40
|
+
deterministicDiagnosticSummary,
|
|
38
41
|
finalizeObservation,
|
|
39
|
-
formatSize,
|
|
40
42
|
isSessionOffloadPath,
|
|
41
43
|
observationBudgetExhausted,
|
|
42
44
|
reserveObservation,
|
|
43
45
|
splitLinesForCounting,
|
|
44
46
|
truncateHead,
|
|
45
47
|
truncateTail
|
|
46
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-ODFEOB4F.js";
|
|
49
|
+
import {
|
|
50
|
+
formatSize
|
|
51
|
+
} from "./chunk-OZNBF4L3.js";
|
|
47
52
|
import {
|
|
53
|
+
byteLength,
|
|
48
54
|
truncateUtf8
|
|
49
55
|
} from "./chunk-6XLNIQDB.js";
|
|
50
56
|
import {
|
|
@@ -56,12 +62,24 @@ import {
|
|
|
56
62
|
} from "./chunk-CGKSTWHD.js";
|
|
57
63
|
import {
|
|
58
64
|
THINKING_LEVELS
|
|
59
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-4OC57DA6.js";
|
|
66
|
+
import {
|
|
67
|
+
gitCommitAttributionEnabled,
|
|
68
|
+
reportCommitAttributionDiagnostic,
|
|
69
|
+
resolveSafeCwd,
|
|
70
|
+
withManagedGitCommitAttributionEnvironment
|
|
71
|
+
} from "./chunk-VEZEGCGW.js";
|
|
72
|
+
import {
|
|
73
|
+
clampTimerDelayMs
|
|
74
|
+
} from "./chunk-FQ4SKYE4.js";
|
|
60
75
|
import {
|
|
61
76
|
GUARDRAIL_DEFAULTS,
|
|
62
77
|
GUARDRAIL_ENV_VARS,
|
|
63
78
|
resolveGuardrail
|
|
64
79
|
} from "./chunk-4ZG3XFUR.js";
|
|
80
|
+
import {
|
|
81
|
+
AI_AGENT_NAME
|
|
82
|
+
} from "./chunk-6EJMN2Y3.js";
|
|
65
83
|
import {
|
|
66
84
|
init_esm_shims
|
|
67
85
|
} from "./chunk-3R73A4XB.js";
|
|
@@ -137,6 +155,255 @@ function applyCodewikiWorkerPolicy(tools, context) {
|
|
|
137
155
|
return tools.filter((tool) => !isCodewikiTool(tool));
|
|
138
156
|
}
|
|
139
157
|
|
|
158
|
+
// src/core/bash-exec.ts
|
|
159
|
+
init_esm_shims();
|
|
160
|
+
import { spawn } from "node:child_process";
|
|
161
|
+
import { StringDecoder } from "node:string_decoder";
|
|
162
|
+
var BASH_HARD_CAP_BYTES = 16 * 1024 * 1024;
|
|
163
|
+
var CLIO_CONTROL_ENV_KEYS = ["CLIO_CODER_INTERACTIVE", "CLIO_CODER_RESUME_SESSION_ID"];
|
|
164
|
+
var BASH_UPDATE_THROTTLE_MS = 100;
|
|
165
|
+
function buildToolEnv() {
|
|
166
|
+
const env = { ...process.env };
|
|
167
|
+
env.AI_AGENT = AI_AGENT_NAME;
|
|
168
|
+
for (const key of CLIO_CONTROL_ENV_KEYS) {
|
|
169
|
+
Reflect.deleteProperty(env, key);
|
|
170
|
+
}
|
|
171
|
+
return env;
|
|
172
|
+
}
|
|
173
|
+
var LOGIN_ENV_CAPTURE_TIMEOUT_MS = 1e4;
|
|
174
|
+
var loginEnvCapture = null;
|
|
175
|
+
function parseNullDelimitedEnv(raw) {
|
|
176
|
+
const env = {};
|
|
177
|
+
for (const entry of raw.split("\0")) {
|
|
178
|
+
if (entry.length === 0) continue;
|
|
179
|
+
const eq = entry.indexOf("=");
|
|
180
|
+
if (eq <= 0) continue;
|
|
181
|
+
env[entry.slice(0, eq)] = entry.slice(eq + 1);
|
|
182
|
+
}
|
|
183
|
+
return typeof env.PATH === "string" && env.PATH.length > 0 ? env : null;
|
|
184
|
+
}
|
|
185
|
+
function captureLoginEnv() {
|
|
186
|
+
return new Promise((resolve) => {
|
|
187
|
+
let stdout = "";
|
|
188
|
+
let settled = false;
|
|
189
|
+
const finish = (value) => {
|
|
190
|
+
if (settled) return;
|
|
191
|
+
settled = true;
|
|
192
|
+
clearTimeout(timer);
|
|
193
|
+
resolve(value);
|
|
194
|
+
};
|
|
195
|
+
const child = spawn("/bin/bash", ["-lc", "env -0"], {
|
|
196
|
+
env: buildToolEnv(),
|
|
197
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
198
|
+
});
|
|
199
|
+
const timer = setTimeout(() => {
|
|
200
|
+
child.kill("SIGKILL");
|
|
201
|
+
finish(null);
|
|
202
|
+
}, LOGIN_ENV_CAPTURE_TIMEOUT_MS);
|
|
203
|
+
child.stdout?.on("data", (chunk) => {
|
|
204
|
+
stdout += chunk.toString("utf8");
|
|
205
|
+
});
|
|
206
|
+
child.on("error", () => finish(null));
|
|
207
|
+
child.on("close", (code) => finish(code === 0 ? parseNullDelimitedEnv(stdout) : null));
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
async function bashSpawnPlan() {
|
|
211
|
+
loginEnvCapture ??= captureLoginEnv();
|
|
212
|
+
const captured = await loginEnvCapture;
|
|
213
|
+
if (captured === null) return { mode: "-lc", env: buildToolEnv() };
|
|
214
|
+
const env = { ...process.env, ...captured };
|
|
215
|
+
env.AI_AGENT = AI_AGENT_NAME;
|
|
216
|
+
for (const key of CLIO_CONTROL_ENV_KEYS) {
|
|
217
|
+
Reflect.deleteProperty(env, key);
|
|
218
|
+
}
|
|
219
|
+
return { mode: "-c", env };
|
|
220
|
+
}
|
|
221
|
+
function combineBashOutput(result) {
|
|
222
|
+
const { stdout, stderr } = result;
|
|
223
|
+
return stderr.length > 0 ? `${stdout}${stdout.endsWith("\n") || stdout.length === 0 ? "" : "\n"}${stderr}` : stdout;
|
|
224
|
+
}
|
|
225
|
+
async function runBashCommand(command, options = {}) {
|
|
226
|
+
const plan = await bashSpawnPlan();
|
|
227
|
+
const attribution = withManagedGitCommitAttributionEnvironment(plan.env, {
|
|
228
|
+
cwd: options.cwd ?? process.cwd(),
|
|
229
|
+
enabled: gitCommitAttributionEnabled(process.env)
|
|
230
|
+
});
|
|
231
|
+
reportCommitAttributionDiagnostic(attribution.diagnostic);
|
|
232
|
+
return new Promise((resolve) => {
|
|
233
|
+
const timeout = clampTimerDelayMs(options.timeoutMs ?? 3e5);
|
|
234
|
+
let aborted = false;
|
|
235
|
+
let timedOut = false;
|
|
236
|
+
let settled = false;
|
|
237
|
+
let timeoutId = null;
|
|
238
|
+
let killGraceTimer = null;
|
|
239
|
+
let killSent = false;
|
|
240
|
+
let stdout = "";
|
|
241
|
+
let stderr = "";
|
|
242
|
+
const stdoutDecoder = new StringDecoder("utf8");
|
|
243
|
+
const stderrDecoder = new StringDecoder("utf8");
|
|
244
|
+
let decodersFinished = false;
|
|
245
|
+
let outputBytes = 0;
|
|
246
|
+
let outputCapped = false;
|
|
247
|
+
let updateTimer = null;
|
|
248
|
+
let updateDirty = false;
|
|
249
|
+
let lastUpdateAt = 0;
|
|
250
|
+
const child = spawn("/bin/bash", [plan.mode, command], {
|
|
251
|
+
...options.cwd === void 0 ? {} : { cwd: options.cwd },
|
|
252
|
+
env: attribution.env,
|
|
253
|
+
detached: process.platform !== "win32",
|
|
254
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
255
|
+
});
|
|
256
|
+
const finishDecoders = () => {
|
|
257
|
+
if (decodersFinished) return;
|
|
258
|
+
decodersFinished = true;
|
|
259
|
+
if (outputCapped) return;
|
|
260
|
+
stdout += stdoutDecoder.end();
|
|
261
|
+
stderr += stderrDecoder.end();
|
|
262
|
+
};
|
|
263
|
+
const emitUpdate = () => {
|
|
264
|
+
if (options.onUpdate === void 0 || !updateDirty) return;
|
|
265
|
+
updateDirty = false;
|
|
266
|
+
lastUpdateAt = Date.now();
|
|
267
|
+
try {
|
|
268
|
+
options.onUpdate({ stdout, stderr, outputBytes: Math.min(outputBytes, BASH_HARD_CAP_BYTES) });
|
|
269
|
+
} catch {
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
const clearUpdateTimer = () => {
|
|
273
|
+
if (updateTimer === null) return;
|
|
274
|
+
clearTimeout(updateTimer);
|
|
275
|
+
updateTimer = null;
|
|
276
|
+
};
|
|
277
|
+
const scheduleUpdate = () => {
|
|
278
|
+
if (options.onUpdate === void 0) return;
|
|
279
|
+
updateDirty = true;
|
|
280
|
+
const delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);
|
|
281
|
+
if (delay <= 0) {
|
|
282
|
+
clearUpdateTimer();
|
|
283
|
+
emitUpdate();
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
updateTimer ??= setTimeout(() => {
|
|
287
|
+
updateTimer = null;
|
|
288
|
+
emitUpdate();
|
|
289
|
+
}, delay);
|
|
290
|
+
};
|
|
291
|
+
const finishUpdates = () => {
|
|
292
|
+
clearUpdateTimer();
|
|
293
|
+
emitUpdate();
|
|
294
|
+
};
|
|
295
|
+
if (options.onUpdate !== void 0) {
|
|
296
|
+
updateDirty = true;
|
|
297
|
+
emitUpdate();
|
|
298
|
+
}
|
|
299
|
+
const clearKillGraceTimer = () => {
|
|
300
|
+
if (!killGraceTimer) return;
|
|
301
|
+
clearTimeout(killGraceTimer);
|
|
302
|
+
killGraceTimer = null;
|
|
303
|
+
};
|
|
304
|
+
const sendSignal = (signalName) => {
|
|
305
|
+
const pid = child.pid;
|
|
306
|
+
if (pid && process.platform !== "win32") {
|
|
307
|
+
try {
|
|
308
|
+
process.kill(-pid, signalName);
|
|
309
|
+
return;
|
|
310
|
+
} catch {
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
child.kill(signalName);
|
|
314
|
+
};
|
|
315
|
+
const killChild = () => {
|
|
316
|
+
if (killSent) return;
|
|
317
|
+
killSent = true;
|
|
318
|
+
sendSignal("SIGTERM");
|
|
319
|
+
killGraceTimer = setTimeout(() => {
|
|
320
|
+
sendSignal("SIGKILL");
|
|
321
|
+
}, 5e3);
|
|
322
|
+
};
|
|
323
|
+
function onAbort() {
|
|
324
|
+
aborted = true;
|
|
325
|
+
killChild();
|
|
326
|
+
}
|
|
327
|
+
if (timeout > 0) {
|
|
328
|
+
timeoutId = setTimeout(() => {
|
|
329
|
+
timedOut = true;
|
|
330
|
+
killChild();
|
|
331
|
+
}, timeout);
|
|
332
|
+
}
|
|
333
|
+
if (options.signal?.aborted) {
|
|
334
|
+
onAbort();
|
|
335
|
+
} else {
|
|
336
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
337
|
+
}
|
|
338
|
+
const appendChunk = (target, chunk) => {
|
|
339
|
+
if (outputCapped) return;
|
|
340
|
+
const remaining = BASH_HARD_CAP_BYTES - outputBytes;
|
|
341
|
+
const accepted = chunk.byteLength <= remaining ? chunk : chunk.subarray(0, Math.max(0, remaining));
|
|
342
|
+
outputBytes += accepted.byteLength;
|
|
343
|
+
if (accepted.byteLength > 0) {
|
|
344
|
+
const decoded = target === "stdout" ? stdoutDecoder.write(accepted) : stderrDecoder.write(accepted);
|
|
345
|
+
if (target === "stdout") stdout += decoded;
|
|
346
|
+
else stderr += decoded;
|
|
347
|
+
}
|
|
348
|
+
if (accepted.byteLength < chunk.byteLength) {
|
|
349
|
+
outputCapped = true;
|
|
350
|
+
scheduleUpdate();
|
|
351
|
+
killChild();
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
scheduleUpdate();
|
|
355
|
+
};
|
|
356
|
+
child.stdout?.on("data", (chunk) => appendChunk("stdout", chunk));
|
|
357
|
+
child.stderr?.on("data", (chunk) => appendChunk("stderr", chunk));
|
|
358
|
+
child.on("error", (error) => {
|
|
359
|
+
if (settled) return;
|
|
360
|
+
settled = true;
|
|
361
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
362
|
+
clearKillGraceTimer();
|
|
363
|
+
finishDecoders();
|
|
364
|
+
finishUpdates();
|
|
365
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
366
|
+
resolve({
|
|
367
|
+
error,
|
|
368
|
+
stdout,
|
|
369
|
+
stderr,
|
|
370
|
+
exitCode: null,
|
|
371
|
+
signal: null,
|
|
372
|
+
aborted,
|
|
373
|
+
timedOut,
|
|
374
|
+
outputCapped,
|
|
375
|
+
outputBytes
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
child.on("close", (code, signalName) => {
|
|
379
|
+
if (settled) return;
|
|
380
|
+
settled = true;
|
|
381
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
382
|
+
clearKillGraceTimer();
|
|
383
|
+
finishDecoders();
|
|
384
|
+
finishUpdates();
|
|
385
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
386
|
+
const error = code === 0 && signalName === null ? null : {
|
|
387
|
+
name: "Error",
|
|
388
|
+
message: signalName ? `command terminated by ${signalName}` : `command exited with code ${code ?? "?"}`,
|
|
389
|
+
code: code ?? void 0,
|
|
390
|
+
signal: signalName ?? void 0
|
|
391
|
+
};
|
|
392
|
+
resolve({
|
|
393
|
+
error,
|
|
394
|
+
stdout,
|
|
395
|
+
stderr,
|
|
396
|
+
exitCode: code,
|
|
397
|
+
signal: signalName,
|
|
398
|
+
aborted,
|
|
399
|
+
timedOut,
|
|
400
|
+
outputCapped,
|
|
401
|
+
outputBytes
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
|
|
140
407
|
// src/tools/network-policy.ts
|
|
141
408
|
init_esm_shims();
|
|
142
409
|
var NO_NETWORK_TOOLS_ENV = "CLIO_CODER_NO_NETWORK_TOOLS";
|
|
@@ -534,10 +801,13 @@ function validateAllowedTools(value) {
|
|
|
534
801
|
}
|
|
535
802
|
function validateWorkerBudget(value) {
|
|
536
803
|
const budget = readRecord(value, "WorkerSpec.budget");
|
|
537
|
-
const expected = ["hardCap", "readReserve", "synthesis", "toolCalls"];
|
|
804
|
+
const expected = ["hardCap", "readReserve", "revision", "synthesis", "toolCalls"];
|
|
538
805
|
const actual = Object.keys(budget).sort();
|
|
539
|
-
if (actual.
|
|
540
|
-
throw new Error(`WorkerSpec.budget
|
|
806
|
+
if (actual.some((key) => !expected.includes(key)) || actual.some((key) => key === "revision" && budget.revision === void 0)) {
|
|
807
|
+
throw new Error(`WorkerSpec.budget may contain only: ${expected.join(", ")}`);
|
|
808
|
+
}
|
|
809
|
+
for (const required of ["hardCap", "readReserve", "synthesis", "toolCalls"]) {
|
|
810
|
+
if (!Object.hasOwn(budget, required)) throw new Error(`WorkerSpec.budget.${required} is required`);
|
|
541
811
|
}
|
|
542
812
|
for (const key of ["toolCalls", "readReserve", "hardCap"]) {
|
|
543
813
|
const value2 = budget[key];
|
|
@@ -554,6 +824,30 @@ function validateWorkerBudget(value) {
|
|
|
554
824
|
throw new Error("WorkerSpec.budget.readReserve must be an integer in [0, toolCalls)");
|
|
555
825
|
}
|
|
556
826
|
if (typeof budget.synthesis !== "boolean") throw new Error("WorkerSpec.budget.synthesis must be a boolean");
|
|
827
|
+
if (budget.revision !== void 0) {
|
|
828
|
+
const revision = readRecord(budget.revision, "WorkerSpec.budget.revision");
|
|
829
|
+
const revisionKeys = Object.keys(revision).sort();
|
|
830
|
+
if (revisionKeys.length !== 2 || revisionKeys[0] !== "readReserve" || revisionKeys[1] !== "toolCalls") {
|
|
831
|
+
throw new Error("WorkerSpec.budget.revision must contain exactly: readReserve, toolCalls");
|
|
832
|
+
}
|
|
833
|
+
for (const key of ["toolCalls", "readReserve"]) {
|
|
834
|
+
if (typeof revision[key] !== "number" || !Number.isSafeInteger(revision[key])) {
|
|
835
|
+
throw new Error(`WorkerSpec.budget.revision.${key} must be a safe integer`);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
if (revision.toolCalls < budget.toolCalls) {
|
|
839
|
+
throw new Error("WorkerSpec.budget.revision.toolCalls must not be smaller than WorkerSpec.budget.toolCalls");
|
|
840
|
+
}
|
|
841
|
+
if (revision.toolCalls === budget.toolCalls && revision.readReserve <= budget.readReserve) {
|
|
842
|
+
throw new Error("WorkerSpec.budget.revision must increase toolCalls or readReserve");
|
|
843
|
+
}
|
|
844
|
+
if (revision.toolCalls > budget.hardCap) {
|
|
845
|
+
throw new Error("WorkerSpec.budget.revision.toolCalls must not exceed WorkerSpec.budget.hardCap");
|
|
846
|
+
}
|
|
847
|
+
if (revision.readReserve < 0 || revision.readReserve >= revision.toolCalls) {
|
|
848
|
+
throw new Error("WorkerSpec.budget.revision.readReserve must be an integer in [0, toolCalls)");
|
|
849
|
+
}
|
|
850
|
+
}
|
|
557
851
|
}
|
|
558
852
|
function validateRuntimeCapabilityDecision(value, source) {
|
|
559
853
|
const caps = readRecord(value, source);
|
|
@@ -777,6 +1071,293 @@ function validateRehydratedWorkerRuntime(spec, runtime) {
|
|
|
777
1071
|
}
|
|
778
1072
|
}
|
|
779
1073
|
|
|
1074
|
+
// src/domains/dispatch/budget-envelope.ts
|
|
1075
|
+
init_esm_shims();
|
|
1076
|
+
var BudgetAdmissionError = class extends Error {
|
|
1077
|
+
code;
|
|
1078
|
+
constructor(code, message) {
|
|
1079
|
+
super(`dispatch: budget admission denied (${code}): ${message}`);
|
|
1080
|
+
this.name = "BudgetAdmissionError";
|
|
1081
|
+
this.code = code;
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1084
|
+
function isRecord(value) {
|
|
1085
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1086
|
+
}
|
|
1087
|
+
function clonePhase(value, prefix) {
|
|
1088
|
+
if (!isRecord(value)) throw new Error(`${prefix} must be an object`);
|
|
1089
|
+
for (const key of Object.keys(value)) {
|
|
1090
|
+
if (key !== "toolCalls" && key !== "readReserve") throw new Error(`${prefix}.${key} is unknown`);
|
|
1091
|
+
}
|
|
1092
|
+
for (const key of ["toolCalls", "readReserve"]) {
|
|
1093
|
+
if (!Object.hasOwn(value, key)) throw new Error(`${prefix}.${key} is required`);
|
|
1094
|
+
}
|
|
1095
|
+
const toolCalls = value.toolCalls;
|
|
1096
|
+
if (typeof toolCalls !== "number" || !Number.isSafeInteger(toolCalls) || toolCalls <= 0) {
|
|
1097
|
+
throw new Error(`${prefix}.toolCalls must be a positive safe integer`);
|
|
1098
|
+
}
|
|
1099
|
+
const readReserve = value.readReserve;
|
|
1100
|
+
if (typeof readReserve !== "number" || !Number.isSafeInteger(readReserve) || readReserve < 0) {
|
|
1101
|
+
throw new Error(`${prefix}.readReserve must be a non-negative safe integer`);
|
|
1102
|
+
}
|
|
1103
|
+
if (readReserve >= toolCalls) throw new Error(`${prefix}.readReserve must be less than ${prefix}.toolCalls`);
|
|
1104
|
+
return { toolCalls, readReserve };
|
|
1105
|
+
}
|
|
1106
|
+
function cloneDispatchBudgetRequest(value, prefix = "budget") {
|
|
1107
|
+
if (!isRecord(value)) throw new Error(`${prefix} must be an object`);
|
|
1108
|
+
for (const key of Object.keys(value)) {
|
|
1109
|
+
if (key !== "toolCalls" && key !== "readReserve" && key !== "retryRevision") {
|
|
1110
|
+
throw new Error(`${prefix}.${key} is unknown`);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
const phase = clonePhase({ toolCalls: value.toolCalls, readReserve: value.readReserve }, prefix);
|
|
1114
|
+
const retryRevision = value.retryRevision === void 0 ? void 0 : clonePhase(value.retryRevision, `${prefix}.retryRevision`);
|
|
1115
|
+
return { ...phase, ...retryRevision === void 0 ? {} : { retryRevision } };
|
|
1116
|
+
}
|
|
1117
|
+
function freezeEnvelope(envelope) {
|
|
1118
|
+
Object.freeze(envelope.policy.default);
|
|
1119
|
+
Object.freeze(envelope.policy.maximum);
|
|
1120
|
+
Object.freeze(envelope.policy);
|
|
1121
|
+
if (envelope.request !== null) {
|
|
1122
|
+
if (envelope.request.retryRevision !== void 0) Object.freeze(envelope.request.retryRevision);
|
|
1123
|
+
Object.freeze(envelope.request);
|
|
1124
|
+
}
|
|
1125
|
+
Object.freeze(envelope.effective);
|
|
1126
|
+
for (const reason of envelope.reasons) Object.freeze(reason);
|
|
1127
|
+
Object.freeze(envelope.reasons);
|
|
1128
|
+
return Object.freeze(envelope);
|
|
1129
|
+
}
|
|
1130
|
+
function phaseWithin(candidate, maximum) {
|
|
1131
|
+
return candidate.toolCalls <= maximum.toolCalls && candidate.readReserve <= maximum.readReserve;
|
|
1132
|
+
}
|
|
1133
|
+
function samePhase(left, right) {
|
|
1134
|
+
return left.toolCalls === right.toolCalls && left.readReserve === right.readReserve;
|
|
1135
|
+
}
|
|
1136
|
+
function assertRequestAdmitted(input) {
|
|
1137
|
+
const { request, policy, hardCap } = input;
|
|
1138
|
+
const authoredMaximum = policy.maximum ?? policy;
|
|
1139
|
+
if (policy.maximum === void 0 && !samePhase(request, policy)) {
|
|
1140
|
+
throw new BudgetAdmissionError(
|
|
1141
|
+
"exact-recipe-policy",
|
|
1142
|
+
`the recipe pins ${policy.toolCalls} tool calls with a read reserve of ${policy.readReserve}`
|
|
1143
|
+
);
|
|
1144
|
+
}
|
|
1145
|
+
if (!phaseWithin(request, authoredMaximum)) {
|
|
1146
|
+
throw new BudgetAdmissionError(
|
|
1147
|
+
"recipe-maximum",
|
|
1148
|
+
`the requested phase ${request.toolCalls}/${request.readReserve} exceeds recipe maximum ${authoredMaximum.toolCalls}/${authoredMaximum.readReserve}`
|
|
1149
|
+
);
|
|
1150
|
+
}
|
|
1151
|
+
if (request.toolCalls > hardCap) {
|
|
1152
|
+
throw new BudgetAdmissionError(
|
|
1153
|
+
"global-cap",
|
|
1154
|
+
`the requested ${request.toolCalls} tool calls exceed the operator cap of ${hardCap}`
|
|
1155
|
+
);
|
|
1156
|
+
}
|
|
1157
|
+
const ceiling = request.retryRevision;
|
|
1158
|
+
if (ceiling === void 0) return;
|
|
1159
|
+
if (ceiling.toolCalls < request.toolCalls || ceiling.readReserve < request.readReserve) {
|
|
1160
|
+
throw new BudgetAdmissionError(
|
|
1161
|
+
"ceiling-below-request",
|
|
1162
|
+
`retryRevision ${ceiling.toolCalls}/${ceiling.readReserve} must not be smaller than the requested phase ${request.toolCalls}/${request.readReserve}`
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
if (policy.maximum === void 0 && !samePhase(ceiling, policy)) {
|
|
1166
|
+
throw new BudgetAdmissionError(
|
|
1167
|
+
"exact-recipe-policy",
|
|
1168
|
+
`the recipe pins ${policy.toolCalls} tool calls with a read reserve of ${policy.readReserve}`
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1171
|
+
if (!phaseWithin(ceiling, authoredMaximum)) {
|
|
1172
|
+
throw new BudgetAdmissionError(
|
|
1173
|
+
"recipe-maximum",
|
|
1174
|
+
`retryRevision ${ceiling.toolCalls}/${ceiling.readReserve} exceeds recipe maximum ${authoredMaximum.toolCalls}/${authoredMaximum.readReserve}`
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
if (ceiling.toolCalls > hardCap) {
|
|
1178
|
+
throw new BudgetAdmissionError(
|
|
1179
|
+
"global-cap",
|
|
1180
|
+
`retryRevision ${ceiling.toolCalls} exceeds the operator cap of ${hardCap}`
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
function resolveToolBudgetEnvelope(input) {
|
|
1185
|
+
if (!Number.isSafeInteger(input.hardCap) || input.hardCap <= 0) {
|
|
1186
|
+
throw new Error("dispatch: worker tool-call cap must be a positive safe integer");
|
|
1187
|
+
}
|
|
1188
|
+
if (input.request !== void 0)
|
|
1189
|
+
assertRequestAdmitted({ request: input.request, policy: input.policy, hardCap: input.hardCap });
|
|
1190
|
+
const request = input.request === void 0 ? null : cloneDispatchBudgetRequest(input.request);
|
|
1191
|
+
const base = request ?? input.policy;
|
|
1192
|
+
const reasons = [];
|
|
1193
|
+
let selected = base;
|
|
1194
|
+
const phaseKind = input.retry ? "retry" : input.revision ? "revision" : null;
|
|
1195
|
+
if (phaseKind !== null) {
|
|
1196
|
+
const ceiling = request?.retryRevision;
|
|
1197
|
+
if (ceiling !== void 0 && !samePhase(ceiling, base)) {
|
|
1198
|
+
selected = ceiling;
|
|
1199
|
+
reasons.push({
|
|
1200
|
+
code: phaseKind === "retry" ? "retry-growth-authorized" : "revision-growth-authorized",
|
|
1201
|
+
detail: `${phaseKind} phase grew from ${base.toolCalls}/${base.readReserve} to the preauthorized ceiling ${ceiling.toolCalls}/${ceiling.readReserve}`
|
|
1202
|
+
});
|
|
1203
|
+
} else {
|
|
1204
|
+
reasons.push({
|
|
1205
|
+
code: phaseKind === "retry" ? "retry-growth-denied" : "revision-growth-denied",
|
|
1206
|
+
detail: ceiling === void 0 ? `${phaseKind} phase retained ${base.toolCalls}/${base.readReserve} because the original request declared no ceiling` : `${phaseKind} phase retained ${base.toolCalls}/${base.readReserve} because the declared ceiling did not authorize growth`
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
const revisionCeiling = phaseKind === null ? request?.retryRevision : void 0;
|
|
1211
|
+
if (revisionCeiling !== void 0 && !samePhase(revisionCeiling, selected)) {
|
|
1212
|
+
reasons.push({
|
|
1213
|
+
code: "revision-growth-authorized",
|
|
1214
|
+
detail: `a result-contract revision may grow from ${selected.toolCalls}/${selected.readReserve} to the preauthorized ceiling ${revisionCeiling.toolCalls}/${revisionCeiling.readReserve}`
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
let toolCalls = selected.toolCalls;
|
|
1218
|
+
if (toolCalls > input.hardCap) {
|
|
1219
|
+
reasons.push({
|
|
1220
|
+
code: "global-cap-clamp",
|
|
1221
|
+
detail: `tool calls were clamped from ${toolCalls} to the operator cap of ${input.hardCap}`
|
|
1222
|
+
});
|
|
1223
|
+
toolCalls = input.hardCap;
|
|
1224
|
+
}
|
|
1225
|
+
let readReserve = selected.readReserve;
|
|
1226
|
+
if (!input.hasReadTool && readReserve > 0) {
|
|
1227
|
+
reasons.push({
|
|
1228
|
+
code: "read-reserve-unavailable-clamp",
|
|
1229
|
+
detail: `read reserve was clamped from ${readReserve} to 0 because the read tool is unavailable`
|
|
1230
|
+
});
|
|
1231
|
+
readReserve = 0;
|
|
1232
|
+
}
|
|
1233
|
+
const maximumEffectiveReserve = Math.max(0, toolCalls - 1);
|
|
1234
|
+
if (readReserve > maximumEffectiveReserve) {
|
|
1235
|
+
reasons.push({
|
|
1236
|
+
code: "read-reserve-cap-clamp",
|
|
1237
|
+
detail: `read reserve was clamped from ${readReserve} to ${maximumEffectiveReserve} after the tool-call cap`
|
|
1238
|
+
});
|
|
1239
|
+
readReserve = maximumEffectiveReserve;
|
|
1240
|
+
}
|
|
1241
|
+
let effectiveRevision;
|
|
1242
|
+
if (revisionCeiling !== void 0 && !samePhase(revisionCeiling, selected)) {
|
|
1243
|
+
let revisionReadReserve = revisionCeiling.readReserve;
|
|
1244
|
+
if (!input.hasReadTool && revisionReadReserve > 0) {
|
|
1245
|
+
reasons.push({
|
|
1246
|
+
code: "read-reserve-unavailable-clamp",
|
|
1247
|
+
detail: `result-contract revision read reserve was clamped from ${revisionReadReserve} to 0 because the read tool is unavailable`
|
|
1248
|
+
});
|
|
1249
|
+
revisionReadReserve = 0;
|
|
1250
|
+
}
|
|
1251
|
+
effectiveRevision = { toolCalls: revisionCeiling.toolCalls, readReserve: revisionReadReserve };
|
|
1252
|
+
}
|
|
1253
|
+
const authoredMaximum = input.policy.maximum ?? input.policy;
|
|
1254
|
+
return freezeEnvelope({
|
|
1255
|
+
version: 1,
|
|
1256
|
+
policy: {
|
|
1257
|
+
recipeId: input.recipeId,
|
|
1258
|
+
default: {
|
|
1259
|
+
toolCalls: input.policy.toolCalls,
|
|
1260
|
+
readReserve: input.policy.readReserve,
|
|
1261
|
+
synthesis: input.policy.synthesis
|
|
1262
|
+
},
|
|
1263
|
+
maximum: { toolCalls: authoredMaximum.toolCalls, readReserve: authoredMaximum.readReserve },
|
|
1264
|
+
exact: input.policy.maximum === void 0
|
|
1265
|
+
},
|
|
1266
|
+
request,
|
|
1267
|
+
effective: {
|
|
1268
|
+
toolCalls,
|
|
1269
|
+
readReserve,
|
|
1270
|
+
synthesis: input.policy.synthesis,
|
|
1271
|
+
hardCap: input.hardCap,
|
|
1272
|
+
...effectiveRevision === void 0 ? {} : { revision: effectiveRevision }
|
|
1273
|
+
},
|
|
1274
|
+
reasons
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
function formatBudgetPolicy(envelope) {
|
|
1278
|
+
const policy = envelope.policy;
|
|
1279
|
+
const range = policy.exact ? `exact ${policy.default.toolCalls}/${policy.default.readReserve}` : `default ${policy.default.toolCalls}/${policy.default.readReserve}, max ${policy.maximum.toolCalls}/${policy.maximum.readReserve}`;
|
|
1280
|
+
return `${policy.recipeId} ${range}, synthesis=${policy.default.synthesis ? "on" : "off"}`;
|
|
1281
|
+
}
|
|
1282
|
+
function formatBudgetRequest(envelope) {
|
|
1283
|
+
const request = envelope.request;
|
|
1284
|
+
if (request === null) return "recipe default";
|
|
1285
|
+
const ceiling = request.retryRevision;
|
|
1286
|
+
return ceiling === void 0 ? `${request.toolCalls}/${request.readReserve}, no retry/revision growth` : `${request.toolCalls}/${request.readReserve}, retry/revision ceiling ${ceiling.toolCalls}/${ceiling.readReserve}`;
|
|
1287
|
+
}
|
|
1288
|
+
function formatEffectiveBudget(envelope) {
|
|
1289
|
+
const budget = envelope.effective;
|
|
1290
|
+
const revision = budget.revision ? `, result revision ${budget.revision.toolCalls}/${budget.revision.readReserve}` : "";
|
|
1291
|
+
return `${budget.toolCalls}/${budget.readReserve}${revision}, lifetime cap ${budget.hardCap}, synthesis=${budget.synthesis ? "on" : "off"}`;
|
|
1292
|
+
}
|
|
1293
|
+
function formatBudgetReasons(envelope) {
|
|
1294
|
+
return envelope.reasons.length === 0 ? "none" : envelope.reasons.map((reason) => reason.code).join(",");
|
|
1295
|
+
}
|
|
1296
|
+
var BUDGET_REASON_CODES = /* @__PURE__ */ new Set([
|
|
1297
|
+
"global-cap-clamp",
|
|
1298
|
+
"read-reserve-unavailable-clamp",
|
|
1299
|
+
"read-reserve-cap-clamp",
|
|
1300
|
+
"retry-growth-authorized",
|
|
1301
|
+
"retry-growth-denied",
|
|
1302
|
+
"revision-growth-authorized",
|
|
1303
|
+
"revision-growth-denied"
|
|
1304
|
+
]);
|
|
1305
|
+
function cloneRunToolBudgetEnvelope(value) {
|
|
1306
|
+
try {
|
|
1307
|
+
if (!isRecord(value) || value.version !== 1 || !isRecord(value.policy) || !isRecord(value.effective)) {
|
|
1308
|
+
return void 0;
|
|
1309
|
+
}
|
|
1310
|
+
const recipeId = value.policy.recipeId;
|
|
1311
|
+
if (typeof recipeId !== "string" || recipeId.length === 0 || typeof value.policy.exact !== "boolean") {
|
|
1312
|
+
return void 0;
|
|
1313
|
+
}
|
|
1314
|
+
if (!isRecord(value.policy.default) || typeof value.policy.default.synthesis !== "boolean") return void 0;
|
|
1315
|
+
const defaultPhase = clonePhase(
|
|
1316
|
+
{ toolCalls: value.policy.default.toolCalls, readReserve: value.policy.default.readReserve },
|
|
1317
|
+
"budget.policy.default"
|
|
1318
|
+
);
|
|
1319
|
+
const maximum = clonePhase(value.policy.maximum, "budget.policy.maximum");
|
|
1320
|
+
const request = value.request === null ? null : cloneDispatchBudgetRequest(value.request);
|
|
1321
|
+
const effectivePhase = clonePhase(
|
|
1322
|
+
{ toolCalls: value.effective.toolCalls, readReserve: value.effective.readReserve },
|
|
1323
|
+
"budget.effective"
|
|
1324
|
+
);
|
|
1325
|
+
const revision = value.effective.revision === void 0 ? void 0 : clonePhase(value.effective.revision, "budget.effective.revision");
|
|
1326
|
+
if (typeof value.effective.synthesis !== "boolean" || typeof value.effective.hardCap !== "number" || !Number.isSafeInteger(value.effective.hardCap) || value.effective.hardCap <= 0 || !Array.isArray(value.reasons)) {
|
|
1327
|
+
return void 0;
|
|
1328
|
+
}
|
|
1329
|
+
if (maximum.toolCalls < defaultPhase.toolCalls || maximum.readReserve < defaultPhase.readReserve || value.policy.exact && !samePhase(maximum, defaultPhase) || effectivePhase.toolCalls > value.effective.hardCap || value.effective.synthesis !== value.policy.default.synthesis || revision !== void 0 && (revision.toolCalls < effectivePhase.toolCalls || revision.toolCalls > value.effective.hardCap || revision.toolCalls === effectivePhase.toolCalls && revision.readReserve <= effectivePhase.readReserve)) {
|
|
1330
|
+
return void 0;
|
|
1331
|
+
}
|
|
1332
|
+
const reasons = [];
|
|
1333
|
+
for (const reason of value.reasons) {
|
|
1334
|
+
if (!isRecord(reason) || typeof reason.code !== "string" || !BUDGET_REASON_CODES.has(reason.code) || typeof reason.detail !== "string") {
|
|
1335
|
+
return void 0;
|
|
1336
|
+
}
|
|
1337
|
+
reasons.push({ code: reason.code, detail: reason.detail });
|
|
1338
|
+
}
|
|
1339
|
+
return freezeEnvelope({
|
|
1340
|
+
version: 1,
|
|
1341
|
+
policy: {
|
|
1342
|
+
recipeId,
|
|
1343
|
+
default: { ...defaultPhase, synthesis: value.policy.default.synthesis },
|
|
1344
|
+
maximum,
|
|
1345
|
+
exact: value.policy.exact
|
|
1346
|
+
},
|
|
1347
|
+
request,
|
|
1348
|
+
effective: {
|
|
1349
|
+
...effectivePhase,
|
|
1350
|
+
synthesis: value.effective.synthesis,
|
|
1351
|
+
hardCap: value.effective.hardCap,
|
|
1352
|
+
...revision === void 0 ? {} : { revision }
|
|
1353
|
+
},
|
|
1354
|
+
reasons
|
|
1355
|
+
});
|
|
1356
|
+
} catch {
|
|
1357
|
+
return void 0;
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
|
|
780
1361
|
// src/domains/dispatch/gate-role-prompts.ts
|
|
781
1362
|
init_esm_shims();
|
|
782
1363
|
var REVIEWER_GATE_PROMPT = [
|
|
@@ -831,525 +1412,222 @@ function runKindSupportsLiveSteering(kind) {
|
|
|
831
1412
|
return kind === "http" || kind === "sdk";
|
|
832
1413
|
}
|
|
833
1414
|
|
|
834
|
-
// src/domains/
|
|
1415
|
+
// src/domains/safety/call-target.ts
|
|
835
1416
|
init_esm_shims();
|
|
836
|
-
import { randomUUID } from "node:crypto";
|
|
837
1417
|
|
|
838
|
-
// src/domains/
|
|
1418
|
+
// src/domains/safety/redaction.ts
|
|
839
1419
|
init_esm_shims();
|
|
840
|
-
|
|
841
|
-
"
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
"
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
return
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
return
|
|
868
|
-
}
|
|
869
|
-
function isNumber(value) {
|
|
870
|
-
return typeof value === "number" && Number.isFinite(value);
|
|
871
|
-
}
|
|
872
|
-
function isPositiveInteger(value) {
|
|
873
|
-
return isNumber(value) && Number.isInteger(value) && value > 0;
|
|
874
|
-
}
|
|
875
|
-
function isOptionalNumber(value) {
|
|
876
|
-
return value === void 0 || isNumber(value);
|
|
1420
|
+
function isPlainObject2(value) {
|
|
1421
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1422
|
+
}
|
|
1423
|
+
var SECRET_KEY_RE = /(?:api[-_]?key|access[-_]?key|auth(?:orization)?|credential|password|private[-_]?key|secret|token)/iu;
|
|
1424
|
+
var ENV_KEY_RE = /^env(?:ironment)?$/iu;
|
|
1425
|
+
var SECRET_STRING_RE = /(https?:\/\/[^\s/@]+:)[^\s/@]+@/giu;
|
|
1426
|
+
var SECRET_URL_PARAM_RE = /([?&](?:api[-_]?key|access[-_]?token|auth(?:orization)?|credential|password|secret|token)[^=\s]*=)[^&#\s]+/giu;
|
|
1427
|
+
var SECRET_ASSIGNMENT_RE = /(?<![A-Z0-9_])((?:[A-Z0-9_]*(?:ACCESS|API|AUTH|CREDENTIAL|KEY|PASS(?:WORD)?|PRIVATE|SECRET|TOKEN)[A-Z0-9_]*)=)[^\s;&|]+/giu;
|
|
1428
|
+
var SECRET_FLAG_RE = /(--?(?:[a-z0-9-]*(?:api[-_]?key|access[-_]?token|auth(?:orization)?|credential|password|secret|token)[a-z0-9-]*))(=|\s+)([^\s;&|]+)/giu;
|
|
1429
|
+
function redactSecretString(value) {
|
|
1430
|
+
return value.replace(SECRET_STRING_RE, "$1[redacted]@").replace(SECRET_URL_PARAM_RE, "$1[redacted]").replace(SECRET_ASSIGNMENT_RE, "$1[redacted]").replace(SECRET_FLAG_RE, "$1$2[redacted]");
|
|
1431
|
+
}
|
|
1432
|
+
function isSecretArgKey(key) {
|
|
1433
|
+
return SECRET_KEY_RE.test(key);
|
|
1434
|
+
}
|
|
1435
|
+
function isEnvironmentArgKey(key) {
|
|
1436
|
+
return ENV_KEY_RE.test(key);
|
|
1437
|
+
}
|
|
1438
|
+
function redactEnvironmentValue(value, depth) {
|
|
1439
|
+
if (depth > 8) return "[redacted nested values]";
|
|
1440
|
+
if (typeof value === "string") return "[redacted]";
|
|
1441
|
+
if (Array.isArray(value)) return value.map((item) => redactEnvironmentValue(item, depth + 1));
|
|
1442
|
+
if (!isPlainObject2(value)) return value;
|
|
1443
|
+
const out = {};
|
|
1444
|
+
for (const [childKey, childValue] of Object.entries(value)) {
|
|
1445
|
+
out[childKey] = redactEnvironmentValue(childValue, depth + 1);
|
|
1446
|
+
}
|
|
1447
|
+
return out;
|
|
877
1448
|
}
|
|
878
|
-
function
|
|
879
|
-
|
|
1449
|
+
function redactToolArgs(value, key = "", depth = 0) {
|
|
1450
|
+
if (isSecretArgKey(key)) return "[redacted]";
|
|
1451
|
+
if (isEnvironmentArgKey(key)) return redactEnvironmentValue(value, depth);
|
|
1452
|
+
if (typeof value === "string") return redactSecretString(value);
|
|
1453
|
+
if (depth > 8) return "[redacted nested values]";
|
|
1454
|
+
if (Array.isArray(value)) return value.map((item) => redactToolArgs(item, key, depth + 1));
|
|
1455
|
+
if (!isPlainObject2(value)) return value;
|
|
1456
|
+
const out = {};
|
|
1457
|
+
for (const [childKey, childValue] of Object.entries(value)) {
|
|
1458
|
+
out[childKey] = redactToolArgs(childValue, childKey, depth + 1);
|
|
1459
|
+
}
|
|
1460
|
+
return out;
|
|
880
1461
|
}
|
|
881
|
-
|
|
882
|
-
|
|
1462
|
+
|
|
1463
|
+
// src/domains/safety/call-target.ts
|
|
1464
|
+
var ESC_CHAR = String.fromCharCode(27);
|
|
1465
|
+
var BEL_CHAR = String.fromCharCode(7);
|
|
1466
|
+
var OSC_PATTERN = new RegExp(`${ESC_CHAR}\\][\\s\\S]*?(?:${BEL_CHAR}|${ESC_CHAR}\\\\|$)`, "g");
|
|
1467
|
+
var CSI_PATTERN = new RegExp(`${ESC_CHAR}\\[[0-9;?]*[0-9A-Za-z]`, "g");
|
|
1468
|
+
function sanitizeForDisplay(value) {
|
|
1469
|
+
const stripped = value.replace(OSC_PATTERN, "").replace(CSI_PATTERN, "");
|
|
1470
|
+
let out = "";
|
|
1471
|
+
for (const ch of stripped) {
|
|
1472
|
+
const code = ch.codePointAt(0) ?? 0;
|
|
1473
|
+
out += code < 32 || code === 127 ? " " : ch;
|
|
1474
|
+
}
|
|
1475
|
+
return out;
|
|
883
1476
|
}
|
|
884
|
-
function
|
|
885
|
-
return
|
|
1477
|
+
function oneLine(value) {
|
|
1478
|
+
return value.replace(/\s+/g, " ").trim();
|
|
1479
|
+
}
|
|
1480
|
+
function sanitizeCallTargetText(value) {
|
|
1481
|
+
return oneLine(sanitizeForDisplay(value));
|
|
1482
|
+
}
|
|
1483
|
+
var CALL_ACTION_OBJECT_MAX_CHARS = 64;
|
|
1484
|
+
var CALL_TARGET_MAX_CHARS = 120;
|
|
1485
|
+
var CALL_ACTION_VOCABULARY = {
|
|
1486
|
+
read: { verb: "reading", field: "path" },
|
|
1487
|
+
edit: { verb: "editing", field: "path" },
|
|
1488
|
+
write: { verb: "writing", field: "path" },
|
|
1489
|
+
ls: { verb: "listing", field: "path" },
|
|
1490
|
+
bash: { verb: "running", field: "command" },
|
|
1491
|
+
grep: { verb: "searching", field: "pattern" },
|
|
1492
|
+
find: { verb: "finding", field: "pattern" },
|
|
1493
|
+
web_fetch: { verb: "fetching", field: "url" },
|
|
1494
|
+
git: { verb: "git", field: "op" },
|
|
1495
|
+
verify: { verb: "verifying", field: "check" },
|
|
1496
|
+
code_nav: { verb: "navigating", field: "query" },
|
|
1497
|
+
context: { verb: "context", field: "scope" },
|
|
1498
|
+
artifact: { verb: "writing", field: "kind" },
|
|
1499
|
+
monitor: { verb: "monitoring", field: "run_id" },
|
|
1500
|
+
steer: { verb: "steering", field: "run_id" },
|
|
1501
|
+
tasks: { verb: "tasks", field: "action" },
|
|
1502
|
+
dispatch: { verb: "dispatching", field: "agent" },
|
|
1503
|
+
// ACP tool kinds. A peer names its own argument fields, so these rely on
|
|
1504
|
+
// the shared allowlist below rather than on a field this side can predict.
|
|
1505
|
+
execute: { verb: "running", field: "command" },
|
|
1506
|
+
search: { verb: "searching", field: "query" },
|
|
1507
|
+
fetch: { verb: "fetching", field: "url" },
|
|
1508
|
+
delete: { verb: "deleting", field: "path" },
|
|
1509
|
+
move: { verb: "moving", field: "path" },
|
|
1510
|
+
think: { verb: "thinking", field: "" }
|
|
1511
|
+
};
|
|
1512
|
+
var CALL_ACTION_OBJECT_FIELDS = ["path", "file_path", "command", "pattern", "query", "url"];
|
|
1513
|
+
var CALL_TARGET_FIELDS = {
|
|
1514
|
+
read: ["path", "offset", "limit", "tail"],
|
|
1515
|
+
grep: ["pattern", "path", "mode", "glob", "ignore_case", "literal", "context", "limit", "include_ignored"],
|
|
1516
|
+
find: ["pattern", "path", "order", "limit", "include_ignored"],
|
|
1517
|
+
ls: ["path", "limit"],
|
|
1518
|
+
code_nav: ["mode", "query", "limit"],
|
|
1519
|
+
context: ["scope", "query", "name", "limit", "ref", "include_tree"],
|
|
1520
|
+
credential_present: ["name", "source", "file"],
|
|
1521
|
+
write: ["path"],
|
|
1522
|
+
edit: ["path"],
|
|
1523
|
+
bash: ["command", "cwd", "timeout_ms", "output_policy"],
|
|
1524
|
+
git: ["op", "path", "cached", "stat", "name_only", "limit", "cwd", "timeout_ms", "max_output_bytes"],
|
|
1525
|
+
verify: ["check", "path", "browser", "cwd", "timeout_ms", "max_output_bytes"],
|
|
1526
|
+
dispatch: [
|
|
1527
|
+
"list",
|
|
1528
|
+
"mode",
|
|
1529
|
+
"agent",
|
|
1530
|
+
"target",
|
|
1531
|
+
"model",
|
|
1532
|
+
"node",
|
|
1533
|
+
"autonomy",
|
|
1534
|
+
"tool_profile",
|
|
1535
|
+
"thinking_level",
|
|
1536
|
+
"detach",
|
|
1537
|
+
"timeout_ms"
|
|
1538
|
+
],
|
|
1539
|
+
monitor: ["run_id", "mode"],
|
|
1540
|
+
steer: ["run_id", "action"],
|
|
1541
|
+
tasks: ["action", "id"],
|
|
1542
|
+
ledger: ["action", "kind", "path", "line", "target", "passed", "since"],
|
|
1543
|
+
web_fetch: ["url", "method", "timeout_ms", "max_bytes", "format"],
|
|
1544
|
+
ask_user: ["action", "mode", "max_rounds", "exposure"],
|
|
1545
|
+
artifact: ["kind", "path", "title"],
|
|
1546
|
+
// ACP tool kinds use only fields whose meaning the protocol defines.
|
|
1547
|
+
execute: ["command", "cwd"],
|
|
1548
|
+
search: ["query", "path"],
|
|
1549
|
+
fetch: ["url", "method"],
|
|
1550
|
+
delete: ["path"],
|
|
1551
|
+
move: ["path", "target"]
|
|
1552
|
+
};
|
|
1553
|
+
function boundActionObject(value) {
|
|
1554
|
+
if (typeof value !== "string") return null;
|
|
1555
|
+
const clean = sanitizeCallTargetText(redactSecretString(value));
|
|
1556
|
+
if (clean.length === 0) return null;
|
|
1557
|
+
if (clean.length <= CALL_ACTION_OBJECT_MAX_CHARS) return { object: clean, truncated: false };
|
|
1558
|
+
return { object: clean.slice(0, CALL_ACTION_OBJECT_MAX_CHARS), truncated: true };
|
|
1559
|
+
}
|
|
1560
|
+
function describeCallAction(tool, args) {
|
|
1561
|
+
const known = CALL_ACTION_VOCABULARY[tool];
|
|
1562
|
+
const candidates = known?.field ? [known.field, ...CALL_ACTION_OBJECT_FIELDS] : [...CALL_ACTION_OBJECT_FIELDS];
|
|
1563
|
+
let bounded = null;
|
|
1564
|
+
if (args) {
|
|
1565
|
+
for (const field of candidates) {
|
|
1566
|
+
if (isSecretArgKey(field)) continue;
|
|
1567
|
+
bounded = boundActionObject(args[field]);
|
|
1568
|
+
if (bounded !== null) break;
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
if (known === void 0 && bounded === null) return null;
|
|
1572
|
+
const verb = known?.verb ?? "calling";
|
|
1573
|
+
if (bounded === null) return { verb };
|
|
1574
|
+
return { verb, object: bounded.object, ...bounded.truncated ? { truncated: true } : {} };
|
|
1575
|
+
}
|
|
1576
|
+
function renderAllowedTargetValue(value) {
|
|
1577
|
+
if (typeof value === "string") {
|
|
1578
|
+
const rendered = sanitizeCallTargetText(redactSecretString(value));
|
|
1579
|
+
return rendered.length > 0 ? rendered : null;
|
|
1580
|
+
}
|
|
1581
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
1582
|
+
if (typeof value === "boolean") return String(value);
|
|
1583
|
+
return null;
|
|
886
1584
|
}
|
|
887
|
-
function
|
|
888
|
-
return
|
|
1585
|
+
function countLabel(count, singular, plural) {
|
|
1586
|
+
return `${count} ${count === 1 ? singular : plural}`;
|
|
889
1587
|
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
var PROTECTED_ARTIFACT_SOURCES = [
|
|
894
|
-
"validation",
|
|
895
|
-
"middleware",
|
|
896
|
-
"user",
|
|
897
|
-
"session"
|
|
898
|
-
];
|
|
899
|
-
var TASK_LEDGER_STATUSES = ["pending", "active", "completed", "blocked", "cancelled"];
|
|
900
|
-
var TASK_LEDGER_EVIDENCE_STATUSES = [
|
|
901
|
-
"required",
|
|
902
|
-
"pending",
|
|
903
|
-
"passed",
|
|
904
|
-
"failed",
|
|
905
|
-
"missing"
|
|
906
|
-
];
|
|
907
|
-
var DECISION_STATUSES = ["active", "superseded"];
|
|
908
|
-
var DECISION_INTERVIEW_STATUSES = ["complete", "cancelled"];
|
|
909
|
-
var WORKER_RUN_ORIGINS = ["user", "agent"];
|
|
910
|
-
var WORKER_RUN_RUNTIME_KINDS = ["clio", "acp", "claude-sdk", "claude-code"];
|
|
911
|
-
function isWorkerRunRuntime(value) {
|
|
912
|
-
if (!isRecord(value)) return false;
|
|
913
|
-
return isOneOf(value.kind, WORKER_RUN_RUNTIME_KINDS) && isOptionalString(value.targetId) && isOptionalString(value.wireModelId) && isOptionalString(value.peerId);
|
|
914
|
-
}
|
|
915
|
-
function isTaskLedgerGoal(value) {
|
|
916
|
-
if (!isRecord(value)) return false;
|
|
917
|
-
if (!isString(value.id) || !isString(value.title)) return false;
|
|
918
|
-
if (!isOneOf(value.status, TASK_LEDGER_STATUSES)) return false;
|
|
919
|
-
if (value.parentGoalId !== void 0 && !isNullableString(value.parentGoalId)) return false;
|
|
920
|
-
const hasPairedProvenance = value.origin === "user" ? isString(value.userTaskId) && /^u[1-9]\d*$/.test(value.userTaskId) : (value.origin === void 0 || value.origin === "agent") && value.userTaskId === void 0;
|
|
921
|
-
return isOptionalString(value.description) && hasPairedProvenance;
|
|
922
|
-
}
|
|
923
|
-
function isTaskLedgerEvidence(value) {
|
|
924
|
-
if (!isRecord(value)) return false;
|
|
925
|
-
if (!isString(value.id) || !isString(value.description)) return false;
|
|
926
|
-
if (!isOneOf(value.status, TASK_LEDGER_EVIDENCE_STATUSES)) return false;
|
|
927
|
-
return isOptionalString(value.command) && isOptionalString(value.artifactPath) && isOptionalString(value.observedAt) && isOptionalString(value.notes);
|
|
928
|
-
}
|
|
929
|
-
function isDecisionRecord(value) {
|
|
930
|
-
if (!isRecord(value)) return false;
|
|
931
|
-
if (!isString(value.key) || !/^[a-z0-9]+(?:_[a-z0-9]+)*$/.test(value.key)) return false;
|
|
932
|
-
if (!isString(value.value) || !isOneOf(value.status, DECISION_STATUSES) || !isString(value.decidedAt)) return false;
|
|
933
|
-
if (!isOptionalString(value.label) || !isOptionalString(value.source_question)) return false;
|
|
934
|
-
if (!isOptionalString(value.revisedAt) || !isOptionalString(value.correction)) return false;
|
|
935
|
-
return value.status === "superseded" ? isString(value.revisedAt) : value.revisedAt === void 0 && value.correction === void 0;
|
|
936
|
-
}
|
|
937
|
-
function isOptionalCompactionUsage(value) {
|
|
938
|
-
if (value === void 0) return true;
|
|
939
|
-
if (!isRecord(value)) return false;
|
|
940
|
-
const cost = value.cost;
|
|
941
|
-
return isNumber(value.input) && isNumber(value.output) && isNumber(value.cacheRead) && isNumber(value.cacheWrite) && isNumber(value.reasoning) && isNumber(value.totalTokens) && isNumber(value.apiCalls) && isRecord(cost) && isNumber(cost.total);
|
|
942
|
-
}
|
|
943
|
-
function isProtectedArtifact(value) {
|
|
944
|
-
if (!isRecord(value)) return false;
|
|
945
|
-
return isString(value.path) && isString(value.protectedAt) && isString(value.reason) && isOneOf(value.source, PROTECTED_ARTIFACT_SOURCES) && isOptionalString(value.validationCommand) && isOptionalNumber(value.validationExitCode);
|
|
946
|
-
}
|
|
947
|
-
function isSessionHeader(value) {
|
|
948
|
-
if (!isRecord(value)) return false;
|
|
949
|
-
return value.type === "session" && isPositiveInteger(value.version) && isString(value.id) && isString(value.timestamp) && isString(value.cwd) && isOptionalString(value.parentSession) && isOptionalString(value.parentTurnId);
|
|
950
|
-
}
|
|
951
|
-
function isSessionEntry(value) {
|
|
952
|
-
if (!value || typeof value !== "object") return false;
|
|
953
|
-
const v = value;
|
|
954
|
-
if (!hasBaseSessionEntryFields(v)) return false;
|
|
955
|
-
if (!isOneOf(v.kind, SESSION_ENTRY_KINDS)) return false;
|
|
956
|
-
switch (v.kind) {
|
|
957
|
-
case "message":
|
|
958
|
-
return Object.hasOwn(v, "payload") && isOneOf(v.role, MESSAGE_ROLES);
|
|
959
|
-
case "bashExecution":
|
|
960
|
-
return isString(v.command) && isString(v.output) && (v.exitCode === null || isNumber(v.exitCode)) && typeof v.cancelled === "boolean" && typeof v.truncated === "boolean" && isOptionalString(v.fullOutputPath) && isOptionalBoolean(v.excludeFromContext);
|
|
961
|
-
case "custom":
|
|
962
|
-
return isString(v.customType) && isOptionalBoolean(v.display);
|
|
963
|
-
case "modelChange":
|
|
964
|
-
return isString(v.provider) && isString(v.modelId) && isOptionalString(v.target);
|
|
965
|
-
case "thinkingLevelChange":
|
|
966
|
-
return isString(v.thinkingLevel);
|
|
967
|
-
case "fileEntry":
|
|
968
|
-
return isString(v.path) && isOneOf(v.operation, FILE_OPERATIONS) && isOptionalNumber(v.bytes) && isOptionalString(v.hash);
|
|
969
|
-
case "branchSummary":
|
|
970
|
-
return isString(v.fromTurnId) && isString(v.summary);
|
|
971
|
-
case "compactionSummary":
|
|
972
|
-
return isString(v.summary) && isNumber(v.tokensBefore) && isString(v.firstKeptTurnId) && isOptionalCompactionUsage(v.usage) && (v.trigger === void 0 || isOneOf(v.trigger, COMPACTION_TRIGGERS)) && isOptionalNumber(v.tokensAfter) && isOptionalNumber(v.messagesSummarized) && isOptionalBoolean(v.isSplitTurn);
|
|
973
|
-
case "sessionInfo":
|
|
974
|
-
return isOptionalString(v.name) && isOptionalString(v.targetTurnId) && isOptionalString(v.label);
|
|
975
|
-
case "label":
|
|
976
|
-
return isString(v.targetTurnId) && isOptionalString(v.label);
|
|
977
|
-
case "protectedArtifact":
|
|
978
|
-
return v.action === "protect" && isProtectedArtifact(v.artifact) && isOptionalString(v.toolName) && isOptionalString(v.toolCallId) && isOptionalString(v.runId) && isOptionalString(v.correlationId);
|
|
979
|
-
case "skillActivation":
|
|
980
|
-
return isSkillActivation(v.activation);
|
|
981
|
-
case "taskLedger":
|
|
982
|
-
return isOptionalString(v.boardId) && Array.isArray(v.goals) && v.goals.every(isTaskLedgerGoal) && Array.isArray(v.subgoals) && v.subgoals.every(isTaskLedgerGoal) && isStringArray(v.activeRunIds) && Array.isArray(v.requiredValidationEvidence) && v.requiredValidationEvidence.every(isTaskLedgerEvidence);
|
|
983
|
-
case "decisionLedger":
|
|
984
|
-
return isString(v.interviewId) && isOneOf(v.interviewStatus, DECISION_INTERVIEW_STATUSES) && isString(v.startedAt) && isString(v.endedAt) && isNumber(v.roundCount) && Number.isInteger(v.roundCount) && v.roundCount >= 0 && isOptionalString(v.summary) && isOptionalString(v.transcriptPath) && Array.isArray(v.decisions) && v.decisions.every(isDecisionRecord);
|
|
985
|
-
case "workerRun":
|
|
986
|
-
return isString(v.assignmentId) && isString(v.runId) && isOneOf(v.origin, WORKER_RUN_ORIGINS) && isString(v.agentId) && isWorkerRunRuntime(v.runtime) && isOptionalString(v.parentToolCallId);
|
|
1588
|
+
function summarizeUnlistedTargetValue(value) {
|
|
1589
|
+
if (typeof value === "string") {
|
|
1590
|
+
return `<string ${countLabel(Buffer.byteLength(value, "utf8"), "byte", "bytes")}>`;
|
|
987
1591
|
}
|
|
988
|
-
return
|
|
1592
|
+
if (Array.isArray(value)) return `<array ${countLabel(value.length, "item", "items")}>`;
|
|
1593
|
+
if (value !== null && typeof value === "object") {
|
|
1594
|
+
return `<object ${countLabel(Object.keys(value).length, "field", "fields")}>`;
|
|
1595
|
+
}
|
|
1596
|
+
if (value === null) return "<null 0 values>";
|
|
1597
|
+
if (typeof value === "undefined") return "<undefined 0 values>";
|
|
1598
|
+
return `<${typeof value} 1 value>`;
|
|
989
1599
|
}
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
var TASK_BOARD_GOAL_ID = "board";
|
|
993
|
-
var LEGACY_TASK_BOARD_ID = "legacy";
|
|
994
|
-
function isOpenUserTask(task) {
|
|
995
|
-
return task.origin === "user" && (task.status === "pending" || task.status === "active");
|
|
996
|
-
}
|
|
997
|
-
function taskBoardCounts(board) {
|
|
998
|
-
const counts = {
|
|
999
|
-
total: board.tasks.length,
|
|
1000
|
-
completed: 0,
|
|
1001
|
-
active: 0,
|
|
1002
|
-
pending: 0,
|
|
1003
|
-
blocked: 0,
|
|
1004
|
-
cancelled: 0,
|
|
1005
|
-
open: 0
|
|
1006
|
-
};
|
|
1007
|
-
for (const task of board.tasks) {
|
|
1008
|
-
if (task.status === "completed") counts.completed += 1;
|
|
1009
|
-
else if (task.status === "active") counts.active += 1;
|
|
1010
|
-
else if (task.status === "pending") counts.pending += 1;
|
|
1011
|
-
else if (task.status === "blocked") counts.blocked += 1;
|
|
1012
|
-
else counts.cancelled += 1;
|
|
1013
|
-
}
|
|
1014
|
-
counts.open = counts.pending + counts.active;
|
|
1015
|
-
return counts;
|
|
1016
|
-
}
|
|
1017
|
-
function boardStatus(tasks) {
|
|
1018
|
-
const counts = taskBoardCounts({ tasks });
|
|
1019
|
-
if (counts.total === 0) return "pending";
|
|
1020
|
-
if (counts.active > 0) return "active";
|
|
1021
|
-
if (counts.open === 0 && counts.blocked === 0) return "completed";
|
|
1022
|
-
if (counts.blocked > 0 && counts.open === 0) return "blocked";
|
|
1023
|
-
return "pending";
|
|
1024
|
-
}
|
|
1025
|
-
function toTaskLedgerEntryFields(board, now) {
|
|
1026
|
-
const evidence = [];
|
|
1027
|
-
const subgoals = board.tasks.map((task) => {
|
|
1028
|
-
if (task.status === "completed" && task.evidence) {
|
|
1029
|
-
evidence.push({
|
|
1030
|
-
id: `${task.id}.evidence`,
|
|
1031
|
-
description: task.evidence,
|
|
1032
|
-
status: "passed",
|
|
1033
|
-
observedAt: now.toISOString()
|
|
1034
|
-
});
|
|
1035
|
-
}
|
|
1036
|
-
const goal = {
|
|
1037
|
-
id: task.id,
|
|
1038
|
-
title: task.title,
|
|
1039
|
-
status: task.status,
|
|
1040
|
-
parentGoalId: TASK_BOARD_GOAL_ID
|
|
1041
|
-
};
|
|
1042
|
-
if (task.origin) goal.origin = task.origin;
|
|
1043
|
-
if (task.userTaskId) goal.userTaskId = task.userTaskId;
|
|
1044
|
-
if (task.reason) goal.description = task.reason;
|
|
1045
|
-
return goal;
|
|
1046
|
-
});
|
|
1047
|
-
return {
|
|
1048
|
-
kind: "taskLedger",
|
|
1049
|
-
parentTurnId: null,
|
|
1050
|
-
boardId: board.boardId,
|
|
1051
|
-
goals: [{ id: TASK_BOARD_GOAL_ID, title: board.title, status: boardStatus(board.tasks) }],
|
|
1052
|
-
subgoals,
|
|
1053
|
-
activeRunIds: [...board.activeRunIds],
|
|
1054
|
-
requiredValidationEvidence: evidence
|
|
1055
|
-
};
|
|
1600
|
+
function targetFieldName(value) {
|
|
1601
|
+
return sanitizeCallTargetText(value).slice(0, 32) || "field";
|
|
1056
1602
|
}
|
|
1057
|
-
function
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
for (const
|
|
1063
|
-
if (
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
}
|
|
1067
|
-
function foldSessionTaskHistory(entries) {
|
|
1068
|
-
const boards = /* @__PURE__ */ new Map();
|
|
1069
|
-
for (const [index, raw] of entries.entries()) {
|
|
1070
|
-
if (!isTaskLedgerShaped(raw)) continue;
|
|
1071
|
-
const view = toEntryView(raw);
|
|
1072
|
-
if (!view) continue;
|
|
1073
|
-
const boardId = typeof raw.boardId === "string" && raw.boardId.length > 0 ? raw.boardId : LEGACY_TASK_BOARD_ID;
|
|
1074
|
-
const timestamp = typeof raw.timestamp === "string" ? raw.timestamp : "";
|
|
1075
|
-
if (boardId === LEGACY_TASK_BOARD_ID) {
|
|
1076
|
-
boards.set(boardId, {
|
|
1077
|
-
boardId,
|
|
1078
|
-
title: view.title,
|
|
1079
|
-
tasks: new Map(view.tasks.map((task) => [task.id, task])),
|
|
1080
|
-
lastSnapshotAt: timestamp,
|
|
1081
|
-
lastIndex: index
|
|
1082
|
-
});
|
|
1603
|
+
function describeCallTarget(tool, args) {
|
|
1604
|
+
if (!args) return "";
|
|
1605
|
+
const allowedFields = CALL_TARGET_FIELDS[tool] ?? [];
|
|
1606
|
+
const allowed = new Set(allowedFields);
|
|
1607
|
+
const parts = [];
|
|
1608
|
+
for (const field of allowedFields) {
|
|
1609
|
+
if (!(field in args)) continue;
|
|
1610
|
+
if (isSecretArgKey(field)) {
|
|
1611
|
+
parts.push(`${targetFieldName(field)}=${summarizeUnlistedTargetValue(args[field])}`);
|
|
1083
1612
|
continue;
|
|
1084
1613
|
}
|
|
1085
|
-
const
|
|
1086
|
-
if (
|
|
1087
|
-
|
|
1088
|
-
boardId,
|
|
1089
|
-
title: view.title,
|
|
1090
|
-
tasks: new Map(view.tasks.map((task) => [task.id, task])),
|
|
1091
|
-
lastSnapshotAt: timestamp,
|
|
1092
|
-
lastIndex: index
|
|
1093
|
-
});
|
|
1614
|
+
const rendered = renderAllowedTargetValue(args[field]);
|
|
1615
|
+
if (rendered === null) {
|
|
1616
|
+
parts.push(`${targetFieldName(field)}=${summarizeUnlistedTargetValue(args[field])}`);
|
|
1094
1617
|
continue;
|
|
1095
1618
|
}
|
|
1096
|
-
|
|
1097
|
-
for (const task of view.tasks) existing.tasks.set(task.id, task);
|
|
1098
|
-
existing.lastSnapshotAt = timestamp;
|
|
1099
|
-
existing.lastIndex = index;
|
|
1100
|
-
}
|
|
1101
|
-
return [...boards.values()].sort((left, right) => right.lastIndex - left.lastIndex).map(({ lastIndex: _lastIndex, tasks, ...board }) => ({ ...board, tasks: [...tasks.values()] }));
|
|
1102
|
-
}
|
|
1103
|
-
function toEntryView(entry) {
|
|
1104
|
-
const boardGoal = entry.goals[0];
|
|
1105
|
-
if (!boardGoal) return null;
|
|
1106
|
-
const evidenceByTask = /* @__PURE__ */ new Map();
|
|
1107
|
-
for (const item of entry.requiredValidationEvidence) {
|
|
1108
|
-
const taskId = item.id.endsWith(".evidence") ? item.id.slice(0, -".evidence".length) : item.id;
|
|
1109
|
-
evidenceByTask.set(taskId, item.description);
|
|
1110
|
-
}
|
|
1111
|
-
return {
|
|
1112
|
-
boardId: entry.boardId ?? LEGACY_TASK_BOARD_ID,
|
|
1113
|
-
title: boardGoal.title,
|
|
1114
|
-
tasks: entry.subgoals.map((goal) => {
|
|
1115
|
-
const task = {
|
|
1116
|
-
id: goal.id,
|
|
1117
|
-
title: goal.title,
|
|
1118
|
-
status: goal.status,
|
|
1119
|
-
origin: goal.origin ?? "agent"
|
|
1120
|
-
};
|
|
1121
|
-
if (goal.userTaskId) task.userTaskId = goal.userTaskId;
|
|
1122
|
-
if (goal.description) task.reason = goal.description;
|
|
1123
|
-
const evidence = evidenceByTask.get(goal.id);
|
|
1124
|
-
if (evidence) task.evidence = evidence;
|
|
1125
|
-
return task;
|
|
1126
|
-
}),
|
|
1127
|
-
// Run linkage is process-live: the runs recorded in old entries ended
|
|
1128
|
-
// with the process that dispatched them, so a refold starts empty and
|
|
1129
|
-
// the historical linkage stays readable in the earlier entries.
|
|
1130
|
-
activeRunIds: []
|
|
1131
|
-
};
|
|
1132
|
-
}
|
|
1133
|
-
function nextTaskId(tasks) {
|
|
1134
|
-
let max = 0;
|
|
1135
|
-
for (const task of tasks) {
|
|
1136
|
-
const match = /^t(\d+)$/.exec(task.id);
|
|
1137
|
-
if (match) max = Math.max(max, Number(match[1]));
|
|
1138
|
-
}
|
|
1139
|
-
return max + 1;
|
|
1140
|
-
}
|
|
1141
|
-
function normalizeTitles(titles) {
|
|
1142
|
-
return titles.map((title) => title.trim()).filter((title) => title.length > 0);
|
|
1143
|
-
}
|
|
1144
|
-
function applyMutation(board, mutation) {
|
|
1145
|
-
if (mutation.op === "plan") {
|
|
1146
|
-
const titles = normalizeTitles(mutation.tasks);
|
|
1147
|
-
if (mutation.title.trim().length === 0) return { error: "plan requires a non-empty title" };
|
|
1148
|
-
if (titles.length === 0) return { error: "plan requires at least one task" };
|
|
1149
|
-
const retained = board?.tasks.filter(isOpenUserTask) ?? [];
|
|
1150
|
-
const notes2 = [];
|
|
1151
|
-
const replacedOpen = board ? taskBoardCounts(board).open - retained.length : 0;
|
|
1152
|
-
if (board && replacedOpen > 0) {
|
|
1153
|
-
notes2.push(`replaced board "${board.title}" with ${replacedOpen} agent task(s) still open`);
|
|
1154
|
-
}
|
|
1155
|
-
if (retained.length > 0) notes2.push(`preserved ${retained.length} open operator task(s)`);
|
|
1156
|
-
const start = nextTaskId(retained);
|
|
1157
|
-
return {
|
|
1158
|
-
board: {
|
|
1159
|
-
boardId: "",
|
|
1160
|
-
title: mutation.title.trim(),
|
|
1161
|
-
tasks: [
|
|
1162
|
-
...retained,
|
|
1163
|
-
...titles.map((title, index) => ({
|
|
1164
|
-
id: `t${start + index}`,
|
|
1165
|
-
title,
|
|
1166
|
-
status: "pending",
|
|
1167
|
-
origin: "agent"
|
|
1168
|
-
}))
|
|
1169
|
-
],
|
|
1170
|
-
// Runs in flight outlive a board swap: they belong to the session,
|
|
1171
|
-
// so the fresh board inherits the linkage until the runs finish.
|
|
1172
|
-
activeRunIds: board?.activeRunIds ?? []
|
|
1173
|
-
},
|
|
1174
|
-
notes: notes2
|
|
1175
|
-
};
|
|
1176
|
-
}
|
|
1177
|
-
if (mutation.op === "pick") {
|
|
1178
|
-
const title = mutation.title.trim();
|
|
1179
|
-
if (title.length === 0) return { error: "pick requires a non-empty operator task title" };
|
|
1180
|
-
if (!/^u[1-9]\d*$/.test(mutation.userTaskId)) return { error: "pick requires an operator task id like u3" };
|
|
1181
|
-
if (board?.tasks.some(
|
|
1182
|
-
(task) => task.userTaskId === mutation.userTaskId && (task.status === "pending" || task.status === "active" || task.status === "completed")
|
|
1183
|
-
)) {
|
|
1184
|
-
return { error: `operator task ${mutation.userTaskId} is already linked to durable board work` };
|
|
1185
|
-
}
|
|
1186
|
-
const tasks2 = board?.tasks ?? [];
|
|
1187
|
-
const picked = {
|
|
1188
|
-
id: `t${nextTaskId(tasks2)}`,
|
|
1189
|
-
title,
|
|
1190
|
-
status: "pending",
|
|
1191
|
-
origin: "user",
|
|
1192
|
-
userTaskId: mutation.userTaskId
|
|
1193
|
-
};
|
|
1194
|
-
return {
|
|
1195
|
-
board: {
|
|
1196
|
-
boardId: board?.boardId ?? "",
|
|
1197
|
-
title: board?.title ?? "Operator tasks",
|
|
1198
|
-
tasks: [...tasks2, picked],
|
|
1199
|
-
activeRunIds: board?.activeRunIds ?? []
|
|
1200
|
-
},
|
|
1201
|
-
notes: []
|
|
1202
|
-
};
|
|
1619
|
+
parts.push(parts.length === 0 ? rendered : `${targetFieldName(field)}=${rendered}`);
|
|
1203
1620
|
}
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
if (titles.length === 0) return { error: "add requires at least one task" };
|
|
1208
|
-
const start = nextTaskId(board.tasks);
|
|
1209
|
-
const added = titles.map((title, index) => ({
|
|
1210
|
-
id: `t${start + index}`,
|
|
1211
|
-
title,
|
|
1212
|
-
status: "pending",
|
|
1213
|
-
origin: "agent"
|
|
1214
|
-
}));
|
|
1215
|
-
return { board: { ...board, tasks: [...board.tasks, ...added] }, notes: [] };
|
|
1216
|
-
}
|
|
1217
|
-
const target = board.tasks.find((task) => task.id === mutation.id);
|
|
1218
|
-
if (!target) return { error: `task ${mutation.id} not found on the board` };
|
|
1219
|
-
if (mutation.op === "block" && mutation.reason.trim().length === 0) {
|
|
1220
|
-
return { error: "block requires a reason so the ledger records why work stopped" };
|
|
1221
|
-
}
|
|
1222
|
-
if (mutation.op === "done") {
|
|
1223
|
-
if (mutation.evidence.trim().length === 0) {
|
|
1224
|
-
return {
|
|
1225
|
-
error: "done requires note as the evidence that the task actually finished (the command you ran, the file:line you verified). If the work did not happen, use block with a reason or drop it."
|
|
1226
|
-
};
|
|
1227
|
-
}
|
|
1228
|
-
if (target.status === "pending") {
|
|
1229
|
-
return {
|
|
1230
|
-
error: `task ${target.id} was never started, so it cannot be completed. Start it and do the work, or record the truth with block (reason) or drop.`
|
|
1231
|
-
};
|
|
1232
|
-
}
|
|
1621
|
+
for (const [field, value] of Object.entries(args)) {
|
|
1622
|
+
if (allowed.has(field)) continue;
|
|
1623
|
+
parts.push(`${targetFieldName(field)}=${summarizeUnlistedTargetValue(value)}`);
|
|
1233
1624
|
}
|
|
1234
|
-
|
|
1235
|
-
const tasks = board.tasks.map((task) => {
|
|
1236
|
-
if (task.id !== target.id) {
|
|
1237
|
-
if (mutation.op === "start" && task.status === "active") {
|
|
1238
|
-
notes.push(`parked ${task.id} back to pending (one task active at a time)`);
|
|
1239
|
-
return { ...task, status: "pending" };
|
|
1240
|
-
}
|
|
1241
|
-
return task;
|
|
1242
|
-
}
|
|
1243
|
-
return applyStatusMutation(task, mutation);
|
|
1244
|
-
});
|
|
1245
|
-
return { board: { ...board, tasks }, notes };
|
|
1246
|
-
}
|
|
1247
|
-
function applyStatusMutation(task, mutation) {
|
|
1248
|
-
switch (mutation.op) {
|
|
1249
|
-
case "start":
|
|
1250
|
-
return { ...task, status: "active" };
|
|
1251
|
-
case "done": {
|
|
1252
|
-
const done = { ...task, status: "completed", evidence: mutation.evidence.trim() };
|
|
1253
|
-
delete done.reason;
|
|
1254
|
-
return done;
|
|
1255
|
-
}
|
|
1256
|
-
case "block":
|
|
1257
|
-
return { ...task, status: "blocked", reason: mutation.reason.trim() };
|
|
1258
|
-
case "drop": {
|
|
1259
|
-
const dropped = { ...task, status: "cancelled" };
|
|
1260
|
-
if (mutation.reason?.trim()) dropped.reason = mutation.reason.trim();
|
|
1261
|
-
return dropped;
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
function createTaskBoardStore(deps = {}) {
|
|
1266
|
-
let cachedSessionId;
|
|
1267
|
-
let dirty = true;
|
|
1268
|
-
let board = null;
|
|
1269
|
-
const syncToSession = () => {
|
|
1270
|
-
const sessionId = deps.getSessionId?.() ?? null;
|
|
1271
|
-
if (!dirty && cachedSessionId === sessionId) return;
|
|
1272
|
-
dirty = false;
|
|
1273
|
-
cachedSessionId = sessionId;
|
|
1274
|
-
try {
|
|
1275
|
-
board = deps.readEntries ? foldTaskBoard(deps.readEntries()) : null;
|
|
1276
|
-
} catch {
|
|
1277
|
-
board = null;
|
|
1278
|
-
}
|
|
1279
|
-
};
|
|
1280
|
-
const persist = (next) => {
|
|
1281
|
-
try {
|
|
1282
|
-
deps.appendEntry?.(toTaskLedgerEntryFields(next, deps.now?.() ?? /* @__PURE__ */ new Date()));
|
|
1283
|
-
} catch {
|
|
1284
|
-
}
|
|
1285
|
-
};
|
|
1286
|
-
const mutationRequiresAcknowledgement = (current, mutation) => {
|
|
1287
|
-
if (mutation.op === "pick") return true;
|
|
1288
|
-
if (mutation.op === "plan") return current?.tasks.some(isOpenUserTask) ?? false;
|
|
1289
|
-
if (mutation.op !== "done") return false;
|
|
1290
|
-
return current?.tasks.some((task) => task.id === mutation.id && task.origin === "user") ?? false;
|
|
1291
|
-
};
|
|
1292
|
-
return {
|
|
1293
|
-
snapshot() {
|
|
1294
|
-
syncToSession();
|
|
1295
|
-
return board;
|
|
1296
|
-
},
|
|
1297
|
-
cachedSnapshot() {
|
|
1298
|
-
const sessionId = deps.getSessionId?.() ?? null;
|
|
1299
|
-
return !dirty && cachedSessionId === sessionId ? board : null;
|
|
1300
|
-
},
|
|
1301
|
-
historySnapshot() {
|
|
1302
|
-
syncToSession();
|
|
1303
|
-
try {
|
|
1304
|
-
return deps.readEntries ? foldSessionTaskHistory(deps.readEntries()) : [];
|
|
1305
|
-
} catch {
|
|
1306
|
-
return [];
|
|
1307
|
-
}
|
|
1308
|
-
},
|
|
1309
|
-
apply(mutation) {
|
|
1310
|
-
syncToSession();
|
|
1311
|
-
const result = applyMutation(board, mutation);
|
|
1312
|
-
if ("error" in result) return { ok: false, message: result.error };
|
|
1313
|
-
const needsBoardId = mutation.op === "plan" || result.board.boardId.length === 0;
|
|
1314
|
-
const nextBoard = needsBoardId ? { ...result.board, boardId: deps.createBoardId?.() ?? randomUUID() } : result.board;
|
|
1315
|
-
if (mutationRequiresAcknowledgement(board, mutation)) {
|
|
1316
|
-
if (!deps.appendEntry) {
|
|
1317
|
-
return { ok: false, message: "durable task-ledger persistence is unavailable for operator-linked work" };
|
|
1318
|
-
}
|
|
1319
|
-
try {
|
|
1320
|
-
deps.appendEntry(toTaskLedgerEntryFields(nextBoard, deps.now?.() ?? /* @__PURE__ */ new Date()));
|
|
1321
|
-
} catch (error) {
|
|
1322
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1323
|
-
return { ok: false, message: `could not persist operator-linked task board: ${message}` };
|
|
1324
|
-
}
|
|
1325
|
-
board = nextBoard;
|
|
1326
|
-
return { ok: true, board: nextBoard, notes: result.notes };
|
|
1327
|
-
}
|
|
1328
|
-
board = nextBoard;
|
|
1329
|
-
persist(nextBoard);
|
|
1330
|
-
return { ok: true, board: nextBoard, notes: result.notes };
|
|
1331
|
-
},
|
|
1332
|
-
attachRun(runId) {
|
|
1333
|
-
syncToSession();
|
|
1334
|
-
if (board === null || runId.length === 0 || board.activeRunIds.includes(runId)) return;
|
|
1335
|
-
board = { ...board, activeRunIds: [...board.activeRunIds, runId] };
|
|
1336
|
-
persist(board);
|
|
1337
|
-
},
|
|
1338
|
-
detachRun(runId) {
|
|
1339
|
-
syncToSession();
|
|
1340
|
-
if (board === null || !board.activeRunIds.includes(runId)) return;
|
|
1341
|
-
board = { ...board, activeRunIds: board.activeRunIds.filter((id) => id !== runId) };
|
|
1342
|
-
persist(board);
|
|
1343
|
-
},
|
|
1344
|
-
invalidate() {
|
|
1345
|
-
dirty = true;
|
|
1346
|
-
}
|
|
1347
|
-
};
|
|
1625
|
+
return sanitizeCallTargetText(parts.join(" \xB7 ")).slice(0, CALL_TARGET_MAX_CHARS);
|
|
1348
1626
|
}
|
|
1349
1627
|
|
|
1350
1628
|
// src/engine/antigravity/subprocess-runtime.ts
|
|
1351
1629
|
init_esm_shims();
|
|
1352
|
-
import { spawn } from "node:child_process";
|
|
1630
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
1353
1631
|
|
|
1354
1632
|
// src/engine/external-subprocess.ts
|
|
1355
1633
|
init_esm_shims();
|
|
@@ -1464,7 +1742,7 @@ async function readStdout(child, emit, state) {
|
|
|
1464
1742
|
}
|
|
1465
1743
|
function startAntigravityWorkerRun(input, emit) {
|
|
1466
1744
|
const args = buildAgyArgs(input);
|
|
1467
|
-
const child =
|
|
1745
|
+
const child = spawn2(ANTIGRAVITY_BINARY, args, {
|
|
1468
1746
|
cwd: process.cwd(),
|
|
1469
1747
|
env: process.env,
|
|
1470
1748
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -1519,7 +1797,7 @@ function startAntigravityWorkerRun(input, emit) {
|
|
|
1519
1797
|
|
|
1520
1798
|
// src/engine/claude/subprocess-runtime.ts
|
|
1521
1799
|
init_esm_shims();
|
|
1522
|
-
import { spawn as
|
|
1800
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
1523
1801
|
import { createInterface } from "node:readline";
|
|
1524
1802
|
|
|
1525
1803
|
// src/engine/claude/session-id.ts
|
|
@@ -1712,7 +1990,7 @@ async function readJsonLines(child, emit, state) {
|
|
|
1712
1990
|
}
|
|
1713
1991
|
function startClaudeCodeWorkerRun(input, emit) {
|
|
1714
1992
|
const args = buildClaudeCodeArgs(input);
|
|
1715
|
-
const child =
|
|
1993
|
+
const child = spawn3("claude", args, {
|
|
1716
1994
|
cwd: process.cwd(),
|
|
1717
1995
|
env: process.env,
|
|
1718
1996
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -1775,6 +2053,12 @@ function startClaudeCodeWorkerRun(input, emit) {
|
|
|
1775
2053
|
init_esm_shims();
|
|
1776
2054
|
var WORKER_RUNTIME_MEDIATES_CLIO_DISPATCH = false;
|
|
1777
2055
|
|
|
2056
|
+
// src/tools/builtin-tool-catalog.ts
|
|
2057
|
+
init_esm_shims();
|
|
2058
|
+
|
|
2059
|
+
// src/tools/bash.ts
|
|
2060
|
+
init_esm_shims();
|
|
2061
|
+
|
|
1778
2062
|
// src/tools/presentation.ts
|
|
1779
2063
|
init_esm_shims();
|
|
1780
2064
|
var FOLDED = { foldDefault: "folded", showDiffWhenFolded: false, failureExcerpt: true };
|
|
@@ -1827,8 +2111,215 @@ function toolPresentationPolicy(toolName, args) {
|
|
|
1827
2111
|
return TOOL_PRESENTATION[toolName] ?? FOLDED;
|
|
1828
2112
|
}
|
|
1829
2113
|
|
|
1830
|
-
// src/tools/
|
|
1831
|
-
|
|
2114
|
+
// src/tools/bash.ts
|
|
2115
|
+
var BASH_DISPLAY_MAX_BYTES = 16 * 1024;
|
|
2116
|
+
var BASH_OUTPUT_POLICIES = /* @__PURE__ */ new Set(["full", "bounded", "summary", "metadata-only"]);
|
|
2117
|
+
function bashContextDisposition(policy) {
|
|
2118
|
+
if (policy === "full") {
|
|
2119
|
+
return { mode: "full", maxBytes: BASH_DISPLAY_MAX_BYTES, downgradeExcerpt: "tail" };
|
|
2120
|
+
}
|
|
2121
|
+
if (policy === "summary") {
|
|
2122
|
+
return {
|
|
2123
|
+
mode: "summary",
|
|
2124
|
+
maxBytes: BASH_DISPLAY_MAX_BYTES,
|
|
2125
|
+
strategy: "diagnostic",
|
|
2126
|
+
redact: true
|
|
2127
|
+
};
|
|
2128
|
+
}
|
|
2129
|
+
if (policy === "metadata-only") return { mode: "metadata-only", maxBytes: BASH_DISPLAY_MAX_BYTES };
|
|
2130
|
+
return { mode: "bounded", maxBytes: BASH_DISPLAY_MAX_BYTES, excerpt: "tail" };
|
|
2131
|
+
}
|
|
2132
|
+
var BASH_DEFAULT_RESULT_DISPOSITION = {
|
|
2133
|
+
presentation: {
|
|
2134
|
+
...toolPresentationPolicy(ToolNames.Bash, void 0),
|
|
2135
|
+
maxBytes: BASH_DISPLAY_MAX_BYTES,
|
|
2136
|
+
overflow: "tail"
|
|
2137
|
+
},
|
|
2138
|
+
context: bashContextDisposition("bounded")
|
|
2139
|
+
};
|
|
2140
|
+
function normalizeBashArguments(args) {
|
|
2141
|
+
return args.output_policy === void 0 ? { ...args, output_policy: "bounded" } : args;
|
|
2142
|
+
}
|
|
2143
|
+
function bashOutputPolicy(args) {
|
|
2144
|
+
const value = args.output_policy;
|
|
2145
|
+
return typeof value === "string" && BASH_OUTPUT_POLICIES.has(value) ? value : null;
|
|
2146
|
+
}
|
|
2147
|
+
function resolveBashResultDisposition(args, declared = BASH_DEFAULT_RESULT_DISPOSITION) {
|
|
2148
|
+
const policy = bashOutputPolicy(args) ?? "bounded";
|
|
2149
|
+
const base = declared ?? BASH_DEFAULT_RESULT_DISPOSITION;
|
|
2150
|
+
return { presentation: base.presentation, context: bashContextDisposition(policy) };
|
|
2151
|
+
}
|
|
2152
|
+
function normalizedBashDisposition(policy) {
|
|
2153
|
+
return {
|
|
2154
|
+
presentation: { ...BASH_DEFAULT_RESULT_DISPOSITION.presentation, maxBytes: BASH_DISPLAY_MAX_BYTES },
|
|
2155
|
+
context: bashContextDisposition(policy)
|
|
2156
|
+
};
|
|
2157
|
+
}
|
|
2158
|
+
function shapeBashProgress(rawOutput, outputBytes, policy) {
|
|
2159
|
+
const disposition = normalizedBashDisposition(policy);
|
|
2160
|
+
let output;
|
|
2161
|
+
if (policy === "metadata-only") {
|
|
2162
|
+
output = `bash: running; captured ${outputBytes} bytes; stdout/stderr omitted by metadata-only policy`;
|
|
2163
|
+
} else if (policy === "summary") {
|
|
2164
|
+
output = deterministicDiagnosticSummary(rawOutput, BASH_DISPLAY_MAX_BYTES, true).text;
|
|
2165
|
+
} else {
|
|
2166
|
+
output = truncateTail(rawOutput, {
|
|
2167
|
+
maxLines: DEFAULT_MAX_LINES,
|
|
2168
|
+
maxBytes: disposition.context.maxBytes
|
|
2169
|
+
}).content;
|
|
2170
|
+
}
|
|
2171
|
+
return {
|
|
2172
|
+
kind: "ok",
|
|
2173
|
+
output,
|
|
2174
|
+
details: {
|
|
2175
|
+
resultSize: {
|
|
2176
|
+
bytes: outputBytes,
|
|
2177
|
+
shownBytes: byteLength(output),
|
|
2178
|
+
maxBytes: BASH_DISPLAY_MAX_BYTES,
|
|
2179
|
+
truncated: byteLength(rawOutput) > byteLength(output),
|
|
2180
|
+
policy
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
};
|
|
2184
|
+
}
|
|
2185
|
+
function bashResultDetails(result, rawOutput, outcome) {
|
|
2186
|
+
return {
|
|
2187
|
+
outcome,
|
|
2188
|
+
exitCode: result.exitCode,
|
|
2189
|
+
signal: result.signal,
|
|
2190
|
+
timedOut: result.timedOut,
|
|
2191
|
+
aborted: result.aborted,
|
|
2192
|
+
outputCapped: result.outputCapped,
|
|
2193
|
+
outputBytes: result.outputBytes,
|
|
2194
|
+
retainedBytes: byteLength(rawOutput),
|
|
2195
|
+
stdoutBytes: byteLength(result.stdout),
|
|
2196
|
+
stderrBytes: byteLength(result.stderr)
|
|
2197
|
+
};
|
|
2198
|
+
}
|
|
2199
|
+
var OBSERVE_COMMAND_PATTERN = /^\s*(?:cat|head|tail|ls|grep|rg|find)\b/;
|
|
2200
|
+
var OBSERVE_NUDGE_SESSION_LIMIT = 64;
|
|
2201
|
+
var observeNudgeSeenSessions = /* @__PURE__ */ new Set();
|
|
2202
|
+
function observeToolsNudge(command, sessionId) {
|
|
2203
|
+
if (!OBSERVE_COMMAND_PATTERN.test(command)) return "";
|
|
2204
|
+
const key = sessionId ?? "no-session";
|
|
2205
|
+
if (observeNudgeSeenSessions.has(key)) return "";
|
|
2206
|
+
if (observeNudgeSeenSessions.size >= OBSERVE_NUDGE_SESSION_LIMIT) {
|
|
2207
|
+
const oldest = observeNudgeSeenSessions.values().next().value;
|
|
2208
|
+
if (oldest !== void 0) observeNudgeSeenSessions.delete(oldest);
|
|
2209
|
+
}
|
|
2210
|
+
observeNudgeSeenSessions.add(key);
|
|
2211
|
+
return "\n\n[note: prefer the structured observe tools over shell file inspection: read pages files with offset/limit, ls lists directories, grep and find search, code_nav maps symbols. Their results are capped and continuable; keep bash for builds, git, and scripts.]";
|
|
2212
|
+
}
|
|
2213
|
+
var bashTool = {
|
|
2214
|
+
name: ToolNames.Bash,
|
|
2215
|
+
description: "Execute a bash command inside the session workspace. output_policy controls model context: bounded keeps the diagnostic tail and is the default; summary keeps deterministic redacted diagnostics; metadata-only keeps facts and retrieval; full is admitted only within the result budget.",
|
|
2216
|
+
parameters: typebox_exports.Object({
|
|
2217
|
+
command: typebox_exports.String({ description: "Bash command to execute." }),
|
|
2218
|
+
cwd: typebox_exports.Optional(
|
|
2219
|
+
typebox_exports.String({
|
|
2220
|
+
description: "Omit this. The command already runs at the session workspace root. Set it only to run in a subdirectory of that root, as a relative path; an absolute path outside the root is blocked."
|
|
2221
|
+
})
|
|
2222
|
+
),
|
|
2223
|
+
timeout_ms: typebox_exports.Optional(typebox_exports.Number({ description: "Timeout in milliseconds." })),
|
|
2224
|
+
output_policy: typebox_exports.Optional(
|
|
2225
|
+
typebox_exports.Union([typebox_exports.Literal("full"), typebox_exports.Literal("bounded"), typebox_exports.Literal("summary"), typebox_exports.Literal("metadata-only")], {
|
|
2226
|
+
description: "Model-context disposition. Omit for bounded tail output. Use summary for noisy runs, metadata-only when only status and retrieval matter, and full only for known-small output."
|
|
2227
|
+
})
|
|
2228
|
+
)
|
|
2229
|
+
}),
|
|
2230
|
+
baseActionClass: "execute",
|
|
2231
|
+
executionMode: "sequential",
|
|
2232
|
+
prepareArguments: normalizeBashArguments,
|
|
2233
|
+
resolveResultDisposition: resolveBashResultDisposition,
|
|
2234
|
+
async run(args, options) {
|
|
2235
|
+
args = normalizeBashArguments(args);
|
|
2236
|
+
if (typeof args.command !== "string" || args.command.length === 0) {
|
|
2237
|
+
return { kind: "error", message: "bash: missing command argument" };
|
|
2238
|
+
}
|
|
2239
|
+
const outputPolicy = bashOutputPolicy(args);
|
|
2240
|
+
if (outputPolicy === null) {
|
|
2241
|
+
return {
|
|
2242
|
+
kind: "error",
|
|
2243
|
+
message: "bash: output_policy must be one of full, bounded, summary, or metadata-only (omit it for bounded)",
|
|
2244
|
+
details: { outcome: "invalid-arguments", exitCode: null }
|
|
2245
|
+
};
|
|
2246
|
+
}
|
|
2247
|
+
const cwdArg = typeof args.cwd === "string" && args.cwd.length > 0 ? args.cwd : void 0;
|
|
2248
|
+
let cwd;
|
|
2249
|
+
try {
|
|
2250
|
+
cwd = resolveSafeCwd(cwdArg === void 0 ? void 0 : expandPath(cwdArg), process.cwd());
|
|
2251
|
+
} catch {
|
|
2252
|
+
return {
|
|
2253
|
+
kind: "error",
|
|
2254
|
+
message: `bash: cwd '${cwdArg}' escapes workspace root '${process.cwd()}'; use a typed tool or a project policy entry with explicit cwd`
|
|
2255
|
+
};
|
|
2256
|
+
}
|
|
2257
|
+
const timeout = typeof args.timeout_ms === "number" && args.timeout_ms > 0 ? args.timeout_ms : 3e5;
|
|
2258
|
+
try {
|
|
2259
|
+
const runOptions = {
|
|
2260
|
+
cwd,
|
|
2261
|
+
timeoutMs: timeout,
|
|
2262
|
+
...options?.signal === void 0 ? {} : { signal: options.signal }
|
|
2263
|
+
};
|
|
2264
|
+
if (options?.onUpdate !== void 0) {
|
|
2265
|
+
runOptions.onUpdate = (progress) => {
|
|
2266
|
+
options.onUpdate?.(shapeBashProgress(combineBashOutput(progress), progress.outputBytes, outputPolicy));
|
|
2267
|
+
};
|
|
2268
|
+
}
|
|
2269
|
+
const result = await runBashCommand(args.command, runOptions);
|
|
2270
|
+
const { error, aborted, timedOut, outputCapped } = result;
|
|
2271
|
+
const rawOutput = combineBashOutput(result);
|
|
2272
|
+
const output = rawOutput.trim();
|
|
2273
|
+
if (aborted) {
|
|
2274
|
+
const status = "bash: command aborted";
|
|
2275
|
+
return {
|
|
2276
|
+
kind: "error",
|
|
2277
|
+
message: output.length > 0 ? `${output}
|
|
2278
|
+
|
|
2279
|
+
${status}` : status,
|
|
2280
|
+
details: bashResultDetails(result, rawOutput, "abort")
|
|
2281
|
+
};
|
|
2282
|
+
}
|
|
2283
|
+
if (timedOut) {
|
|
2284
|
+
const status = `bash: command timed out after ${timeout}ms`;
|
|
2285
|
+
return {
|
|
2286
|
+
kind: "error",
|
|
2287
|
+
message: output.length > 0 ? `${output}
|
|
2288
|
+
|
|
2289
|
+
${status}` : status,
|
|
2290
|
+
details: bashResultDetails(result, rawOutput, "timeout")
|
|
2291
|
+
};
|
|
2292
|
+
}
|
|
2293
|
+
if (outputCapped) {
|
|
2294
|
+
const status = `bash: command output exceeded ${BASH_HARD_CAP_BYTES} bytes and was stopped`;
|
|
2295
|
+
return {
|
|
2296
|
+
kind: "error",
|
|
2297
|
+
message: output.length > 0 ? `${output}
|
|
2298
|
+
|
|
2299
|
+
${status}` : status,
|
|
2300
|
+
details: bashResultDetails(result, rawOutput, "output-cap")
|
|
2301
|
+
};
|
|
2302
|
+
}
|
|
2303
|
+
if (error) {
|
|
2304
|
+
const code = typeof error.code === "number" ? error.code : error.code;
|
|
2305
|
+
const status = `bash: command failed (exit ${code ?? "?"})`;
|
|
2306
|
+
const message = output.length > 0 ? `${output}
|
|
2307
|
+
|
|
2308
|
+
${status}` : `${status}: ${error.message}`;
|
|
2309
|
+
return { kind: "error", message, details: bashResultDetails(result, rawOutput, "nonzero") };
|
|
2310
|
+
}
|
|
2311
|
+
const body = rawOutput.length > 0 ? rawOutput : "(no output)";
|
|
2312
|
+
return {
|
|
2313
|
+
kind: "ok",
|
|
2314
|
+
output: `${body}${observeToolsNudge(args.command, options?.sessionId)}`,
|
|
2315
|
+
details: bashResultDetails(result, rawOutput, "success")
|
|
2316
|
+
};
|
|
2317
|
+
} catch (err) {
|
|
2318
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2319
|
+
return { kind: "error", message: `bash: ${msg}` };
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
};
|
|
1832
2323
|
|
|
1833
2324
|
// src/tools/read.ts
|
|
1834
2325
|
init_esm_shims();
|
|
@@ -2031,7 +2522,7 @@ var TOOL_METADATA = {
|
|
|
2031
2522
|
"Use a narrower query or scope to inspect omitted content."
|
|
2032
2523
|
),
|
|
2033
2524
|
costLatency: "local_fast",
|
|
2034
|
-
promptHint: 'Call context with scope="skills" to list installed and marketplace skills; when one matches the task, or the operator names a skill or asks how one works, suggest the operator run /skill <name> (a marketplace skill is offered for install) and never load it uninvited. When the user message carries a skill request, first load that skill via context (scope="skills", name=<skill>) before doing anything else.'
|
|
2525
|
+
promptHint: 'Call context with scope="skills" to list installed and marketplace skills; when one matches the task, or the operator names a skill or asks how one works, suggest the operator run /skill <name> (a marketplace skill is offered for install) and never load it uninvited. When the user message carries a skill request, first load that skill via context (scope="skills", name=<skill>) before doing anything else. When an [evicted ...] marker names content you need, recall it with context(scope="recall", ref=...); re-read the file only when the marker says it changed.'
|
|
2035
2526
|
},
|
|
2036
2527
|
[ToolNames.CredentialPresent]: {
|
|
2037
2528
|
objective: "Check whether a credential key is present without returning its value.",
|
|
@@ -2059,15 +2550,18 @@ var TOOL_METADATA = {
|
|
|
2059
2550
|
resultSizePolicy: exactMutationPolicy,
|
|
2060
2551
|
costLatency: "local_fast"
|
|
2061
2552
|
},
|
|
2062
|
-
// EXECUTE: the safe-exec spine (
|
|
2553
|
+
// EXECUTE: the safe-exec spine (canonical shaping offloads Bash overflow).
|
|
2063
2554
|
[ToolNames.Bash]: {
|
|
2064
2555
|
objective: "Execute an explicit shell command when narrower tools are insufficient.",
|
|
2065
2556
|
uiLabel: "Shell",
|
|
2066
2557
|
retrySafety: "unknown",
|
|
2067
|
-
resultSizePolicy:
|
|
2068
|
-
"Use a narrower command or a dedicated verification/read/search tool to inspect omitted output."
|
|
2069
|
-
|
|
2070
|
-
|
|
2558
|
+
resultSizePolicy: {
|
|
2559
|
+
...summaryPolicy("Use a narrower command or a dedicated verification/read/search tool to inspect omitted output."),
|
|
2560
|
+
offloadMaxBytes: BASH_HARD_CAP_BYTES
|
|
2561
|
+
},
|
|
2562
|
+
resultDisposition: BASH_DEFAULT_RESULT_DISPOSITION,
|
|
2563
|
+
costLatency: "local_slow",
|
|
2564
|
+
promptHint: "Bash output_policy defaults to bounded diagnostic tail. Use summary for noisy commands, metadata-only when only outcome and retrieval matter, and full only when output is known to fit the bounded result budget."
|
|
2071
2565
|
},
|
|
2072
2566
|
[ToolNames.Git]: {
|
|
2073
2567
|
objective: "Read-only git inspection: status, diff, or log.",
|
|
@@ -2548,6 +3042,7 @@ var KNOWN_KEYS = /* @__PURE__ */ new Set([
|
|
|
2548
3042
|
"target",
|
|
2549
3043
|
"model",
|
|
2550
3044
|
"thinkingLevel",
|
|
3045
|
+
"budget",
|
|
2551
3046
|
"node",
|
|
2552
3047
|
"routingIntent",
|
|
2553
3048
|
"failover",
|
|
@@ -2578,12 +3073,12 @@ var VALID_COMPETE_STANCES = new Set(COMPETE_STANCES);
|
|
|
2578
3073
|
var VALID_THINKING = new Set(THINKING_LEVELS);
|
|
2579
3074
|
var VALID_REQUEST_ORIGINS = /* @__PURE__ */ new Set(["user", "agent", "internal"]);
|
|
2580
3075
|
var VALID_FAILOVER_MODES = /* @__PURE__ */ new Set(["none", "approved", "automatic"]);
|
|
2581
|
-
function
|
|
3076
|
+
function isPlainObject3(value) {
|
|
2582
3077
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2583
3078
|
}
|
|
2584
3079
|
function validateJobSpec(spec) {
|
|
2585
3080
|
const errors = [];
|
|
2586
|
-
if (!
|
|
3081
|
+
if (!isPlainObject3(spec)) {
|
|
2587
3082
|
return { ok: false, errors: ["spec must be an object"] };
|
|
2588
3083
|
}
|
|
2589
3084
|
for (const key of Object.keys(spec)) {
|
|
@@ -2672,7 +3167,7 @@ function validateJobSpec(spec) {
|
|
|
2672
3167
|
errors.push("failover automatic is not allowed on a plan-approved dispatch");
|
|
2673
3168
|
}
|
|
2674
3169
|
if ("plannedNode" in spec && spec.plannedNode !== void 0) {
|
|
2675
|
-
if (!
|
|
3170
|
+
if (!isPlainObject3(spec.plannedNode)) {
|
|
2676
3171
|
errors.push("plannedNode must be an object");
|
|
2677
3172
|
} else {
|
|
2678
3173
|
for (const key of Object.keys(spec.plannedNode)) {
|
|
@@ -2693,7 +3188,7 @@ function validateJobSpec(spec) {
|
|
|
2693
3188
|
}
|
|
2694
3189
|
}
|
|
2695
3190
|
if ("protectedArtifactRemap" in spec && spec.protectedArtifactRemap !== void 0) {
|
|
2696
|
-
if (!
|
|
3191
|
+
if (!isPlainObject3(spec.protectedArtifactRemap) || Object.keys(spec.protectedArtifactRemap).some((key) => key !== "sourceRoot" && key !== "workerRoot") || typeof spec.protectedArtifactRemap.sourceRoot !== "string" || !path2.isAbsolute(spec.protectedArtifactRemap.sourceRoot) || typeof spec.protectedArtifactRemap.workerRoot !== "string" || !path2.isAbsolute(spec.protectedArtifactRemap.workerRoot)) {
|
|
2697
3192
|
errors.push("protectedArtifactRemap must carry absolute sourceRoot and workerRoot paths");
|
|
2698
3193
|
}
|
|
2699
3194
|
}
|
|
@@ -2707,6 +3202,14 @@ function validateJobSpec(spec) {
|
|
|
2707
3202
|
errors.push("thinkingLevel must be one of: off|minimal|low|medium|high|xhigh");
|
|
2708
3203
|
}
|
|
2709
3204
|
}
|
|
3205
|
+
let budget;
|
|
3206
|
+
if ("budget" in spec && spec.budget !== void 0) {
|
|
3207
|
+
try {
|
|
3208
|
+
budget = cloneDispatchBudgetRequest(spec.budget);
|
|
3209
|
+
} catch (error) {
|
|
3210
|
+
errors.push(error instanceof Error ? error.message : String(error));
|
|
3211
|
+
}
|
|
3212
|
+
}
|
|
2710
3213
|
if ("requiredCapabilities" in spec && spec.requiredCapabilities !== void 0) {
|
|
2711
3214
|
if (!Array.isArray(spec.requiredCapabilities) || spec.requiredCapabilities.some((c) => typeof c !== "string")) {
|
|
2712
3215
|
errors.push("requiredCapabilities must be a string[]");
|
|
@@ -2833,6 +3336,7 @@ function validateJobSpec(spec) {
|
|
|
2833
3336
|
out.reroutes = spec.reroutes.map((hop) => ({ ...hop }));
|
|
2834
3337
|
}
|
|
2835
3338
|
if (typeof spec.thinkingLevel === "string") out.thinkingLevel = spec.thinkingLevel;
|
|
3339
|
+
if (budget !== void 0) out.budget = budget;
|
|
2836
3340
|
if (Array.isArray(spec.requiredCapabilities)) {
|
|
2837
3341
|
out.requiredCapabilities = spec.requiredCapabilities.map((c) => String(c));
|
|
2838
3342
|
}
|
|
@@ -2869,7 +3373,7 @@ function isValidPredecessorHandoffs(value) {
|
|
|
2869
3373
|
if (!Array.isArray(value) || value.length > EXECUTION_HANDOFF_MAX_ITEMS || Buffer.byteLength(JSON.stringify(value), "utf8") > EXECUTION_HANDOFF_MAX_TEXT_BYTES * 2)
|
|
2870
3374
|
return false;
|
|
2871
3375
|
return value.every((candidate) => {
|
|
2872
|
-
if (!
|
|
3376
|
+
if (!isPlainObject3(candidate)) return false;
|
|
2873
3377
|
const fields = [
|
|
2874
3378
|
candidate.stepId,
|
|
2875
3379
|
candidate.assignmentId,
|
|
@@ -2881,14 +3385,14 @@ function isValidPredecessorHandoffs(value) {
|
|
|
2881
3385
|
});
|
|
2882
3386
|
}
|
|
2883
3387
|
function isValidPipelineInput(value) {
|
|
2884
|
-
if (!
|
|
3388
|
+
if (!isPlainObject3(value)) return false;
|
|
2885
3389
|
const fromRunOk = value.fromRunId === null || typeof value.fromRunId === "string" && value.fromRunId.length > 0;
|
|
2886
3390
|
const positionOk = typeof value.position === "number" && Number.isInteger(value.position) && value.position >= 1;
|
|
2887
3391
|
const textOk = typeof value.text === "string";
|
|
2888
3392
|
return fromRunOk && positionOk && textOk;
|
|
2889
3393
|
}
|
|
2890
3394
|
function isValidReroute(value) {
|
|
2891
|
-
if (!
|
|
3395
|
+
if (!isPlainObject3(value)) return false;
|
|
2892
3396
|
const attemptOk = typeof value.attempt === "number" && Number.isInteger(value.attempt) && value.attempt >= 1;
|
|
2893
3397
|
const fromOk = typeof value.fromNode === "string" && value.fromNode.length > 0;
|
|
2894
3398
|
const toOk = typeof value.toNode === "string";
|
|
@@ -2896,7 +3400,7 @@ function isValidReroute(value) {
|
|
|
2896
3400
|
return attemptOk && fromOk && toOk && reasonOk;
|
|
2897
3401
|
}
|
|
2898
3402
|
function isValidFailoverCandidate(value) {
|
|
2899
|
-
if (!
|
|
3403
|
+
if (!isPlainObject3(value)) return false;
|
|
2900
3404
|
if (Object.keys(value).some((key) => key !== "agentId" && key !== "target" && key !== "model" && key !== "node")) {
|
|
2901
3405
|
return false;
|
|
2902
3406
|
}
|
|
@@ -2905,26 +3409,26 @@ function isValidFailoverCandidate(value) {
|
|
|
2905
3409
|
);
|
|
2906
3410
|
}
|
|
2907
3411
|
function isValidPlannedNode(value) {
|
|
2908
|
-
if (!
|
|
3412
|
+
if (!isPlainObject3(value) || typeof value.id !== "string" || value.id.trim().length === 0) return false;
|
|
2909
3413
|
if (value.kind === "local") return value.host === void 0;
|
|
2910
3414
|
return value.kind === "ssh" && typeof value.host === "string" && value.host.trim().length > 0;
|
|
2911
3415
|
}
|
|
2912
3416
|
function isValidProtectedArtifactRemap(value) {
|
|
2913
|
-
return
|
|
3417
|
+
return isPlainObject3(value) && typeof value.sourceRoot === "string" && path2.isAbsolute(value.sourceRoot) && typeof value.workerRoot === "string" && path2.isAbsolute(value.workerRoot);
|
|
2914
3418
|
}
|
|
2915
3419
|
var VALID_GATE_ROLES = /* @__PURE__ */ new Set(["builder", "reviewer", "candidate", "judge"]);
|
|
2916
3420
|
var VALID_GATE_VERDICTS = /* @__PURE__ */ new Set(["pass", "fail", "revise"]);
|
|
2917
3421
|
var VALID_PLAN_TOPOLOGIES = /* @__PURE__ */ new Set(["parallel", "sequential", "pipeline", "review", "compete", "detached", "fleet"]);
|
|
2918
3422
|
var VALID_PLAN_APPROVALS = /* @__PURE__ */ new Set(["operator", "full-auto"]);
|
|
2919
3423
|
function isValidGate(value) {
|
|
2920
|
-
if (!
|
|
3424
|
+
if (!isPlainObject3(value)) return false;
|
|
2921
3425
|
if (typeof value.role !== "string" || !VALID_GATE_ROLES.has(value.role)) return false;
|
|
2922
3426
|
if (typeof value.group !== "string" || value.group.length === 0) return false;
|
|
2923
3427
|
if (typeof value.cycle !== "number" || !Number.isInteger(value.cycle) || value.cycle < 1) return false;
|
|
2924
3428
|
if (value.subjects !== void 0) {
|
|
2925
3429
|
if (!Array.isArray(value.subjects)) return false;
|
|
2926
3430
|
for (const subject of value.subjects) {
|
|
2927
|
-
if (!
|
|
3431
|
+
if (!isPlainObject3(subject)) return false;
|
|
2928
3432
|
if (typeof subject.runId !== "string" || subject.runId.length === 0) return false;
|
|
2929
3433
|
if (subject.digest !== null && typeof subject.digest !== "string") return false;
|
|
2930
3434
|
}
|
|
@@ -2944,13 +3448,13 @@ function cloneGate(gate) {
|
|
|
2944
3448
|
};
|
|
2945
3449
|
}
|
|
2946
3450
|
function isValidPlan(value) {
|
|
2947
|
-
if (!
|
|
3451
|
+
if (!isPlainObject3(value)) return false;
|
|
2948
3452
|
if (typeof value.hash !== "string" || value.hash.length === 0) return false;
|
|
2949
3453
|
if (typeof value.topology !== "string" || !VALID_PLAN_TOPOLOGIES.has(value.topology)) return false;
|
|
2950
3454
|
if (typeof value.taskCount !== "number" || !Number.isInteger(value.taskCount) || value.taskCount < 1) return false;
|
|
2951
3455
|
if (typeof value.approval !== "string" || !VALID_PLAN_APPROVALS.has(value.approval)) return false;
|
|
2952
3456
|
if (value.source !== null) {
|
|
2953
|
-
if (!
|
|
3457
|
+
if (!isPlainObject3(value.source) || value.source.kind !== "scout-transition" || typeof value.source.runId !== "string" || value.source.runId.length === 0 || typeof value.source.receiptDigest !== "string" || !/^[0-9a-f]{64}$/u.test(value.source.receiptDigest) || typeof value.source.executionPlanHash !== "string" || !/^[0-9a-f]{64}$/u.test(value.source.executionPlanHash))
|
|
2954
3458
|
return false;
|
|
2955
3459
|
}
|
|
2956
3460
|
if (value.approvalRequestId !== void 0 && (typeof value.approvalRequestId !== "string" || value.approvalRequestId.length === 0)) {
|
|
@@ -2965,7 +3469,7 @@ function isValidPlan(value) {
|
|
|
2965
3469
|
return true;
|
|
2966
3470
|
}
|
|
2967
3471
|
function isValidLineage(value) {
|
|
2968
|
-
if (!
|
|
3472
|
+
if (!isPlainObject3(value)) return false;
|
|
2969
3473
|
const parentOk = value.parentRunId === null || typeof value.parentRunId === "string" && value.parentRunId.length > 0;
|
|
2970
3474
|
const rootOk = typeof value.rootRunId === "string" && value.rootRunId.length > 0;
|
|
2971
3475
|
const attemptOk = typeof value.attempt === "number" && Number.isInteger(value.attempt) && value.attempt >= 0;
|
|
@@ -3180,9 +3684,10 @@ function finishDecision(decision) {
|
|
|
3180
3684
|
if (decision.kind === "ask") return "permission_requested";
|
|
3181
3685
|
return "blocked";
|
|
3182
3686
|
}
|
|
3183
|
-
function emitToolFinish(emit, mapped, startedAtClock, decision, outcome, reason, reasonCode) {
|
|
3687
|
+
function emitToolFinish(emit, mapped, startedAtClock, decision, outcome, reason, reasonCode, toolCallId) {
|
|
3184
3688
|
const event = {
|
|
3185
3689
|
tool: mapped.clioToolName,
|
|
3690
|
+
...toolCallId !== void 0 ? { toolCallId } : {},
|
|
3186
3691
|
posture: "operating",
|
|
3187
3692
|
durationMs: Math.round(performance.now() - startedAtClock),
|
|
3188
3693
|
outcome,
|
|
@@ -3200,10 +3705,14 @@ function emitClaudeToolPermissionDecision(input) {
|
|
|
3200
3705
|
const startedAt = Date.now();
|
|
3201
3706
|
const startedAtClock = performance.now();
|
|
3202
3707
|
const decision = evaluateClaudeToolPermission(input);
|
|
3708
|
+
const toolCallId = input.toolCallId?.trim() ? input.toolCallId : void 0;
|
|
3709
|
+
const action = describeCallAction(decision.mapped.clioToolName, decision.mapped.args);
|
|
3203
3710
|
const start = {
|
|
3204
3711
|
tool: decision.mapped.clioToolName,
|
|
3712
|
+
...toolCallId !== void 0 ? { toolCallId } : {},
|
|
3205
3713
|
posture: "operating",
|
|
3206
|
-
startedAt
|
|
3714
|
+
startedAt,
|
|
3715
|
+
...action !== null ? { action } : {}
|
|
3207
3716
|
};
|
|
3208
3717
|
input.emit({ type: "clio_tool_start", payload: start });
|
|
3209
3718
|
if (decision.kind === "allow") {
|
|
@@ -3214,7 +3723,8 @@ function emitClaudeToolPermissionDecision(input) {
|
|
|
3214
3723
|
decision.decision,
|
|
3215
3724
|
"ok",
|
|
3216
3725
|
decision.reason,
|
|
3217
|
-
decision.reasonCode
|
|
3726
|
+
decision.reasonCode,
|
|
3727
|
+
toolCallId
|
|
3218
3728
|
);
|
|
3219
3729
|
return decision;
|
|
3220
3730
|
}
|
|
@@ -3237,7 +3747,8 @@ function emitClaudeToolPermissionDecision(input) {
|
|
|
3237
3747
|
decision.decision,
|
|
3238
3748
|
"blocked",
|
|
3239
3749
|
decision.reason,
|
|
3240
|
-
decision.reasonCode
|
|
3750
|
+
decision.reasonCode,
|
|
3751
|
+
toolCallId
|
|
3241
3752
|
);
|
|
3242
3753
|
return decision;
|
|
3243
3754
|
}
|
|
@@ -3419,6 +3930,11 @@ export {
|
|
|
3419
3930
|
responseSchemaConflictsWithTools,
|
|
3420
3931
|
UnsupportedResponseSchemaError,
|
|
3421
3932
|
isResponseSchemaRejection,
|
|
3933
|
+
redactSecretString,
|
|
3934
|
+
redactToolArgs,
|
|
3935
|
+
sanitizeCallTargetText,
|
|
3936
|
+
describeCallAction,
|
|
3937
|
+
describeCallTarget,
|
|
3422
3938
|
TOOL_PROFILE_NAMES,
|
|
3423
3939
|
isToolProfileName,
|
|
3424
3940
|
assertToolProfileEnforceable,
|
|
@@ -3433,8 +3949,11 @@ export {
|
|
|
3433
3949
|
emitClaudeToolPermissionDecision,
|
|
3434
3950
|
coerceToolInput,
|
|
3435
3951
|
WORKER_RUNTIME_MEDIATES_CLIO_DISPATCH,
|
|
3952
|
+
combineBashOutput,
|
|
3953
|
+
runBashCommand,
|
|
3436
3954
|
classifyResourceRead,
|
|
3437
3955
|
toolPresentationPolicy,
|
|
3956
|
+
bashTool,
|
|
3438
3957
|
readMaxBytes,
|
|
3439
3958
|
readTool,
|
|
3440
3959
|
toolPromptHintsForNames,
|
|
@@ -3461,6 +3980,13 @@ export {
|
|
|
3461
3980
|
AGENT_LEDGER_PROMPT_MAX_CHARS,
|
|
3462
3981
|
claimConflicts,
|
|
3463
3982
|
renderAgentLedger,
|
|
3983
|
+
cloneDispatchBudgetRequest,
|
|
3984
|
+
resolveToolBudgetEnvelope,
|
|
3985
|
+
formatBudgetPolicy,
|
|
3986
|
+
formatBudgetRequest,
|
|
3987
|
+
formatEffectiveBudget,
|
|
3988
|
+
formatBudgetReasons,
|
|
3989
|
+
cloneRunToolBudgetEnvelope,
|
|
3464
3990
|
REVIEWER_GATE_PROMPT,
|
|
3465
3991
|
JUDGE_GATE_PROMPT,
|
|
3466
3992
|
COMPETE_STANCES,
|
|
@@ -3472,11 +3998,6 @@ export {
|
|
|
3472
3998
|
runKindSupportsLiveSteering,
|
|
3473
3999
|
projectExecutionHandoffs,
|
|
3474
4000
|
DISPATCH_BRIEFING_MAX_BYTES,
|
|
3475
|
-
validateJobSpec
|
|
3476
|
-
isSessionHeader,
|
|
3477
|
-
isSessionEntry,
|
|
3478
|
-
taskBoardCounts,
|
|
3479
|
-
foldSessionTaskHistory,
|
|
3480
|
-
createTaskBoardStore
|
|
4001
|
+
validateJobSpec
|
|
3481
4002
|
};
|
|
3482
|
-
//# sourceMappingURL=chunk-
|
|
4003
|
+
//# sourceMappingURL=chunk-XXQNGV4M.js.map
|