@iowarp/clio-coder 0.3.1 → 0.3.2
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 +90 -2
- package/CONTRIBUTING.md +23 -23
- package/README.md +284 -613
- package/dist/{acp-FPR54DGL.js → acp-BIYHVZIM.js} +43 -53
- package/dist/{agents-OGPIHPJH.js → agents-YT6SSRIT.js} +43 -26
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-IC3K6NIZ.js → auth-5TWEIYDN.js} +20 -12
- package/dist/{chunk-PV4JUBVJ.js → chunk-2EHAIA3X.js} +40 -21
- package/dist/{chunk-IS3ONKU3.js → chunk-2IR2NMPA.js} +6 -4
- package/dist/chunk-2SFS6XQE.js +122 -0
- package/dist/chunk-2VTFPG5O.js +48 -0
- package/dist/{chunk-MAR7Y6HW.js → chunk-3ZXDFGR5.js} +23 -16
- package/dist/chunk-4BJ5BYCE.js +61 -0
- package/dist/{chunk-474KN5II.js → chunk-4BPJXDWC.js} +111 -181
- package/dist/chunk-4KLWL3UC.js +18 -0
- package/dist/chunk-4VP4KH3K.js +962 -0
- package/dist/chunk-4ZG3XFUR.js +77 -0
- package/dist/chunk-5B2AEOW5.js +5407 -0
- package/dist/{chunk-K2ITRMHZ.js → chunk-5TSRNF4G.js} +6 -138
- package/dist/{chunk-OLBBMFRD.js → chunk-5UUP6MWO.js} +24 -62
- package/dist/chunk-65DEGPJ6.js +52 -0
- package/dist/chunk-6EJMN2Y3.js +17 -0
- package/dist/chunk-6EJV5X2W.js +16405 -0
- package/dist/chunk-6N5PTWMY.js +136 -0
- package/dist/chunk-6XLNIQDB.js +27 -0
- package/dist/{chunk-TEKV33Q5.js → chunk-77VKQEHF.js} +65 -33
- package/dist/chunk-7CR24IG7.js +242 -0
- package/dist/{chunk-M5T5VO65.js → chunk-7EYHLWU7.js} +837 -635
- package/dist/chunk-7MNJORFF.js +22 -0
- package/dist/{chunk-KY56HMHH.js → chunk-A3CYT5EX.js} +125 -31
- package/dist/chunk-AGYYIBLL.js +1069 -0
- package/dist/chunk-AO4RKG4M.js +277 -0
- package/dist/{chunk-GB6QRBXN.js → chunk-APJ265NV.js} +54 -1187
- package/dist/chunk-ARBGF5F7.js +174 -0
- package/dist/{chunk-673JJUWJ.js → chunk-BMEMKKIT.js} +2 -2
- package/dist/chunk-CBCAPZAA.js +229 -0
- package/dist/chunk-CMZWFGD2.js +352 -0
- package/dist/chunk-ECH6PKUQ.js +39 -0
- package/dist/chunk-ED4KHGC3.js +143 -0
- package/dist/chunk-EKMEHE4H.js +340 -0
- package/dist/{chunk-RPTR2H26.js → chunk-EPVUXGXG.js} +21 -15
- package/dist/chunk-FCSXB6T2.js +338 -0
- package/dist/chunk-FJ3H4MN5.js +48 -0
- package/dist/chunk-FQ4SKYE4.js +29 -0
- package/dist/chunk-G2DE3C7R.js +644 -0
- package/dist/chunk-G4BMMOKF.js +182 -0
- package/dist/{chunk-ZPY3JZ5E.js → chunk-GGXXDWE4.js} +183 -1233
- package/dist/chunk-HC4CLZ2Y.js +68 -0
- package/dist/{chunk-LU4TK2PR.js → chunk-HFSBBKSQ.js} +5 -56
- package/dist/{chunk-PIUMUEMV.js → chunk-HKIYEGME.js} +10 -6
- package/dist/chunk-I4HZDVNP.js +73 -0
- package/dist/{chunk-4QKXUHSR.js → chunk-IGLFWIYI.js} +70 -20
- package/dist/chunk-IKCO5N3L.js +162 -0
- package/dist/chunk-IR4CFBFN.js +56 -0
- package/dist/{chunk-PFEFKVGL.js → chunk-J5HN4RYU.js} +13 -11
- package/dist/{chunk-R5KLMSBV.js → chunk-J5Q24KAG.js} +2 -2
- package/dist/{chunk-K5XEMXTI.js → chunk-JVCV3ICN.js} +1 -1
- package/dist/chunk-KJ5LWLOE.js +1077 -0
- package/dist/chunk-LBMZMYH2.js +285 -0
- package/dist/{chunk-G34LV2PF.js → chunk-LBNRH5WM.js} +84 -170
- package/dist/{chunk-H6F6BYOH.js → chunk-LZSJBIVT.js} +7003 -7434
- package/dist/{chunk-HQQID6OA.js → chunk-M6SHUN7Q.js} +5 -5
- package/dist/chunk-MAW544W2.js +1882 -0
- package/dist/chunk-MBS4V7ZP.js +217 -0
- package/dist/{chunk-FST4FYJB.js → chunk-MFFY33HR.js} +99 -140
- package/dist/chunk-MNA4JGU4.js +255 -0
- package/dist/chunk-MQSRRFWA.js +3428 -0
- package/dist/{chunk-BSU2YIWB.js → chunk-MVVUPGPW.js} +131 -136
- package/dist/chunk-OAO4GE4M.js +619 -0
- package/dist/chunk-OHHN2SO4.js +5135 -0
- package/dist/chunk-OKGUZO2U.js +34 -0
- package/dist/{chunk-GAEBEQVI.js → chunk-OOJYHWRB.js} +32 -346
- package/dist/{chunk-Q5WJOSJ7.js → chunk-OQ33BKR3.js} +2 -1
- package/dist/chunk-OQE5J4C6.js +73 -0
- package/dist/{chunk-KKNLWXI6.js → chunk-ORBHGJC5.js} +8 -8
- package/dist/chunk-POHLU5DW.js +1186 -0
- package/dist/chunk-QKMUKYO7.js +4961 -0
- package/dist/{chunk-ASND7OZK.js → chunk-QTYWRVRA.js} +13 -13
- package/dist/{chunk-EYOKLTMF.js → chunk-SRF2PJNW.js} +17 -3
- package/dist/chunk-SST6Z5JA.js +80 -0
- package/dist/chunk-STBPMHSX.js +2456 -0
- package/dist/chunk-T6YILFSB.js +80 -0
- package/dist/chunk-TZTZS7QK.js +227 -0
- package/dist/chunk-UOV2BYIW.js +107 -0
- package/dist/{chunk-Q3RUPKEJ.js → chunk-V4RXGQ5Q.js} +58 -189
- package/dist/chunk-VAKQQHWR.js +434 -0
- package/dist/chunk-VG7TBQIY.js +128 -0
- package/dist/chunk-VJWL6YS5.js +244 -0
- package/dist/chunk-WEH5XRJQ.js +32 -0
- package/dist/chunk-WMSVI4G2.js +2095 -0
- package/dist/chunk-WVO7V2QY.js +797 -0
- package/dist/chunk-X4RCMKVQ.js +641 -0
- package/dist/chunk-X75S7HFS.js +374 -0
- package/dist/chunk-XN3L4EYL.js +46 -0
- package/dist/{chunk-RDLVBZEO.js → chunk-YCWGATWI.js} +6 -4
- package/dist/chunk-YHZX5GEU.js +193 -0
- package/dist/chunk-YXLYO42X.js +91 -0
- package/dist/{chunk-NMOX6HFD.js → chunk-ZDOOVTXZ.js} +29 -77
- package/dist/chunk-ZI647VB5.js +37 -0
- package/dist/{chunk-C4PTHK7P.js → chunk-ZWLZP4ZT.js} +5 -5
- package/dist/cli/index.js +62 -54
- package/dist/clio-4LY5K2AC.js +25 -0
- package/dist/code-nav-7AX6FYE6.js +600 -0
- package/dist/codewiki/build-worker.js +66 -0
- package/dist/compile-cache-CVJMMODC.js +18 -0
- package/dist/{components-DMAOEKFB.js → components-KELWS457.js} +11 -6
- package/dist/{config-IRUQ7SE4.js → config-GTLUW2PR.js} +92 -55
- package/dist/configure-R6A64DHX.js +42 -0
- package/dist/context-5VKGUVJJ.js +866 -0
- package/dist/{context-3KWFLHJG.js → context-JFZEJ7W5.js} +15 -13
- package/dist/{context-5RADCKTR.js → context-RW5HC47S.js} +71 -35
- package/dist/{context-clear-7TSNPAAI.js → context-clear-6ZHBAZZT.js} +54 -28
- package/dist/{context-index-W4RLWOQH.js → context-index-BZ4UYMTC.js} +30 -24
- package/dist/dispatch-runner-VKBRCWQC.js +1997 -0
- package/dist/{docs-5AWSPS37.js → docs-2C2LTVT2.js} +23 -10
- package/dist/{doctor-UC5NAJYQ.js → doctor-KI767GSN.js} +27 -17
- package/dist/{eval-U6TJHRLX.js → eval-XSSNATB4.js} +29 -16
- package/dist/{evidence-YEGUW4L3.js → evidence-UA6AWDQQ.js} +46 -26
- package/dist/{evolve-TXARCTPG.js → evolve-QNTFGV6Z.js} +45 -25
- package/dist/{extensions-OZFJ3A3G.js → extensions-QVDOHDGJ.js} +16 -7
- package/dist/{fleet-6G3DHNYE.js → fleet-Q7UOMUSG.js} +163 -54
- package/dist/{fleet-preflight-DSNT37JK.js → fleet-preflight-DDN536IT.js} +7 -4
- package/dist/{init-KZ5QTF6M.js → init-WBB65ZHQ.js} +69 -32
- package/dist/{memory-73ESV5YC.js → memory-MD3O64RI.js} +48 -27
- package/dist/{models-A4PVNWJK.js → models-BZU34YWD.js} +39 -25
- package/dist/monitor-MEQA5C3I.js +661 -0
- package/dist/{chunk-FCIH3BIZ.js → orchestrator-CGFKEP27.js} +11832 -8687
- package/dist/{paths-C4H6IV77.js → paths-UXLN5YYZ.js} +10 -5
- package/dist/{preload-6WVMHX3A.js → preload-P6DGH2PZ.js} +2 -2
- package/dist/{reset-BGW6OGMV.js → reset-L2FQEE3E.js} +16 -10
- package/dist/{run-YTPEYQOH.js → run-IV4Q6RLN.js} +101 -61
- package/dist/{share-YIFFV4NQ.js → share-S5BZQC5I.js} +15 -8
- package/dist/{skills-2V6RA3OQ.js → skills-LQEKRDTN.js} +34 -14
- package/dist/{skills-eval-S2TVJO4F.js → skills-eval-3DC4HEWS.js} +70 -34
- package/dist/steer-GGWFUJUD.js +77 -0
- package/dist/{targets-TYXLPB23.js → targets-C4SSGQOB.js} +43 -27
- package/dist/terminal-lease-IT5JW2NR.js +395 -0
- package/dist/{trace-GGOJ6Q6Z.js → trace-PNCASAXC.js} +41 -16
- package/dist/{chunk-N6F52NLF.js → tree-sitter-HGKH6LG4.js} +28 -2306
- package/dist/{uninstall-LLLT4F4W.js → uninstall-FZCQCDKC.js} +10 -5
- package/dist/{upgrade-33G2LMM5.js → upgrade-7TT7SQ3G.js} +45 -25
- package/dist/{usage-ZAFSXKKG.js → usage-GV4PKT3M.js} +62 -31
- package/dist/verify-G6V4D2G7.js +716 -0
- package/dist/web-fetch-2YHJ3KTG.js +638 -0
- package/dist/{wiki-generate-NUQCVOQ3.js → wiki-generate-DQF6Z66B.js} +74 -34
- package/dist/worker/entry.js +221 -36
- package/dist/workspace-G4ZWUIPR.js +22 -0
- package/docs/README.md +22 -17
- package/docs/acp.md +168 -16
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +136 -7
- 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 +114 -71
- package/docs/config-knobs-audit.md +1 -3
- package/docs/configuration-and-targets.md +174 -46
- package/docs/context-engine.md +29 -6
- package/docs/development-pipeline.md +26 -1
- package/docs/dispatch-architecture-rationale.md +1 -1
- package/docs/documentation-coverage.md +2 -2
- package/docs/documentation-guide.md +1 -1
- package/docs/environment-variables.md +13 -5
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +1 -1
- package/docs/evidence-and-memory.md +6 -2
- package/docs/evolution.md +2 -2
- package/docs/exit-codes-and-output.md +15 -9
- package/docs/extensions-and-sharing.md +9 -9
- package/docs/fleet-dispatch.md +7 -5
- package/docs/git-commit-provenance.md +120 -0
- package/docs/glossary.md +1 -1
- package/docs/installation-and-lifecycle.md +34 -27
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +45 -14
- package/docs/observability.md +8 -5
- package/docs/performance-methodology.md +491 -0
- package/docs/pi-boundary.md +72 -0
- package/docs/proactive-memory.md +3 -3
- package/docs/prompt-envelope-and-tools.md +24 -3
- package/docs/provider-adapter-cookbook.md +57 -4
- package/docs/release-cut-checklist.md +129 -115
- package/docs/safety-model.md +9 -5
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +55 -12
- package/docs/skills-marketplace.md +12 -8
- package/docs/time-conventions.md +1 -1
- package/docs/tool-usage.md +3 -3
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +10 -7
- package/docs/tui-design.md +47 -10
- package/docs/worker-dispatch-mechanics.md +1 -1
- package/package.json +19 -22
- package/skills/coding/ast-grep/SKILL.md +136 -0
- package/skills/coding/ast-grep/evals.md +56 -0
- package/skills/coding/ast-grep/references/rule_reference.md +297 -0
- package/skills/coding/coding-standards/SKILL.md +113 -0
- package/skills/coding/coding-standards/evals.md +34 -0
- package/skills/coding/prototype/SKILL.md +86 -0
- package/skills/coding/prototype/evals.md +42 -0
- package/skills/coding/prototype/references/LOGIC.md +67 -0
- package/skills/coding/prototype/references/UI.md +112 -0
- package/skills/coding/tdd/SKILL.md +101 -0
- package/skills/coding/tdd/evals.md +41 -0
- package/skills/coding/tdd/references/mocking.md +59 -0
- package/skills/coding/tdd/references/tests.md +77 -0
- package/skills/context/context-handoff/SKILL.md +126 -0
- package/skills/context/context-handoff/evals.md +57 -0
- package/skills/context/context-handoff/scripts/new-handoff.sh +26 -0
- package/skills/context/context-prime/SKILL.md +95 -0
- package/skills/context/context-prime/evals.md +54 -0
- package/skills/meta/clio-dev/SKILL.md +91 -0
- package/skills/meta/clio-dev/evals.md +45 -0
- package/skills/meta/clio-test/SKILL.md +130 -0
- package/skills/meta/clio-test/evals.md +43 -0
- package/skills/meta/clio-test/references/harness.md +97 -0
- package/skills/meta/clio-test/references/test-map.md +59 -0
- package/skills/meta/credentials/SKILL.md +125 -0
- package/skills/meta/credentials/evals.md +104 -0
- package/skills/meta/find-skills/SKILL.md +72 -0
- package/skills/meta/find-skills/evals.md +47 -0
- package/skills/meta/herdr/SKILL.md +127 -0
- package/skills/meta/herdr/evals.md +38 -0
- package/skills/meta/skill-craft/SKILL.md +102 -0
- package/skills/meta/skill-craft/evals.md +41 -0
- package/skills/planning/architecture/SKILL.md +129 -0
- package/skills/planning/architecture/evals.md +36 -0
- package/skills/planning/backlog/SKILL.md +90 -0
- package/skills/planning/backlog/evals.md +43 -0
- package/skills/planning/prd/SKILL.md +82 -0
- package/skills/planning/prd/evals.md +49 -0
- package/skills/planning/product-intent/SKILL.md +112 -0
- package/skills/planning/product-intent/evals.md +36 -0
- package/skills/planning/tech-spec/SKILL.md +115 -0
- package/skills/planning/tech-spec/evals.md +47 -0
- package/skills/registry.yaml +136 -0
- package/skills/research/arxiv-literature/SKILL.md +104 -0
- package/skills/research/arxiv-literature/evals.md +58 -0
- package/skills/research/experiment-protocol/SKILL.md +122 -0
- package/skills/research/experiment-protocol/evals.md +91 -0
- package/skills/research/scientific-debugging/SKILL.md +119 -0
- package/skills/research/scientific-debugging/evals.md +138 -0
- package/skills/research/scientific-modernization/SKILL.md +138 -0
- package/skills/research/scientific-modernization/evals.md +84 -0
- package/skills/workflow/design-council/SKILL.md +139 -0
- package/skills/workflow/design-council/evals.md +97 -0
- package/skills/workflow/grill-me/SKILL.md +186 -0
- package/skills/workflow/grill-me/evals.md +78 -0
- package/skills/workflow/workflow-distiller/SKILL.md +136 -0
- package/skills/workflow/workflow-distiller/evals.md +107 -0
- package/src/cli/acp.ts +31 -4
- package/src/cli/clio.ts +68 -6
- package/src/cli/config-inspect.ts +28 -22
- package/src/cli/configure.ts +47 -9
- package/src/cli/context-clear.ts +2 -2
- package/src/cli/context-index.ts +21 -23
- package/src/cli/context.ts +13 -8
- package/src/cli/default-target.ts +9 -17
- package/src/cli/docs.ts +11 -5
- package/src/cli/evidence.ts +4 -1
- package/src/cli/extensions.ts +10 -1
- package/src/cli/fleet.ts +47 -6
- package/src/cli/index.ts +55 -26
- package/src/cli/memory.ts +3 -1
- package/src/cli/models.ts +1 -1
- package/src/cli/modes/json-stream.ts +37 -1
- package/src/cli/modes/print.ts +24 -9
- package/src/cli/run.ts +2 -2
- package/src/cli/skills-eval.ts +23 -8
- package/src/cli/skills.ts +19 -4
- package/src/cli/targets.ts +4 -0
- package/src/cli/text-layout.ts +15 -5
- package/src/cli/trace.ts +62 -14
- package/src/cli/upgrade.ts +18 -2
- package/src/cli/usage.ts +10 -3
- package/src/cli/wiki-generate.ts +2 -1
- package/src/core/agent-environment.ts +7 -0
- package/src/core/bash-exec.ts +72 -1
- package/src/core/boot-trace.ts +9 -4
- package/src/core/bus-events.ts +20 -4
- package/src/core/commit-attribution.ts +157 -0
- package/src/core/compile-cache.ts +159 -0
- package/src/core/config.ts +131 -2
- package/src/core/defaults.ts +39 -5
- package/src/core/domain-loader.ts +12 -5
- package/src/core/git-commit-attribution.ts +362 -0
- package/src/core/incomplete-installation.ts +45 -0
- package/src/core/response-schema.ts +1 -1
- package/src/core/safe-exec.ts +13 -1
- package/src/core/settings-layers.ts +155 -21
- package/src/core/skill-activation.ts +1 -1
- package/src/core/startup-timer.ts +3 -3
- package/src/core/state-file-lock.ts +13 -1
- package/src/core/termination.ts +78 -5
- package/src/domains/config/classify.ts +15 -3
- package/src/domains/config/extension.ts +19 -13
- package/src/domains/config/index.ts +10 -0
- package/src/domains/config/keybindings.ts +42 -6
- package/src/domains/context/bootstrap-prompt.ts +1 -1
- package/src/domains/context/bootstrap.ts +111 -18
- package/src/domains/context/clear.ts +16 -11
- package/src/domains/context/clio-md.ts +111 -9
- package/src/domains/context/codewiki/artifact.ts +400 -0
- package/src/domains/context/codewiki/build-worker-protocol.ts +24 -0
- package/src/domains/context/codewiki/build-worker.ts +54 -0
- package/src/domains/context/codewiki/coordinator.ts +182 -0
- package/src/domains/context/codewiki/indexer.ts +59 -144
- package/src/domains/context/codewiki/paths.ts +67 -0
- package/src/domains/context/codewiki/schema.ts +80 -0
- package/src/domains/context/codewiki/tree-sitter.ts +1 -1
- package/src/domains/context/contract.ts +11 -5
- package/src/domains/context/extension.ts +94 -143
- package/src/domains/context/fingerprint.ts +3 -1
- package/src/domains/context/index.ts +12 -22
- package/src/domains/context/project-metadata.ts +19 -0
- package/src/domains/context/prompt-context.ts +9 -10
- package/src/domains/context/refresh.ts +29 -21
- package/src/domains/context/runtime.ts +17 -0
- package/src/domains/context/wiki/generate.ts +39 -34
- package/src/domains/context/wiki/plan.ts +1 -1
- package/src/domains/context/wiki/prompts.ts +21 -8
- package/src/domains/dispatch/code-step.ts +20 -1
- package/src/domains/dispatch/extension.ts +158 -21
- package/src/domains/dispatch/failure-classification.ts +6 -0
- package/src/domains/dispatch/fleet-commit-attribution.ts +56 -0
- package/src/domains/dispatch/orphan-recovery.ts +50 -8
- package/src/domains/dispatch/receipt-integrity.ts +5 -0
- package/src/domains/dispatch/state.ts +31 -6
- package/src/domains/dispatch/transport.ts +2 -1
- package/src/domains/dispatch/types.ts +14 -0
- package/src/domains/dispatch/worker-spawn.ts +21 -2
- package/src/domains/eval/metrics/context.ts +1 -1
- package/src/domains/eval/types.ts +0 -1
- package/src/domains/evidence/build.ts +41 -1
- package/src/domains/lifecycle/migrations/2026-08-18-lmstudio-runtime-id.ts +52 -0
- package/src/domains/lifecycle/migrations/index.ts +24 -4
- package/src/domains/middleware/hooks-io.ts +12 -0
- package/src/domains/middleware/skills-reminder.ts +30 -15
- package/src/domains/prompts/compiler.ts +142 -84
- package/src/domains/prompts/contract.ts +18 -2
- package/src/domains/prompts/extension.ts +39 -7
- package/src/domains/prompts/fragment-loader.ts +0 -1
- package/src/domains/prompts/fragments/identity/clio.md +2 -4
- package/src/domains/prompts/fragments/identity/docs-routing.md +10 -0
- package/src/domains/prompts/fragments/identity/self-awareness.md +1 -45
- package/src/domains/prompts/fragments/operating/contract.md +4 -50
- package/src/domains/prompts/fragments/operating/delegation.md +42 -0
- package/src/domains/prompts/fragments/operating/skills.md +26 -0
- package/src/domains/prompts/fragments/operating/worker.md +16 -0
- package/src/domains/prompts/fragments/safety/auto-edit.md +5 -5
- package/src/domains/prompts/fragments/safety/full-auto.md +3 -3
- package/src/domains/prompts/fragments/safety/read-only.md +4 -4
- package/src/domains/prompts/fragments/safety/suggest.md +2 -2
- package/src/domains/prompts/fragments/wiki/page.md +10 -0
- package/src/domains/prompts/fragments/wiki/plan.md +10 -0
- package/src/domains/prompts/preload.ts +3 -3
- package/src/domains/providers/auth/api-key.ts +1 -1
- package/src/domains/providers/auth/backend-file.ts +20 -10
- package/src/domains/providers/auth/backend-memory.ts +59 -4
- package/src/domains/providers/auth/boot-status.ts +65 -0
- package/src/domains/providers/auth/oauth.ts +2 -1
- package/src/domains/providers/auth/storage.ts +97 -38
- package/src/domains/providers/capabilities.ts +12 -4
- package/src/domains/providers/contract.ts +15 -4
- package/src/domains/providers/extension.ts +18 -6
- package/src/domains/providers/model-runtime-capabilities.ts +15 -4
- package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +118 -35
- package/src/domains/providers/plugins.ts +5 -3
- package/src/domains/providers/probe/fingerprint.ts +25 -5
- package/src/domains/providers/registry.ts +31 -10
- package/src/domains/providers/runtimes/boot-manifest.ts +55 -0
- package/src/domains/providers/runtimes/builtins.ts +2 -2
- package/src/domains/providers/runtimes/common/lmstudio-http.ts +423 -0
- package/src/domains/providers/runtimes/common/local-synth.ts +6 -7
- package/src/domains/providers/runtimes/local-native/lmstudio.ts +241 -0
- package/src/domains/providers/support.ts +6 -3
- package/src/domains/providers/types/local-model-quirks.ts +7 -9
- package/src/domains/providers/types/runtime-descriptor.ts +12 -1
- package/src/domains/providers/types/target-descriptor.ts +22 -0
- package/src/domains/resources/contract.ts +0 -1
- package/src/domains/resources/extension.ts +1 -3
- package/src/domains/resources/loader.ts +3 -4
- package/src/domains/resources/prompts/loader.ts +16 -2
- package/src/domains/resources/prompts/substitute.ts +1 -65
- package/src/domains/resources/skills/content-hash.ts +2 -0
- package/src/domains/resources/skills/install.ts +17 -0
- package/src/domains/resources/skills/loader.ts +17 -10
- package/src/domains/resources/skills/marketplace.ts +55 -9
- package/src/domains/safety/action-classifier.ts +4 -2
- package/src/domains/safety/audit.ts +8 -2
- package/src/domains/safety/extension.ts +1 -1
- package/src/domains/session/compaction/branch-summary.ts +3 -2
- package/src/domains/session/compaction/cut-point.ts +2 -1
- package/src/domains/session/compaction/tokens.ts +2 -1
- package/src/domains/session/context-ledger.ts +14 -0
- package/src/domains/session/contract.ts +15 -0
- package/src/domains/session/decision-board.ts +190 -0
- package/src/domains/session/entries.ts +66 -3
- package/src/domains/session/extension.ts +93 -12
- package/src/domains/session/retry.ts +10 -18
- package/src/domains/session/session-artifacts.ts +107 -0
- package/src/domains/session/task-board.ts +207 -13
- package/src/domains/session/tree/active-path.ts +44 -5
- package/src/domains/session/tree/fork.ts +26 -27
- package/src/domains/session/tree/preview.ts +2 -2
- package/src/domains/session/workspace/git-probe.ts +17 -11
- package/src/domains/user-tasks/store.ts +297 -0
- package/src/engine/acp/errors.ts +96 -0
- package/src/engine/acp/server.ts +1728 -146
- package/src/engine/acp/transport.ts +135 -14
- package/src/engine/acp/types.ts +26 -0
- package/src/engine/agent.ts +3 -3
- package/src/engine/ai.ts +32 -27
- package/src/engine/alcf-oauth.ts +26 -19
- package/src/engine/api-registry.ts +223 -0
- package/src/engine/apis/index.ts +3 -7
- package/src/engine/apis/llamacpp-residency.ts +49 -9
- package/src/engine/apis/lmstudio-residency.ts +5 -21
- package/src/engine/apis/lmstudio.ts +243 -0
- package/src/engine/apis/ollama-native.ts +24 -3
- package/src/engine/apis/openai-completions.ts +170 -91
- package/src/engine/apis/residency.ts +139 -3
- package/src/engine/apis/types.ts +16 -0
- package/src/engine/env-api-keys.ts +98 -0
- package/src/engine/gemma-channel-filter.ts +223 -0
- package/src/engine/instrumented-tui.ts +192 -0
- package/src/engine/messages.ts +14 -0
- package/src/engine/models.ts +42 -0
- package/src/engine/oauth.ts +16 -12
- package/src/engine/prompt-templates.ts +1 -0
- package/src/engine/provider-payload.ts +16 -59
- package/src/engine/strip-tokenizer-sentinels.ts +1 -1
- package/src/engine/truncate.ts +9 -0
- package/src/engine/tui.ts +17 -9
- package/src/engine/types.ts +3 -6
- package/src/engine/worker-runtime-capabilities.ts +5 -0
- package/src/engine/worker-runtime.ts +1 -1
- package/src/engine/worker-tools.ts +9 -4
- package/src/entry/boot-options.ts +50 -0
- package/src/entry/orchestrator.ts +288 -150
- package/src/interactive/application-controller.ts +89 -2
- package/src/interactive/chat-loop.ts +266 -41
- package/src/interactive/chat-panel.ts +173 -47
- package/src/interactive/chat-renderer.ts +262 -72
- package/src/interactive/clio-editor.ts +3 -8
- package/src/interactive/command-fallbacks.ts +2 -2
- package/src/interactive/context-overlay.ts +27 -1
- package/src/interactive/editor-submit.ts +228 -24
- package/src/interactive/export-html/ansi-to-html.ts +161 -0
- package/src/interactive/export-html/index.ts +51 -0
- package/src/interactive/export-html/template.ts +45 -0
- package/src/interactive/export-html/tool-renderer.ts +54 -0
- package/src/interactive/footer/dashboard.ts +4 -0
- package/src/interactive/footer/notifications.ts +1 -1
- package/src/interactive/footer/widgets.ts +20 -2
- package/src/interactive/footer-panel.ts +2 -2
- package/src/interactive/format-time.ts +14 -2
- package/src/interactive/interactive-application.ts +201 -17
- package/src/interactive/interactive-event-projection.ts +6 -1
- package/src/interactive/interactive-input-runtime.ts +50 -4
- package/src/interactive/interactive-presentation.ts +151 -19
- package/src/interactive/interactive-shell.ts +268 -14
- package/src/interactive/interactive-slash-runtime.ts +176 -114
- package/src/interactive/interactive-tickers.ts +38 -7
- package/src/interactive/keybinding-manager.ts +1 -1
- package/src/interactive/layout.ts +40 -3
- package/src/interactive/overlay-frame.ts +1 -1
- package/src/interactive/overlay-general-openers.ts +58 -1
- package/src/interactive/overlay-key-routing.ts +3 -0
- package/src/interactive/overlay-lifecycle.ts +13 -0
- package/src/interactive/overlay-permission-lifecycle.ts +2 -1
- package/src/interactive/overlay-session-lifecycle.ts +69 -12
- package/src/interactive/overlays/decisions.ts +300 -0
- package/src/interactive/overlays/help-reference.ts +15 -10
- package/src/interactive/overlays/model-selector.ts +34 -16
- package/src/interactive/overlays/session-selector.ts +18 -0
- package/src/interactive/overlays/settings.ts +105 -17
- package/src/interactive/overlays/skills-hub.ts +4 -4
- package/src/interactive/overlays/tree-selector.ts +41 -6
- package/src/interactive/render-trace.ts +499 -90
- package/src/interactive/renderers/compaction-summary.ts +2 -2
- package/src/interactive/renderers/diff.ts +115 -104
- package/src/interactive/renderers/mermaid.ts +53 -0
- package/src/interactive/renderers/tool-execution.ts +386 -133
- package/src/interactive/renderers/worker-entry.ts +20 -4
- package/src/interactive/session-switch-settlement.ts +10 -0
- package/src/interactive/slash-autocomplete.ts +6 -114
- package/src/interactive/slash-commands.ts +135 -47
- package/src/interactive/slash-spec.ts +9 -38
- package/src/interactive/status/controller.ts +5 -1
- package/src/interactive/stdout-backpressure.ts +99 -0
- package/src/interactive/stream-pacer.ts +530 -0
- package/src/interactive/stream-pacing-policy.ts +66 -0
- package/src/interactive/tasks-overlay.ts +368 -14
- package/src/interactive/terminal-lease.ts +485 -0
- package/src/interactive/theme/tokens.ts +1 -1
- package/src/interactive/turn-context.ts +4 -3
- package/src/interactive/turn-persistence.ts +30 -13
- package/src/interactive/turn-queues.ts +12 -0
- package/src/interactive/turn-recovery.ts +25 -8
- package/src/interactive/turn-runtime.ts +79 -12
- package/src/interactive/turn-state.ts +10 -0
- package/src/interactive/view/artifacts.ts +114 -4
- package/src/interactive/view/view-overlay.ts +3 -0
- package/src/interactive/welcome-dashboard.ts +17 -16
- package/src/interactive/worker-receipts.ts +52 -3
- package/src/interactive/worker-stream.ts +5 -1
- package/src/tools/agent-tools.ts +23 -3
- package/src/tools/artifact.ts +2 -2
- package/src/tools/ask-user.ts +23 -13
- package/src/tools/bash.ts +30 -2
- package/src/tools/bootstrap.ts +34 -431
- package/src/tools/builtin-tool-catalog.ts +265 -0
- package/src/tools/codewiki/code-nav-surface.ts +29 -0
- package/src/tools/codewiki/code-nav.ts +8 -22
- package/src/tools/codewiki/shared.ts +41 -38
- package/src/tools/context/docs-engine.ts +14 -3
- package/src/tools/context/index.ts +107 -28
- package/src/tools/context/surface.ts +19 -0
- package/src/tools/core-bootstrap.ts +168 -0
- package/src/tools/credential-present.ts +5 -5
- package/src/tools/dispatch-admission.ts +533 -0
- package/src/tools/dispatch-background.ts +54 -0
- package/src/tools/dispatch-event-text.ts +6 -0
- package/src/tools/dispatch-plan.ts +9 -4
- package/src/tools/dispatch-run-events.ts +238 -0
- package/src/tools/dispatch-runner.ts +2370 -0
- package/src/tools/dispatch-scout-admission.ts +295 -0
- package/src/tools/dispatch-types.ts +77 -0
- package/src/tools/dispatch.ts +67 -3161
- package/src/tools/find.ts +4 -2
- package/src/tools/grep.ts +2 -2
- package/src/tools/lazy-tool.ts +60 -0
- package/src/tools/ledger.ts +3 -3
- package/src/tools/monitor-surface.ts +36 -0
- package/src/tools/monitor.ts +2 -32
- package/src/tools/observers.ts +2 -2
- package/src/tools/registry.ts +39 -27
- package/src/tools/safe-exec.ts +2 -2
- package/src/tools/steer-surface.ts +17 -0
- package/src/tools/steer.ts +2 -13
- package/src/tools/tasks.ts +108 -11
- package/src/tools/truncate.ts +25 -184
- package/src/tools/verify/frontend.ts +3 -1
- package/src/tools/verify/index.ts +3 -38
- package/src/tools/verify/surface.ts +46 -0
- package/src/tools/web-fetch-surface.ts +23 -0
- package/src/tools/web-fetch.ts +2 -20
- package/src/tools/write.ts +7 -2
- package/src/worker/entry.ts +39 -2
- package/src/worker/spec-contract.ts +26 -5
- package/dist/chunk-7SS2CTV2.js +0 -61361
- package/dist/chunk-DKGKUHFA.js +0 -924
- package/dist/chunk-GEP36Y4X.js +0 -12796
- package/dist/chunk-XYWBQRDM.js +0 -137
- package/dist/clio-BZVGEUFJ.js +0 -58
- package/dist/configure-S7S6F6CL.js +0 -32
- package/docs/html/agents_blueprint.html +0 -936
- package/docs/html/alcf_blueprint.html +0 -324
- package/docs/html/architecture_blueprint.html +0 -850
- package/docs/html/commands_blueprint.html +0 -939
- package/docs/html/config_knobs_audit_blueprint.html +0 -178
- package/docs/html/configuration_blueprint.html +0 -1080
- package/docs/html/context_blueprint.html +0 -603
- package/docs/html/documentation_blueprint.html +0 -832
- package/docs/html/environment_blueprint.html +0 -404
- package/docs/html/eval_blueprint.html +0 -743
- package/docs/html/evals_internal_blueprint.html +0 -190
- package/docs/html/evolution_blueprint.html +0 -674
- package/docs/html/extensions_blueprint.html +0 -2065
- package/docs/html/fleet_dispatch_blueprint.html +0 -286
- package/docs/html/index.html +0 -919
- package/docs/html/lifecycle_blueprint.html +0 -723
- package/docs/html/memory_blueprint.html +0 -699
- package/docs/html/middleware_blueprint.html +0 -664
- package/docs/html/models_blueprint.html +0 -2366
- package/docs/html/observability_blueprint.html +0 -683
- package/docs/html/provider_adapter_blueprint.html +0 -245
- package/docs/html/safety_blueprint.html +0 -1386
- package/docs/html/shared.css +0 -571
- package/docs/html/shared.js +0 -143
- package/docs/html/skills_blueprint.html +0 -671
- package/docs/html/soak_blueprint.html +0 -182
- package/docs/html/tool_usage_blueprint.html +0 -350
- package/docs/html/tools_blueprint.html +0 -2249
- package/docs/html/trace_blueprint.html +0 -235
- package/docs/html/tui_design_blueprint.html +0 -374
- package/docs/html/validation_blueprint.html +0 -961
- package/docs/html/worker_dispatch_blueprint.html +0 -231
- package/src/core/release.ts +0 -2
- package/src/domains/providers/runtimes/common/lmstudio-logger.ts +0 -32
- package/src/domains/providers/runtimes/local-native/lmstudio-native.ts +0 -491
- package/src/engine/apis/lmstudio-native.ts +0 -1438
- package/src/engine/apis/thinking-replay.ts +0 -11
- package/src/tools/string-enum.ts +0 -15
|
@@ -4,6 +4,10 @@ import { loadMemoryRecordsSync, type MemoryRecord } from "../domains/memory/inde
|
|
|
4
4
|
import type { ObservabilityContract } from "../domains/observability/index.js";
|
|
5
5
|
import type { ContextLedger } from "../domains/session/context-ledger.js";
|
|
6
6
|
import type { SessionMeta } from "../domains/session/index.js";
|
|
7
|
+
import { foldSessionArtifacts } from "../domains/session/session-artifacts.js";
|
|
8
|
+
import { foldSessionTaskHistory } from "../domains/session/task-board.js";
|
|
9
|
+
import { filterEntriesToActivePath } from "../domains/session/tree/active-path.js";
|
|
10
|
+
import type { UserTasksStore } from "../domains/user-tasks/store.js";
|
|
7
11
|
import type { TUI } from "../engine/tui.js";
|
|
8
12
|
import { type OpenContextOverlayOptions, openContextOverlay } from "./context-overlay.js";
|
|
9
13
|
import { openCostOverlay } from "./cost-overlay.js";
|
|
@@ -20,7 +24,8 @@ import {
|
|
|
20
24
|
contextResetOptions,
|
|
21
25
|
openContextResetOverlay,
|
|
22
26
|
} from "./overlays/context-reset.js";
|
|
23
|
-
import
|
|
27
|
+
import { formatDecisionCorrectionTurn, openDecisionsOverlay } from "./overlays/decisions.js";
|
|
28
|
+
import { type ContextClearCommandOptions, formatUserTaskHandoff } from "./slash-commands.js";
|
|
24
29
|
import { openTasksOverlay } from "./tasks-overlay.js";
|
|
25
30
|
import { type ArtifactProviderDeps, createDefaultArtifactProviders } from "./view/artifacts.js";
|
|
26
31
|
import { openViewOverlay } from "./view/view-overlay.js";
|
|
@@ -40,6 +45,10 @@ export interface OverlayGeneralOpenersDeps {
|
|
|
40
45
|
renderTaskIsland: () => void;
|
|
41
46
|
requestRender: () => void;
|
|
42
47
|
getTaskBoard?: Parameters<typeof openTasksOverlay>[1];
|
|
48
|
+
userTasks?: UserTasksStore;
|
|
49
|
+
getDecisionBoard?: Parameters<typeof openDecisionsOverlay>[1];
|
|
50
|
+
supersedeDecision?: (interviewId: string, key: string, correction?: string) => unknown;
|
|
51
|
+
submitChat: (text: string) => void;
|
|
43
52
|
getTaskMemoryStatus?: Parameters<typeof openMemoryOverlay>[1];
|
|
44
53
|
dataDir: string;
|
|
45
54
|
notify: (level: "info" | "success" | "warning" | "error", text: string, key?: string) => void;
|
|
@@ -56,6 +65,7 @@ export interface OverlayGeneralOpenersDeps {
|
|
|
56
65
|
openContextOverlay?: typeof openContextOverlay;
|
|
57
66
|
openContextResetOverlay?: typeof openContextResetOverlay;
|
|
58
67
|
openTasksOverlay?: typeof openTasksOverlay;
|
|
68
|
+
openDecisionsOverlay?: typeof openDecisionsOverlay;
|
|
59
69
|
openMemoryOverlay?: typeof openMemoryOverlay;
|
|
60
70
|
openViewOverlay?: typeof openViewOverlay;
|
|
61
71
|
}
|
|
@@ -66,6 +76,7 @@ export interface OverlayGeneralOpeners {
|
|
|
66
76
|
openContextReset(): void;
|
|
67
77
|
toggleFooter(): void;
|
|
68
78
|
openTasks(): void;
|
|
79
|
+
openDecisions(): void;
|
|
69
80
|
openMemory(): void;
|
|
70
81
|
openView(initialFilter?: string): void;
|
|
71
82
|
toggleDispatchBoard(): void;
|
|
@@ -76,6 +87,7 @@ export function createOverlayGeneralOpeners(deps: OverlayGeneralOpenersDeps): Ov
|
|
|
76
87
|
const openContextOverlayFactory = deps.openContextOverlay ?? openContextOverlay;
|
|
77
88
|
const openContextResetOverlayFactory = deps.openContextResetOverlay ?? openContextResetOverlay;
|
|
78
89
|
const openTasksOverlayFactory = deps.openTasksOverlay ?? openTasksOverlay;
|
|
90
|
+
const openDecisionsOverlayFactory = deps.openDecisionsOverlay ?? openDecisionsOverlay;
|
|
79
91
|
const openMemoryOverlayFactory = deps.openMemoryOverlay ?? openMemoryOverlay;
|
|
80
92
|
const openViewOverlayFactory = deps.openViewOverlay ?? openViewOverlay;
|
|
81
93
|
const showOverlayFrameFactory = deps.showOverlayFrame ?? showClioOverlayFrame;
|
|
@@ -137,6 +149,50 @@ export function createOverlayGeneralOpeners(deps: OverlayGeneralOpenersDeps): Ov
|
|
|
137
149
|
deps.transitions.state = "tasks";
|
|
138
150
|
deps.transitions.handle = openTasksOverlayFactory(deps.tui, () => deps.getTaskBoard?.() ?? null, {
|
|
139
151
|
onClose: deps.closeOverlay,
|
|
152
|
+
getSessionSnapshot: () => {
|
|
153
|
+
const meta = deps.getSessionMeta();
|
|
154
|
+
const entries = filterEntriesToActivePath(deps.readSessionEntries?.() ?? [], meta?.pinnedLeafTurnId ?? undefined);
|
|
155
|
+
const workspace = meta?.cwd ?? process.cwd();
|
|
156
|
+
return {
|
|
157
|
+
history: foldSessionTaskHistory(entries),
|
|
158
|
+
artifacts: foldSessionArtifacts(entries, { workspace }),
|
|
159
|
+
};
|
|
160
|
+
},
|
|
161
|
+
...(deps.userTasks
|
|
162
|
+
? {
|
|
163
|
+
getUserTasks: () => deps.userTasks?.snapshot() ?? [],
|
|
164
|
+
onAddUserTask: (title: string) => void deps.userTasks?.add(title),
|
|
165
|
+
onHandUserTask: (id: string) => {
|
|
166
|
+
const task = deps.userTasks?.hand(id, deps.getSessionId?.() ?? undefined);
|
|
167
|
+
if (!task) throw new Error("operator task inbox is unavailable");
|
|
168
|
+
deps.submitChat(formatUserTaskHandoff(task));
|
|
169
|
+
},
|
|
170
|
+
onDoneUserTask: (id: string) => void deps.userTasks?.done(id),
|
|
171
|
+
onDropUserTask: (id: string) => void deps.userTasks?.drop(id),
|
|
172
|
+
}
|
|
173
|
+
: {}),
|
|
174
|
+
onOpenArtifact: (path: string) => openView(`workspace:${path}`),
|
|
175
|
+
requestRender: deps.requestRender,
|
|
176
|
+
workspace: deps.getSessionMeta()?.cwd ?? process.cwd(),
|
|
177
|
+
});
|
|
178
|
+
deps.requestRender();
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const openDecisions = (): void => {
|
|
182
|
+
if (deps.transitions.state !== "closed") return;
|
|
183
|
+
deps.transitions.state = "decisions";
|
|
184
|
+
deps.transitions.handle = openDecisionsOverlayFactory(deps.tui, () => deps.getDecisionBoard?.() ?? [], {
|
|
185
|
+
onSupersede: (selection) => {
|
|
186
|
+
if (!deps.supersedeDecision) throw new Error("decision board is unavailable in this session");
|
|
187
|
+
deps.supersedeDecision(selection.interviewId, selection.key);
|
|
188
|
+
},
|
|
189
|
+
onCorrection: (selection, correction) => {
|
|
190
|
+
if (!deps.supersedeDecision) throw new Error("decision board is unavailable in this session");
|
|
191
|
+
deps.supersedeDecision(selection.interviewId, selection.key, correction);
|
|
192
|
+
deps.closeOverlay();
|
|
193
|
+
deps.submitChat(formatDecisionCorrectionTurn(selection, correction));
|
|
194
|
+
},
|
|
195
|
+
onClose: deps.closeOverlay,
|
|
140
196
|
});
|
|
141
197
|
deps.requestRender();
|
|
142
198
|
};
|
|
@@ -210,6 +266,7 @@ export function createOverlayGeneralOpeners(deps: OverlayGeneralOpenersDeps): Ov
|
|
|
210
266
|
openContextReset,
|
|
211
267
|
toggleFooter,
|
|
212
268
|
openTasks,
|
|
269
|
+
openDecisions,
|
|
213
270
|
openMemory,
|
|
214
271
|
openView,
|
|
215
272
|
toggleDispatchBoard,
|
|
@@ -10,6 +10,7 @@ export type OverlayState =
|
|
|
10
10
|
| "context-view"
|
|
11
11
|
| "context-reset"
|
|
12
12
|
| "tasks"
|
|
13
|
+
| "decisions"
|
|
13
14
|
| "memory"
|
|
14
15
|
| "view"
|
|
15
16
|
| "model"
|
|
@@ -158,6 +159,7 @@ export function routeOverlayKey(
|
|
|
158
159
|
if (overlayState === "closed") return false;
|
|
159
160
|
if (
|
|
160
161
|
(overlayState === "dispatch-board" && matches(data, "clio.dispatchBoard.toggle")) ||
|
|
162
|
+
(overlayState === "tasks" && matches(data, "clio.tasks.open")) ||
|
|
161
163
|
(overlayState === "tree" && matches(data, "clio.session.tree")) ||
|
|
162
164
|
(overlayState === "model" && matches(data, "clio.model.select")) ||
|
|
163
165
|
(overlayState === "help" && matches(data, "clio.leader"))
|
|
@@ -180,6 +182,7 @@ export function routeOverlayKey(
|
|
|
180
182
|
}
|
|
181
183
|
if (overlayState === "context-reset") return false;
|
|
182
184
|
if (overlayState === "tasks") return false;
|
|
185
|
+
if (overlayState === "decisions") return false;
|
|
183
186
|
if (overlayState === "memory") return false;
|
|
184
187
|
if (overlayState === "view") return false;
|
|
185
188
|
if (overlayState === "model") return routeModelOverlayKey(data, deps);
|
|
@@ -33,6 +33,8 @@ export type OverlayLifecycleApplicationDeps = Pick<
|
|
|
33
33
|
| "getSessionId"
|
|
34
34
|
| "getSettings"
|
|
35
35
|
| "getTaskBoard"
|
|
36
|
+
| "userTasks"
|
|
37
|
+
| "getDecisionBoard"
|
|
36
38
|
| "getTaskMemoryStatus"
|
|
37
39
|
| "interop"
|
|
38
40
|
| "observability"
|
|
@@ -46,6 +48,7 @@ export type OverlayLifecycleApplicationDeps = Pick<
|
|
|
46
48
|
| "resources"
|
|
47
49
|
| "session"
|
|
48
50
|
| "stateDir"
|
|
51
|
+
| "supersedeDecision"
|
|
49
52
|
| "toolRegistry"
|
|
50
53
|
| "writeSettings"
|
|
51
54
|
>;
|
|
@@ -94,6 +97,7 @@ export interface OverlayLifecycleRuntimeDeps {
|
|
|
94
97
|
openContextOverlay?: typeof import("./context-overlay.js").openContextOverlay;
|
|
95
98
|
openContextResetOverlay?: typeof import("./overlays/context-reset.js").openContextResetOverlay;
|
|
96
99
|
openTasksOverlay?: typeof import("./tasks-overlay.js").openTasksOverlay;
|
|
100
|
+
openDecisionsOverlay?: typeof import("./overlays/decisions.js").openDecisionsOverlay;
|
|
97
101
|
openMemoryOverlay?: typeof import("./memory-overlay.js").openMemoryOverlay;
|
|
98
102
|
openViewOverlay?: typeof import("./view/view-overlay.js").openViewOverlay;
|
|
99
103
|
openHelpOverlay?: typeof import("./overlays/help-reference.js").openHelpOverlay;
|
|
@@ -118,6 +122,7 @@ export interface OverlayLifecycleController {
|
|
|
118
122
|
openContextResetOverlayState(): void;
|
|
119
123
|
toggleFooterDashboardState(): void;
|
|
120
124
|
openTasksOverlayState(): void;
|
|
125
|
+
openDecisionsOverlayState(): void;
|
|
121
126
|
openMemoryOverlayState(): void;
|
|
122
127
|
openViewOverlayState(initialFilter?: string): void;
|
|
123
128
|
openModelOverlayState(): void;
|
|
@@ -169,6 +174,7 @@ export function createOverlayLifecycle(deps: OverlayLifecycleRuntimeDeps): Overl
|
|
|
169
174
|
openContextOverlay: openContextOverlayFactory,
|
|
170
175
|
openContextResetOverlay: openContextResetOverlayFactory,
|
|
171
176
|
openTasksOverlay: openTasksOverlayFactory,
|
|
177
|
+
openDecisionsOverlay: openDecisionsOverlayFactory,
|
|
172
178
|
openMemoryOverlay: openMemoryOverlayFactory,
|
|
173
179
|
openViewOverlay: openViewOverlayFactory,
|
|
174
180
|
openHelpOverlay: openHelpOverlayFactory,
|
|
@@ -334,6 +340,10 @@ export function createOverlayLifecycle(deps: OverlayLifecycleRuntimeDeps): Overl
|
|
|
334
340
|
renderTaskIsland: () => interactiveTickers.renderTaskIsland(),
|
|
335
341
|
requestRender: () => tui.requestRender(),
|
|
336
342
|
...(deps.app.getTaskBoard ? { getTaskBoard: deps.app.getTaskBoard } : {}),
|
|
343
|
+
...(deps.app.userTasks ? { userTasks: deps.app.userTasks } : {}),
|
|
344
|
+
...(deps.app.getDecisionBoard ? { getDecisionBoard: deps.app.getDecisionBoard } : {}),
|
|
345
|
+
...(deps.app.supersedeDecision ? { supersedeDecision: deps.app.supersedeDecision } : {}),
|
|
346
|
+
submitChat: (text) => deps.getSlashContext().submitChat(text),
|
|
337
347
|
...(deps.app.getTaskMemoryStatus ? { getTaskMemoryStatus: deps.app.getTaskMemoryStatus } : {}),
|
|
338
348
|
dataDir: deps.app.dataDir,
|
|
339
349
|
notify,
|
|
@@ -350,6 +360,7 @@ export function createOverlayLifecycle(deps: OverlayLifecycleRuntimeDeps): Overl
|
|
|
350
360
|
...(openContextOverlayFactory ? { openContextOverlay: openContextOverlayFactory } : {}),
|
|
351
361
|
...(openContextResetOverlayFactory ? { openContextResetOverlay: openContextResetOverlayFactory } : {}),
|
|
352
362
|
...(openTasksOverlayFactory ? { openTasksOverlay: openTasksOverlayFactory } : {}),
|
|
363
|
+
...(openDecisionsOverlayFactory ? { openDecisionsOverlay: openDecisionsOverlayFactory } : {}),
|
|
353
364
|
...(openMemoryOverlayFactory ? { openMemoryOverlay: openMemoryOverlayFactory } : {}),
|
|
354
365
|
...(openViewOverlayFactory ? { openViewOverlay: openViewOverlayFactory } : {}),
|
|
355
366
|
});
|
|
@@ -362,6 +373,7 @@ export function createOverlayLifecycle(deps: OverlayLifecycleRuntimeDeps): Overl
|
|
|
362
373
|
const openContextResetOverlayState = overlayGeneralOpeners.openContextReset;
|
|
363
374
|
const toggleFooterDashboardState = overlayGeneralOpeners.toggleFooter;
|
|
364
375
|
const openTasksOverlayState = overlayGeneralOpeners.openTasks;
|
|
376
|
+
const openDecisionsOverlayState = overlayGeneralOpeners.openDecisions;
|
|
365
377
|
const openMemoryOverlayState = overlayGeneralOpeners.openMemory;
|
|
366
378
|
const openViewOverlayState = overlayGeneralOpeners.openView;
|
|
367
379
|
const toggleDispatchBoardOverlay = overlayGeneralOpeners.toggleDispatchBoard;
|
|
@@ -380,6 +392,7 @@ export function createOverlayLifecycle(deps: OverlayLifecycleRuntimeDeps): Overl
|
|
|
380
392
|
openContextResetOverlayState,
|
|
381
393
|
toggleFooterDashboardState,
|
|
382
394
|
openTasksOverlayState,
|
|
395
|
+
openDecisionsOverlayState,
|
|
383
396
|
openMemoryOverlayState,
|
|
384
397
|
openViewOverlayState,
|
|
385
398
|
openModelOverlayState: overlayModelSelectors.openModelOverlayState,
|
|
@@ -192,6 +192,7 @@ export function createOverlayPermissionLifecycle(deps: OverlayPermissionLifecycl
|
|
|
192
192
|
const unsubscribePermission =
|
|
193
193
|
deps.toolRegistry?.onPermissionRequired((call, decision, meta) => {
|
|
194
194
|
const autonomy = deps.getAutonomy();
|
|
195
|
+
const view = mainApprovalRequestView(call, decision, meta, autonomy, deps.toolRegistry?.parkedCount());
|
|
195
196
|
// The dialog states the tool, the target, the action class, the axis
|
|
196
197
|
// that asked, and the keys that answer it. While it is on screen the
|
|
197
198
|
// notice repeats all of that one line above the transcript, so it is
|
|
@@ -207,13 +208,13 @@ export function createOverlayPermissionLifecycle(deps: OverlayPermissionLifecycl
|
|
|
207
208
|
type: "tool_approval_state",
|
|
208
209
|
toolCallId: meta.toolCallId,
|
|
209
210
|
state: "awaiting-approval",
|
|
211
|
+
view,
|
|
210
212
|
});
|
|
211
213
|
}
|
|
212
214
|
if (deps.getOverlayState() !== "closed") {
|
|
213
215
|
announceParked();
|
|
214
216
|
return;
|
|
215
217
|
}
|
|
216
|
-
const view = mainApprovalRequestView(call, decision, meta, autonomy, deps.toolRegistry?.parkedCount());
|
|
217
218
|
if (!deps.openPermissionOverlay(view)) {
|
|
218
219
|
announceParked();
|
|
219
220
|
return;
|
|
@@ -12,6 +12,7 @@ import { openMessagePickerOverlay } from "./overlays/message-picker.js";
|
|
|
12
12
|
import { openSessionOverlay } from "./overlays/session-selector.js";
|
|
13
13
|
import { openTreeOverlay } from "./overlays/tree-selector.js";
|
|
14
14
|
import { lastTurnSummaryFromLedger } from "./session-last-turn.js";
|
|
15
|
+
import { settleChatBeforeSessionSwitch } from "./session-switch-settlement.js";
|
|
15
16
|
import { reseedSessionUsageFromLedger, type SessionUsageSink } from "./session-usage-reseed.js";
|
|
16
17
|
import type { SlashCommandContext } from "./slash-commands.js";
|
|
17
18
|
import type { TurnSummary } from "./status/index.js";
|
|
@@ -20,7 +21,7 @@ export interface OverlaySessionLifecycleDeps {
|
|
|
20
21
|
tui: TUI;
|
|
21
22
|
transitions: OverlayTransitions;
|
|
22
23
|
session?: SessionContract;
|
|
23
|
-
chat: Pick<ChatLoop, "resetForSession">;
|
|
24
|
+
chat: Pick<ChatLoop, "cancel" | "isStreaming" | "resetForSession" | "whenSettled">;
|
|
24
25
|
chatPanel: ChatPanel;
|
|
25
26
|
/** The one transcript reset: the panel plus every view folded alongside it. */
|
|
26
27
|
resetTranscript(): void;
|
|
@@ -113,20 +114,58 @@ export function createOverlaySessionLifecycle(deps: OverlaySessionLifecycleDeps)
|
|
|
113
114
|
deps.transitions.state = "resume";
|
|
114
115
|
deps.transitions.handle = openResumeOverlay(deps.tui, {
|
|
115
116
|
session,
|
|
116
|
-
onResume: (sessionId) => {
|
|
117
|
+
onResume: async (sessionId) => {
|
|
118
|
+
const settlement = settleChatBeforeSessionSwitch(deps.chat);
|
|
119
|
+
if (settlement) await settlement;
|
|
117
120
|
deps.onResumeSession?.(sessionId);
|
|
121
|
+
// onResumeSession (wired to session.resume) catches and stderr-logs
|
|
122
|
+
// its own failure rather than throwing here, so this is the only
|
|
123
|
+
// signal available: a successful switch always leaves session.current()
|
|
124
|
+
// pointing at the requested id. Without this check, a failed switch
|
|
125
|
+
// still replayed the target's transcript and moved the chat leaf to
|
|
126
|
+
// it while session.current() stayed on the session the operator
|
|
127
|
+
// started on (issue #93), so the next message was appended with a
|
|
128
|
+
// parent turn from a session that was never actually opened.
|
|
129
|
+
if (session.current()?.id !== sessionId) {
|
|
130
|
+
emitCommandNotice(
|
|
131
|
+
deps.getSlashNotice(),
|
|
132
|
+
"error",
|
|
133
|
+
"resume",
|
|
134
|
+
`could not switch to that session; staying on ${preResumeSessionId ?? "no session"}`,
|
|
135
|
+
);
|
|
136
|
+
deps.refreshFooter();
|
|
137
|
+
deps.requestRender();
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
118
140
|
try {
|
|
119
141
|
const turns = deps.readStructuredEntries(sessionId);
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
142
|
+
// The leaf is read before the transcript is rebuilt because it is
|
|
143
|
+
// what the rebuild has to follow. resolveLeafOnOpen prefers a
|
|
144
|
+
// persisted `/tree` pin over the newest turn, so a session resumed
|
|
145
|
+
// on a pin extends from the pinned turn while the file still holds
|
|
146
|
+
// the abandoned branch after it. Replaying the file unfiltered
|
|
147
|
+
// rendered those abandoned turns as ordinary history above the
|
|
148
|
+
// prompt, disagreeing with the branch the next message parents onto
|
|
149
|
+
// and with the tip `/tree` marks (issue #107). The `/tree` switch
|
|
150
|
+
// path below has always scoped its replay to the selected turn;
|
|
151
|
+
// this is the same active-path filter, rooted at the leaf resume
|
|
152
|
+
// actually landed on.
|
|
123
153
|
const leafTurnId = session.tree(sessionId).leafId;
|
|
154
|
+
// activeLeafTurnId, not uptoTurnId: this is a live branch about to
|
|
155
|
+
// be extended, so sidecars anchored to a path turn but written
|
|
156
|
+
// after it (a compaction summary covering the leaf, above all)
|
|
157
|
+
// still belong on screen. uptoTurnId is the historical-truncation
|
|
158
|
+
// variant `/tree` uses.
|
|
159
|
+
const replayOptions = leafTurnId ? { activeLeafTurnId: leafTurnId } : {};
|
|
160
|
+
deps.resetTranscript();
|
|
161
|
+
rehydrateChatPanelFromTurns(deps.chatPanel, turns, replayOptions);
|
|
162
|
+
const replayMessages = buildReplayAgentMessagesFromTurns(turns, replayOptions);
|
|
124
163
|
deps.chat.resetForSession(leafTurnId, replayMessages);
|
|
125
164
|
rescopeToBranch(session, turns, leafTurnId);
|
|
126
165
|
} catch (error) {
|
|
127
166
|
deps.stderr(`[/resume] transcript replay failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
128
167
|
}
|
|
129
|
-
if (
|
|
168
|
+
if (sessionId !== preResumeSessionId) {
|
|
130
169
|
deps.announceTaskMemorySeedOffer();
|
|
131
170
|
}
|
|
132
171
|
deps.refreshFooter();
|
|
@@ -160,7 +199,9 @@ export function createOverlaySessionLifecycle(deps: OverlaySessionLifecycleDeps)
|
|
|
160
199
|
deps.transitions.state = "tree";
|
|
161
200
|
deps.transitions.handle = openTreeSelector(deps.tui, {
|
|
162
201
|
session,
|
|
163
|
-
onSwitchTurn: (turnId) => {
|
|
202
|
+
onSwitchTurn: async (turnId) => {
|
|
203
|
+
const settlement = settleChatBeforeSessionSwitch(deps.chat);
|
|
204
|
+
if (settlement) await settlement;
|
|
164
205
|
try {
|
|
165
206
|
session.switchTurn(turnId);
|
|
166
207
|
const sessionId = session.current()?.id ?? null;
|
|
@@ -195,7 +236,8 @@ export function createOverlaySessionLifecycle(deps: OverlaySessionLifecycleDeps)
|
|
|
195
236
|
return;
|
|
196
237
|
}
|
|
197
238
|
const session = deps.session;
|
|
198
|
-
|
|
239
|
+
const preForkSessionId = session.current()?.id ?? null;
|
|
240
|
+
if (preForkSessionId === null) {
|
|
199
241
|
emitCommandNotice(
|
|
200
242
|
deps.getSlashNotice(),
|
|
201
243
|
"warn",
|
|
@@ -207,14 +249,29 @@ export function createOverlaySessionLifecycle(deps: OverlaySessionLifecycleDeps)
|
|
|
207
249
|
deps.transitions.state = "message-picker";
|
|
208
250
|
deps.transitions.handle = openMessagePicker(deps.tui, {
|
|
209
251
|
session,
|
|
210
|
-
onFork: (parentTurnId) => {
|
|
252
|
+
onFork: async (parentTurnId) => {
|
|
253
|
+
const settlement = settleChatBeforeSessionSwitch(deps.chat);
|
|
254
|
+
if (settlement) await settlement;
|
|
211
255
|
try {
|
|
212
256
|
if (deps.onForkSession) deps.onForkSession(parentTurnId);
|
|
213
257
|
else session.fork(parentTurnId);
|
|
214
|
-
deps.resetTranscript();
|
|
215
258
|
const forkedSessionId = session.current()?.id ?? null;
|
|
216
|
-
|
|
217
|
-
|
|
259
|
+
// A successful fork always creates a fresh session id; landing back
|
|
260
|
+
// on the id fork started from means the fork threw and
|
|
261
|
+
// onForkSession swallowed it (orchestrator.ts stderr-logs there).
|
|
262
|
+
// Do not replay: session.current() did not move (issue #93's
|
|
263
|
+
// extension.ts/fork.ts ordering fix keeps it on the session the
|
|
264
|
+
// operator started on instead of orphaning it), so there is
|
|
265
|
+
// nothing new to replay and doing so anyway just re-renders the
|
|
266
|
+
// same transcript while hiding that the fork failed.
|
|
267
|
+
if (forkedSessionId === null || forkedSessionId === preForkSessionId) {
|
|
268
|
+
emitCommandNotice(deps.getSlashNotice(), "error", "fork", `fork failed; staying on ${preForkSessionId}`);
|
|
269
|
+
deps.refreshFooter();
|
|
270
|
+
deps.requestRender();
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
deps.resetTranscript();
|
|
274
|
+
replayFork(forkedSessionId, parentTurnId, session);
|
|
218
275
|
} catch (error) {
|
|
219
276
|
deps.stderr(`[/fork] fork failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
220
277
|
}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import type { DecisionLedgerEntry, DecisionRecord } from "../../domains/session/entries.js";
|
|
2
|
+
import {
|
|
3
|
+
type Component,
|
|
4
|
+
Input,
|
|
5
|
+
matchesKey,
|
|
6
|
+
type OverlayHandle,
|
|
7
|
+
type TUI,
|
|
8
|
+
truncateToWidth,
|
|
9
|
+
visibleWidth,
|
|
10
|
+
wrapTextWithAnsi,
|
|
11
|
+
} from "../../engine/tui.js";
|
|
12
|
+
import { buildHint, showClioOverlayFrame } from "../overlay-frame.js";
|
|
13
|
+
import { clioTheme, GLYPH, rule } from "../theme/index.js";
|
|
14
|
+
|
|
15
|
+
const DEFAULT_CONTENT_WIDTH = 88;
|
|
16
|
+
|
|
17
|
+
export const DECISIONS_OVERLAY_WIDTH = DEFAULT_CONTENT_WIDTH + 4;
|
|
18
|
+
|
|
19
|
+
export interface DecisionSelection {
|
|
20
|
+
interviewId: string;
|
|
21
|
+
key: string;
|
|
22
|
+
label: string;
|
|
23
|
+
value: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** The operator-authored turn that makes a durable correction visible to the model. */
|
|
27
|
+
export function formatDecisionCorrectionTurn(selection: DecisionSelection, correction: string): string {
|
|
28
|
+
return `Decision "${selection.label}" (previously: ${selection.value}) is superseded by the operator. New direction: ${correction}. Acknowledge and adjust the plan.`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface OpenDecisionsOverlayOptions {
|
|
32
|
+
onSupersede: (selection: DecisionSelection) => void;
|
|
33
|
+
onCorrection: (selection: DecisionSelection, correction: string) => void;
|
|
34
|
+
onClose: () => void;
|
|
35
|
+
requestRender?: () => void;
|
|
36
|
+
now?: () => number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface SelectableDecision {
|
|
40
|
+
interview: DecisionLedgerEntry;
|
|
41
|
+
decision: DecisionRecord;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function fitLine(text: string, width: number): string {
|
|
45
|
+
const safeWidth = Math.max(1, Math.floor(width));
|
|
46
|
+
return visibleWidth(text) <= safeWidth ? text : truncateToWidth(text, safeWidth, "…", true);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function relativeTime(timestamp: string, now: number): string {
|
|
50
|
+
const value = Date.parse(timestamp);
|
|
51
|
+
if (!Number.isFinite(value)) return "unknown time";
|
|
52
|
+
const seconds = Math.max(0, Math.floor((now - value) / 1000));
|
|
53
|
+
if (seconds < 60) return `${seconds}s ago`;
|
|
54
|
+
const minutes = Math.floor(seconds / 60);
|
|
55
|
+
if (minutes < 60) return `${minutes}m ago`;
|
|
56
|
+
const hours = Math.floor(minutes / 60);
|
|
57
|
+
if (hours < 24) return `${hours}h ago`;
|
|
58
|
+
return `${Math.floor(hours / 24)}d ago`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function selectionFor(row: SelectableDecision): DecisionSelection {
|
|
62
|
+
return {
|
|
63
|
+
interviewId: row.interview.interviewId,
|
|
64
|
+
key: row.decision.key,
|
|
65
|
+
label: row.decision.label ?? row.decision.key,
|
|
66
|
+
value: row.decision.value,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function selectableRows(interviews: ReadonlyArray<DecisionLedgerEntry>): SelectableDecision[] {
|
|
71
|
+
return interviews.flatMap((interview) => interview.decisions.map((decision) => ({ interview, decision })));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function interviewHeader(interview: DecisionLedgerEntry, width: number, now: number): string[] {
|
|
75
|
+
const theme = clioTheme();
|
|
76
|
+
const rounds = `${interview.roundCount} round${interview.roundCount === 1 ? "" : "s"}`;
|
|
77
|
+
const status =
|
|
78
|
+
interview.interviewStatus === "complete" ? theme.fg("success", "complete") : theme.fg("warning", "cancelled");
|
|
79
|
+
const heading = `${theme.fg("accent", relativeTime(interview.endedAt, now))}${theme.fg("dim", " · ")}${theme.fg("muted", rounds)}${theme.fg("dim", " · ")}${status}`;
|
|
80
|
+
const lines = [fitLine(heading, width)];
|
|
81
|
+
if (interview.summary) {
|
|
82
|
+
lines.push(...wrapTextWithAnsi(theme.fg("dim", interview.summary), width).map((line) => fitLine(line, width)));
|
|
83
|
+
}
|
|
84
|
+
return lines;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function decisionLines(decision: DecisionRecord, selected: boolean, expanded: boolean, width: number): string[] {
|
|
88
|
+
const theme = clioTheme();
|
|
89
|
+
const cursor = selected ? theme.fg("accent", GLYPH.cursor) : " ";
|
|
90
|
+
const status = decision.status === "active" ? theme.fg("success", GLYPH.ok) : theme.fg("dim", GLYPH.cancelled);
|
|
91
|
+
const labelText = decision.label ?? decision.key;
|
|
92
|
+
const label = decision.status === "superseded" ? theme.fg("dim", labelText) : theme.fg("muted", labelText);
|
|
93
|
+
const value = decision.status === "superseded" ? theme.fg("dim", decision.value) : decision.value;
|
|
94
|
+
const lines = [fitLine(`${cursor} ${status} ${label}${theme.fg("dim", ":")} ${value}`, width)];
|
|
95
|
+
if (decision.status === "superseded" && decision.correction) {
|
|
96
|
+
lines.push(fitLine(` ${theme.fg("dim", "correction")} ${theme.fg("muted", decision.correction)}`, width));
|
|
97
|
+
}
|
|
98
|
+
if (selected && expanded) {
|
|
99
|
+
if (decision.source_question) {
|
|
100
|
+
lines.push(
|
|
101
|
+
...wrapTextWithAnsi(`${theme.fg("dim", "question")} ${theme.fg("muted", decision.source_question)}`, width).map(
|
|
102
|
+
(line) => fitLine(` ${line}`, width),
|
|
103
|
+
),
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
lines.push(
|
|
107
|
+
...wrapTextWithAnsi(`${theme.fg("dim", "answer")} ${theme.fg("muted", decision.value)}`, width).map((line) =>
|
|
108
|
+
fitLine(` ${line}`, width),
|
|
109
|
+
),
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
return lines;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function formatDecisionsOverlayBodyLines(
|
|
116
|
+
interviews: ReadonlyArray<DecisionLedgerEntry>,
|
|
117
|
+
selectedIndex = 0,
|
|
118
|
+
expandedKey: string | null = null,
|
|
119
|
+
contentWidth = DEFAULT_CONTENT_WIDTH,
|
|
120
|
+
now = Date.now(),
|
|
121
|
+
): string[] {
|
|
122
|
+
const width = Math.max(1, Math.floor(contentWidth));
|
|
123
|
+
const theme = clioTheme();
|
|
124
|
+
if (interviews.length === 0) {
|
|
125
|
+
return [
|
|
126
|
+
...wrapTextWithAnsi(theme.fg("muted", "No interview decisions have been recorded on this branch."), width),
|
|
127
|
+
"",
|
|
128
|
+
...wrapTextWithAnsi(theme.fg("dim", "Completed and cancelled ask_user interviews appear here."), width),
|
|
129
|
+
].map((line) => fitLine(line, width));
|
|
130
|
+
}
|
|
131
|
+
const selected = selectableRows(interviews)[selectedIndex];
|
|
132
|
+
const lines: string[] = [];
|
|
133
|
+
for (let interviewIndex = 0; interviewIndex < interviews.length; interviewIndex += 1) {
|
|
134
|
+
const interview = interviews[interviewIndex];
|
|
135
|
+
if (!interview) continue;
|
|
136
|
+
if (interviewIndex > 0) lines.push(rule(theme, width));
|
|
137
|
+
lines.push(...interviewHeader(interview, width, now));
|
|
138
|
+
if (interview.decisions.length === 0) {
|
|
139
|
+
lines.push(fitLine(` ${theme.fg("dim", "No compact decisions were recorded.")}`, width));
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
for (const decision of interview.decisions) {
|
|
143
|
+
const isSelected =
|
|
144
|
+
selected?.interview.interviewId === interview.interviewId && selected.decision.key === decision.key;
|
|
145
|
+
const rowKey = `${interview.interviewId}:${decision.key}`;
|
|
146
|
+
lines.push(...decisionLines(decision, isSelected, isSelected && expandedKey === rowKey, width));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return lines;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
class DecisionsOverlayBody implements Component {
|
|
153
|
+
private selectedIndex = 0;
|
|
154
|
+
private expandedKey: string | null = null;
|
|
155
|
+
private correctionInput: Input | null = null;
|
|
156
|
+
private status = "";
|
|
157
|
+
|
|
158
|
+
constructor(
|
|
159
|
+
private readonly getInterviews: () => ReadonlyArray<DecisionLedgerEntry>,
|
|
160
|
+
private readonly options: OpenDecisionsOverlayOptions,
|
|
161
|
+
) {}
|
|
162
|
+
|
|
163
|
+
render(width: number): string[] {
|
|
164
|
+
const interviews = this.readInterviews();
|
|
165
|
+
const rows = selectableRows(interviews);
|
|
166
|
+
this.selectedIndex = Math.max(0, Math.min(this.selectedIndex, Math.max(0, rows.length - 1)));
|
|
167
|
+
const body = formatDecisionsOverlayBodyLines(
|
|
168
|
+
interviews,
|
|
169
|
+
this.selectedIndex,
|
|
170
|
+
this.expandedKey,
|
|
171
|
+
width,
|
|
172
|
+
this.options.now?.() ?? Date.now(),
|
|
173
|
+
);
|
|
174
|
+
if (this.correctionInput) {
|
|
175
|
+
const theme = clioTheme();
|
|
176
|
+
body.push("", fitLine(theme.fg("accent", "New direction"), width));
|
|
177
|
+
body.push(
|
|
178
|
+
...this.correctionInput
|
|
179
|
+
.render(Math.max(1, width))
|
|
180
|
+
.map((line) =>
|
|
181
|
+
fitLine(line.startsWith("> ") ? `${theme.fg("accent", `${GLYPH.cursor} `)}${line.slice(2)}` : line, width),
|
|
182
|
+
),
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
if (this.status) body.push("", fitLine(clioTheme().fg("warning", this.status), width));
|
|
186
|
+
return body;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
handleInput(data: string): void {
|
|
190
|
+
if (this.correctionInput) {
|
|
191
|
+
this.correctionInput.handleInput(data);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const rows = selectableRows(this.readInterviews());
|
|
195
|
+
if (matchesKey(data, "esc")) {
|
|
196
|
+
this.options.onClose();
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (rows.length === 0) return;
|
|
200
|
+
if (matchesKey(data, "up")) {
|
|
201
|
+
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
|
202
|
+
this.expandedKey = null;
|
|
203
|
+
this.requestRender();
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (matchesKey(data, "down")) {
|
|
207
|
+
this.selectedIndex = Math.min(rows.length - 1, this.selectedIndex + 1);
|
|
208
|
+
this.expandedKey = null;
|
|
209
|
+
this.requestRender();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const selected = rows[this.selectedIndex];
|
|
213
|
+
if (!selected) return;
|
|
214
|
+
if (matchesKey(data, "enter") || data === "\n") {
|
|
215
|
+
const key = `${selected.interview.interviewId}:${selected.decision.key}`;
|
|
216
|
+
this.expandedKey = this.expandedKey === key ? null : key;
|
|
217
|
+
this.requestRender();
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (matchesKey(data, "s")) {
|
|
221
|
+
try {
|
|
222
|
+
this.options.onSupersede(selectionFor(selected));
|
|
223
|
+
this.status = "Decision superseded.";
|
|
224
|
+
} catch (error) {
|
|
225
|
+
this.status = error instanceof Error ? error.message : String(error);
|
|
226
|
+
}
|
|
227
|
+
this.requestRender();
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (matchesKey(data, "c")) this.beginCorrection(selected);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
invalidate(): void {
|
|
234
|
+
this.correctionInput?.invalidate();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
footerHint(): string {
|
|
238
|
+
return this.correctionInput
|
|
239
|
+
? buildHint([{ key: "Enter", verb: "submit" }])
|
|
240
|
+
: buildHint([
|
|
241
|
+
{ key: "↑↓", verb: "select" },
|
|
242
|
+
{ key: "Enter", verb: "expand" },
|
|
243
|
+
{ key: "s", verb: "supersede" },
|
|
244
|
+
{ key: "c", verb: "correct" },
|
|
245
|
+
]);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private readInterviews(): ReadonlyArray<DecisionLedgerEntry> {
|
|
249
|
+
try {
|
|
250
|
+
return this.getInterviews();
|
|
251
|
+
} catch (error) {
|
|
252
|
+
this.status = error instanceof Error ? error.message : String(error);
|
|
253
|
+
return [];
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
private beginCorrection(selected: SelectableDecision): void {
|
|
258
|
+
const input = new Input();
|
|
259
|
+
input.onSubmit = (value) => {
|
|
260
|
+
const correction = value.trim();
|
|
261
|
+
if (correction.length === 0) {
|
|
262
|
+
this.status = "Enter the operator's new direction.";
|
|
263
|
+
this.requestRender();
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
try {
|
|
267
|
+
this.options.onCorrection(selectionFor(selected), correction);
|
|
268
|
+
} catch (error) {
|
|
269
|
+
this.status = error instanceof Error ? error.message : String(error);
|
|
270
|
+
this.requestRender();
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
input.onEscape = () => this.options.onClose();
|
|
274
|
+
this.correctionInput = input;
|
|
275
|
+
this.status = "";
|
|
276
|
+
this.requestRender();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
private requestRender(): void {
|
|
280
|
+
this.options.requestRender?.();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** Mount the settled interview decision board. */
|
|
285
|
+
export function openDecisionsOverlay(
|
|
286
|
+
tui: TUI,
|
|
287
|
+
getInterviews: () => ReadonlyArray<DecisionLedgerEntry>,
|
|
288
|
+
options: OpenDecisionsOverlayOptions,
|
|
289
|
+
): OverlayHandle {
|
|
290
|
+
const body = new DecisionsOverlayBody(getInterviews, {
|
|
291
|
+
...options,
|
|
292
|
+
requestRender: options.requestRender ?? (() => tui.requestRender()),
|
|
293
|
+
});
|
|
294
|
+
return showClioOverlayFrame(tui, body, {
|
|
295
|
+
anchor: "center",
|
|
296
|
+
width: DECISIONS_OVERLAY_WIDTH,
|
|
297
|
+
title: () => "Decisions",
|
|
298
|
+
footerHint: () => body.footerHint(),
|
|
299
|
+
});
|
|
300
|
+
}
|