@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
@@ -0,0 +1,35 @@
1
+ import { BusChannels } from "../core/bus-events.js";
2
+ import type { SafeEventBus } from "../core/event-bus.js";
3
+ import type { TaskMemoryStepUsage } from "../domains/memory/task-memory-policy.js";
4
+ import type { MemoryInterventionRegistration } from "../domains/middleware/memory-intervention.js";
5
+ import {
6
+ type RecordBackgroundMemoryStepInput,
7
+ recordBackgroundMemoryStep,
8
+ } from "../domains/observability/background-memory-usage.js";
9
+
10
+ /** Explicit navigation owns memory lifetime; ordinary leaf advances and tree reads do not. */
11
+ export function bindTaskMemoryLifecycle(
12
+ bus: SafeEventBus,
13
+ memory: Pick<MemoryInterventionRegistration, "reset" | "dispose">,
14
+ ): () => void {
15
+ const unsubscribe = [
16
+ bus.on(BusChannels.SessionParked, () => memory.reset()),
17
+ bus.on(BusChannels.SessionResumed, () => memory.reset()),
18
+ bus.on(BusChannels.SessionTurnSwitched, () => memory.reset()),
19
+ bus.on(BusChannels.SessionEnd, () => memory.dispose()),
20
+ ];
21
+ return () => {
22
+ memory.dispose();
23
+ for (const off of unsubscribe) off();
24
+ };
25
+ }
26
+
27
+ /** The durable row keeps launch identity even when the live cost tracker has moved on. */
28
+ export function captureTaskMemoryUsage(
29
+ input: Omit<RecordBackgroundMemoryStepInput, "usage">,
30
+ ): (usage: TaskMemoryStepUsage, isCurrent: boolean) => void {
31
+ const { observability, ...origin } = input;
32
+ return (usage, isCurrent) => {
33
+ recordBackgroundMemoryStep({ ...origin, usage, observability: isCurrent ? observability : undefined });
34
+ };
35
+ }
@@ -471,11 +471,11 @@ export function backendCacheVerdict(
471
471
  return classifyCacheUsage(input, cacheRead);
472
472
  }
473
473
 
474
- /** Per-API-call latency captured from the agent event stream (T3.2). */
474
+ /** Native stream-invocation latency, measured on one monotonic clock. */
475
475
  export interface AssistantCallTiming {
476
- /** message_start first assistant delta; null when no delta arrived. */
476
+ /** Invocation to first assistant output; null when no output arrived. */
477
477
  ttftMs: number | null;
478
- /** message_start message_end for the same assistant API call. */
478
+ /** Invocation to message_end for the same assistant API call. */
479
479
  apiMs: number;
480
480
  }
481
481
 
