@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,594 @@
1
+ /**
2
+ * Everything `clio-coder configure` knows about building one target, with no
3
+ * prompting in it.
4
+ *
5
+ * This was the middle of configure.ts. It moved out when the first-run wizard
6
+ * became its own screen flow: both the wizard and the flag-driven path resolve
7
+ * a URL, probe it, decide what the model list is, and write the same pointers,
8
+ * and the alternative to a shared module was a circular import between the two
9
+ * files that prompt.
10
+ */
11
+ import chalk from "chalk";
12
+
13
+ import type { ClioSettings } from "../core/config.js";
14
+ import { openAuthStorage, resolveAuthTarget, targetRequiresAuth } from "../domains/providers/auth/index.js";
15
+ import { getCatalogModelForRuntime } from "../domains/providers/catalog.js";
16
+ import { credentialsPresent } from "../domains/providers/credentials.js";
17
+ import {
18
+ isOrchestratorEligibleRuntime,
19
+ listKnownModelsForRuntime,
20
+ type ProviderSupportEntry,
21
+ readTargetModelSnapshot,
22
+ recordTargetModelSnapshot,
23
+ resolveRuntimeAuthTarget,
24
+ } from "../domains/providers/index.js";
25
+ import { probeCapabilitiesForModel } from "../domains/providers/model-capabilities.js";
26
+ import { getRuntimeRegistry } from "../domains/providers/registry.js";
27
+ import type {
28
+ ProbeContext,
29
+ ProbeModelStatus,
30
+ ProbeResult,
31
+ RuntimeDescriptor,
32
+ } from "../domains/providers/types/runtime-descriptor.js";
33
+ import type { TargetDescriptor } from "../domains/providers/types/target-descriptor.js";
34
+ import type { ConfigureCategory } from "./configure-layout.js";
35
+ import { type LiveModelInventory, validateModelChoice } from "./validate-model.js";
36
+
37
+ const DEFAULT_PORTS: Record<string, number> = {
38
+ llamacpp: 8080,
39
+ "llamacpp-anthropic": 8080,
40
+ "llamacpp-completion": 8080,
41
+ "llamacpp-embed": 8080,
42
+ "llamacpp-rerank": 8080,
43
+ "lmstudio-native": 1234,
44
+ lmstudio: 1234,
45
+ "ollama-native": 11434,
46
+ vllm: 8000,
47
+ sglang: 30000,
48
+ "lemonade-anthropic": 8000,
49
+ lemonade: 8000,
50
+ "anthropic-compat": 8000,
51
+ "openai-compat": 8000,
52
+ litellm: 4000,
53
+ };
54
+
55
+ function trimTrailing(url: string): string {
56
+ return url.endsWith("/") && url.length > 1 ? url.slice(0, -1) : url;
57
+ }
58
+
59
+ export function normalizeUrl(input: string, runtimeId: string): string {
60
+ const trimmed = input.trim();
61
+ if (trimmed.length === 0) return defaultUrlFor(runtimeId);
62
+ const hasScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed);
63
+ let withScheme = hasScheme ? trimmed : `http://${trimmed}`;
64
+ if (runtimeId === "lmstudio") withScheme = withScheme.replace(/^ws:/u, "http:").replace(/^wss:/u, "https:");
65
+ try {
66
+ const parsed = new URL(withScheme);
67
+ if (!hasScheme && !parsed.port && DEFAULT_PORTS[runtimeId]) {
68
+ parsed.port = String(DEFAULT_PORTS[runtimeId]);
69
+ }
70
+ return trimTrailing(parsed.toString());
71
+ } catch {
72
+ return trimTrailing(withScheme);
73
+ }
74
+ }
75
+
76
+ export function defaultUrlFor(runtimeId: string): string {
77
+ const port = DEFAULT_PORTS[runtimeId];
78
+ return port ? `http://127.0.0.1:${port}` : "http://127.0.0.1:8080";
79
+ }
80
+
81
+ export function deriveTargetId(runtimeId: string, existing: ReadonlyArray<TargetDescriptor>): string {
82
+ const base = runtimeId;
83
+ const taken = new Set(existing.map((e) => e.id));
84
+ if (!taken.has(base)) return base;
85
+ for (let i = 2; i < 1000; i++) {
86
+ const candidate = `${base}-${i}`;
87
+ if (!taken.has(candidate)) return candidate;
88
+ }
89
+ return `${base}-${Date.now()}`;
90
+ }
91
+
92
+ async function buildProbeContext(runtime?: RuntimeDescriptor, target?: TargetDescriptor): Promise<ProbeContext> {
93
+ const probeCtx: ProbeContext = {
94
+ credentialsPresent: credentialsPresent(),
95
+ httpTimeoutMs: 5000,
96
+ };
97
+ if (!runtime || !target || !targetRequiresAuth(target, runtime)) return probeCtx;
98
+ try {
99
+ const resolution = await openAuthStorage().resolveForTarget(resolveAuthTarget(target, runtime), {
100
+ includeFallback: false,
101
+ });
102
+ if (resolution.apiKey) probeCtx.authToken = resolution.apiKey;
103
+ } catch {
104
+ // Let the runtime's probe report its own missing-auth diagnostic.
105
+ }
106
+ return probeCtx;
107
+ }
108
+
109
+ function runtimeKnownModelsFor(runtimeId: string): ReadonlyArray<string> {
110
+ return listKnownModelsForRuntime(runtimeId);
111
+ }
112
+
113
+ function catalogContextWindowFor(runtime: RuntimeDescriptor, modelId: string): number | null {
114
+ const catalogModel = getCatalogModelForRuntime(runtime.id, modelId);
115
+ if (typeof catalogModel?.contextWindow === "number" && catalogModel.contextWindow > 0) {
116
+ return catalogModel.contextWindow;
117
+ }
118
+ if (runtimeKnownModelsFor(runtime.id).includes(modelId) && runtime.defaultCapabilities.contextWindow > 0) {
119
+ return runtime.defaultCapabilities.contextWindow;
120
+ }
121
+ return null;
122
+ }
123
+
124
+ /**
125
+ * Check the resolved model against the catalog where there is one and against
126
+ * the target's own list where there is not. A runtime with no catalog used to
127
+ * pass any string here while the same command had a live list that ruled it
128
+ * out, so the target saved as `ok` and failed on its first
129
+ * turn. Without a catalog or a live list there is nothing to check against, and
130
+ * the note says so rather than implying the id was verified.
131
+ */
132
+ export function validateResolvedModel(
133
+ runtime: RuntimeDescriptor,
134
+ target: Pick<TargetDescriptor, "id" | "url">,
135
+ modelId: string | undefined,
136
+ force: boolean,
137
+ inventory: WireModelInventory,
138
+ ): boolean {
139
+ if (!modelId) return true;
140
+ const knownModels = runtimeKnownModelsFor(runtime.id);
141
+ const live = inventory.source === "probe" ? liveInventoryFor(target, inventory) : undefined;
142
+ const validation = validateModelChoice({ runtimeId: runtime.id, modelId, knownModels, live, force });
143
+ if (!validation.ok) {
144
+ process.stderr.write(`error: ${validation.reason}\n`);
145
+ return false;
146
+ }
147
+ if (validation.warning) process.stderr.write(`warning: ${validation.warning}\n`);
148
+ if (knownModels.length === 0 && live === undefined && runtime.kind === "http") {
149
+ process.stderr.write(
150
+ `warning: could not verify model '${modelId}': ${target.url ?? `target '${target.id}'`} returned no model list; it is saved as written\n`,
151
+ );
152
+ }
153
+ return true;
154
+ }
155
+
156
+ /** The same check without the stderr diagnostics, for a screen that owns its own rail. */
157
+ export function modelChoiceRefusal(
158
+ runtime: RuntimeDescriptor,
159
+ target: { id: string; url?: string | undefined },
160
+ modelId: string,
161
+ inventory: WireModelInventory,
162
+ ): string | null {
163
+ const live = inventory.source === "probe" ? liveInventoryFor(target, inventory) : undefined;
164
+ const validation = validateModelChoice({
165
+ runtimeId: runtime.id,
166
+ modelId,
167
+ knownModels: runtimeKnownModelsFor(runtime.id),
168
+ live,
169
+ force: false,
170
+ });
171
+ return validation.ok ? null : validation.reason;
172
+ }
173
+
174
+ export function validateContextWindowOverride(
175
+ runtime: RuntimeDescriptor,
176
+ modelId: string | undefined,
177
+ contextWindow: number | undefined,
178
+ force: boolean,
179
+ ): boolean {
180
+ if (contextWindow === undefined || !modelId) return true;
181
+ const catalogMax = catalogContextWindowFor(runtime, modelId);
182
+ if (catalogMax === null || contextWindow <= catalogMax) return true;
183
+ const message = `--context-window ${contextWindow} exceeds catalog max ${catalogMax} for model '${modelId}'`;
184
+ if (!force) {
185
+ process.stderr.write(`error: ${message}. Use --force to override.\n`);
186
+ return false;
187
+ }
188
+ process.stderr.write(`warning: ${message}\n`);
189
+ return true;
190
+ }
191
+
192
+ export async function runtimeProbe(
193
+ runtime: RuntimeDescriptor,
194
+ target: TargetDescriptor,
195
+ authToken?: string,
196
+ ): Promise<ProbeResult | null> {
197
+ if (typeof runtime.probe !== "function") return null;
198
+ try {
199
+ const context = await buildProbeContext(runtime, target);
200
+ return await runtime.probe(target, authToken === undefined ? context : { ...context, authToken });
201
+ } catch (err) {
202
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
203
+ }
204
+ }
205
+
206
+ async function runtimeProbeModels(
207
+ runtime: RuntimeDescriptor,
208
+ target: TargetDescriptor,
209
+ authToken?: string,
210
+ ): Promise<string[]> {
211
+ if (typeof runtime.probeModels !== "function") return [];
212
+ try {
213
+ const context = await buildProbeContext(runtime, target);
214
+ return await runtime.probeModels(target, authToken === undefined ? context : { ...context, authToken });
215
+ } catch {
216
+ return [];
217
+ }
218
+ }
219
+
220
+ export function applyTarget(settings: ClioSettings, descriptor: TargetDescriptor): void {
221
+ const idx = settings.targets.findIndex((e) => e.id === descriptor.id);
222
+ if (idx >= 0) settings.targets[idx] = descriptor;
223
+ else settings.targets.push(descriptor);
224
+ }
225
+
226
+ export function setOrchestratorPointer(
227
+ settings: ClioSettings,
228
+ descriptor: TargetDescriptor,
229
+ model?: string | null,
230
+ ): void {
231
+ const runtime = getRuntimeRegistry().get(descriptor.runtime);
232
+ if (!runtime) {
233
+ throw new Error(
234
+ `cannot use target '${descriptor.id}' as orchestrator target because runtime '${descriptor.runtime}' is not registered`,
235
+ );
236
+ }
237
+ if (!isOrchestratorEligibleRuntime(runtime)) {
238
+ throw new Error(
239
+ `cannot use target '${descriptor.id}' as orchestrator target because runtime '${runtime.id}' is not an HTTP/native runtime`,
240
+ );
241
+ }
242
+ settings.chat.target = descriptor.id;
243
+ settings.chat.model = model ?? descriptor.defaultModel ?? null;
244
+ }
245
+
246
+ export function setWorkerDefaultPointer(
247
+ settings: ClioSettings,
248
+ descriptor: TargetDescriptor,
249
+ model?: string | null,
250
+ ): void {
251
+ settings.fleet.default.target = descriptor.id;
252
+ settings.fleet.default.model = model ?? descriptor.defaultModel ?? null;
253
+ }
254
+
255
+ export function setBackgroundPointer(
256
+ settings: ClioSettings,
257
+ descriptor: TargetDescriptor,
258
+ model?: string | null,
259
+ ): void {
260
+ const runtime = getRuntimeRegistry().get(descriptor.runtime);
261
+ if (!runtime || !isOrchestratorEligibleRuntime(runtime)) {
262
+ throw new Error(
263
+ `cannot use target '${descriptor.id}' as background target because runtime '${descriptor.runtime}' is not an HTTP/native runtime`,
264
+ );
265
+ }
266
+ settings.context.memory.target = descriptor.id;
267
+ settings.context.memory.model = model ?? descriptor.defaultModel ?? null;
268
+ }
269
+
270
+ export function assertOrchestratorReplacementEligible(settings: ClioSettings, descriptor: TargetDescriptor): void {
271
+ if (settings.chat.target !== descriptor.id && settings.context.memory.target !== descriptor.id) return;
272
+ const role = settings.chat.target === descriptor.id ? "orchestrator" : "background";
273
+ const runtime = getRuntimeRegistry().get(descriptor.runtime);
274
+ if (!runtime) {
275
+ throw new Error(
276
+ `cannot update ${role} target '${descriptor.id}' because runtime '${descriptor.runtime}' is not registered`,
277
+ );
278
+ }
279
+ if (!isOrchestratorEligibleRuntime(runtime)) {
280
+ throw new Error(`cannot update ${role} target '${descriptor.id}' to non-HTTP/native runtime '${runtime.id}'`);
281
+ }
282
+ }
283
+
284
+ export function setWorkerProfilePointer(
285
+ settings: ClioSettings,
286
+ name: string,
287
+ descriptor: TargetDescriptor,
288
+ model?: string | null,
289
+ ): void {
290
+ const trimmed = name.trim();
291
+ if (trimmed.length === 0) throw new Error("fleet profile name must be non-empty");
292
+ settings.fleet.profiles[trimmed] = {
293
+ target: descriptor.id,
294
+ model: model ?? descriptor.defaultModel ?? null,
295
+ thinkingLevel: "off",
296
+ };
297
+ }
298
+
299
+ /**
300
+ * Whether a target that was probed successfully still has no context window to
301
+ * work from, in which case it will run against the runtime descriptor's
302
+ * placeholder. Callers say so at the moment the target is written, because the
303
+ * alternative is a plausible-looking number the operator never chose and the
304
+ * server never claimed.
305
+ */
306
+ export function contextWindowUndiscovered(descriptor: TargetDescriptor, probe: ProbeResult | null): boolean {
307
+ if (!probe?.ok) return false;
308
+ if (typeof descriptor.capabilities?.contextWindow === "number" && descriptor.capabilities.contextWindow > 0) {
309
+ return false;
310
+ }
311
+ const discovered = probeCapabilitiesForModel(
312
+ {
313
+ target: descriptor,
314
+ probeCapabilities: probe.discoveredCapabilities ?? null,
315
+ probeModelCapabilities: probe.modelCapabilities ?? null,
316
+ probeModelId: probe.capabilityModelId ?? null,
317
+ },
318
+ descriptor.defaultModel,
319
+ );
320
+ return !(typeof discovered?.contextWindow === "number" && discovered.contextWindow > 0);
321
+ }
322
+
323
+ export function warnUndiscoveredContextWindow(descriptor: TargetDescriptor, probe: ProbeResult | null): void {
324
+ if (!contextWindowUndiscovered(descriptor, probe)) return;
325
+ process.stdout.write(
326
+ " warning: the target reported no context window; Clio will use the runtime default as a guess. Set one with --context-window.\n",
327
+ );
328
+ }
329
+
330
+ /** Whether the chosen model is one Clio will send a thinking level to. */
331
+ export function modelSupportsThinking(
332
+ runtime: RuntimeDescriptor,
333
+ descriptor: TargetDescriptor,
334
+ probe: ProbeResult | null,
335
+ ): boolean {
336
+ const discovered = probe
337
+ ? probeCapabilitiesForModel(
338
+ {
339
+ target: descriptor,
340
+ probeCapabilities: probe.discoveredCapabilities ?? null,
341
+ probeModelCapabilities: probe.modelCapabilities ?? null,
342
+ probeModelId: probe.capabilityModelId ?? null,
343
+ },
344
+ descriptor.defaultModel,
345
+ )
346
+ : null;
347
+ if (typeof discovered?.reasoning === "boolean") return discovered.reasoning;
348
+ if (typeof descriptor.capabilities?.reasoning === "boolean") return descriptor.capabilities.reasoning;
349
+ return runtime.defaultCapabilities.reasoning === true;
350
+ }
351
+
352
+ /**
353
+ * What the probe read, as opposed to whether it connected.
354
+ *
355
+ * A health check can pass while every enrichment read behind it returns
356
+ * nothing, and reporting that as `probe ok` makes it indistinguishable from a
357
+ * full read. That is how a target gets blessed at configure time and then
358
+ * fails on the first turn. Naming the gap is the difference between a user who
359
+ * knows to look now and one who finds out from a raw 404 later.
360
+ */
361
+ export function probeReadings(probe: ProbeResult): string[] {
362
+ const readings: string[] = [];
363
+ if (probe.models && probe.models.length > 0) readings.push(`${probe.models.length} models`);
364
+ if (probe.serverVersion) readings.push(probe.serverVersion);
365
+ if (probe.discoveredCapabilities && Object.keys(probe.discoveredCapabilities).length > 0) {
366
+ readings.push("capabilities");
367
+ }
368
+ return readings;
369
+ }
370
+
371
+ /** The probe result as the lines a user reads, cause and next step included. */
372
+ export function probeLines(descriptor: TargetDescriptor, probe: ProbeResult): string[] {
373
+ const latency = probe.latencyMs !== undefined ? ` (${probe.latencyMs}ms)` : "";
374
+ if (!probe.ok) {
375
+ if (descriptor.runtime === "antigravity-code") {
376
+ const next =
377
+ probe.failureKind === "missing"
378
+ ? "install the official Antigravity CLI and put `agy` on PATH"
379
+ : probe.failureKind === "authentication"
380
+ ? "run `agy` yourself and complete sign-in; Clio never reads or manages that session"
381
+ : probe.failureKind === "unsupported-feature"
382
+ ? "update `agy`; this integration requires its structured JSON model catalog"
383
+ : "run `agy` directly to inspect setup, then re-run `clio-coder targets --probe`";
384
+ return [`probe failed${latency}: ${probe.error ?? "unknown"}`, ` ${next}`];
385
+ }
386
+ const where = descriptor.url ? ` ${descriptor.url}` : "";
387
+ return [
388
+ `probe failed${latency}:${where} ${probe.error ?? "unknown"}`,
389
+ ` check the server is running and reachable, then re-run: clio-coder configure --id ${descriptor.id} --url <url>`,
390
+ ];
391
+ }
392
+ const readings = probeReadings(probe);
393
+ if (readings.length > 0) return [`probe ok${latency} ${readings.join(", ")}`];
394
+ return [
395
+ `probe reachable${latency}, but the target answered no model list and no version`,
396
+ " Clio cannot verify the model id or the context window from here and will send both as written.",
397
+ " re-read them once the server serves them with: clio-coder targets --probe",
398
+ ];
399
+ }
400
+
401
+ export interface DescriptorParts {
402
+ url?: string;
403
+ model?: string;
404
+ apiKeyEnv?: string;
405
+ apiKeyRef?: string;
406
+ oauthProfile?: string;
407
+ gateway?: boolean;
408
+ lifecycle?: TargetDescriptor["lifecycle"];
409
+ contextWindow?: number;
410
+ maxTokens?: number;
411
+ reasoning?: boolean;
412
+ lmstudio?: TargetDescriptor["lmstudio"];
413
+ litellm?: TargetDescriptor["litellm"];
414
+ }
415
+
416
+ export function buildDescriptor(runtime: RuntimeDescriptor, id: string, parts: DescriptorParts): TargetDescriptor {
417
+ const descriptor: TargetDescriptor = { id, runtime: runtime.id };
418
+ if (parts.url) descriptor.url = parts.url;
419
+ if (parts.model) descriptor.defaultModel = parts.model;
420
+ const auth: NonNullable<TargetDescriptor["auth"]> = {};
421
+ if (parts.apiKeyEnv) auth.apiKeyEnvVar = parts.apiKeyEnv;
422
+ if (parts.apiKeyRef) auth.apiKeyRef = parts.apiKeyRef;
423
+ if (parts.oauthProfile) auth.oauthProfile = parts.oauthProfile;
424
+ if (Object.keys(auth).length > 0) descriptor.auth = auth;
425
+ if (parts.gateway) descriptor.gateway = true;
426
+ if (parts.lifecycle) descriptor.lifecycle = parts.lifecycle;
427
+ const caps: NonNullable<TargetDescriptor["capabilities"]> = {};
428
+ if (parts.contextWindow !== undefined) caps.contextWindow = parts.contextWindow;
429
+ if (parts.maxTokens !== undefined) caps.maxTokens = parts.maxTokens;
430
+ if (parts.reasoning !== undefined) caps.reasoning = parts.reasoning;
431
+ if (Object.keys(caps).length > 0) descriptor.capabilities = caps;
432
+ if (parts.lmstudio) descriptor.lmstudio = parts.lmstudio;
433
+ if (parts.litellm) descriptor.litellm = parts.litellm;
434
+ return descriptor;
435
+ }
436
+
437
+ export function describeAuthStatus(runtime: RuntimeDescriptor): string {
438
+ const status = openAuthStorage().statusForTarget(resolveRuntimeAuthTarget(runtime), { includeFallback: false });
439
+ // This describes a credential, not a network state. It is printed before the
440
+ // wizard has asked for a URL, so `not connected` read as a connection that
441
+ // had already been tried and failed.
442
+ if (!status.available) return "none stored";
443
+ if (status.source === "environment") return `environment${status.detail ? ` (${status.detail})` : ""}`;
444
+ if (status.source === "stored-api-key") return "stored api key";
445
+ if (status.source === "stored-oauth") return "stored oauth";
446
+ return status.source;
447
+ }
448
+
449
+ /**
450
+ * The model ids a target can be configured with, and where they came from.
451
+ * `probe` is the only source that says anything about the server in front of
452
+ * us right now; `catalog` is static provider knowledge, and `existing` is the
453
+ * list a previous configure recorded, which the server may no longer match.
454
+ */
455
+ export interface WireModelInventory {
456
+ models: string[];
457
+ source: "catalog" | "probe" | "cache" | "legacy" | "none";
458
+ labels?: Readonly<Record<string, string>>;
459
+ /** Redacted explanation when a live catalog could not replace cache/hints. */
460
+ probeError?: string;
461
+ /** Per-model load state when the probe reported it. */
462
+ modelStates?: Readonly<Record<string, ProbeModelStatus>> | undefined;
463
+ }
464
+
465
+ /**
466
+ * Every id the runtime would resolve. LM Studio lists a loaded model under its
467
+ * instance id and keeps the model key only in the state map, and the request
468
+ * path accepts either, so both count as advertised.
469
+ */
470
+ function advertisedModelIds(inventory: Pick<WireModelInventory, "models" | "modelStates">): string[] {
471
+ const ids = [...inventory.models];
472
+ for (const id of Object.keys(inventory.modelStates ?? {})) if (!ids.includes(id)) ids.push(id);
473
+ return ids;
474
+ }
475
+
476
+ function residentModelIds(modelStates: WireModelInventory["modelStates"]): string[] {
477
+ return Object.entries(modelStates ?? {})
478
+ .filter(([, status]) => status.state === "loaded" || status.state === "loading")
479
+ .map(([id]) => id);
480
+ }
481
+
482
+ function liveInventoryFor(
483
+ target: { id: string; url?: string | undefined },
484
+ inventory: WireModelInventory,
485
+ ): LiveModelInventory {
486
+ return {
487
+ targetId: target.id,
488
+ url: target.url,
489
+ models: advertisedModelIds(inventory),
490
+ resident: residentModelIds(inventory.modelStates),
491
+ };
492
+ }
493
+
494
+ export async function resolveSupportedWireModels(
495
+ runtime: RuntimeDescriptor,
496
+ target: TargetDescriptor,
497
+ existing?: TargetDescriptor,
498
+ authToken?: string,
499
+ ): Promise<WireModelInventory> {
500
+ const known = listKnownModelsForRuntime(runtime.id);
501
+ const liveAuthoritative = runtime.externalAgentLoop?.modelCatalog === "live-authoritative";
502
+ // A static catalog stays authoritative unless the runtime declares its live
503
+ // catalog authoritative; only then are the known ids demoted to hints.
504
+ if (known.length > 0 && !liveAuthoritative) return { models: known, source: "catalog" };
505
+ let probeError: string | undefined;
506
+ if (runtime.kind === "http" || liveAuthoritative) {
507
+ // The full probe carries load state alongside the ids; a runtime that
508
+ // lists models only through probeModels still gets its ids checked.
509
+ const probe = await runtimeProbe(runtime, target, authToken);
510
+ if (probe?.ok && probe.models && probe.models.length > 0) {
511
+ recordTargetModelSnapshot(target, probe.models, probe.modelLabels ? { modelLabels: probe.modelLabels } : {});
512
+ return {
513
+ models: [...probe.models],
514
+ source: "probe",
515
+ modelStates: probe.modelStates,
516
+ ...(probe.modelLabels ? { labels: probe.modelLabels } : {}),
517
+ };
518
+ }
519
+ probeError = probe?.error;
520
+ const discovered = await runtimeProbeModels(runtime, target, authToken);
521
+ if (discovered.length > 0) {
522
+ recordTargetModelSnapshot(target, discovered);
523
+ return { models: discovered, source: "probe" };
524
+ }
525
+ }
526
+ const cached = readTargetModelSnapshot(target);
527
+ if (cached && cached.models.length > 0) {
528
+ return {
529
+ models: [...cached.models],
530
+ source: "cache",
531
+ ...(cached.modelLabels ? { labels: cached.modelLabels } : {}),
532
+ ...(probeError ? { probeError } : {}),
533
+ };
534
+ }
535
+ if (known.length > 0) return { models: known, source: "catalog", ...(probeError ? { probeError } : {}) };
536
+ if (existing?.wireModels && existing.wireModels.length > 0) {
537
+ recordTargetModelSnapshot(target, existing.wireModels);
538
+ return { models: [...existing.wireModels], source: "legacy" };
539
+ }
540
+ return { models: [], source: "none", ...(probeError ? { probeError } : {}) };
541
+ }
542
+
543
+ /** Why a target offered no model list, in the words the screen shows. */
544
+ export function inventoryGap(runtime: RuntimeDescriptor, target: { url?: string | undefined }): string {
545
+ if (runtime.externalAgentLoop?.modelCatalog === "live-authoritative") {
546
+ return "Antigravity returned no live model catalog; run `agy` yourself, complete sign-in, then probe again";
547
+ }
548
+ if (runtime.kind !== "http") return `${runtime.id} does not list its models; type the id the provider documents`;
549
+ return `${target.url ?? runtime.id} answered no model list; type the id the server serves`;
550
+ }
551
+
552
+ const LOCAL_APP_RUNTIME_IDS: ReadonlySet<string> = new Set(["ollama-native", "lmstudio"]);
553
+
554
+ // Generic protocol-compatible runtimes. They are classified local-http (they
555
+ // carry a probe and no cloud catalog entry), but a hosted endpoint such as
556
+ // Inception/Mercury is exactly an OpenAI-compatible cloud API, so the wizard
557
+ // also surfaces them under the Cloud API path.
558
+ export const PROTOCOL_COMPAT_RUNTIME_IDS: ReadonlySet<string> = new Set(["openai-compat", "anthropic-compat"]);
559
+
560
+ export function runtimesForCategory(
561
+ entries: ReadonlyArray<ProviderSupportEntry>,
562
+ category: ConfigureCategory,
563
+ ): ProviderSupportEntry[] {
564
+ switch (category) {
565
+ case "local-app":
566
+ return entries.filter((entry) => LOCAL_APP_RUNTIME_IDS.has(entry.runtimeId));
567
+ case "local-http":
568
+ return entries.filter((entry) => entry.group === "local-http" && !LOCAL_APP_RUNTIME_IDS.has(entry.runtimeId));
569
+ case "chatgpt":
570
+ return entries.filter((entry) => entry.runtimeId === "openai-codex");
571
+ case "cloud-api": {
572
+ const byLabel = (a: ProviderSupportEntry, b: ProviderSupportEntry) =>
573
+ a.label.localeCompare(b.label) || a.runtimeId.localeCompare(b.runtimeId);
574
+ const named = entries
575
+ .filter((entry) => entry.group === "cloud-api")
576
+ .slice()
577
+ .sort(byLabel);
578
+ // Surface the generic OpenAI/Anthropic-compatible runtimes here too,
579
+ // shown last and under the cloud heading rather than their native group.
580
+ const compat = entries
581
+ .filter((entry) => PROTOCOL_COMPAT_RUNTIME_IDS.has(entry.runtimeId))
582
+ .map((entry) => ({ ...entry, group: "cloud-api" as const }))
583
+ .sort(byLabel);
584
+ return [...named, ...compat];
585
+ }
586
+ case "all":
587
+ return entries.slice();
588
+ }
589
+ }
590
+
591
+ /** The rail prefix the interactive prompts draw on, matching the presenter's. */
592
+ export function railPrefix(plain: boolean): string {
593
+ return plain ? " " : `${chalk.cyan("│")} `;
594
+ }