@iowarp/clio-coder 0.4.2 → 0.4.3
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 +35 -0
- package/CONTRIBUTING.md +86 -19
- package/README.md +35 -6
- package/dist/{acp-TMDQZDIG.js → acp-H2NGRPWO.js} +11 -11
- package/dist/{agents-5N5NG3XG.js → agents-TL5LLUQP.js} +54 -53
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-Z5CCBXKQ.js → auth-E5SW4HMS.js} +19 -16
- package/dist/{builtins-K6TNDT24.js → builtins-IA7V7FUC.js} +9 -4
- package/dist/{chunk-ZW4HH5JJ.js → chunk-2APPQIER.js} +6 -6
- package/dist/{chunk-72GZI5EV.js → chunk-2JH2WHGE.js} +2 -2
- package/dist/{chunk-UBRFI4HS.js → chunk-2UG5F4C5.js} +127 -47
- package/dist/{chunk-UH632ZYL.js → chunk-2UH2KFUP.js} +2 -2
- package/dist/{chunk-3F7VUY77.js → chunk-2VIKGWFZ.js} +2 -2
- package/dist/{chunk-I66EAJFY.js → chunk-2WZ546HR.js} +267 -232
- package/dist/{chunk-RKSR6VSF.js → chunk-4IUZQIJ3.js} +29 -1
- package/dist/{chunk-2X4RYJTJ.js → chunk-4UVU7BJ5.js} +2 -2
- package/dist/{chunk-M2DAX4F6.js → chunk-4WR7VSYB.js} +2 -2
- package/dist/{chunk-5KW52TEP.js → chunk-54CBCGIR.js} +5 -5
- package/dist/{chunk-3KIPBMUA.js → chunk-5ICU3EUH.js} +2 -2
- package/dist/{chunk-77QIVUZB.js → chunk-5MEZN6CB.js} +4 -4
- package/dist/{chunk-O42A54GG.js → chunk-5OIVVPHF.js} +2 -2
- package/dist/{chunk-LJID3DYZ.js → chunk-64I3JVYM.js} +2 -2
- package/dist/{chunk-4JDLP6ZS.js → chunk-6PTFB5VS.js} +7 -7
- package/dist/{chunk-VN3SHNBN.js → chunk-7DICMOS6.js} +2 -2
- package/dist/{chunk-HLAFFSEK.js → chunk-7DRAWPTZ.js} +2 -2
- package/dist/chunk-7E7I3WLS.js +3762 -0
- package/dist/{chunk-YJISEZKC.js → chunk-7ZYNNDKC.js} +6 -6
- package/dist/{chunk-I66ZTYNP.js → chunk-AF4YM7Z4.js} +236 -101
- package/dist/{chunk-2HFQNRV3.js → chunk-AX2THNSA.js} +12 -12
- package/dist/{chunk-PGF63K6I.js → chunk-B4OAX3SI.js} +65 -3
- package/dist/{chunk-W6NIE6OW.js → chunk-B4VEBZKF.js} +3 -3
- package/dist/{chunk-JBCS7CRR.js → chunk-BEPZRGGU.js} +10 -10
- package/dist/{chunk-XGDPUNND.js → chunk-CE5AX47J.js} +2 -2
- package/dist/{chunk-I64IFBLB.js → chunk-DWUOQKRU.js} +17 -10
- package/dist/{chunk-DZAW46HP.js → chunk-E3TPLWFX.js} +3 -3
- package/dist/{chunk-HIICAHCJ.js → chunk-EKCHAPYA.js} +2 -2
- package/dist/{chunk-XE3PCIXH.js → chunk-F5JHEYZM.js} +7 -7
- package/dist/{chunk-5PFYMY2V.js → chunk-FTMGRKEF.js} +2 -2
- package/dist/{chunk-ZNT2M6TG.js → chunk-G76U63X4.js} +17 -17
- package/dist/{chunk-34BHNEE3.js → chunk-GHS5EBTQ.js} +58 -7
- package/dist/{chunk-2NHR3NAY.js → chunk-GI7YYQ3F.js} +40 -34
- package/dist/{chunk-DYHAXKHD.js → chunk-GWZNEVM2.js} +12 -8
- package/dist/chunk-GYV6VZOC.js +26 -0
- package/dist/{chunk-MQXIVJ35.js → chunk-HAXOFFRH.js} +5 -5
- package/dist/{chunk-W4YEMFBX.js → chunk-HEQY7ZFI.js} +2 -2
- package/dist/{chunk-IKOZFYBN.js → chunk-I7ZPNEJM.js} +145 -102
- package/dist/{chunk-WNP7O5WZ.js → chunk-ID64D7PE.js} +4 -4
- package/dist/{chunk-XQRY4DTA.js → chunk-IGLP3ODT.js} +10 -10
- package/dist/chunk-IJNZMHLA.js +101 -0
- package/dist/{chunk-JWJGP5DQ.js → chunk-INY6HTFL.js} +7 -7
- package/dist/{chunk-PBP4B7XR.js → chunk-IUE3Y34X.js} +2 -2
- package/dist/{chunk-B74PXLU7.js → chunk-IWT4SF4R.js} +3 -3
- package/dist/{chunk-B7HM5Z7T.js → chunk-JDAY6FIL.js} +5 -5
- package/dist/{chunk-PJX3WQUQ.js → chunk-JEQ3XTHC.js} +2 -2
- package/dist/{chunk-FSP7CMNU.js → chunk-JGRC33J2.js} +50 -4
- package/dist/{chunk-X7IARSHT.js → chunk-JKKCYP3C.js} +9 -9
- package/dist/{chunk-HJWWJ6IL.js → chunk-JSC3U7TI.js} +16 -4
- package/dist/{chunk-SSEYRH53.js → chunk-KK4JZPBQ.js} +19 -140
- package/dist/{chunk-IHXBNWMM.js → chunk-KXDSS5WJ.js} +7 -3
- package/dist/{chunk-Q4XWMHX6.js → chunk-L47TF46W.js} +2 -2
- package/dist/{chunk-O3YUNJZ2.js → chunk-LDJG7DW3.js} +81 -24
- package/dist/{chunk-CDNVLKUX.js → chunk-LLDJM5XK.js} +13 -7
- package/dist/{chunk-F2I26BDK.js → chunk-MUW2BDDH.js} +4 -4
- package/dist/{chunk-HKMD33FO.js → chunk-MWUZBSAQ.js} +79 -76
- package/dist/{chunk-QQLGQY2A.js → chunk-N2Z7HLVY.js} +20 -20
- package/dist/{chunk-DZEK6CJN.js → chunk-NIQJ66N4.js} +19 -19
- package/dist/{chunk-CWVRRIEI.js → chunk-NZMNUPZZ.js} +2 -2
- package/dist/{chunk-462T4EGZ.js → chunk-O5CVSAG5.js} +2 -2
- package/dist/{chunk-TPEQIQIE.js → chunk-OML5D5V5.js} +8 -8
- package/dist/{chunk-IKSLQ4XV.js → chunk-PAJQJ7BS.js} +558 -216
- package/dist/{chunk-ZW55JB7N.js → chunk-PUVDKJ2Y.js} +2 -2
- package/dist/{chunk-UH347SHR.js → chunk-QWGDJJYJ.js} +11 -11
- package/dist/chunk-R6Q67RJH.js +134 -0
- package/dist/{chunk-CRFOIAX3.js → chunk-RRNP2ANY.js} +6 -6
- package/dist/{chunk-IDNA72AH.js → chunk-RSJ25QSL.js} +2 -2
- package/dist/chunk-SKHCAU7K.js +385 -0
- package/dist/{chunk-RLYRBIYQ.js → chunk-TM6LQDI3.js} +20 -12
- package/dist/chunk-UOIZ7DA4.js +41 -0
- package/dist/{chunk-P75RZCJW.js → chunk-UPZU6GE4.js} +3 -3
- package/dist/{chunk-MCMZMDAC.js → chunk-V2ANDPVT.js} +4 -4
- package/dist/{chunk-AK5XEFVZ.js → chunk-VA5FNYMT.js} +26 -13
- package/dist/{chunk-IMXMHHMQ.js → chunk-VW6DOEDG.js} +332 -57
- package/dist/{chunk-XOXV5GKE.js → chunk-W6RRQCPQ.js} +16 -7
- package/dist/{chunk-CYZW7JHJ.js → chunk-WBKFA554.js} +8 -8
- package/dist/{chunk-BO7Y52RY.js → chunk-WCXUNS7U.js} +7 -7
- package/dist/{chunk-ZGNYYXQ6.js → chunk-WRBAGUNF.js} +3 -3
- package/dist/{chunk-FVDGR2ZL.js → chunk-XIVNBFZS.js} +85 -30
- package/dist/{chunk-BYMNWQ7O.js → chunk-XPWWI35G.js} +299 -58
- package/dist/{chunk-KPXDY6QF.js → chunk-XRZT5WY5.js} +2 -2
- package/dist/{chunk-AZ4WMN4W.js → chunk-Y3CBHOR6.js} +2 -2
- package/dist/{chunk-VXMFAE2W.js → chunk-YPC6ZR5L.js} +19 -6
- package/dist/{chunk-54ODD65L.js → chunk-YQWYVTMC.js} +4 -4
- package/dist/{chunk-M2WXEHER.js → chunk-ZA4VCIGV.js} +2 -2
- package/dist/{chunk-7BHIY2MW.js → chunk-ZDN3Y73Y.js} +6 -6
- package/dist/{chunk-E7GT7O5N.js → chunk-ZWPRK62N.js} +7 -4
- package/dist/cli/index.js +38 -37
- package/dist/{clio-7VB377CC.js → clio-CMMK4KRR.js} +7 -7
- package/dist/{code-nav-YVLCYA7V.js → code-nav-MDZNQS33.js} +7 -7
- package/dist/{components-UBWCQSRW.js → components-UCUQ4QXW.js} +4 -4
- package/dist/{config-4HVOS65E.js → config-SVM5P5YI.js} +76 -74
- package/dist/{configure-PIWO7B24.js → configure-LE3IK2TJ.js} +26 -24
- package/dist/{context-IYEHL3WQ.js → context-2OHRKS42.js} +66 -63
- package/dist/{context-N6ZE3LGJ.js → context-E3VC7RX5.js} +15 -11
- package/dist/{context-KQYIWPWT.js → context-VNCR7KAG.js} +60 -45
- package/dist/{context-clear-G4OGZJDS.js → context-clear-BW4O37TG.js} +61 -59
- package/dist/context-map-COB37XXN.js +505 -0
- package/dist/{context-working-set-BWLF6LJP.js → context-working-set-VDS25HXZ.js} +17 -16
- package/dist/{dispatch-runner-2QQAITS3.js → dispatch-runner-5AHT53RF.js} +85 -74
- package/dist/{doctor-LHBD36VU.js → doctor-WNNVO6FY.js} +37 -37
- package/dist/{eval-C45FYRJ6.js → eval-7G7SGAYO.js} +285 -114
- package/dist/{eval-inventory-6DEJPLBF.js → eval-inventory-Y6QRFOH5.js} +4 -4
- package/dist/{evidence-6SHONYAF.js → evidence-VD6736FQ.js} +63 -62
- package/dist/{evolve-KRKMV72X.js → evolve-AL3NGVRL.js} +62 -61
- package/dist/{extensions-KPZ2UHBB.js → extensions-MOVJ32NM.js} +7 -7
- package/dist/{fleet-IVTCKDHT.js → fleet-QZHUMAGI.js} +110 -108
- package/dist/{fleet-commands-EDWL3IT7.js → fleet-commands-BAYT5FJZ.js} +10 -10
- package/dist/{fleet-decisions-YP3YEFGK.js → fleet-decisions-IREVMRU4.js} +7 -6
- package/dist/{fleet-graph-ZFWKHY2M.js → fleet-graph-YCTT3HTI.js} +19 -18
- package/dist/{fleet-inspect-FVUNCBML.js → fleet-inspect-QVJTDAVB.js} +55 -54
- package/dist/{fleet-preflight-UN5XED4R.js → fleet-preflight-25QAFPK4.js} +4 -4
- package/dist/{fleet-validate-XOWC4HSX.js → fleet-validate-5O57AAJ7.js} +23 -22
- package/dist/{fleet-verify-UN3SODEL.js → fleet-verify-CPH2W2T6.js} +56 -55
- package/dist/{fleet-view-TWHJKCN6.js → fleet-view-SWBR3VGQ.js} +55 -54
- package/dist/{init-T2QORQ3Y.js → init-J477LKZH.js} +78 -76
- package/dist/{interop-IN5I2A66.js → interop-3FCM6XLG.js} +11 -11
- package/dist/{library-LSCATDLZ.js → library-QUQEIUG6.js} +28 -27
- package/dist/{memory-HYOKAGGJ.js → memory-SGGSEP65.js} +64 -63
- package/dist/{models-2GPMFYCM.js → models-HEKUAXXK.js} +49 -43
- package/dist/{monitor-E4ASVUJH.js → monitor-HKU57TYQ.js} +61 -60
- package/dist/{orchestrator-DDMPR3PY.js → orchestrator-VDFAEFAI.js} +919 -546
- package/dist/{panes-E3RUXOW5.js → panes-DN2SSFOH.js} +3 -3
- package/dist/{panes-IXKLOKA2.js → panes-TALGNPZT.js} +8 -8
- package/dist/{paths-L7LGY6RN.js → paths-NBMFAIEZ.js} +5 -5
- package/dist/reset-EAJFFJVB.js +344 -0
- package/dist/{resources-OTRSN34L.js → resources-OVKSEFVE.js} +27 -20
- package/dist/{run-5DEYH5QK.js → run-7DP7ZF2J.js} +113 -109
- package/dist/{share-IHWTLO3M.js → share-WML67FT3.js} +26 -25
- package/dist/{skills-IYMXMKW4.js → skills-SG662R2K.js} +39 -31
- package/dist/{skills-eval-DROHSJAR.js → skills-eval-VVZEUU46.js} +74 -73
- package/dist/{skills-inventory-D7X4L4ZX.js → skills-inventory-I2E23GET.js} +21 -20
- package/dist/{slash-commands-QBM7UZ3B.js → slash-commands-S7MBJDQK.js} +35 -34
- package/dist/{steer-Z5DO23FJ.js → steer-2LQOMCPB.js} +3 -3
- package/dist/{support-U7QOWY26.js → support-CC2UJBJ6.js} +6 -6
- package/dist/{targets-P2FUC4IL.js → targets-4QC3HIEW.js} +48 -45
- package/dist/{terminal-lease-YREJ3JX2.js → terminal-lease-TUHIJ6Y2.js} +2 -2
- package/dist/{tools-5B7RO6MV.js → tools-TFGJICCU.js} +8 -8
- package/dist/{trace-YMGMUM6A.js → trace-FXMXUZUF.js} +7 -7
- package/dist/uninstall-5PEVOE5B.js +408 -0
- package/dist/upgrade-M4WXY6KN.js +303 -0
- package/dist/{usage-ME5MPXGX.js → usage-N7ZNVLEM.js} +147 -102
- package/dist/{verifiers-BVZ7IWOO.js → verifiers-DJTP4XX6.js} +15 -15
- package/dist/{verify-5K7ZKQFC.js → verify-RWE4PPEK.js} +9 -9
- package/dist/{wiki-generate-F5W5QTYY.js → wiki-generate-C7IQOXSP.js} +84 -82
- package/dist/{with-panes-BYOJCLAM.js → with-panes-4GCGSL7J.js} +9 -9
- package/dist/worker/entry.js +61 -60
- package/docs/architecture/artifact-placement.md +1 -0
- package/docs/architecture/artifact-versions.md +1 -1
- package/docs/architecture/context-engine.md +4 -0
- package/docs/architecture/middleware-and-components.md +1 -1
- package/docs/architecture/model-catalog.md +21 -10
- package/docs/architecture/observability.md +12 -1
- package/docs/architecture/prompt-envelope-and-tools.md +2 -0
- package/docs/architecture/provider-adapter-cookbook.md +63 -0
- package/docs/architecture/safety-model.md +15 -5
- package/docs/guide/built-in-agents.md +17 -3
- package/docs/guide/commands-and-modes.md +1 -1
- package/docs/guide/configuration-and-targets.md +97 -9
- package/docs/guide/configuration-reference.md +7 -2
- package/docs/guide/environment-variables.md +2 -0
- package/docs/guide/installation-and-lifecycle.md +37 -4
- package/docs/guide/proactive-memory.md +66 -55
- package/docs/guide/skills-marketplace.md +18 -0
- package/docs/process/development-pipeline.md +34 -1
- package/docs/process/eval-runner.md +67 -3
- package/evals/behavioral-model.yaml +3 -2
- package/package.json +2 -2
- package/skills/README.md +7 -5
- package/skills/coding/ast-grep/SKILL.md +101 -30
- package/skills/coding/ast-grep/evals.md +26 -0
- package/skills/coding/coding-standards/SKILL.md +40 -5
- package/skills/coding/coding-standards/evals.md +23 -0
- package/skills/coding/prototype/SKILL.md +87 -28
- package/skills/coding/prototype/evals.md +19 -0
- package/skills/coding/tdd/SKILL.md +80 -53
- package/skills/coding/tdd/evals.md +20 -0
- package/skills/context/context-handoff/SKILL.md +43 -2
- package/skills/context/context-handoff/evals.md +44 -0
- package/skills/context/context-prime/SKILL.md +45 -15
- package/skills/context/context-prime/evals.md +45 -0
- package/skills/git/branch-closeout/SKILL.md +132 -0
- package/skills/git/branch-closeout/evals.md +133 -0
- package/skills/git/branch-closeout/references/closeout-checklist.md +81 -0
- package/skills/git/file-ticket/SKILL.md +77 -63
- package/skills/git/file-ticket/assets/issue-template.md +22 -0
- package/skills/git/file-ticket/evals.md +31 -26
- package/skills/git/file-ticket/references/issue-discovery.md +49 -0
- package/skills/git/fix-issue/SKILL.md +87 -64
- package/skills/git/fix-issue/evals.md +35 -31
- package/skills/git/fix-issue/references/diagnosis-and-rca.md +46 -0
- package/skills/git/resolve-merge-conflicts/SKILL.md +100 -51
- package/skills/git/resolve-merge-conflicts/evals.md +52 -25
- package/skills/git/resolve-merge-conflicts/references/conflict-matrix.md +126 -0
- package/skills/git/ship/SKILL.md +103 -67
- package/skills/git/ship/assets/pr-template.md +21 -0
- package/skills/git/ship/evals.md +44 -28
- package/skills/git/ship/references/remote-and-branch-policy.md +62 -0
- package/skills/git/worktree-create/SKILL.md +80 -50
- package/skills/git/worktree-create/evals.md +40 -33
- package/skills/git/worktree-create/references/worktree-setup.md +62 -66
- package/skills/git/worktree-merge/SKILL.md +112 -65
- package/skills/git/worktree-merge/evals.md +42 -34
- package/skills/git/worktree-merge/references/merge-strategies.md +52 -0
- package/skills/planning/archify/SKILL.md +196 -0
- package/skills/planning/archify/evals.md +65 -0
- package/skills/planning/architecture/SKILL.md +61 -12
- package/skills/planning/architecture/evals.md +65 -0
- package/skills/planning/backlog/SKILL.md +130 -14
- package/skills/planning/backlog/evals.md +142 -0
- package/skills/planning/prd/SKILL.md +46 -6
- package/skills/planning/prd/evals.md +54 -0
- package/skills/planning/product-intent/SKILL.md +57 -2
- package/skills/planning/product-intent/evals.md +70 -0
- package/skills/planning/tech-spec/SKILL.md +53 -2
- package/skills/planning/tech-spec/evals.md +73 -0
- package/skills/registry.yaml +58 -50
- package/skills/remote.yaml +13 -0
- package/skills/research/arxiv-literature/SKILL.md +76 -18
- package/skills/research/arxiv-literature/evals.md +50 -0
- package/skills/research/experiment-protocol/SKILL.md +20 -1
- package/skills/research/experiment-protocol/evals.md +23 -0
- package/skills/research/scientific-debugging/SKILL.md +23 -1
- package/skills/research/scientific-debugging/evals.md +18 -0
- package/skills/research/scientific-modernization/SKILL.md +26 -1
- package/skills/research/scientific-modernization/evals.md +27 -0
- package/skills/skill-marketplace.json +63 -28
- package/skills/workflow/cut-it/SKILL.md +65 -5
- package/skills/workflow/cut-it/evals.md +101 -0
- package/skills/workflow/design-council/SKILL.md +117 -27
- package/skills/workflow/design-council/evals.md +161 -0
- package/skills/workflow/grill-me/SKILL.md +86 -10
- package/skills/workflow/grill-me/evals.md +153 -0
- package/skills/workflow/workflow-distiller/SKILL.md +76 -17
- package/skills/workflow/workflow-distiller/evals.md +118 -0
- package/src/cli/configure-interop.ts +105 -13
- package/src/cli/configure-oauth.ts +57 -0
- package/src/cli/configure-onboarding.ts +980 -0
- package/src/cli/configure-target.ts +594 -0
- package/src/cli/configure.ts +1082 -528
- package/src/cli/context-map.ts +114 -0
- package/src/cli/context.ts +4 -0
- package/src/cli/index.ts +1 -0
- package/src/cli/lifecycle-presenter.ts +436 -0
- package/src/cli/models.ts +10 -2
- package/src/cli/modes/print.ts +5 -1
- package/src/cli/reset.ts +228 -106
- package/src/cli/run.ts +7 -2
- package/src/cli/select.ts +664 -0
- package/src/cli/skills.ts +9 -2
- package/src/cli/targets.ts +3 -0
- package/src/cli/uninstall.ts +233 -165
- package/src/cli/upgrade.ts +204 -149
- package/src/cli/usage.ts +86 -27
- package/src/cli/validate-model.ts +3 -3
- package/src/core/config.ts +56 -0
- package/src/core/external-diagnostic.ts +44 -0
- package/src/core/gateway-routing.ts +157 -0
- package/src/core/safe-exec.ts +17 -2
- package/src/core/skill-activation.ts +89 -2
- package/src/domains/agents/builtins/world-knowledge.md +31 -0
- package/src/domains/agents/catalog.ts +1 -1
- package/src/domains/agents/result-contract.ts +70 -0
- package/src/domains/context/wiki/map-seed.ts +589 -0
- package/src/domains/context/wiki/plan.ts +2 -2
- package/src/domains/dispatch/admission.ts +29 -0
- package/src/domains/dispatch/agent-candidates.ts +10 -0
- package/src/domains/dispatch/budget-envelope.ts +86 -1
- package/src/domains/dispatch/capability-match.ts +1 -0
- package/src/domains/dispatch/capacity-lease.ts +17 -0
- package/src/domains/dispatch/contract.ts +11 -1
- package/src/domains/dispatch/extension.ts +134 -29
- package/src/domains/dispatch/types.ts +3 -0
- package/src/domains/dispatch/worker-model-metadata.ts +38 -0
- package/src/domains/eval/metrics/call-ledger-stream.ts +34 -11
- package/src/domains/eval/metrics/token-stream.ts +201 -31
- package/src/domains/eval/metrics/tracked.ts +40 -4
- package/src/domains/eval/runners/clio-run.ts +5 -2
- package/src/domains/eval/schema/suite.ts +28 -0
- package/src/domains/eval/schema/verdict.ts +2 -2
- package/src/domains/eval/suites/resolve.ts +13 -1
- package/src/domains/eval/suites/run.ts +24 -3
- package/src/domains/interop/registry.ts +6 -2
- package/src/domains/interop/types.ts +4 -0
- package/src/domains/lifecycle/migrations/index.ts +4 -0
- package/src/domains/memory/task-memory-policy.ts +70 -26
- package/src/domains/memory/task-memory-telemetry.ts +1 -0
- package/src/domains/middleware/index.ts +0 -1
- package/src/domains/middleware/marketplace-offer.ts +3 -35
- package/src/domains/middleware/memory-intervention.ts +127 -32
- package/src/domains/middleware/memory-step-endpoint.ts +3 -2
- package/src/domains/middleware/skills-reminder.ts +31 -2
- package/src/domains/observability/compaction-usage.ts +118 -0
- package/src/domains/observability/cost.ts +1 -1
- package/src/domains/observability/extension.ts +6 -1
- package/src/domains/observability/out-of-turn-usage.ts +52 -21
- package/src/domains/providers/contract.ts +4 -1
- package/src/domains/providers/extension.ts +40 -9
- package/src/domains/providers/model-capabilities.ts +9 -0
- package/src/domains/providers/model-discovery.ts +2 -0
- package/src/domains/providers/model-runtime-capabilities.ts +15 -5
- package/src/domains/providers/models/local-models/clio-coder-local-coding-targets.yaml +32 -12
- package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +225 -45
- package/src/domains/providers/runtimes/common/lmstudio-http.ts +6 -2
- package/src/domains/providers/runtimes/common/local-synth.ts +2 -0
- package/src/domains/providers/runtimes/protocol/litellm.ts +119 -29
- package/src/domains/providers/support.ts +11 -5
- package/src/domains/providers/target-model-cache.ts +25 -2
- package/src/domains/providers/types/capability-flags.ts +2 -0
- package/src/domains/providers/types/runtime-descriptor.ts +20 -1
- package/src/domains/providers/types/target-descriptor.ts +19 -0
- package/src/domains/resources/index.ts +3 -0
- package/src/domains/resources/skills/install.ts +72 -7
- package/src/domains/resources/skills/loader.ts +7 -0
- package/src/domains/resources/skills/marketplace.ts +63 -11
- package/src/domains/safety/autonomy.ts +15 -0
- package/src/domains/safety/index.ts +1 -0
- package/src/domains/safety/path-policy.ts +1 -1
- package/src/domains/safety/policy-engine.ts +34 -11
- package/src/domains/safety/protected-artifacts.ts +191 -88
- package/src/domains/safety/run-effects.ts +2 -22
- package/src/domains/safety/skill-authority.ts +55 -0
- package/src/domains/session/compaction/compact.ts +72 -22
- package/src/domains/session/entries.ts +6 -0
- package/src/domains/session/usage.ts +3 -3
- package/src/engine/agent.ts +13 -3
- package/src/engine/ai.ts +26 -8
- package/src/engine/antigravity/subprocess-runtime.ts +386 -120
- package/src/engine/api-registry.ts +3 -0
- package/src/engine/apis/openai-completions.ts +117 -14
- package/src/engine/external-subprocess.ts +114 -6
- package/src/entry/background-model-metadata.ts +18 -0
- package/src/entry/compaction-prompt.ts +57 -0
- package/src/entry/orchestrator.ts +405 -216
- package/src/entry/task-memory-lifecycle.ts +35 -0
- package/src/interactive/chat-loop-messages.ts +13 -4
- package/src/interactive/chat-loop.ts +65 -2
- package/src/interactive/chat-renderer.ts +1 -0
- package/src/interactive/cost-overlay.ts +26 -2
- package/src/interactive/interactive-slash-runtime.ts +2 -1
- package/src/interactive/renderers/worker-entry.ts +32 -0
- package/src/interactive/slash-commands.ts +24 -6
- package/src/interactive/theme/labels.ts +19 -13
- package/src/interactive/turn-context.ts +9 -5
- package/src/interactive/turn-recovery.ts +8 -0
- package/src/interactive/turn-runtime.ts +27 -11
- package/src/interactive/turn-state.ts +7 -0
- package/src/interactive/worker-receipts.ts +1 -0
- package/src/interactive/worker-stream.ts +6 -1
- package/src/tools/context/index.ts +30 -9
- package/src/tools/dispatch-arguments.ts +1 -0
- package/src/tools/dispatch-event-text.ts +10 -0
- package/src/tools/dispatch-plan.ts +1 -0
- package/src/tools/dispatch-runner.ts +12 -0
- package/src/tools/registry.ts +11 -5
- package/src/tools/worker-evidence.ts +3 -1
- package/src/worker/spec-contract.ts +4 -0
- package/dist/chunk-2Z2IKEXI.js +0 -1554
- package/dist/reset-OAQP3W4O.js +0 -230
- package/dist/uninstall-N34PCTGJ.js +0 -331
- package/dist/upgrade-PXK3S2YM.js +0 -325
|
@@ -25,6 +25,7 @@ export interface TargetModelSnapshot {
|
|
|
25
25
|
runtimeId: string;
|
|
26
26
|
url: string | null;
|
|
27
27
|
models: string[];
|
|
28
|
+
modelLabels?: Record<string, string>;
|
|
28
29
|
observedAt: string;
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -32,6 +33,7 @@ interface TargetModelCacheOptions {
|
|
|
32
33
|
cacheDir?: string;
|
|
33
34
|
nowMs?: number;
|
|
34
35
|
ttlMs?: number;
|
|
36
|
+
modelLabels?: Readonly<Record<string, string>>;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
function targetCacheKey(targetId: string): string {
|
|
@@ -55,6 +57,22 @@ function normalizedModels(models: ReadonlyArray<string>): string[] {
|
|
|
55
57
|
return out;
|
|
56
58
|
}
|
|
57
59
|
|
|
60
|
+
function normalizedLabels(models: ReadonlyArray<string>, labels: unknown): Record<string, string> | undefined {
|
|
61
|
+
if (typeof labels !== "object" || labels === null || Array.isArray(labels)) return undefined;
|
|
62
|
+
const source = labels as Record<string, unknown>;
|
|
63
|
+
const out: Record<string, string> = {};
|
|
64
|
+
for (const id of models) {
|
|
65
|
+
const label = source[id];
|
|
66
|
+
if (typeof label !== "string") continue;
|
|
67
|
+
const trimmed = label.trim();
|
|
68
|
+
if (trimmed.length === 0 || trimmed.length > TARGET_MODEL_CACHE_MAX_MODEL_ID_CHARS || /[\r\n\0]/u.test(trimmed)) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
out[id] = trimmed;
|
|
72
|
+
}
|
|
73
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
58
76
|
function parseSnapshot(value: unknown): TargetModelSnapshot | null {
|
|
59
77
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
|
|
60
78
|
const row = value as Partial<TargetModelSnapshot>;
|
|
@@ -66,7 +84,7 @@ function parseSnapshot(value: unknown): TargetModelSnapshot | null {
|
|
|
66
84
|
if (typeof row.observedAt !== "string" || !Number.isFinite(Date.parse(row.observedAt))) return null;
|
|
67
85
|
const models = normalizedModels(row.models);
|
|
68
86
|
if (models.length !== row.models.length) return null;
|
|
69
|
-
|
|
87
|
+
const snapshot: TargetModelSnapshot = {
|
|
70
88
|
version: TARGET_MODEL_CACHE_VERSION,
|
|
71
89
|
targetId: row.targetId,
|
|
72
90
|
runtimeId: row.runtimeId,
|
|
@@ -74,6 +92,9 @@ function parseSnapshot(value: unknown): TargetModelSnapshot | null {
|
|
|
74
92
|
models,
|
|
75
93
|
observedAt: row.observedAt,
|
|
76
94
|
};
|
|
95
|
+
const modelLabels = normalizedLabels(models, row.modelLabels);
|
|
96
|
+
if (modelLabels !== undefined) snapshot.modelLabels = modelLabels;
|
|
97
|
+
return snapshot;
|
|
77
98
|
}
|
|
78
99
|
|
|
79
100
|
/** Read a fresh snapshot only when it still describes this target identity. */
|
|
@@ -102,7 +123,7 @@ export function readTargetModelSnapshot(
|
|
|
102
123
|
export function recordTargetModelSnapshot(
|
|
103
124
|
target: Pick<TargetDescriptor, "id" | "runtime" | "url">,
|
|
104
125
|
models: ReadonlyArray<string>,
|
|
105
|
-
options: Pick<TargetModelCacheOptions, "cacheDir" | "nowMs"> = {},
|
|
126
|
+
options: Pick<TargetModelCacheOptions, "cacheDir" | "nowMs" | "modelLabels"> = {},
|
|
106
127
|
): boolean {
|
|
107
128
|
if (target.id.length === 0 || target.runtime.length === 0) return false;
|
|
108
129
|
const snapshot: TargetModelSnapshot = {
|
|
@@ -113,6 +134,8 @@ export function recordTargetModelSnapshot(
|
|
|
113
134
|
models: normalizedModels(models),
|
|
114
135
|
observedAt: new Date(options.nowMs ?? Date.now()).toISOString(),
|
|
115
136
|
};
|
|
137
|
+
const modelLabels = normalizedLabels(snapshot.models, options.modelLabels);
|
|
138
|
+
if (modelLabels !== undefined) snapshot.modelLabels = modelLabels;
|
|
116
139
|
try {
|
|
117
140
|
safeResourceWrite(targetModelSnapshotPath(target.id, options.cacheDir), `${JSON.stringify(snapshot, null, 2)}\n`, {
|
|
118
141
|
encoding: "utf8",
|
|
@@ -20,6 +20,8 @@ export interface CapabilityFlags {
|
|
|
20
20
|
toolCallFormat?: ToolCallFormat;
|
|
21
21
|
reasoning: boolean;
|
|
22
22
|
thinkingFormat?: ThinkingFormat;
|
|
23
|
+
/** Probe-declared upstream control dialect only; never changes gateway routing or residency. */
|
|
24
|
+
thinkingControlRuntime?: "lmstudio" | "llamacpp";
|
|
23
25
|
structuredOutputs?: StructuredOutputMode;
|
|
24
26
|
vision: boolean;
|
|
25
27
|
audio: boolean;
|
|
@@ -22,7 +22,8 @@ export type RuntimeApiFamily =
|
|
|
22
22
|
| "rerank-http"
|
|
23
23
|
| "embeddings-http"
|
|
24
24
|
| "claude-agent-sdk"
|
|
25
|
-
| "claude-code-subprocess"
|
|
25
|
+
| "claude-code-subprocess"
|
|
26
|
+
| "external-agent-subprocess";
|
|
26
27
|
|
|
27
28
|
export type RuntimeAuth = "api-key" | "oauth" | "aws-sdk" | "vertex-adc" | "claude-cli" | "none";
|
|
28
29
|
|
|
@@ -93,8 +94,14 @@ export interface ProbeResult {
|
|
|
93
94
|
ok: boolean;
|
|
94
95
|
latencyMs?: number;
|
|
95
96
|
error?: string;
|
|
97
|
+
/** Set when `error` is specifically the server rejecting the credential, not a reachability failure. */
|
|
98
|
+
authFailed?: boolean;
|
|
96
99
|
serverVersion?: string;
|
|
97
100
|
models?: string[];
|
|
101
|
+
/** Human-readable labels keyed by the exact wire id returned in `models`. */
|
|
102
|
+
modelLabels?: Record<string, string>;
|
|
103
|
+
/** Stable cause class for setup UX; `error` remains the redacted human diagnostic. */
|
|
104
|
+
failureKind?: "missing" | "authentication" | "unsupported-feature" | "catalog-unavailable" | "cancelled" | "generic";
|
|
98
105
|
/** Probe-only per-model load state when the runtime exposes it. */
|
|
99
106
|
modelStates?: Record<string, ProbeModelStatus>;
|
|
100
107
|
discoveredCapabilities?: Partial<CapabilityFlags>;
|
|
@@ -155,6 +162,18 @@ export interface RuntimeDescriptor {
|
|
|
155
162
|
headlessCommand?: string;
|
|
156
163
|
outputParser?: string;
|
|
157
164
|
defaultCapabilities: CapabilityFlags;
|
|
165
|
+
/**
|
|
166
|
+
* Declares a black-box agent loop owned by an external executable. `tools`
|
|
167
|
+
* in CapabilityFlags stays false because Clio neither sends nor observes
|
|
168
|
+
* typed calls on this path; this field records the distinct external fact.
|
|
169
|
+
*/
|
|
170
|
+
externalAgentLoop?: {
|
|
171
|
+
tools: "externally-governed-unobserved";
|
|
172
|
+
network: "externally-governed-unobserved";
|
|
173
|
+
budget: "external-one-shot";
|
|
174
|
+
generatingRetry: "forbidden";
|
|
175
|
+
modelCatalog: "live-authoritative" | "static";
|
|
176
|
+
};
|
|
158
177
|
/**
|
|
159
178
|
* When true, this id is a real, distinct runtime (e.g. `llamacpp-anthropic`,
|
|
160
179
|
* the Anthropic Messages surface on llama.cpp, or the embed/rerank runtimes)
|
|
@@ -39,6 +39,24 @@ export interface LmStudioTargetSettings {
|
|
|
39
39
|
request?: LmStudioRequestSettings;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/** Per-request controls understood by a LiteLLM proxy. Values are optional so server policy remains authoritative by default. */
|
|
43
|
+
export interface LiteLLMRequestSettings {
|
|
44
|
+
/** Extra LiteLLM request tags. Clio always adds `clio-coder`. */
|
|
45
|
+
tags?: string[];
|
|
46
|
+
/** Forward Clio's stable session id as `x-litellm-session-id`. Defaults to true. */
|
|
47
|
+
sendSessionId?: boolean;
|
|
48
|
+
/** Override the proxy/upstream request timeout through `x-litellm-timeout`. */
|
|
49
|
+
timeoutSeconds?: number;
|
|
50
|
+
/** Override LiteLLM's streamed-response timeout through `x-litellm-stream-timeout`. */
|
|
51
|
+
streamTimeoutSeconds?: number;
|
|
52
|
+
/** Override LiteLLM router retries for this request; this does not enable client-side SDK retries. */
|
|
53
|
+
numRetries?: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface LiteLLMTargetSettings {
|
|
57
|
+
request?: LiteLLMRequestSettings;
|
|
58
|
+
}
|
|
59
|
+
|
|
42
60
|
/**
|
|
43
61
|
* Persisted target specification from settings.yaml (`targets:`). It binds a
|
|
44
62
|
* user-facing target id to a RuntimeDescriptor id, target URL/auth metadata,
|
|
@@ -57,6 +75,7 @@ export interface TargetDescriptor {
|
|
|
57
75
|
gateway?: boolean;
|
|
58
76
|
pricing?: TargetPricing;
|
|
59
77
|
lmstudio?: LmStudioTargetSettings;
|
|
78
|
+
litellm?: LiteLLMTargetSettings;
|
|
60
79
|
/** Explicit request-slot limit for this inference endpoint. It overrides live discovery. */
|
|
61
80
|
maxConcurrentRequests?: number;
|
|
62
81
|
}
|
|
@@ -67,6 +67,7 @@ export {
|
|
|
67
67
|
modelVisibleSkills,
|
|
68
68
|
parsePendingSkillRequests,
|
|
69
69
|
parseSkillCommand,
|
|
70
|
+
SKILL_SURFACE_CLEAR_ARG,
|
|
70
71
|
type Skill,
|
|
71
72
|
type SkillCatalogInvalidReason,
|
|
72
73
|
type SkillCatalogValidity,
|
|
@@ -89,6 +90,8 @@ export {
|
|
|
89
90
|
type MarketplaceSkill,
|
|
90
91
|
type MarketplaceSkillOrigin,
|
|
91
92
|
type MarketplaceStatus,
|
|
93
|
+
marketplaceInstallShaping,
|
|
94
|
+
resolveMarketplaceShaping,
|
|
92
95
|
} from "./skills/marketplace.js";
|
|
93
96
|
export {
|
|
94
97
|
checkSkillDrift,
|
|
@@ -40,6 +40,20 @@ export interface InstallSkillInput {
|
|
|
40
40
|
force?: boolean;
|
|
41
41
|
/** Override the Clio config dir used for the user root (testing). */
|
|
42
42
|
configDir?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Absolute path of a local directory whose files are copied over the fetched
|
|
45
|
+
* source before the install lands. Its SKILL.md becomes the installed skill
|
|
46
|
+
* text, so the provenance stamps and the pinned hash describe the overlay.
|
|
47
|
+
*/
|
|
48
|
+
overlay?: string;
|
|
49
|
+
/** Top-level names dropped from the fetched source before the overlay is applied. */
|
|
50
|
+
exclude?: string[];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The overlay and exclude list a marketplace entry attaches to a source URL. */
|
|
54
|
+
export interface SkillInstallShaping {
|
|
55
|
+
overlay?: string;
|
|
56
|
+
exclude?: string[];
|
|
43
57
|
}
|
|
44
58
|
|
|
45
59
|
export interface InstallSkillResult {
|
|
@@ -68,6 +82,12 @@ export interface UpdateSkillsInput {
|
|
|
68
82
|
all?: boolean;
|
|
69
83
|
/** Overwrite local modifications. */
|
|
70
84
|
force?: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Recovers the overlay and exclude list an installed skill was shaped with,
|
|
87
|
+
* keyed by its name and recorded source URL. Without it an update of a
|
|
88
|
+
* remote-entry skill would refetch bare upstream and drop the wrapper.
|
|
89
|
+
*/
|
|
90
|
+
resolveShaping?: (skill: { name: string; sourceUrl: string }) => SkillInstallShaping | undefined;
|
|
71
91
|
}
|
|
72
92
|
|
|
73
93
|
/**
|
|
@@ -252,17 +272,51 @@ function fetchSource(spec: SkillSourceSpec): FetchedSource {
|
|
|
252
272
|
}
|
|
253
273
|
}
|
|
254
274
|
|
|
255
|
-
function copySkillDir(from: string, to: string): void {
|
|
275
|
+
function copySkillDir(from: string, to: string, exclude: ReadonlyArray<string> = []): void {
|
|
256
276
|
mkdirSync(path.dirname(to), { recursive: true });
|
|
277
|
+
const excluded = new Set(exclude);
|
|
257
278
|
cpSync(from, to, {
|
|
258
279
|
recursive: true,
|
|
259
280
|
filter: (source) => {
|
|
260
281
|
const base = path.basename(source);
|
|
261
|
-
|
|
282
|
+
if (base === ".git" || base === "node_modules") return false;
|
|
283
|
+
// `exclude` names top-level members only, so a nested `test/` inside
|
|
284
|
+
// a renderer stays where the upstream package put it.
|
|
285
|
+
return !(excluded.size > 0 && path.dirname(source) === from && excluded.has(base));
|
|
262
286
|
},
|
|
263
287
|
});
|
|
264
288
|
}
|
|
265
289
|
|
|
290
|
+
/**
|
|
291
|
+
* Shape a fetched source the way a marketplace remote entry asks: drop the
|
|
292
|
+
* excluded top-level members, then lay the overlay's files on top. The result
|
|
293
|
+
* is a fresh temporary tree so the fetched source (which may be an operator's
|
|
294
|
+
* own local directory) is never modified, and validation runs against what
|
|
295
|
+
* will actually be installed.
|
|
296
|
+
*/
|
|
297
|
+
function shapeSource(fetched: FetchedSource, shaping: SkillInstallShaping): FetchedSource {
|
|
298
|
+
const exclude = shaping.exclude ?? [];
|
|
299
|
+
if (!shaping.overlay && exclude.length === 0) return fetched;
|
|
300
|
+
if (shaping.overlay && !existsSync(shaping.overlay)) {
|
|
301
|
+
fetched.cleanup();
|
|
302
|
+
throw new Error(`skill overlay directory does not exist: ${shaping.overlay}`);
|
|
303
|
+
}
|
|
304
|
+
const tmp = mkdtempSync(path.join(tmpdir(), "clio-coder-skill-shape-"));
|
|
305
|
+
const shaped = path.join(tmp, "skill");
|
|
306
|
+
const cleanup = (): void => {
|
|
307
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
308
|
+
fetched.cleanup();
|
|
309
|
+
};
|
|
310
|
+
try {
|
|
311
|
+
copySkillDir(fetched.skillDir, shaped, exclude);
|
|
312
|
+
if (shaping.overlay) copySkillDir(shaping.overlay, shaped);
|
|
313
|
+
return { skillDir: resolveSkillDir(shaped), cleanup };
|
|
314
|
+
} catch (err) {
|
|
315
|
+
cleanup();
|
|
316
|
+
throw err instanceof Error ? err : new Error(String(err));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
266
320
|
let skillSwapSequence = 0;
|
|
267
321
|
|
|
268
322
|
/**
|
|
@@ -328,7 +382,7 @@ export function installSkillFromSource(input: InstallSkillInput): InstallSkillRe
|
|
|
328
382
|
const cwd = input.cwd ?? process.cwd();
|
|
329
383
|
const scope = input.scope ?? "project";
|
|
330
384
|
|
|
331
|
-
const fetched = fetchSource(spec);
|
|
385
|
+
const fetched = shapeSource(fetchSource(spec), input);
|
|
332
386
|
try {
|
|
333
387
|
const { skill, warnings } = validateSourceSkill(fetched.skillDir);
|
|
334
388
|
const name = (input.name ?? skill.name).trim();
|
|
@@ -385,13 +439,18 @@ function managedSkills(cwd: string, configDir?: string): Skill[] {
|
|
|
385
439
|
);
|
|
386
440
|
}
|
|
387
441
|
|
|
388
|
-
function updateOne(skill: Skill, force: boolean): SkillUpdateReport {
|
|
442
|
+
function updateOne(skill: Skill, force: boolean, shaping: SkillInstallShaping = {}): SkillUpdateReport {
|
|
389
443
|
const sourceUrl = skill.provenance?.installUrl;
|
|
390
444
|
if (!sourceUrl) return { name: skill.name, status: "no-source", detail: "no source-url provenance recorded" };
|
|
391
445
|
const spec = parseSkillSourceSpec(sourceUrl);
|
|
392
446
|
if (!spec) return { name: skill.name, status: "error", detail: `unsupported source-url: ${sourceUrl}` };
|
|
393
447
|
|
|
394
|
-
|
|
448
|
+
let fetched: FetchedSource;
|
|
449
|
+
try {
|
|
450
|
+
fetched = shapeSource(fetchSource(spec), shaping);
|
|
451
|
+
} catch (err) {
|
|
452
|
+
return { name: skill.name, status: "error", detail: err instanceof Error ? err.message : String(err) };
|
|
453
|
+
}
|
|
395
454
|
try {
|
|
396
455
|
// The same gate a fresh install passes. Upstream may have moved on to a
|
|
397
456
|
// SKILL.md that no longer loads, and without this an update replaces a
|
|
@@ -441,11 +500,17 @@ function updateOne(skill: Skill, force: boolean): SkillUpdateReport {
|
|
|
441
500
|
export function updateSkills(input: UpdateSkillsInput = {}): SkillUpdateReport[] {
|
|
442
501
|
const cwd = input.cwd ?? process.cwd();
|
|
443
502
|
const skills = managedSkills(cwd, input.configDir);
|
|
503
|
+
const shapingFor = (skill: Skill): SkillInstallShaping =>
|
|
504
|
+
(skill.provenance?.installUrl &&
|
|
505
|
+
input.resolveShaping?.({ name: skill.name, sourceUrl: skill.provenance.installUrl })) ||
|
|
506
|
+
{};
|
|
444
507
|
if (input.name) {
|
|
445
508
|
const skill = skills.find((entry) => entry.name === input.name);
|
|
446
509
|
if (!skill) return [{ name: input.name, status: "error", detail: "not found in Clio-managed skill roots" }];
|
|
447
|
-
return [updateOne(skill, input.force === true)];
|
|
510
|
+
return [updateOne(skill, input.force === true, shapingFor(skill))];
|
|
448
511
|
}
|
|
449
512
|
if (input.all !== true) throw new Error("updateSkills requires a name or all=true");
|
|
450
|
-
return skills
|
|
513
|
+
return skills
|
|
514
|
+
.filter((skill) => skill.provenance?.installUrl)
|
|
515
|
+
.map((skill) => updateOne(skill, input.force === true, shapingFor(skill)));
|
|
451
516
|
}
|
|
@@ -949,6 +949,13 @@ export function skillCatalogValidity(list: SkillList): SkillCatalogValidity {
|
|
|
949
949
|
return { ok: true, reason: null };
|
|
950
950
|
}
|
|
951
951
|
|
|
952
|
+
/**
|
|
953
|
+
* The one argument `/skill` reserves for itself: `/skill off` clears the tool
|
|
954
|
+
* surface an activated skill armed for the session instead of loading a skill
|
|
955
|
+
* by that name.
|
|
956
|
+
*/
|
|
957
|
+
export const SKILL_SURFACE_CLEAR_ARG = "off";
|
|
958
|
+
|
|
952
959
|
export function parseSkillCommand(input: string): { name: string; args: string } | null {
|
|
953
960
|
const trimmed = input.trim();
|
|
954
961
|
if (!trimmed.startsWith("/skill ")) return null;
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
installSkillFromSource,
|
|
10
10
|
isSkillName,
|
|
11
11
|
parseSkillSourceSpec,
|
|
12
|
+
type SkillInstallShaping,
|
|
12
13
|
} from "./install.js";
|
|
13
14
|
import { loadSkills, type Skill } from "./loader.js";
|
|
14
15
|
|
|
@@ -60,6 +61,14 @@ export interface MarketplaceSkill {
|
|
|
60
61
|
triggers?: string[];
|
|
61
62
|
origin: MarketplaceSkillOrigin;
|
|
62
63
|
requires?: LibraryRequirementRef[];
|
|
64
|
+
/**
|
|
65
|
+
* Remote entry: a package-root-relative directory whose files are copied
|
|
66
|
+
* over the fetched upstream tree at install. Clio owns only the overlay
|
|
67
|
+
* (typically a wrapper SKILL.md); the upstream renderer is never vendored.
|
|
68
|
+
*/
|
|
69
|
+
overlay?: string;
|
|
70
|
+
/** Remote entry: top-level upstream members dropped at install. */
|
|
71
|
+
exclude?: string[];
|
|
63
72
|
}
|
|
64
73
|
|
|
65
74
|
export type MarketplaceStatus = "installed" | "installable" | "unavailable";
|
|
@@ -181,6 +190,12 @@ function parseMarketplaceIndex(indexPath: string, diagnostics: string[] = []): M
|
|
|
181
190
|
const requires = Array.isArray(record.requires)
|
|
182
191
|
? record.requires.filter((entry): entry is LibraryRequirementRef => typeof entry === "string")
|
|
183
192
|
: undefined;
|
|
193
|
+
const overlay = optionalString(record.overlay);
|
|
194
|
+
if (overlay && (path.isAbsolute(overlay) || overlay.split("/").includes(".."))) {
|
|
195
|
+
diagnostics.push(`skill marketplace index entry has an overlay outside the package: ${skill.name}`);
|
|
196
|
+
return [];
|
|
197
|
+
}
|
|
198
|
+
const exclude = optionalTriggerList(record.exclude);
|
|
184
199
|
return [
|
|
185
200
|
{
|
|
186
201
|
kind,
|
|
@@ -192,6 +207,8 @@ function parseMarketplaceIndex(indexPath: string, diagnostics: string[] = []): M
|
|
|
192
207
|
...(category ? { category } : {}),
|
|
193
208
|
...(triggers ? { triggers } : {}),
|
|
194
209
|
...(requires ? { requires } : {}),
|
|
210
|
+
...(overlay ? { overlay } : {}),
|
|
211
|
+
...(exclude ? { exclude } : {}),
|
|
195
212
|
origin: "index" as const,
|
|
196
213
|
},
|
|
197
214
|
];
|
|
@@ -284,25 +301,32 @@ export function discoverMarketplaceSkills(options: DiscoverMarketplaceOptions =
|
|
|
284
301
|
const skills: MarketplaceSkill[] = [];
|
|
285
302
|
const seen = new Set<string>();
|
|
286
303
|
|
|
304
|
+
const indexPath =
|
|
305
|
+
options.indexPath === null ? null : (options.indexPath ?? process.env.CLIO_CODER_SKILL_MARKETPLACE_INDEX ?? null);
|
|
306
|
+
const resolvedIndexPath = indexPath ?? defaultIndexPath();
|
|
307
|
+
const indexSkills =
|
|
308
|
+
options.indexPath !== null && resolvedIndexPath && existsSync(resolvedIndexPath)
|
|
309
|
+
? parseMarketplaceIndex(resolvedIndexPath, diagnostics)
|
|
310
|
+
: [];
|
|
311
|
+
// A remote entry's overlay folder is also a catalog package on disk, but
|
|
312
|
+
// installing that folder alone would land the wrapper without the upstream
|
|
313
|
+
// it wraps. The index entry that names the overlay is the whole skill.
|
|
314
|
+
const overlayNames = new Set(indexSkills.filter((skill) => skill.overlay).map((skill) => skill.name));
|
|
315
|
+
|
|
287
316
|
// Catalog packages first: real local files beat index pointers on name collisions.
|
|
288
317
|
const catalogDir = resolveCatalogDir(options);
|
|
289
318
|
if (catalogDir) {
|
|
290
319
|
for (const skill of catalogSkills(catalogDir, diagnostics)) {
|
|
291
|
-
if (seen.has(skill.name)) continue;
|
|
320
|
+
if (seen.has(skill.name) || overlayNames.has(skill.name)) continue;
|
|
292
321
|
seen.add(skill.name);
|
|
293
322
|
skills.push(skill);
|
|
294
323
|
}
|
|
295
324
|
}
|
|
296
325
|
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
for (const skill of parseMarketplaceIndex(resolvedIndexPath, diagnostics)) {
|
|
302
|
-
if (seen.has(skill.name)) continue;
|
|
303
|
-
seen.add(skill.name);
|
|
304
|
-
skills.push(skill);
|
|
305
|
-
}
|
|
326
|
+
for (const skill of indexSkills) {
|
|
327
|
+
if (seen.has(skill.name)) continue;
|
|
328
|
+
seen.add(skill.name);
|
|
329
|
+
skills.push(skill);
|
|
306
330
|
}
|
|
307
331
|
|
|
308
332
|
if (skills.length === 0 && diagnostics.length === 0) {
|
|
@@ -315,6 +339,34 @@ export function getMarketplaceSkills(options: DiscoverMarketplaceOptions = {}):
|
|
|
315
339
|
return discoverMarketplaceSkills(options).skills;
|
|
316
340
|
}
|
|
317
341
|
|
|
342
|
+
/**
|
|
343
|
+
* The install shaping a marketplace entry carries, with its overlay resolved
|
|
344
|
+
* to an absolute directory under the package root. An entry with neither
|
|
345
|
+
* field shapes nothing, so the caller can spread the result unconditionally.
|
|
346
|
+
*/
|
|
347
|
+
export function marketplaceInstallShaping(skill: MarketplaceSkill): SkillInstallShaping {
|
|
348
|
+
const shaping: SkillInstallShaping = {};
|
|
349
|
+
if (skill.overlay) shaping.overlay = path.join(resolvePackageRoot(), skill.overlay);
|
|
350
|
+
if (skill.exclude && skill.exclude.length > 0) shaping.exclude = [...skill.exclude];
|
|
351
|
+
return shaping;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Recover the shaping for an installed skill by name and recorded source URL,
|
|
356
|
+
* for `updateSkills`. Only a marketplace entry that still points at the same
|
|
357
|
+
* upstream URL applies; a skill installed from a URL the index no longer
|
|
358
|
+
* carries updates bare, as it was installed.
|
|
359
|
+
*/
|
|
360
|
+
export function resolveMarketplaceShaping(options: DiscoverMarketplaceOptions = {}) {
|
|
361
|
+
return (installed: { name: string; sourceUrl: string }): SkillInstallShaping | undefined => {
|
|
362
|
+
const entry = getMarketplaceSkills(options).find(
|
|
363
|
+
(skill) => skill.name === installed.name && skill.sourceUrl === installed.sourceUrl,
|
|
364
|
+
);
|
|
365
|
+
if (!entry || (!entry.overlay && !entry.exclude)) return undefined;
|
|
366
|
+
return marketplaceInstallShaping(entry);
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
318
370
|
/**
|
|
319
371
|
* The single install entry point for every frontend (headless CLI, TUI
|
|
320
372
|
* pending-skill prompt, skills hub). Source resolution, in precedence order:
|
|
@@ -339,7 +391,7 @@ export function installSkill(input: InstallSkillInput): InstallSkillResult {
|
|
|
339
391
|
if (!skill) {
|
|
340
392
|
throw new Error(`"${source}" is neither an existing local path nor available in the local marketplace`);
|
|
341
393
|
}
|
|
342
|
-
return installSkillFromSource({ ...input, source: skill.sourceUrl });
|
|
394
|
+
return installSkillFromSource({ ...input, ...marketplaceInstallShaping(skill), source: skill.sourceUrl });
|
|
343
395
|
}
|
|
344
396
|
return installSkillFromSource({ ...input, source });
|
|
345
397
|
}
|
|
@@ -68,6 +68,21 @@ export interface AutonomyMappingOptions {
|
|
|
68
68
|
exposure?: AutonomyExposure;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Whether the model may activate an installed skill itself rather than
|
|
73
|
+
* emitting the suggestion anchor and waiting for the operator to type
|
|
74
|
+
* `/skill <name>`.
|
|
75
|
+
*
|
|
76
|
+
* At `read-only` and `suggest` the operator asked to be consulted before the
|
|
77
|
+
* agent acts, and activation is an action. At `auto-edit` and `full-auto` they
|
|
78
|
+
* already said otherwise, and a skill can only narrow the tool surface, never
|
|
79
|
+
* widen it, so the gate buys no safety there. The level is the opt-in; there is
|
|
80
|
+
* no per-skill frontmatter flag for this.
|
|
81
|
+
*/
|
|
82
|
+
export function modelMayActivateSkills(level: AutonomyLevel): boolean {
|
|
83
|
+
return level === "auto-edit" || level === "full-auto";
|
|
84
|
+
}
|
|
85
|
+
|
|
71
86
|
/**
|
|
72
87
|
* The §2.3 level-dependent matrix. `git_destructive` never reaches this
|
|
73
88
|
* mapping in practice (the safety net blocks it first); it maps to deny
|
|
@@ -41,7 +41,7 @@ export function isSameOrDescendant(candidatePath: string, policyPath: string): b
|
|
|
41
41
|
const candidate = path.resolve(candidatePath);
|
|
42
42
|
const policy = path.resolve(policyPath);
|
|
43
43
|
const relative = path.relative(policy, candidate);
|
|
44
|
-
return relative === "" || (!relative.startsWith(
|
|
44
|
+
return relative === "" || (relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative));
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
function expandTilde(rawPath: string): string {
|
|
@@ -25,10 +25,12 @@ import {
|
|
|
25
25
|
extractCommandDeleteTargets,
|
|
26
26
|
extractCommandWriteTargets,
|
|
27
27
|
inlineShellScript,
|
|
28
|
-
|
|
28
|
+
invokesClioSkillMutation,
|
|
29
|
+
scanShellLike,
|
|
29
30
|
} from "./protected-artifacts.js";
|
|
30
31
|
import { formatRejection, type RejectionMessage } from "./rejection-feedback.js";
|
|
31
32
|
import { getCachedDefaultRulePacks, type PackId, type RulePacks } from "./rule-pack-loader.js";
|
|
33
|
+
import { activeClioSkillRoots, skillMutationReason } from "./skill-authority.js";
|
|
32
34
|
|
|
33
35
|
export type SafetyPolicySource =
|
|
34
36
|
| "damage-control:base"
|
|
@@ -194,6 +196,7 @@ export function createSafetyPolicyEngine(options: SafetyPolicyEngineOptions = {}
|
|
|
194
196
|
// cwd and roots to compare like against like (the design mandates no symlink chasing).
|
|
195
197
|
const writeRootCwd = path.resolve(options.cwd ?? process.cwd());
|
|
196
198
|
const writeRoots = (options.writeRoots ?? []).map((root) => resolvePathBoundary(writeRootCwd, root));
|
|
199
|
+
const skillRoots = activeClioSkillRoots(cwd);
|
|
197
200
|
const packs = options.rulePacks ?? getCachedDefaultRulePacks();
|
|
198
201
|
const projectPolicy = options.projectPolicy ?? loadProjectSafetyPolicy(cwd);
|
|
199
202
|
const projectPolicyRoot =
|
|
@@ -308,6 +311,27 @@ export function createSafetyPolicyEngine(options: SafetyPolicyEngineOptions = {}
|
|
|
308
311
|
return blockDecision(base, blockInput);
|
|
309
312
|
}
|
|
310
313
|
|
|
314
|
+
// Editing active instructions is an operator privilege at every autonomy
|
|
315
|
+
// level, in both the coordinator and the shared worker safety contract.
|
|
316
|
+
const mutationCommand = call.tool === ToolNames.Bash ? command : catalogCommand;
|
|
317
|
+
const skillReason =
|
|
318
|
+
mutationCommand !== null && invokesClioSkillMutation(mutationCommand)
|
|
319
|
+
? "skill installation and updates require the operator CLI or an explicit operator install choice; draft outside active skill roots"
|
|
320
|
+
: skillMutationReason(
|
|
321
|
+
skillRoots,
|
|
322
|
+
pathPolicyTargets(catalogCommand === null ? call : { tool: ToolNames.Bash, args: { command: catalogCommand } }),
|
|
323
|
+
callCwd,
|
|
324
|
+
mutationCommand,
|
|
325
|
+
);
|
|
326
|
+
if (skillReason !== null) {
|
|
327
|
+
return blockDecision(base, {
|
|
328
|
+
ruleId: "skill-authority",
|
|
329
|
+
reasonCode: "skill-authority",
|
|
330
|
+
reasons: [skillReason],
|
|
331
|
+
policySource: "builtin-classifier",
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
|
|
311
335
|
// The path policy runs regardless of project policy validity. When
|
|
312
336
|
// `.clio-coder/safety.yaml` is invalid, the loader has already dropped every
|
|
313
337
|
// project-authored path entry and forced `disableDefaultPathPolicy`
|
|
@@ -488,10 +512,10 @@ function stripQuotes(token: string): string {
|
|
|
488
512
|
*/
|
|
489
513
|
function bashPathTokenCandidates(command: string): string[] {
|
|
490
514
|
const candidates: string[] = [];
|
|
491
|
-
for (const
|
|
515
|
+
for (const scanned of scanShellLike(command)) {
|
|
516
|
+
if (scanned.operator) continue;
|
|
517
|
+
const token = scanned.value;
|
|
492
518
|
if (token.length === 0) continue;
|
|
493
|
-
if (token === ";" || token === "&&" || token === "||" || token === "|" || token === ">" || token === ">>") continue;
|
|
494
|
-
if (token === "<" || token === "<<") continue;
|
|
495
519
|
// A token containing whitespace came from a quoted string of prose, not
|
|
496
520
|
// a path argument; and flags are not paths unless they embed one
|
|
497
521
|
// (--file=~/.aws/credentials).
|
|
@@ -821,9 +845,6 @@ function matchingProjectCommand(
|
|
|
821
845
|
return null;
|
|
822
846
|
}
|
|
823
847
|
|
|
824
|
-
/** Operators that end chain recognition; only `&&` keeps a chain readable. */
|
|
825
|
-
const CHAIN_BREAKING_TOKENS: ReadonlySet<string> = new Set([";", "|", "||", ">", ">>", "<", "<<"]);
|
|
826
|
-
|
|
827
848
|
/** Chain length ceiling. Real compound calls are two or three steps. */
|
|
828
849
|
const CHAIN_MAX_SEGMENTS = 6;
|
|
829
850
|
|
|
@@ -856,14 +877,16 @@ function recognizeCommandChain(
|
|
|
856
877
|
): ChainRecognition | null {
|
|
857
878
|
const segments: string[][] = [];
|
|
858
879
|
let current: string[] = [];
|
|
859
|
-
for (const token of
|
|
860
|
-
if (token === "&&") {
|
|
880
|
+
for (const token of scanShellLike(command)) {
|
|
881
|
+
if (token.operator && token.value === "&&") {
|
|
861
882
|
segments.push(current);
|
|
862
883
|
current = [];
|
|
863
884
|
continue;
|
|
864
885
|
}
|
|
865
|
-
|
|
866
|
-
|
|
886
|
+
// Only an actual && operator joins recognizable commands. Quoted words
|
|
887
|
+
// remain argv and every other real operator makes this chain unrecognized.
|
|
888
|
+
if (token.operator) return null;
|
|
889
|
+
current.push(token.value);
|
|
867
890
|
}
|
|
868
891
|
segments.push(current);
|
|
869
892
|
if (segments.length < 2 || segments.length > CHAIN_MAX_SEGMENTS) return null;
|