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