@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
package/src/cli/reset.ts
CHANGED
|
@@ -15,7 +15,7 @@ Each level clears exactly the root (or file) it names and nothing else.
|
|
|
15
15
|
Levels (combinable except --all):
|
|
16
16
|
--state state root only (default). Holds every session transcript, so a
|
|
17
17
|
reset is the end of resume, /view, and the audit behind them.
|
|
18
|
-
--data data root only: memory, evidence, evals (durable products)
|
|
18
|
+
--data data root only: memory, evidence, evals, vendored tools (durable products)
|
|
19
19
|
--cache cache root only
|
|
20
20
|
--auth credentials.yaml only
|
|
21
21
|
--config settings.yaml only
|
|
@@ -42,7 +42,10 @@ Safety:
|
|
|
42
42
|
const ROOT_NOTES: Readonly<Record<string, string>> = {
|
|
43
43
|
state:
|
|
44
44
|
"the state root holds every session transcript and the audit trail beside it; resume and /view lose their history",
|
|
45
|
-
|
|
45
|
+
// Vendored tools are named because they are the one durable product a reset
|
|
46
|
+
// cannot regenerate from anything local: getting them back is a download.
|
|
47
|
+
data:
|
|
48
|
+
"the data root holds durable products (memory, evidence, evals, and any vendored external tools, which a reinstall re-downloads)",
|
|
46
49
|
};
|
|
47
50
|
|
|
48
51
|
interface ParsedResetArgs {
|
package/src/cli/run.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { createContextDomainModule } from "../domains/context/runtime.js";
|
|
|
11
11
|
import type { DispatchContract, DispatchRequest } from "../domains/dispatch/contract.js";
|
|
12
12
|
import { agentRoleFactsResolver, requestExecutionRole } from "../domains/dispatch/execution-role.js";
|
|
13
13
|
import { createDispatchDomainModule } from "../domains/dispatch/index.js";
|
|
14
|
+
import { configureRunEventJournal } from "../domains/dispatch/run-event-journal.js";
|
|
14
15
|
import type { RunReceipt } from "../domains/dispatch/types.js";
|
|
15
16
|
import { ensureClioState, LifecycleDomainModule } from "../domains/lifecycle/index.js";
|
|
16
17
|
import {
|
|
@@ -158,6 +159,45 @@ export function explicitSkillPathErrors(skillPaths: ReadonlyArray<string>): stri
|
|
|
158
159
|
return errors;
|
|
159
160
|
}
|
|
160
161
|
|
|
162
|
+
/**
|
|
163
|
+
* The TUI's verdict for a command-shaped token the registry does not own,
|
|
164
|
+
* applied to a headless task. Returns the refusal message, or null when the
|
|
165
|
+
* task is not an unknown command.
|
|
166
|
+
*
|
|
167
|
+
* `parseSlashCommand` is the canonical shape test and the canonical registry
|
|
168
|
+
* walk, so a token that is one word of letters, digits, hyphens, or colons and
|
|
169
|
+
* names no command lands here exactly as it does in the editor. Prose keeps
|
|
170
|
+
* reaching the model: an absolute path such as `/home/user/notes` carries a
|
|
171
|
+
* separator and is not one word, and `\/tmp is full` is the same escape the
|
|
172
|
+
* editor honors.
|
|
173
|
+
*
|
|
174
|
+
* A prompt template claims the token before the refusal does. Only membership
|
|
175
|
+
* is checked, not expansion: a template that exists but refuses (an untrusted
|
|
176
|
+
* project root, an unreadable body) has its own message, which the headless
|
|
177
|
+
* boot path already prints from the expansion itself. Deciding that here would
|
|
178
|
+
* duplicate the trust rules and put two refusals on one token.
|
|
179
|
+
*
|
|
180
|
+
* Both modules are imported lazily, so a task that does not start with a slash
|
|
181
|
+
* pays for neither. The laziness is a startup-cost choice and nothing more: for
|
|
182
|
+
* bundle partitioning a dynamic import is worse than a static one, because a
|
|
183
|
+
* dynamically imported module becomes a chunk split point by itself. What keeps
|
|
184
|
+
* this edge safe is the other end. `slash-commands.ts` is a declared CLI seam
|
|
185
|
+
* whose own imports stay off the interactive render graph, so reaching it does
|
|
186
|
+
* not make this file a second reacher of the chunk the instant shell's Stage 0
|
|
187
|
+
* closure sits on. Boundaries rule6 in `tests/boundaries/check-boundaries.ts`
|
|
188
|
+
* holds both halves of that.
|
|
189
|
+
*/
|
|
190
|
+
export async function unknownSlashCommandRefusal(task: string): Promise<string | null> {
|
|
191
|
+
if (!task.trim().startsWith("/")) return null;
|
|
192
|
+
const { parseSlashCommand } = await import("../interactive/slash-commands.js");
|
|
193
|
+
const command = parseSlashCommand(task);
|
|
194
|
+
if (command.kind !== "unknown-command") return null;
|
|
195
|
+
const { loadPromptTemplates } = await import("../domains/resources/index.js");
|
|
196
|
+
const templates = loadPromptTemplates({ cwd: process.cwd() });
|
|
197
|
+
if (templates.items.some((template) => template.name === command.token)) return null;
|
|
198
|
+
return `/${command.token} is not a command. Type /help for the list.`;
|
|
199
|
+
}
|
|
200
|
+
|
|
161
201
|
export async function runClioRun(
|
|
162
202
|
args: ReadonlyArray<string>,
|
|
163
203
|
options: { apiKey?: string; noContextFiles?: boolean; noSkills?: boolean; skillPaths?: ReadonlyArray<string> } = {},
|
|
@@ -218,6 +258,15 @@ export async function runClioRun(
|
|
|
218
258
|
if (!assembled) return 2;
|
|
219
259
|
|
|
220
260
|
if (parsed.agentId === undefined) {
|
|
261
|
+
// A mistyped slash command is a usage error, not a task. Refusing it
|
|
262
|
+
// here keeps it from booting a session and spending a model turn on a
|
|
263
|
+
// command that was never run, which is what the TUI has always done
|
|
264
|
+
// and what docs/extensions-and-sharing.md documents for both surfaces.
|
|
265
|
+
const slashRefusal = await unknownSlashCommandRefusal(assembled.prompt);
|
|
266
|
+
if (slashRefusal !== null) {
|
|
267
|
+
process.stderr.write(`clio-coder run: ${slashRefusal}\n`);
|
|
268
|
+
return 2;
|
|
269
|
+
}
|
|
221
270
|
// An explicit --target override is a one-run target; a missing id is an
|
|
222
271
|
// operator config error, not an assistant response. Reject it before the
|
|
223
272
|
// headless turn so the resolver diagnostic never streams to stdout as a
|
|
@@ -314,11 +363,20 @@ async function runDispatch(
|
|
|
314
363
|
createDispatchDomainModule({
|
|
315
364
|
getSettings: () => effectiveSettings,
|
|
316
365
|
autonomyOverride: parsed.autonomy !== undefined,
|
|
366
|
+
// This path iterates `handle.events` itself and builds no dispatch
|
|
367
|
+
// event registry, so the domain is the only thing that can write the
|
|
368
|
+
// run's durable transcript.
|
|
369
|
+
journalRunEvents: true,
|
|
317
370
|
}),
|
|
318
371
|
LifecycleDomainModule,
|
|
319
372
|
]);
|
|
320
373
|
const config = loaded.getContract<ConfigContract>("config");
|
|
321
374
|
const baseSettings = config?.get() ?? readSettings();
|
|
375
|
+
// Install `panes.journal` the same way the interactive composition root
|
|
376
|
+
// does. The journal never reads settings.yaml itself: it sits on the
|
|
377
|
+
// dispatch event path, where a settings read would be both a cost and a
|
|
378
|
+
// throw site.
|
|
379
|
+
configureRunEventJournal(baseSettings.panes.journal);
|
|
322
380
|
effectiveSettings =
|
|
323
381
|
parsed.autonomy === undefined ? baseSettings : { ...structuredClone(baseSettings), autonomy: parsed.autonomy };
|
|
324
382
|
const dispatch = loaded.getContract<DispatchContract>("dispatch");
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixed machine-readable projection of this installation's installed skills.
|
|
3
|
+
*
|
|
4
|
+
* `skills list --json` already emits a machine-readable listing, and a GUI host
|
|
5
|
+
* reading it gets two things wrong. Without `--all` it sees only the skills the
|
|
6
|
+
* model may load, which is `trusted && !disableModelInvocation`, so a surface
|
|
7
|
+
* rendering trust and invocability off that payload prints "trusted" and
|
|
8
|
+
* "allowed" on every row and structurally cannot print anything else. And the
|
|
9
|
+
* rows it does get are the full loaded records, carrying the SKILL.md body, the
|
|
10
|
+
* file path, the base directory, and two content hashes, so every consumer has
|
|
11
|
+
* to re-derive the same redaction.
|
|
12
|
+
*
|
|
13
|
+
* This command answers both. It loads once, reports every installed skill
|
|
14
|
+
* whether or not the model can reach it, says which ones it can, and carries
|
|
15
|
+
* only fields that are safe by construction. It is a separate subcommand rather
|
|
16
|
+
* than a flag on `skills inspect`, because that one names a skill and a fixed
|
|
17
|
+
* read a host may run must take no identifier at all.
|
|
18
|
+
*
|
|
19
|
+
* Held back deliberately: the skill body, its file path, its base directory,
|
|
20
|
+
* both hashes, the install and registry URLs, and the free-text loader
|
|
21
|
+
* diagnostics. Whether a skill has an upstream to update from crosses; where
|
|
22
|
+
* that upstream is does not.
|
|
23
|
+
*
|
|
24
|
+
* Marketplace discovery is deliberately not here. `library list --json` already
|
|
25
|
+
* folds `discoverMarketplaceSkills` into its catalog, so every installable
|
|
26
|
+
* skill already crosses through that read, and a second one would report the
|
|
27
|
+
* same rows under a different name.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import {
|
|
31
|
+
loadSkills,
|
|
32
|
+
type ResourceDiagnostic,
|
|
33
|
+
type Skill,
|
|
34
|
+
type SkillCatalogInvalidReason,
|
|
35
|
+
skillCatalogValidity,
|
|
36
|
+
} from "../domains/resources/index.js";
|
|
37
|
+
|
|
38
|
+
/** Wire bound on the emitted skill list. */
|
|
39
|
+
const MAX_SKILLS_INVENTORY_SKILLS = 64;
|
|
40
|
+
/** Wire bound on each skill's declared tool policy. */
|
|
41
|
+
const MAX_SKILLS_INVENTORY_TOOLS = 32;
|
|
42
|
+
|
|
43
|
+
const TOOL_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/;
|
|
44
|
+
|
|
45
|
+
type SkillAuditState = "pass" | "warn" | "fail" | "unknown" | "not-reported";
|
|
46
|
+
|
|
47
|
+
interface SkillsInventoryDiagnosticCounts {
|
|
48
|
+
readonly errors: number;
|
|
49
|
+
readonly warnings: number;
|
|
50
|
+
readonly collisions: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface SkillsInventorySkill {
|
|
54
|
+
readonly name: string;
|
|
55
|
+
readonly description: string;
|
|
56
|
+
readonly scope: string;
|
|
57
|
+
readonly source: string;
|
|
58
|
+
/** Whether the skill's root is trusted enough for the model to see it at all. */
|
|
59
|
+
readonly trusted: boolean;
|
|
60
|
+
/** Whether the skill's own frontmatter permits model invocation. */
|
|
61
|
+
readonly modelInvocable: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* The effective answer, which is both of the above.
|
|
64
|
+
*
|
|
65
|
+
* Reported rather than left to be inferred because it is the fact an
|
|
66
|
+
* operator is actually asking about, and because a listing filtered to it
|
|
67
|
+
* cannot state it.
|
|
68
|
+
*/
|
|
69
|
+
readonly modelVisible: boolean;
|
|
70
|
+
readonly precedence: number;
|
|
71
|
+
readonly diagnostics: SkillsInventoryDiagnosticCounts;
|
|
72
|
+
/** Tools the skill narrows itself to. The harness intersects these with host policy. */
|
|
73
|
+
readonly allowedTools: readonly string[];
|
|
74
|
+
readonly disallowedTools: readonly string[];
|
|
75
|
+
/** True when a dispatched worker installed this, rather than the operator. */
|
|
76
|
+
readonly installedByWorker: boolean;
|
|
77
|
+
/** True when provenance records an upstream, so `skills update` has something to fetch. */
|
|
78
|
+
readonly updatable: boolean;
|
|
79
|
+
readonly audit: SkillAuditState;
|
|
80
|
+
readonly installedAt: string | null;
|
|
81
|
+
readonly updatedAt: string | null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface SkillsInventorySnapshot {
|
|
85
|
+
readonly version: 1;
|
|
86
|
+
readonly generatedAt: string;
|
|
87
|
+
/** The verdict `skills validate` reaches, from the rule both callers share. */
|
|
88
|
+
readonly valid: boolean;
|
|
89
|
+
readonly invalidReason: SkillCatalogInvalidReason | null;
|
|
90
|
+
/** Every installed skill the loader resolved, before the wire bound. */
|
|
91
|
+
readonly total: number;
|
|
92
|
+
/** How many of those the model may actually load by name. */
|
|
93
|
+
readonly modelVisible: number;
|
|
94
|
+
readonly diagnostics: SkillsInventoryDiagnosticCounts;
|
|
95
|
+
readonly skills: readonly SkillsInventorySkill[];
|
|
96
|
+
readonly skillsTruncated: boolean;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const AUDIT_STATES: ReadonlySet<string> = new Set(["pass", "warn", "fail", "unknown"]);
|
|
100
|
+
|
|
101
|
+
function countDiagnostics(diagnostics: ReadonlyArray<ResourceDiagnostic>): SkillsInventoryDiagnosticCounts {
|
|
102
|
+
let errors = 0;
|
|
103
|
+
let warnings = 0;
|
|
104
|
+
let collisions = 0;
|
|
105
|
+
for (const diag of diagnostics) {
|
|
106
|
+
if (diag.type === "error") errors += 1;
|
|
107
|
+
else if (diag.type === "collision") collisions += 1;
|
|
108
|
+
else warnings += 1;
|
|
109
|
+
}
|
|
110
|
+
return { errors, warnings, collisions };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Tool names are already-crossing identifiers: the agent catalog carries the
|
|
115
|
+
* same class. They are re-enforced structurally here anyway, because a skill's
|
|
116
|
+
* frontmatter is operator-authored and the loader does not hold it to a shape.
|
|
117
|
+
*/
|
|
118
|
+
function toolPolicy(value: ReadonlyArray<string> | undefined): string[] {
|
|
119
|
+
if (value === undefined) return [];
|
|
120
|
+
const tools: string[] = [];
|
|
121
|
+
for (const tool of value) {
|
|
122
|
+
if (tools.length >= MAX_SKILLS_INVENTORY_TOOLS) break;
|
|
123
|
+
if (typeof tool !== "string" || tool.length > 64 || !TOOL_PATTERN.test(tool)) continue;
|
|
124
|
+
if (!tools.includes(tool)) tools.push(tool);
|
|
125
|
+
}
|
|
126
|
+
return tools;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function timestamp(value: string | undefined): string | null {
|
|
130
|
+
if (value === undefined) return null;
|
|
131
|
+
const parsed = Date.parse(value);
|
|
132
|
+
return Number.isFinite(parsed) ? new Date(parsed).toISOString() : null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function projectSkill(skill: Skill): SkillsInventorySkill {
|
|
136
|
+
const provenance = skill.provenance;
|
|
137
|
+
const audit = provenance?.audit;
|
|
138
|
+
return {
|
|
139
|
+
name: skill.name,
|
|
140
|
+
description: skill.description,
|
|
141
|
+
scope: skill.scope,
|
|
142
|
+
source: skill.source,
|
|
143
|
+
trusted: skill.trusted,
|
|
144
|
+
modelInvocable: !skill.disableModelInvocation,
|
|
145
|
+
modelVisible: skill.trusted && !skill.disableModelInvocation,
|
|
146
|
+
precedence: skill.precedence,
|
|
147
|
+
diagnostics: countDiagnostics(skill.diagnostics),
|
|
148
|
+
allowedTools: toolPolicy(skill.allowedTools),
|
|
149
|
+
disallowedTools: toolPolicy(skill.disallowedTools),
|
|
150
|
+
installedByWorker: provenance?.installedBy === "worker",
|
|
151
|
+
// The URL itself is a host-side fact; that one exists is what tells the
|
|
152
|
+
// operator whether an update has anywhere to come from.
|
|
153
|
+
updatable: provenance?.installUrl !== undefined || provenance?.registryUrl !== undefined,
|
|
154
|
+
audit: audit !== undefined && AUDIT_STATES.has(audit) ? (audit as SkillAuditState) : "not-reported",
|
|
155
|
+
installedAt: timestamp(provenance?.installedAt),
|
|
156
|
+
updatedAt: timestamp(provenance?.updatedAt),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function skillsInventorySnapshot(now: () => number = Date.now, cwd: string = process.cwd()): SkillsInventorySnapshot {
|
|
161
|
+
const list = loadSkills({ cwd });
|
|
162
|
+
const validity = skillCatalogValidity(list);
|
|
163
|
+
const projected = list.items.map(projectSkill);
|
|
164
|
+
const skills = projected.slice(0, MAX_SKILLS_INVENTORY_SKILLS);
|
|
165
|
+
return {
|
|
166
|
+
version: 1,
|
|
167
|
+
generatedAt: new Date(now()).toISOString(),
|
|
168
|
+
valid: validity.ok,
|
|
169
|
+
invalidReason: validity.reason,
|
|
170
|
+
total: projected.length,
|
|
171
|
+
modelVisible: projected.filter((skill) => skill.modelVisible).length,
|
|
172
|
+
diagnostics: countDiagnostics(list.diagnostics),
|
|
173
|
+
skills,
|
|
174
|
+
skillsTruncated: skills.length < projected.length,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function runSkillsInventory(args: ReadonlyArray<string>): number {
|
|
179
|
+
if (args.length !== 1 || args[0] !== "--json") {
|
|
180
|
+
process.stderr.write("clio-coder skills inventory: usage: clio-coder skills inventory --json\n");
|
|
181
|
+
return 2;
|
|
182
|
+
}
|
|
183
|
+
process.stdout.write(`${JSON.stringify(skillsInventorySnapshot(), null, 2)}\n`);
|
|
184
|
+
return 0;
|
|
185
|
+
}
|
package/src/cli/skills.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type ResourceDiagnostic,
|
|
9
9
|
type Skill,
|
|
10
10
|
type SkillUpdateReport,
|
|
11
|
+
skillCatalogValidity,
|
|
11
12
|
updateSkills,
|
|
12
13
|
} from "../domains/resources/index.js";
|
|
13
14
|
import { formatColumns, printError, printOk } from "./shared.js";
|
|
@@ -18,6 +19,7 @@ Manage local Clio and Agent Skills-compatible skills.
|
|
|
18
19
|
|
|
19
20
|
Commands:
|
|
20
21
|
clio-coder skills list [--json] [--all]
|
|
22
|
+
clio-coder skills inventory --json
|
|
21
23
|
clio-coder skills search <query> [--json]
|
|
22
24
|
clio-coder skills inspect <name> [--json]
|
|
23
25
|
clio-coder skills validate [path] [--json]
|
|
@@ -27,6 +29,10 @@ Commands:
|
|
|
27
29
|
clio-coder skills sync [--force]
|
|
28
30
|
clio-coder skills eval <name|path> [--scenario <id>] [--target <id>] [--workspace <path>] [--timeout <seconds>] [--trust-fixtures] [--allow-network] [--json]
|
|
29
31
|
|
|
32
|
+
inventory is the fixed machine-readable read a GUI host may run. Unlike a bare
|
|
33
|
+
list it reports every installed skill, not only the ones the model may load, and
|
|
34
|
+
says which are which; it carries no body, path, hash, or install URL.
|
|
35
|
+
|
|
30
36
|
search covers installed skills plus the local marketplace: CLIO_CODER_SKILL_CATALOG_DIR,
|
|
31
37
|
a repo skills/ catalog, or the catalog and skill-marketplace.json index the
|
|
32
38
|
installed clio-coder package carries. Installing from the shipped catalog copies
|
|
@@ -249,6 +255,12 @@ function validationLoad(pathArg: string | undefined): ReturnType<typeof loadSkil
|
|
|
249
255
|
}
|
|
250
256
|
|
|
251
257
|
export async function runSkillsCommand(argv: ReadonlyArray<string>): Promise<number> {
|
|
258
|
+
// Routed before the shared parser so the fixed read stays exactly fixed: no
|
|
259
|
+
// skills flag can reach it, and no flag it does not name can be spent on it.
|
|
260
|
+
if (argv[0] === "inventory") {
|
|
261
|
+
const { runSkillsInventory } = await import("./skills-inventory.js");
|
|
262
|
+
return runSkillsInventory(argv.slice(1));
|
|
263
|
+
}
|
|
252
264
|
let parsed: Parsed;
|
|
253
265
|
try {
|
|
254
266
|
parsed = parse(argv);
|
|
@@ -365,19 +377,10 @@ export async function runSkillsCommand(argv: ReadonlyArray<string>): Promise<num
|
|
|
365
377
|
return 2;
|
|
366
378
|
}
|
|
367
379
|
const list = validationLoad(pathArg);
|
|
368
|
-
//
|
|
369
|
-
//
|
|
370
|
-
//
|
|
371
|
-
|
|
372
|
-
// is among the loaded skills and they do not fail validation.
|
|
373
|
-
const loadedPaths = new Set(list.items.map((skill) => skill.filePath));
|
|
374
|
-
const hasInvalidDiagnostic = list.diagnostics.some(
|
|
375
|
-
(diag) =>
|
|
376
|
-
diag.type === "error" ||
|
|
377
|
-
diag.type === "collision" ||
|
|
378
|
-
(diag.type === "warning" && diag.path !== undefined && !loadedPaths.has(diag.path)),
|
|
379
|
-
);
|
|
380
|
-
const ok = list.items.length > 0 && !hasInvalidDiagnostic;
|
|
380
|
+
// The rule itself lives in the loader, because `skills inspect --json`
|
|
381
|
+
// reports the same verdict to a GUI host and a verdict that drifts
|
|
382
|
+
// between the terminal and the browser is worse than no verdict.
|
|
383
|
+
const { ok } = skillCatalogValidity(list);
|
|
381
384
|
if (parsed.json) {
|
|
382
385
|
process.stdout.write(`${JSON.stringify({ ok, skills: list.items, diagnostics: list.diagnostics }, null, 2)}\n`);
|
|
383
386
|
} else {
|
package/src/cli/tools.ts
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { describeYaziProfile, inspectCurrentYaziProfile, resetYaziProfile } from "../domains/mux/index.js";
|
|
2
|
+
import {
|
|
3
|
+
describeFloorRejection,
|
|
4
|
+
describeResolution,
|
|
5
|
+
findPinnedTool,
|
|
6
|
+
installedToolVersions,
|
|
7
|
+
installRemedy,
|
|
8
|
+
installTool,
|
|
9
|
+
PINNED_TOOLS,
|
|
10
|
+
removeTool,
|
|
11
|
+
type ToolStatus,
|
|
12
|
+
toolStatus,
|
|
13
|
+
toolStatuses,
|
|
14
|
+
} from "../domains/toolchain/index.js";
|
|
15
|
+
import { formatColumns, printError, printOk } from "./shared.js";
|
|
16
|
+
|
|
17
|
+
const HELP = `clio-coder tools <command>
|
|
18
|
+
|
|
19
|
+
Manage the external terminal programs Clio can drive. Every one of them is
|
|
20
|
+
optional: Clio works without them and only uses one when it is present. Each is
|
|
21
|
+
pinned to an exact upstream version and checksum, and a copy already on PATH
|
|
22
|
+
wins over Clio's own as long as it clears the pinned minimum.
|
|
23
|
+
|
|
24
|
+
Commands:
|
|
25
|
+
clio-coder tools list [--json] the pinned table and where each resolves
|
|
26
|
+
clio-coder tools status <id> [--json] [--reset-profile] one tool in detail
|
|
27
|
+
clio-coder tools install <id> [--force] [--json] download, verify, and vendor a tool
|
|
28
|
+
clio-coder tools remove <id>|--all [--json] delete every vendored version of a tool
|
|
29
|
+
|
|
30
|
+
Downloads happen only here. Nothing on a startup path fetches anything.
|
|
31
|
+
|
|
32
|
+
An install keeps one version directory per tool: once the pinned version is in
|
|
33
|
+
place, versions it superseded are pruned, along with any staging directory left
|
|
34
|
+
by an install that was killed. Removal touches nothing outside <data>/tools/<id>
|
|
35
|
+
and needs no confirmation, since every byte under it is re-downloadable from the
|
|
36
|
+
checksum-pinned registry. "remove --all" sweeps every tool in the table.
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
interface Parsed {
|
|
40
|
+
command?: string;
|
|
41
|
+
positional: string[];
|
|
42
|
+
json: boolean;
|
|
43
|
+
force: boolean;
|
|
44
|
+
all: boolean;
|
|
45
|
+
resetProfile: boolean;
|
|
46
|
+
help: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function runToolsCommand(argv: ReadonlyArray<string> = []): Promise<number> {
|
|
50
|
+
let parsed: Parsed;
|
|
51
|
+
try {
|
|
52
|
+
parsed = parse(argv);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
printError(error instanceof Error ? error.message : String(error));
|
|
55
|
+
process.stderr.write(HELP);
|
|
56
|
+
return 2;
|
|
57
|
+
}
|
|
58
|
+
if (parsed.help || parsed.command === undefined) {
|
|
59
|
+
process.stdout.write(HELP);
|
|
60
|
+
return parsed.help ? 0 : 2;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// `--all` belongs to `remove` alone. Silently ignoring it elsewhere would let
|
|
64
|
+
// `tools install --all` read as a request that was honored.
|
|
65
|
+
if (parsed.all && parsed.command !== "remove") {
|
|
66
|
+
printError("--all is only valid with `tools remove`");
|
|
67
|
+
return 2;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
switch (parsed.command) {
|
|
71
|
+
case "list":
|
|
72
|
+
if (parsed.resetProfile) return invalidResetProfile();
|
|
73
|
+
return listTools(parsed.json);
|
|
74
|
+
case "status":
|
|
75
|
+
return statusTool(parsed.positional[0], parsed.json, parsed.resetProfile);
|
|
76
|
+
case "install":
|
|
77
|
+
if (parsed.resetProfile) return invalidResetProfile();
|
|
78
|
+
return installOne(parsed.positional[0], parsed.force, parsed.json);
|
|
79
|
+
case "remove":
|
|
80
|
+
if (parsed.resetProfile) return invalidResetProfile();
|
|
81
|
+
return parsed.all ? removeAll(parsed.positional[0], parsed.json) : removeOne(parsed.positional[0], parsed.json);
|
|
82
|
+
default:
|
|
83
|
+
printError(`unknown tools command: ${parsed.command}`);
|
|
84
|
+
process.stderr.write(HELP);
|
|
85
|
+
return 2;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function parse(argv: ReadonlyArray<string>): Parsed {
|
|
90
|
+
const out: Parsed = { positional: [], json: false, force: false, all: false, resetProfile: false, help: false };
|
|
91
|
+
for (const arg of argv) {
|
|
92
|
+
if (!out.command && !arg.startsWith("-")) {
|
|
93
|
+
out.command = arg;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
switch (arg) {
|
|
97
|
+
case "--json":
|
|
98
|
+
out.json = true;
|
|
99
|
+
break;
|
|
100
|
+
case "--force":
|
|
101
|
+
case "-f":
|
|
102
|
+
out.force = true;
|
|
103
|
+
break;
|
|
104
|
+
case "--all":
|
|
105
|
+
out.all = true;
|
|
106
|
+
break;
|
|
107
|
+
case "--reset-profile":
|
|
108
|
+
out.resetProfile = true;
|
|
109
|
+
break;
|
|
110
|
+
case "--help":
|
|
111
|
+
case "-h":
|
|
112
|
+
out.help = true;
|
|
113
|
+
break;
|
|
114
|
+
default:
|
|
115
|
+
if (arg.startsWith("-")) throw new Error(`unknown flag: ${arg}`);
|
|
116
|
+
out.positional.push(arg);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function listTools(json: boolean): number {
|
|
123
|
+
const statuses = toolStatuses();
|
|
124
|
+
if (json) {
|
|
125
|
+
process.stdout.write(`${JSON.stringify(statuses.map(jsonShape), null, 2)}\n`);
|
|
126
|
+
return 0;
|
|
127
|
+
}
|
|
128
|
+
const rows = statuses.map((status) => [
|
|
129
|
+
status.id,
|
|
130
|
+
status.version,
|
|
131
|
+
status.license,
|
|
132
|
+
status.resolution.source,
|
|
133
|
+
describeResolution(status),
|
|
134
|
+
]);
|
|
135
|
+
process.stdout.write(formatColumns([["TOOL", "PIN", "LICENSE", "SOURCE", "RESOLVED"], ...rows]));
|
|
136
|
+
return 0;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function invalidResetProfile(): number {
|
|
140
|
+
printError("--reset-profile is only valid with `tools status yazi`");
|
|
141
|
+
return 2;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* The one refusal an unknown id gets, from every verb.
|
|
146
|
+
*
|
|
147
|
+
* It names the tools that do exist, because the whole error an operator makes
|
|
148
|
+
* here is a name: `tools remove herd` and `tools remove tmux` want different
|
|
149
|
+
* answers, and the registry list gives both of them one.
|
|
150
|
+
*/
|
|
151
|
+
function unknownTool(id: string): number {
|
|
152
|
+
printError(`unknown tool: ${id} (known: ${PINNED_TOOLS.map((row) => row.id).join(", ")})`);
|
|
153
|
+
return 2;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function statusTool(id: string | undefined, json: boolean, resetProfile: boolean): number {
|
|
157
|
+
if (id === undefined) {
|
|
158
|
+
printError("usage: clio-coder tools status <id>");
|
|
159
|
+
return 2;
|
|
160
|
+
}
|
|
161
|
+
const entry = findPinnedTool(id);
|
|
162
|
+
if (entry === null) {
|
|
163
|
+
return unknownTool(id);
|
|
164
|
+
}
|
|
165
|
+
if (resetProfile && id !== "yazi") return invalidResetProfile();
|
|
166
|
+
if (resetProfile) resetYaziProfile();
|
|
167
|
+
const status = toolStatus(entry);
|
|
168
|
+
const profile = id === "yazi" ? inspectCurrentYaziProfile() : null;
|
|
169
|
+
if (json) {
|
|
170
|
+
process.stdout.write(
|
|
171
|
+
`${JSON.stringify({ ...jsonShape(status), ...(profile ? { profile, profileReset: resetProfile } : {}) }, null, 2)}\n`,
|
|
172
|
+
);
|
|
173
|
+
return 0;
|
|
174
|
+
}
|
|
175
|
+
const rejection = describeFloorRejection(status);
|
|
176
|
+
const installedVersions = installedToolVersions(entry.id);
|
|
177
|
+
const lines = [
|
|
178
|
+
`${entry.id} ${entry.version} (${entry.license})`,
|
|
179
|
+
` ${entry.summary}`,
|
|
180
|
+
` homepage ${entry.homepage}`,
|
|
181
|
+
` binaries ${entry.binaries.join(", ")}`,
|
|
182
|
+
` PATH floor ${entry.minimumVersion}`,
|
|
183
|
+
` platform ${status.platform ?? `${process.platform}-${process.arch}`}${status.supported ? "" : " (no pinned asset)"}`,
|
|
184
|
+
` vendor dir ${status.installDir}${status.installed ? "" : " (not installed)"}`,
|
|
185
|
+
` vendored ${installedVersions.length === 0 ? "nothing" : installedVersions.join(", ")}`,
|
|
186
|
+
` resolves to ${describeResolution(status)}`,
|
|
187
|
+
// Spelled out on its own line as well as inside the resolution sentence,
|
|
188
|
+
// because a rejected PATH copy is the one thing an operator reads this
|
|
189
|
+
// command to understand and the sentence above may be about something else.
|
|
190
|
+
...(rejection === null
|
|
191
|
+
? []
|
|
192
|
+
: [
|
|
193
|
+
` floor rejected: ${rejection}`,
|
|
194
|
+
...(status.resolution.source === "none" && status.supported ? [` remedy ${installRemedy(entry.id)}`] : []),
|
|
195
|
+
]),
|
|
196
|
+
...(profile
|
|
197
|
+
? [
|
|
198
|
+
` profile ${describeYaziProfile(profile)}`,
|
|
199
|
+
...(resetProfile ? [" profile reset; next open regenerates it"] : []),
|
|
200
|
+
]
|
|
201
|
+
: []),
|
|
202
|
+
];
|
|
203
|
+
process.stdout.write(`${lines.join("\n")}\n`);
|
|
204
|
+
return 0;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async function installOne(id: string | undefined, force: boolean, json: boolean): Promise<number> {
|
|
208
|
+
if (id === undefined) {
|
|
209
|
+
printError("usage: clio-coder tools install <id>");
|
|
210
|
+
return 2;
|
|
211
|
+
}
|
|
212
|
+
if (findPinnedTool(id) === null) {
|
|
213
|
+
return unknownTool(id);
|
|
214
|
+
}
|
|
215
|
+
const result = await installTool(id, {
|
|
216
|
+
force,
|
|
217
|
+
...(json ? {} : { onProgress: (message: string) => process.stderr.write(` ${message}\n`) }),
|
|
218
|
+
});
|
|
219
|
+
if (json) {
|
|
220
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
221
|
+
return result.ok ? 0 : 1;
|
|
222
|
+
}
|
|
223
|
+
if (!result.ok) {
|
|
224
|
+
printError(result.message);
|
|
225
|
+
return 1;
|
|
226
|
+
}
|
|
227
|
+
printOk(result.message);
|
|
228
|
+
for (const path of result.documents) process.stdout.write(` license ${path}\n`);
|
|
229
|
+
for (const version of result.pruned) process.stdout.write(` pruned ${id} ${version}\n`);
|
|
230
|
+
return 0;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Delete a tool's vendored install.
|
|
235
|
+
*
|
|
236
|
+
* The two answers an operator can act on are "there was nothing there" and
|
|
237
|
+
* "these versions are gone", and both are exit 0: the state they asked for
|
|
238
|
+
* holds either way. Only an id the registry does not know is a usage error,
|
|
239
|
+
* because that is the one case where nothing was inspected at all.
|
|
240
|
+
*/
|
|
241
|
+
function removeOne(id: string | undefined, json: boolean): number {
|
|
242
|
+
if (id === undefined) {
|
|
243
|
+
printError("usage: clio-coder tools remove <id>");
|
|
244
|
+
return 2;
|
|
245
|
+
}
|
|
246
|
+
if (findPinnedTool(id) === null) return unknownTool(id);
|
|
247
|
+
const result = removeTool(id);
|
|
248
|
+
if (json) {
|
|
249
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
250
|
+
return result.ok ? 0 : 1;
|
|
251
|
+
}
|
|
252
|
+
if (!result.ok) {
|
|
253
|
+
printError(result.message);
|
|
254
|
+
return 1;
|
|
255
|
+
}
|
|
256
|
+
printOk(result.message);
|
|
257
|
+
if (result.removed.length > 0) {
|
|
258
|
+
process.stdout.write(` reinstall with \`${installRemedy(id)}\`\n`);
|
|
259
|
+
}
|
|
260
|
+
return 0;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Delete every pinned tool's vendored install.
|
|
265
|
+
*
|
|
266
|
+
* Each tool is swept independently and the exit code is the worst of them, so
|
|
267
|
+
* one directory that resists deletion does not hide the two that came off
|
|
268
|
+
* cleanly. Tools that had nothing installed are counted rather than listed:
|
|
269
|
+
* on the machine this verb is for, most of the registry is usually absent, and
|
|
270
|
+
* three lines of "nothing to remove" would bury the one line that matters.
|
|
271
|
+
*/
|
|
272
|
+
function removeAll(id: string | undefined, json: boolean): number {
|
|
273
|
+
if (id !== undefined) {
|
|
274
|
+
printError("`tools remove --all` takes no tool id; drop the id or drop --all");
|
|
275
|
+
return 2;
|
|
276
|
+
}
|
|
277
|
+
const results = PINNED_TOOLS.map((entry) => removeTool(entry.id));
|
|
278
|
+
if (json) {
|
|
279
|
+
process.stdout.write(`${JSON.stringify(results, null, 2)}\n`);
|
|
280
|
+
return results.every((result) => result.ok) ? 0 : 1;
|
|
281
|
+
}
|
|
282
|
+
for (const result of results) {
|
|
283
|
+
if (!result.ok) printError(result.message);
|
|
284
|
+
else if (result.removed.length > 0 || result.staleStaging.length > 0) printOk(result.message);
|
|
285
|
+
}
|
|
286
|
+
const touched = results.filter((result) => result.ok && result.removed.length > 0);
|
|
287
|
+
const untouched = results.filter((result) => result.ok && result.removed.length === 0);
|
|
288
|
+
if (touched.length > 0) {
|
|
289
|
+
process.stdout.write(` reinstall with \`clio-coder tools install <id>\`\n`);
|
|
290
|
+
}
|
|
291
|
+
if (untouched.length > 0) {
|
|
292
|
+
process.stdout.write(` ${untouched.length} of ${results.length} had nothing vendored\n`);
|
|
293
|
+
}
|
|
294
|
+
return results.every((result) => result.ok) ? 0 : 1;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** The JSON surface, flattened so a script does not have to walk the resolution. */
|
|
298
|
+
function jsonShape(status: ToolStatus): Record<string, unknown> {
|
|
299
|
+
return {
|
|
300
|
+
id: status.id,
|
|
301
|
+
version: status.version,
|
|
302
|
+
license: status.license,
|
|
303
|
+
platform: status.platform,
|
|
304
|
+
supported: status.supported,
|
|
305
|
+
installed: status.installed,
|
|
306
|
+
installDir: status.installDir,
|
|
307
|
+
source: status.resolution.source,
|
|
308
|
+
binaryPath: status.resolution.binaryPath,
|
|
309
|
+
foundVersion: status.resolution.version,
|
|
310
|
+
minimumVersion: status.resolution.entry?.minimumVersion ?? null,
|
|
311
|
+
pathCandidate: status.resolution.pathCandidate,
|
|
312
|
+
// A script deciding whether to warn about a floor rejection should not have
|
|
313
|
+
// to parse `detail` for it, so the rejection and the command that answers
|
|
314
|
+
// it are their own fields. `remedy` is null exactly where installing would
|
|
315
|
+
// change nothing: already vendored, or no asset for this platform.
|
|
316
|
+
floorRejection: describeFloorRejection(status),
|
|
317
|
+
remedy: status.resolution.source === "none" && status.supported ? installRemedy(status.id) : null,
|
|
318
|
+
installedVersions: installedToolVersions(status.id),
|
|
319
|
+
detail: describeResolution(status),
|
|
320
|
+
};
|
|
321
|
+
}
|