@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,114 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { mkdirSync, writeFileSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { CLIO_ARTIFACT_DIR } from "../core/artifact-paths.js";
5
+ import { readCodewiki } from "../domains/context/codewiki/artifact.js";
6
+ import { buildArchitectureSeed, serializeArchitectureSeed } from "../domains/context/wiki/map-seed.js";
7
+
8
+ const HELP = `Usage:
9
+ clio-coder context map [--out <path>] [--json]
10
+
11
+ Write an archify architecture seed for the current repository from the codewiki
12
+ index, without model calls. The seed is the starting spec for the archify skill:
13
+ components are the largest directory areas, connections are collapsed import
14
+ edges, and sources point at indexed files and lines.
15
+
16
+ Options:
17
+ --out <path> where to write the seed (default: ${CLIO_ARTIFACT_DIR}/maps/<repo>.architecture.json)
18
+ --json print machine-readable details about the written seed
19
+ `;
20
+
21
+ /** Where the seed lands when the operator names no path: a human-transient map artifact. */
22
+ function defaultMapSeedPath(cwd: string): string {
23
+ return path.join(cwd, CLIO_ARTIFACT_DIR, "maps", `${path.basename(cwd)}.architecture.json`);
24
+ }
25
+
26
+ function gitValue(cwd: string, args: string[]): string | null {
27
+ try {
28
+ const out = execFileSync("git", args, { cwd, timeout: 5000, stdio: ["ignore", "pipe", "ignore"] })
29
+ .toString("utf8")
30
+ .trim();
31
+ return out.length > 0 ? out : null;
32
+ } catch {
33
+ return null;
34
+ }
35
+ }
36
+
37
+ /** The origin remote as an https URL and HEAD as a full sha, when git can say. */
38
+ function repositoryFacts(cwd: string): { url: string; revision: string } | undefined {
39
+ const remote = gitValue(cwd, ["remote", "get-url", "origin"]);
40
+ const revision = gitValue(cwd, ["rev-parse", "--verify", "HEAD"]);
41
+ if (!remote || !revision) return undefined;
42
+ let url = remote.endsWith(".git") ? remote.slice(0, -4) : remote;
43
+ const ssh = /^git@([^:]+):(.+)$/.exec(url);
44
+ if (ssh) url = `https://${ssh[1]}/${ssh[2]}`;
45
+ return { url, revision };
46
+ }
47
+
48
+ export async function runContextMapCommand(args: string[]): Promise<number> {
49
+ if (args.includes("--help") || args.includes("-h")) {
50
+ process.stdout.write(HELP);
51
+ return 0;
52
+ }
53
+ let out: string | null = null;
54
+ let json = false;
55
+ for (let index = 0; index < args.length; index += 1) {
56
+ const arg = args[index] as string;
57
+ if (arg === "--json") {
58
+ json = true;
59
+ continue;
60
+ }
61
+ if (arg === "--out") {
62
+ const value = args[index + 1];
63
+ if (!value || value.startsWith("--")) {
64
+ process.stderr.write("clio-coder context map: --out requires a path\n");
65
+ return 2;
66
+ }
67
+ out = value;
68
+ index += 1;
69
+ continue;
70
+ }
71
+ process.stderr.write(`clio-coder context map: unknown flag ${arg}\n`);
72
+ return 2;
73
+ }
74
+ const cwd = process.cwd();
75
+ const codewiki = readCodewiki(cwd);
76
+ if (!codewiki) {
77
+ process.stderr.write(
78
+ "clio-coder context map: no codewiki index in .clio-coder/codewiki.json; run `clio-coder context index` first\n",
79
+ );
80
+ return 1;
81
+ }
82
+ const seed = buildArchitectureSeed(codewiki, {
83
+ title: path.basename(cwd),
84
+ repository: repositoryFacts(cwd),
85
+ });
86
+ const target = out ? path.resolve(cwd, out) : defaultMapSeedPath(cwd);
87
+ mkdirSync(path.dirname(target), { recursive: true });
88
+ writeFileSync(target, serializeArchitectureSeed(seed), "utf8");
89
+ const payload = {
90
+ path: target,
91
+ components: seed.components.length,
92
+ connections: seed.connections.length,
93
+ repository: seed.meta.repository ?? null,
94
+ };
95
+ if (json) {
96
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
97
+ return 0;
98
+ }
99
+ process.stdout.write(
100
+ [
101
+ `clio-coder context map wrote ${target}`,
102
+ ` ${payload.components} components, ${payload.connections} connections${
103
+ payload.repository
104
+ ? `, sources pinned at ${payload.repository.revision.slice(0, 12)}`
105
+ : "; no GitHub origin at a full revision, so no source citations"
106
+ }`,
107
+ payload.repository
108
+ ? " next: validate and deliver it with the archify skill, passing --repo-root ."
109
+ : " next: validate and deliver it with the archify skill (without --repo-root)",
110
+ "",
111
+ ].join("\n"),
112
+ );
113
+ return 0;
114
+ }
@@ -10,6 +10,7 @@ const HELP = `Usage:
10
10
  [--target <id>] [--model <id>] [--thinking off|low|medium|high]
11
11
  clio-coder context reset [--all] [--yes]
12
12
  clio-coder context index [--json]
13
+ clio-coder context map [--out <path>] [--json]
13
14
  clio-coder context replay --sessions <path>... [options]
14
15
  clio-coder context working-set --session <id|path>
15
16
 
@@ -20,6 +21,7 @@ Project context commands:
20
21
  clio-coder context wiki generate or inspect the agent-authored Markdown wiki
21
22
  clio-coder context reset clear accumulated project context artifacts
22
23
  clio-coder context index build the codewiki index without model calls
24
+ clio-coder context map write an archify architecture seed from the codewiki index
23
25
  clio-coder context replay compare working-set policies over Clio ledgers
24
26
  clio-coder context working-set inspect one session's working-set fold and path index
25
27
  `;
@@ -317,6 +319,8 @@ export async function runContextCommand(args: string[]): Promise<number> {
317
319
  return (await import("./context-clear.js")).runContextClearCommand(rest);
318
320
  case "index":
319
321
  return (await import("./context-index.js")).runContextIndexCommand(rest);
322
+ case "map":
323
+ return (await import("./context-map.js")).runContextMapCommand(rest);
320
324
  case "replay":
321
325
  return (await import("./context-working-set.js")).runContextReplayCommand(rest);
322
326
  case "working-set":
package/src/cli/index.ts CHANGED
@@ -56,6 +56,7 @@ Usage:
56
56
  clio-coder context wiki [--update] [--status] [--depth auto|simple|medium|detailed] [--target <id>] [--model <id>]
57
57
  clio-coder context reset [--all] [--yes] clear accumulated project context artifacts
58
58
  clio-coder context index [--json] build the codewiki index without model calls
59
+ clio-coder context map [--out <path>] [--json] write an archify architecture seed from the codewiki index
59
60
  clio-coder context replay --sessions <path>... compare working-set policies over Clio ledgers
60
61
  clio-coder context working-set --session <id|path> inspect one session's working-set state
61
62
  clio-coder uninstall remove all Clio Coder state; --remove-binary also unlinks the launcher
@@ -0,0 +1,436 @@
1
+ import { type Dirent, lstatSync, readdirSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { stdin as defaultInput, stdout as defaultOutput } from "node:process";
5
+ import { createInterface } from "node:readline/promises";
6
+ import chalk from "chalk";
7
+
8
+ import { terminalColumns, wrapPlain } from "./text-layout.js";
9
+
10
+ export interface LifecyclePresenterOptions {
11
+ json?: boolean;
12
+ plain?: boolean;
13
+ stream?: NodeJS.WritableStream;
14
+ inputStream?: NodeJS.ReadableStream;
15
+ /** Terminal width used to wrap prose. Defaults to the stream's columns, else 80. */
16
+ columns?: number;
17
+ }
18
+
19
+ export type LifecycleItemStatus = "remove" | "keep" | "absent" | "skip" | "clean";
20
+
21
+ // `| undefined` on every optional field is required, not decorative: the repo
22
+ // compiles with exactOptionalPropertyTypes, and every inventory in reset and
23
+ // uninstall builds these rows from a conditional that can produce undefined.
24
+ export interface LifecycleItem {
25
+ label: string;
26
+ path: string;
27
+ bytes?: number | null | undefined;
28
+ status?: LifecycleItemStatus | undefined;
29
+ detail?: string | undefined;
30
+ }
31
+
32
+ export interface LifecycleReport {
33
+ command: string;
34
+ title: string;
35
+ method?: string;
36
+ status: "success" | "skipped" | "dry-run" | "error";
37
+ items: LifecycleItem[];
38
+ steps: Array<{ type: string; message: string }>;
39
+ warnings: string[];
40
+ errors: string[];
41
+ advice: Array<{ lead: string; command: string }>;
42
+ summary?: string;
43
+ }
44
+
45
+ /**
46
+ * One decimal above the byte range, which is the precision a size on a lifecycle
47
+ * listing is read at: the operator wants to know whether a root is megabytes or
48
+ * gigabytes before agreeing to delete it, not its third significant figure.
49
+ *
50
+ * Not `formatSize` from pi-agent-core, which this otherwise matches. That one
51
+ * stops at megabytes, so a data root holding evidence and vendored tools reads
52
+ * as `4300.8MB` where the question being asked is whether it is gigabytes; and
53
+ * it writes no space before the unit, which is fine inside a tool observation
54
+ * and wrong in a column of paths a person is scanning.
55
+ */
56
+ export function formatBytes(bytes: number): string {
57
+ if (bytes < 1024) return `${bytes} B`;
58
+ const units = ["KB", "MB", "GB", "TB"];
59
+ let value = bytes / 1024;
60
+ let unitIndex = 0;
61
+ while (value >= 1024 && unitIndex < units.length - 1) {
62
+ value /= 1024;
63
+ unitIndex += 1;
64
+ }
65
+ return `${value.toFixed(1)} ${units[unitIndex]}`;
66
+ }
67
+
68
+ export function measurePath(targetPath: string): {
69
+ bytes: number;
70
+ exists: boolean;
71
+ isDirectory: boolean;
72
+ isSymbolicLink: boolean;
73
+ } {
74
+ let stats: ReturnType<typeof lstatSync>;
75
+ try {
76
+ stats = lstatSync(targetPath);
77
+ } catch {
78
+ return { bytes: 0, exists: false, isDirectory: false, isSymbolicLink: false };
79
+ }
80
+ if (stats.isSymbolicLink()) {
81
+ return { bytes: stats.size, exists: true, isDirectory: false, isSymbolicLink: true };
82
+ }
83
+ if (!stats.isDirectory()) {
84
+ return { bytes: stats.size, exists: true, isDirectory: false, isSymbolicLink: false };
85
+ }
86
+
87
+ let total = 0;
88
+ // A symlinked subdirectory is counted as the link it is and never descended
89
+ // into, so a root that links out to a shared tree reports its own footprint
90
+ // and the walk cannot loop.
91
+ function walk(dir: string): void {
92
+ let entries: Dirent[];
93
+ try {
94
+ entries = readdirSync(dir, { withFileTypes: true });
95
+ } catch {
96
+ return;
97
+ }
98
+ for (const entry of entries) {
99
+ const full = join(dir, entry.name);
100
+ try {
101
+ if (entry.isDirectory()) walk(full);
102
+ else total += lstatSync(full).size;
103
+ } catch {
104
+ // An entry that vanished or cannot be read contributes nothing.
105
+ }
106
+ }
107
+ }
108
+ walk(targetPath);
109
+ return { bytes: total, exists: true, isDirectory: true, isSymbolicLink: false };
110
+ }
111
+
112
+ export function shortenPath(targetPath: string, home = homedir()): string {
113
+ if (!targetPath) return targetPath;
114
+ if (targetPath === home) return "~";
115
+ if (targetPath.startsWith(`${home}/`) || targetPath.startsWith(`${home}\\`)) {
116
+ return `~/${targetPath.slice(home.length + 1)}`;
117
+ }
118
+ return targetPath;
119
+ }
120
+
121
+ /**
122
+ * The kinds of block the rail knows how to space. One blank rail separates two
123
+ * adjacent blocks of different kinds; consecutive blocks of the same kind (a run
124
+ * of detected facts, a run of completed steps) stay together, which is what
125
+ * makes the transcript read as groups rather than as one padded line per call.
126
+ * Spacing lives here rather than in each emitter so no caller can produce a
127
+ * transcript with a doubled or a missing separator.
128
+ */
129
+ type Block = "header" | "step" | "list" | "warn" | "note" | "advice" | "completed" | "message" | "confirm";
130
+
131
+ export class LifecyclePresenter {
132
+ private readonly json: boolean;
133
+ private readonly plain: boolean;
134
+ private readonly out: NodeJS.WritableStream;
135
+ private readonly in: NodeJS.ReadableStream;
136
+ private readonly columns: number;
137
+ private readonly report: LifecycleReport;
138
+ private lastBlock: Block | null = null;
139
+ private emitted = false;
140
+
141
+ constructor(options: LifecyclePresenterOptions = {}) {
142
+ this.json = Boolean(options.json);
143
+ const stream = options.stream ?? defaultOutput;
144
+ const isTty = Boolean((stream as { isTTY?: boolean }).isTTY);
145
+ this.plain = options.plain ?? (!isTty || Boolean(process.env.NO_COLOR));
146
+ this.out = stream;
147
+ this.in = options.inputStream ?? defaultInput;
148
+ // terminalColumns also reads $COLUMNS, so a piped or captured run can be
149
+ // told how wide it is instead of being pinned to 80.
150
+ this.columns = options.columns ?? terminalColumns(stream as { columns?: number | undefined });
151
+ this.report = {
152
+ command: "",
153
+ title: "",
154
+ status: "success",
155
+ items: [],
156
+ steps: [],
157
+ warnings: [],
158
+ errors: [],
159
+ advice: [],
160
+ };
161
+ }
162
+
163
+ isJson(): boolean {
164
+ return this.json;
165
+ }
166
+
167
+ isPlain(): boolean {
168
+ return this.plain;
169
+ }
170
+
171
+ getReport(): LifecycleReport {
172
+ return this.report;
173
+ }
174
+
175
+ setMethod(method: string): void {
176
+ this.report.method = method;
177
+ }
178
+
179
+ /** Open a block, writing the one separator that belongs before it. */
180
+ private open(block: Block): void {
181
+ if (this.lastBlock !== null && this.lastBlock !== block) this.separator();
182
+ this.lastBlock = block;
183
+ }
184
+
185
+ private separator(): void {
186
+ this.out.write(this.plain ? "\n" : `${chalk.cyan("│")}\n`);
187
+ }
188
+
189
+ /**
190
+ * Close the current block, for a caller that is about to draw its own lines
191
+ * on the rail. `configure` hands the rail to the arrow-key selector after
192
+ * rendering a screen's values, and the selector cannot know what came before
193
+ * it.
194
+ */
195
+ blank(): void {
196
+ if (this.json) return;
197
+ this.separator();
198
+ this.lastBlock = null;
199
+ }
200
+
201
+ /** Rail-level prose, wrapped to the terminal so the rail survives a narrow window. */
202
+ private prose(text: string): void {
203
+ const prefix = this.plain ? " " : `${chalk.cyan("│")} `;
204
+ for (const line of wrapPlain(text, this.columns - 3)) this.out.write(`${prefix}${line}\n`);
205
+ }
206
+
207
+ header(title: string, command = ""): void {
208
+ this.report.title = title;
209
+ this.report.command = command;
210
+ if (this.json) return;
211
+ if (this.plain) {
212
+ this.out.write(`\n${title}\n`);
213
+ } else {
214
+ this.out.write(`\n${chalk.cyan("┌")} ${chalk.bold(title)}\n`);
215
+ }
216
+ this.lastBlock = "header";
217
+ }
218
+
219
+ /** One detected fact. Consecutive facts group into a single block. */
220
+ step(text: string): void {
221
+ this.report.steps.push({ type: "step", message: text });
222
+ if (this.json) return;
223
+ this.open("step");
224
+ if (this.plain) this.out.write(` ${text}\n`);
225
+ else this.out.write(`${chalk.blue("●")} ${text}\n`);
226
+ }
227
+
228
+ /** A line of prose on the rail, not a detected fact. */
229
+ note(text: string): void {
230
+ this.report.steps.push({ type: "note", message: text });
231
+ if (this.json) return;
232
+ this.open("note");
233
+ this.prose(text);
234
+ }
235
+
236
+ /**
237
+ * Aligned label/value rows for a settings screen. Not `note()`, because
238
+ * these must not reflow: the column is what makes eight values scannable,
239
+ * and a wrap would put the value under the wrong label.
240
+ */
241
+ fields(rows: ReadonlyArray<readonly [string, string]>): void {
242
+ for (const [label, value] of rows) this.report.steps.push({ type: "field", message: `${label}: ${value}` });
243
+ if (this.json || rows.length === 0) return;
244
+ this.open("step");
245
+ const width = Math.max(...rows.map(([label]) => label.length));
246
+ for (const [label, value] of rows) {
247
+ const padded = `${label}${" ".repeat(width - label.length)}`;
248
+ if (this.plain) this.out.write(` ${padded} ${value}\n`);
249
+ else this.out.write(`${chalk.blue("●")} ${chalk.dim(padded)} ${value}\n`);
250
+ }
251
+ }
252
+
253
+ substep(text: string, glyph = "✓"): void {
254
+ this.report.steps.push({ type: "substep", message: text });
255
+ if (this.json) return;
256
+ this.open("list");
257
+ if (this.plain) {
258
+ this.out.write(` ${glyph} ${text}\n`);
259
+ return;
260
+ }
261
+ const coloredGlyph = glyph === "✓" ? chalk.green(glyph) : chalk.dim(glyph);
262
+ this.out.write(`${chalk.blue("●")} ${coloredGlyph} ${text}\n`);
263
+ }
264
+
265
+ listItems(header: string, items: ReadonlyArray<LifecycleItem>): void {
266
+ for (const item of items) {
267
+ this.report.items.push(item);
268
+ }
269
+ if (this.json) return;
270
+
271
+ this.open("note");
272
+ this.prose(`${header}:`);
273
+ this.open("list");
274
+
275
+ for (const item of items) {
276
+ const sizeStr =
277
+ item.status !== "absent" && item.bytes !== undefined && item.bytes !== null ? ` (${formatBytes(item.bytes)})` : "";
278
+ const removes = item.status === undefined || item.status === "remove";
279
+ let suffix = "";
280
+ if (item.status === "keep") suffix = item.detail ? ` (${item.detail})` : " (kept)";
281
+ else if (item.status === "absent") suffix = item.detail ? ` (${item.detail})` : " (absent)";
282
+ else if (item.status === "skip") suffix = item.detail ? ` (${item.detail})` : " (skipped)";
283
+ else if (item.status === "clean") suffix = item.detail ? ` (${item.detail})` : " (nothing to remove)";
284
+ else if (item.detail) suffix = ` (${item.detail})`;
285
+
286
+ const body = `${item.label}: ${shortenPath(item.path)}${sizeStr}`;
287
+ if (this.plain) {
288
+ this.out.write(` ${removes ? "✓" : "–"} ${body}${suffix}\n`);
289
+ continue;
290
+ }
291
+ const glyph = removes ? chalk.green("✓") : item.status === "skip" ? chalk.yellow("–") : chalk.dim("–");
292
+ const tail = suffix.length === 0 ? "" : item.status === "skip" ? chalk.yellow(suffix) : chalk.dim(suffix);
293
+ this.out.write(
294
+ `${chalk.blue("●")} ${glyph} ${chalk.bold(item.label)}: ${shortenPath(item.path)}${sizeStr}${tail}\n`,
295
+ );
296
+ }
297
+ }
298
+
299
+ /** One action that has already happened. Consecutive results group together. */
300
+ completedStep(text: string): void {
301
+ this.report.steps.push({ type: "completed", message: text });
302
+ if (this.json) return;
303
+ this.open("completed");
304
+ if (this.plain) this.out.write(` ✓ ${text}\n`);
305
+ else this.out.write(`${chalk.green("◇")} ${text}\n`);
306
+ }
307
+
308
+ warn(text: string): void {
309
+ this.report.warnings.push(text);
310
+ if (this.json) return;
311
+ this.open("warn");
312
+ if (this.plain) {
313
+ for (const line of wrapPlain(text, this.columns - 3)) this.out.write(` ${line}\n`);
314
+ return;
315
+ }
316
+ const prefix = `${chalk.yellow("▲")} `;
317
+ const continuation = `${chalk.cyan("│")} `;
318
+ wrapPlain(text, this.columns - 3).forEach((line, index) => {
319
+ this.out.write(`${index === 0 ? prefix : continuation}${chalk.yellow(line)}\n`);
320
+ });
321
+ }
322
+
323
+ /**
324
+ * Record a failure and say it once on stderr. The JSON report is not written
325
+ * here: a command that fails still has advice to add, and emitting mid-flight
326
+ * either dropped it or put a second document on stdout. Callers end on
327
+ * `finish()`.
328
+ */
329
+ fail(message: string, detail?: string): void {
330
+ this.report.status = "error";
331
+ this.report.errors.push(detail ? `${message}: ${detail}` : message);
332
+ if (this.json) return;
333
+ if (this.plain) {
334
+ process.stderr.write(`error: ${message}\n`);
335
+ if (detail) process.stderr.write(` ${detail}\n`);
336
+ return;
337
+ }
338
+ process.stderr.write(`${chalk.red("✖")} ${chalk.red(message)}\n`);
339
+ if (detail) process.stderr.write(`${chalk.cyan("│")} ${chalk.dim(detail)}\n`);
340
+ }
341
+
342
+ commandAdvice(lead: string, command: string): void {
343
+ this.report.advice.push({ lead, command });
344
+ if (this.json) return;
345
+ this.open("advice");
346
+ this.prose(lead);
347
+ for (const line of command.split("\n")) {
348
+ if (this.plain) this.out.write(` ${line}\n`);
349
+ else this.out.write(`${chalk.blue("●")} ${chalk.cyan(line)}\n`);
350
+ }
351
+ }
352
+
353
+ message(text: string): void {
354
+ this.report.steps.push({ type: "message", message: text });
355
+ if (this.json) return;
356
+ this.open("message");
357
+ if (this.plain) this.out.write(` ${text}\n`);
358
+ else this.out.write(`${chalk.cyan("◆")} ${chalk.bold(text)}\n`);
359
+ }
360
+
361
+ /**
362
+ * Ask once, and treat a closed input as a refusal.
363
+ *
364
+ * `rl.question()` from readline/promises settles on an answer and on an abort
365
+ * signal, but not on the input ending: at EOF the interface emits `close` and
366
+ * the promise is simply never resolved. Every caller here guards a delete, so
367
+ * the failure mode was a `clio-coder uninstall` that printed its prompt and
368
+ * then hung forever on Ctrl-D. Racing the `close` event settles that case as
369
+ * "no", which is the only safe reading of an input that stopped talking.
370
+ */
371
+ async confirm(question: string, defaultYes = false): Promise<boolean> {
372
+ if (this.json) return false;
373
+ const hint = defaultYes ? "Y/n" : "y/N";
374
+ this.open("confirm");
375
+ const rl = createInterface({ input: this.in, output: this.out });
376
+ try {
377
+ const promptStr = this.plain
378
+ ? ` ${question} [${hint}]: `
379
+ : `${chalk.cyan("◇")} ${chalk.bold(question)} [${hint}]\n${chalk.cyan("│")} `;
380
+ const answer = await new Promise<string | null>((resolve) => {
381
+ let settled = false;
382
+ const settle = (value: string | null): void => {
383
+ if (settled) return;
384
+ settled = true;
385
+ resolve(value);
386
+ };
387
+ rl.once("close", () => settle(null));
388
+ rl.question(promptStr).then(
389
+ (value) => settle(value),
390
+ () => settle(null),
391
+ );
392
+ });
393
+ if (answer === null) return false;
394
+ const normalized = answer.trim().toLowerCase();
395
+ const confirmed = normalized.length === 0 ? defaultYes : normalized === "y" || normalized === "yes";
396
+ this.out.write(this.plain ? ` ${confirmed ? "Yes" : "No"}\n` : `${chalk.cyan("│")} ${confirmed ? "Yes" : "No"}\n`);
397
+ return confirmed;
398
+ } finally {
399
+ rl.close();
400
+ }
401
+ }
402
+
403
+ /**
404
+ * Close the transcript. Every command ends here, on success and on failure,
405
+ * so `--json` emits exactly one document containing everything that was
406
+ * recorded, including advice added after a failure.
407
+ */
408
+ done(summary = "Done"): void {
409
+ this.report.summary = summary;
410
+ if (this.json) {
411
+ this.emit();
412
+ return;
413
+ }
414
+ if (this.plain) {
415
+ this.out.write(`\n${summary}\n`);
416
+ return;
417
+ }
418
+ this.separator();
419
+ this.out.write(`${chalk.cyan("└")} ${chalk.bold(summary)}\n\n`);
420
+ }
421
+
422
+ /** Emit the JSON report without a closing line, for paths that ended in an error. */
423
+ finish(): void {
424
+ if (this.json) this.emit();
425
+ }
426
+
427
+ private emit(): void {
428
+ if (this.emitted) return;
429
+ this.emitted = true;
430
+ this.out.write(`${JSON.stringify(this.report, null, 2)}\n`);
431
+ }
432
+ }
433
+
434
+ export function createLifecyclePresenter(options: LifecyclePresenterOptions = {}): LifecyclePresenter {
435
+ return new LifecyclePresenter(options);
436
+ }
package/src/cli/models.ts CHANGED
@@ -14,6 +14,8 @@ export interface ModelRow {
14
14
  targetId: string;
15
15
  runtimeId: string;
16
16
  modelId: string;
17
+ label?: string;
18
+ source: string;
17
19
  caps: string;
18
20
  contextWindow: number;
19
21
  maxTokens: number;
@@ -128,6 +130,7 @@ function collectRows(entries: ReadonlyArray<TargetStatus>, providers: ProvidersC
128
130
  targetId: status.target.id,
129
131
  runtimeId,
130
132
  modelId: "(no models)",
133
+ source: status.discoveredModelsSource ?? "none",
131
134
  state: "-",
132
135
  ...formatCapabilities(caps),
133
136
  });
@@ -140,6 +143,8 @@ function collectRows(entries: ReadonlyArray<TargetStatus>, providers: ProvidersC
140
143
  targetId: status.target.id,
141
144
  runtimeId,
142
145
  modelId,
146
+ ...(candidate.label ? { label: candidate.label } : {}),
147
+ source: candidate.source,
143
148
  state: candidate.loadState ?? "-",
144
149
  ...formatCapabilities(caps),
145
150
  });
@@ -219,11 +224,14 @@ function truncateModelId(id: string): string {
219
224
 
220
225
  function modelTableLines(rows: ReadonlyArray<ModelRow>): string[] {
221
226
  const includeState = rows.some((row) => row.state && row.state !== "-");
227
+ const includeLabel = rows.some((row) => row.label && row.label !== row.modelId);
222
228
  const headers = includeState
223
- ? ["target", "runtime", "model", "state", "caps", "ctx", "max"]
224
- : ["target", "runtime", "model", "caps", "ctx", "max"];
229
+ ? ["target", "runtime", "model", ...(includeLabel ? ["label"] : []), "source", "state", "caps", "ctx", "max"]
230
+ : ["target", "runtime", "model", ...(includeLabel ? ["label"] : []), "source", "caps", "ctx", "max"];
225
231
  const cells = rows.map((row) => {
226
232
  const base = [row.targetId, row.runtimeId, truncateModelId(row.modelId)];
233
+ if (includeLabel) base.push(row.label ?? "-");
234
+ base.push(row.source);
227
235
  if (includeState) base.push(row.state || "-");
228
236
  base.push(row.caps, compactTokenCount(row.contextWindow), compactTokenCount(row.maxTokens));
229
237
  return base;
@@ -153,10 +153,14 @@ function resultFromEvent(event: ChatLoopEvent, current: HeadlessMainAgentResult)
153
153
  }
154
154
  if (event.type !== "message_end") return current;
155
155
  const message = event.message;
156
+ if (message?.role !== "assistant") return current;
156
157
  const error = assistantError(message);
157
158
  if (error) return { ...current, text: "", error };
158
159
  const text = assistantText(message).trimEnd();
159
- if (text.length === 0) return current;
160
+ // A successful retry may contain only tool calls. It supersedes the prior
161
+ // provider error even without prose; the terminal tool/answer checks still
162
+ // decide whether the task completed. Tool-result messages cannot clear it.
163
+ if (text.length === 0) return { ...current, error: null };
160
164
  return { ...current, text, error: null };
161
165
  }
162
166