@@ -490,7 +490,16 @@ export function assistantSessionPayload(
490
490
  if (Array.isArray(raw.content)) payload.content = raw.content;
491
491
  if (thinking.length > 0) payload.thinking = thinking;
492
492
  payload.responseModelIdObservation = responseModelIdObservationFromRecord(raw, "not-observed");
493
- for (const key of ["usage", "api", "provider", "model", "responseModel", "responseId", "diagnostics"]) {
493
+ for (const key of [
494
+ "usage",
495
+ "api",
496
+ "provider",
497
+ "model",
498
+ "responseModel",
499
+ "responseId",
500
+ "gatewayRouting",
501
+ "diagnostics",
502
+ ]) {
494
503
  if (raw[key] !== undefined) payload[key] = raw[key];
495
504
  }
496
505
  if (failure && !isSelfExplainingAbort({ stopReason: raw.stopReason, errorMessage: raw.errorMessage, text })) {
@@ -16,7 +16,14 @@
16
16
  import { BusChannels, type RunAbortSource } from "../core/bus-events.js";
17
17
  import type { ClioSettings } from "../core/config.js";
18
18
  import type { SafeEventBus } from "../core/event-bus.js";
19
- import type { PendingSkillRequest } from "../core/skill-activation.js";
19
+ import {
20
+ armedSkillSurface,
21
+ type PendingSkillRequest,
22
+ type PendingSkillToolPolicy,
23
+ skillSurfaceLabels,
24
+ skillSurfaceNames,
25
+ withModelSkillActivation,
26
+ } from "../core/skill-activation.js";
20
27
  import { clioStateDir } from "../core/xdg.js";
21
28
  import {
22
29
  createMiddlewareToolChoiceControl,
@@ -36,6 +43,7 @@ import {
36
43
  runtimeTargetSnapshot,
37
44
  targetRequiresAuth,
38
45
  } from "../domains/providers/index.js";
46
+ import { type AutonomyLevel, modelMayActivateSkills } from "../domains/safety/autonomy.js";
39
47
  import type { ProtectedArtifactState } from "../domains/safety/protected-artifacts.js";
40
48
  import type { CompactResult } from "../domains/session/compaction/compact.js";
41
49
  import type { ContextSnapshot, ContextUsageSnapshot } from "../domains/session/context-accounting.js";
@@ -285,6 +293,12 @@ export interface ChatLoop {
285
293
  * queues the text for the next slot instead.
286
294
  */
287
295
  interruptRefusal(): string | null;
296
+ /**
297
+ * `/skill off`: drop the tool surface an activated skill armed, so the next
298
+ * turn runs with the full surface again. Returns the skill names that were
299
+ * armed, or an empty list when nothing was.
300
+ */
301
+ clearSkillSurface(): ReadonlyArray<string>;
288
302
  clearQueuedFollowUps(): string[];
289
303
  queuedMessages(): QueuedMessagesSnapshot;
290
304
  cancel(options?: ChatCancelOptions): void;
@@ -368,6 +382,12 @@ export interface ChatLoop {
368
382
 
369
383
  export interface CreateChatLoopDeps {
370
384
  getSettings: () => Readonly<ClioSettings>;
385
+ /**
386
+ * The same effective autonomy level registry admission resolves, so the
387
+ * skill-activation gate and the tool gate can never disagree. Absent falls
388
+ * back to the settings value.
389
+ */
390
+ getAutonomy?: () => AutonomyLevel;
371
391
  providers: ProvidersContract;
372
392
  /**
373
393
  * Whitelist of target ids that the chat-loop is allowed to drive. The
@@ -622,6 +642,31 @@ export function createChatLoop(deps: CreateChatLoopDeps): ChatLoop {
622
642
  emit({ type: "notice", level, surface: "transcript", text, ...(key === undefined ? {} : { key }) });
623
643
  };
624
644
 
645
+ /**
646
+ * Carry (or drop) the tool surface a skill declared once the turn that
647
+ * loaded it settles, and say so once on the transcript. The operator needs
648
+ * to know a narrowing is armed across their next messages, and needs one
649
+ * line back when it lifts; the skill-activation ledger entry already
650
+ * records provenance, so this is the notice, not a second UI.
651
+ */
652
+ const armSkillSurface = (policy: PendingSkillToolPolicy | undefined, loadedBefore?: ReadonlySet<string>): void => {
653
+ const previous = skillSurfaceNames(state.activeSkillSurface).join(", ");
654
+ const next = armedSkillSurface(policy);
655
+ const current = skillSurfaceNames(next).join(", ");
656
+ state.activeSkillSurface = next;
657
+ const activated = skillSurfaceLabels(policy).filter((label) => !loadedBefore?.has(label.split(" ")[0] ?? label));
658
+ if (activated.length > 0) {
659
+ emitNotice(
660
+ current.length > 0
661
+ ? `[Clio Coder] Skill activated: ${activated.join(", ")}. Its tool surface stays armed across your next turns until another skill replaces it or you run /skill off.`
662
+ : `[Clio Coder] Skill activated: ${activated.join(", ")}. It declares no tool narrowing.`,
663
+ );
664
+ }
665
+ if (current !== previous && current.length === 0 && previous.length > 0) {
666
+ emitNotice(`[Clio Coder] Skill tool surface cleared: ${previous}. The full tool surface is back.`);
667
+ }
668
+ };
669
+
625
670
  /**
626
671
  * The same transcript notice every admission exit already emitted, carrying
627
672
  * the reason the turn never started. Text, level, and surface are unchanged,
@@ -745,6 +790,7 @@ export function createChatLoop(deps: CreateChatLoopDeps): ChatLoop {
745
790
  context,
746
791
  middleware,
747
792
  retrySettings,
793
+ sessionId: () => deps.session?.current()?.id,
748
794
  emit: emitRuntimeEvent,
749
795
  emitNotice,
750
796
  toolStartTimes,
@@ -959,6 +1005,11 @@ export function createChatLoop(deps: CreateChatLoopDeps): ChatLoop {
959
1005
  steer: (text) => queues.steer(text),
960
1006
  queueFollowUp: (text) => queues.queueFollowUp(text),
961
1007
  interruptRefusal: () => (state.streaming ? interruptRefusalReason() : null),
1008
+ clearSkillSurface: () => {
1009
+ const cleared = skillSurfaceNames(state.activeSkillSurface);
1010
+ armSkillSurface(undefined);
1011
+ return cleared;
1012
+ },
962
1013
  clearQueuedFollowUps: () => queues.clearQueuedMirror().map((entry) => entry.text),
963
1014
  queuedMessages: () => queues.queuedMessages(),
964
1015
 
@@ -1043,7 +1094,18 @@ export function createChatLoop(deps: CreateChatLoopDeps): ChatLoop {
1043
1094
  const images = options.images && options.images.length > 0 ? [...options.images] : undefined;
1044
1095
  const pendingSkillRequests = options.pendingSkillRequests ?? [];
1045
1096
  context.addWorkingContextPaths(options.workingContextPaths ?? []);
1046
- const pendingSkillPolicy = createPendingSkillToolPolicy(pendingSkillRequests);
1097
+ // A skill the operator activated narrows the tools for the workflow
1098
+ // it started, and that workflow outlives the turn it began in. A
1099
+ // fresh /skill this turn replaces the armed surface; otherwise the
1100
+ // armed surface is what this turn runs under.
1101
+ const pendingSkillPolicy = withModelSkillActivation(
1102
+ createPendingSkillToolPolicy(pendingSkillRequests) ?? state.activeSkillSurface,
1103
+ modelMayActivateSkills(deps.getAutonomy?.() ?? deps.getSettings().safety.autonomy),
1104
+ );
1105
+ // What was already loaded when this turn started, so the settle-time
1106
+ // notice names the skills this turn activated and not the ones a
1107
+ // carried surface has been holding since an earlier message.
1108
+ const skillsLoadedBeforeTurn = new Set(pendingSkillPolicy?.loadedSkillNames ?? []);
1047
1109
  // Resolve the frozen session tool surface before turn_start so intent
1048
1110
  // middleware sees the exact tools this request can actually call.
1049
1111
  agentRuntime.agent.state.tools = resolveSessionTools(
@@ -1310,6 +1372,7 @@ export function createChatLoop(deps: CreateChatLoopDeps): ChatLoop {
1310
1372
  }
1311
1373
  state.currentPendingSkillPolicy = priorPendingSkillPolicy;
1312
1374
  state.currentAskUserPolicy = priorAskUserPolicy;
1375
+ armSkillSurface(pendingSkillPolicy, skillsLoadedBeforeTurn);
1313
1376
  state.activeUserTurnId = null;
1314
1377
  // Safety net for thrown paths where agent_end never delivered;
1315
1378
  // no-op when the agent_end flush already ran.
@@ -451,6 +451,7 @@ function richMessageFromEntry(entry: MessageEntry, maxTextChars?: number): Agent
451
451
  "responseModelIdObservation",
452
452
  "responseModel",
453
453
  "responseId",
454
+ "gatewayRouting",
454
455
  "diagnostics",
455
456
  "contextUsageInvalidated",
456
457
  ]) {
@@ -46,6 +46,7 @@ export interface CostRow {
46
46
  prewarms: number;
47
47
  /** Calls in this row that were proactive-memory steps on the background target. */
48
48
  backgroundMemory: number;
49
+ failedCompaction: number;
49
50
  cost: CostAggregate;
50
51
  }
51
52
 
@@ -79,6 +80,7 @@ export function aggregateCostEntries(entries: ReadonlyArray<CostEntry>): CostRow
79
80
  if (entry.label === "handoff") existing.row.handoffs += 1;
80
81
  if (entry.label === "prewarm") existing.row.prewarms += 1;
81
82
  if (entry.label === "background-memory") existing.row.backgroundMemory += 1;
83
+ if (entry.label === "failed-compaction") existing.row.failedCompaction += 1;
82
84
  for (const requestedModelId of entry.requestedModelIds) existing.requestedModelIds.add(requestedModelId);
83
85
  addResponseModelIdObservationCounts(
84
86
  existing.responseModelIdObservationCounts,
@@ -103,6 +105,7 @@ export function aggregateCostEntries(entries: ReadonlyArray<CostEntry>): CostRow
103
105
  handoffs: entry.label === "handoff" ? 1 : 0,
104
106
  prewarms: entry.label === "prewarm" ? 1 : 0,
105
107
  backgroundMemory: entry.label === "background-memory" ? 1 : 0,
108
+ failedCompaction: entry.label === "failed-compaction" ? 1 : 0,
106
109
  },
107
110
  requestedModelIds: new Set(entry.requestedModelIds),
108
111
  responseModelIdObservationCounts: { ...entry.responseModelIdObservationCounts },
@@ -143,6 +146,7 @@ function sumRows(
143
146
  handoffs: acc.handoffs + row.handoffs,
144
147
  prewarms: acc.prewarms + row.prewarms,
145
148
  backgroundMemory: acc.backgroundMemory + row.backgroundMemory,
149
+ failedCompaction: acc.failedCompaction + row.failedCompaction,
146
150
  }),
147
151
  {
148
152
  runs: 0,
@@ -157,6 +161,7 @@ function sumRows(
157
161
  handoffs: 0,
158
162
  prewarms: 0,
159
163
  backgroundMemory: 0,
164
+ failedCompaction: 0,
160
165
  },
161
166
  );
162
167
  }
@@ -229,13 +234,26 @@ function summaryBlock(
229
234
  return kvBlock([
230
235
  [
231
236
  "turns",
232
- formatTokens(totals.runs - totals.sideQuestions - totals.handoffs - totals.prewarms - totals.backgroundMemory),
237
+ formatTokens(
238
+ totals.runs -
239
+ totals.sideQuestions -
240
+ totals.handoffs -
241
+ totals.prewarms -
242
+ totals.backgroundMemory -
243
+ totals.failedCompaction,
244
+ ),
233
245
  ],
234
246
  ["model calls", formatTokens(totals.apiCalls)],
235
247
  ...(totals.sideQuestions > 0 ? [["side questions", formatTokens(totals.sideQuestions)] as const] : []),
236
248
  ...(totals.handoffs > 0 ? [["handoffs", formatTokens(totals.handoffs)] as const] : []),
237
249
  ...(totals.prewarms > 0 ? [["pre-warms", formatTokens(totals.prewarms)] as const] : []),
238
250
  ...(totals.backgroundMemory > 0 ? [["memory steps", formatTokens(totals.backgroundMemory)] as const] : []),
251
+ ...(totals.failedCompaction > 0
252
+ ? [
253
+ ["failed compaction calls", formatTokens(totals.failedCompaction)] as const,
254
+ ["compaction usage", "known subtotals; missing usage is unknown"] as const,
255
+ ]
256
+ : []),
239
257
  ...(cost === null ? [] : [["cost", cost] as const]),
240
258
  ["input", formatTokens(totals.input)],
241
259
  ["output", formatTokens(totals.output)],
@@ -255,12 +273,18 @@ function modelBlock(row: CostRow): string[] {
255
273
  return kvBlock([
256
274
  ["requested model ids", row.requestedModelIds.join(", ")],
257
275
  ["response model id observation", responseModelIdObservationCountsLabel(row.responseModelIdObservationCounts)],
258
- ["turns", formatTokens(row.runs - row.sideQuestions - row.handoffs - row.prewarms - row.backgroundMemory)],
276
+ [
277
+ "turns",
278
+ formatTokens(
279
+ row.runs - row.sideQuestions - row.handoffs - row.prewarms - row.backgroundMemory - row.failedCompaction,
280
+ ),
281
+ ],
259
282
  ["model calls", formatTokens(row.apiCalls)],
260
283
  ...(row.sideQuestions > 0 ? [["side questions", formatTokens(row.sideQuestions)] as const] : []),
261
284
  ...(row.handoffs > 0 ? [["handoffs", formatTokens(row.handoffs)] as const] : []),
262
285
  ...(row.prewarms > 0 ? [["pre-warms", formatTokens(row.prewarms)] as const] : []),
263
286
  ...(row.backgroundMemory > 0 ? [["memory steps", formatTokens(row.backgroundMemory)] as const] : []),
287
+ ...(row.failedCompaction > 0 ? [["failed compaction calls", formatTokens(row.failedCompaction)] as const] : []),
264
288
  ...(cost === null ? [] : [["cost", cost] as const]),
265
289
  ["input", formatTokens(row.input)],
266
290
  ["output", formatTokens(row.output)],
@@ -62,7 +62,7 @@ export interface InteractiveSlashSubmitExpansion {
62
62
  pendingSkillRequests: PendingSkillRequest[];
63
63
  }
64
64
 
65
- type SlashChat = Pick<ChatLoop, "getSessionId" | "isStreaming" | "submit">;
65
+ type SlashChat = Pick<ChatLoop, "clearSkillSurface" | "getSessionId" | "isStreaming" | "submit">;
66
66
  type SlashChatPanel = Pick<ChatPanel, "appendReplayBlock" | "appendUser" | "clearFoldOverrides">;
67
67
  type UserTurnStatus = import("./chat-panel.js").UserTurnStatus;
68
68
  type SlashResources = Pick<ResourcesContract, "prompts" | "expandPromptTemplate" | "reload">;
@@ -389,6 +389,7 @@ export function createInteractiveSlashRuntime(deps: InteractiveSlashRuntimeDeps)
389
389
  listPrompts: () => deps.resources?.prompts(cwd()) ?? { items: [], diagnostics: [] },
390
390
  ...(resources ? { expandPromptTemplate: (text: string) => resources.expandPromptTemplate(text, cwd()) } : {}),
391
391
  openSkillsHub: deps.openSkillsHub,
392
+ clearSkillSurface: () => deps.chat.clearSkillSurface(),
392
393
  listExtensions: () => deps.extensions?.list(cwd(), { all: true }) ?? [],
393
394
  listAgents: () => deps.agents?.listSpecs().filter((spec) => spec.audience !== "internal") ?? [],
394
395
  listDelegationAgents: () => deps.getSettings?.().integrations.externalAgents.entries ?? [],
@@ -206,6 +206,36 @@ function researchReport(value: Record<string, unknown>): PresentedContractAnswer
206
206
  return { lines: lines.length === 0 ? ["No findings reported."] : lines, footer: `source ${value.source}` };
207
207
  }
208
208
 
209
+ function worldKnowledgeReport(value: Record<string, unknown>): PresentedContractAnswer | null {
210
+ if (
211
+ (value.discovery !== "performed" &&
212
+ value.discovery !== "caller-supplied-only" &&
213
+ value.discovery !== "unavailable") ||
214
+ !Array.isArray(value.facts) ||
215
+ !isStringArray(value.synthesis) ||
216
+ !isStringArray(value.uncertainties) ||
217
+ !isStringArray(value.followUpVerification)
218
+ ) {
219
+ return null;
220
+ }
221
+ const lines: string[] = [];
222
+ for (const raw of value.facts) {
223
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null;
224
+ const fact = raw as Record<string, unknown>;
225
+ const claim = reportString(fact.claim);
226
+ const evidence = reportString(fact.evidence);
227
+ if (claim === null || evidence === null || !isStringArray(fact.sources)) return null;
228
+ lines.push(`- ${claim}`, ` support: ${evidence}`);
229
+ if (fact.sources.length > 0) lines.push(` sources: ${fact.sources.join(", ")}`);
230
+ }
231
+ if (value.synthesis.length > 0) lines.push("Synthesis:", ...value.synthesis.map((item) => `- ${item}`));
232
+ if (value.uncertainties.length > 0) lines.push("Uncertainties:", ...value.uncertainties.map((item) => `- ${item}`));
233
+ if (value.followUpVerification.length > 0) {
234
+ lines.push("Verify next:", ...value.followUpVerification.map((item) => `- ${item}`));
235
+ }
236
+ return { lines: lines.length === 0 ? ["No findings reported."] : lines, footer: `discovery ${value.discovery}` };
237
+ }
238
+
209
239
  function scoutReport(value: Record<string, unknown>): PresentedContractAnswer | null {
210
240
  if (!Array.isArray(value.findings) || typeof value.needsSplit !== "boolean") return null;
211
241
  const lines: string[] = [];
@@ -250,6 +280,8 @@ function presentedContractAnswer(entry: WorkerEntryState): PresentedContractAnsw
250
280
  return verifierReport(value);
251
281
  case "research-report":
252
282
  return researchReport(value);
283
+ case "world-knowledge-report":
284
+ return worldKnowledgeReport(value);
253
285
  case "scout-report":
254
286
  return scoutReport(value);
255
287
  }
@@ -28,7 +28,7 @@ import type {
28
28
  PromptTemplateExpansion,
29
29
  ResourceList,
30
30
  } from "../domains/resources/index.js";
31
- import { parseSkillCommand } from "../domains/resources/index.js";
31
+ import { parseSkillCommand, SKILL_SURFACE_CLEAR_ARG } from "../domains/resources/index.js";
32
32
  import type { ShareImportPlan } from "../domains/share/index.js";
33
33
  import type { UserTask } from "../domains/user-tasks/store.js";
34
34
  import type { ExtensionReloadOutcome } from "../entry/extension-reload.js";
@@ -118,6 +118,8 @@ type SlashCommandVariant =
118
118
  | { kind: "skill-selector" }
119
119
  | { kind: "resources"; family?: "skills" | "prompts" | "extensions"; tab?: LibraryEntryKind; action?: "reload" }
120
120
  | { kind: "skill-invocation"; text: string }
121
+ /** `/skill off`: drop the tool surface an activated skill armed for the session. */
122
+ | { kind: "skill-surface-clear" }
121
123
  | ShareCommandVariant
122
124
  | ArchiveCommandVariant
123
125
  /** `source` is the line the operator typed, echoed above the run's transcript block. */
@@ -595,6 +597,12 @@ export interface SlashCommandContext {
595
597
  */
596
598
  runContextRecall?: (ref: string) => void;
597
599
  openSkillsHub?: (tab?: LibraryEntryKind) => void;
600
+ /**
601
+ * `/skill off`: drop the tool surface an activated skill armed for the
602
+ * session. Returns the names that were armed. Absent on a host with no
603
+ * chat loop, where nothing can be armed in the first place.
604
+ */
605
+ clearSkillSurface?: () => ReadonlyArray<string>;
598
606
  listPrompts: () => ResourceList<PromptTemplate>;
599
607
  /**
600
608
  * Resolve a `/name` against the loaded prompt templates. Absent when the host
@@ -912,9 +920,9 @@ export const BUILTIN_SLASH_COMMANDS: ReadonlyArray<BuiltinSlashCommand> = [
912
920
  },
913
921
  {
914
922
  name: "skill",
915
- description: "Open the Skills Hub or invoke a skill",
923
+ description: "Open the Skills Hub, invoke a skill, or `off` to drop an active skill's tool surface",
916
924
  group: "Work",
917
- kinds: ["skill-selector", "skill-invocation"],
925
+ kinds: ["skill-selector", "skill-invocation", "skill-surface-clear"],
918
926
  args: {
919
927
  positionals: [
920
928
  { name: "name", required: false },
@@ -926,16 +934,26 @@ export const BUILTIN_SLASH_COMMANDS: ReadonlyArray<BuiltinSlashCommand> = [
926
934
  return { kind: "skill-selector" };
927
935
  }
928
936
  const command = parseSkillCommand(trimmed);
929
- if (command) {
930
- return { kind: "skill-invocation", text: trimmed };
937
+ if (!command) return null;
938
+ // `off` is the one reserved name: an installed skill called `off`
939
+ // would still be reachable from the hub, and clearing the armed
940
+ // surface has to stay typeable without a second command.
941
+ if (command.name === SKILL_SURFACE_CLEAR_ARG && command.args.length === 0) {
942
+ return { kind: "skill-surface-clear" };
931
943
  }
932
- return null;
944
+ return { kind: "skill-invocation", text: trimmed };
933
945
  },
934
946
  handle(command, ctx) {
935
947
  if (command.kind === "skill-selector") {
936
948
  ctx.openSkillsHub?.();
937
949
  } else if (command.kind === "skill-invocation") {
938
950
  ctx.submitChat(command.text);
951
+ } else if (command.kind === "skill-surface-clear") {
952
+ const cleared = ctx.clearSkillSurface?.() ?? [];
953
+ ctx.notice(
954
+ "info",
955
+ cleared.length > 0 ? `Skill tool surface cleared: ${cleared.join(", ")}.` : "No skill tool surface is active.",
956
+ );
939
957
  }
940
958
  },
941
959
  },
@@ -1,23 +1,29 @@
1
1
  /**
2
2
  * Abbreviate a wire model id for chips and dashboards without amputating a
3
- * version suffix. Whole dash-separated parts are kept while the joined result
4
- * stays within 18 characters, so `claude-sonnet-5` and `claude-opus-4-8`
5
- * survive intact and `qwen3-coder-30b-a3b-instruct` collapses to
6
- * `qwen3-coder-30b`. A single part longer than 18 characters is hard-clipped.
3
+ * meaningful placement prefix or version suffix. `dynamo/qwen3.8-27b` remains
4
+ * visible as selected; only the leaf is shortened when the complete route is
5
+ * wider than 24 characters.
7
6
  */
8
7
  export function abbreviateModelId(modelId: string | null | undefined): string {
9
- const base = (modelId ?? "").trim().split("/").filter(Boolean).pop() ?? "";
8
+ const segments = (modelId ?? "").trim().split("/").filter(Boolean);
9
+ const base = segments.pop() ?? "";
10
10
  if (base.length === 0) return "model";
11
+ const prefix = segments[0];
12
+ const maxLeaf = prefix ? Math.max(8, 24 - prefix.length - 1) : 18;
11
13
  const parts = base.split("-").filter((part) => part.length > 0);
12
- if (parts.length <= 1) return base.length > 18 ? base.slice(0, 18) : base;
13
- const kept: string[] = [];
14
- for (const part of parts) {
15
- const next = [...kept, part].join("-");
16
- if (kept.length > 0 && next.length > 18) break;
17
- kept.push(part);
14
+ let leaf: string;
15
+ if (parts.length <= 1) leaf = base.length > maxLeaf ? base.slice(0, maxLeaf) : base;
16
+ else {
17
+ const kept: string[] = [];
18
+ for (const part of parts) {
19
+ const next = [...kept, part].join("-");
20
+ if (kept.length > 0 && next.length > maxLeaf) break;
21
+ kept.push(part);
22
+ }
23
+ const joined = kept.join("-");
24
+ leaf = joined.length > maxLeaf ? joined.slice(0, maxLeaf) : joined;
18
25
  }
19
- const joined = kept.join("-");
20
- return joined.length > 18 ? joined.slice(0, 18) : joined;
26
+ return prefix ? `${prefix}/${leaf}` : leaf;
21
27
  }
22
28
 
23
29
  export interface TargetLabelOptions {
@@ -641,8 +641,8 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
641
641
  if (!usage || !deps.observability) return;
642
642
  if (usage.totalTokens <= 0 && usage.cost.total <= 0) return;
643
643
  deps.observability.recordTokens(
644
- agentRuntime.targetId,
645
- agentRuntime.wireModelId,
644
+ usage.targetId ?? agentRuntime.targetId,
645
+ usage.modelId ?? agentRuntime.wireModelId,
646
646
  usage.totalTokens,
647
647
  usage.cost.total,
648
648
  {
@@ -654,7 +654,11 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
654
654
  totalTokens: usage.totalTokens,
655
655
  apiCalls: Math.max(1, Math.round(usage.apiCalls)),
656
656
  },
657
- agentRuntime.runtimeResolution.costProvenance,
657
+ usage.targetId === undefined && usage.modelId === undefined
658
+ ? agentRuntime.runtimeResolution.costProvenance
659
+ : usage.cost.total > 0
660
+ ? "estimated"
661
+ : "unknown",
658
662
  );
659
663
  };
660
664
 
@@ -915,8 +919,8 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
915
919
  if (!summaryLifecycleStarted) startSummaryLifecycle();
916
920
  deps.bus?.emit(BusChannels.CompactionEnd, { trigger, at: Date.now() });
917
921
 
918
- // The summarization call spends tokens on the same target the turn would
919
- // have. The ledger entry carries its usage for a later reseed; this is the
922
+ // The checkpoint identifies the selected summary route; older results
923
+ // fall back to the active chat route. The ledger carries usage for reseed; this is the
920
924
  // live sink, so `/cost` and the footer move the moment /context compact
921
925
  // returns instead of staying byte-identical to before it ran.
922
926
  recordCompactionUsage(agentRuntime, result);
@@ -217,6 +217,14 @@ export function createTurnRecovery(deps: TurnRecoveryDeps): TurnRecovery {
217
217
  text: string,
218
218
  initialFailure: TerminalAssistantFailure,
219
219
  ): Promise<boolean> => {
220
+ // A LiteLLM model id can be a deliberate physical route. Retrying it in
221
+ // Clio obscures the failure, delays operator recovery, and can multiply
222
+ // attempts beneath a gateway. Preserve and emit the one terminal failure;
223
+ // the operator can choose another advertised route with /model.
224
+ if (agentRuntime.runtimeId === "litellm") {
225
+ ensureFailureVisibleAndPersisted(initialFailure);
226
+ return true;
227
+ }
220
228
  const settings = deps.retrySettings();
221
229
  if (!settings.enabled || settings.maxRetries <= 0) return false;
222
230
  if (initialFailure.stopReason === "aborted" || !isRetryableErrorMessage(initialFailure.errorMessage)) return false;
@@ -8,6 +8,7 @@
8
8
  import { performance } from "node:perf_hooks";
9
9
  import type { BackendCompletionTimings } from "../core/cache-telemetry.js";
10
10
  import type { ClioSettings } from "../core/config.js";
11
+ import { gatewayRoutingObservationFromRecord, gatewayRoutingObservationLabel } from "../core/gateway-routing.js";
11
12
  import { attributedModelId } from "../core/response-model-id.js";
12
13
  import type { MiddlewareToolChoiceControl } from "../domains/middleware/index.js";
13
14
  import type { ObservabilityContract } from "../domains/observability/contract.js";
@@ -130,6 +131,8 @@ export interface TurnRuntimeDeps {
130
131
  context: TurnContext;
131
132
  middleware: TurnMiddleware;
132
133
  retrySettings: () => RetrySettings;
134
+ /** Stable Clio session id forwarded only to gateway runtimes that understand it. */
135
+ sessionId?: () => string | undefined;
133
136
  emit: (event: AgentEvent | AssistantDeltaEvent) => void;
134
137
  emitNotice: (text: string) => void;
135
138
  /** Tool-call id to its `performance.now()` start mark; spans only, never an instant. */
@@ -447,6 +450,11 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
447
450
  cleanupSessionResources(state.runtime.agent.sessionId);
448
451
  }
449
452
  let getCurrentAgentSignal: () => AbortSignal | undefined = () => undefined;
453
+ const gatewaySessionId = target.runtime.id === "litellm" ? deps.sessionId?.() : undefined;
454
+ // message_start can follow response headers. Keep each invocation's
455
+ // monotonic anchor before that wait, including custom stream delegates.
456
+ let apiCallStartedAt: number | null = null;
457
+ let apiCallFirstDeltaAt: number | null = null;
450
458
  const handle = deps.createAgent({
451
459
  initialState: {
452
460
  systemPrompt: fallbackIdentityPrompt(),
@@ -456,6 +464,11 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
456
464
  messages: priorMessages,
457
465
  },
458
466
  maxRetryDelayMs: deps.retrySettings().maxDelayMs,
467
+ ...(gatewaySessionId ? { sessionId: gatewaySessionId } : {}),
468
+ onStreamInvocation: () => {
469
+ apiCallStartedAt = performance.now();
470
+ apiCallFirstDeltaAt = null;
471
+ },
459
472
  onPayload: async (payload, currentModel) => {
460
473
  const thinkingPatched = patchProviderThinkingPayload(payload, currentModel, state.currentThinkingLevel);
461
474
  const basePayload = thinkingPatched ?? payload;
@@ -575,10 +588,6 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
575
588
 
576
589
  let streamStartedAt: number | null = null;
577
590
  let firstAssistantDeltaAt: number | null = null;
578
- // Per-API-call timing (T3.2): one assistant message per provider call,
579
- // bounded by message_start/message_end; the first delta marks TTFT.
580
- let apiCallStartedAt: number | null = null;
581
- let apiCallFirstDeltaAt: number | null = null;
582
591
  // First call of the run is the one whose verdict says whether the
583
592
  // backend reused the session prefix; later calls in a tool loop are
584
593
  // trivially warm.
@@ -669,6 +678,15 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
669
678
  }
670
679
  let publicEvent = enrichedEvent;
671
680
  if (enrichedEvent.type === "message_end" && enrichedEvent.message?.role === "assistant") {
681
+ const gatewayRouting = gatewayRoutingObservationFromRecord(
682
+ enrichedEvent.message as unknown as Record<string, unknown>,
683
+ );
684
+ if (
685
+ gatewayRouting !== null &&
686
+ ((gatewayRouting.attemptedFallbacks ?? 0) > 0 || (gatewayRouting.attemptedRetries ?? 0) > 0)
687
+ ) {
688
+ deps.emitNotice(`[Clio Coder] ${gatewayRoutingObservationLabel(gatewayRouting)}`);
689
+ }
672
690
  const interruptedUsage = estimatedUsageForInterruptedTurn(enrichedEvent.message, context.promptSideTokens());
673
691
  if (interruptedUsage !== null) {
674
692
  // Persistence records the same estimate, but it does so after the
@@ -718,17 +736,15 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
718
736
  // mediator, a dropped frame) therefore stops suspending the watchdog
719
737
  // at the turn that issued it instead of for the rest of the run.
720
738
  if (publicEvent?.type === "turn_end") toolsInFlight = 0;
721
- if (publicEvent?.type === "message_start" && publicEvent.message?.role === "assistant") {
722
- apiCallStartedAt = eventClock;
723
- apiCallFirstDeltaAt = null;
724
- }
725
739
  if (publicEvent?.type === "message_update") {
726
740
  const assistantEvent = publicEvent.assistantMessageEvent as { type?: string; delta?: unknown };
727
741
  const hasDelta =
728
- assistantEvent.type === "text_delta" ||
729
- assistantEvent.type === "thinking_delta" ||
730
742
  assistantEvent.type === "toolcall_start" ||
731
- assistantEvent.type === "toolcall_delta";
743
+ ((assistantEvent.type === "text_delta" ||
744
+ assistantEvent.type === "thinking_delta" ||
745
+ assistantEvent.type === "toolcall_delta") &&
746
+ typeof assistantEvent.delta === "string" &&
747
+ assistantEvent.delta.length > 0);
732
748
  if (hasDelta && firstAssistantDeltaAt === null) firstAssistantDeltaAt = eventClock;
733
749
  if (hasDelta && apiCallFirstDeltaAt === null) apiCallFirstDeltaAt = eventClock;
734
750
  }
@@ -127,6 +127,12 @@ export interface ChatTurnState {
127
127
  /** A middleware request_continuation is waiting to resubmit after settle. */
128
128
  pendingRequestContinuation: boolean;
129
129
  currentPendingSkillPolicy: PendingSkillToolPolicy | undefined;
130
+ /**
131
+ * Tool surface an activated skill narrowed, held across the operator's
132
+ * later turns. Replaced when the operator activates a different skill,
133
+ * cleared by `/skill off`, gone with the session.
134
+ */
135
+ activeSkillSurface: PendingSkillToolPolicy | undefined;
130
136
  currentAskUserPolicy: AskUserToolPolicy | undefined;
131
137
  lastRunSnapshot: ChatLoopRunSnapshot | null;
132
138
  }
@@ -153,6 +159,7 @@ export function createTurnState(initialThinkingLevel: ThinkingLevel): ChatTurnSt
153
159
  stalledTurnNudgeSpent: false,
154
160
  pendingRequestContinuation: false,
155
161
  currentPendingSkillPolicy: undefined,
162
+ activeSkillSurface: undefined,
156
163
  currentAskUserPolicy: undefined,
157
164
  lastRunSnapshot: null,
158
165
  };
@@ -59,6 +59,7 @@ const PRESENTED_RESULT_CONTRACTS: ReadonlyArray<WorkerPresentedResultContract> =
59
59
  "debugger-report",
60
60
  "verifier-report",
61
61
  "research-report",
62
+ "world-knowledge-report",
62
63
  "scout-report",
63
64
  ];
64
65