@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
|
@@ -74,8 +74,18 @@ interface NormalizedArtifact {
|
|
|
74
74
|
artifact: ProtectedArtifact;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
const COMMAND_SEPARATORS = new Set([";", "&&", "||", "|"]);
|
|
77
|
+
const COMMAND_SEPARATORS = new Set([";", "&", "&&", "||", "|"]);
|
|
78
78
|
const SHELL_WRAPPERS = new Set(["command", "builtin", "sudo", "doas"]);
|
|
79
|
+
const SHELL_REDIRECTIONS = new Set([">", ">>", "<", "<<", "<<<", "<&", ">&", "<>", ">|", "&>", "&>>"]);
|
|
80
|
+
const SHELL_WRITE_REDIRECTIONS = new Set([">", ">>", ">&", "<>", ">|", "&>", "&>>"]);
|
|
81
|
+
|
|
82
|
+
export interface ShellToken {
|
|
83
|
+
value: string;
|
|
84
|
+
operator: boolean;
|
|
85
|
+
quoted: boolean;
|
|
86
|
+
start: number;
|
|
87
|
+
end: number;
|
|
88
|
+
}
|
|
79
89
|
|
|
80
90
|
/**
|
|
81
91
|
* Paths a tool call would mutate, derived from the tool's path argument.
|
|
@@ -149,9 +159,9 @@ function classifyDestructiveCommand(
|
|
|
149
159
|
const artifacts = normalizedArtifacts(protectedArtifacts);
|
|
150
160
|
if (artifacts.length === 0) return { kind: "benign", matches: [] };
|
|
151
161
|
|
|
152
|
-
const tokens
|
|
153
|
-
|
|
154
|
-
const redirect = classifyRedirect(
|
|
162
|
+
for (const tokens of splitSegments(scanShellLike(command))) {
|
|
163
|
+
const segment = shellCommandArguments(tokens);
|
|
164
|
+
const redirect = classifyRedirect(tokens, artifacts);
|
|
155
165
|
if (redirect.kind === "destructive") return redirect;
|
|
156
166
|
|
|
157
167
|
const commandIndex = commandTokenIndex(segment);
|
|
@@ -217,8 +227,8 @@ export function detectValidationCommand(
|
|
|
217
227
|
command: string,
|
|
218
228
|
scope: ValidationCommandScope = "finish-contract",
|
|
219
229
|
): ValidationCommandDetection {
|
|
220
|
-
const tokens
|
|
221
|
-
|
|
230
|
+
for (const tokens of splitSegments(scanShellLike(command))) {
|
|
231
|
+
const segment = shellCommandArguments(tokens);
|
|
222
232
|
const commandIndex = commandTokenIndex(segment);
|
|
223
233
|
if (commandIndex === null) continue;
|
|
224
234
|
const executable = basenameToken(segment[commandIndex]);
|
|
@@ -248,10 +258,11 @@ export function detectValidationCommand(
|
|
|
248
258
|
*/
|
|
249
259
|
export function extractCommandWriteTargets(command: string): string[] {
|
|
250
260
|
const targets: string[] = [];
|
|
251
|
-
for (const segment of
|
|
261
|
+
for (const segment of expandedShellSegments(command)) {
|
|
252
262
|
collectRedirectTargets(segment, targets);
|
|
253
|
-
|
|
254
|
-
|
|
263
|
+
const argv = shellCommandArguments(segment);
|
|
264
|
+
collectInvokedWriteTargets(argv, targets);
|
|
265
|
+
collectInPlaceEditTargets(argv, targets);
|
|
255
266
|
}
|
|
256
267
|
return targets.filter(isInterestingWriteTarget);
|
|
257
268
|
}
|
|
@@ -295,14 +306,14 @@ function segmentShellScript(segment: ReadonlyArray<string>): string | null {
|
|
|
295
306
|
* segments of the script it runs. The wrapper segment itself is kept: a
|
|
296
307
|
* scanner that reads its operands (`cp`, `tee`) must still see them.
|
|
297
308
|
*/
|
|
298
|
-
function
|
|
299
|
-
const segments = splitSegments(
|
|
309
|
+
function expandedShellSegments(command: string, depth = 0): ShellToken[][] {
|
|
310
|
+
const segments = splitSegments(scanShellLike(command));
|
|
300
311
|
if (depth >= INNER_SHELL_MAX_DEPTH) return segments;
|
|
301
|
-
const out:
|
|
312
|
+
const out: ShellToken[][] = [];
|
|
302
313
|
for (const segment of segments) {
|
|
303
314
|
out.push(segment);
|
|
304
|
-
const script = segmentShellScript(segment);
|
|
305
|
-
if (script !== null) out.push(...
|
|
315
|
+
const script = segmentShellScript(shellCommandArguments(segment));
|
|
316
|
+
if (script !== null) out.push(...expandedShellSegments(script, depth + 1));
|
|
306
317
|
}
|
|
307
318
|
return out;
|
|
308
319
|
}
|
|
@@ -313,11 +324,11 @@ function expandedSegments(command: string, depth = 0): string[][] {
|
|
|
313
324
|
* script rather than treating `sh` as an unrecognized executable.
|
|
314
325
|
*/
|
|
315
326
|
export function inlineShellScript(command: string): string | null {
|
|
316
|
-
const segments = splitSegments(
|
|
327
|
+
const segments = splitSegments(scanShellLike(command));
|
|
317
328
|
if (segments.length !== 1) return null;
|
|
318
329
|
const segment = segments[0];
|
|
319
330
|
if (segment === undefined) return null;
|
|
320
|
-
return segmentShellScript(segment);
|
|
331
|
+
return segmentShellScript(shellCommandArguments(segment));
|
|
321
332
|
}
|
|
322
333
|
|
|
323
334
|
/**
|
|
@@ -331,7 +342,8 @@ export function inlineShellScript(command: string): string | null {
|
|
|
331
342
|
*/
|
|
332
343
|
export function extractCommandCdTargets(command: string): string[] {
|
|
333
344
|
const targets: string[] = [];
|
|
334
|
-
for (const
|
|
345
|
+
for (const tokens of expandedShellSegments(command)) {
|
|
346
|
+
const segment = shellCommandArguments(tokens);
|
|
335
347
|
const commandIndex = commandTokenIndex(segment);
|
|
336
348
|
if (commandIndex === null) continue;
|
|
337
349
|
const executable = basenameToken(segment[commandIndex]);
|
|
@@ -349,7 +361,8 @@ export function extractCommandCdTargets(command: string): string[] {
|
|
|
349
361
|
*/
|
|
350
362
|
export function extractCommandDeleteTargets(command: string): string[] {
|
|
351
363
|
const targets: string[] = [];
|
|
352
|
-
for (const
|
|
364
|
+
for (const tokens of expandedShellSegments(command)) {
|
|
365
|
+
const segment = shellCommandArguments(tokens);
|
|
353
366
|
const commandIndex = commandTokenIndex(segment);
|
|
354
367
|
if (commandIndex === null) continue;
|
|
355
368
|
const executable = basenameToken(segment[commandIndex]);
|
|
@@ -369,17 +382,108 @@ export function extractCommandDeleteTargets(command: string): string[] {
|
|
|
369
382
|
return targets.filter(isInterestingWriteTarget);
|
|
370
383
|
}
|
|
371
384
|
|
|
385
|
+
/** Recognizable operator CLI installation paths invoked through a model shell.
|
|
386
|
+
* This is command inspection, not confinement of arbitrary scripts or aliases.
|
|
387
|
+
*/
|
|
388
|
+
export function invokesClioSkillMutation(command: string): boolean {
|
|
389
|
+
for (const segment of expandedShellSegments(command)) {
|
|
390
|
+
const argv = shellCommandArguments(segment);
|
|
391
|
+
const index = commandTokenIndex(argv);
|
|
392
|
+
if (index === null) continue;
|
|
393
|
+
let args = argv.slice(index);
|
|
394
|
+
const executable = basenameToken(args[0]);
|
|
395
|
+
if (executable === "npx" || (executable === "npm" && args[1] === "exec")) {
|
|
396
|
+
args = args.slice(executable === "npm" ? 2 : 1);
|
|
397
|
+
while (args[0]?.startsWith("-")) args = args.slice(1);
|
|
398
|
+
}
|
|
399
|
+
const program = args[0] ?? "";
|
|
400
|
+
if (basenameToken(program) === "node" || basenameToken(program) === "tsx") {
|
|
401
|
+
// The checked-in and built entry points are also operator CLIs.
|
|
402
|
+
if (!/(?:^|\/)(?:src|dist)\/cli\/index\.(?:js|ts)$/.test(args[1] ?? "")) continue;
|
|
403
|
+
args = args.slice(2);
|
|
404
|
+
} else if (/^(?:@iowarp\/)?clio-coder(?:@[^/]+)?$/.test(program) || basenameToken(program) === "clio-coder") {
|
|
405
|
+
args = args.slice(1);
|
|
406
|
+
} else continue;
|
|
407
|
+
if (args.includes("--version") || args.includes("-v")) continue;
|
|
408
|
+
let rootHelp = false;
|
|
409
|
+
let firstRootFlag: string | undefined;
|
|
410
|
+
while (args[0]?.startsWith("-")) {
|
|
411
|
+
const flag = args[0];
|
|
412
|
+
// Startup flags are consumed before dispatch. Help is terminal only
|
|
413
|
+
// when it is the first flag left in the root dispatcher's argv.
|
|
414
|
+
if (flag === "--all" || flag === "--help" || flag === "-h") firstRootFlag ??= flag;
|
|
415
|
+
rootHelp = firstRootFlag === "--help" || firstRootFlag === "-h";
|
|
416
|
+
args = args.slice(flag === "--skill" || flag === "--api-key" ? 2 : 1);
|
|
417
|
+
}
|
|
418
|
+
if (rootHelp) continue;
|
|
419
|
+
if (args[0] !== "skills" && args[0] !== "library") continue;
|
|
420
|
+
if (resourceCliMutatesSkills(args[0], args.slice(1))) return true;
|
|
421
|
+
}
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function shellCommandArguments(segment: ReadonlyArray<ShellToken>): string[] {
|
|
426
|
+
const args: ShellToken[] = [];
|
|
427
|
+
for (let index = 0; index < segment.length; index += 1) {
|
|
428
|
+
const token = segment[index];
|
|
429
|
+
if (token === undefined) continue;
|
|
430
|
+
if (token.operator && SHELL_REDIRECTIONS.has(token.value)) {
|
|
431
|
+
// A redirection target is consumed by the shell, not passed to Clio.
|
|
432
|
+
// Only an adjacent, unquoted number is its optional file descriptor.
|
|
433
|
+
const previous = args.at(-1);
|
|
434
|
+
if (previous && previous.end === token.start && !previous.quoted && /^\d+$/.test(previous.value)) args.pop();
|
|
435
|
+
if (segment[index + 1]?.operator === false) index += 1;
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
args.push(token);
|
|
439
|
+
}
|
|
440
|
+
return args.map((token) => token.value);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function resourceCliMutatesSkills(resource: "skills" | "library", args: ReadonlyArray<string>): boolean {
|
|
444
|
+
// Both resource parsers accept flags before the verb. Consume their value
|
|
445
|
+
// options so a catalog path called --yes or --help is not treated as a flag.
|
|
446
|
+
const valueOptions =
|
|
447
|
+
resource === "skills"
|
|
448
|
+
? ["--name", "--category", "--scenario", "--target", "--workspace", "--timeout"]
|
|
449
|
+
: ["--kind", "--from"];
|
|
450
|
+
let verb: string | undefined;
|
|
451
|
+
let confirmed = false;
|
|
452
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
453
|
+
const arg = args[index];
|
|
454
|
+
if (arg === undefined) continue;
|
|
455
|
+
if (valueOptions.includes(arg)) {
|
|
456
|
+
index += 1;
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
if (arg === "--help" || arg === "-h") return false;
|
|
460
|
+
if (arg === "--yes") confirmed = true;
|
|
461
|
+
if (!arg.startsWith("-")) verb ??= arg;
|
|
462
|
+
}
|
|
463
|
+
if (resource === "skills") return verb === "install" || verb === "update" || verb === "sync";
|
|
464
|
+
// Unconfirmed library add only prints a plan. A confirmed add can install
|
|
465
|
+
// skill dependencies of any resource kind, or resolve an untyped skill ref.
|
|
466
|
+
return verb === "add" && confirmed;
|
|
467
|
+
}
|
|
468
|
+
|
|
372
469
|
const STANDARD_DEV_TARGETS = new Set(["/dev/null", "/dev/stdout", "/dev/stderr", "/dev/tty", "/dev/zero"]);
|
|
373
470
|
|
|
374
|
-
function collectRedirectTargets(segment: ReadonlyArray<
|
|
471
|
+
function collectRedirectTargets(segment: ReadonlyArray<ShellToken>, out: string[]): void {
|
|
375
472
|
for (let index = 0; index < segment.length - 1; index += 1) {
|
|
376
|
-
const
|
|
377
|
-
if (
|
|
378
|
-
const target = segment[index + 1];
|
|
379
|
-
if (target !== undefined) out.push(target);
|
|
473
|
+
const target = redirectWriteTarget(segment[index], segment[index + 1]);
|
|
474
|
+
if (target !== null) out.push(target);
|
|
380
475
|
}
|
|
381
476
|
}
|
|
382
477
|
|
|
478
|
+
function redirectWriteTarget(operator: ShellToken | undefined, target: ShellToken | undefined): string | null {
|
|
479
|
+
if (!operator?.operator || target === undefined || target.operator || !SHELL_WRITE_REDIRECTIONS.has(operator.value))
|
|
480
|
+
return null;
|
|
481
|
+
// >& duplicates or closes a descriptor when its operand is a number or -;
|
|
482
|
+
// Bash also accepts a filename here, redirecting stdout and stderr to it.
|
|
483
|
+
if (operator.value === ">&" && /^(?:\d+-?|-)$/u.test(target.value)) return null;
|
|
484
|
+
return target.value;
|
|
485
|
+
}
|
|
486
|
+
|
|
383
487
|
function collectInvokedWriteTargets(segment: ReadonlyArray<string>, out: string[]): void {
|
|
384
488
|
const cmdIndex = commandTokenIndex(segment);
|
|
385
489
|
if (cmdIndex === null) return;
|
|
@@ -430,7 +534,6 @@ function hasSedInPlaceFlag(segment: ReadonlyArray<string>, cmdIndex: number): bo
|
|
|
430
534
|
for (let index = cmdIndex + 1; index < segment.length; index += 1) {
|
|
431
535
|
const token = segment[index];
|
|
432
536
|
if (token === undefined) continue;
|
|
433
|
-
if (COMMAND_SEPARATORS.has(token)) break;
|
|
434
537
|
if (token === "--") break;
|
|
435
538
|
if (token === "--in-place" || token.startsWith("--in-place=")) return true;
|
|
436
539
|
if (token.startsWith("--")) continue;
|
|
@@ -453,7 +556,6 @@ function sedFileOperands(segment: ReadonlyArray<string>, cmdIndex: number): stri
|
|
|
453
556
|
for (let index = cmdIndex + 1; index < segment.length; index += 1) {
|
|
454
557
|
const token = segment[index];
|
|
455
558
|
if (token === undefined) continue;
|
|
456
|
-
if (COMMAND_SEPARATORS.has(token)) break;
|
|
457
559
|
if (!endOfOptions && token === "--") {
|
|
458
560
|
endOfOptions = true;
|
|
459
561
|
continue;
|
|
@@ -487,20 +589,20 @@ function sedFileOperands(segment: ReadonlyArray<string>, cmdIndex: number): stri
|
|
|
487
589
|
|
|
488
590
|
function isInterestingWriteTarget(target: string): boolean {
|
|
489
591
|
if (target.length === 0) return false;
|
|
490
|
-
if (target.startsWith("&")) return false;
|
|
491
592
|
if (STANDARD_DEV_TARGETS.has(target)) return false;
|
|
492
593
|
if (target.startsWith("/dev/fd/")) return false;
|
|
493
594
|
return true;
|
|
494
595
|
}
|
|
495
596
|
|
|
496
597
|
function classifyRedirect(
|
|
497
|
-
segment: ReadonlyArray<
|
|
598
|
+
segment: ReadonlyArray<ShellToken>,
|
|
498
599
|
artifacts: ReadonlyArray<NormalizedArtifact>,
|
|
499
600
|
): DestructiveCommandClassification {
|
|
500
601
|
for (let index = 0; index < segment.length; index += 1) {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
602
|
+
// Keep the existing distinction between overwriting and appending here.
|
|
603
|
+
if (segment[index]?.value === ">>" || segment[index]?.value === "&>>") continue;
|
|
604
|
+
const target = redirectWriteTarget(segment[index], segment[index + 1]);
|
|
605
|
+
if (target === null) continue;
|
|
504
606
|
const matches = matchesForPaths([target], artifacts, "target", "redirect can overwrite protected artifacts");
|
|
505
607
|
if (matches.length > 0) {
|
|
506
608
|
return {
|
|
@@ -738,36 +840,47 @@ function isPythonExecutable(executable: string): boolean {
|
|
|
738
840
|
return executable === "python" || executable === "python3" || /^python3\.\d+$/.test(executable);
|
|
739
841
|
}
|
|
740
842
|
|
|
843
|
+
/** Input is one command's argv. Literal words must never be reparsed as shell syntax. */
|
|
741
844
|
function pathArgs(segment: ReadonlyArray<string>, commandIndex: number): string[] {
|
|
742
845
|
const args: string[] = [];
|
|
743
846
|
let endOfOptions = false;
|
|
744
847
|
for (let index = commandIndex + 1; index < segment.length; index += 1) {
|
|
745
848
|
const token = segment[index];
|
|
746
849
|
if (token === undefined) continue;
|
|
747
|
-
if (COMMAND_SEPARATORS.has(token)) break;
|
|
748
850
|
if (!endOfOptions && token === "--") {
|
|
749
851
|
endOfOptions = true;
|
|
750
852
|
continue;
|
|
751
853
|
}
|
|
752
854
|
if (!endOfOptions && token.startsWith("-")) continue;
|
|
753
|
-
if (token === ">" || token === ">>" || token === "<" || token === "<<") {
|
|
754
|
-
index += 1;
|
|
755
|
-
continue;
|
|
756
|
-
}
|
|
757
855
|
args.push(token);
|
|
758
856
|
}
|
|
759
857
|
return args;
|
|
760
858
|
}
|
|
761
859
|
|
|
860
|
+
/** Flat compatibility values; use scanShellLike when operator identity matters. */
|
|
762
861
|
export function tokenizeShellLike(command: string): string[] {
|
|
763
|
-
|
|
862
|
+
return scanShellLike(command).map((token) => token.value);
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
/** Literal argv by command, with actual operators and redirections removed. */
|
|
866
|
+
export function commandArgumentSegments(command: string): string[][] {
|
|
867
|
+
return splitSegments(scanShellLike(command)).map(shellCommandArguments);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/** Literal shell words and operators only; no expansion or script execution. */
|
|
871
|
+
export function scanShellLike(command: string): ShellToken[] {
|
|
872
|
+
const tokens: ShellToken[] = [];
|
|
764
873
|
let current = "";
|
|
874
|
+
let wordStart: number | null = null;
|
|
875
|
+
let quoted = false;
|
|
765
876
|
let quote: "'" | '"' | null = null;
|
|
766
877
|
|
|
767
|
-
const pushCurrent = (): void => {
|
|
768
|
-
if (
|
|
769
|
-
tokens.push(current);
|
|
878
|
+
const pushCurrent = (end: number): void => {
|
|
879
|
+
if (wordStart === null) return;
|
|
880
|
+
tokens.push({ value: current, operator: false, quoted, start: wordStart, end });
|
|
770
881
|
current = "";
|
|
882
|
+
wordStart = null;
|
|
883
|
+
quoted = false;
|
|
771
884
|
};
|
|
772
885
|
|
|
773
886
|
for (let index = 0; index < command.length; index += 1) {
|
|
@@ -779,80 +892,70 @@ export function tokenizeShellLike(command: string): string[] {
|
|
|
779
892
|
continue;
|
|
780
893
|
}
|
|
781
894
|
if (quote === '"' && char === "\\" && index + 1 < command.length) {
|
|
782
|
-
index
|
|
783
|
-
|
|
784
|
-
|
|
895
|
+
const next = command[index + 1] ?? "";
|
|
896
|
+
if (next === "\n" || '$`"\\'.includes(next)) {
|
|
897
|
+
index += 1;
|
|
898
|
+
if (next !== "\n") current += next;
|
|
899
|
+
continue;
|
|
900
|
+
}
|
|
785
901
|
}
|
|
786
902
|
current += char;
|
|
787
903
|
continue;
|
|
788
904
|
}
|
|
789
905
|
|
|
790
906
|
if (char === "'" || char === '"') {
|
|
907
|
+
wordStart ??= index;
|
|
908
|
+
quoted = true;
|
|
791
909
|
quote = char;
|
|
792
910
|
continue;
|
|
793
911
|
}
|
|
794
912
|
if (char === "\\" && index + 1 < command.length) {
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
if (char === "\n") tokens.push(";");
|
|
802
|
-
continue;
|
|
803
|
-
}
|
|
804
|
-
if (char === ";") {
|
|
805
|
-
pushCurrent();
|
|
806
|
-
tokens.push(";");
|
|
807
|
-
continue;
|
|
808
|
-
}
|
|
809
|
-
if (char === "&" && command[index + 1] === "&") {
|
|
810
|
-
pushCurrent();
|
|
811
|
-
tokens.push("&&");
|
|
913
|
+
// Backslash-newline joins lines before tokenization, even between words.
|
|
914
|
+
if (command[index + 1] !== "\n") {
|
|
915
|
+
wordStart ??= index;
|
|
916
|
+
quoted = true;
|
|
917
|
+
current += command[index + 1] ?? "";
|
|
918
|
+
}
|
|
812
919
|
index += 1;
|
|
813
920
|
continue;
|
|
814
921
|
}
|
|
815
|
-
if (char === "
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
index += 1;
|
|
820
|
-
} else {
|
|
821
|
-
tokens.push("|");
|
|
822
|
-
}
|
|
922
|
+
if (char === "#" && wordStart === null) {
|
|
923
|
+
// A comment starts only at an unquoted word boundary. Leave its newline
|
|
924
|
+
// for normal separation so a following command is still inspected.
|
|
925
|
+
while (index + 1 < command.length && command[index + 1] !== "\n") index += 1;
|
|
823
926
|
continue;
|
|
824
927
|
}
|
|
825
|
-
if (char
|
|
826
|
-
pushCurrent();
|
|
827
|
-
if (
|
|
828
|
-
tokens.push(">>");
|
|
829
|
-
index += 1;
|
|
830
|
-
} else {
|
|
831
|
-
tokens.push(">");
|
|
832
|
-
}
|
|
928
|
+
if (/\s/.test(char)) {
|
|
929
|
+
pushCurrent(index);
|
|
930
|
+
if (char === "\n") tokens.push({ value: ";", operator: true, quoted: false, start: index, end: index + 1 });
|
|
833
931
|
continue;
|
|
834
932
|
}
|
|
835
|
-
if (
|
|
836
|
-
pushCurrent();
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
933
|
+
if (";&|><".includes(char)) {
|
|
934
|
+
pushCurrent(index);
|
|
935
|
+
const three = command.slice(index, index + 3);
|
|
936
|
+
const two = command.slice(index, index + 2);
|
|
937
|
+
const value =
|
|
938
|
+
SHELL_REDIRECTIONS.has(three) || COMMAND_SEPARATORS.has(three)
|
|
939
|
+
? three
|
|
940
|
+
: SHELL_REDIRECTIONS.has(two) || COMMAND_SEPARATORS.has(two)
|
|
941
|
+
? two
|
|
942
|
+
: char;
|
|
943
|
+
tokens.push({ value, operator: true, quoted: false, start: index, end: index + value.length });
|
|
944
|
+
index += value.length - 1;
|
|
843
945
|
continue;
|
|
844
946
|
}
|
|
947
|
+
wordStart ??= index;
|
|
845
948
|
current += char;
|
|
846
949
|
}
|
|
847
|
-
pushCurrent();
|
|
950
|
+
pushCurrent(command.length);
|
|
848
951
|
return tokens;
|
|
849
952
|
}
|
|
850
953
|
|
|
851
|
-
function splitSegments(tokens: ReadonlyArray<
|
|
852
|
-
const segments:
|
|
853
|
-
let current:
|
|
954
|
+
function splitSegments(tokens: ReadonlyArray<ShellToken>): ShellToken[][] {
|
|
955
|
+
const segments: ShellToken[][] = [];
|
|
956
|
+
let current: ShellToken[] = [];
|
|
854
957
|
for (const token of tokens) {
|
|
855
|
-
if (COMMAND_SEPARATORS.has(token)) {
|
|
958
|
+
if (token.operator && COMMAND_SEPARATORS.has(token.value)) {
|
|
856
959
|
if (current.length > 0) segments.push(current);
|
|
857
960
|
current = [];
|
|
858
961
|
continue;
|
|
@@ -3,10 +3,10 @@ import { ToolNames } from "../../core/tool-names.js";
|
|
|
3
3
|
import { classify } from "./action-classifier.js";
|
|
4
4
|
import { typedValidationSummary } from "./finish-contract.js";
|
|
5
5
|
import {
|
|
6
|
+
commandArgumentSegments,
|
|
6
7
|
detectValidationCommand,
|
|
7
8
|
extractCommandDeleteTargets,
|
|
8
9
|
extractCommandWriteTargets,
|
|
9
|
-
tokenizeShellLike,
|
|
10
10
|
toolMutationPaths,
|
|
11
11
|
type ValidationCommandScope,
|
|
12
12
|
} from "./protected-artifacts.js";
|
|
@@ -155,7 +155,7 @@ const GIT_PATH_MUTATIONS: ReadonlySet<string> = new Set(["mv", "rm"]);
|
|
|
155
155
|
|
|
156
156
|
function gitPathOperands(command: string): string[] {
|
|
157
157
|
const targets: string[] = [];
|
|
158
|
-
for (const segment of
|
|
158
|
+
for (const segment of commandArgumentSegments(command)) {
|
|
159
159
|
if (segment[0] !== "git") continue;
|
|
160
160
|
const subcommand = segment[1];
|
|
161
161
|
if (subcommand === undefined || !GIT_PATH_MUTATIONS.has(subcommand)) continue;
|
|
@@ -167,26 +167,6 @@ function gitPathOperands(command: string): string[] {
|
|
|
167
167
|
return targets;
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
/**
|
|
171
|
-
* Split the shared tokenizer's output on command separators. Only the
|
|
172
|
-
* git-operand scan above needs segments, and it needs them after tokenization
|
|
173
|
-
* rather than off the raw string.
|
|
174
|
-
*/
|
|
175
|
-
function splitCommandSegments(command: string): string[][] {
|
|
176
|
-
const segments: string[][] = [];
|
|
177
|
-
let current: string[] = [];
|
|
178
|
-
for (const token of tokenizeShellLike(command)) {
|
|
179
|
-
if (token === ";" || token === "&&" || token === "||" || token === "|") {
|
|
180
|
-
if (current.length > 0) segments.push(current);
|
|
181
|
-
current = [];
|
|
182
|
-
continue;
|
|
183
|
-
}
|
|
184
|
-
current.push(token);
|
|
185
|
-
}
|
|
186
|
-
if (current.length > 0) segments.push(current);
|
|
187
|
-
return segments;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
170
|
function commandOf(args: Record<string, unknown> | undefined): string | null {
|
|
191
171
|
const command = args?.command;
|
|
192
172
|
return typeof command === "string" && command.length > 0 ? command : null;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { canonicalizeExistingPath } from "../../core/path-canonical.js";
|
|
4
|
+
import { clioConfigDir } from "../../core/xdg.js";
|
|
5
|
+
import { isSameOrDescendant, type PathPolicyOperation } from "./path-policy.js";
|
|
6
|
+
import { extractCommandCdTargets } from "./protected-artifacts.js";
|
|
7
|
+
|
|
8
|
+
/** Active Clio skill trees are operator-owned, independently of optional path
|
|
9
|
+
* defaults. Keep lexical roots and resolve them again at admission: an operator
|
|
10
|
+
* may install or replace a symlink after the session starts. Reads stay allowed.
|
|
11
|
+
*/
|
|
12
|
+
export function activeClioSkillRoots(cwd: string): string[] {
|
|
13
|
+
return [path.join(cwd, ".clio-coder", "skills"), path.join(clioConfigDir(), "skills")];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function skillMutationReason(
|
|
17
|
+
roots: ReadonlyArray<string>,
|
|
18
|
+
targets: ReadonlyArray<{ operation: PathPolicyOperation; path: string }>,
|
|
19
|
+
cwd: string,
|
|
20
|
+
command: string | null,
|
|
21
|
+
): string | null {
|
|
22
|
+
const workingDirs = [cwd];
|
|
23
|
+
// Existing shell inspection extracts literal path-bearing operations. Include
|
|
24
|
+
// their possible cd bases so a visible cd cannot hide the protected target.
|
|
25
|
+
// This deliberately cannot interpret arbitrary programs, variables or aliases.
|
|
26
|
+
if (command !== null) {
|
|
27
|
+
for (const destination of extractCommandCdTargets(command)) {
|
|
28
|
+
workingDirs.push(path.resolve(workingDirs.at(-1) ?? cwd, expandHome(destination)));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
for (const target of targets) {
|
|
32
|
+
if (target.operation === "read") continue;
|
|
33
|
+
for (const directory of workingDirs) {
|
|
34
|
+
const lexical = path.resolve(directory, expandHome(target.path));
|
|
35
|
+
const resolved = canonicalizeExistingPath(lexical);
|
|
36
|
+
for (const root of roots) {
|
|
37
|
+
for (const boundary of [root, canonicalizeExistingPath(root)]) {
|
|
38
|
+
for (const candidate of [lexical, resolved]) {
|
|
39
|
+
if (
|
|
40
|
+
isSameOrDescendant(candidate, boundary) ||
|
|
41
|
+
(target.operation === "delete" && isSameOrDescendant(boundary, candidate))
|
|
42
|
+
) {
|
|
43
|
+
return `active skill tree ${root} is operator-owned; draft changes outside active skill roots and ask the operator to install or update them`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function expandHome(value: string): string {
|
|
54
|
+
return value === "~" ? homedir() : value.startsWith("~/") ? path.join(homedir(), value.slice(2)) : value;
|
|
55
|
+
}
|