@iowarp/clio-coder 0.3.9 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/NOTICE +33 -0
- package/README.md +7 -2
- package/dist/{acp-7LOELQFP.js → acp-G5WJBNCT.js} +13 -12
- package/dist/{agents-FIBG2SHA.js → agents-FMV2Q5G4.js} +39 -36
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-OI4LIH2I.js → auth-3IDSJEIK.js} +16 -15
- package/dist/{builtins-AD25UL3C.js → builtins-XCZWXSC7.js} +3 -3
- package/dist/{chunk-IFBNV6H6.js → chunk-2ANTL7MR.js} +3 -3
- package/dist/{chunk-56KB5IJP.js → chunk-2OQE55CK.js} +3 -3
- package/dist/{chunk-N3PBVRTZ.js → chunk-32KWKNSF.js} +9 -7
- package/dist/{chunk-VKBMFOYV.js → chunk-36EJLSQQ.js} +23 -27
- package/dist/{chunk-465CC7FK.js → chunk-3BT2XMV4.js} +16 -13
- package/dist/{chunk-NQ6UCCOD.js → chunk-3URVFKWK.js} +7 -7
- package/dist/{chunk-WIE7ZOSW.js → chunk-3XML7CDN.js} +2 -2
- package/dist/chunk-42FMPA75.js +101 -0
- package/dist/{chunk-A2NJGIB3.js → chunk-5LXZXPKX.js} +2 -2
- package/dist/{chunk-HAY4ZE2P.js → chunk-5PSMVOLM.js} +2 -2
- package/dist/{chunk-JEQQR47K.js → chunk-6DB53AJS.js} +168 -9
- package/dist/{chunk-KV2AOLDF.js → chunk-76ONBSIA.js} +5 -25
- package/dist/{chunk-FALJGAWU.js → chunk-7MCTRUCE.js} +2 -2
- package/dist/{chunk-5T7RBWN2.js → chunk-AB44T6BB.js} +5 -5
- package/dist/chunk-B7OBL7PK.js +1405 -0
- package/dist/{chunk-B5CSFE7B.js → chunk-BBVJUZHB.js} +2 -2
- package/dist/{chunk-EQ63NRB7.js → chunk-BBVYXMFO.js} +2 -2
- package/dist/{chunk-O6I4CIEU.js → chunk-BKFJHQCA.js} +6 -6
- package/dist/chunk-BKFM6EJV.js +462 -0
- package/dist/chunk-BMS5RKQY.js +27 -0
- package/dist/{chunk-MV2VUEJC.js → chunk-BPKCPIL7.js} +2 -2
- package/dist/{chunk-TEO2TLVN.js → chunk-BUMFYQFY.js} +964 -1120
- package/dist/{chunk-BNAZZHFG.js → chunk-BYP5D4HI.js} +1 -1
- package/dist/chunk-C2LTL2W6.js +2447 -0
- package/dist/{chunk-EBOC7MT3.js → chunk-CODPRO7Q.js} +8 -8
- package/dist/{chunk-HPCTNZM2.js → chunk-CTJ4RNAA.js} +4 -4
- package/dist/{chunk-ODFEOB4F.js → chunk-CY6FY24N.js} +26 -8
- package/dist/{chunk-MIX5N5AC.js → chunk-DQITNCXG.js} +394 -154
- package/dist/{chunk-S4COXYBG.js → chunk-DYJP44XW.js} +129 -106
- package/dist/{chunk-N5XKWMDW.js → chunk-F4CKPOEQ.js} +6 -6
- package/dist/{chunk-AMKHQW3C.js → chunk-FEFIFZTL.js} +3 -3
- package/dist/{chunk-MV3K5QF2.js → chunk-GCSMB2KY.js} +2 -2
- package/dist/{chunk-7C6RYZGQ.js → chunk-GKF55TAZ.js} +3 -3
- package/dist/{chunk-B5XRQOLB.js → chunk-GR5G2PVF.js} +9 -8
- package/dist/{chunk-XDOQXGFO.js → chunk-GXNLGKAB.js} +64 -8
- package/dist/chunk-HHV2GANA.js +88 -0
- package/dist/{chunk-774ILSRL.js → chunk-HI63TFOG.js} +4 -3
- package/dist/{chunk-R7LNVMCS.js → chunk-HJJTYUHX.js} +64 -72
- package/dist/{chunk-RKRLDWD3.js → chunk-HLW2MRKE.js} +1 -1
- package/dist/{chunk-CA42X6KT.js → chunk-HWHKMHUA.js} +6 -6
- package/dist/chunk-HZHHCK24.js +1631 -0
- package/dist/{chunk-HJB5IUKP.js → chunk-I5VEOC6I.js} +12 -12
- package/dist/chunk-IBEBSCYA.js +564 -0
- package/dist/chunk-IQ7KR472.js +362 -0
- package/dist/{chunk-4H6ULJ3H.js → chunk-J4W7KFM7.js} +921 -990
- package/dist/{chunk-4LJX2PUC.js → chunk-JDG2WCRO.js} +5 -5
- package/dist/{chunk-NZU6YDNV.js → chunk-K5C3NCBD.js} +4 -4
- package/dist/{chunk-CGKSTWHD.js → chunk-K6BSR66V.js} +2 -1
- package/dist/{chunk-NNNWO6F2.js → chunk-KFZI4NIL.js} +93 -3
- package/dist/chunk-KMVISBZR.js +132 -0
- package/dist/{chunk-BVDVID7E.js → chunk-LDQ2ZF2M.js} +2 -2
- package/dist/{chunk-OEDBCISO.js → chunk-LQ3DZAMX.js} +2 -2
- package/dist/{chunk-PZ4I4JE2.js → chunk-LY4S7GJC.js} +124 -116
- package/dist/{chunk-3DUR4WUA.js → chunk-MLKNTWH2.js} +19 -19
- package/dist/chunk-NEKRRTYW.js +56 -0
- package/dist/{chunk-5DQRIYDZ.js → chunk-NHCZP4K7.js} +2 -2
- package/dist/chunk-NHLBIGRH.js +1506 -0
- package/dist/chunk-NQQH3YT7.js +302 -0
- package/dist/chunk-NYS75XW5.js +15 -0
- package/dist/{chunk-TD7UE2L5.js → chunk-O4XIVISU.js} +7 -7
- package/dist/{chunk-WXCJ7VME.js → chunk-O6TL7WWY.js} +6 -6
- package/dist/chunk-OQBA45DZ.js +97 -0
- package/dist/{chunk-LU7P4LHA.js → chunk-P3FOHJT4.js} +2 -2
- package/dist/chunk-PMZCIOCJ.js +25 -0
- package/dist/{chunk-I4HZDVNP.js → chunk-PQEFIJ36.js} +2 -2
- package/dist/{chunk-HKO36JWF.js → chunk-QBJA7R7N.js} +31 -3
- package/dist/chunk-QDC3K2U3.js +262 -0
- package/dist/{chunk-5HFBWUMU.js → chunk-QLFS5GO2.js} +4 -4
- package/dist/{chunk-GAYUJ7LE.js → chunk-QLL7ILRG.js} +41 -32
- package/dist/{chunk-LXPJXFM5.js → chunk-QREDIESB.js} +7 -7
- package/dist/chunk-QSNYB6ZV.js +195 -0
- package/dist/chunk-R346GLFC.js +31 -0
- package/dist/{chunk-VPTUJU4P.js → chunk-SJ5ZKQ4S.js} +2 -2
- package/dist/{chunk-QQ7EKM72.js → chunk-SP2RXXYO.js} +6 -54
- package/dist/chunk-SUCTJL45.js +45 -0
- package/dist/{chunk-5QKCQQ3E.js → chunk-SUW5DORT.js} +2 -2
- package/dist/chunk-T56WDKA5.js +183 -0
- package/dist/chunk-TVHHYFHE.js +255 -0
- package/dist/{chunk-IHKBWSXF.js → chunk-TZ3SGWZZ.js} +2 -2
- package/dist/{chunk-ECUO3KDP.js → chunk-U77AMWDL.js} +47 -7
- package/dist/{chunk-3UUY7R3Z.js → chunk-ULC6OTWO.js} +7 -7
- package/dist/{chunk-AEYBF3TB.js → chunk-UM7N4G5A.js} +2 -2
- package/dist/{chunk-3V5AYSEQ.js → chunk-UXMFQ54G.js} +43 -36
- package/dist/{chunk-YW7UVM5V.js → chunk-V5DHCITQ.js} +34 -1
- package/dist/{chunk-47CMYGET.js → chunk-VAZSBTKF.js} +2 -2
- package/dist/{chunk-3MRC2YSQ.js → chunk-VEO4AP2K.js} +2 -2
- package/dist/{chunk-PNY46YEY.js → chunk-VFA6GDY5.js} +47 -3
- package/dist/chunk-VO67MWHC.js +75 -0
- package/dist/{chunk-XK56QHLX.js → chunk-VPKWYKEY.js} +19 -5
- package/dist/{chunk-AD7Y7STJ.js → chunk-VYMXRQI6.js} +36 -22
- package/dist/{chunk-T3Z6VAAF.js → chunk-W5VSYASO.js} +19 -17
- package/dist/{chunk-5PVQ4SRS.js → chunk-WZR7K7ZX.js} +7 -123
- package/dist/{chunk-DG4M6ZUE.js → chunk-X3YGUTOB.js} +4 -4
- package/dist/chunk-X75E3D2N.js +686 -0
- package/dist/{chunk-P3JGPQFL.js → chunk-YDFRH54B.js} +4 -4
- package/dist/chunk-YJX4SHTD.js +40 -0
- package/dist/{chunk-ZI647VB5.js → chunk-YPI3QQCF.js} +2 -2
- package/dist/{chunk-YSEHGPCT.js → chunk-Z2RR6MAK.js} +3 -3
- package/dist/{chunk-HCBCAYZU.js → chunk-Z4TXYIEG.js} +5 -5
- package/dist/cli/index.js +47 -36
- package/dist/{clio-LT5V7SSZ.js → clio-2JXHBBY5.js} +7 -7
- package/dist/{code-nav-LMW275PA.js → code-nav-3YYRMYNF.js} +6 -6
- package/dist/{compile-cache-CVJMMODC.js → compile-cache-7FPE6PS3.js} +3 -3
- package/dist/{components-ZFA3SAER.js → components-RYZV4JGP.js} +5 -5
- package/dist/{config-RXS5T3JT.js → config-QZPCMYSO.js} +58 -50
- package/dist/{configure-2WYWSCSD.js → configure-TEGEBYCA.js} +21 -19
- package/dist/{context-I3BTOTCS.js → context-AV7OEZ4D.js} +11 -11
- package/dist/{context-MVOORGMF.js → context-E6H5RNMC.js} +49 -41
- package/dist/{context-PALKKQYL.js → context-GSXUE4CT.js} +25 -23
- package/dist/{context-clear-N2WOYZ2K.js → context-clear-SHIBYK6T.js} +48 -40
- package/dist/{context-working-set-MIEVECVZ.js → context-working-set-5ZGKPGZQ.js} +11 -10
- package/dist/{dispatch-runner-VVA4SRRH.js → dispatch-runner-EFMJT4LD.js} +88 -60
- package/dist/{docs-7LQ23DLM.js → docs-23KQS3XK.js} +5 -5
- package/dist/doctor-QOA5FNY5.js +313 -0
- package/dist/{eval-IJ5VEZDJ.js → eval-TFBYQH4H.js} +66 -64
- package/dist/eval-inventory-SXH7PDKX.js +316 -0
- package/dist/{evidence-L5APPXNV.js → evidence-ERGESKGN.js} +198 -44
- package/dist/{evolve-RGNKFJ52.js → evolve-VDXTSYCJ.js} +46 -38
- package/dist/{extensions-7WYWUX5A.js → extensions-7BGBHN57.js} +6 -6
- package/dist/{fleet-6CNVBZZP.js → fleet-2RRVDF2V.js} +189 -101
- package/dist/{fleet-commands-L2SXSYEI.js → fleet-commands-VJ726XIA.js} +10 -10
- package/dist/fleet-decisions-EPAPM3XJ.js +157 -0
- package/dist/{fleet-graph-2J3OOIPO.js → fleet-graph-JF5QOATM.js} +16 -15
- package/dist/fleet-inspect-VLY4S7QM.js +442 -0
- package/dist/{fleet-preflight-CZRJ4JP5.js → fleet-preflight-AIZUEJOY.js} +6 -5
- package/dist/{fleet-validate-C5RI6DP7.js → fleet-validate-AJRPDMDV.js} +20 -18
- package/dist/fleet-verify-JFEL2L3H.js +175 -0
- package/dist/fleet-view-ZCON35AG.js +102 -0
- package/dist/{init-VBN2ACVA.js → init-DN2WWLFE.js} +64 -56
- package/dist/install-XGLBQY5E.js +13 -0
- package/dist/interop-OZBKXAYL.js +114 -0
- package/dist/{library-JHGUMLY2.js → library-YWZG7IMW.js} +19 -18
- package/dist/{memory-K4OQIYWG.js → memory-I4C4HMLW.js} +48 -40
- package/dist/{models-2NCZUWDD.js → models-CEYXJBO6.js} +30 -28
- package/dist/{monitor-MMVTJABD.js → monitor-NZ6GCI3P.js} +53 -47
- package/dist/{orchestrator-ZKBPCHW6.js → orchestrator-GCGQ4N5I.js} +6311 -7145
- package/dist/panes-HMABYVO4.js +58 -0
- package/dist/panes-KY6W3V2E.js +103 -0
- package/dist/{paths-DBXMZMDU.js → paths-II4K7DNR.js} +5 -5
- package/dist/{reset-DD5JGOY3.js → reset-DQ6FGCSH.js} +13 -11
- package/dist/resources-BB3MVJMD.js +111 -0
- package/dist/{run-QEGNX7FL.js → run-H2GQDUER.js} +113 -82
- package/dist/{share-JKD3BQMW.js → share-GTJN6A5O.js} +18 -17
- package/dist/{skills-LMQIKDOZ.js → skills-L55TEW6R.js} +31 -24
- package/dist/{skills-eval-I7X2774U.js → skills-eval-XVXPH2JI.js} +61 -52
- package/dist/skills-inventory-S4MXPJFV.js +126 -0
- package/dist/slash-commands-ZSGASKJC.js +77 -0
- package/dist/{steer-CF5TDANS.js → steer-RZGSCY4R.js} +3 -3
- package/dist/{support-I7LOJLIF.js → support-PKEUNNQL.js} +4 -4
- package/dist/{targets-RUSR6B5Z.js → targets-NCPZ644J.js} +31 -29
- package/dist/{terminal-lease-QYVORFR4.js → terminal-lease-44SV3YCN.js} +4 -4
- package/dist/tools-DAF3DI3C.js +27 -0
- package/dist/{trace-ODOQIVIW.js → trace-FYVW2MQA.js} +149 -7
- package/dist/tui-primitives-2AKXQNZK.js +13 -0
- package/dist/{uninstall-ZJF5H5ZN.js → uninstall-DW2PNOIC.js} +5 -5
- package/dist/{upgrade-XANW3FXB.js → upgrade-3XPP6OQL.js} +26 -24
- package/dist/{usage-4H7ZRXQT.js → usage-3NLHGTU2.js} +57 -49
- package/dist/{verifiers-UZXNBZEB.js → verifiers-SSQONKRT.js} +171 -12
- package/dist/{verify-BVKWTNDL.js → verify-3U6J7FZI.js} +9 -9
- package/dist/{web-fetch-2YHJ3KTG.js → web-fetch-S7RR6GZ7.js} +3 -3
- package/dist/{wiki-generate-MY7WV2QI.js → wiki-generate-CEHYGPGQ.js} +67 -59
- package/dist/with-panes-MKB46MPQ.js +782 -0
- package/dist/worker/entry.js +101 -66
- package/docs/README.md +3 -2
- package/docs/acp.md +24 -3
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/artifact-versions.md +4 -1
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +43 -5
- package/docs/commands-and-modes.md +31 -2
- package/docs/configuration-and-targets.md +40 -10
- package/docs/context-engine.md +1 -1
- package/docs/development-pipeline.md +19 -0
- package/docs/dispatch-typed-intent.md +385 -0
- package/docs/documentation-coverage.md +2 -2
- package/docs/documentation-guide.md +1 -1
- package/docs/environment-variables.md +1 -0
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +1 -1
- package/docs/evidence-and-memory.md +2 -2
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +1 -1
- package/docs/extensions-and-sharing.md +25 -1
- package/docs/fleet-dispatch.md +22 -1
- package/docs/installation-and-lifecycle.md +15 -2
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +10 -1
- package/docs/observability.md +3 -3
- package/docs/proactive-memory.md +1 -1
- package/docs/prompt-envelope-and-tools.md +1 -1
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/safety-model.md +2 -2
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +1 -1
- package/docs/skills-marketplace.md +1 -1
- package/docs/tool-usage.md +18 -8
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +1 -1
- package/docs/tui-design.md +1 -1
- package/docs/worker-dispatch-mechanics.md +1 -1
- package/package.json +4 -2
- package/src/cli/acp.ts +6 -2
- package/src/cli/argv.ts +25 -0
- package/src/cli/configure.ts +23 -21
- package/src/cli/doctor-panes.ts +124 -0
- package/src/cli/doctor-toolchain.ts +57 -0
- package/src/cli/doctor.ts +20 -1
- package/src/cli/eval-inventory.ts +436 -0
- package/src/cli/eval.ts +13 -0
- package/src/cli/evidence-detail.ts +88 -0
- package/src/cli/evidence-inventory.ts +183 -0
- package/src/cli/evidence.ts +30 -5
- package/src/cli/fleet-decisions.ts +69 -0
- package/src/cli/fleet-inspect.ts +334 -0
- package/src/cli/fleet-verify.ts +133 -0
- package/src/cli/fleet-view.ts +810 -0
- package/src/cli/fleet.ts +148 -37
- package/src/cli/index.ts +14 -2
- package/src/cli/interop-inspect.ts +128 -0
- package/src/cli/interop.ts +34 -0
- package/src/cli/panes.ts +35 -0
- package/src/cli/reset.ts +5 -2
- package/src/cli/run.ts +58 -0
- package/src/cli/skills-inventory.ts +185 -0
- package/src/cli/skills.ts +16 -13
- package/src/cli/tools.ts +321 -0
- package/src/cli/trace-inspect.ts +252 -0
- package/src/cli/trace.ts +23 -2
- package/src/cli/verifiers-inspect.ts +347 -0
- package/src/cli/verifiers.ts +9 -0
- package/src/core/bus-events.ts +4 -0
- package/src/core/config.ts +49 -0
- package/src/core/defaults.ts +93 -7
- package/src/core/response-schema.ts +44 -4
- package/src/core/theme-token-hex.ts +43 -0
- package/src/core/tool-names.ts +2 -1
- package/src/core/xdg.ts +1 -1
- package/src/domains/agents/fleets/build-review.md +0 -3
- package/src/domains/agents/fleets/build-test.md +0 -3
- package/src/domains/agents/result-contract-filesystem.ts +32 -0
- package/src/domains/agents/result-contract.ts +164 -35
- package/src/domains/config/classify.ts +3 -0
- package/src/domains/dispatch/admission-error.ts +9 -0
- package/src/domains/dispatch/admission.ts +22 -21
- package/src/domains/dispatch/capacity-lease.ts +21 -1
- package/src/domains/dispatch/council-topology.ts +398 -0
- package/src/domains/dispatch/extension.ts +222 -50
- package/src/domains/dispatch/fleet-node-prompt.ts +62 -0
- package/src/domains/dispatch/fleet-plan.ts +7 -2
- package/src/domains/dispatch/fleet-run.ts +64 -1
- package/src/domains/dispatch/gate-decisions.ts +11 -1
- package/src/domains/dispatch/gate-role-prompts.ts +9 -0
- package/src/domains/dispatch/gate-topology.ts +289 -0
- package/src/domains/dispatch/index.ts +19 -0
- package/src/domains/dispatch/intent-compatibility.ts +330 -0
- package/src/domains/dispatch/intent.ts +85 -1
- package/src/domains/dispatch/reservation-store.ts +24 -4
- package/src/domains/dispatch/run-event-journal-bridge.ts +149 -0
- package/src/domains/dispatch/run-event-journal.ts +598 -0
- package/src/domains/dispatch/state.ts +45 -1
- package/src/domains/dispatch/types.ts +13 -0
- package/src/domains/dispatch/validation.ts +33 -8
- package/src/domains/eval/compare/compare.ts +3 -16
- package/src/domains/eval/inventory.ts +113 -0
- package/src/domains/eval/schema/serving.ts +31 -0
- package/src/domains/evidence/store.ts +6 -0
- package/src/domains/memory/index.ts +0 -1
- package/src/domains/memory/task-memory-policy.ts +6 -10
- package/src/domains/memory/task-memory-telemetry.ts +1 -0
- package/src/domains/middleware/memory-intervention.ts +33 -21
- package/src/domains/mux/contract.ts +434 -0
- package/src/domains/mux/detect.ts +158 -0
- package/src/domains/mux/extension.ts +47 -0
- package/src/domains/mux/index.ts +96 -0
- package/src/domains/mux/manifest.ts +6 -0
- package/src/domains/mux/operations.ts +164 -0
- package/src/domains/mux/pane-registry.ts +90 -0
- package/src/domains/mux/protocol.ts +49 -0
- package/src/domains/mux/socket-client.ts +816 -0
- package/src/domains/mux/types.ts +222 -0
- package/src/domains/mux/viewer-command.ts +59 -0
- package/src/domains/mux/yazi/assets/init.lua +2 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/LICENSE +21 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/README.md +78 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/main.lua +255 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/types.lua +12 -0
- package/src/domains/mux/yazi/assets/yazi.toml +17 -0
- package/src/domains/mux/yazi/event-stream.ts +180 -0
- package/src/domains/mux/yazi/profile.ts +299 -0
- package/src/domains/mux/yazi/session.ts +228 -0
- package/src/domains/mux/yazi/theme.ts +30 -0
- package/src/domains/observability/cost.ts +21 -0
- package/src/domains/observability/index.ts +2 -0
- package/src/domains/observability/trace-store.ts +42 -0
- package/src/domains/providers/endpoint-capacity.ts +154 -22
- package/src/domains/providers/endpoint-slots-store.ts +189 -0
- package/src/domains/providers/extension.ts +20 -3
- package/src/domains/providers/index.ts +22 -0
- package/src/domains/providers/model-runtime-capabilities.ts +32 -0
- package/src/domains/providers/runtimes/boot-manifest.ts +1 -0
- package/src/domains/providers/runtimes/builtins.ts +2 -0
- package/src/domains/providers/runtimes/protocol/litellm.ts +375 -0
- package/src/domains/providers/support.ts +1 -0
- package/src/domains/providers/target-model-cache.ts +124 -0
- package/src/domains/resources/index.ts +3 -0
- package/src/domains/resources/skills/loader.ts +33 -0
- package/src/domains/safety/action-classifier.ts +6 -0
- package/src/domains/toolchain/archive.ts +175 -0
- package/src/domains/toolchain/contract.ts +28 -0
- package/src/domains/toolchain/extension.ts +47 -0
- package/src/domains/toolchain/index.ts +39 -0
- package/src/domains/toolchain/install.ts +327 -0
- package/src/domains/toolchain/manifest.ts +8 -0
- package/src/domains/toolchain/paths.ts +34 -0
- package/src/domains/toolchain/registry.ts +265 -0
- package/src/domains/toolchain/remove.ts +218 -0
- package/src/domains/toolchain/resolve.ts +182 -0
- package/src/domains/toolchain/types.ts +113 -0
- package/src/domains/toolchain/version.ts +88 -0
- package/src/engine/acp/server.ts +413 -70
- package/src/engine/acp/types.ts +19 -1
- package/src/engine/claude/sdk-module.ts +98 -0
- package/src/engine/claude/sdk-runtime.ts +19 -11
- package/src/engine/tui-primitives.ts +21 -0
- package/src/engine/tui.ts +1 -0
- package/src/engine/worker-runtime.ts +2 -13
- package/src/entry/boot-options.ts +2 -0
- package/src/entry/orchestrator.ts +103 -5
- package/src/entry/panes-activation.ts +31 -0
- package/src/entry/with-panes.ts +20 -0
- package/src/interactive/context-overlay.ts +1 -0
- package/src/interactive/cost-overlay.ts +2 -0
- package/src/interactive/council-grid.ts +1 -3
- package/src/interactive/council.ts +11 -0
- package/src/interactive/dispatch-board.ts +26 -16
- package/src/interactive/interactive-application.ts +153 -6
- package/src/interactive/interactive-input-runtime.ts +7 -0
- package/src/interactive/interactive-slash-runtime.ts +36 -6
- package/src/interactive/memory-overlay.ts +1 -0
- package/src/interactive/modal-marker.ts +170 -0
- package/src/interactive/mux-bridge.ts +214 -0
- package/src/interactive/overlay-frame.ts +58 -2
- package/src/interactive/overlay-general-openers.ts +1 -0
- package/src/interactive/overlay-key-routing.ts +14 -3
- package/src/interactive/overlay-lifecycle.ts +19 -3
- package/src/interactive/overlay-model-selectors.ts +40 -3
- package/src/interactive/overlay-permission-lifecycle.ts +90 -22
- package/src/interactive/overlay-transitions.ts +18 -4
- package/src/interactive/overlays/agents.ts +1 -0
- package/src/interactive/overlays/ask-user.ts +136 -30
- package/src/interactive/overlays/auth-dialog.ts +1 -0
- package/src/interactive/overlays/context-reset.ts +1 -0
- package/src/interactive/overlays/cwd-fallback.ts +1 -0
- package/src/interactive/overlays/decisions.ts +11 -11
- package/src/interactive/overlays/extensions.ts +1 -0
- package/src/interactive/overlays/fleet-run-approval.ts +1 -0
- package/src/interactive/overlays/handoff-review.ts +1 -0
- package/src/interactive/overlays/help-reference.ts +2 -0
- package/src/interactive/overlays/interop.ts +1 -0
- package/src/interactive/overlays/library-install-confirm.ts +1 -0
- package/src/interactive/overlays/library-tabs.ts +28 -0
- package/src/interactive/overlays/list-overlay.ts +10 -1
- package/src/interactive/overlays/message-picker.ts +1 -0
- package/src/interactive/overlays/model-scope.ts +86 -0
- package/src/interactive/overlays/model-selector.ts +1 -0
- package/src/interactive/overlays/prompts.ts +1 -0
- package/src/interactive/overlays/session-selector.ts +1 -0
- package/src/interactive/overlays/settings-sections.ts +30 -0
- package/src/interactive/overlays/settings.ts +579 -44
- package/src/interactive/overlays/side-question.ts +1 -0
- package/src/interactive/overlays/skills-hub.ts +3 -11
- package/src/interactive/overlays/tree-selector.ts +1 -0
- package/src/interactive/pane-policy.ts +46 -0
- package/src/interactive/panes-runtime.ts +292 -0
- package/src/interactive/renderers/compaction-summary.ts +29 -0
- package/src/interactive/renderers/worker-entry.ts +122 -14
- package/src/interactive/slash-commands.ts +251 -15
- package/src/interactive/tasks-overlay.ts +1 -0
- package/src/interactive/theme/tokens.ts +3 -14
- package/src/interactive/turn-context.ts +47 -2
- package/src/interactive/view/artifacts.ts +109 -1
- package/src/interactive/view/view-overlay.ts +1 -0
- package/src/interactive/watch-pane.ts +152 -0
- package/src/interactive/worker-progress.ts +7 -1
- package/src/interactive/worker-receipts.ts +19 -1
- package/src/interactive/worker-stream.ts +5 -0
- package/src/interactive/yazi-bridge.ts +444 -0
- package/src/tools/bootstrap.ts +26 -2
- package/src/tools/builtin-tool-catalog.ts +15 -0
- package/src/tools/compete-worktrees.ts +83 -2
- package/src/tools/core-bootstrap.ts +2 -1
- package/src/tools/dispatch-admission.ts +14 -3
- package/src/tools/dispatch-arguments.ts +20 -20
- package/src/tools/dispatch-run-events.ts +134 -19
- package/src/tools/dispatch-runner.ts +29 -7
- package/src/tools/dispatch-types.ts +15 -3
- package/src/tools/dispatch.ts +1 -1
- package/src/tools/executables.ts +17 -14
- package/src/tools/observation.ts +54 -4
- package/src/tools/panes-surface.ts +38 -0
- package/src/tools/panes.ts +112 -0
- package/src/tools/policy.ts +10 -1
- package/src/tools/presentation.ts +1 -0
- package/dist/chunk-D73KXYPF.js +0 -37
- package/dist/chunk-MLOK6ZOS.js +0 -2888
- package/dist/chunk-YKOFT37S.js +0 -279
- package/dist/doctor-TWBWFK5V.js +0 -165
|
@@ -6,7 +6,16 @@ import {
|
|
|
6
6
|
setFleetProfileInSettings,
|
|
7
7
|
useTargetInSettings,
|
|
8
8
|
} from "../../core/config.js";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
ACTIVE_ROUTING_POSTURES,
|
|
11
|
+
ACTIVE_ROUTING_ROLES,
|
|
12
|
+
type ActiveRoutingPosture,
|
|
13
|
+
type ActiveRoutingRole,
|
|
14
|
+
DEFAULT_SETTINGS,
|
|
15
|
+
THINKING_LEVELS,
|
|
16
|
+
type WorkerEscalationSettings,
|
|
17
|
+
} from "../../core/defaults.js";
|
|
18
|
+
import type { GuardrailValues } from "../../core/guardrails.js";
|
|
10
19
|
import { getAtPath, isRoutingPath } from "../../core/session-routing.js";
|
|
11
20
|
import { MAX_TIMER_DELAY_MS } from "../../core/timers.js";
|
|
12
21
|
import { capacityLeaseUsage } from "../../domains/dispatch/capacity-lease.js";
|
|
@@ -48,6 +57,7 @@ import { clockLocal } from "../format-time.js";
|
|
|
48
57
|
import { buildHint, DEFAULT_SELECT_THEME, showClioOverlayFrame } from "../overlay-frame.js";
|
|
49
58
|
import { barSep, clioTheme, GLYPH, padAnsi, rule, screenTitle } from "../theme/index.js";
|
|
50
59
|
import { modelsForTarget } from "./model-selector.js";
|
|
60
|
+
import { SETTINGS_SECTIONS, type SettingsSectionId } from "./settings-sections.js";
|
|
51
61
|
|
|
52
62
|
export const SETTINGS_OVERLAY_WIDTH = "100%";
|
|
53
63
|
export const SETTINGS_OVERLAY_MAX_HEIGHT = "100%";
|
|
@@ -93,6 +103,16 @@ const ULTRA_NARROW_TERMINAL_WIDTH = 60;
|
|
|
93
103
|
/** Shown when no runtime is resolvable, so it offers the full vocabulary. */
|
|
94
104
|
const FALLBACK_THINKING_VALUES: ReadonlyArray<string> = THINKING_LEVELS;
|
|
95
105
|
const ROW_GAP = " ";
|
|
106
|
+
/**
|
|
107
|
+
* `workers.escalation` and `workers.resilienceCooldownMs` are optional keys, so
|
|
108
|
+
* the row that shows them and the mutation that writes them both need a
|
|
109
|
+
* definite shipped value to fall back to.
|
|
110
|
+
*/
|
|
111
|
+
const SHIPPED_ESCALATION: WorkerEscalationSettings = DEFAULT_SETTINGS.workers.escalation ?? {
|
|
112
|
+
timeoutMs: 120_000,
|
|
113
|
+
fallback: "deny",
|
|
114
|
+
};
|
|
115
|
+
const SHIPPED_RESILIENCE_COOLDOWN_MS = DEFAULT_SETTINGS.workers.resilienceCooldownMs ?? 15_000;
|
|
96
116
|
/**
|
|
97
117
|
* The product's cut marker, as the help center and every list overlay use it.
|
|
98
118
|
*
|
|
@@ -126,36 +146,27 @@ const RESTART_REQUIRED_IDS = new Set<string>([
|
|
|
126
146
|
"runtimePlugins",
|
|
127
147
|
"terminal.tuiMode",
|
|
128
148
|
"terminal.fullscreenScrollbar",
|
|
149
|
+
// The mux domain runs its detection ladder once, at boot, from the value this
|
|
150
|
+
// key held then. Changing the rung mid-session would leave the contract on
|
|
151
|
+
// the rung it resolved to, so the row says restart rather than lying.
|
|
152
|
+
"panes.enabled",
|
|
129
153
|
]);
|
|
130
154
|
|
|
131
|
-
export
|
|
132
|
-
{ id: "safety", label: "Autonomy & Safety", group: "CORE" },
|
|
133
|
-
{ id: "orchestrator", label: "Orchestrator", group: "CORE" },
|
|
134
|
-
{ id: "fleet", label: "Fleet", group: "ROUTING" },
|
|
135
|
-
{ id: "targets", label: "Targets", group: "ROUTING" },
|
|
136
|
-
{ id: "models", label: "Models", group: "ROUTING" },
|
|
137
|
-
{ id: "budget", label: "Budget", group: "RUNTIME" },
|
|
138
|
-
{ id: "compaction", label: "Compaction", group: "RUNTIME" },
|
|
139
|
-
{ id: "retry", label: "Retry", group: "RUNTIME" },
|
|
140
|
-
{ id: "terminal", label: "Terminal", group: "EXPERIENCE" },
|
|
141
|
-
{ id: "watchdog", label: "Watchdog", group: "EXPERIENCE" },
|
|
142
|
-
{ id: "advanced", label: "Advanced", group: "EXPERIENCE" },
|
|
143
|
-
] as const;
|
|
144
|
-
|
|
145
|
-
export type SettingsSectionId = (typeof SETTINGS_SECTIONS)[number]["id"];
|
|
155
|
+
export { SETTINGS_SECTIONS, type SettingsSectionId };
|
|
146
156
|
|
|
147
157
|
const SETTINGS_SECTION_DESCRIPTIONS = {
|
|
148
|
-
safety: "How freely Clio acts, and how delegated agents' tools are governed.",
|
|
149
|
-
orchestrator: "Interactive chat routing and the optional proactive-memory model plane.",
|
|
150
|
-
fleet: "Defaults, profiles,
|
|
158
|
+
safety: "How freely Clio acts, how a worker's approval ask resolves, and how delegated agents' tools are governed.",
|
|
159
|
+
orchestrator: "Interactive chat routing, prompt pre-warm, and the optional proactive-memory model plane.",
|
|
160
|
+
fleet: "Defaults, profiles, agent bindings, and route activation for dispatched workers, and where they run.",
|
|
151
161
|
targets: "Configured inference targets: which one chat and the fleet use, and whether each answers.",
|
|
152
162
|
models: "The /model picker, favorites, and Alt+J / Alt+K cycling.",
|
|
153
|
-
budget: "Cost ceiling, per-turn output budget, and
|
|
154
|
-
compaction: "When and how the context window is summarized under pressure.",
|
|
155
|
-
retry: "Automatic recovery from transient provider and
|
|
163
|
+
budget: "Cost ceiling, per-turn output budget, worker concurrency, and the guardrail backstops.",
|
|
164
|
+
compaction: "When and how the context window is evicted and summarized under pressure.",
|
|
165
|
+
retry: "Automatic recovery from transient provider, network, and stalled-stream errors.",
|
|
156
166
|
terminal: "Terminal integration and the Clio color palette.",
|
|
157
167
|
watchdog: "The opt-in turn-end verifier run, where it is routed, and whether it also fires mid-turn.",
|
|
158
|
-
advanced:
|
|
168
|
+
advanced:
|
|
169
|
+
"Commit provenance, runtime plugins, delegation timeouts, the resource library, and links to other surfaces.",
|
|
159
170
|
} as const satisfies Record<SettingsSectionId, string>;
|
|
160
171
|
|
|
161
172
|
export const SETTINGS_LABELS_BY_ID = {
|
|
@@ -165,6 +176,8 @@ export const SETTINGS_LABELS_BY_ID = {
|
|
|
165
176
|
// section headed Fleet whose rows read "Worker profiles" and "Worker
|
|
166
177
|
// retries" made one setting look like two subsystems.
|
|
167
178
|
"workers.onPermission": "Fleet approvals routing",
|
|
179
|
+
"workers.escalation.timeoutMs": "Escalation timeout (ms)",
|
|
180
|
+
"workers.escalation.fallback": "Escalation fallback",
|
|
168
181
|
"delegation.defaults.toolGovernance": "Delegation governance",
|
|
169
182
|
"skills.trustProjectCompatRoots": "Trust project skill roots",
|
|
170
183
|
"attribution.gitCommits": "Clio commit provenance",
|
|
@@ -180,25 +193,49 @@ export const SETTINGS_LABELS_BY_ID = {
|
|
|
180
193
|
"memory.intervention.windowSteps": "Memory trajectory steps",
|
|
181
194
|
"memory.intervention.maxTokens": "Memory reminder tokens",
|
|
182
195
|
"memory.intervention.timeoutMs": "Memory timeout (ms)",
|
|
196
|
+
"prewarm.enabled": "Prompt pre-warm",
|
|
183
197
|
"workers.default.target": "Default target",
|
|
184
198
|
"workers.default.model": "Default model",
|
|
185
199
|
"workers.default.thinkingLevel": "Default thinking level",
|
|
186
200
|
"workers.profiles": "Add profile",
|
|
187
201
|
"workers.agentBindings": "Add agent route",
|
|
188
202
|
"workers.maxRetries": "Fleet retries",
|
|
203
|
+
"workers.resilienceCooldownMs": "Resilience cooldown (ms)",
|
|
204
|
+
"routing.activeRoles": "Active routing roles",
|
|
205
|
+
"routing.activePostures": "Active routing postures",
|
|
206
|
+
"routing.agentAutomation.activeAgentRoles": "Active agent routes",
|
|
207
|
+
"panes.enabled": "Panes",
|
|
208
|
+
"panes.notifications": "Pane notifications",
|
|
209
|
+
"panes.journal": "Run event journal",
|
|
210
|
+
"panes.yazi.enabled": "Files pane",
|
|
211
|
+
"panes.yazi.mode": "Files pane mode",
|
|
212
|
+
"panes.yazi.profile": "Yazi profile",
|
|
213
|
+
"panes.yazi.followCwd": "Follow conversation cwd",
|
|
189
214
|
scope: "Model cycle set",
|
|
190
215
|
"modelSelector.recentLimit": "Recent models kept",
|
|
191
216
|
"modelSelector.favorites": "Pinned favorites",
|
|
192
217
|
"budget.sessionCeilingUsd": "Session ceiling (USD)",
|
|
193
218
|
"defaults.maxTokens": "Output budget (tokens)",
|
|
194
219
|
"budget.concurrency": "Fleet concurrency",
|
|
220
|
+
"guardrails.turnToolCallBudget": "Turn tool-call budget",
|
|
221
|
+
"guardrails.workerToolCallCap": "Worker tool-call cap",
|
|
222
|
+
"guardrails.maxDispatchRuns": "Run ledger retention",
|
|
223
|
+
"guardrails.readMaxBytes": "Read byte cap",
|
|
224
|
+
"guardrails.observationTurnBudgetBytes": "Observation byte pool",
|
|
225
|
+
"guardrails.internalDispatchTimeoutMs": "Internal dispatch timeout (ms)",
|
|
195
226
|
"compaction.auto": "Auto-compact",
|
|
196
227
|
"compaction.excludeLastTurns": "Protected recent turns",
|
|
197
228
|
"compaction.threshold": "Compaction threshold",
|
|
229
|
+
"context.workingSet.enabled": "Working-set eviction",
|
|
230
|
+
"context.workingSet.policy": "Eviction policy",
|
|
231
|
+
"context.workingSet.target": "Eviction target pressure",
|
|
232
|
+
"context.workingSet.protectLastTurns": "Turns protected from eviction",
|
|
233
|
+
"context.workingSet.minEvictableTokens": "Minimum evictable tokens",
|
|
198
234
|
"retry.enabled": "Retry transient errors",
|
|
199
235
|
"retry.maxRetries": "Max retries",
|
|
200
236
|
"retry.baseDelayMs": "Base delay (ms)",
|
|
201
237
|
"retry.maxDelayMs": "Max delay (ms)",
|
|
238
|
+
"retry.streamStallMs": "Stream stall timeout (ms)",
|
|
202
239
|
"terminal.showTerminalProgress": "Terminal progress badges",
|
|
203
240
|
"terminal.outputVerbosity": "Output detail",
|
|
204
241
|
"terminal.tuiMode": "TUI mode",
|
|
@@ -218,6 +255,10 @@ export const SETTINGS_LABELS_BY_ID = {
|
|
|
218
255
|
targets: "Configured targets",
|
|
219
256
|
keybindings: "Keybinding overrides",
|
|
220
257
|
"delegation.agents": "Delegation agents",
|
|
258
|
+
"library.catalog": "Library catalog path",
|
|
259
|
+
"library.remote": "Library remote",
|
|
260
|
+
"library.confirmedRemote": "Confirmed library remote",
|
|
261
|
+
"library.sync": "Library sync",
|
|
221
262
|
} as const;
|
|
222
263
|
|
|
223
264
|
/**
|
|
@@ -231,9 +272,20 @@ type EntrySettingId =
|
|
|
231
272
|
| `fleet.nodes.${string}`
|
|
232
273
|
| `fleet.endpoints.${string}`;
|
|
233
274
|
export type EditableSettingId = keyof typeof SETTINGS_LABELS_BY_ID | EntrySettingId;
|
|
234
|
-
type FleetGroupHeaderId =
|
|
275
|
+
type FleetGroupHeaderId =
|
|
276
|
+
`fleet.group.${"defaults" | "profiles" | "agent-routes" | "route-activation" | "placement" | "panes"}`;
|
|
277
|
+
type TerminalGroupHeaderId = "terminal.group.files-pane";
|
|
278
|
+
type BudgetGroupHeaderId = "budget.group.guardrails";
|
|
279
|
+
type CompactionGroupHeaderId = "compaction.group.working-set";
|
|
280
|
+
type AdvancedGroupHeaderId = "advanced.group.library";
|
|
281
|
+
type GroupHeaderId =
|
|
282
|
+
| FleetGroupHeaderId
|
|
283
|
+
| TerminalGroupHeaderId
|
|
284
|
+
| BudgetGroupHeaderId
|
|
285
|
+
| CompactionGroupHeaderId
|
|
286
|
+
| AdvancedGroupHeaderId;
|
|
235
287
|
type TargetsCtaId = "targets.add-cta";
|
|
236
|
-
export type SettingsCenterRowId = EditableSettingId |
|
|
288
|
+
export type SettingsCenterRowId = EditableSettingId | GroupHeaderId | TargetsCtaId;
|
|
237
289
|
const REMOVE_PROFILE_CHOICE = "(remove profile)";
|
|
238
290
|
const UNBIND_CHOICE = "(unbind)";
|
|
239
291
|
const AUTO_PLACEMENT_CHOICE = "(auto placement)";
|
|
@@ -244,6 +296,8 @@ export const SETTINGS_SECTION_ROWS = {
|
|
|
244
296
|
safety: [
|
|
245
297
|
"autonomy",
|
|
246
298
|
"workers.onPermission",
|
|
299
|
+
"workers.escalation.timeoutMs",
|
|
300
|
+
"workers.escalation.fallback",
|
|
247
301
|
"delegation.defaults.toolGovernance",
|
|
248
302
|
"skills.trustProjectCompatRoots",
|
|
249
303
|
"safetyNet",
|
|
@@ -260,19 +314,46 @@ export const SETTINGS_SECTION_ROWS = {
|
|
|
260
314
|
"memory.intervention.windowSteps",
|
|
261
315
|
"memory.intervention.maxTokens",
|
|
262
316
|
"memory.intervention.timeoutMs",
|
|
317
|
+
"prewarm.enabled",
|
|
263
318
|
],
|
|
264
319
|
fleet: [
|
|
265
320
|
"workers.default.target",
|
|
266
321
|
"workers.default.model",
|
|
267
322
|
"workers.default.thinkingLevel",
|
|
268
323
|
"workers.maxRetries",
|
|
324
|
+
"workers.resilienceCooldownMs",
|
|
269
325
|
"workers.profiles",
|
|
270
326
|
"workers.agentBindings",
|
|
327
|
+
"routing.activeRoles",
|
|
328
|
+
"routing.activePostures",
|
|
329
|
+
"routing.agentAutomation.activeAgentRoles",
|
|
330
|
+
"panes.enabled",
|
|
331
|
+
"panes.notifications",
|
|
332
|
+
"panes.journal",
|
|
271
333
|
],
|
|
272
334
|
models: ["scope", "modelSelector.recentLimit", "modelSelector.favorites"],
|
|
273
|
-
budget: [
|
|
274
|
-
|
|
275
|
-
|
|
335
|
+
budget: [
|
|
336
|
+
"budget.sessionCeilingUsd",
|
|
337
|
+
"defaults.maxTokens",
|
|
338
|
+
"budget.concurrency",
|
|
339
|
+
"guardrails.turnToolCallBudget",
|
|
340
|
+
"guardrails.workerToolCallCap",
|
|
341
|
+
"guardrails.maxDispatchRuns",
|
|
342
|
+
"guardrails.readMaxBytes",
|
|
343
|
+
"guardrails.observationTurnBudgetBytes",
|
|
344
|
+
"guardrails.internalDispatchTimeoutMs",
|
|
345
|
+
],
|
|
346
|
+
compaction: [
|
|
347
|
+
"compaction.auto",
|
|
348
|
+
"compaction.threshold",
|
|
349
|
+
"compaction.excludeLastTurns",
|
|
350
|
+
"context.workingSet.enabled",
|
|
351
|
+
"context.workingSet.policy",
|
|
352
|
+
"context.workingSet.target",
|
|
353
|
+
"context.workingSet.protectLastTurns",
|
|
354
|
+
"context.workingSet.minEvictableTokens",
|
|
355
|
+
],
|
|
356
|
+
retry: ["retry.enabled", "retry.maxRetries", "retry.baseDelayMs", "retry.maxDelayMs", "retry.streamStallMs"],
|
|
276
357
|
terminal: [
|
|
277
358
|
"terminal.showTerminalProgress",
|
|
278
359
|
"terminal.outputVerbosity",
|
|
@@ -281,6 +362,10 @@ export const SETTINGS_SECTION_ROWS = {
|
|
|
281
362
|
"terminal.smoothStreaming",
|
|
282
363
|
"terminal.notify",
|
|
283
364
|
"theme",
|
|
365
|
+
"panes.yazi.enabled",
|
|
366
|
+
"panes.yazi.mode",
|
|
367
|
+
"panes.yazi.profile",
|
|
368
|
+
"panes.yazi.followCwd",
|
|
284
369
|
],
|
|
285
370
|
watchdog: ["watchdog.enabled", "watchdog.target", "watchdog.cadenceToolCalls"],
|
|
286
371
|
advanced: [
|
|
@@ -293,6 +378,10 @@ export const SETTINGS_SECTION_ROWS = {
|
|
|
293
378
|
"delegation.defaults.permissionTimeoutMs",
|
|
294
379
|
"keybindings",
|
|
295
380
|
"delegation.agents",
|
|
381
|
+
"library.catalog",
|
|
382
|
+
"library.remote",
|
|
383
|
+
"library.confirmedRemote",
|
|
384
|
+
"library.sync",
|
|
296
385
|
],
|
|
297
386
|
targets: ["targets"],
|
|
298
387
|
} as const satisfies Record<SettingsSectionId, readonly EditableSettingId[]>;
|
|
@@ -301,6 +390,8 @@ const SETTINGS_DESCRIPTIONS_BY_ID = {
|
|
|
301
390
|
autonomy: "How freely Clio acts; the safety net always applies.",
|
|
302
391
|
"workers.onPermission":
|
|
303
392
|
"How a worker resolves an approval ask: deny the call, fail the run, or escalate to this session.",
|
|
393
|
+
"workers.escalation.timeoutMs": "How long an escalated worker approval waits for you before the fallback applies.",
|
|
394
|
+
"workers.escalation.fallback": "What an escalated approval becomes when nobody answers inside the timeout.",
|
|
304
395
|
"delegation.defaults.toolGovernance": "Tool policy for delegated external agents.",
|
|
305
396
|
"skills.trustProjectCompatRoots": "Whether third-party project skill roots are loaded.",
|
|
306
397
|
"attribution.gitCommits":
|
|
@@ -317,25 +408,51 @@ const SETTINGS_DESCRIPTIONS_BY_ID = {
|
|
|
317
408
|
"memory.intervention.windowSteps": "Recent completed tool steps visible to the memory policy.",
|
|
318
409
|
"memory.intervention.maxTokens": "Hard cap for one visible memory reminder.",
|
|
319
410
|
"memory.intervention.timeoutMs": "Hard deadline for one background-model memory call.",
|
|
411
|
+
"prewarm.enabled": "Send the next turn's known prefix ahead of time so a local server has already prefilled it.",
|
|
320
412
|
"workers.default.target": "Default /run target id.",
|
|
321
413
|
"workers.default.model": "Default /run wire model id.",
|
|
322
414
|
"workers.default.thinkingLevel": "Reasoning budget for dispatched workers.",
|
|
323
415
|
"workers.profiles": "Named target/model/thinking choices that native workers can use. Enter adds one.",
|
|
324
416
|
"workers.agentBindings": "Pins native Clio agents, including shadow agents, to worker profiles. Enter adds one.",
|
|
325
417
|
"workers.maxRetries": "Automatic retries for a retryable worker outcome.",
|
|
418
|
+
"workers.resilienceCooldownMs":
|
|
419
|
+
"How long a failing target, runtime, and model route is skipped before it is tried again.",
|
|
420
|
+
"routing.activeRoles": "Execution roles whose joint route selection may act instead of only shadowing.",
|
|
421
|
+
"routing.activePostures": "Route postures whose selection may act instead of only shadowing.",
|
|
422
|
+
"routing.agentAutomation.activeAgentRoles": "Exact agent and execution-role pairs whose agent choice may act.",
|
|
423
|
+
"panes.enabled": "Default panes activation for new sessions; `--with-panes` / `--no-panes` beat it.",
|
|
424
|
+
"panes.notifications": "Which terminal run states raise a pane-host toast.",
|
|
425
|
+
"panes.journal": "Whether every dispatched run's event tail is written to disk for `clio-coder fleet view`.",
|
|
426
|
+
"panes.yazi.enabled": "Whether `/panes open yazi` may open the files pane or one-shot chooser.",
|
|
427
|
+
"panes.yazi.mode": "Keep Yazi beside the conversation, or close it after one selection.",
|
|
428
|
+
"panes.yazi.profile": "Use Clio's managed pick profile or leave the operator's Yazi profile untouched.",
|
|
429
|
+
"panes.yazi.followCwd": "Push the conversation directory into an already-open companion pane.",
|
|
326
430
|
scope: "Alt+J and Alt+K model cycle set.",
|
|
327
431
|
"modelSelector.recentLimit": "How many recently used models /model remembers.",
|
|
328
432
|
"modelSelector.favorites": "Exact target/model refs pinned in /model.",
|
|
329
433
|
"budget.sessionCeilingUsd": "Per-session cost cap.",
|
|
330
434
|
"defaults.maxTokens": "Output tokens requested per turn, applied to every target.",
|
|
331
435
|
"budget.concurrency": "Parallel workers allowed during dispatch.",
|
|
436
|
+
"guardrails.turnToolCallBudget": "Soft per-turn tool-call budget for this chat loop.",
|
|
437
|
+
"guardrails.workerToolCallCap": "Lifetime ceiling on tool calls one dispatched worker may execute.",
|
|
438
|
+
"guardrails.maxDispatchRuns": "How many finished runs the dispatch ledger keeps before the oldest are dropped.",
|
|
439
|
+
"guardrails.readMaxBytes": "Per-call byte cap for the read tool.",
|
|
440
|
+
"guardrails.observationTurnBudgetBytes": "Shared per-turn byte pool across every observation-producing tool.",
|
|
441
|
+
"guardrails.internalDispatchTimeoutMs": "Wall-clock cap for one internal generator dispatch.",
|
|
332
442
|
"compaction.auto": "Auto-compact before a turn when context crosses the threshold.",
|
|
333
443
|
"compaction.excludeLastTurns": "Recent user turns protected from observation masking.",
|
|
334
444
|
"compaction.threshold": "Pressure at which compaction masks stale observations, then summarizes.",
|
|
445
|
+
"context.workingSet.enabled": "Non-destructive eviction of stale tool results before a summary is ever needed.",
|
|
446
|
+
"context.workingSet.policy": "Which candidates the eviction pass selects.",
|
|
447
|
+
"context.workingSet.target": "Context pressure an applied eviction batch brings the session down to.",
|
|
448
|
+
"context.workingSet.protectLastTurns": "Recent user turns whose observations are never evicted.",
|
|
449
|
+
"context.workingSet.minEvictableTokens":
|
|
450
|
+
"Results below this token estimate stay; the marker would cost more than it saves.",
|
|
335
451
|
"retry.enabled": "Retry transient provider errors on the next submit.",
|
|
336
452
|
"retry.maxRetries": "Retry attempts after the initial failure.",
|
|
337
453
|
"retry.baseDelayMs": "Initial retry delay in milliseconds.",
|
|
338
454
|
"retry.maxDelayMs": "Maximum retry delay in milliseconds.",
|
|
455
|
+
"retry.streamStallMs": "Silence on an in-flight stream past this long is treated as a wedged backend.",
|
|
339
456
|
"terminal.showTerminalProgress": "Emit OSC 9;4 progress badges during agent turns.",
|
|
340
457
|
"terminal.outputVerbosity": "How much reasoning, tool input, and live tool output appears in the transcript.",
|
|
341
458
|
"terminal.tuiMode": "Use regular terminal scrollback or a fullscreen transcript with a sticky composer and footer.",
|
|
@@ -356,6 +473,10 @@ const SETTINGS_DESCRIPTIONS_BY_ID = {
|
|
|
356
473
|
targets: "Inference targets available for chat and workers. Add one with `clio-coder targets add`.",
|
|
357
474
|
keybindings: "Custom key overrides layered on the defaults.",
|
|
358
475
|
"delegation.agents": "External ACP agents available to /delegate.",
|
|
476
|
+
"library.catalog": "Path to the private resource catalog; blank uses the one in your config directory.",
|
|
477
|
+
"library.remote": "Git remote the catalog syncs with; blank keeps the library entirely local.",
|
|
478
|
+
"library.confirmedRemote": "The remote you confirmed. Sync refuses until it matches library.remote.",
|
|
479
|
+
"library.sync": "Whether `clio-coder library sync` and `push` may talk to the remote at all.",
|
|
359
480
|
} as const satisfies Record<EditableSettingId, string>;
|
|
360
481
|
|
|
361
482
|
/** Longer, optional guidance shown beneath the one-line description when there is room. */
|
|
@@ -366,6 +487,38 @@ const SETTINGS_HELP_BY_ID: Partial<Record<EditableSettingId, string>> = {
|
|
|
366
487
|
"Clamped down to each model's max-output cap and the remaining context window. Set 0 to use per-model caps only.",
|
|
367
488
|
"compaction.threshold":
|
|
368
489
|
"pressure = estimated tokens ÷ context window. Higher keeps more history but risks overflow before a summary runs.",
|
|
490
|
+
"context.workingSet.enabled":
|
|
491
|
+
"Eviction moves stale tool-result bodies and thinking blocks out of the model's working set and records a ledger entry; history is never rewritten. Off skips eviction and goes straight to summary compaction. Legal values: true, false · default: true.",
|
|
492
|
+
"context.workingSet.policy":
|
|
493
|
+
"structural-v1 selects by message structure; age-horizon is the older age-based rule. Legal values: structural-v1, age-horizon · default: structural-v1.",
|
|
494
|
+
"context.workingSet.target":
|
|
495
|
+
"An applied eviction batch keeps evicting until pressure reaches this ratio, so it sits below compaction.threshold. Greater than 0 and less than 1 · default: 0.6.",
|
|
496
|
+
"context.workingSet.protectLastTurns":
|
|
497
|
+
"Counted in user turns, the same unit compaction.excludeLastTurns uses. Whole number of at least 1 · default: 6.",
|
|
498
|
+
"context.workingSet.minEvictableTokens":
|
|
499
|
+
"The floor sweep put marker break-even near 50 tokens; 200 is the churn guard. Whole number, 0 evicts anything · default: 200.",
|
|
500
|
+
"guardrails.turnToolCallBudget":
|
|
501
|
+
"Crossing it blocks further calls in the turn with a stop-and-summarize directive, and the hard interrupt ceiling sits a fixed margin above. A backstop against a model spraying unproductive calls, not a routine ceiling: a repo-wide audit legitimately runs dozens. Whole number of at least 1 · default: 60. Env override CLIO_CODER_TURN_TOOL_CALL_BUDGET beats this value.",
|
|
502
|
+
"guardrails.workerToolCallCap":
|
|
503
|
+
"Bounds admitted calls, not attempts: a call the harness refuses never ran and never spends the cap. Dispatch takes the smaller of this and the agent recipe's own budget, so the recipe normally binds. Whole number of at least 1 · default: 150. Env override CLIO_CODER_WORKER_TOOL_CALL_CAP beats this value.",
|
|
504
|
+
"guardrails.maxDispatchRuns":
|
|
505
|
+
"Runs leaving the ring also lose their event journal directory. Whole number of at least 1 · default: 1000. Env override CLIO_CODER_MAX_DISPATCH_RUNS beats this value.",
|
|
506
|
+
"guardrails.readMaxBytes":
|
|
507
|
+
"Clamped up to a 1KB floor at use. Whole number of bytes, at least 1 · default: 51200 (50KB). Env override CLIO_CODER_READ_MAX_BYTES beats this value.",
|
|
508
|
+
"guardrails.observationTurnBudgetBytes":
|
|
509
|
+
"One pool shared by every observation-producing tool in a turn, so a single verbose tool cannot starve the rest. Whole number of bytes, at least 1 · default: 196608 (192KB). Env override CLIO_CODER_OBSERVATION_TURN_BUDGET_BYTES beats this value.",
|
|
510
|
+
"guardrails.internalDispatchTimeoutMs":
|
|
511
|
+
"Covers the wiki documenter and the bootstrap scout. Continuous output satisfies the heartbeat watchdog and a run mid-generation spends no tool calls, so this is the only guard that ends a degenerate generator. Healthy runs finish in minutes. Whole milliseconds of at least 1 · default: 900000 (15 minutes). Env override CLIO_CODER_INTERNAL_DISPATCH_TIMEOUT_MS beats this value.",
|
|
512
|
+
"retry.streamStallMs":
|
|
513
|
+
"Measured from the last token received, not from the request, so a slow-but-alive stream is never aborted. The retry then follows the same enabled/maxRetries/delay settings above. Whole milliseconds · default: 180000 (three minutes).",
|
|
514
|
+
"library.catalog":
|
|
515
|
+
"Absolute path, or blank for the catalog in your config directory. The catalog is the index `clio-coder library` reads; installed resources land in the usual skill and resource roots either way. Default: blank.",
|
|
516
|
+
"library.remote":
|
|
517
|
+
"A Git remote URL, or blank to keep the library local. Setting it is not enough to sync: the remote must also be confirmed, and library.sync must be true. Default: blank.",
|
|
518
|
+
"library.confirmedRemote":
|
|
519
|
+
"Written by the confirm flow, not by hand, because confirming a remote here would be the record confirming itself. Sync refuses with library_remote_unconfirmed until this equals library.remote. Default: blank.",
|
|
520
|
+
"library.sync":
|
|
521
|
+
"Off means `clio-coder library sync` and `push` refuse before touching the network, whatever the remote says. Legal values: true, false · default: false.",
|
|
369
522
|
"budget.concurrency": "auto sizes to your machine. A fixed number caps how many workers run at once.",
|
|
370
523
|
"skills.trustProjectCompatRoots":
|
|
371
524
|
"Project roots like .claude/skills and .codex/skills are untrusted by default; enabling exposes them to the model.",
|
|
@@ -373,6 +526,20 @@ const SETTINGS_HELP_BY_ID: Partial<Record<EditableSettingId, string>> = {
|
|
|
373
526
|
"Role trailers are added only when Clio has trusted evidence for that role. Disabling leaves subsequent commit messages entirely unchanged.",
|
|
374
527
|
"workers.onPermission":
|
|
375
528
|
"deny turns the ask into a tool denial and the run continues; fail stops the run as permission_required; escalate forwards the ask to you and falls back per workers.escalation on timeout.",
|
|
529
|
+
"workers.escalation.timeoutMs":
|
|
530
|
+
"Only the escalate posture reads it, and it is what keeps that posture non-stall: a headless session has no operator to answer, so the fallback always governs there. Whole milliseconds of at least 1; default: 120000 (two minutes).",
|
|
531
|
+
"workers.escalation.fallback":
|
|
532
|
+
"deny turns the unanswered ask into a tool denial and the run continues; fail ends the run as permission_required. Legal values: deny, fail · default: deny.",
|
|
533
|
+
"workers.resilienceCooldownMs":
|
|
534
|
+
"Applied per target, runtime, and wire model after a failure class that trips the breaker; a clean run clears it immediately. Whole milliseconds, 0 disables the cooldown; default: 15000.",
|
|
535
|
+
"routing.activeRoles":
|
|
536
|
+
"Joint route selection stays shadow-only, recording what it would have picked, unless both the execution role and the requested posture are named as active. Legal values: researcher, verifier, reviewer, judge · default: none active.",
|
|
537
|
+
"routing.activePostures":
|
|
538
|
+
"Manual pins are exact rather than adaptive, so manual is never an activated posture. Legal values: quality, balanced, latency, economy · default: none active.",
|
|
539
|
+
"routing.agentAutomation.activeAgentRoles":
|
|
540
|
+
"Exact agentId and executionRole pairs, because independent agent and role lists would authorize their whole cross-product. Execution roles: builder, researcher, verifier, reviewer, judge; the agentId `auto` is reserved. Edit the pairs in settings.yaml; default: none active.",
|
|
541
|
+
"prewarm.enabled":
|
|
542
|
+
"Fires at session start, after a resume rebuilds the message array, and after a compaction settles, never while a turn or dispatch is running. Local-native targets and interactive sessions only, whatever this says. Legal values: true, false · default: true.",
|
|
376
543
|
"workers.agentBindings":
|
|
377
544
|
"Bind base, custom, and shadow native agents such as scout, researcher, and provenance to profiles. ACP delegation agents cannot be bound.",
|
|
378
545
|
"delegation.defaults.toolGovernance":
|
|
@@ -408,6 +575,26 @@ const SETTINGS_VALUE_HELP_BY_ID: Partial<Record<EditableSettingId, Record<string
|
|
|
408
575
|
escalate:
|
|
409
576
|
"the ask is forwarded to this session's operator; on timeout it falls back to deny or fail per workers.escalation",
|
|
410
577
|
},
|
|
578
|
+
"workers.escalation.fallback": {
|
|
579
|
+
deny: "an unanswered escalation becomes a tool denial and the run continues",
|
|
580
|
+
fail: "an unanswered escalation ends the run as permission_required",
|
|
581
|
+
},
|
|
582
|
+
"prewarm.enabled": {
|
|
583
|
+
true: "prefill the next turn's known prefix on local-native targets",
|
|
584
|
+
false: "never send a pre-warm request; the first turn pays the whole prefill",
|
|
585
|
+
},
|
|
586
|
+
"context.workingSet.enabled": {
|
|
587
|
+
true: "evict stale observations non-destructively before summarizing",
|
|
588
|
+
false: "skip eviction and go straight to summary compaction",
|
|
589
|
+
},
|
|
590
|
+
"context.workingSet.policy": {
|
|
591
|
+
"structural-v1": "select eviction candidates by message structure",
|
|
592
|
+
"age-horizon": "the older rule: select by age alone",
|
|
593
|
+
},
|
|
594
|
+
"library.sync": {
|
|
595
|
+
true: "allow `clio-coder library sync` and `push` to reach the confirmed remote",
|
|
596
|
+
false: "refuse every library network operation",
|
|
597
|
+
},
|
|
411
598
|
"delegation.defaults.toolGovernance": {
|
|
412
599
|
"clio-policy": "Clio's safety policy gates the delegated agent's tools",
|
|
413
600
|
"agent-managed": "the external agent governs its own tools",
|
|
@@ -733,6 +920,16 @@ const NUMBER_SETTING_RULES = {
|
|
|
733
920
|
"delegation.defaults.connectTimeoutMs": { min: 1, max: MAX_TIMER_DELAY_MS, integer: true },
|
|
734
921
|
"delegation.defaults.turnTimeoutMs": { min: 1, max: MAX_TIMER_DELAY_MS, integer: true },
|
|
735
922
|
"delegation.defaults.permissionTimeoutMs": { min: 1, max: MAX_TIMER_DELAY_MS, integer: true },
|
|
923
|
+
// The escalation deadline is armed as a timer, so it shares the delegation
|
|
924
|
+
// bounds; the rest mirror the config validator's own integer bounds.
|
|
925
|
+
"workers.escalation.timeoutMs": { min: 1, max: MAX_TIMER_DELAY_MS, integer: true },
|
|
926
|
+
"workers.resilienceCooldownMs": { min: 0, integer: true },
|
|
927
|
+
"guardrails.turnToolCallBudget": { min: 1, integer: true },
|
|
928
|
+
"guardrails.workerToolCallCap": { min: 1, integer: true },
|
|
929
|
+
"guardrails.maxDispatchRuns": { min: 1, integer: true },
|
|
930
|
+
"guardrails.readMaxBytes": { min: 1, integer: true },
|
|
931
|
+
"guardrails.observationTurnBudgetBytes": { min: 1, integer: true },
|
|
932
|
+
"guardrails.internalDispatchTimeoutMs": { min: 1, integer: true },
|
|
736
933
|
} as const satisfies Partial<Record<EditableSettingId, NumberSettingRule>>;
|
|
737
934
|
|
|
738
935
|
export type NumberSettingId = keyof typeof NUMBER_SETTING_RULES;
|
|
@@ -818,6 +1015,51 @@ function editNumberSubmenu(title: string, id: NumberSettingId): SettingSubmenuBu
|
|
|
818
1015
|
};
|
|
819
1016
|
}
|
|
820
1017
|
|
|
1018
|
+
/**
|
|
1019
|
+
* The comma-separated set an activation list holds, refused in place when an
|
|
1020
|
+
* entry is not one of the legal values. Silently dropping the unknown entry
|
|
1021
|
+
* would leave the operator looking at a list they thought they had activated,
|
|
1022
|
+
* so the editor stays open and names both the entry and the vocabulary.
|
|
1023
|
+
*/
|
|
1024
|
+
function parseEnumListSetting(value: string, legal: readonly string[]): { values: string[] } | { refusal: string } {
|
|
1025
|
+
const entries = value
|
|
1026
|
+
.split(",")
|
|
1027
|
+
.map((entry) => entry.trim())
|
|
1028
|
+
.filter((entry) => entry.length > 0);
|
|
1029
|
+
const unknown = entries.find((entry) => !legal.includes(entry));
|
|
1030
|
+
if (unknown !== undefined) {
|
|
1031
|
+
return { refusal: `Not applied: '${unknown}' is not one of ${legal.join(", ")}.` };
|
|
1032
|
+
}
|
|
1033
|
+
const duplicate = entries.find((entry, index) => entries.indexOf(entry) !== index);
|
|
1034
|
+
if (duplicate !== undefined) return { refusal: `Not applied: '${duplicate}' is listed twice.` };
|
|
1035
|
+
return { values: entries };
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
function editEnumListSubmenu(title: string, legal: readonly string[]): SettingSubmenuBuilder {
|
|
1039
|
+
return (currentValue: string, done: (val?: string) => void) => {
|
|
1040
|
+
const input = new Input();
|
|
1041
|
+
input.setValue(currentValue);
|
|
1042
|
+
input.focused = true;
|
|
1043
|
+
const wrapper = new SubmenuWrapper(
|
|
1044
|
+
title,
|
|
1045
|
+
input,
|
|
1046
|
+
buildHint([{ key: "Enter", verb: "confirm" }], "back"),
|
|
1047
|
+
`Comma-separated, from ${legal.join(", ")}; blank activates none.`,
|
|
1048
|
+
);
|
|
1049
|
+
input.onSubmit = (val) => {
|
|
1050
|
+
const outcome = parseEnumListSetting(val, legal);
|
|
1051
|
+
if ("refusal" in outcome) {
|
|
1052
|
+
wrapper.setProblem(outcome.refusal);
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
wrapper.setProblem(null);
|
|
1056
|
+
done(outcome.values.join(", "));
|
|
1057
|
+
};
|
|
1058
|
+
input.onEscape = () => done();
|
|
1059
|
+
return wrapper;
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
|
|
821
1063
|
function selectListSubmenu(
|
|
822
1064
|
title: string,
|
|
823
1065
|
items: ReadonlyArray<{
|
|
@@ -1288,13 +1530,23 @@ function settingItem(
|
|
|
1288
1530
|
return item;
|
|
1289
1531
|
}
|
|
1290
1532
|
|
|
1291
|
-
|
|
1533
|
+
/**
|
|
1534
|
+
* A heading row that names the block of settings under it. The id carries the
|
|
1535
|
+
* section it belongs to, so one builder serves every section that groups its
|
|
1536
|
+
* rows rather than a near-duplicate per section.
|
|
1537
|
+
*/
|
|
1538
|
+
function groupHeader(
|
|
1539
|
+
id: GroupHeaderId,
|
|
1540
|
+
section: SettingsSectionId,
|
|
1541
|
+
label: string,
|
|
1542
|
+
description: string,
|
|
1543
|
+
): SettingsCenterItem {
|
|
1292
1544
|
return {
|
|
1293
1545
|
id,
|
|
1294
1546
|
label,
|
|
1295
1547
|
currentValue: "",
|
|
1296
|
-
description
|
|
1297
|
-
section
|
|
1548
|
+
description,
|
|
1549
|
+
section,
|
|
1298
1550
|
configPath: id,
|
|
1299
1551
|
affordance: "group heading",
|
|
1300
1552
|
scope: "live",
|
|
@@ -1304,6 +1556,14 @@ function fleetGroupHeader(id: FleetGroupHeaderId, label: string): SettingsCenter
|
|
|
1304
1556
|
};
|
|
1305
1557
|
}
|
|
1306
1558
|
|
|
1559
|
+
function fleetGroupHeader(id: FleetGroupHeaderId, label: string): SettingsCenterItem {
|
|
1560
|
+
return groupHeader(id, "fleet", label, `${label} in the Fleet workbench.`);
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
function terminalGroupHeader(id: TerminalGroupHeaderId, label: string): SettingsCenterItem {
|
|
1564
|
+
return groupHeader(id, "terminal", label, `${label} behavior in the terminal.`);
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1307
1567
|
function targetAddCta(): SettingsCenterItem {
|
|
1308
1568
|
return {
|
|
1309
1569
|
id: "targets.add-cta",
|
|
@@ -1352,6 +1612,7 @@ export function buildSettingItems(
|
|
|
1352
1612
|
const retry = settings.retry;
|
|
1353
1613
|
const terminal = settings.terminal;
|
|
1354
1614
|
const watchdog = settings.watchdog;
|
|
1615
|
+
const panes = settings.panes;
|
|
1355
1616
|
const orchestratorThinking = thinkingChoices(
|
|
1356
1617
|
options?.providers,
|
|
1357
1618
|
settings.orchestrator.target,
|
|
@@ -1394,6 +1655,15 @@ export function buildSettingItems(
|
|
|
1394
1655
|
const backgroundModelSubmenu = options?.providers
|
|
1395
1656
|
? selectModelSubmenu(options.providers, () => live().background.target ?? undefined)
|
|
1396
1657
|
: editTextSubmenu("Type memory model name");
|
|
1658
|
+
// Both are optional in the settings type, so the row falls back to the
|
|
1659
|
+
// shipped value rather than rendering a blank for a key that is in force.
|
|
1660
|
+
const escalation = settings.workers.escalation ?? SHIPPED_ESCALATION;
|
|
1661
|
+
const resilienceCooldownMs = settings.workers.resilienceCooldownMs ?? SHIPPED_RESILIENCE_COOLDOWN_MS;
|
|
1662
|
+
const workingSet = settings.context.workingSet;
|
|
1663
|
+
const guardrails = settings.guardrails;
|
|
1664
|
+
const routing = settings.routing;
|
|
1665
|
+
const library = settings.library;
|
|
1666
|
+
const activeAgentRoles = routing.agentAutomation.activeAgentRoles;
|
|
1397
1667
|
const favorites = settings.modelSelector?.favorites ?? [];
|
|
1398
1668
|
const agents = settings.delegation?.agents ?? [];
|
|
1399
1669
|
const keybindingCount = Object.keys(settings.keybindings ?? {}).length;
|
|
@@ -1404,6 +1674,13 @@ export function buildSettingItems(
|
|
|
1404
1674
|
settingItem("workers.onPermission", settings.workers.onPermission ?? "deny", {
|
|
1405
1675
|
values: ["deny", "fail", "escalate"],
|
|
1406
1676
|
}),
|
|
1677
|
+
settingItem("workers.escalation.timeoutMs", String(escalation.timeoutMs), {
|
|
1678
|
+
submenu: editNumberSubmenu("Edit escalation timeout (ms)", "workers.escalation.timeoutMs"),
|
|
1679
|
+
affordance: "free text",
|
|
1680
|
+
}),
|
|
1681
|
+
settingItem("workers.escalation.fallback", escalation.fallback, {
|
|
1682
|
+
values: ["deny", "fail"],
|
|
1683
|
+
}),
|
|
1407
1684
|
settingItem("delegation.defaults.toolGovernance", settings.delegation.defaults.toolGovernance, {
|
|
1408
1685
|
values: ["clio-policy", "agent-managed", "deny-all"],
|
|
1409
1686
|
}),
|
|
@@ -1451,6 +1728,9 @@ export function buildSettingItems(
|
|
|
1451
1728
|
settingItem("memory.intervention.timeoutMs", String(settings.memory.intervention.timeoutMs), {
|
|
1452
1729
|
values: ["5000", "10000", "20000", "30000", "60000"],
|
|
1453
1730
|
}),
|
|
1731
|
+
settingItem("prewarm.enabled", String(settings.prewarm.enabled), {
|
|
1732
|
+
values: ["true", "false"],
|
|
1733
|
+
}),
|
|
1454
1734
|
fleetGroupHeader("fleet.group.defaults", "Defaults"),
|
|
1455
1735
|
settingItem("workers.default.target", settings.workers.default.target ?? "(unset)", {
|
|
1456
1736
|
submenu: targetSubmenu,
|
|
@@ -1466,6 +1746,10 @@ export function buildSettingItems(
|
|
|
1466
1746
|
settingItem("workers.maxRetries", String(settings.workers.maxRetries), {
|
|
1467
1747
|
values: ["0", "1", "2", "3", "5", "8"],
|
|
1468
1748
|
}),
|
|
1749
|
+
settingItem("workers.resilienceCooldownMs", String(resilienceCooldownMs), {
|
|
1750
|
+
submenu: editNumberSubmenu("Edit resilience cooldown (ms)", "workers.resilienceCooldownMs"),
|
|
1751
|
+
affordance: "free text",
|
|
1752
|
+
}),
|
|
1469
1753
|
fleetGroupHeader("fleet.group.profiles", "Profiles"),
|
|
1470
1754
|
...fleetProfileRows(settings, live, options),
|
|
1471
1755
|
settingItem("workers.profiles", "", {
|
|
@@ -1484,9 +1768,35 @@ export function buildSettingItems(
|
|
|
1484
1768
|
presentationKind: profileCount > 0 ? "action" : "read-only-fact",
|
|
1485
1769
|
valueSegments: [],
|
|
1486
1770
|
}),
|
|
1771
|
+
fleetGroupHeader("fleet.group.route-activation", "Route activation"),
|
|
1772
|
+
settingItem("routing.activeRoles", routing.activeRoles.length > 0 ? routing.activeRoles.join(", ") : "(none)", {
|
|
1773
|
+
submenu: editEnumListSubmenu("Edit active routing roles", ACTIVE_ROUTING_ROLES),
|
|
1774
|
+
affordance: `free text from ${ACTIVE_ROUTING_ROLES.join(", ")}`,
|
|
1775
|
+
editValue: routing.activeRoles.join(", "),
|
|
1776
|
+
}),
|
|
1777
|
+
settingItem(
|
|
1778
|
+
"routing.activePostures",
|
|
1779
|
+
routing.activePostures.length > 0 ? routing.activePostures.join(", ") : "(none)",
|
|
1780
|
+
{
|
|
1781
|
+
submenu: editEnumListSubmenu("Edit active routing postures", ACTIVE_ROUTING_POSTURES),
|
|
1782
|
+
affordance: `free text from ${ACTIVE_ROUTING_POSTURES.join(", ")}`,
|
|
1783
|
+
editValue: routing.activePostures.join(", "),
|
|
1784
|
+
},
|
|
1785
|
+
),
|
|
1786
|
+
settingItem(
|
|
1787
|
+
"routing.agentAutomation.activeAgentRoles",
|
|
1788
|
+
activeAgentRoles.length > 0
|
|
1789
|
+
? activeAgentRoles.map((pair) => `${pair.agentId}/${pair.executionRole}`).join(", ")
|
|
1790
|
+
: "(none)",
|
|
1791
|
+
{ affordance: "edit settings.yaml", readOnly: true },
|
|
1792
|
+
),
|
|
1487
1793
|
fleetGroupHeader("fleet.group.placement", "Placement"),
|
|
1488
1794
|
...fleetNodeRows(options?.getFleetNodes?.() ?? []),
|
|
1489
1795
|
...fleetEndpointRows(options?.providers),
|
|
1796
|
+
fleetGroupHeader("fleet.group.panes", "Panes"),
|
|
1797
|
+
settingItem("panes.enabled", panes.enabled, { values: ["auto", "embedded", "off"] }),
|
|
1798
|
+
settingItem("panes.notifications", panes.notifications, { values: ["failures", "all", "off"] }),
|
|
1799
|
+
settingItem("panes.journal", String(panes.journal), { values: ["true", "false"] }),
|
|
1490
1800
|
settingItem("targets", "", {
|
|
1491
1801
|
description: "Live inference target inventory and routing roles.",
|
|
1492
1802
|
affordance: "column heading",
|
|
@@ -1517,6 +1827,36 @@ export function buildSettingItems(
|
|
|
1517
1827
|
settingItem("budget.concurrency", String(settings.budget.concurrency), {
|
|
1518
1828
|
values: ["auto", "1", "2", "4", "8"],
|
|
1519
1829
|
}),
|
|
1830
|
+
groupHeader(
|
|
1831
|
+
"budget.group.guardrails",
|
|
1832
|
+
"budget",
|
|
1833
|
+
"Guardrails",
|
|
1834
|
+
"Numeric backstops that bound runaway agent behavior.",
|
|
1835
|
+
),
|
|
1836
|
+
settingItem("guardrails.turnToolCallBudget", String(guardrails.turnToolCallBudget), {
|
|
1837
|
+
submenu: editNumberSubmenu("Edit turn tool-call budget", "guardrails.turnToolCallBudget"),
|
|
1838
|
+
affordance: "free text",
|
|
1839
|
+
}),
|
|
1840
|
+
settingItem("guardrails.workerToolCallCap", String(guardrails.workerToolCallCap), {
|
|
1841
|
+
submenu: editNumberSubmenu("Edit worker tool-call cap", "guardrails.workerToolCallCap"),
|
|
1842
|
+
affordance: "free text",
|
|
1843
|
+
}),
|
|
1844
|
+
settingItem("guardrails.maxDispatchRuns", String(guardrails.maxDispatchRuns), {
|
|
1845
|
+
submenu: editNumberSubmenu("Edit run ledger retention", "guardrails.maxDispatchRuns"),
|
|
1846
|
+
affordance: "free text",
|
|
1847
|
+
}),
|
|
1848
|
+
settingItem("guardrails.readMaxBytes", String(guardrails.readMaxBytes), {
|
|
1849
|
+
submenu: editNumberSubmenu("Edit read byte cap", "guardrails.readMaxBytes"),
|
|
1850
|
+
affordance: "free text",
|
|
1851
|
+
}),
|
|
1852
|
+
settingItem("guardrails.observationTurnBudgetBytes", String(guardrails.observationTurnBudgetBytes), {
|
|
1853
|
+
submenu: editNumberSubmenu("Edit observation byte pool", "guardrails.observationTurnBudgetBytes"),
|
|
1854
|
+
affordance: "free text",
|
|
1855
|
+
}),
|
|
1856
|
+
settingItem("guardrails.internalDispatchTimeoutMs", String(guardrails.internalDispatchTimeoutMs), {
|
|
1857
|
+
submenu: editNumberSubmenu("Edit internal dispatch timeout (ms)", "guardrails.internalDispatchTimeoutMs"),
|
|
1858
|
+
affordance: "free text",
|
|
1859
|
+
}),
|
|
1520
1860
|
settingItem("compaction.auto", String(compaction.auto), {
|
|
1521
1861
|
values: ["true", "false"],
|
|
1522
1862
|
}),
|
|
@@ -1526,6 +1866,27 @@ export function buildSettingItems(
|
|
|
1526
1866
|
settingItem("compaction.excludeLastTurns", String(compaction.excludeLastTurns), {
|
|
1527
1867
|
values: ["3", "6", "10", "15"],
|
|
1528
1868
|
}),
|
|
1869
|
+
groupHeader(
|
|
1870
|
+
"compaction.group.working-set",
|
|
1871
|
+
"compaction",
|
|
1872
|
+
"Working set",
|
|
1873
|
+
"The non-destructive eviction layer that runs before a summary is needed.",
|
|
1874
|
+
),
|
|
1875
|
+
settingItem("context.workingSet.enabled", String(workingSet.enabled), {
|
|
1876
|
+
values: ["true", "false"],
|
|
1877
|
+
}),
|
|
1878
|
+
settingItem("context.workingSet.policy", workingSet.policy, {
|
|
1879
|
+
values: ["structural-v1", "age-horizon"],
|
|
1880
|
+
}),
|
|
1881
|
+
settingItem("context.workingSet.target", formatThreshold(workingSet.target, "0.6"), {
|
|
1882
|
+
values: ["0.4", "0.5", "0.6", "0.7"],
|
|
1883
|
+
}),
|
|
1884
|
+
settingItem("context.workingSet.protectLastTurns", String(workingSet.protectLastTurns), {
|
|
1885
|
+
values: ["3", "6", "10", "15"],
|
|
1886
|
+
}),
|
|
1887
|
+
settingItem("context.workingSet.minEvictableTokens", String(workingSet.minEvictableTokens), {
|
|
1888
|
+
values: ["0", "100", "200", "500", "1000"],
|
|
1889
|
+
}),
|
|
1529
1890
|
settingItem("retry.enabled", String(retry.enabled), {
|
|
1530
1891
|
values: ["true", "false"],
|
|
1531
1892
|
}),
|
|
@@ -1538,6 +1899,9 @@ export function buildSettingItems(
|
|
|
1538
1899
|
settingItem("retry.maxDelayMs", String(retry.maxDelayMs), {
|
|
1539
1900
|
values: ["10000", "30000", "60000", "120000", "300000"],
|
|
1540
1901
|
}),
|
|
1902
|
+
settingItem("retry.streamStallMs", String(retry.streamStallMs), {
|
|
1903
|
+
values: ["60000", "120000", "180000", "300000", "600000"],
|
|
1904
|
+
}),
|
|
1541
1905
|
settingItem("terminal.showTerminalProgress", String(terminal.showTerminalProgress), {
|
|
1542
1906
|
values: ["false", "true"],
|
|
1543
1907
|
}),
|
|
@@ -1560,6 +1924,11 @@ export function buildSettingItems(
|
|
|
1560
1924
|
affordance: "single clio-coder palette",
|
|
1561
1925
|
readOnly: true,
|
|
1562
1926
|
}),
|
|
1927
|
+
terminalGroupHeader("terminal.group.files-pane", "Files pane"),
|
|
1928
|
+
settingItem("panes.yazi.enabled", String(panes.yazi.enabled), { values: ["true", "false"] }),
|
|
1929
|
+
settingItem("panes.yazi.mode", panes.yazi.mode, { values: ["companion", "chooser"] }),
|
|
1930
|
+
settingItem("panes.yazi.profile", panes.yazi.profile, { values: ["managed", "user"] }),
|
|
1931
|
+
settingItem("panes.yazi.followCwd", String(panes.yazi.followCwd), { values: ["true", "false"] }),
|
|
1563
1932
|
settingItem("watchdog.enabled", String(watchdog.enabled), {
|
|
1564
1933
|
values: ["false", "true"],
|
|
1565
1934
|
}),
|
|
@@ -1617,6 +1986,31 @@ export function buildSettingItems(
|
|
|
1617
1986
|
settingItem("delegation.agents", agents.length > 0 ? `${agents.length} agent(s)` : "(none)", {
|
|
1618
1987
|
...delegationAgentsAffordance(agents, options?.getInteropProposals?.() ?? []),
|
|
1619
1988
|
}),
|
|
1989
|
+
groupHeader(
|
|
1990
|
+
"advanced.group.library",
|
|
1991
|
+
"advanced",
|
|
1992
|
+
"Library",
|
|
1993
|
+
"The private resource catalog and the remote it may sync with.",
|
|
1994
|
+
),
|
|
1995
|
+
settingItem("library.catalog", library.catalog ?? "(config directory)", {
|
|
1996
|
+
submenu: editTextSubmenu("Edit library catalog path; blank uses the config directory"),
|
|
1997
|
+
affordance: "free text",
|
|
1998
|
+
editValue: library.catalog ?? "",
|
|
1999
|
+
}),
|
|
2000
|
+
settingItem("library.remote", library.remote ?? "(local only)", {
|
|
2001
|
+
submenu: editTextSubmenu("Edit library remote URL; blank keeps the library local"),
|
|
2002
|
+
affordance: "free text",
|
|
2003
|
+
editValue: library.remote ?? "",
|
|
2004
|
+
}),
|
|
2005
|
+
// Confirming a remote from the settings row would be the trust record
|
|
2006
|
+
// confirming itself, so this row reports what the confirm flow wrote.
|
|
2007
|
+
settingItem("library.confirmedRemote", library.confirmedRemote ?? "(unconfirmed)", {
|
|
2008
|
+
affordance: "set by `clio-coder library` on confirmation",
|
|
2009
|
+
readOnly: true,
|
|
2010
|
+
}),
|
|
2011
|
+
settingItem("library.sync", String(library.sync), {
|
|
2012
|
+
values: ["true", "false"],
|
|
2013
|
+
}),
|
|
1620
2014
|
];
|
|
1621
2015
|
}
|
|
1622
2016
|
|
|
@@ -1935,8 +2329,8 @@ function refreshSettingItemsInPlace(items: SettingsCenterItem[], next: readonly
|
|
|
1935
2329
|
}
|
|
1936
2330
|
}
|
|
1937
2331
|
|
|
1938
|
-
function formatThreshold(value: number): string {
|
|
1939
|
-
return Number.isFinite(value) ? String(value) :
|
|
2332
|
+
function formatThreshold(value: number, fallback = "0.8"): string {
|
|
2333
|
+
return Number.isFinite(value) ? String(value) : fallback;
|
|
1940
2334
|
}
|
|
1941
2335
|
|
|
1942
2336
|
function applyNonNegativeInteger(value: string, set: (next: number) => void): void {
|
|
@@ -2024,6 +2418,27 @@ export function applySettingChange(settings: ClioSettings, id: string, value: st
|
|
|
2024
2418
|
settings.workers.maxRetries = next;
|
|
2025
2419
|
});
|
|
2026
2420
|
return;
|
|
2421
|
+
case "panes.enabled":
|
|
2422
|
+
if (value === "auto" || value === "embedded" || value === "off") settings.panes.enabled = value;
|
|
2423
|
+
return;
|
|
2424
|
+
case "panes.notifications":
|
|
2425
|
+
if (value === "failures" || value === "all" || value === "off") settings.panes.notifications = value;
|
|
2426
|
+
return;
|
|
2427
|
+
case "panes.journal":
|
|
2428
|
+
if (value === "true" || value === "false") settings.panes.journal = value === "true";
|
|
2429
|
+
return;
|
|
2430
|
+
case "panes.yazi.enabled":
|
|
2431
|
+
if (value === "true" || value === "false") settings.panes.yazi.enabled = value === "true";
|
|
2432
|
+
return;
|
|
2433
|
+
case "panes.yazi.mode":
|
|
2434
|
+
if (value === "companion" || value === "chooser") settings.panes.yazi.mode = value;
|
|
2435
|
+
return;
|
|
2436
|
+
case "panes.yazi.profile":
|
|
2437
|
+
if (value === "managed" || value === "user") settings.panes.yazi.profile = value;
|
|
2438
|
+
return;
|
|
2439
|
+
case "panes.yazi.followCwd":
|
|
2440
|
+
if (value === "true" || value === "false") settings.panes.yazi.followCwd = value === "true";
|
|
2441
|
+
return;
|
|
2027
2442
|
case "modelSelector.recentLimit":
|
|
2028
2443
|
applyNonNegativeInteger(value, (next) => {
|
|
2029
2444
|
if (next >= 1) settings.modelSelector.recentLimit = next;
|
|
@@ -2200,6 +2615,83 @@ export function applySettingChange(settings: ClioSettings, id: string, value: st
|
|
|
2200
2615
|
if (next !== null) settings.budget.sessionCeilingUsd = next;
|
|
2201
2616
|
});
|
|
2202
2617
|
return;
|
|
2618
|
+
case "workers.escalation.timeoutMs":
|
|
2619
|
+
applyNumberSetting("workers.escalation.timeoutMs", value, (next) => {
|
|
2620
|
+
if (next === null) return;
|
|
2621
|
+
settings.workers.escalation = { ...(settings.workers.escalation ?? SHIPPED_ESCALATION), timeoutMs: next };
|
|
2622
|
+
});
|
|
2623
|
+
return;
|
|
2624
|
+
case "workers.escalation.fallback": {
|
|
2625
|
+
if (value !== "deny" && value !== "fail") return;
|
|
2626
|
+
settings.workers.escalation = { ...(settings.workers.escalation ?? SHIPPED_ESCALATION), fallback: value };
|
|
2627
|
+
return;
|
|
2628
|
+
}
|
|
2629
|
+
case "workers.resilienceCooldownMs":
|
|
2630
|
+
applyNumberSetting("workers.resilienceCooldownMs", value, (next) => {
|
|
2631
|
+
if (next !== null) settings.workers.resilienceCooldownMs = next;
|
|
2632
|
+
});
|
|
2633
|
+
return;
|
|
2634
|
+
case "routing.activeRoles": {
|
|
2635
|
+
const outcome = parseEnumListSetting(value, ACTIVE_ROUTING_ROLES);
|
|
2636
|
+
if ("values" in outcome) settings.routing.activeRoles = outcome.values as ActiveRoutingRole[];
|
|
2637
|
+
return;
|
|
2638
|
+
}
|
|
2639
|
+
case "routing.activePostures": {
|
|
2640
|
+
const outcome = parseEnumListSetting(value, ACTIVE_ROUTING_POSTURES);
|
|
2641
|
+
if ("values" in outcome) settings.routing.activePostures = outcome.values as ActiveRoutingPosture[];
|
|
2642
|
+
return;
|
|
2643
|
+
}
|
|
2644
|
+
case "prewarm.enabled":
|
|
2645
|
+
if (value === "true" || value === "false") settings.prewarm.enabled = value === "true";
|
|
2646
|
+
return;
|
|
2647
|
+
case "guardrails.turnToolCallBudget":
|
|
2648
|
+
case "guardrails.workerToolCallCap":
|
|
2649
|
+
case "guardrails.maxDispatchRuns":
|
|
2650
|
+
case "guardrails.readMaxBytes":
|
|
2651
|
+
case "guardrails.observationTurnBudgetBytes":
|
|
2652
|
+
case "guardrails.internalDispatchTimeoutMs":
|
|
2653
|
+
applyNumberSetting(id, value, (next) => {
|
|
2654
|
+
if (next !== null) settings.guardrails[id.slice("guardrails.".length) as keyof GuardrailValues] = next;
|
|
2655
|
+
});
|
|
2656
|
+
return;
|
|
2657
|
+
case "context.workingSet.enabled":
|
|
2658
|
+
if (value === "true" || value === "false") settings.context.workingSet.enabled = value === "true";
|
|
2659
|
+
return;
|
|
2660
|
+
case "context.workingSet.policy":
|
|
2661
|
+
if (value === "structural-v1" || value === "age-horizon") settings.context.workingSet.policy = value;
|
|
2662
|
+
return;
|
|
2663
|
+
case "context.workingSet.target": {
|
|
2664
|
+
// The validator's bound is exclusive at both ends, so an eviction target
|
|
2665
|
+
// of 0 or 1 is refused here rather than written and rejected at boot.
|
|
2666
|
+
const parsed = Number(value);
|
|
2667
|
+
if (Number.isFinite(parsed) && parsed > 0 && parsed < 1) settings.context.workingSet.target = parsed;
|
|
2668
|
+
return;
|
|
2669
|
+
}
|
|
2670
|
+
case "context.workingSet.protectLastTurns":
|
|
2671
|
+
applyNonNegativeInteger(value, (next) => {
|
|
2672
|
+
if (next >= 1) settings.context.workingSet.protectLastTurns = next;
|
|
2673
|
+
});
|
|
2674
|
+
return;
|
|
2675
|
+
case "context.workingSet.minEvictableTokens":
|
|
2676
|
+
applyNonNegativeInteger(value, (next) => {
|
|
2677
|
+
settings.context.workingSet.minEvictableTokens = next;
|
|
2678
|
+
});
|
|
2679
|
+
return;
|
|
2680
|
+
case "retry.streamStallMs":
|
|
2681
|
+
applyNonNegativeInteger(value, (next) => {
|
|
2682
|
+
settings.retry.streamStallMs = next;
|
|
2683
|
+
});
|
|
2684
|
+
return;
|
|
2685
|
+
case "library.catalog":
|
|
2686
|
+
case "library.remote": {
|
|
2687
|
+
const key = id.slice("library.".length) as "catalog" | "remote";
|
|
2688
|
+
const trimmed = value.trim();
|
|
2689
|
+
settings.library[key] = trimmed.length > 0 ? trimmed : null;
|
|
2690
|
+
return;
|
|
2691
|
+
}
|
|
2692
|
+
case "library.sync":
|
|
2693
|
+
if (value === "true" || value === "false") settings.library.sync = value === "true";
|
|
2694
|
+
return;
|
|
2203
2695
|
}
|
|
2204
2696
|
}
|
|
2205
2697
|
|
|
@@ -3280,7 +3772,7 @@ export class SettingsCenter implements Component {
|
|
|
3280
3772
|
if (this.sections().length === 0) return [...head, ...this.emptyFilterLines(width, available)];
|
|
3281
3773
|
// A detail page owns the work area, and the footer describes the row the
|
|
3282
3774
|
// operator has already left, so it is suppressed while a submenu is open.
|
|
3283
|
-
const footer = this.submenuComponent ? [] : this.renderFooter(width, this.footerBudget(available));
|
|
3775
|
+
const footer = this.submenuComponent ? [] : this.renderFooter(width, this.footerBudget(available, width));
|
|
3284
3776
|
const contentHeight = Math.max(1, available - footer.length);
|
|
3285
3777
|
const leftWidth = Math.min(SECTION_LANE_WIDTH, Math.max(16, Math.floor(width * 0.28)));
|
|
3286
3778
|
const separator = barSep(clioTheme());
|
|
@@ -3300,9 +3792,16 @@ export class SettingsCenter implements Component {
|
|
|
3300
3792
|
* The footer is help, and the list is the work. A fixed six-line ceiling spent
|
|
3301
3793
|
* a third of a 20-row body on prose, so the budget is what the body can spare
|
|
3302
3794
|
* once the list keeps six rows.
|
|
3795
|
+
*
|
|
3796
|
+
* The ceiling follows the scope note, which wraps rather than cuts: at 90
|
|
3797
|
+
* columns that note needs two rows, and the flat four-line ceiling then paid
|
|
3798
|
+
* for the second row out of the explanation above it. The note buys its own
|
|
3799
|
+
* rows instead. A note that fits on one line leaves the ceiling at four, so
|
|
3800
|
+
* every width above the wrap point renders exactly as it did.
|
|
3303
3801
|
*/
|
|
3304
|
-
private footerBudget(bodyHeight: number): number {
|
|
3305
|
-
|
|
3802
|
+
private footerBudget(bodyHeight: number, width: number): number {
|
|
3803
|
+
const noteLines = wrapTextWithAnsi(this.footerNoteText(), Math.max(1, width)).length;
|
|
3804
|
+
return Math.min(2 + noteLines + 1, Math.max(0, bodyHeight - 6));
|
|
3306
3805
|
}
|
|
3307
3806
|
|
|
3308
3807
|
private renderSectionLane(width: number, height: number): string[] {
|
|
@@ -3468,15 +3967,27 @@ export class SettingsCenter implements Component {
|
|
|
3468
3967
|
const query = this.filterQuery.trim().length > 0 ? ` ${theme.fg("accent", `/${this.filterQuery}`)}` : "";
|
|
3469
3968
|
const positionText = `${theme.fg("dim", `section ${position}/${sections.length}`)}${query}`;
|
|
3470
3969
|
|
|
3970
|
+
// The note is prose the operator acts on ("choose session, global, or
|
|
3971
|
+
// cancel"), so it wraps under the same rule as the description above it. A
|
|
3972
|
+
// truncated instruction is the one line in this footer that cannot afford
|
|
3973
|
+
// to be a fragment.
|
|
3974
|
+
const noteLines = (text: string, tone: "dim" | "muted"): string[] =>
|
|
3975
|
+
wrapTextWithAnsi(theme.fg(tone, text), safeWidth);
|
|
3976
|
+
|
|
3471
3977
|
if (this.level === "sections") {
|
|
3472
3978
|
const breadcrumb = `${screenTitle(theme, section.label)} ${theme.fg("dim", "·")} ${positionText}`;
|
|
3473
3979
|
const body = wrapTextWithAnsi(theme.fg("muted", SETTINGS_SECTION_DESCRIPTIONS[section.id]), safeWidth);
|
|
3474
|
-
|
|
3475
|
-
|
|
3980
|
+
return this.assembleFooter(
|
|
3981
|
+
[separator, breadcrumb],
|
|
3982
|
+
body,
|
|
3983
|
+
noteLines(this.footerNoteText(), "dim"),
|
|
3984
|
+
maxFooterLines,
|
|
3985
|
+
safeWidth,
|
|
3986
|
+
);
|
|
3476
3987
|
}
|
|
3477
3988
|
|
|
3478
3989
|
if (!item) {
|
|
3479
|
-
return this.assembleFooter([separator], [],
|
|
3990
|
+
return this.assembleFooter([separator], [], noteLines(this.footerNoteText(), "muted"), maxFooterLines, safeWidth);
|
|
3480
3991
|
}
|
|
3481
3992
|
|
|
3482
3993
|
const breadcrumb = `${screenTitle(theme, section.label)} ${theme.fg("dim", "›")} ${theme.style("accent", item.label, { bold: true })} ${theme.fg("dim", "·")} ${positionText}`;
|
|
@@ -3485,8 +3996,27 @@ export class SettingsCenter implements Component {
|
|
|
3485
3996
|
if (item.help) contentLines.push(...wrapTextWithAnsi(theme.fg("dim", item.help), safeWidth));
|
|
3486
3997
|
const detail = this.footerDetail(item, theme);
|
|
3487
3998
|
if (detail) contentLines.push(...wrapTextWithAnsi(detail, safeWidth));
|
|
3488
|
-
|
|
3489
|
-
|
|
3999
|
+
return this.assembleFooter(
|
|
4000
|
+
[separator, breadcrumb],
|
|
4001
|
+
contentLines,
|
|
4002
|
+
noteLines(this.footerScopeNote(item), "dim"),
|
|
4003
|
+
maxFooterLines,
|
|
4004
|
+
safeWidth,
|
|
4005
|
+
);
|
|
4006
|
+
}
|
|
4007
|
+
|
|
4008
|
+
/**
|
|
4009
|
+
* The note text renderFooter will show, without theming. `footerBudget` needs
|
|
4010
|
+
* its wrapped height before the footer is rendered, so both read it here and
|
|
4011
|
+
* the ceiling can never disagree with what lands.
|
|
4012
|
+
*/
|
|
4013
|
+
private footerNoteText(): string {
|
|
4014
|
+
const section = this.currentSection();
|
|
4015
|
+
if (!section) return "";
|
|
4016
|
+
if (this.level === "sections") return "Tab or → to edit its settings";
|
|
4017
|
+
const item = this.selectedItem();
|
|
4018
|
+
if (!item) return "No setting selected.";
|
|
4019
|
+
return this.footerScopeNote(item);
|
|
3490
4020
|
}
|
|
3491
4021
|
|
|
3492
4022
|
private footerDetail(item: SettingsCenterItem, theme: ReturnType<typeof clioTheme>): string {
|
|
@@ -3523,7 +4053,7 @@ export class SettingsCenter implements Component {
|
|
|
3523
4053
|
private assembleFooter(
|
|
3524
4054
|
top: readonly string[],
|
|
3525
4055
|
middle: readonly string[],
|
|
3526
|
-
note: string,
|
|
4056
|
+
note: readonly string[],
|
|
3527
4057
|
maxFooterLines: number,
|
|
3528
4058
|
width: number,
|
|
3529
4059
|
): string[] {
|
|
@@ -3532,7 +4062,11 @@ export class SettingsCenter implements Component {
|
|
|
3532
4062
|
if (maxFooterLines <= top.length) {
|
|
3533
4063
|
out = top.slice(0, maxFooterLines).map(fit);
|
|
3534
4064
|
} else {
|
|
3535
|
-
|
|
4065
|
+
// The note owns the rows it wrapped to, up to whatever is left under the
|
|
4066
|
+
// breadcrumb; the explanation fills the rest. Dropping a wrapped note
|
|
4067
|
+
// line loses less than cutting the sentence mid-word did.
|
|
4068
|
+
const noteKept = note.slice(0, Math.max(1, maxFooterLines - top.length));
|
|
4069
|
+
const middleBudget = Math.max(0, maxFooterLines - top.length - noteKept.length);
|
|
3536
4070
|
// The explanation is wrapped, so a short terminal drops whole lines off
|
|
3537
4071
|
// its end rather than cutting one. At 40 columns the autonomy help
|
|
3538
4072
|
// stopped at "read-only observes; suggest" and read as the whole
|
|
@@ -3541,7 +4075,7 @@ export class SettingsCenter implements Component {
|
|
|
3541
4075
|
const last = kept.at(-1);
|
|
3542
4076
|
const marked =
|
|
3543
4077
|
middle.length > kept.length && last !== undefined ? [...kept.slice(0, -1), `${last}${ELLIPSIS}`] : kept;
|
|
3544
|
-
out = [...top.map(fit), ...marked.map(fit), fit
|
|
4078
|
+
out = [...top.map(fit), ...marked.map(fit), ...noteKept.map(fit)];
|
|
3545
4079
|
}
|
|
3546
4080
|
while (out.length < maxFooterLines) out.push("");
|
|
3547
4081
|
return out.slice(0, maxFooterLines);
|
|
@@ -3651,6 +4185,7 @@ export function openSettingsOverlay(tui: TUI, deps: OpenSettingsOverlayDeps): Se
|
|
|
3651
4185
|
margin.right = side;
|
|
3652
4186
|
return true;
|
|
3653
4187
|
},
|
|
4188
|
+
markerId: "settings",
|
|
3654
4189
|
title: "Settings",
|
|
3655
4190
|
footerHint: (innerWidth) =>
|
|
3656
4191
|
innerWidth < WIDE_LAYOUT_MIN_WIDTH
|