@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,5 +1,6 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
|
+
import { BusChannels } from "../core/bus-events.js";
|
|
3
4
|
import type { ClioSettings } from "../core/config.js";
|
|
4
5
|
import type { SafeEventBus } from "../core/event-bus.js";
|
|
5
6
|
import type { PendingSkillRequest } from "../core/skill-activation.js";
|
|
@@ -28,6 +29,7 @@ import { type ChatPanel, createChatPanel } from "./chat-panel.js";
|
|
|
28
29
|
import { rehydrateChatPanelFromTurns } from "./chat-renderer.js";
|
|
29
30
|
import { runCompactWithNotice } from "./command-fallbacks.js";
|
|
30
31
|
import { appendNotice, appendOperatorCommand } from "./command-output.js";
|
|
32
|
+
import { runOperatorRecall } from "./context-recall-command.js";
|
|
31
33
|
import { renderSessionHtml } from "./export-html/index.js";
|
|
32
34
|
import { dateLocal } from "./format-time.js";
|
|
33
35
|
import type { SettingsCenterRowId, SettingsSectionId } from "./overlays/settings.js";
|
|
@@ -100,8 +102,10 @@ export interface InteractiveSlashRuntimeDeps {
|
|
|
100
102
|
* Leaf lookup for `/export`, so the export follows the branch the session
|
|
101
103
|
* is actually on. current.jsonl still holds the abandoned turns after a
|
|
102
104
|
* `/tree` pin, and an unscoped rehydrate reproduced them (issue #109).
|
|
105
|
+
* `/context recall` uses the same leaf for its fold, plus `appendEntry` for
|
|
106
|
+
* the `contextRecall` record.
|
|
103
107
|
*/
|
|
104
|
-
session?: Pick<SessionContract, "tree">;
|
|
108
|
+
session?: Pick<SessionContract, "tree" | "current" | "appendEntry">;
|
|
105
109
|
expandSubmit: (text: string) => Promise<InteractiveSlashSubmitExpansion>;
|
|
106
110
|
openAskUser: AskUserHandler;
|
|
107
111
|
openSkillsHub: () => void;
|
|
@@ -512,6 +516,38 @@ export function createInteractiveSlashRuntime(deps: InteractiveSlashRuntimeDeps)
|
|
|
512
516
|
}
|
|
513
517
|
deps.openContextReset();
|
|
514
518
|
},
|
|
519
|
+
...(deps.session
|
|
520
|
+
? {
|
|
521
|
+
runContextRecall: (ref: string) => {
|
|
522
|
+
const session = deps.session;
|
|
523
|
+
if (!session) return;
|
|
524
|
+
const outcome = runOperatorRecall(ref, {
|
|
525
|
+
hasSession: () => session.current() !== null,
|
|
526
|
+
readEntries: () => {
|
|
527
|
+
const sessionId = deps.chat.getSessionId();
|
|
528
|
+
return sessionId ? deps.readStructuredEntries(sessionId) : [];
|
|
529
|
+
},
|
|
530
|
+
activeLeafTurnId: () => {
|
|
531
|
+
const meta = session.current();
|
|
532
|
+
return meta ? (session.tree(meta.id).leafId ?? undefined) : undefined;
|
|
533
|
+
},
|
|
534
|
+
appendEntry: (entry) => session.appendEntry(entry),
|
|
535
|
+
onRecalled: (payload) => deps.bus.emit(BusChannels.ContextRecalled, payload),
|
|
536
|
+
...(deps.now ? { now: () => (deps.now?.() ?? new Date()).getTime() } : {}),
|
|
537
|
+
});
|
|
538
|
+
if (!outcome.ok) {
|
|
539
|
+
appendCommandNotice("error", outcome.message);
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
appendCommandNotice("success", outcome.headline);
|
|
543
|
+
// The body is transcript output, not a notice: notices collapse
|
|
544
|
+
// newlines, and a recalled build log is worth nothing on one line.
|
|
545
|
+
// It is a replay block either way, so it never enters model context.
|
|
546
|
+
deps.io.stdout(`${outcome.body}\n`);
|
|
547
|
+
deps.requestRender();
|
|
548
|
+
},
|
|
549
|
+
}
|
|
550
|
+
: {}),
|
|
515
551
|
runContextRefresh: () => {
|
|
516
552
|
if (!deps.onContextRefresh) {
|
|
517
553
|
deps.io.stderr("[/context refresh] context refresh not wired; pass onContextRefresh to startInteractive\n");
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
describeTaskMemoryActivity,
|
|
3
|
+
type MemoryProposalResult,
|
|
3
4
|
type MemoryRecord,
|
|
4
5
|
type TaskMemoryActivityEvent,
|
|
5
6
|
type TaskMemoryEntry,
|
|
@@ -182,6 +183,7 @@ function memorySignature(status: TaskMemoryOperatorStatus, records: ReadonlyArra
|
|
|
182
183
|
|
|
183
184
|
interface OpenMemoryOverlayOptions {
|
|
184
185
|
onClose?: () => void;
|
|
186
|
+
onPromote?: (entry: TaskMemoryEntry, scope: "repo" | "global") => Promise<MemoryProposalResult>;
|
|
185
187
|
}
|
|
186
188
|
|
|
187
189
|
/** Master-detail memory view: status header, grouped list, scrollable detail pane. */
|
|
@@ -189,12 +191,18 @@ export class MemoryOverlayView implements Component {
|
|
|
189
191
|
private readonly list: ListOverlayView;
|
|
190
192
|
private signature: string | null = null;
|
|
191
193
|
private renderMemo: { width: number; status: string; listLines: string[]; lines: string[] } | null = null;
|
|
194
|
+
private pendingGlobalEntryId: string | null = null;
|
|
195
|
+
private promotionMessage: { token: "muted" | "warning" | "success" | "error"; text: string } | null = null;
|
|
196
|
+
private promotionInFlight = false;
|
|
192
197
|
|
|
193
198
|
constructor(
|
|
194
199
|
private readonly getStatus: () => TaskMemoryOperatorStatus,
|
|
195
200
|
private readonly getRecords: () => ReadonlyArray<MemoryRecord>,
|
|
196
201
|
onClose: () => void,
|
|
197
202
|
onChange: () => void,
|
|
203
|
+
private readonly promotion?: {
|
|
204
|
+
onPromote: (entry: TaskMemoryEntry, scope: "repo" | "global") => Promise<MemoryProposalResult>;
|
|
205
|
+
},
|
|
198
206
|
) {
|
|
199
207
|
this.list = new ListOverlayView(
|
|
200
208
|
{
|
|
@@ -203,6 +211,18 @@ export class MemoryOverlayView implements Component {
|
|
|
203
211
|
filterable: true,
|
|
204
212
|
layout: "split",
|
|
205
213
|
emptyMessage: EMPTY_MESSAGE,
|
|
214
|
+
...(promotion
|
|
215
|
+
? {
|
|
216
|
+
hints: [
|
|
217
|
+
{ key: "p", verb: "propose repo" },
|
|
218
|
+
{ key: "g", verb: "propose global" },
|
|
219
|
+
],
|
|
220
|
+
actions: {
|
|
221
|
+
p: (item: ListOverlayItem) => this.promote(item, "repo", onChange),
|
|
222
|
+
g: (item: ListOverlayItem) => this.promote(item, "global", onChange),
|
|
223
|
+
},
|
|
224
|
+
}
|
|
225
|
+
: {}),
|
|
206
226
|
onClose,
|
|
207
227
|
},
|
|
208
228
|
onChange,
|
|
@@ -217,11 +237,21 @@ export class MemoryOverlayView implements Component {
|
|
|
217
237
|
render(width: number): string[] {
|
|
218
238
|
const status = this.sync();
|
|
219
239
|
const statusLine = formatMemoryStatusLine(status, width);
|
|
240
|
+
const promotionLine =
|
|
241
|
+
this.promotionMessage === null
|
|
242
|
+
? null
|
|
243
|
+
: fitUnits(clioTheme(), "", [clioTheme().fg(this.promotionMessage.token, this.promotionMessage.text)], width);
|
|
244
|
+
const statusKey = promotionLine === null ? statusLine : `${statusLine}\n${promotionLine}`;
|
|
220
245
|
const listLines = this.list.render(width);
|
|
221
246
|
const memo = this.renderMemo;
|
|
222
|
-
if (memo && memo.width === width && memo.status ===
|
|
223
|
-
const lines = [
|
|
224
|
-
|
|
247
|
+
if (memo && memo.width === width && memo.status === statusKey && memo.listLines === listLines) return memo.lines;
|
|
248
|
+
const lines = [
|
|
249
|
+
statusLine,
|
|
250
|
+
...(promotionLine === null ? [] : [promotionLine]),
|
|
251
|
+
rule(clioTheme(), width),
|
|
252
|
+
...listLines,
|
|
253
|
+
];
|
|
254
|
+
this.renderMemo = { width, status: statusKey, listLines, lines };
|
|
225
255
|
return lines;
|
|
226
256
|
}
|
|
227
257
|
|
|
@@ -247,9 +277,63 @@ export class MemoryOverlayView implements Component {
|
|
|
247
277
|
}
|
|
248
278
|
return status;
|
|
249
279
|
}
|
|
280
|
+
|
|
281
|
+
private promote(item: ListOverlayItem, scope: "repo" | "global", onChange: () => void): void {
|
|
282
|
+
if (this.promotion === undefined || this.promotionInFlight) return;
|
|
283
|
+
const entry = this.selectedBankEntry(item);
|
|
284
|
+
if (entry === null) {
|
|
285
|
+
this.pendingGlobalEntryId = null;
|
|
286
|
+
this.promotionMessage = { token: "warning", text: "select a knowledge or procedural task-bank entry" };
|
|
287
|
+
this.invalidate();
|
|
288
|
+
onChange();
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
if (scope === "global" && this.pendingGlobalEntryId !== entry.id) {
|
|
292
|
+
this.pendingGlobalEntryId = entry.id;
|
|
293
|
+
this.promotionMessage = {
|
|
294
|
+
token: "warning",
|
|
295
|
+
text: `global scope broadens applicability for ${entry.id}; press g again to acknowledge`,
|
|
296
|
+
};
|
|
297
|
+
this.invalidate();
|
|
298
|
+
onChange();
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
this.pendingGlobalEntryId = null;
|
|
302
|
+
this.promotionInFlight = true;
|
|
303
|
+
this.promotionMessage = { token: "muted", text: `proposing ${entry.id} with ${scope} scope` };
|
|
304
|
+
this.invalidate();
|
|
305
|
+
onChange();
|
|
306
|
+
void this.promotion
|
|
307
|
+
.onPromote(entry, scope)
|
|
308
|
+
.then((result) => {
|
|
309
|
+
this.promotionMessage = {
|
|
310
|
+
token: "success",
|
|
311
|
+
text: `${result.created ? "proposed" : "found existing"} ${result.record.id}; review, then run clio-coder memory approve ${result.record.id}`,
|
|
312
|
+
};
|
|
313
|
+
})
|
|
314
|
+
.catch((error: unknown) => {
|
|
315
|
+
this.promotionMessage = {
|
|
316
|
+
token: "error",
|
|
317
|
+
text: `promotion failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
318
|
+
};
|
|
319
|
+
})
|
|
320
|
+
.finally(() => {
|
|
321
|
+
this.promotionInFlight = false;
|
|
322
|
+
this.invalidate();
|
|
323
|
+
onChange();
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
private selectedBankEntry(item: ListOverlayItem): TaskMemoryEntry | null {
|
|
328
|
+
if (!item.id.startsWith("bank:")) return null;
|
|
329
|
+
const entryId = item.id.slice("bank:".length);
|
|
330
|
+
const entry = bankEntries(this.getStatus().bank).find((candidate) => candidate.id === entryId);
|
|
331
|
+
if (entry === undefined || entry.kind === "status") return null;
|
|
332
|
+
return entry;
|
|
333
|
+
}
|
|
250
334
|
}
|
|
251
335
|
|
|
252
|
-
/** Mount
|
|
336
|
+
/** Mount durable lessons and the live task bank with reviewed promotion actions. */
|
|
253
337
|
export function openMemoryOverlay(
|
|
254
338
|
tui: TUI,
|
|
255
339
|
getStatus: () => TaskMemoryOperatorStatus,
|
|
@@ -261,6 +345,7 @@ export function openMemoryOverlay(
|
|
|
261
345
|
getRecords,
|
|
262
346
|
() => options.onClose?.(),
|
|
263
347
|
() => tui.requestRender(),
|
|
348
|
+
options.onPromote ? { onPromote: options.onPromote } : undefined,
|
|
264
349
|
);
|
|
265
350
|
const handle = showClioOverlayFrame(tui, view, {
|
|
266
351
|
anchor: "center",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { foldWorkingSet } from "../domains/context/working-set/fold.js";
|
|
2
|
+
import { projectWorkingSet } from "../domains/context/working-set/project.js";
|
|
3
|
+
import type { SessionEntry } from "../domains/session/entries.js";
|
|
4
|
+
import type { AgentMessage } from "../engine/types.js";
|
|
5
|
+
import { buildReplayAgentMessagesFromTurns, type RehydrateChatPanelOptions } from "./chat-renderer.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Build provider-facing replay messages from the durable session ledger.
|
|
9
|
+
* Projection always honors existing eviction and recall entries; the enabled
|
|
10
|
+
* setting gates creation of new evictions, not replay of durable state.
|
|
11
|
+
* Visible transcript and export callers intentionally keep using the raw
|
|
12
|
+
* rehydration helpers so eviction remains a model projection, not data loss.
|
|
13
|
+
*/
|
|
14
|
+
export function buildModelReplayAgentMessagesFromTurns(
|
|
15
|
+
entries: ReadonlyArray<SessionEntry>,
|
|
16
|
+
options: RehydrateChatPanelOptions = {},
|
|
17
|
+
): AgentMessage[] {
|
|
18
|
+
const activeLeafTurnId = options.activeLeafTurnId ?? options.uptoTurnId;
|
|
19
|
+
const projected = projectWorkingSet(entries, foldWorkingSet(entries, activeLeafTurnId));
|
|
20
|
+
return buildReplayAgentMessagesFromTurns(projected, options);
|
|
21
|
+
}
|
|
@@ -77,7 +77,7 @@ export function createOverlayAskUserLifecycle(deps: OverlayAskUserLifecycleDeps)
|
|
|
77
77
|
const activeSession = ensureSession();
|
|
78
78
|
if (!activeSession) return cancelledAskUserResult();
|
|
79
79
|
pendingCancel = cancel;
|
|
80
|
-
const result = await activeSession.ask(questions);
|
|
80
|
+
const result = await activeSession.ask(questions, invokeOptions?.decisionPresentation);
|
|
81
81
|
if (result.cancelled === true || !toolBacked) {
|
|
82
82
|
if (result.cancelled === true) cancelledForTurn = true;
|
|
83
83
|
close();
|
|
@@ -478,16 +478,19 @@ export function showClioOverlayFrame(
|
|
|
478
478
|
const { title, footerHint, tone, width, visible, maxHeight, margin, ...overlayOptions } = options;
|
|
479
479
|
const boxWidth = typeof width === "number" ? width : 0;
|
|
480
480
|
const frame = new ClioOverlayFrame(child, title, footerHint, boxWidth, frameAlignForAnchor(options.anchor), tone);
|
|
481
|
-
const marginRows = typeof margin === "number" ? margin * 2 : (margin?.top ?? 0) + (margin?.bottom ?? 0);
|
|
482
481
|
return tui.showOverlay(frame, {
|
|
483
482
|
...overlayOptions,
|
|
484
483
|
...(margin !== undefined ? { margin } : {}),
|
|
485
484
|
width: "100%",
|
|
486
485
|
visible: (termWidth, termHeight) => {
|
|
486
|
+
const shown = visible ? visible(termWidth, termHeight) : true;
|
|
487
|
+
// A caller may update an object margin in its visibility callback to
|
|
488
|
+
// follow live content geometry. Read it after that callback, every frame.
|
|
489
|
+
const marginRows = typeof margin === "number" ? margin * 2 : (margin?.top ?? 0) + (margin?.bottom ?? 0);
|
|
487
490
|
const available = Math.max(1, termHeight - marginRows);
|
|
488
491
|
const requested = resolveRowSize(maxHeight, termHeight);
|
|
489
492
|
frame.setRowBudget(requested === null ? available : Math.min(requested, available));
|
|
490
|
-
return
|
|
493
|
+
return shown;
|
|
491
494
|
},
|
|
492
495
|
});
|
|
493
496
|
}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
import type { ClioSettings } from "../core/config.js";
|
|
1
2
|
import type { SafeEventBus } from "../core/event-bus.js";
|
|
3
|
+
import { foldWorkingSet } from "../domains/context/working-set/fold.js";
|
|
2
4
|
import type { DispatchContract } from "../domains/dispatch/index.js";
|
|
3
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
canonicalMemoryRepositoryIdentity,
|
|
7
|
+
loadMemoryRecordsSync,
|
|
8
|
+
type MemoryRecord,
|
|
9
|
+
proposeMemoryPromotion,
|
|
10
|
+
} from "../domains/memory/index.js";
|
|
4
11
|
import type { ObservabilityContract } from "../domains/observability/index.js";
|
|
5
12
|
import type { ContextLedger } from "../domains/session/context-ledger.js";
|
|
6
13
|
import type { SessionMeta } from "../domains/session/index.js";
|
|
@@ -56,6 +63,8 @@ export interface OverlayGeneralOpenersDeps {
|
|
|
56
63
|
stateDir: string;
|
|
57
64
|
getSessionMeta: () => SessionMeta | null;
|
|
58
65
|
readSessionEntries?: ArtifactProviderDeps["readSessionEntries"];
|
|
66
|
+
/** Live settings, so `/context` can state the configured working-set policy. */
|
|
67
|
+
getSettings?: () => Readonly<ClioSettings>;
|
|
59
68
|
terminal: { columns: number };
|
|
60
69
|
dispatchBoard: ReturnType<typeof createDispatchBoardView>;
|
|
61
70
|
startDispatchBoardTicker: () => void;
|
|
@@ -107,6 +116,15 @@ export function createOverlayGeneralOpeners(deps: OverlayGeneralOpenersDeps): Ov
|
|
|
107
116
|
deps.transitions.handle = openContextOverlayFactory(deps.tui, deps.getContextLedger, {
|
|
108
117
|
bus: deps.bus,
|
|
109
118
|
chat: deps.contextChat,
|
|
119
|
+
getWorkingSet: () => {
|
|
120
|
+
const readSessionEntries = deps.readSessionEntries;
|
|
121
|
+
if (!readSessionEntries) return null;
|
|
122
|
+
return foldWorkingSet(readSessionEntries(), deps.getSessionMeta()?.pinnedLeafTurnId ?? undefined);
|
|
123
|
+
},
|
|
124
|
+
getWorkingSetConfig: () => {
|
|
125
|
+
const workingSet = deps.getSettings?.().context.workingSet;
|
|
126
|
+
return workingSet ? { enabled: workingSet.enabled, policy: workingSet.policy } : null;
|
|
127
|
+
},
|
|
110
128
|
});
|
|
111
129
|
deps.requestRender();
|
|
112
130
|
};
|
|
@@ -212,6 +230,32 @@ export function createOverlayGeneralOpeners(deps: OverlayGeneralOpenersDeps): Ov
|
|
|
212
230
|
deps.transitions.state = "memory";
|
|
213
231
|
deps.transitions.handle = openMemoryOverlayFactory(deps.tui, deps.getTaskMemoryStatus, () => records, {
|
|
214
232
|
onClose: deps.closeOverlay,
|
|
233
|
+
onPromote: async (entry, scope) => {
|
|
234
|
+
const meta = deps.getSessionMeta();
|
|
235
|
+
if (!meta) throw new Error("memory promotion requires an active session");
|
|
236
|
+
const selection =
|
|
237
|
+
scope === "global"
|
|
238
|
+
? ({ scope: "global", acknowledgeGlobal: true } as const)
|
|
239
|
+
: (() => {
|
|
240
|
+
const repository = canonicalMemoryRepositoryIdentity(meta.cwd);
|
|
241
|
+
if (repository === null) {
|
|
242
|
+
throw new Error("repo promotion requires a canonical active repository identity");
|
|
243
|
+
}
|
|
244
|
+
return { scope: "repo", repository } as const;
|
|
245
|
+
})();
|
|
246
|
+
const result = await proposeMemoryPromotion(
|
|
247
|
+
deps.dataDir,
|
|
248
|
+
{
|
|
249
|
+
kind: "task-bank-entry",
|
|
250
|
+
sessionId: meta.id,
|
|
251
|
+
evidenceRefs: [`session-${meta.id}`],
|
|
252
|
+
entry,
|
|
253
|
+
},
|
|
254
|
+
selection,
|
|
255
|
+
);
|
|
256
|
+
records = loadMemoryRecordsSync(deps.dataDir);
|
|
257
|
+
return result;
|
|
258
|
+
},
|
|
215
259
|
});
|
|
216
260
|
deps.requestRender();
|
|
217
261
|
};
|
|
@@ -255,6 +299,7 @@ export function createOverlayGeneralOpeners(deps: OverlayGeneralOpenersDeps): Ov
|
|
|
255
299
|
const dispatchBoardHint = (): string => {
|
|
256
300
|
const row = deps.dispatchBoard.selectedRow();
|
|
257
301
|
const entries = [{ key: "↑↓", verb: "select" }];
|
|
302
|
+
if (row) entries.push({ key: "Enter", verb: deps.dispatchBoard.detailExpanded() ? "hide detail" : "detail" });
|
|
258
303
|
if (row && isDispatchBoardRowSteerable(row)) entries.push({ key: "s", verb: "steer" });
|
|
259
304
|
if (row && isDispatchBoardRowCancellable(row)) entries.push({ key: "x", verb: "cancel" });
|
|
260
305
|
return buildHint(entries);
|
|
@@ -31,6 +31,19 @@ export interface PermissionOverlayKeyDeps {
|
|
|
31
31
|
cancelPermission: () => void;
|
|
32
32
|
confirmPermission: () => void;
|
|
33
33
|
stopTurnFromPermission: () => void;
|
|
34
|
+
/**
|
|
35
|
+
* Whether the composer holds text. Enter must not allow a parked call while
|
|
36
|
+
* it does (issue #186): an operator who typed a message and pressed the
|
|
37
|
+
* habitual send key meant to send, and on a safety rail the ambiguous key
|
|
38
|
+
* resolves away from "allow". Absent means an empty composer.
|
|
39
|
+
*/
|
|
40
|
+
composerHasDraft?: () => boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Deliver a draft-editing key to the composer while the prompt owns input,
|
|
43
|
+
* so the draft that makes Enter inert can be cleared without first denying
|
|
44
|
+
* the call. Only the deletion keys in `isDraftEditKey` arrive here.
|
|
45
|
+
*/
|
|
46
|
+
editDraft?: (data: string) => void;
|
|
34
47
|
}
|
|
35
48
|
|
|
36
49
|
export interface DispatchBoardOverlayKeyDeps {
|
|
@@ -39,6 +52,8 @@ export interface DispatchBoardOverlayKeyDeps {
|
|
|
39
52
|
selectNextDispatch: () => void;
|
|
40
53
|
steerSelectedDispatch: () => void;
|
|
41
54
|
cancelSelectedDispatch: () => void;
|
|
55
|
+
/** Open or close the selected run's worker-progress detail. */
|
|
56
|
+
toggleSelectedDispatchDetail: () => void;
|
|
42
57
|
}
|
|
43
58
|
|
|
44
59
|
interface CloseOverlayKeyDeps {
|
|
@@ -55,10 +70,29 @@ export function isEscapeKey(data: string): boolean {
|
|
|
55
70
|
return matchesKey(data, "escape") && !isKeyRelease(data);
|
|
56
71
|
}
|
|
57
72
|
|
|
73
|
+
const DRAFT_EDIT_KEYS = ["backspace", "delete", "ctrl+u", "ctrl+w", "alt+backspace", "ctrl+k"] as const;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The keys that only ever remove text from the composer. They are the one
|
|
77
|
+
* class of input a pending permission prompt lets through, because they
|
|
78
|
+
* cannot type a command, cannot submit, and are the way out of the inert-Enter
|
|
79
|
+
* state a draft puts the prompt in.
|
|
80
|
+
*/
|
|
81
|
+
function isDraftEditKey(data: string): boolean {
|
|
82
|
+
return !isKeyRelease(data) && DRAFT_EDIT_KEYS.some((key) => matchesKey(data, key));
|
|
83
|
+
}
|
|
84
|
+
|
|
58
85
|
/** Pure permission overlay key router: returns true when the input was consumed. */
|
|
59
86
|
export function routePermissionOverlayKey(data: string, deps: PermissionOverlayKeyDeps): boolean {
|
|
60
87
|
if (matchesKey(data, "enter") && !isKeyRelease(data)) {
|
|
61
|
-
|
|
88
|
+
// Consumed either way: with a draft the press changes nothing, and the
|
|
89
|
+
// composer rail says what clears it. Letting it fall through would hand
|
|
90
|
+
// Enter to the editor, which is the send path this guard exists to block.
|
|
91
|
+
if (!(deps.composerHasDraft?.() ?? false)) deps.confirmPermission();
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
if (deps.editDraft && isDraftEditKey(data)) {
|
|
95
|
+
deps.editDraft(data);
|
|
62
96
|
return true;
|
|
63
97
|
}
|
|
64
98
|
if (isEscapeKey(data)) {
|
|
@@ -98,6 +132,12 @@ export function routeDispatchBoardOverlayKey(data: string, deps: DispatchBoardOv
|
|
|
98
132
|
deps.cancelSelectedDispatch();
|
|
99
133
|
return true;
|
|
100
134
|
}
|
|
135
|
+
// Worker progress is expanded detail the operator asks for. The default list
|
|
136
|
+
// stays compact so a fan-out of scouts costs one card each.
|
|
137
|
+
if (matchesKey(data, "enter")) {
|
|
138
|
+
deps.toggleSelectedDispatchDetail();
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
101
141
|
return false;
|
|
102
142
|
}
|
|
103
143
|
|
|
@@ -12,7 +12,9 @@ import {
|
|
|
12
12
|
createPermissionOverlayBody,
|
|
13
13
|
PERMISSION_OVERLAY_WIDTH,
|
|
14
14
|
permissionOverlayHint,
|
|
15
|
+
permissionOverlayPlacement,
|
|
15
16
|
permissionOverlayTitle,
|
|
17
|
+
permissionOverlayTone,
|
|
16
18
|
} from "./permission-overlay.js";
|
|
17
19
|
|
|
18
20
|
export * from "./overlay-key-routing.js";
|
|
@@ -82,7 +84,7 @@ export interface OverlayLifecycleRuntimeDeps {
|
|
|
82
84
|
/** Rescopes the footer's last-turn line when a session overlay changes the branch. */
|
|
83
85
|
setLastTurnSummary?: (summary: import("./status/index.js").TurnSummary | null) => void;
|
|
84
86
|
keybindings: ReturnType<typeof import("./keybinding-manager.js").createKeybindingManager>;
|
|
85
|
-
editor: Pick<import("./clio-editor.js").ClioEditor, "getText" | "setText">;
|
|
87
|
+
editor: Pick<import("./clio-editor.js").ClioEditor, "getText" | "render" | "setText">;
|
|
86
88
|
getSlashContext: () => import("./slash-commands.js").SlashCommandContext;
|
|
87
89
|
showOverlayFrame?: typeof showClioOverlayFrame;
|
|
88
90
|
openAuthDialog?: typeof import("./overlays/auth-dialog.js").openAuthDialog;
|
|
@@ -194,6 +196,7 @@ export function createOverlayLifecycle(deps: OverlayLifecycleRuntimeDeps): Overl
|
|
|
194
196
|
cancelPendingAskUser: () => overlayAskUser?.cancelPending() ?? false,
|
|
195
197
|
finishAuth: (dismiss) => overlayAuth.finish(dismiss),
|
|
196
198
|
onPermissionOverlayClosed: () => overlayPermission?.onPermissionOverlayClosed(),
|
|
199
|
+
onOverlayClosed: () => overlayPermission?.retryPending(),
|
|
197
200
|
});
|
|
198
201
|
const closeOverlay = overlayTransitions.close;
|
|
199
202
|
|
|
@@ -227,10 +230,13 @@ export function createOverlayLifecycle(deps: OverlayLifecycleRuntimeDeps): Overl
|
|
|
227
230
|
if (overlayTransitions.state !== "closed") return false;
|
|
228
231
|
overlayTransitions.state = "permission-confirm";
|
|
229
232
|
overlayTransitions.handle = showOverlayFrame(tui, createPermissionOverlayBody(view), {
|
|
230
|
-
|
|
233
|
+
...permissionOverlayPlacement(tui, editor, footer.view),
|
|
231
234
|
width: PERMISSION_OVERLAY_WIDTH,
|
|
232
|
-
title: permissionOverlayTitle(),
|
|
233
|
-
|
|
235
|
+
title: permissionOverlayTitle(view),
|
|
236
|
+
tone: permissionOverlayTone(view),
|
|
237
|
+
// Read per frame: the footer names what Enter does right now, and
|
|
238
|
+
// that depends on whether the composer holds a draft.
|
|
239
|
+
footerHint: (innerWidth) => permissionOverlayHint(innerWidth, editor.getText().length > 0),
|
|
234
240
|
});
|
|
235
241
|
tui.requestRender();
|
|
236
242
|
return true;
|
|
@@ -351,6 +357,7 @@ export function createOverlayLifecycle(deps: OverlayLifecycleRuntimeDeps): Overl
|
|
|
351
357
|
stateDir: deps.app.stateDir,
|
|
352
358
|
getSessionMeta: () => deps.app.session?.current() ?? null,
|
|
353
359
|
...(deps.app.readSessionEntries ? { readSessionEntries: deps.app.readSessionEntries } : {}),
|
|
360
|
+
...(deps.app.getSettings ? { getSettings: deps.app.getSettings } : {}),
|
|
354
361
|
terminal,
|
|
355
362
|
dispatchBoard,
|
|
356
363
|
startDispatchBoardTicker: () => interactiveTickers.startDispatchBoardTicker(),
|
|
@@ -2,9 +2,11 @@ import { BusChannels, type PermissionRequestedPayload } from "../core/bus-events
|
|
|
2
2
|
import type { SafeEventBus } from "../core/event-bus.js";
|
|
3
3
|
import { ToolNames } from "../core/tool-names.js";
|
|
4
4
|
import type { DispatchContract } from "../domains/dispatch/contract.js";
|
|
5
|
-
import type { ClassifierCall } from "../domains/safety/action-classifier.js";
|
|
5
|
+
import type { ActionClass, ClassifierCall } from "../domains/safety/action-classifier.js";
|
|
6
6
|
import { sanitizeCallTargetText } from "../domains/safety/call-target.js";
|
|
7
7
|
import type { SafetyDecision } from "../domains/safety/contract.js";
|
|
8
|
+
import { decisionActionClass } from "../domains/safety/decision-presentation.js";
|
|
9
|
+
import { askUserExposure } from "../tools/ask-user.js";
|
|
8
10
|
import type { PermissionRequiredMeta, ToolRegistry } from "../tools/registry.js";
|
|
9
11
|
import { approvalParkedNotice, autonomyDeniedNotice, workerEscalationNotice } from "./bus-notices.js";
|
|
10
12
|
import type { ToolApprovalStateEvent } from "./chat-loop.js";
|
|
@@ -29,7 +31,7 @@ interface WorkerEscalationEntry {
|
|
|
29
31
|
requestId: string;
|
|
30
32
|
agentId: string;
|
|
31
33
|
tool: string;
|
|
32
|
-
actionClass:
|
|
34
|
+
actionClass: ActionClass;
|
|
33
35
|
axis: ApprovalRequestView["axis"];
|
|
34
36
|
reason: string;
|
|
35
37
|
target?: string;
|
|
@@ -60,6 +62,14 @@ export interface OverlayPermissionLifecycle {
|
|
|
60
62
|
*/
|
|
61
63
|
stopTurn(): void;
|
|
62
64
|
onPermissionOverlayClosed(): void;
|
|
65
|
+
/**
|
|
66
|
+
* Re-present whatever is still parked once no overlay holds the screen. A
|
|
67
|
+
* request that arrived while `/context` or a picker was open could only be
|
|
68
|
+
* announced, and nothing re-attempted the dialog when that overlay closed:
|
|
69
|
+
* the transcript said awaiting approval, the footer said confirm, and the
|
|
70
|
+
* operator had no key to press (issue #186).
|
|
71
|
+
*/
|
|
72
|
+
retryPending(): void;
|
|
63
73
|
dispose(): void;
|
|
64
74
|
}
|
|
65
75
|
|
|
@@ -114,7 +124,7 @@ function mainApprovalRequestView(
|
|
|
114
124
|
(axisFromDecision.kind === "net"
|
|
115
125
|
? { kind: "net" as const, ruleId: axisFromDecision.ruleId }
|
|
116
126
|
: { kind: "autonomy" as const, level: autonomy });
|
|
117
|
-
const target = describeCallTarget(call.args);
|
|
127
|
+
const target = describeCallTarget(call.tool, call.args);
|
|
118
128
|
return {
|
|
119
129
|
requestId: meta?.requestId ?? "permission-pending",
|
|
120
130
|
tool: call.tool,
|
|
@@ -126,6 +136,7 @@ function mainApprovalRequestView(
|
|
|
126
136
|
...(call.tool === ToolNames.Dispatch && decision.kind === "ask"
|
|
127
137
|
? { artifact: { kind: "dispatch-plan" as const, text: decision.rejection.detail } }
|
|
128
138
|
: {}),
|
|
139
|
+
...(call.tool === ToolNames.AskUser ? { exposure: askUserExposure(call.args) } : {}),
|
|
129
140
|
...(target.length > 0 ? { target } : {}),
|
|
130
141
|
...(queueDepth !== undefined && queueDepth > 1 ? { queueDepth } : {}),
|
|
131
142
|
};
|
|
@@ -141,7 +152,7 @@ function workerEscalationEntry(payload: PermissionRequestedPayload, autonomy: st
|
|
|
141
152
|
requestId: payload.requestId,
|
|
142
153
|
agentId: typeof payload.agentId === "string" ? payload.agentId : "worker",
|
|
143
154
|
tool: typeof payload.tool === "string" ? payload.tool : "unknown",
|
|
144
|
-
actionClass:
|
|
155
|
+
actionClass: decisionActionClass(payload.actionClass),
|
|
145
156
|
axis:
|
|
146
157
|
axisViewFromId(typeof payload.axis === "string" ? payload.axis : undefined, autonomy) ??
|
|
147
158
|
(typeof payload.ruleId === "string"
|
|
@@ -188,6 +199,12 @@ export function createOverlayPermissionLifecycle(deps: OverlayPermissionLifecycl
|
|
|
188
199
|
const next = workerQueue.shift();
|
|
189
200
|
if (next) openWorker(next);
|
|
190
201
|
};
|
|
202
|
+
const retryPending = (): void => {
|
|
203
|
+
maybeOpenWorker();
|
|
204
|
+
if (deps.getOverlayState() === "closed" && deps.toolRegistry?.hasParkedCalls()) {
|
|
205
|
+
deps.toolRegistry.renotifyHead();
|
|
206
|
+
}
|
|
207
|
+
};
|
|
191
208
|
|
|
192
209
|
const unsubscribePermission =
|
|
193
210
|
deps.toolRegistry?.onPermissionRequired((call, decision, meta) => {
|
|
@@ -310,10 +327,7 @@ export function createOverlayPermissionLifecycle(deps: OverlayPermissionLifecycl
|
|
|
310
327
|
workerQueue.length = 0;
|
|
311
328
|
return;
|
|
312
329
|
}
|
|
313
|
-
|
|
314
|
-
if (deps.getOverlayState() === "closed" && deps.toolRegistry?.hasParkedCalls()) {
|
|
315
|
-
deps.toolRegistry.renotifyHead();
|
|
316
|
-
}
|
|
330
|
+
retryPending();
|
|
317
331
|
};
|
|
318
332
|
|
|
319
333
|
return {
|
|
@@ -336,6 +350,7 @@ export function createOverlayPermissionLifecycle(deps: OverlayPermissionLifecycl
|
|
|
336
350
|
);
|
|
337
351
|
},
|
|
338
352
|
onPermissionOverlayClosed,
|
|
353
|
+
retryPending,
|
|
339
354
|
dispose: () => {
|
|
340
355
|
unsubscribePermission();
|
|
341
356
|
unsubscribeWorker();
|
|
@@ -3,9 +3,10 @@ import type { SessionContract, SessionEntry } from "../domains/session/index.js"
|
|
|
3
3
|
import type { TUI } from "../engine/tui.js";
|
|
4
4
|
import type { ChatLoop } from "./chat-loop.js";
|
|
5
5
|
import type { ChatPanel } from "./chat-panel.js";
|
|
6
|
-
import {
|
|
6
|
+
import { rehydrateChatPanelFromTurns } from "./chat-renderer.js";
|
|
7
7
|
import { emitCommandNotice } from "./command-fallbacks.js";
|
|
8
8
|
import type { InteractiveNoticeLevel } from "./interactive-subscriptions.js";
|
|
9
|
+
import { buildModelReplayAgentMessagesFromTurns } from "./model-session-replay.js";
|
|
9
10
|
import type { OverlayTransitions } from "./overlay-transitions.js";
|
|
10
11
|
import { openCwdFallbackOverlay } from "./overlays/cwd-fallback.js";
|
|
11
12
|
import { openMessagePickerOverlay } from "./overlays/message-picker.js";
|
|
@@ -159,7 +160,7 @@ export function createOverlaySessionLifecycle(deps: OverlaySessionLifecycleDeps)
|
|
|
159
160
|
const replayOptions = leafTurnId ? { activeLeafTurnId: leafTurnId } : {};
|
|
160
161
|
deps.resetTranscript();
|
|
161
162
|
rehydrateChatPanelFromTurns(deps.chatPanel, turns, replayOptions);
|
|
162
|
-
const replayMessages =
|
|
163
|
+
const replayMessages = buildModelReplayAgentMessagesFromTurns(turns, replayOptions);
|
|
163
164
|
deps.chat.resetForSession(leafTurnId, replayMessages);
|
|
164
165
|
rescopeToBranch(session, turns, leafTurnId);
|
|
165
166
|
} catch (error) {
|
|
@@ -209,7 +210,7 @@ export function createOverlaySessionLifecycle(deps: OverlaySessionLifecycleDeps)
|
|
|
209
210
|
const turns = deps.readStructuredEntries(sessionId);
|
|
210
211
|
deps.resetTranscript();
|
|
211
212
|
rehydrateChatPanelFromTurns(deps.chatPanel, turns, { uptoTurnId: turnId });
|
|
212
|
-
const replayMessages =
|
|
213
|
+
const replayMessages = buildModelReplayAgentMessagesFromTurns(turns, { uptoTurnId: turnId });
|
|
213
214
|
deps.chat.resetForSession(turnId, replayMessages);
|
|
214
215
|
// The same branch the transcript above was just scoped to. Without the
|
|
215
216
|
// leaf, /cost, the footer Σ, and the last-turn line kept reporting the
|
|
@@ -287,8 +288,11 @@ export function createOverlaySessionLifecycle(deps: OverlaySessionLifecycleDeps)
|
|
|
287
288
|
try {
|
|
288
289
|
const turns = deps.readStructuredEntries(forkedSessionId);
|
|
289
290
|
rehydrateChatPanelFromTurns(deps.chatPanel, turns);
|
|
290
|
-
const replayMessages = buildReplayAgentMessagesFromTurns(turns);
|
|
291
291
|
const leafTurnId = session.tree(forkedSessionId).leafId ?? parentTurnId;
|
|
292
|
+
const replayMessages = buildModelReplayAgentMessagesFromTurns(
|
|
293
|
+
turns,
|
|
294
|
+
leafTurnId ? { activeLeafTurnId: leafTurnId } : {},
|
|
295
|
+
);
|
|
292
296
|
deps.chat.resetForSession(leafTurnId, replayMessages);
|
|
293
297
|
rescopeToBranch(session, turns, leafTurnId);
|
|
294
298
|
} catch (error) {
|
|
@@ -9,6 +9,12 @@ export interface OverlayTransitionsDeps {
|
|
|
9
9
|
cancelPendingAskUser: () => boolean;
|
|
10
10
|
finishAuth: (dismiss: boolean) => void;
|
|
11
11
|
onPermissionOverlayClosed: () => void;
|
|
12
|
+
/**
|
|
13
|
+
* Runs after any overlay has closed and the state is back to `closed`. The
|
|
14
|
+
* permission lifecycle uses it to re-present a call that parked while this
|
|
15
|
+
* overlay held the screen; nothing else re-attempts that dialog.
|
|
16
|
+
*/
|
|
17
|
+
onOverlayClosed?: () => void;
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
export interface OverlayTransitions {
|
|
@@ -26,7 +32,11 @@ export function createOverlayTransitions(deps: OverlayTransitionsDeps): OverlayT
|
|
|
26
32
|
return state;
|
|
27
33
|
},
|
|
28
34
|
set state(next) {
|
|
35
|
+
const closing = state !== "closed" && next === "closed";
|
|
29
36
|
state = next;
|
|
37
|
+
// The ask-user and auth lifecycles leave by assigning the state rather
|
|
38
|
+
// than through `close`, so the hook fires here for them.
|
|
39
|
+
if (closing) deps.onOverlayClosed?.();
|
|
30
40
|
},
|
|
31
41
|
get handle() {
|
|
32
42
|
return handle;
|
|
@@ -50,6 +60,7 @@ export function createOverlayTransitions(deps: OverlayTransitionsDeps): OverlayT
|
|
|
50
60
|
handle?.hide();
|
|
51
61
|
handle = null;
|
|
52
62
|
if (leaving === "permission-confirm") deps.onPermissionOverlayClosed();
|
|
63
|
+
else deps.onOverlayClosed?.();
|
|
53
64
|
deps.renderContextIsland();
|
|
54
65
|
deps.renderTaskIsland();
|
|
55
66
|
deps.requestRender();
|