@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
|
@@ -36,6 +36,7 @@ interface WorkerEscalationEntry {
|
|
|
36
36
|
axis: ApprovalRequestView["axis"];
|
|
37
37
|
reason: string;
|
|
38
38
|
target?: string;
|
|
39
|
+
fallback: "deny" | "fail";
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
export interface OverlayPermissionLifecycleDeps {
|
|
@@ -190,6 +191,7 @@ function workerEscalationEntry(payload: PermissionRequestedPayload, autonomy: st
|
|
|
190
191
|
...(typeof payload.target === "string" && payload.target.length > 0
|
|
191
192
|
? { target: sanitizeCallTargetText(payload.target).slice(0, 200) }
|
|
192
193
|
: {}),
|
|
194
|
+
fallback: payload.fallback === "fail" ? "fail" : "deny",
|
|
193
195
|
};
|
|
194
196
|
}
|
|
195
197
|
|
|
@@ -207,42 +209,87 @@ function workerApprovalRequestView(entry: WorkerEscalationEntry): ApprovalReques
|
|
|
207
209
|
|
|
208
210
|
export function createOverlayPermissionLifecycle(deps: OverlayPermissionLifecycleDeps): OverlayPermissionLifecycle {
|
|
209
211
|
let pendingPermission: { call: ClassifierCall; decision: SafetyDecision; meta?: PermissionRequiredMeta } | null = null;
|
|
210
|
-
let pendingWorker:
|
|
212
|
+
let pendingWorker: WorkerEscalationEntry | null = null;
|
|
211
213
|
const workerQueue: WorkerEscalationEntry[] = [];
|
|
212
214
|
const announcedRequestIds = new Set<string>();
|
|
213
215
|
/** Worker escalations already surfaced, so one request parks the operator once. */
|
|
214
216
|
const announcedWorkerRequestIds = new Set<string>();
|
|
217
|
+
/** Expiry notices already printed, including a decision that lost the terminal-state race. */
|
|
218
|
+
const expiredWorkerRequestIds = new Set<string>();
|
|
215
219
|
let confirmed = false;
|
|
216
220
|
let stopping = false;
|
|
221
|
+
let withdrawingWorker = false;
|
|
217
222
|
|
|
218
|
-
const openWorker = (entry: WorkerEscalationEntry):
|
|
219
|
-
if (deps.
|
|
220
|
-
|
|
221
|
-
pendingWorker = { runId: entry.runId, requestId: entry.requestId, agentId: entry.agentId };
|
|
223
|
+
const openWorker = (entry: WorkerEscalationEntry): boolean => {
|
|
224
|
+
if (!deps.openPermissionOverlay(workerApprovalRequestView(entry))) return false;
|
|
225
|
+
pendingWorker = entry;
|
|
222
226
|
pendingPermission = null;
|
|
223
227
|
confirmed = false;
|
|
228
|
+
return true;
|
|
224
229
|
};
|
|
225
230
|
const maybeOpenWorker = (): void => {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
if (next) openWorker(next);
|
|
231
|
+
const next = workerQueue[0];
|
|
232
|
+
if (next && openWorker(next)) workerQueue.shift();
|
|
229
233
|
};
|
|
230
234
|
const retryPending = (): void => {
|
|
231
235
|
maybeOpenWorker();
|
|
232
|
-
if (deps.getOverlayState()
|
|
236
|
+
if (deps.getOverlayState() !== "permission-confirm" && deps.toolRegistry?.hasParkedCalls()) {
|
|
233
237
|
deps.toolRegistry.renotifyHead();
|
|
234
238
|
}
|
|
235
239
|
};
|
|
240
|
+
const announceWorkerExpiry = (
|
|
241
|
+
entry: WorkerEscalationEntry,
|
|
242
|
+
fallback: "deny" | "fail",
|
|
243
|
+
cause: "timeout" | "terminal" | "late-answer",
|
|
244
|
+
): void => {
|
|
245
|
+
if (!markPermissionRequestSurfaced(expiredWorkerRequestIds, entry.requestId)) return;
|
|
246
|
+
const why =
|
|
247
|
+
cause === "timeout"
|
|
248
|
+
? "expired after its escalation timeout"
|
|
249
|
+
: cause === "terminal"
|
|
250
|
+
? "expired when its run ended"
|
|
251
|
+
: "expired before the operator decision arrived";
|
|
252
|
+
deps.appendNotice(
|
|
253
|
+
"warn",
|
|
254
|
+
`Worker approval request ${entry.requestId} for ${entry.agentId} (${entry.runId}) ${why}; fallback ${fallback} applied.`,
|
|
255
|
+
);
|
|
256
|
+
};
|
|
257
|
+
const removeQueuedWorkers = (matches: (entry: WorkerEscalationEntry) => boolean): WorkerEscalationEntry[] => {
|
|
258
|
+
const removed: WorkerEscalationEntry[] = [];
|
|
259
|
+
for (let index = workerQueue.length - 1; index >= 0; index -= 1) {
|
|
260
|
+
const entry = workerQueue[index];
|
|
261
|
+
if (entry === undefined || !matches(entry)) continue;
|
|
262
|
+
removed.unshift(entry);
|
|
263
|
+
workerQueue.splice(index, 1);
|
|
264
|
+
}
|
|
265
|
+
return removed;
|
|
266
|
+
};
|
|
267
|
+
const withdrawWorkers = (
|
|
268
|
+
matches: (entry: WorkerEscalationEntry) => boolean,
|
|
269
|
+
cause: "timeout" | "terminal",
|
|
270
|
+
fallback?: "deny" | "fail",
|
|
271
|
+
): void => {
|
|
272
|
+
const active = pendingWorker !== null && matches(pendingWorker) ? pendingWorker : null;
|
|
273
|
+
const expired = [...(active === null ? [] : [active]), ...removeQueuedWorkers(matches)];
|
|
274
|
+
if (expired.length === 0) return;
|
|
275
|
+
if (active !== null) {
|
|
276
|
+
pendingWorker = null;
|
|
277
|
+
confirmed = false;
|
|
278
|
+
withdrawingWorker = true;
|
|
279
|
+
deps.closeOverlay();
|
|
280
|
+
}
|
|
281
|
+
for (const entry of expired) announceWorkerExpiry(entry, fallback ?? entry.fallback, cause);
|
|
282
|
+
deps.requestRender();
|
|
283
|
+
};
|
|
236
284
|
|
|
237
285
|
const unsubscribePermission =
|
|
238
286
|
deps.toolRegistry?.onPermissionRequired((call, decision, meta) => {
|
|
239
287
|
const autonomy = deps.getAutonomy();
|
|
240
288
|
const view = mainApprovalRequestView(call, decision, meta, autonomy, deps.toolRegistry?.parkedCount());
|
|
241
|
-
// The dialog states the tool,
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
//
|
|
245
|
-
// screen), which is the case where it is the operator's only signal.
|
|
289
|
+
// The dialog states the tool, target, action class, asking axis, and
|
|
290
|
+
// decision keys. Another modal is interrupted so this prompt can take
|
|
291
|
+
// focus. The notice remains for a second queued approval or a frame that
|
|
292
|
+
// could not mount, when it is the operator's only additional signal.
|
|
246
293
|
const announceParked = (): void => {
|
|
247
294
|
if (!markPermissionRequestSurfaced(announcedRequestIds, meta.requestId)) return;
|
|
248
295
|
const notice = approvalParkedNotice(call.tool, decision, autonomy);
|
|
@@ -256,10 +303,6 @@ export function createOverlayPermissionLifecycle(deps: OverlayPermissionLifecycl
|
|
|
256
303
|
view,
|
|
257
304
|
});
|
|
258
305
|
}
|
|
259
|
-
if (deps.getOverlayState() !== "closed") {
|
|
260
|
-
announceParked();
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
306
|
if (!deps.openPermissionOverlay(view, mainMutationInspector(call, view))) {
|
|
264
307
|
announceParked();
|
|
265
308
|
return;
|
|
@@ -280,6 +323,18 @@ export function createOverlayPermissionLifecycle(deps: OverlayPermissionLifecycl
|
|
|
280
323
|
workerQueue.push(entry);
|
|
281
324
|
maybeOpenWorker();
|
|
282
325
|
});
|
|
326
|
+
const unsubscribeWorkerResolution = deps.bus.on(BusChannels.PermissionResolved, (payload) => {
|
|
327
|
+
if (typeof payload.requestId !== "string") return;
|
|
328
|
+
if (payload.decidedBy !== "timeout" && payload.status !== "expired") return;
|
|
329
|
+
const fallback = payload.fallback === "fail" ? "fail" : "deny";
|
|
330
|
+
withdrawWorkers((entry) => entry.requestId === payload.requestId, "timeout", fallback);
|
|
331
|
+
});
|
|
332
|
+
const withdrawTerminalRun = (payload: { runId?: unknown }): void => {
|
|
333
|
+
if (typeof payload.runId !== "string") return;
|
|
334
|
+
withdrawWorkers((entry) => entry.runId === payload.runId, "terminal");
|
|
335
|
+
};
|
|
336
|
+
const unsubscribeWorkerCompleted = deps.bus.on(BusChannels.DispatchCompleted, withdrawTerminalRun);
|
|
337
|
+
const unsubscribeWorkerFailed = deps.bus.on(BusChannels.DispatchFailed, withdrawTerminalRun);
|
|
283
338
|
|
|
284
339
|
const unsubscribeAutonomy =
|
|
285
340
|
deps.toolRegistry?.onAutonomyDenied((_call, decision, level) => {
|
|
@@ -289,6 +344,12 @@ export function createOverlayPermissionLifecycle(deps: OverlayPermissionLifecycl
|
|
|
289
344
|
}) ?? (() => {});
|
|
290
345
|
|
|
291
346
|
const onPermissionOverlayClosed = (): void => {
|
|
347
|
+
if (withdrawingWorker) {
|
|
348
|
+
withdrawingWorker = false;
|
|
349
|
+
confirmed = false;
|
|
350
|
+
retryPending();
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
292
353
|
const permission = pendingPermission;
|
|
293
354
|
const worker = pendingWorker;
|
|
294
355
|
pendingPermission = null;
|
|
@@ -299,10 +360,14 @@ export function createOverlayPermissionLifecycle(deps: OverlayPermissionLifecycl
|
|
|
299
360
|
try {
|
|
300
361
|
deps.dispatch.resolveWorkerPermission?.(worker.runId, worker.requestId, wasConfirmed ? "approve" : "deny");
|
|
301
362
|
} catch (error) {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
)
|
|
363
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
364
|
+
if (
|
|
365
|
+
/run or assignment '.+' is not active|run '.+' is (?:aborting|terminating)|no longer accepts input/u.test(message)
|
|
366
|
+
) {
|
|
367
|
+
announceWorkerExpiry(worker, worker.fallback, "late-answer");
|
|
368
|
+
} else {
|
|
369
|
+
deps.appendNotice("warn", `Could not deliver permission decision to run ${worker.runId}: ${message}`);
|
|
370
|
+
}
|
|
306
371
|
}
|
|
307
372
|
} else if (wasConfirmed && permission) {
|
|
308
373
|
deps.bus.emit(BusChannels.PermissionResolved, {
|
|
@@ -384,6 +449,9 @@ export function createOverlayPermissionLifecycle(deps: OverlayPermissionLifecycl
|
|
|
384
449
|
dispose: () => {
|
|
385
450
|
unsubscribePermission();
|
|
386
451
|
unsubscribeWorker();
|
|
452
|
+
unsubscribeWorkerResolution();
|
|
453
|
+
unsubscribeWorkerCompleted();
|
|
454
|
+
unsubscribeWorkerFailed();
|
|
387
455
|
unsubscribeAutonomy();
|
|
388
456
|
},
|
|
389
457
|
};
|
|
@@ -20,12 +20,15 @@ export interface OverlayTransitionsDeps {
|
|
|
20
20
|
export interface OverlayTransitions {
|
|
21
21
|
state: OverlayState;
|
|
22
22
|
handle: OverlayHandle | null;
|
|
23
|
+
/** Raise a permission prompt while preserving the modal it interrupted. */
|
|
24
|
+
showPermission(handle: OverlayHandle): boolean;
|
|
23
25
|
close(): void;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
export function createOverlayTransitions(deps: OverlayTransitionsDeps): OverlayTransitions {
|
|
27
29
|
let state: OverlayState = "closed";
|
|
28
30
|
let handle: OverlayHandle | null = null;
|
|
31
|
+
let interrupted: { state: OverlayState; handle: OverlayHandle | null } | null = null;
|
|
29
32
|
|
|
30
33
|
return {
|
|
31
34
|
get state() {
|
|
@@ -44,6 +47,13 @@ export function createOverlayTransitions(deps: OverlayTransitionsDeps): OverlayT
|
|
|
44
47
|
set handle(next) {
|
|
45
48
|
handle = next;
|
|
46
49
|
},
|
|
50
|
+
showPermission(nextHandle) {
|
|
51
|
+
if (state === "permission-confirm") return false;
|
|
52
|
+
interrupted = state === "closed" ? null : { state, handle };
|
|
53
|
+
state = "permission-confirm";
|
|
54
|
+
handle = nextHandle;
|
|
55
|
+
return true;
|
|
56
|
+
},
|
|
47
57
|
close,
|
|
48
58
|
};
|
|
49
59
|
|
|
@@ -55,12 +65,16 @@ export function createOverlayTransitions(deps: OverlayTransitionsDeps): OverlayT
|
|
|
55
65
|
return;
|
|
56
66
|
}
|
|
57
67
|
const leaving = state;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
68
|
+
const leavingHandle = handle;
|
|
69
|
+
const restoring = leaving === "permission-confirm" ? interrupted : null;
|
|
70
|
+
interrupted = null;
|
|
71
|
+
state = restoring?.state ?? "closed";
|
|
72
|
+
handle = restoring?.handle ?? null;
|
|
73
|
+
if (restoring === null) deps.stopDispatchBoardTicker();
|
|
74
|
+
leavingHandle?.hide();
|
|
62
75
|
if (leaving === "permission-confirm") deps.onPermissionOverlayClosed();
|
|
63
76
|
else deps.onOverlayClosed?.();
|
|
77
|
+
restoring?.handle?.focus();
|
|
64
78
|
deps.renderContextIsland();
|
|
65
79
|
deps.renderTaskIsland();
|
|
66
80
|
deps.requestRender();
|
|
@@ -18,7 +18,13 @@ import {
|
|
|
18
18
|
} from "../../engine/tui.js";
|
|
19
19
|
import type { AskUserAnswer, AskUserQuestion, AskUserResult } from "../../tools/ask-user.js";
|
|
20
20
|
import { ASK_USER_OTHER_LABEL, cancelledAskUserResult } from "../../tools/ask-user.js";
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
buildHint,
|
|
23
|
+
DEFAULT_SELECT_THEME,
|
|
24
|
+
type HintEntry,
|
|
25
|
+
type OverlayEscVerb,
|
|
26
|
+
showClioOverlayFrame,
|
|
27
|
+
} from "../overlay-frame.js";
|
|
22
28
|
import { type ClioToken, clioTheme, dotSep, GLYPH, screenTitle } from "../theme/index.js";
|
|
23
29
|
import { nextContentScrollOffset, type ViewScrollAction } from "../view/view-overlay.js";
|
|
24
30
|
|
|
@@ -91,6 +97,8 @@ const MIN_VISIBLE_OPTIONS = 3;
|
|
|
91
97
|
/** Interview rows spent on chrome before an option row: strip, header, blanks, status, one question row. */
|
|
92
98
|
const INTERVIEW_CHROME_ROWS = 7;
|
|
93
99
|
const MAX_VISIBLE_OPTIONS = 12;
|
|
100
|
+
/** Below this the second column is too narrow to wrap a sentence into. */
|
|
101
|
+
const MIN_DESCRIPTION_COLUMN = 28;
|
|
94
102
|
const ELLIPSIS = "…";
|
|
95
103
|
|
|
96
104
|
/**
|
|
@@ -511,16 +519,24 @@ class AskUserOverlayView implements Component {
|
|
|
511
519
|
this.presentation.requiredActions.find((action) => action.id === "record-answer")?.label.toLowerCase() ??
|
|
512
520
|
"record answer";
|
|
513
521
|
if (state.mode === "text") {
|
|
522
|
+
// Esc means two different things depending on what is behind the field.
|
|
523
|
+
// A question with options has a list to fall back to, so the key goes
|
|
524
|
+
// back; a question without one has nothing behind it and the key still
|
|
525
|
+
// leaves the interview. The footer says which one this is.
|
|
526
|
+
const escapeVerb: OverlayEscVerb = questionHasOptions(question) ? "back" : "close";
|
|
514
527
|
return this.questions.length > 1
|
|
515
|
-
? this.withScrollHint(
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
528
|
+
? this.withScrollHint(
|
|
529
|
+
[
|
|
530
|
+
{ key: "Enter", verb: recordAnswer },
|
|
531
|
+
{ key: "Alt+Left/Right", verb: "question" },
|
|
532
|
+
],
|
|
533
|
+
escapeVerb,
|
|
534
|
+
)
|
|
535
|
+
: this.withScrollHint([{ key: "Enter", verb: recordAnswer }], escapeVerb);
|
|
520
536
|
}
|
|
521
537
|
// The classified action label distinguishes recording an answer from
|
|
522
|
-
// granting authority. Esc
|
|
523
|
-
//
|
|
538
|
+
// granting authority. Esc on the option list is the way out of the whole
|
|
539
|
+
// interview, which is the one place the product spells `close`.
|
|
524
540
|
// `t` is on every select footer because the operator cannot tell from a
|
|
525
541
|
// label whether the option needs a figure attached until they read it.
|
|
526
542
|
const addText: HintEntry = { key: "t", verb: "add text", short: "text" };
|
|
@@ -558,9 +574,9 @@ class AskUserOverlayView implements Component {
|
|
|
558
574
|
* scroll. A footer that always advertised PgUp would be advertising a key that
|
|
559
575
|
* does nothing on most rounds.
|
|
560
576
|
*/
|
|
561
|
-
private withScrollHint(entries: ReadonlyArray<HintEntry
|
|
562
|
-
if (this.surface !== "interview" || !this.contentOverflows) return buildHint(entries);
|
|
563
|
-
return buildHint([...entries, { key: "PgUp/PgDn", verb: "scroll" }]);
|
|
577
|
+
private withScrollHint(entries: ReadonlyArray<HintEntry>, esc: OverlayEscVerb = "close"): string {
|
|
578
|
+
if (this.surface !== "interview" || !this.contentOverflows) return buildHint(entries, esc);
|
|
579
|
+
return buildHint([...entries, { key: "PgUp/PgDn", verb: "scroll" }], esc);
|
|
564
580
|
}
|
|
565
581
|
|
|
566
582
|
private setSurface(next: AskUserSurface): void {
|
|
@@ -784,17 +800,29 @@ class AskUserOverlayView implements Component {
|
|
|
784
800
|
0,
|
|
785
801
|
items.findIndex((item) => item.value === selectedItem.value),
|
|
786
802
|
);
|
|
787
|
-
const
|
|
803
|
+
const primaryColumnWidth = this.primaryColumnWidth(items, width);
|
|
804
|
+
const acceptKey = question.multi_select === true ? "Space" : "Enter";
|
|
805
|
+
// The focused option's description wraps in full, so the rows it needs come
|
|
806
|
+
// out of the list rather than out of the sentence. Options the operator
|
|
807
|
+
// cannot currently read are what a windowed list is for, and one arrow key
|
|
808
|
+
// brings any of them back; a cut explanation has no such recovery.
|
|
809
|
+
const focusedRows = this.renderOptionRow(
|
|
810
|
+
items[selectedIndex] as SelectItem,
|
|
811
|
+
true,
|
|
812
|
+
width,
|
|
813
|
+
primaryColumnWidth,
|
|
814
|
+
acceptKey,
|
|
815
|
+
).length;
|
|
816
|
+
const budget = Math.max(1, this.maxVisibleOptions() - (focusedRows - 1));
|
|
817
|
+
const visibleCount = Math.min(budget, Math.max(1, items.length));
|
|
788
818
|
const start = Math.max(0, Math.min(selectedIndex - Math.floor(visibleCount / 2), items.length - visibleCount));
|
|
789
819
|
const end = Math.min(items.length, start + visibleCount);
|
|
790
|
-
const primaryColumnWidth = this.primaryColumnWidth(items, width);
|
|
791
820
|
const lines: string[] = [];
|
|
792
821
|
|
|
793
|
-
const acceptKey = question.multi_select === true ? "Space" : "Enter";
|
|
794
822
|
for (let index = start; index < end; index += 1) {
|
|
795
823
|
const item = items[index];
|
|
796
824
|
if (!item) continue;
|
|
797
|
-
lines.push(this.renderOptionRow(item, index === selectedIndex, width, primaryColumnWidth, acceptKey));
|
|
825
|
+
lines.push(...this.renderOptionRow(item, index === selectedIndex, width, primaryColumnWidth, acceptKey));
|
|
798
826
|
}
|
|
799
827
|
|
|
800
828
|
if (start > 0 || end < items.length) {
|
|
@@ -809,13 +837,22 @@ class AskUserOverlayView implements Component {
|
|
|
809
837
|
return Math.max(1, Math.min(bounded, Math.max(1, width - 4)));
|
|
810
838
|
}
|
|
811
839
|
|
|
840
|
+
/**
|
|
841
|
+
* One option, as the rows it needs.
|
|
842
|
+
*
|
|
843
|
+
* The focused option's description wraps under its own column and is never
|
|
844
|
+
* cut: a description is what the operator is choosing between, and half of
|
|
845
|
+
* one reads as the whole thing. An unfocused row stays a one-line table cell
|
|
846
|
+
* whose ellipsis says there is more, which the operator reads by moving to
|
|
847
|
+
* it.
|
|
848
|
+
*/
|
|
812
849
|
private renderOptionRow(
|
|
813
850
|
item: SelectItem,
|
|
814
851
|
selected: boolean,
|
|
815
852
|
width: number,
|
|
816
853
|
primaryColumnWidth: number,
|
|
817
854
|
acceptKey: string,
|
|
818
|
-
): string {
|
|
855
|
+
): string[] {
|
|
819
856
|
const theme = clioTheme();
|
|
820
857
|
const prefix = selected ? theme.fg("accent", `${GLYPH.cursor} `) : " ";
|
|
821
858
|
// The key that answers rides on the focused row. An operator whose eyes are
|
|
@@ -825,22 +862,40 @@ class AskUserOverlayView implements Component {
|
|
|
825
862
|
const available = Math.max(1, width - 2 - visibleWidth(affordance));
|
|
826
863
|
const description = item.description?.replace(/[\r\n]+/g, " ").trim();
|
|
827
864
|
|
|
828
|
-
|
|
829
|
-
if (description && width > 40) {
|
|
830
|
-
const labelWidth = Math.max(1, Math.min(primaryColumnWidth - 2, available - 4));
|
|
831
|
-
const label = truncateToWidth(item.label, labelWidth, ELLIPSIS, false);
|
|
832
|
-
const spacing = " ".repeat(Math.max(1, primaryColumnWidth - visibleWidth(label)));
|
|
833
|
-
const descriptionWidth = Math.max(1, available - visibleWidth(label) - visibleWidth(spacing));
|
|
834
|
-
const desc = truncateToWidth(description, descriptionWidth, ELLIPSIS, false);
|
|
835
|
-
body = selected
|
|
836
|
-
? theme.style("accent", `${label}${spacing}${desc}`, { bold: true })
|
|
837
|
-
: `${label}${theme.fg("muted", `${spacing}${desc}`)}`;
|
|
838
|
-
} else {
|
|
865
|
+
if (!description || width <= 40) {
|
|
839
866
|
const label = truncateToWidth(item.label, available, ELLIPSIS, false);
|
|
840
|
-
body = selected ? theme.style("accent", label, { bold: true }) : label;
|
|
867
|
+
const body = selected ? theme.style("accent", label, { bold: true }) : label;
|
|
868
|
+
return [fitLine(`${prefix}${body}${affordance}`, width)];
|
|
841
869
|
}
|
|
842
870
|
|
|
843
|
-
|
|
871
|
+
const labelWidth = Math.max(1, Math.min(primaryColumnWidth - 2, available - 4));
|
|
872
|
+
const label = truncateToWidth(item.label, labelWidth, ELLIPSIS, false);
|
|
873
|
+
const spacing = " ".repeat(Math.max(1, primaryColumnWidth - visibleWidth(label)));
|
|
874
|
+
const descriptionWidth = Math.max(1, available - visibleWidth(label) - visibleWidth(spacing));
|
|
875
|
+
if (!selected) {
|
|
876
|
+
const desc = truncateToWidth(description, descriptionWidth, ELLIPSIS, false);
|
|
877
|
+
return [fitLine(`${prefix}${label}${theme.fg("muted", `${spacing}${desc}`)}`, width)];
|
|
878
|
+
}
|
|
879
|
+
// A gutter this narrow wraps a sentence into slivers and breaks words, so
|
|
880
|
+
// below the floor the description drops to its own full-width lines under
|
|
881
|
+
// the label instead of squeezing into the second column.
|
|
882
|
+
if (descriptionWidth < MIN_DESCRIPTION_COLUMN) {
|
|
883
|
+
const indent = " ";
|
|
884
|
+
const body = theme.style("accent", label, { bold: true });
|
|
885
|
+
return [
|
|
886
|
+
fitLine(`${prefix}${body}${affordance}`, width),
|
|
887
|
+
...wrapTextWithAnsi(description, Math.max(1, width - indent.length)).map((line) =>
|
|
888
|
+
fitLine(`${indent}${theme.style("accent", line, { bold: true })}`, width),
|
|
889
|
+
),
|
|
890
|
+
];
|
|
891
|
+
}
|
|
892
|
+
const wrapped = wrapTextWithAnsi(description, descriptionWidth);
|
|
893
|
+
const head = wrapped[0] ?? "";
|
|
894
|
+
const indent = " ".repeat(visibleWidth(prefix) + visibleWidth(label) + visibleWidth(spacing));
|
|
895
|
+
return [
|
|
896
|
+
fitLine(`${prefix}${theme.style("accent", `${label}${spacing}${head}`, { bold: true })}${affordance}`, width),
|
|
897
|
+
...wrapped.slice(1).map((line) => fitLine(`${indent}${theme.style("accent", line, { bold: true })}`, width)),
|
|
898
|
+
];
|
|
844
899
|
}
|
|
845
900
|
|
|
846
901
|
private ensureControl(): void {
|
|
@@ -889,7 +944,7 @@ class AskUserOverlayView implements Component {
|
|
|
889
944
|
state.answer = questionHasOptions(question) ? answerText(question, state.selected, state.customAnswer) : answer;
|
|
890
945
|
this.finishIfCompleteOrAdvance();
|
|
891
946
|
};
|
|
892
|
-
activeInput.onEscape = () => this.
|
|
947
|
+
activeInput.onEscape = () => this.escapeFromTextInput(question, state);
|
|
893
948
|
this.input = activeInput;
|
|
894
949
|
this.list = null;
|
|
895
950
|
}
|
|
@@ -960,6 +1015,53 @@ class AskUserOverlayView implements Component {
|
|
|
960
1015
|
return 0;
|
|
961
1016
|
}
|
|
962
1017
|
|
|
1018
|
+
/**
|
|
1019
|
+
* Esc in the text field.
|
|
1020
|
+
*
|
|
1021
|
+
* The field used to resolve the whole round as cancelled, which made a typed
|
|
1022
|
+
* draft unrecoverable: a single-question round had no other question to answer
|
|
1023
|
+
* first, so the only way off `t` was to abandon the interview (issue #260). A
|
|
1024
|
+
* question with options has a surface behind the field, so Esc goes back to it
|
|
1025
|
+
* and drops the draft. A question with no options has nothing behind it, so Esc
|
|
1026
|
+
* keeps its old meaning and leaves the interview; the footer says which.
|
|
1027
|
+
*
|
|
1028
|
+
* The draft is dropped rather than parked because Esc is the discard gesture.
|
|
1029
|
+
* It never reached `answer`, `options`, or `value` in the first place, since
|
|
1030
|
+
* only a submit writes those, so #228's clearing rule holds either way.
|
|
1031
|
+
*/
|
|
1032
|
+
private escapeFromTextInput(question: AskUserQuestion, state: QuestionState): void {
|
|
1033
|
+
if (!questionHasOptions(question)) {
|
|
1034
|
+
this.cancel();
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
state.inputValue = "";
|
|
1038
|
+
state.mode = "select";
|
|
1039
|
+
this.status = "";
|
|
1040
|
+
this.rebuildSelectList(question, state);
|
|
1041
|
+
this.deps.requestRender();
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
/**
|
|
1045
|
+
* Leave a question the operator is walking away from on its option list.
|
|
1046
|
+
*
|
|
1047
|
+
* The mode used to belong to the question for the rest of the round, so a
|
|
1048
|
+
* question opened with `t` came back as a prefilled field however the operator
|
|
1049
|
+
* returned to it, and the option list was gone for good. Navigating away is not
|
|
1050
|
+
* the discard gesture, so the draft stays in `inputValue` and `t` finds it
|
|
1051
|
+
* again; what does not survive is the field being the thing that greets them.
|
|
1052
|
+
*
|
|
1053
|
+
* A question whose value was actually submitted keeps its field, because
|
|
1054
|
+
* coming back to a recorded figure is how it gets revised (issue #228).
|
|
1055
|
+
*/
|
|
1056
|
+
private parkTextMode(): void {
|
|
1057
|
+
const question = this.currentQuestion();
|
|
1058
|
+
const state = this.currentState();
|
|
1059
|
+
if (!question || !state) return;
|
|
1060
|
+
if (state.mode !== "text" || !questionHasOptions(question)) return;
|
|
1061
|
+
if (state.rawValue.length > 0) return;
|
|
1062
|
+
state.mode = "select";
|
|
1063
|
+
}
|
|
1064
|
+
|
|
963
1065
|
private openTextInput(nextStatus: string): void {
|
|
964
1066
|
const state = this.currentState();
|
|
965
1067
|
const question = this.currentQuestion();
|
|
@@ -1077,6 +1179,7 @@ class AskUserOverlayView implements Component {
|
|
|
1077
1179
|
private goToRelativeQuestion(delta: -1 | 1): void {
|
|
1078
1180
|
if (this.questions.length <= 1) return;
|
|
1079
1181
|
this.syncActiveControl();
|
|
1182
|
+
this.parkTextMode();
|
|
1080
1183
|
this.index = (this.index + delta + this.questions.length) % this.questions.length;
|
|
1081
1184
|
this.status = "";
|
|
1082
1185
|
this.resetContentScroll();
|
|
@@ -1128,6 +1231,9 @@ export function openAskUserOverlay(tui: TUI, deps: OpenAskUserOverlayDeps): AskU
|
|
|
1128
1231
|
// the terminal has left after the margins.
|
|
1129
1232
|
...(geometry.maxInnerRows > 0 ? { maxHeight: geometry.maxInnerRows + ASK_USER_FRAME_ROWS } : {}),
|
|
1130
1233
|
margin: geometry.margin,
|
|
1234
|
+
// Not derived from the title: this modal swaps between a waiting title
|
|
1235
|
+
// and a classified decision title without ever changing hands.
|
|
1236
|
+
markerId: "ask-user",
|
|
1131
1237
|
title: () => (view.isDecisionPending() ? view.decisionTitle() : ASK_USER_WAITING_TITLE),
|
|
1132
1238
|
tone: () => (view.isDecisionPending() ? view.decisionTone() : undefined),
|
|
1133
1239
|
footerHint: () => view.footerHint(),
|
|
@@ -211,6 +211,7 @@ export function openAuthDialog(tui: TUI, title: string, onCancel: () => void): A
|
|
|
211
211
|
const handle = showClioOverlayFrame(tui, box, {
|
|
212
212
|
anchor: "center",
|
|
213
213
|
width: AUTH_DIALOG_WIDTH,
|
|
214
|
+
markerId: "auth",
|
|
214
215
|
title: "Authentication",
|
|
215
216
|
footerHint: getHint,
|
|
216
217
|
});
|
|
@@ -102,6 +102,7 @@ export function openContextResetOverlay(tui: TUI, deps: OpenContextResetOverlayD
|
|
|
102
102
|
return showClioOverlayFrame(tui, new FocusBox(list), {
|
|
103
103
|
anchor: "center",
|
|
104
104
|
width: CONTEXT_RESET_OVERLAY_WIDTH,
|
|
105
|
+
markerId: "context-reset",
|
|
105
106
|
title: "Reset Project Context",
|
|
106
107
|
footerHint: buildHint([{ key: "Enter", verb: "select" }]),
|
|
107
108
|
});
|
|
@@ -135,6 +135,7 @@ export function openCwdFallbackOverlay(tui: TUI, deps: OpenCwdFallbackOverlayDep
|
|
|
135
135
|
return showClioOverlayFrame(tui, box, {
|
|
136
136
|
anchor: "center",
|
|
137
137
|
width: CWD_FALLBACK_OVERLAY_WIDTH,
|
|
138
|
+
markerId: "cwd-fallback",
|
|
138
139
|
title: "Session Working Directory",
|
|
139
140
|
footerHint: buildHint([{ key: "Enter", verb: "select" }]),
|
|
140
141
|
});
|
|
@@ -94,22 +94,21 @@ function decisionLines(decision: DecisionRecord, selected: boolean, expanded: bo
|
|
|
94
94
|
const label = decision.status === "superseded" ? theme.fg("dim", labelText) : theme.fg("muted", labelText);
|
|
95
95
|
const value = decision.status === "superseded" ? theme.fg("dim", decision.value) : decision.value;
|
|
96
96
|
const lines = [fitLine(`${cursor} ${status} ${label}${theme.fg("dim", ":")} ${value}`, width)];
|
|
97
|
+
// The indent belongs to the container, so this text wraps inside what is left
|
|
98
|
+
// of the row. Wrapping to the full width and then indenting cost every line
|
|
99
|
+
// its last six columns to a cut that landed mid-sentence.
|
|
100
|
+
const indent = " ";
|
|
101
|
+
const indented = Math.max(1, width - indent.length);
|
|
102
|
+
const wrapIndented = (text: string): string[] =>
|
|
103
|
+
wrapTextWithAnsi(text, indented).map((line) => fitLine(`${indent}${line}`, width));
|
|
97
104
|
if (decision.status === "superseded" && decision.correction) {
|
|
98
|
-
lines.push(
|
|
105
|
+
lines.push(...wrapIndented(`${theme.fg("dim", "correction")} ${theme.fg("muted", decision.correction)}`));
|
|
99
106
|
}
|
|
100
107
|
if (selected && expanded) {
|
|
101
108
|
if (decision.source_question) {
|
|
102
|
-
lines.push(
|
|
103
|
-
...wrapTextWithAnsi(`${theme.fg("dim", "question")} ${theme.fg("muted", decision.source_question)}`, width).map(
|
|
104
|
-
(line) => fitLine(` ${line}`, width),
|
|
105
|
-
),
|
|
106
|
-
);
|
|
109
|
+
lines.push(...wrapIndented(`${theme.fg("dim", "question")} ${theme.fg("muted", decision.source_question)}`));
|
|
107
110
|
}
|
|
108
|
-
lines.push(
|
|
109
|
-
...wrapTextWithAnsi(`${theme.fg("dim", "answer")} ${theme.fg("muted", decision.value)}`, width).map((line) =>
|
|
110
|
-
fitLine(` ${line}`, width),
|
|
111
|
-
),
|
|
112
|
-
);
|
|
111
|
+
lines.push(...wrapIndented(`${theme.fg("dim", "answer")} ${theme.fg("muted", decision.value)}`));
|
|
113
112
|
}
|
|
114
113
|
return lines;
|
|
115
114
|
}
|
|
@@ -296,6 +295,7 @@ export function openDecisionsOverlay(
|
|
|
296
295
|
return showClioOverlayFrame(tui, body, {
|
|
297
296
|
anchor: "center",
|
|
298
297
|
width: DECISIONS_OVERLAY_WIDTH,
|
|
298
|
+
markerId: "decisions",
|
|
299
299
|
title: () => "Decisions",
|
|
300
300
|
footerHint: () => body.footerHint(),
|
|
301
301
|
});
|
|
@@ -191,6 +191,7 @@ export function openFleetRunApprovalOverlay(tui: TUI, options: OpenFleetRunAppro
|
|
|
191
191
|
const handle = showClioOverlayFrame(tui, focus, {
|
|
192
192
|
anchor: "center",
|
|
193
193
|
width: fleetRunApprovalOverlayWidth(options.columns),
|
|
194
|
+
markerId: "fleet-run-approval",
|
|
194
195
|
title: FLEET_RUN_APPROVAL_OVERLAY_TITLE,
|
|
195
196
|
footerHint: buildResponsiveHint(
|
|
196
197
|
[...(acceptable ? [{ key: "Enter", verb: "dispatch" }] : []), { key: "↑↓", verb: "scroll" }],
|
|
@@ -163,6 +163,7 @@ export function openHandoffReviewOverlay(
|
|
|
163
163
|
const handle = showClioOverlayFrame(tui, focus, {
|
|
164
164
|
anchor: "center",
|
|
165
165
|
width: handoffReviewOverlayWidth(options.columns),
|
|
166
|
+
markerId: "handoff-review",
|
|
166
167
|
title: HANDOFF_REVIEW_OVERLAY_TITLE,
|
|
167
168
|
footerHint: buildResponsiveHint(
|
|
168
169
|
[
|
|
@@ -94,6 +94,7 @@ export function openHelpOverlay(
|
|
|
94
94
|
detail: () => [
|
|
95
95
|
"# Fleet runs & steering",
|
|
96
96
|
"**Fleet Runs board**: open it with the configured Dispatch Board key (Alt+W by default). Use Up/Down or `j`/`k` to select a live or recent run.",
|
|
97
|
+
"**Enter**: on a live run in a `--with-panes` session, Enter opens (or retargets) the watch pane beside Clio, rendering that run's stream; the arrow keys then move it between runs. On a finished run, or without panes, Enter toggles the inline worker-progress detail instead.",
|
|
97
98
|
"**Steer**: press `s` on a live native run to close the board and prefill `@<runId> `. Add guidance and submit it normally. The first notice means queued; a received notice confirms worker delivery.",
|
|
98
99
|
"**Cancel**: press `x` on a running, stale, queued, or retry-waiting run. The row changes to cancelling while the worker or retry is being stopped.",
|
|
99
100
|
"**Capabilities**: ACP delegation runs cannot accept live steering. The board footer only advertises actions supported by the selected row.",
|
|
@@ -140,6 +141,7 @@ export function openHelpOverlay(
|
|
|
140
141
|
const items = [...commands, ...keys, ...topics];
|
|
141
142
|
|
|
142
143
|
return openListOverlay(tui, {
|
|
144
|
+
markerId: "help",
|
|
143
145
|
title: "Help Center",
|
|
144
146
|
items,
|
|
145
147
|
filterable: true,
|
|
@@ -137,6 +137,7 @@ export function openLibraryInstallConfirmOverlay(
|
|
|
137
137
|
const handle = showClioOverlayFrame(tui, focus, {
|
|
138
138
|
anchor: "center",
|
|
139
139
|
width: confirmOverlayWidth(options.columns),
|
|
140
|
+
markerId: "library-install",
|
|
140
141
|
title: LIBRARY_INSTALL_CONFIRM_TITLE,
|
|
141
142
|
footerHint: buildResponsiveHint([{ key: "Enter", verb: "install" }], { key: "Esc", verb: "cancel" }),
|
|
142
143
|
});
|