@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
package/src/cli/usage.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
} from "../core/response-model-id.js";
|
|
9
9
|
import { clioDataDir, clioStateDir } from "../core/xdg.js";
|
|
10
10
|
import { loadMemoryRecordsSync, type MemoryRecord } from "../domains/memory/index.js";
|
|
11
|
+
import { summarizeFailedCompactionUsage } from "../domains/observability/compaction-usage.js";
|
|
11
12
|
import { readEvidenceIndex } from "../domains/observability/evidence-index.js";
|
|
12
13
|
import { type OutOfTurnUsageRow, readOutOfTurnUsageRows } from "../domains/observability/out-of-turn-usage.js";
|
|
13
14
|
import { loadSkills } from "../domains/resources/index.js";
|
|
@@ -119,18 +120,32 @@ interface CallOrigins {
|
|
|
119
120
|
handoffs: number;
|
|
120
121
|
prewarms: number;
|
|
121
122
|
backgroundMemory: number;
|
|
123
|
+
failedCompaction: number;
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
function emptyCallOrigins(): CallOrigins {
|
|
125
|
-
return { rows: 0, sideQuestions: 0, handoffs: 0, prewarms: 0, backgroundMemory: 0 };
|
|
127
|
+
return { rows: 0, sideQuestions: 0, handoffs: 0, prewarms: 0, backgroundMemory: 0, failedCompaction: 0 };
|
|
126
128
|
}
|
|
127
129
|
|
|
128
130
|
function turnsOf(origins: CallOrigins): number {
|
|
129
|
-
return
|
|
131
|
+
return (
|
|
132
|
+
origins.rows -
|
|
133
|
+
origins.sideQuestions -
|
|
134
|
+
origins.handoffs -
|
|
135
|
+
origins.prewarms -
|
|
136
|
+
origins.backgroundMemory -
|
|
137
|
+
origins.failedCompaction
|
|
138
|
+
);
|
|
130
139
|
}
|
|
131
140
|
|
|
132
141
|
function hasLabelledCall(origins: CallOrigins): boolean {
|
|
133
|
-
return
|
|
142
|
+
return (
|
|
143
|
+
origins.sideQuestions > 0 ||
|
|
144
|
+
origins.handoffs > 0 ||
|
|
145
|
+
origins.prewarms > 0 ||
|
|
146
|
+
origins.backgroundMemory > 0 ||
|
|
147
|
+
origins.failedCompaction > 0
|
|
148
|
+
);
|
|
134
149
|
}
|
|
135
150
|
|
|
136
151
|
function addOutOfTurnRow(origins: CallOrigins, row: OutOfTurnUsageRow): void {
|
|
@@ -138,6 +153,7 @@ function addOutOfTurnRow(origins: CallOrigins, row: OutOfTurnUsageRow): void {
|
|
|
138
153
|
if (row.label === "side-question") origins.sideQuestions += 1;
|
|
139
154
|
else if (row.label === "prewarm") origins.prewarms += 1;
|
|
140
155
|
else if (row.label === "background-memory") origins.backgroundMemory += 1;
|
|
156
|
+
else if (row.label === "failed-compaction") origins.failedCompaction += 1;
|
|
141
157
|
else origins.handoffs += 1;
|
|
142
158
|
}
|
|
143
159
|
|
|
@@ -148,16 +164,32 @@ function outOfTurnUsageCall(row: OutOfTurnUsageRow): LedgerUsageCall {
|
|
|
148
164
|
attributedModelId: row.attributedModelId,
|
|
149
165
|
requestedModelId: row.attributedModelId,
|
|
150
166
|
responseModelIdObservation: { state: "not-observed" },
|
|
151
|
-
input: row.usage.input,
|
|
152
|
-
output: row.usage.output,
|
|
153
|
-
cacheRead: row.usage.cacheRead,
|
|
154
|
-
cacheWrite: row.usage.cacheWrite,
|
|
155
|
-
reasoningTokens: row.usage.reasoning,
|
|
156
|
-
totalTokens: row.usage.totalTokens,
|
|
157
|
-
costUsd: row.usage.costUsd,
|
|
167
|
+
input: row.usage.input ?? 0,
|
|
168
|
+
output: row.usage.output ?? 0,
|
|
169
|
+
cacheRead: row.usage.cacheRead ?? 0,
|
|
170
|
+
cacheWrite: row.usage.cacheWrite ?? 0,
|
|
171
|
+
reasoningTokens: row.usage.reasoning ?? 0,
|
|
172
|
+
totalTokens: row.usage.totalTokens ?? 0,
|
|
173
|
+
costUsd: row.usage.costUsd ?? 0,
|
|
158
174
|
};
|
|
159
175
|
}
|
|
160
176
|
|
|
177
|
+
/** Existing numeric accumulators sum known contributions; the report retains missing coverage. */
|
|
178
|
+
function reportedUsageTotals(totals: UsageTotals, rows: ReadonlyArray<OutOfTurnUsageRow>) {
|
|
179
|
+
const failedCompaction = summarizeFailedCompactionUsage(rows);
|
|
180
|
+
if (failedCompaction.calls === 0) return totals;
|
|
181
|
+
const reported: Record<string, unknown> = { ...totals, knownSubtotals: true, failedCompaction };
|
|
182
|
+
for (const [field, missing] of Object.entries(failedCompaction.unobservedUsageCalls)) {
|
|
183
|
+
const key = field === "reasoning" ? "reasoningTokens" : field;
|
|
184
|
+
if (missing > 0 && reported[key] === 0) reported[key] = null;
|
|
185
|
+
}
|
|
186
|
+
return reported;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function usageAmount(value: unknown): string {
|
|
190
|
+
return typeof value === "number" ? String(value) : "unknown";
|
|
191
|
+
}
|
|
192
|
+
|
|
161
193
|
function addUsageCall(totals: UsageTotals, call: LedgerUsageCall): void {
|
|
162
194
|
totals.apiCalls += call.apiCalls ?? 1;
|
|
163
195
|
totals.input += call.input;
|
|
@@ -442,6 +474,8 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
442
474
|
// session store is gone can still have recorded out-of-turn spend, and
|
|
443
475
|
// dropping those rows would report money that was spent as nothing at all.
|
|
444
476
|
const usageMeasurable = presence.sessionsPresent || outOfTurnRows.length > 0;
|
|
477
|
+
const reportedTotals = reportedUsageTotals(usageTotals, outOfTurnRows);
|
|
478
|
+
const failedCompaction = summarizeFailedCompactionUsage(outOfTurnRows);
|
|
445
479
|
const usageRows = [...usageByModel.values()].sort(
|
|
446
480
|
(a, b) => b.totals.totalTokens - a.totals.totalTokens || a.providerId.localeCompare(b.providerId),
|
|
447
481
|
);
|
|
@@ -533,7 +567,7 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
533
567
|
emit({
|
|
534
568
|
kind: "fact",
|
|
535
569
|
fact: "tokens",
|
|
536
|
-
...
|
|
570
|
+
...reportedTotals,
|
|
537
571
|
...(hasLabelledCall(callOrigins)
|
|
538
572
|
? {
|
|
539
573
|
turns: turnsOf(callOrigins),
|
|
@@ -541,6 +575,7 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
541
575
|
handoffs: callOrigins.handoffs,
|
|
542
576
|
prewarms: callOrigins.prewarms,
|
|
543
577
|
backgroundMemorySteps: callOrigins.backgroundMemory,
|
|
578
|
+
...(callOrigins.failedCompaction > 0 ? { failedCompactionCalls: callOrigins.failedCompaction } : {}),
|
|
544
579
|
}
|
|
545
580
|
: {}),
|
|
546
581
|
});
|
|
@@ -552,7 +587,12 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
552
587
|
attributedModelId: row.attributedModelId,
|
|
553
588
|
requestedModelIds: [...row.requestedModelIds].sort(),
|
|
554
589
|
responseModelIdObservationCounts: row.responseModelIdObservationCounts,
|
|
555
|
-
...
|
|
590
|
+
...reportedUsageTotals(
|
|
591
|
+
row.totals,
|
|
592
|
+
outOfTurnRows.filter(
|
|
593
|
+
(call) => call.target === row.providerId && call.attributedModelId === row.attributedModelId,
|
|
594
|
+
),
|
|
595
|
+
),
|
|
556
596
|
});
|
|
557
597
|
}
|
|
558
598
|
for (const session of cacheSessions) {
|
|
@@ -615,7 +655,7 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
615
655
|
out(` audited tool calls in window: ${auditToolCalls.length} (${auditBlocked.length} blocked/denied)`);
|
|
616
656
|
if (usageMeasurable) {
|
|
617
657
|
out(
|
|
618
|
-
` tokens in window: ${
|
|
658
|
+
` tokens in window: ${usageAmount(reportedTotals.totalTokens)} over ${usageTotals.apiCalls} model calls (input ${usageAmount(reportedTotals.input)}, output ${usageAmount(reportedTotals.output)}, cache read ${usageAmount(reportedTotals.cacheRead)}, cache write ${usageAmount(reportedTotals.cacheWrite)}, reasoning ${usageAmount(reportedTotals.reasoningTokens)})`,
|
|
619
659
|
);
|
|
620
660
|
if (hasLabelledCall(callOrigins)) {
|
|
621
661
|
// Only printed when a labelled call is in the window. Over an archive
|
|
@@ -629,7 +669,18 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
629
669
|
out(` background memory steps in window: ${callOrigins.backgroundMemory}`);
|
|
630
670
|
}
|
|
631
671
|
}
|
|
632
|
-
|
|
672
|
+
if (failedCompaction.calls > 0) {
|
|
673
|
+
out(
|
|
674
|
+
` failed-compaction streams: ${failedCompaction.calls} (${failedCompaction.erroredCalls} errored, ${failedCompaction.abortedCalls} aborted, ${failedCompaction.successfulCalls} completed before the attempt failed)`,
|
|
675
|
+
);
|
|
676
|
+
out(" usage figures are known subtotals; missing compaction usage is not zero or a complete spending bound");
|
|
677
|
+
out(
|
|
678
|
+
` errored compaction known cost: ${failedCompaction.erroredKnownUsage.costUsd === null ? "unknown" : `$${failedCompaction.erroredKnownUsage.costUsd.toFixed(4)}`}`,
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
out(
|
|
682
|
+
` ${failedCompaction.calls > 0 ? "known reported/estimated" : "provider-reported"} cost in window: ${typeof reportedTotals.costUsd === "number" ? `$${reportedTotals.costUsd.toFixed(4)}` : "unknown"}`,
|
|
683
|
+
);
|
|
633
684
|
}
|
|
634
685
|
if (usageRows.length > 0) {
|
|
635
686
|
out("");
|
|
@@ -650,19 +701,27 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
650
701
|
"tokens",
|
|
651
702
|
"cost",
|
|
652
703
|
],
|
|
653
|
-
...usageRows.map((row) =>
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
704
|
+
...usageRows.map((row) => {
|
|
705
|
+
const reported = reportedUsageTotals(
|
|
706
|
+
row.totals,
|
|
707
|
+
outOfTurnRows.filter(
|
|
708
|
+
(call) => call.target === row.providerId && call.attributedModelId === row.attributedModelId,
|
|
709
|
+
),
|
|
710
|
+
);
|
|
711
|
+
return [
|
|
712
|
+
row.providerId,
|
|
713
|
+
row.attributedModelId,
|
|
714
|
+
[...row.requestedModelIds].sort().join(","),
|
|
715
|
+
responseModelIdObservationCountsLabel(row.responseModelIdObservationCounts),
|
|
716
|
+
String(row.totals.apiCalls),
|
|
717
|
+
usageAmount(reported.input),
|
|
718
|
+
usageAmount(reported.output),
|
|
719
|
+
usageAmount(reported.cacheRead),
|
|
720
|
+
usageAmount(reported.reasoningTokens),
|
|
721
|
+
usageAmount(reported.totalTokens),
|
|
722
|
+
typeof reported.costUsd === "number" ? `$${reported.costUsd.toFixed(4)}` : "unknown",
|
|
723
|
+
];
|
|
724
|
+
}),
|
|
666
725
|
]),
|
|
667
726
|
),
|
|
668
727
|
);
|
|
@@ -15,9 +15,8 @@ export interface ValidateModelInput {
|
|
|
15
15
|
modelId: string;
|
|
16
16
|
knownModels: ReadonlyArray<string>;
|
|
17
17
|
/**
|
|
18
|
-
* The live list, when one was fetched.
|
|
19
|
-
*
|
|
20
|
-
* and the probe becomes the authority where there is nothing else.
|
|
18
|
+
* The live list, when one was fetched. Callers provide it only when that
|
|
19
|
+
* runtime declares live discovery authoritative for the concrete target.
|
|
21
20
|
*/
|
|
22
21
|
live?: LiveModelInventory | undefined;
|
|
23
22
|
force: boolean;
|
|
@@ -50,6 +49,7 @@ function formatUnadvertisedModelReason(modelId: string, live: LiveModelInventory
|
|
|
50
49
|
|
|
51
50
|
export function validateModelChoice(input: ValidateModelInput): ValidateModelResult {
|
|
52
51
|
const { runtimeId, modelId, knownModels, live, force } = input;
|
|
52
|
+
if (live !== undefined) return validateAgainstLive(modelId, live, force);
|
|
53
53
|
if (knownModels.length === 0) return validateAgainstLive(modelId, live, force);
|
|
54
54
|
if (knownModels.includes(modelId)) return { ok: true };
|
|
55
55
|
if (force) {
|
package/src/core/config.ts
CHANGED
|
@@ -525,6 +525,57 @@ function validateLmStudioSettings(
|
|
|
525
525
|
return Object.keys(out).length > 0 ? out : undefined;
|
|
526
526
|
}
|
|
527
527
|
|
|
528
|
+
function validateLiteLLMSettings(
|
|
529
|
+
issues: Issues,
|
|
530
|
+
path: string,
|
|
531
|
+
value: unknown,
|
|
532
|
+
): ClioSettings["targets"][number]["litellm"] | undefined {
|
|
533
|
+
if (!isPlainObject(value)) {
|
|
534
|
+
issues.add(path, `expected a map, got ${describe(value)}`);
|
|
535
|
+
return undefined;
|
|
536
|
+
}
|
|
537
|
+
issues.unknownKeys(path, value, ["request"]);
|
|
538
|
+
const out: NonNullable<ClioSettings["targets"][number]["litellm"]> = {};
|
|
539
|
+
if ("request" in value) {
|
|
540
|
+
if (!isPlainObject(value.request)) {
|
|
541
|
+
issues.add(`${path}.request`, `expected a map, got ${describe(value.request)}`);
|
|
542
|
+
} else {
|
|
543
|
+
issues.unknownKeys(`${path}.request`, value.request, [
|
|
544
|
+
"tags",
|
|
545
|
+
"sendSessionId",
|
|
546
|
+
"timeoutSeconds",
|
|
547
|
+
"streamTimeoutSeconds",
|
|
548
|
+
"numRetries",
|
|
549
|
+
]);
|
|
550
|
+
const request: NonNullable<typeof out.request> = {};
|
|
551
|
+
if ("tags" in value.request) {
|
|
552
|
+
const parsed = expectStringArray(issues, `${path}.request.tags`, value.request.tags);
|
|
553
|
+
if (parsed !== undefined) {
|
|
554
|
+
const invalidTag = parsed.find((tag) => tag.includes(","));
|
|
555
|
+
if (invalidTag) issues.add(`${path}.request.tags`, "tags may not contain commas");
|
|
556
|
+
else if (parsed.length > 0) request.tags = [...new Set(parsed)];
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
if ("sendSessionId" in value.request) {
|
|
560
|
+
const parsed = expectBoolean(issues, `${path}.request.sendSessionId`, value.request.sendSessionId);
|
|
561
|
+
if (parsed !== undefined) request.sendSessionId = parsed;
|
|
562
|
+
}
|
|
563
|
+
for (const key of ["timeoutSeconds", "streamTimeoutSeconds"] as const) {
|
|
564
|
+
if (key in value.request) {
|
|
565
|
+
const parsed = expectNumber(issues, `${path}.request.${key}`, value.request[key], { min: 0.001, max: 86_400 });
|
|
566
|
+
if (parsed !== undefined) request[key] = parsed;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
if ("numRetries" in value.request) {
|
|
570
|
+
const parsed = expectInteger(issues, `${path}.request.numRetries`, value.request.numRetries, { min: 0, max: 100 });
|
|
571
|
+
if (parsed !== undefined) request.numRetries = parsed;
|
|
572
|
+
}
|
|
573
|
+
if (Object.keys(request).length > 0) out.request = request;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
577
|
+
}
|
|
578
|
+
|
|
528
579
|
function validateTarget(issues: Issues, path: string, value: unknown): ClioSettings["targets"][number] | null {
|
|
529
580
|
if (!isPlainObject(value)) {
|
|
530
581
|
issues.add(path, `expected a map, got ${describe(value)}`);
|
|
@@ -542,6 +593,7 @@ function validateTarget(issues: Issues, path: string, value: unknown): ClioSetti
|
|
|
542
593
|
"gateway",
|
|
543
594
|
"pricing",
|
|
544
595
|
"lmstudio",
|
|
596
|
+
"litellm",
|
|
545
597
|
"maxConcurrentRequests",
|
|
546
598
|
]);
|
|
547
599
|
const id = "id" in value ? expectString(issues, `${path}.id`, value.id) : undefined;
|
|
@@ -593,6 +645,10 @@ function validateTarget(issues: Issues, path: string, value: unknown): ClioSetti
|
|
|
593
645
|
const v = validateLmStudioSettings(issues, `${path}.lmstudio`, value.lmstudio);
|
|
594
646
|
if (v !== undefined) target.lmstudio = v;
|
|
595
647
|
}
|
|
648
|
+
if ("litellm" in value) {
|
|
649
|
+
const v = validateLiteLLMSettings(issues, `${path}.litellm`, value.litellm);
|
|
650
|
+
if (v !== undefined) target.litellm = v;
|
|
651
|
+
}
|
|
596
652
|
if ("maxConcurrentRequests" in value) {
|
|
597
653
|
const v = expectInteger(issues, `${path}.maxConcurrentRequests`, value.maxConcurrentRequests, { min: 1 });
|
|
598
654
|
if (v !== undefined) target.maxConcurrentRequests = v;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const REDACTED = "[redacted]";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sanitize free-form text received from an external process before it crosses
|
|
5
|
+
* into errors, receipts, transcripts, evidence, or model-catalog snapshots.
|
|
6
|
+
*/
|
|
7
|
+
function redactExternalDiagnostic(input: string): string {
|
|
8
|
+
return input
|
|
9
|
+
.replace(/\b(?:authorization|proxy-authorization)\s*:\s*[^\r\n]+/giu, `Authorization: ${REDACTED}`)
|
|
10
|
+
.replace(/\b(?:set-cookie|cookie)\s*:\s*[^\r\n]+/giu, `Cookie: ${REDACTED}`)
|
|
11
|
+
.replace(/\bbearer\s+[A-Za-z0-9._~+/-]+=*/giu, `Bearer ${REDACTED}`)
|
|
12
|
+
.replace(
|
|
13
|
+
/\b(?:api[_-]?key|access[_-]?token|refresh[_-]?token|token|secret|password)\s*[:=]\s*[^\s,;]+/giu,
|
|
14
|
+
(match) => {
|
|
15
|
+
const separator = match.includes(":") ? ":" : "=";
|
|
16
|
+
return `${match.slice(0, match.indexOf(separator)).trim()}${separator}${REDACTED}`;
|
|
17
|
+
},
|
|
18
|
+
)
|
|
19
|
+
.replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu, REDACTED)
|
|
20
|
+
.replace(
|
|
21
|
+
/(?:~|\/[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)*)\/\.(?:gemini\/antigravity-cli|antigravitycli)(?:\/[^\s]*)?/gu,
|
|
22
|
+
"[redacted credential path]",
|
|
23
|
+
)
|
|
24
|
+
.replace(/https?:\/\/[^\s"'<>]+/giu, (url) => {
|
|
25
|
+
try {
|
|
26
|
+
const parsed = new URL(url);
|
|
27
|
+
if (/(?:auth|oauth|login|signin|callback)/iu.test(parsed.pathname)) return "[redacted authorization URL]";
|
|
28
|
+
parsed.username = "";
|
|
29
|
+
parsed.password = "";
|
|
30
|
+
parsed.search = "";
|
|
31
|
+
parsed.hash = "";
|
|
32
|
+
return parsed.toString();
|
|
33
|
+
} catch {
|
|
34
|
+
return REDACTED;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function boundedExternalDiagnostic(input: string, maxBytes = 8192): string {
|
|
40
|
+
const redacted = redactExternalDiagnostic(input).trim();
|
|
41
|
+
const bytes = Buffer.from(redacted, "utf8");
|
|
42
|
+
if (bytes.byteLength <= maxBytes) return redacted;
|
|
43
|
+
return `${bytes.subarray(0, Math.max(0, maxBytes - 32)).toString("utf8")}\n[diagnostic truncated]`;
|
|
44
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable routing facts reported by an AI gateway for one upstream response.
|
|
3
|
+
*
|
|
4
|
+
* The gateway is authoritative for the physical deployment that served an
|
|
5
|
+
* alias. Clio deliberately records only the host portion of an upstream API
|
|
6
|
+
* base: LiteLLM deployments may embed paths, query credentials, or user-info
|
|
7
|
+
* in the configured URL, none of which belongs in a session or sealed receipt.
|
|
8
|
+
*/
|
|
9
|
+
export interface LiteLLMGatewayRoutingObservation {
|
|
10
|
+
gateway: "litellm";
|
|
11
|
+
callId?: string;
|
|
12
|
+
modelGroup?: string;
|
|
13
|
+
modelName?: string;
|
|
14
|
+
apiBaseHost?: string;
|
|
15
|
+
deploymentId?: string;
|
|
16
|
+
attemptedFallbacks?: number;
|
|
17
|
+
attemptedRetries?: number;
|
|
18
|
+
overheadMs?: number;
|
|
19
|
+
responseDurationMs?: number;
|
|
20
|
+
version?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type GatewayRoutingObservation = LiteLLMGatewayRoutingObservation;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Preserve the provider's diagnostic while making Clio's failure policy
|
|
27
|
+
* explicit and actionable. LiteLLM targets deliberately do not enter Clio's
|
|
28
|
+
* transient retry ladder: a named route is an operator choice, not permission
|
|
29
|
+
* to substitute another model behind their back.
|
|
30
|
+
*/
|
|
31
|
+
export function liteLLMRouteFailureMessage(
|
|
32
|
+
errorMessage: string | null | undefined,
|
|
33
|
+
targetId: string,
|
|
34
|
+
modelId: string,
|
|
35
|
+
): string {
|
|
36
|
+
const providerMessage = errorMessage?.trim() || "LiteLLM request failed.";
|
|
37
|
+
const advice =
|
|
38
|
+
`LiteLLM route '${modelId}' on target '${targetId}' failed. ` +
|
|
39
|
+
"Clio did not retry or substitute another model; select a different route with /model, then resend.";
|
|
40
|
+
return providerMessage.includes(advice) ? providerMessage : `${providerMessage}\n\n${advice}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface HeaderReader {
|
|
44
|
+
get(name: string): string | null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function nonEmptyString(value: unknown): string | undefined {
|
|
48
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function nonnegativeNumber(value: unknown): number | undefined {
|
|
52
|
+
if (typeof value === "number" && Number.isFinite(value) && value >= 0) return value;
|
|
53
|
+
if (typeof value !== "string" || value.trim().length === 0) return undefined;
|
|
54
|
+
const parsed = Number(value);
|
|
55
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function nonnegativeInteger(value: unknown): number | undefined {
|
|
59
|
+
const parsed = nonnegativeNumber(value);
|
|
60
|
+
return parsed === undefined ? undefined : Math.floor(parsed);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function apiBaseHost(value: unknown): string | undefined {
|
|
64
|
+
const raw = nonEmptyString(value);
|
|
65
|
+
if (raw === undefined) return undefined;
|
|
66
|
+
try {
|
|
67
|
+
return new URL(raw).host || undefined;
|
|
68
|
+
} catch {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function storedApiBaseHost(value: unknown): string | undefined {
|
|
74
|
+
const raw = nonEmptyString(value);
|
|
75
|
+
if (raw === undefined) return undefined;
|
|
76
|
+
try {
|
|
77
|
+
return new URL(raw.includes("://") ? raw : `http://${raw}`).host || undefined;
|
|
78
|
+
} catch {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Read LiteLLM's response headers without retaining sensitive API-base data. */
|
|
84
|
+
export function liteLLMGatewayRoutingFromHeaders(headers: HeaderReader): GatewayRoutingObservation | null {
|
|
85
|
+
const callId = nonEmptyString(headers.get("x-litellm-call-id"));
|
|
86
|
+
const modelGroup = nonEmptyString(headers.get("x-litellm-model-group"));
|
|
87
|
+
const modelName = nonEmptyString(headers.get("x-litellm-model-name"));
|
|
88
|
+
const host = apiBaseHost(headers.get("x-litellm-model-api-base"));
|
|
89
|
+
const deploymentId = nonEmptyString(headers.get("x-litellm-model-id"));
|
|
90
|
+
const attemptedFallbacks = nonnegativeInteger(headers.get("x-litellm-attempted-fallbacks"));
|
|
91
|
+
const attemptedRetries = nonnegativeInteger(headers.get("x-litellm-attempted-retries"));
|
|
92
|
+
const overheadMs = nonnegativeNumber(headers.get("x-litellm-overhead-duration-ms"));
|
|
93
|
+
const responseDurationMs = nonnegativeNumber(headers.get("x-litellm-response-duration-ms"));
|
|
94
|
+
const version = nonEmptyString(headers.get("x-litellm-version"));
|
|
95
|
+
const observation: GatewayRoutingObservation = {
|
|
96
|
+
gateway: "litellm",
|
|
97
|
+
...(callId !== undefined ? { callId } : {}),
|
|
98
|
+
...(modelGroup !== undefined ? { modelGroup } : {}),
|
|
99
|
+
...(modelName !== undefined ? { modelName } : {}),
|
|
100
|
+
...(host !== undefined ? { apiBaseHost: host } : {}),
|
|
101
|
+
...(deploymentId !== undefined ? { deploymentId } : {}),
|
|
102
|
+
...(attemptedFallbacks !== undefined ? { attemptedFallbacks } : {}),
|
|
103
|
+
...(attemptedRetries !== undefined ? { attemptedRetries } : {}),
|
|
104
|
+
...(overheadMs !== undefined ? { overheadMs } : {}),
|
|
105
|
+
...(responseDurationMs !== undefined ? { responseDurationMs } : {}),
|
|
106
|
+
...(version !== undefined ? { version } : {}),
|
|
107
|
+
};
|
|
108
|
+
return Object.keys(observation).length > 1 ? observation : null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Parse a live message, persisted session row, or receipt response defensively. */
|
|
112
|
+
export function gatewayRoutingObservationFromRecord(
|
|
113
|
+
record: Readonly<Record<string, unknown>>,
|
|
114
|
+
): GatewayRoutingObservation | null {
|
|
115
|
+
const value = record.gatewayRouting;
|
|
116
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return null;
|
|
117
|
+
const raw = value as Record<string, unknown>;
|
|
118
|
+
if (raw.gateway !== "litellm") return null;
|
|
119
|
+
const callId = nonEmptyString(raw.callId);
|
|
120
|
+
const modelGroup = nonEmptyString(raw.modelGroup);
|
|
121
|
+
const modelName = nonEmptyString(raw.modelName);
|
|
122
|
+
const host = storedApiBaseHost(raw.apiBaseHost);
|
|
123
|
+
const deploymentId = nonEmptyString(raw.deploymentId);
|
|
124
|
+
const attemptedFallbacks = nonnegativeInteger(raw.attemptedFallbacks);
|
|
125
|
+
const attemptedRetries = nonnegativeInteger(raw.attemptedRetries);
|
|
126
|
+
const overheadMs = nonnegativeNumber(raw.overheadMs);
|
|
127
|
+
const responseDurationMs = nonnegativeNumber(raw.responseDurationMs);
|
|
128
|
+
const version = nonEmptyString(raw.version);
|
|
129
|
+
const observation: GatewayRoutingObservation = {
|
|
130
|
+
gateway: "litellm",
|
|
131
|
+
...(callId !== undefined ? { callId } : {}),
|
|
132
|
+
...(modelGroup !== undefined ? { modelGroup } : {}),
|
|
133
|
+
...(modelName !== undefined ? { modelName } : {}),
|
|
134
|
+
...(host !== undefined ? { apiBaseHost: host } : {}),
|
|
135
|
+
...(deploymentId !== undefined ? { deploymentId } : {}),
|
|
136
|
+
...(attemptedFallbacks !== undefined ? { attemptedFallbacks } : {}),
|
|
137
|
+
...(attemptedRetries !== undefined ? { attemptedRetries } : {}),
|
|
138
|
+
...(overheadMs !== undefined ? { overheadMs } : {}),
|
|
139
|
+
...(responseDurationMs !== undefined ? { responseDurationMs } : {}),
|
|
140
|
+
...(version !== undefined ? { version } : {}),
|
|
141
|
+
};
|
|
142
|
+
return Object.keys(observation).length > 1 ? observation : null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Compact human projection for receipts and operator notices. */
|
|
146
|
+
export function gatewayRoutingObservationLabel(observation: GatewayRoutingObservation): string {
|
|
147
|
+
const route = [observation.modelGroup, observation.modelName].filter(Boolean).join("->");
|
|
148
|
+
const destination = [route, observation.apiBaseHost ? `@${observation.apiBaseHost}` : ""].filter(Boolean).join("");
|
|
149
|
+
const parts = [
|
|
150
|
+
"gateway=litellm",
|
|
151
|
+
...(destination ? [`route=${destination}`] : []),
|
|
152
|
+
...(observation.attemptedFallbacks !== undefined ? [`fallbacks=${observation.attemptedFallbacks}`] : []),
|
|
153
|
+
...(observation.attemptedRetries !== undefined ? [`retries=${observation.attemptedRetries}`] : []),
|
|
154
|
+
...(observation.overheadMs !== undefined ? [`overhead_ms=${observation.overheadMs}`] : []),
|
|
155
|
+
];
|
|
156
|
+
return parts.join(" ");
|
|
157
|
+
}
|
package/src/core/safe-exec.ts
CHANGED
|
@@ -24,6 +24,18 @@ const ENV_ALLOWLIST = [
|
|
|
24
24
|
"TMP",
|
|
25
25
|
"CI",
|
|
26
26
|
"NO_COLOR",
|
|
27
|
+
// Platform/session location variables needed by installed local CLIs. These
|
|
28
|
+
// locate operator-owned state; provider keys and Clio gates are deliberately
|
|
29
|
+
// absent from this allowlist.
|
|
30
|
+
"XDG_CONFIG_HOME",
|
|
31
|
+
"XDG_CACHE_HOME",
|
|
32
|
+
"XDG_STATE_HOME",
|
|
33
|
+
"APPDATA",
|
|
34
|
+
"LOCALAPPDATA",
|
|
35
|
+
"SYSTEMROOT",
|
|
36
|
+
"WINDIR",
|
|
37
|
+
"COMSPEC",
|
|
38
|
+
"PATHEXT",
|
|
27
39
|
] as const;
|
|
28
40
|
|
|
29
41
|
export interface SafeCommandResult {
|
|
@@ -49,10 +61,13 @@ export interface RunCommandVectorOptions {
|
|
|
49
61
|
env?: Record<string, string>;
|
|
50
62
|
}
|
|
51
63
|
|
|
52
|
-
export function buildSafeToolEnv(
|
|
64
|
+
export function buildSafeToolEnv(
|
|
65
|
+
extra: Record<string, string> = {},
|
|
66
|
+
source: NodeJS.ProcessEnv = process.env,
|
|
67
|
+
): NodeJS.ProcessEnv {
|
|
53
68
|
const env: NodeJS.ProcessEnv = {};
|
|
54
69
|
for (const key of ENV_ALLOWLIST) {
|
|
55
|
-
const value =
|
|
70
|
+
const value = source[key];
|
|
56
71
|
if (value !== undefined) env[key] = value;
|
|
57
72
|
}
|
|
58
73
|
for (const [key, value] of Object.entries(extra)) {
|
|
@@ -58,6 +58,90 @@ export interface PendingSkillToolPolicy {
|
|
|
58
58
|
loadedSkillNames: Set<string>;
|
|
59
59
|
/** Declared tool policy per successfully loaded skill, recorded by context(scope=skills). */
|
|
60
60
|
loadedSkillPolicies: Map<string, SkillDeclaredToolPolicy>;
|
|
61
|
+
/**
|
|
62
|
+
* True once this policy is a surface that outlived the turn that armed it.
|
|
63
|
+
* The narrowing is identical; the flag exists so a load request the policy
|
|
64
|
+
* does not cover reads as "only the operator activates skills" rather than
|
|
65
|
+
* claiming a pending request that no longer exists.
|
|
66
|
+
*/
|
|
67
|
+
carriedSurface?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* True when the session's autonomy level lets the model activate an
|
|
70
|
+
* installed skill itself instead of emitting the suggestion anchor and
|
|
71
|
+
* waiting for `/skill`. Activation is the same per-run policy the operator's
|
|
72
|
+
* path produces: skills only ever narrow the tool surface, so this grants
|
|
73
|
+
* nothing the level had not already granted. Marketplace (not yet
|
|
74
|
+
* installed) skills stay operator-gated at every level.
|
|
75
|
+
*/
|
|
76
|
+
modelActivation?: boolean;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The surface that stays armed after an interactive turn ends.
|
|
81
|
+
*
|
|
82
|
+
* A skill an operator loaded narrows the tools for the workflow it started,
|
|
83
|
+
* and a multi-turn workflow (an interview skill asking a question per turn)
|
|
84
|
+
* is still inside that workflow on the operator's next message. Dropping the
|
|
85
|
+
* narrowing at turn end handed the workflow back the full surface partway
|
|
86
|
+
* through, which is how a `bash` call correctly refused in turn one ran in
|
|
87
|
+
* turn six. Returns undefined when nothing declared a narrowing, which is the
|
|
88
|
+
* signal to clear whatever surface was armed before.
|
|
89
|
+
*/
|
|
90
|
+
export function armedSkillSurface(policy: PendingSkillToolPolicy | undefined): PendingSkillToolPolicy | undefined {
|
|
91
|
+
if (!policy) return undefined;
|
|
92
|
+
const declared = [...policy.loadedSkillPolicies.entries()].filter(
|
|
93
|
+
([, declaration]) => (declaration.allowedTools?.length ?? 0) > 0 || (declaration.disallowedTools?.length ?? 0) > 0,
|
|
94
|
+
);
|
|
95
|
+
if (declared.length === 0) return undefined;
|
|
96
|
+
return {
|
|
97
|
+
allowedSkillNames: [...policy.allowedSkillNames],
|
|
98
|
+
requests: [...policy.requests],
|
|
99
|
+
loadedSkillNames: new Set(policy.loadedSkillNames),
|
|
100
|
+
loadedSkillPolicies: new Map(declared),
|
|
101
|
+
carriedSurface: true,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Skill names contributing a declaration to an armed surface, for the operator notice. */
|
|
106
|
+
export function skillSurfaceNames(policy: PendingSkillToolPolicy | undefined): ReadonlyArray<string> {
|
|
107
|
+
return policy ? [...policy.loadedSkillPolicies.keys()] : [];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The same names, each tagged with who activated it. A skill the operator
|
|
112
|
+
* named arrives as a pending request; anything else was activated by the model
|
|
113
|
+
* under `modelActivation`, and the operator's one line about the surface is
|
|
114
|
+
* where that distinction has to be visible.
|
|
115
|
+
*/
|
|
116
|
+
export function skillSurfaceLabels(policy: PendingSkillToolPolicy | undefined): ReadonlyArray<string> {
|
|
117
|
+
if (!policy) return [];
|
|
118
|
+
return [...policy.loadedSkillPolicies.keys()].map((name) =>
|
|
119
|
+
policy.requests.some((request) => request.name === name) ? `${name} (operator)` : `${name} (model)`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Stamp (or clear) the model-activation grant on the policy this turn runs
|
|
125
|
+
* under, creating one when nothing else did. Mutates in place so a surface
|
|
126
|
+
* carried from an earlier turn keeps its identity, and re-stamps every turn so
|
|
127
|
+
* a level change takes effect on the next message rather than the next skill.
|
|
128
|
+
*/
|
|
129
|
+
export function withModelSkillActivation(
|
|
130
|
+
policy: PendingSkillToolPolicy | undefined,
|
|
131
|
+
enabled: boolean,
|
|
132
|
+
): PendingSkillToolPolicy | undefined {
|
|
133
|
+
if (policy) {
|
|
134
|
+
policy.modelActivation = enabled;
|
|
135
|
+
return policy;
|
|
136
|
+
}
|
|
137
|
+
if (!enabled) return undefined;
|
|
138
|
+
return {
|
|
139
|
+
allowedSkillNames: [],
|
|
140
|
+
requests: [],
|
|
141
|
+
loadedSkillNames: new Set<string>(),
|
|
142
|
+
loadedSkillPolicies: new Map<string, SkillDeclaredToolPolicy>(),
|
|
143
|
+
modelActivation: true,
|
|
144
|
+
};
|
|
61
145
|
}
|
|
62
146
|
|
|
63
147
|
/**
|
|
@@ -75,6 +159,8 @@ export interface SkillToolSurfaceViolation {
|
|
|
75
159
|
mergedAllowedTools: ReadonlyArray<string> | null;
|
|
76
160
|
/** Skills whose disallowed-tools name the tool directly. */
|
|
77
161
|
disallowedBy: ReadonlyArray<string>;
|
|
162
|
+
/** True when the surface outlived the turn that armed it, which changes the lifetime the block message states. */
|
|
163
|
+
carriedSurface: boolean;
|
|
78
164
|
}
|
|
79
165
|
|
|
80
166
|
/**
|
|
@@ -98,15 +184,16 @@ export function evaluateSkillToolSurface(
|
|
|
98
184
|
if (SKILL_SURFACE_EXEMPT_TOOLS.has(tool)) return null;
|
|
99
185
|
const entries = [...policy.loadedSkillPolicies.entries()];
|
|
100
186
|
const skills = entries.map(([name]) => name);
|
|
187
|
+
const carriedSurface = policy.carriedSurface === true;
|
|
101
188
|
const disallowedBy = entries
|
|
102
189
|
.filter(([, declared]) => declared.disallowedTools?.includes(tool) === true)
|
|
103
190
|
.map(([name]) => name);
|
|
104
|
-
if (disallowedBy.length > 0) return { skills, mergedAllowedTools: null, disallowedBy };
|
|
191
|
+
if (disallowedBy.length > 0) return { skills, mergedAllowedTools: null, disallowedBy, carriedSurface };
|
|
105
192
|
const allowLists = entries.map(([, declared]) => declared.allowedTools);
|
|
106
193
|
if (allowLists.some((list) => list === undefined || list.length === 0)) return null;
|
|
107
194
|
const merged = [...new Set(allowLists.flatMap((list) => [...(list ?? [])]))];
|
|
108
195
|
if (merged.includes(tool)) return null;
|
|
109
|
-
return { skills, mergedAllowedTools: merged, disallowedBy: [] };
|
|
196
|
+
return { skills, mergedAllowedTools: merged, disallowedBy: [], carriedSurface };
|
|
110
197
|
}
|
|
111
198
|
|
|
112
199
|
/**
|