@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
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import type { ActionClass } from "./action-classifier.js";
|
|
2
|
+
import type { AutonomyExposure } from "./autonomy.js";
|
|
3
|
+
|
|
4
|
+
/** Closed consequence categories used only to explain an already-made decision request. */
|
|
5
|
+
export const DECISION_TIERS = ["conversation", "workspace", "outward", "safety-net", "system", "worker"] as const;
|
|
6
|
+
|
|
7
|
+
export type DecisionTier = (typeof DECISION_TIERS)[number];
|
|
8
|
+
export type DecisionSemanticToken = "accent" | "action" | "warning";
|
|
9
|
+
export type DecisionRequestKind = "question" | "permission";
|
|
10
|
+
export type DecisionAffectedScope = "conversation" | "workspace" | "outward" | "system";
|
|
11
|
+
export type DecisionReversibility = "reversible" | "limited" | "unknown";
|
|
12
|
+
export type DecisionAuthorityEffect = "records-answer" | "grants-once";
|
|
13
|
+
export type DecisionActionId = "record-answer" | "cancel" | "approve-once" | "deny" | "stop";
|
|
14
|
+
|
|
15
|
+
export type DecisionAxis =
|
|
16
|
+
| { kind: "answer" }
|
|
17
|
+
| { kind: "autonomy"; level: string }
|
|
18
|
+
| { kind: "safety-net"; ruleId: string };
|
|
19
|
+
|
|
20
|
+
export type DecisionOrigin = { kind: "main" } | { kind: "worker"; agentId: string; runId: string };
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Facts the host has already authenticated or derived from enforced policy.
|
|
24
|
+
* No model-authored title, question, reason, summary, or option label belongs
|
|
25
|
+
* here, so prose has no path to the tier selection.
|
|
26
|
+
*/
|
|
27
|
+
export interface TrustedDecisionFacts {
|
|
28
|
+
requestKind: DecisionRequestKind;
|
|
29
|
+
axis: DecisionAxis;
|
|
30
|
+
exposure: AutonomyExposure;
|
|
31
|
+
affectedScope: DecisionAffectedScope;
|
|
32
|
+
reversibility: DecisionReversibility;
|
|
33
|
+
origin: DecisionOrigin;
|
|
34
|
+
authorityEffect: DecisionAuthorityEffect;
|
|
35
|
+
tool?: string;
|
|
36
|
+
actionClass?: ActionClass;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface DecisionPresentationAction {
|
|
40
|
+
id: DecisionActionId;
|
|
41
|
+
label: string;
|
|
42
|
+
consequence: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* This projection contains display data only. Registry admission and interview
|
|
47
|
+
* settlement never consume it, and it contains no allow, deny, or autonomy
|
|
48
|
+
* disposition that an execution layer could mistake for authority.
|
|
49
|
+
*/
|
|
50
|
+
export interface DecisionPresentation {
|
|
51
|
+
tier: DecisionTier;
|
|
52
|
+
tierLabel: string;
|
|
53
|
+
title: string;
|
|
54
|
+
semanticToken: DecisionSemanticToken;
|
|
55
|
+
authorizationCopy: string;
|
|
56
|
+
consequenceCopy: string;
|
|
57
|
+
reversibilityCopy: string;
|
|
58
|
+
requestedByCopy: string;
|
|
59
|
+
requiredActions: ReadonlyArray<DecisionPresentationAction>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const ACTION_CLASSES = new Set<ActionClass>([
|
|
63
|
+
"read",
|
|
64
|
+
"write",
|
|
65
|
+
"execute",
|
|
66
|
+
"dispatch",
|
|
67
|
+
"system_modify",
|
|
68
|
+
"git_destructive",
|
|
69
|
+
"unknown",
|
|
70
|
+
]);
|
|
71
|
+
|
|
72
|
+
/** Unknown or malformed action classes classify conservatively as unknown. */
|
|
73
|
+
export function decisionActionClass(value: unknown): ActionClass {
|
|
74
|
+
return typeof value === "string" && ACTION_CLASSES.has(value as ActionClass) ? (value as ActionClass) : "unknown";
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function actionConsequence(actionClass: ActionClass): {
|
|
78
|
+
affectedScope: DecisionAffectedScope;
|
|
79
|
+
reversibility: DecisionReversibility;
|
|
80
|
+
} {
|
|
81
|
+
switch (actionClass) {
|
|
82
|
+
case "read":
|
|
83
|
+
return { affectedScope: "workspace", reversibility: "reversible" };
|
|
84
|
+
case "write":
|
|
85
|
+
return { affectedScope: "workspace", reversibility: "reversible" };
|
|
86
|
+
case "execute":
|
|
87
|
+
case "dispatch":
|
|
88
|
+
return { affectedScope: "workspace", reversibility: "limited" };
|
|
89
|
+
case "system_modify":
|
|
90
|
+
case "git_destructive":
|
|
91
|
+
case "unknown":
|
|
92
|
+
return { affectedScope: "system", reversibility: "unknown" };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function decisionFactsForPermission(input: {
|
|
97
|
+
tool: string;
|
|
98
|
+
actionClass: ActionClass;
|
|
99
|
+
axis: Exclude<DecisionAxis, { kind: "answer" }>;
|
|
100
|
+
origin: DecisionOrigin;
|
|
101
|
+
exposure?: AutonomyExposure;
|
|
102
|
+
}): TrustedDecisionFacts {
|
|
103
|
+
const exposure = input.exposure ?? "local";
|
|
104
|
+
const consequence = actionConsequence(input.actionClass);
|
|
105
|
+
return {
|
|
106
|
+
requestKind: "permission",
|
|
107
|
+
axis: input.axis,
|
|
108
|
+
exposure,
|
|
109
|
+
affectedScope: exposure === "outward" ? "outward" : consequence.affectedScope,
|
|
110
|
+
reversibility: exposure === "outward" ? "limited" : consequence.reversibility,
|
|
111
|
+
origin: input.origin,
|
|
112
|
+
authorityEffect: "grants-once",
|
|
113
|
+
tool: input.tool,
|
|
114
|
+
actionClass: input.actionClass,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function decisionFactsForAnswer(exposure: AutonomyExposure): TrustedDecisionFacts {
|
|
119
|
+
return {
|
|
120
|
+
requestKind: "question",
|
|
121
|
+
axis: { kind: "answer" },
|
|
122
|
+
exposure,
|
|
123
|
+
affectedScope: exposure === "outward" ? "outward" : "conversation",
|
|
124
|
+
reversibility: exposure === "outward" ? "limited" : "reversible",
|
|
125
|
+
origin: { kind: "main" },
|
|
126
|
+
authorityEffect: "records-answer",
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function classifyTier(facts: TrustedDecisionFacts): DecisionTier {
|
|
131
|
+
if (facts.origin.kind === "worker") return "worker";
|
|
132
|
+
if (facts.affectedScope === "system") return "system";
|
|
133
|
+
if (facts.exposure === "outward" || facts.affectedScope === "outward") return "outward";
|
|
134
|
+
if (facts.axis.kind === "safety-net") return "safety-net";
|
|
135
|
+
if (facts.authorityEffect === "grants-once") return "workspace";
|
|
136
|
+
return "conversation";
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function tierIdentity(tier: DecisionTier): {
|
|
140
|
+
tierLabel: string;
|
|
141
|
+
title: string;
|
|
142
|
+
semanticToken: DecisionSemanticToken;
|
|
143
|
+
} {
|
|
144
|
+
switch (tier) {
|
|
145
|
+
case "conversation":
|
|
146
|
+
return { tierLabel: "Conversational answer", title: "Answer a question", semanticToken: "accent" };
|
|
147
|
+
case "workspace":
|
|
148
|
+
return { tierLabel: "Workspace authority", title: "Approve workspace action", semanticToken: "action" };
|
|
149
|
+
case "outward":
|
|
150
|
+
return { tierLabel: "Outward consequence", title: "Confirm outward consequence", semanticToken: "warning" };
|
|
151
|
+
case "safety-net":
|
|
152
|
+
return { tierLabel: "Safety-net confirmation", title: "Safety-net confirmation", semanticToken: "warning" };
|
|
153
|
+
case "system":
|
|
154
|
+
return { tierLabel: "System change", title: "Approve system change", semanticToken: "warning" };
|
|
155
|
+
case "worker":
|
|
156
|
+
return { tierLabel: "Worker escalation", title: "Worker needs approval", semanticToken: "action" };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function requestedByCopy(facts: TrustedDecisionFacts): string {
|
|
161
|
+
const requester =
|
|
162
|
+
facts.origin.kind === "worker" ? `worker ${facts.origin.agentId} (run ${facts.origin.runId})` : "main agent";
|
|
163
|
+
if (facts.axis.kind === "answer") return requester;
|
|
164
|
+
if (facts.axis.kind === "safety-net") return `${requester} through safety-net rail ${facts.axis.ruleId}`;
|
|
165
|
+
return `${requester} through autonomy level (${facts.axis.level})`;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function authorizationCopy(facts: TrustedDecisionFacts): string {
|
|
169
|
+
if (facts.authorityEffect === "records-answer") {
|
|
170
|
+
return facts.exposure === "outward"
|
|
171
|
+
? "Your response records an answer about an outward step. It does not publish or send anything by itself."
|
|
172
|
+
: "Your response records an answer for this interview. It grants no tool authority.";
|
|
173
|
+
}
|
|
174
|
+
const tool = facts.tool ?? "the presented tool";
|
|
175
|
+
const actionClass = facts.actionClass ?? "unknown";
|
|
176
|
+
if (tool === "ask_user" && facts.exposure === "outward") {
|
|
177
|
+
return "Approval opens this one outward-decision interview. It does not publish or send anything by itself.";
|
|
178
|
+
}
|
|
179
|
+
return `Approval authorizes one ${actionClass} call to ${tool}. It does not change the autonomy level.`;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function consequenceCopy(facts: TrustedDecisionFacts, tier: DecisionTier): string {
|
|
183
|
+
switch (tier) {
|
|
184
|
+
case "conversation":
|
|
185
|
+
return "The answer stays in this session's decision record.";
|
|
186
|
+
case "workspace":
|
|
187
|
+
return facts.actionClass === "read"
|
|
188
|
+
? "The call reads within the workspace without mutating it."
|
|
189
|
+
: "The call can affect files or processes inside the workspace.";
|
|
190
|
+
case "outward":
|
|
191
|
+
return "The resulting step can reach people or systems outside the workspace.";
|
|
192
|
+
case "safety-net":
|
|
193
|
+
return "An always-on safety-net rail requires a one-shot operator decision before this call can run.";
|
|
194
|
+
case "system":
|
|
195
|
+
return "The call can change state outside the workspace or state the classifier cannot safely bound.";
|
|
196
|
+
case "worker":
|
|
197
|
+
return "A dispatched worker is parked. Your answer returns only to that run's exact request.";
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function reversibilityCopy(facts: TrustedDecisionFacts): string {
|
|
202
|
+
if (facts.requestKind === "question") {
|
|
203
|
+
return facts.reversibility === "reversible"
|
|
204
|
+
? "Reversible: yes. The recorded answer can be superseded later."
|
|
205
|
+
: "Reversible: not guaranteed. An outward step that later uses this answer may have lasting effects.";
|
|
206
|
+
}
|
|
207
|
+
if (facts.actionClass === "read" && facts.reversibility === "reversible") {
|
|
208
|
+
return "Reversible: yes. This call does not mutate the workspace.";
|
|
209
|
+
}
|
|
210
|
+
switch (facts.reversibility) {
|
|
211
|
+
case "reversible":
|
|
212
|
+
return "Reversible: yes. Workspace changes can be reviewed and reverted.";
|
|
213
|
+
case "limited":
|
|
214
|
+
return "Reversible: not guaranteed. Effects that already ran or reached an outward system may remain.";
|
|
215
|
+
case "unknown":
|
|
216
|
+
return "Reversible: unknown. Treat the effect as not safely reversible.";
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function requiredActions(facts: TrustedDecisionFacts, tier: DecisionTier): ReadonlyArray<DecisionPresentationAction> {
|
|
221
|
+
if (facts.authorityEffect === "records-answer") {
|
|
222
|
+
return [
|
|
223
|
+
{
|
|
224
|
+
id: "record-answer",
|
|
225
|
+
label: facts.exposure === "outward" ? "Record outward answer" : "Record answer",
|
|
226
|
+
consequence: "Records the selected or typed answer without granting tool authority.",
|
|
227
|
+
},
|
|
228
|
+
{ id: "cancel", label: "Cancel", consequence: "Closes the interview without recording an answer for this round." },
|
|
229
|
+
];
|
|
230
|
+
}
|
|
231
|
+
const approveLabel =
|
|
232
|
+
tier === "system"
|
|
233
|
+
? "Approve system change once"
|
|
234
|
+
: tier === "safety-net"
|
|
235
|
+
? "Approve guarded action once"
|
|
236
|
+
: tier === "worker"
|
|
237
|
+
? "Approve worker request once"
|
|
238
|
+
: tier === "outward"
|
|
239
|
+
? "Approve outward decision once"
|
|
240
|
+
: "Approve workspace action once";
|
|
241
|
+
const stopConsequence =
|
|
242
|
+
facts.origin.kind === "worker"
|
|
243
|
+
? "Denies this worker request and ends the active main-agent turn. Other worker requests retain their timeout policy."
|
|
244
|
+
: "Denies every parked request from this turn and ends the run.";
|
|
245
|
+
return [
|
|
246
|
+
{
|
|
247
|
+
id: "approve-once",
|
|
248
|
+
label: approveLabel,
|
|
249
|
+
consequence: "Runs only the presented request and does not change the autonomy level.",
|
|
250
|
+
},
|
|
251
|
+
{ id: "deny", label: "Deny this request", consequence: "Denies only the presented request and advances the queue." },
|
|
252
|
+
{ id: "stop", label: "Deny and stop", consequence: stopConsequence },
|
|
253
|
+
];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Pure presentation classifier. It performs no I/O and has no execution authority. */
|
|
257
|
+
export function classifyDecisionPresentation(facts: TrustedDecisionFacts): DecisionPresentation {
|
|
258
|
+
const tier = classifyTier(facts);
|
|
259
|
+
return {
|
|
260
|
+
tier,
|
|
261
|
+
...tierIdentity(tier),
|
|
262
|
+
authorizationCopy: authorizationCopy(facts),
|
|
263
|
+
consequenceCopy: consequenceCopy(facts, tier),
|
|
264
|
+
reversibilityCopy: reversibilityCopy(facts),
|
|
265
|
+
requestedByCopy: requestedByCopy(facts),
|
|
266
|
+
requiredActions: requiredActions(facts, tier),
|
|
267
|
+
};
|
|
268
|
+
}
|
|
@@ -61,6 +61,14 @@ export const DEFAULT_DAMAGE_CONTROL_PATH_POLICY: PathPolicyInput = {
|
|
|
61
61
|
"*.dump",
|
|
62
62
|
],
|
|
63
63
|
readOnlyPaths: [
|
|
64
|
+
// Clio's own operator-authority files in the project. `safety.yaml` is the
|
|
65
|
+
// policy that gates the model's tools, and `verifiers.yaml` is an argv
|
|
66
|
+
// catalog that verify() executes; a model that can author either one can
|
|
67
|
+
// widen its own permissions in two tool calls. Both are authored by the
|
|
68
|
+
// operator through the CLI (`clio-coder verifiers author` lands nothing
|
|
69
|
+
// before `--yes`), so model-side writes and deletes are refused.
|
|
70
|
+
".clio-coder/safety.yaml",
|
|
71
|
+
".clio-coder/verifiers.yaml",
|
|
64
72
|
"/etc/",
|
|
65
73
|
"/usr/",
|
|
66
74
|
"/bin/",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ToolNames } from "../../core/tool-names.js";
|
|
2
|
-
import { isVerificationScriptName } from "../../core/verification-scripts.js";
|
|
2
|
+
import { isProjectVerifierCheckId, isVerificationScriptName } from "../../core/verification-scripts.js";
|
|
3
3
|
import {
|
|
4
4
|
detectValidationCommand,
|
|
5
5
|
extractCommandDeleteTargets,
|
|
@@ -399,8 +399,9 @@ export function typedValidationSummary(toolName: string, payload: Record<string,
|
|
|
399
399
|
const path = typeof args?.path === "string" && args.path.trim().length > 0 ? args.path.trim() : "artifact";
|
|
400
400
|
return `verify frontend ${path}`;
|
|
401
401
|
}
|
|
402
|
-
if (
|
|
403
|
-
return `
|
|
402
|
+
if (isVerificationScriptName(check)) return `npm run ${check}`;
|
|
403
|
+
if (isProjectVerifierCheckId(check)) return `verify ${check}`;
|
|
404
|
+
return null;
|
|
404
405
|
}
|
|
405
406
|
return null;
|
|
406
407
|
}
|
|
@@ -4,6 +4,7 @@ import { artifactDefaultPath } from "../../core/artifact-paths.js";
|
|
|
4
4
|
import { canonicalizeExistingPath } from "../../core/path-canonical.js";
|
|
5
5
|
import { ToolNames } from "../../core/tool-names.js";
|
|
6
6
|
import { clioConfigDir } from "../../core/xdg.js";
|
|
7
|
+
import { type DeclaredCheck, loadProjectVerifierCatalog } from "../../tools/verify/catalog.js";
|
|
7
8
|
import { type ActionClass, type Classification, type ClassifierCall, classify } from "./action-classifier.js";
|
|
8
9
|
import type { DamageControlMatch, DamageControlRule } from "./damage-control.js";
|
|
9
10
|
import { DEFAULT_DAMAGE_CONTROL_PATH_POLICY, mergePathPolicyInputs } from "./default-path-policy.js";
|
|
@@ -225,7 +226,9 @@ export function createSafetyPolicyEngine(options: SafetyPolicyEngineOptions = {}
|
|
|
225
226
|
const rawClassification = classify(call);
|
|
226
227
|
const command = commandArg(call.args);
|
|
227
228
|
const callCwd = cwdArg(call.args, cwd);
|
|
228
|
-
const
|
|
229
|
+
const catalogCheck = resolveVerifyCatalogCheck(call, cwd);
|
|
230
|
+
const catalogCommand = catalogCheck === null ? null : catalogCheck.command.join(" ");
|
|
231
|
+
const scan = catalogCommand ?? damageControlScan(call);
|
|
229
232
|
const hit = scan ? matchSourcedRule(scan, sourcedRules) : null;
|
|
230
233
|
const classification = effectiveClassification(rawClassification, hit?.match);
|
|
231
234
|
|
|
@@ -335,8 +338,9 @@ export function createSafetyPolicyEngine(options: SafetyPolicyEngineOptions = {}
|
|
|
335
338
|
// command; the one carve-out is the exit-code-only presence check
|
|
336
339
|
// (`grep -q`/`grep -sq` with a ^NAME= pattern), which is the safe
|
|
337
340
|
// protocol the credentials skill teaches.
|
|
338
|
-
|
|
339
|
-
|
|
341
|
+
const scannedCommand = call.tool === ToolNames.Bash ? command : catalogCommand;
|
|
342
|
+
if (scannedCommand !== null) {
|
|
343
|
+
const secretRead = evaluateBashZeroAccessRead(zeroAccessPolicy, scannedCommand, callCwd);
|
|
340
344
|
if (secretRead !== null) {
|
|
341
345
|
const blockInput: Omit<
|
|
342
346
|
SafetyPolicyDecision,
|
|
@@ -407,9 +411,22 @@ export function createSafetyPolicyEngine(options: SafetyPolicyEngineOptions = {}
|
|
|
407
411
|
};
|
|
408
412
|
if (hit?.match.ruleId !== undefined) allowInput.ruleId = hit.match.ruleId;
|
|
409
413
|
if (hit?.match !== undefined) allowInput.match = hit.match;
|
|
410
|
-
// The typed execution tool (verify)
|
|
411
|
-
//
|
|
412
|
-
|
|
414
|
+
// The typed execution tool (verify) sits in the no-prompt set when the
|
|
415
|
+
// check is a package script or the frontend validator: both are bounded
|
|
416
|
+
// by the verification-script family and run a fixed argv shape. A
|
|
417
|
+
// project-catalog check runs whatever argv the workspace file declares,
|
|
418
|
+
// so it is unrecognized: auto-edit parks it for one confirmation that
|
|
419
|
+
// shows the argv, full-auto runs it, and the damage-control match and
|
|
420
|
+
// zero-access scan above have already seen the declared vector.
|
|
421
|
+
if (classification.actionClass === "execute") {
|
|
422
|
+
allowInput.execRecognition = catalogCheck === null ? "recognized" : "unrecognized";
|
|
423
|
+
if (catalogCheck !== null) {
|
|
424
|
+
allowInput.reasons = [
|
|
425
|
+
...allowInput.reasons,
|
|
426
|
+
`project verifier '${catalogCheck.id}' runs declared argv: ${catalogCommand ?? ""}`,
|
|
427
|
+
];
|
|
428
|
+
}
|
|
429
|
+
}
|
|
413
430
|
return allowDecision(base, allowInput);
|
|
414
431
|
},
|
|
415
432
|
metadata() {
|
|
@@ -958,6 +975,31 @@ function damageControlScan(call: ClassifierCall): string {
|
|
|
958
975
|
return typeof pathArg === "string" ? pathArg : "";
|
|
959
976
|
}
|
|
960
977
|
|
|
978
|
+
/**
|
|
979
|
+
* The project-catalog check a verify call resolves to, or null for a listing,
|
|
980
|
+
* the frontend validator, a package script, or an id the catalog does not
|
|
981
|
+
* declare. The catalog is an argv vector the operator authored, but the file
|
|
982
|
+
* sits in the workspace, so the engine reads it fresh on every verify call and
|
|
983
|
+
* treats the declared argv exactly like a bash command string: it is what the
|
|
984
|
+
* damage-control rules and the zero-access read guard scan, and it is not in
|
|
985
|
+
* the no-prompt set. An unreadable or invalid catalog resolves to null here and
|
|
986
|
+
* fails closed in the tool itself.
|
|
987
|
+
*/
|
|
988
|
+
function resolveVerifyCatalogCheck(call: ClassifierCall, workspaceRoot: string): DeclaredCheck | null {
|
|
989
|
+
if (call.tool !== ToolNames.Verify) return null;
|
|
990
|
+
const check = call.args?.check;
|
|
991
|
+
if (typeof check !== "string") return null;
|
|
992
|
+
const id = check.trim();
|
|
993
|
+
if (id.length === 0 || id === "frontend") return null;
|
|
994
|
+
try {
|
|
995
|
+
const catalog = loadProjectVerifierCatalog(workspaceRoot);
|
|
996
|
+
if (!catalog.ok || catalog.source === null) return null;
|
|
997
|
+
return catalog.source.checks.find((candidate) => candidate.id === id) ?? null;
|
|
998
|
+
} catch {
|
|
999
|
+
return null;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
961
1003
|
function serializeArgs(args?: Record<string, unknown>): string {
|
|
962
1004
|
if (!args) return "";
|
|
963
1005
|
const parts: string[] = [];
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Display-time secret redaction for tool arguments.
|
|
3
|
+
*
|
|
4
|
+
* Two surfaces need the same rules and must not drift. The transcript's tool
|
|
5
|
+
* renderer projects a call's arguments for the operator's own screen, and the
|
|
6
|
+
* worker tool-admission seam composes a bounded action descriptor that crosses
|
|
7
|
+
* the NDJSON stdout boundary. A credential that one of them scrubs and the
|
|
8
|
+
* other prints is a leak, so the patterns live here and both import them.
|
|
9
|
+
*
|
|
10
|
+
* This is presentation only. Execution, receipts, and the safety verdict all
|
|
11
|
+
* keep the original argument values; nothing here changes what a tool runs.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
15
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const SECRET_KEY_RE =
|
|
19
|
+
/(?:api[-_]?key|access[-_]?key|auth(?:orization)?|credential|password|private[-_]?key|secret|token)/iu;
|
|
20
|
+
const ENV_KEY_RE = /^env(?:ironment)?$/iu;
|
|
21
|
+
const SECRET_STRING_RE = /(https?:\/\/[^\s/@]+:)[^\s/@]+@/giu;
|
|
22
|
+
const SECRET_URL_PARAM_RE =
|
|
23
|
+
/([?&](?:api[-_]?key|access[-_]?token|auth(?:orization)?|credential|password|secret|token)[^=\s]*=)[^&#\s]+/giu;
|
|
24
|
+
const SECRET_ASSIGNMENT_RE =
|
|
25
|
+
/(?<![A-Z0-9_])((?:[A-Z0-9_]*(?:ACCESS|API|AUTH|CREDENTIAL|KEY|PASS(?:WORD)?|PRIVATE|SECRET|TOKEN)[A-Z0-9_]*)=)[^\s;&|]+/giu;
|
|
26
|
+
const SECRET_FLAG_RE =
|
|
27
|
+
/(--?(?:[a-z0-9-]*(?:api[-_]?key|access[-_]?token|auth(?:orization)?|credential|password|secret|token)[a-z0-9-]*))(=|\s+)([^\s;&|]+)/giu;
|
|
28
|
+
|
|
29
|
+
/** Scrub credentials embedded in one string: URL userinfo, query params, `KEY=value`, and `--flag value`. */
|
|
30
|
+
export function redactSecretString(value: string): string {
|
|
31
|
+
return value
|
|
32
|
+
.replace(SECRET_STRING_RE, "$1[redacted]@")
|
|
33
|
+
.replace(SECRET_URL_PARAM_RE, "$1[redacted]")
|
|
34
|
+
.replace(SECRET_ASSIGNMENT_RE, "$1[redacted]")
|
|
35
|
+
.replace(SECRET_FLAG_RE, "$1$2[redacted]");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Whether an argument key names a secret outright, so its value never renders. */
|
|
39
|
+
export function isSecretArgKey(key: string): boolean {
|
|
40
|
+
return SECRET_KEY_RE.test(key);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Whether an argument key names an environment block, whose every string value is a candidate secret. */
|
|
44
|
+
function isEnvironmentArgKey(key: string): boolean {
|
|
45
|
+
return ENV_KEY_RE.test(key);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function redactEnvironmentValue(value: unknown, depth: number): unknown {
|
|
49
|
+
if (depth > 8) return "[redacted nested values]";
|
|
50
|
+
if (typeof value === "string") return "[redacted]";
|
|
51
|
+
if (Array.isArray(value)) return value.map((item) => redactEnvironmentValue(item, depth + 1));
|
|
52
|
+
if (!isPlainObject(value)) return value;
|
|
53
|
+
const out: Record<string, unknown> = {};
|
|
54
|
+
for (const [childKey, childValue] of Object.entries(value)) {
|
|
55
|
+
out[childKey] = redactEnvironmentValue(childValue, depth + 1);
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Project tool arguments for display only; execution and receipts retain the original values. */
|
|
61
|
+
export function redactToolArgs(value: unknown, key = "", depth = 0): unknown {
|
|
62
|
+
if (isSecretArgKey(key)) return "[redacted]";
|
|
63
|
+
if (isEnvironmentArgKey(key)) return redactEnvironmentValue(value, depth);
|
|
64
|
+
if (typeof value === "string") return redactSecretString(value);
|
|
65
|
+
if (depth > 8) return "[redacted nested values]";
|
|
66
|
+
if (Array.isArray(value)) return value.map((item) => redactToolArgs(item, key, depth + 1));
|
|
67
|
+
if (!isPlainObject(value)) return value;
|
|
68
|
+
const out: Record<string, unknown> = {};
|
|
69
|
+
for (const [childKey, childValue] of Object.entries(value)) {
|
|
70
|
+
out[childKey] = redactToolArgs(childValue, childKey, depth + 1);
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
import { stream } from "../../../engine/ai.js";
|
|
14
14
|
import type { EngineModel, Usage } from "../../../engine/types.js";
|
|
15
|
+
import { foldWorkingSet } from "../../context/working-set/fold.js";
|
|
16
|
+
import { recallableRefListing } from "../../context/working-set/recall.js";
|
|
15
17
|
import type { CompactionUsage, SessionEntry } from "../entries.js";
|
|
16
18
|
import { serializeConversation } from "./branch-summary.js";
|
|
17
19
|
import { findCutPoint } from "./cut-point.js";
|
|
@@ -307,6 +309,23 @@ function formatFileOperations(fileOps: FileOperations): string {
|
|
|
307
309
|
return sections.length > 0 ? `\n\n${sections.join("\n\n")}` : "";
|
|
308
310
|
}
|
|
309
311
|
|
|
312
|
+
function formatRecallableRefs(entries: ReadonlyArray<SessionEntry>, firstKeptEntryIndex: number): string {
|
|
313
|
+
const entryIndexes = new Map<string, number>();
|
|
314
|
+
for (let index = 0; index < entries.length; index += 1) {
|
|
315
|
+
const entry = entries[index];
|
|
316
|
+
if (entry) entryIndexes.set(entry.turnId, index);
|
|
317
|
+
}
|
|
318
|
+
const view = foldWorkingSet(entries);
|
|
319
|
+
const evictedBeforeCut = new Map(
|
|
320
|
+
[...view.evicted].filter(([ref]) => (entryIndexes.get(ref) ?? Number.POSITIVE_INFINITY) < firstKeptEntryIndex),
|
|
321
|
+
);
|
|
322
|
+
const listing = recallableRefListing(entries, { ...view, evicted: evictedBeforeCut });
|
|
323
|
+
if (listing.refs.length === 0) return "";
|
|
324
|
+
const rows = [...listing.refs];
|
|
325
|
+
if (listing.remaining > 0) rows.push(`and ${listing.remaining} more`);
|
|
326
|
+
return `\n\n<recallable-refs>\n${rows.join("\n")}\n</recallable-refs>`;
|
|
327
|
+
}
|
|
328
|
+
|
|
310
329
|
function numberOrZero(value: unknown): number {
|
|
311
330
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
|
|
312
331
|
}
|
|
@@ -457,7 +476,10 @@ export async function compact(input: CompactInput): Promise<CompactResult> {
|
|
|
457
476
|
}
|
|
458
477
|
}
|
|
459
478
|
|
|
460
|
-
const summary = `${summaryParts.join("\n\n---\n\n").trim()}${formatFileOperations(fileOps)}
|
|
479
|
+
const summary = `${summaryParts.join("\n\n---\n\n").trim()}${formatFileOperations(fileOps)}${formatRecallableRefs(
|
|
480
|
+
input.entries,
|
|
481
|
+
cut.firstKeptEntryIndex,
|
|
482
|
+
)}`.trim();
|
|
461
483
|
|
|
462
484
|
return {
|
|
463
485
|
summary,
|
|
@@ -34,7 +34,18 @@ export interface TokenEstimator {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
function estimateMessage(entry: MessageEntry): number {
|
|
37
|
-
|
|
37
|
+
// Usage invalidation is bookkeeping for token-anchor selection. The replay
|
|
38
|
+
// builder carries it as AgentMessage metadata, but providers never see it in
|
|
39
|
+
// message content, so it cannot change a projected entry's prompt cost. Drop
|
|
40
|
+
// it here so plan-time pricing and the post-event projection use one byte
|
|
41
|
+
// definition even though only the latter has applied the stamp.
|
|
42
|
+
if (entry.role !== "assistant" || !entry.payload || typeof entry.payload !== "object") {
|
|
43
|
+
return estimateAgentMessageTokens(entry);
|
|
44
|
+
}
|
|
45
|
+
const payload = entry.payload as Record<string, unknown>;
|
|
46
|
+
if (!("contextUsageInvalidated" in payload)) return estimateAgentMessageTokens(entry);
|
|
47
|
+
const { contextUsageInvalidated: _stamp, ...promptPayload } = payload;
|
|
48
|
+
return estimateAgentMessageTokens({ ...entry, payload: promptPayload });
|
|
38
49
|
}
|
|
39
50
|
|
|
40
51
|
function estimateBashExecution(entry: BashExecutionEntry): number {
|
|
@@ -78,6 +89,10 @@ export function estimateTokens(entry: SessionEntry): number {
|
|
|
78
89
|
case "taskLedger":
|
|
79
90
|
case "decisionLedger":
|
|
80
91
|
case "workerRun":
|
|
92
|
+
// Working-set bookkeeping: refs and markers, never bodies. The
|
|
93
|
+
// projection accounts for marker cost on the projected messages.
|
|
94
|
+
case "contextEviction":
|
|
95
|
+
case "contextRecall":
|
|
81
96
|
return 0;
|
|
82
97
|
}
|
|
83
98
|
}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* proportional reconciliation the footer bar already performs.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import type { ContextWindowSource } from "../providers/index.js";
|
|
19
|
+
import type { ContextWindowSlots, ContextWindowSource } from "../providers/index.js";
|
|
20
20
|
import { DEFAULT_COMPACTION_THRESHOLD } from "./compaction/auto.js";
|
|
21
21
|
|
|
22
22
|
/** Distinct buckets a context window is divided into for display. */
|
|
@@ -46,6 +46,8 @@ export interface BuildContextLedgerInput {
|
|
|
46
46
|
contextWindow: number | null;
|
|
47
47
|
/** Which layer answered `contextWindow`; omitted before a runtime resolves. */
|
|
48
48
|
contextWindowSource?: ContextWindowSource | null;
|
|
49
|
+
/** The server-side split the probed window is a share of, when there is one. */
|
|
50
|
+
contextWindowSlots?: ContextWindowSlots | null;
|
|
49
51
|
/**
|
|
50
52
|
* Per-segment token estimates from the prompt compiler's segment manifest.
|
|
51
53
|
* When empty, `systemPromptTokens` is used as a single opaque system bucket.
|
|
@@ -122,6 +124,8 @@ export interface PromptCacheStats {
|
|
|
122
124
|
* combination the overlay renders as a warning.
|
|
123
125
|
*/
|
|
124
126
|
backendVerdict: "hot" | "partial" | "cold" | "small" | null;
|
|
127
|
+
/** Cache disturbances Clio expected before the last settled run. */
|
|
128
|
+
expectedColdReasons?: ReadonlyArray<string>;
|
|
125
129
|
}
|
|
126
130
|
|
|
127
131
|
export interface ContextLedgerGroup {
|
|
@@ -144,6 +148,12 @@ export interface ContextLedger {
|
|
|
144
148
|
* the difference decides whether autocompact fires in time.
|
|
145
149
|
*/
|
|
146
150
|
contextWindowSource: ContextWindowSource | null;
|
|
151
|
+
/**
|
|
152
|
+
* Present when `contextWindow` is one slot's share of the server's KV
|
|
153
|
+
* budget, so the overlay can show `196,608 (786,432 / 4 slots)` instead of
|
|
154
|
+
* a number that looks like the whole server.
|
|
155
|
+
*/
|
|
156
|
+
contextWindowSlots: ContextWindowSlots | null;
|
|
147
157
|
/** Sum of every content category (system..pending). */
|
|
148
158
|
usedTokens: number;
|
|
149
159
|
/** Autocompact headroom held in reserve above the conversation. */
|
|
@@ -344,6 +354,7 @@ export function buildContextLedger(input: BuildContextLedgerInput): ContextLedge
|
|
|
344
354
|
model: input.model ?? null,
|
|
345
355
|
contextWindow: window,
|
|
346
356
|
contextWindowSource: input.contextWindowSource ?? null,
|
|
357
|
+
contextWindowSlots: input.contextWindowSlots ?? null,
|
|
347
358
|
usedTokens,
|
|
348
359
|
reserveTokens,
|
|
349
360
|
freeTokens,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AskUserToolPolicy } from "../../tools/registry.js";
|
|
2
|
+
import type { AutonomyExposure } from "../safety/autonomy.js";
|
|
2
3
|
import type { DecisionLedgerEntry, DecisionRecord } from "./entries.js";
|
|
3
4
|
|
|
4
5
|
export interface DecisionLedgerEntryFields {
|
|
@@ -11,6 +12,7 @@ export interface DecisionLedgerEntryFields {
|
|
|
11
12
|
roundCount: number;
|
|
12
13
|
summary?: string;
|
|
13
14
|
transcriptPath?: string;
|
|
15
|
+
exposure?: AutonomyExposure;
|
|
14
16
|
decisions: DecisionRecord[];
|
|
15
17
|
}
|
|
16
18
|
|
|
@@ -83,6 +85,7 @@ export function finalizedInterviewEntryFields(policy: AskUserToolPolicy): Decisi
|
|
|
83
85
|
roundCount: policy.rounds.length,
|
|
84
86
|
...(policy.summary ? { summary: policy.summary } : {}),
|
|
85
87
|
...(policy.transcriptPath ? { transcriptPath: policy.transcriptPath } : {}),
|
|
88
|
+
exposure: policy.exposure ?? "local",
|
|
86
89
|
decisions: [...decisionsByKey.values()],
|
|
87
90
|
};
|
|
88
91
|
}
|
|
@@ -172,6 +175,7 @@ export function createDecisionBoardStore(deps: DecisionBoardStoreDeps = {}): Dec
|
|
|
172
175
|
roundCount: interview.roundCount,
|
|
173
176
|
...(interview.summary ? { summary: interview.summary } : {}),
|
|
174
177
|
...(interview.transcriptPath ? { transcriptPath: interview.transcriptPath } : {}),
|
|
178
|
+
...(interview.exposure ? { exposure: interview.exposure } : {}),
|
|
175
179
|
decisions: interview.decisions.map((decision) => {
|
|
176
180
|
if (decision.key !== selected.key) return { ...decision };
|
|
177
181
|
const next: DecisionRecord = { ...decision, status: "superseded", revisedAt };
|