@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
@@ -2,32 +2,32 @@ import { spawn } from "node:child_process";
2
2
  import { initializeClioHome } from "../core/init.js";
3
3
  import { clioStateDir } from "../core/xdg.js";
4
4
  import { detectInstallMethod } from "../domains/lifecycle/install-method.js";
5
- import { listMigrations, runPending } from "../domains/lifecycle/migrations/index.js";
5
+ import { listMigrations, readMigrationManifest, runPending } from "../domains/lifecycle/migrations/index.js";
6
6
  import { readStateInfo } from "../domains/lifecycle/state.js";
7
7
  import { getVersionInfo } from "../domains/lifecycle/version.js";
8
- import { printError, printHeader, printOk } from "./shared.js";
8
+ import { createLifecyclePresenter, shortenPath } from "./lifecycle-presenter.js";
9
+ import { printError } from "./shared.js";
9
10
 
10
11
  const CHANNELS = ["latest", "beta", "dev"] as const;
11
12
  type Channel = (typeof CHANNELS)[number];
12
13
 
13
- const HELP = `clio-coder upgrade [--dry-run] [--channel=<latest|beta|dev>] [--skip-migrations]
14
+ const HELP = `clio-coder upgrade [--dry-run] [--channel=<latest|beta|dev>] [--skip-migrations] [--json]
14
15
 
15
- Refresh state metadata and apply pending data-dir migrations. An npm-installed
16
- binary is also reinstalled via npm; a source-checkout install instead prints
16
+ Upgrade Clio Coder and apply pending state migrations. An npm-installed
17
+ binary is reinstalled via npm; a source-checkout install instead prints
17
18
  the git-based update steps and never touches the global npm prefix.
18
19
 
19
20
  Flags:
20
21
  --dry-run print planned actions without changing anything
21
22
  --channel=<chan> npm dist-tag to install (latest|beta|dev). npm installs only.
22
23
  --skip-migrations skip migrations after the install step
24
+ --json emit machine-readable JSON output
25
+ --help, -h show this message
23
26
  `;
24
27
 
25
28
  const SOURCE_UPGRADE_STEPS = ["git pull", "npm run install:local", "hash -r"] as const;
26
-
27
- function printSourceUpgradeSteps(): void {
28
- process.stdout.write("[upgrade] source checkout install: update the code with:\n");
29
- for (const step of SOURCE_UPGRADE_STEPS) process.stdout.write(` ${step}\n`);
30
- }
29
+ /** One wording for the source-update advice. Three paths print it; they used to disagree. */
30
+ const SOURCE_UPGRADE_LEAD = "To update the checkout itself, run:";
31
31
 
32
32
  interface UpgradeOptions {
33
33
  dryRun: boolean;
@@ -35,108 +35,131 @@ interface UpgradeOptions {
35
35
  skipMigrations: boolean;
36
36
  help: boolean;
37
37
  postInstall: boolean;
38
+ json: boolean;
38
39
  }
39
40
 
41
+ /**
42
+ * Positional scan, not `argv.indexOf`. The previous parser looked each token up
43
+ * by value to find its neighbour, so the second `--channel` in a repeated pair
44
+ * read the first one's value, and a value that happened to equal an earlier
45
+ * token was consumed at the wrong index.
46
+ */
40
47
  function parseUpgradeArgs(argv: ReadonlyArray<string>): UpgradeOptions {
41
48
  let dryRun = false;
42
49
  let channel: Channel = "latest";
43
50
  let skipMigrations = false;
44
51
  let help = false;
45
52
  let postInstall = false;
46
- for (const arg of argv) {
47
- if (arg === "upgrade") continue;
48
- if (arg === "--help" || arg === "-h") {
49
- help = true;
50
- continue;
51
- }
52
- if (arg === "--dry-run") {
53
- dryRun = true;
54
- continue;
55
- }
56
- if (arg === "--skip-migrations") {
57
- skipMigrations = true;
58
- continue;
59
- }
60
- if (arg === "--post-install") {
61
- postInstall = true;
62
- continue;
63
- }
64
- if (arg.startsWith("--channel=")) {
65
- const value = arg.slice("--channel=".length);
66
- if (!(CHANNELS as ReadonlyArray<string>).includes(value)) {
67
- throw new Error(`--channel must be one of ${CHANNELS.join("|")}, got '${value}'`);
68
- }
69
- channel = value as Channel;
70
- continue;
53
+ let json = false;
54
+
55
+ const toChannel = (value: string | undefined): Channel => {
56
+ if (value === undefined || !(CHANNELS as ReadonlyArray<string>).includes(value)) {
57
+ throw new Error(`--channel must be one of ${CHANNELS.join("|")}, got '${value ?? ""}'`);
71
58
  }
72
- throw new Error(`unknown upgrade argument: ${arg}`);
59
+ return value as Channel;
60
+ };
61
+
62
+ for (let i = 0; i < argv.length; i += 1) {
63
+ const arg = argv[i];
64
+ if (arg === undefined || arg === "upgrade") continue;
65
+ if (arg === "--help" || arg === "-h") help = true;
66
+ else if (arg === "--dry-run") dryRun = true;
67
+ else if (arg === "--skip-migrations") skipMigrations = true;
68
+ else if (arg === "--post-install") postInstall = true;
69
+ else if (arg === "--json") json = true;
70
+ else if (arg.startsWith("--channel=")) channel = toChannel(arg.slice("--channel=".length));
71
+ else if (arg === "--channel") {
72
+ channel = toChannel(argv[i + 1]);
73
+ i += 1;
74
+ } else throw new Error(`unknown upgrade argument: ${arg}`);
73
75
  }
74
- return { dryRun, channel, skipMigrations, help, postInstall };
76
+ return { dryRun, channel, skipMigrations, help, postInstall, json };
75
77
  }
76
78
 
77
- function streamPrefixed(source: NodeJS.ReadableStream, sink: NodeJS.WritableStream): void {
78
- let buffered = "";
79
- source.on("data", (chunk: Buffer | string) => {
80
- buffered += typeof chunk === "string" ? chunk : chunk.toString("utf8");
81
- let idx = buffered.indexOf("\n");
82
- while (idx !== -1) {
83
- const line = buffered.slice(0, idx);
84
- buffered = buffered.slice(idx + 1);
85
- // A spawned `clio-coder upgrade --post-install` prefixes its own lines;
86
- // wrapping those again printed `[upgrade] [upgrade] ...` for every row.
87
- sink.write(line.startsWith("[upgrade] ") ? `${line}\n` : `[upgrade] ${line}\n`);
88
- idx = buffered.indexOf("\n");
89
- }
90
- });
91
- source.on("end", () => {
92
- if (buffered.length > 0) sink.write(`[upgrade] ${buffered}\n`);
93
- });
79
+ /**
80
+ * What the registry said, and whether it was asked at all.
81
+ *
82
+ * "Not asked" and "asked and could not answer" are different facts, and
83
+ * collapsing both into `null` is what let an offline npm install report itself
84
+ * already current: an unanswered lookup compared nothing, so it cannot conclude
85
+ * the installed version is the newest one.
86
+ */
87
+ type RegistryLookup =
88
+ | { asked: false; reason: "source checkout" | "network checks are disabled" }
89
+ | { asked: true; version: string | null };
90
+
91
+ async function lookUpAvailableVersion(
92
+ channel: Channel,
93
+ method: "source" | "npm",
94
+ noNetwork: boolean,
95
+ ): Promise<RegistryLookup> {
96
+ const seam = process.env.CLIO_CODER_TEST_UPGRADE_AVAILABLE;
97
+ // `unreachable` stands in for a registry that answered nothing, which is the
98
+ // only way to reach that branch without a network in the test.
99
+ if (seam) return { asked: true, version: seam === "unreachable" ? null : seam };
100
+ if (noNetwork) return { asked: false, reason: "network checks are disabled" };
101
+ if (method === "source") return { asked: false, reason: "source checkout" };
102
+ try {
103
+ const res = await fetch(`https://registry.npmjs.org/@iowarp/clio-coder/${channel}`, {
104
+ headers: { Accept: "application/json" },
105
+ signal: AbortSignal.timeout(2500),
106
+ });
107
+ if (!res.ok) return { asked: true, version: null };
108
+ const data = (await res.json()) as { version?: unknown };
109
+ return { asked: true, version: typeof data.version === "string" ? data.version : null };
110
+ } catch {
111
+ return { asked: true, version: null };
112
+ }
94
113
  }
95
114
 
96
- async function runNpmInstall(channel: Channel): Promise<void> {
97
- const args = ["install", "-g", `@iowarp/clio-coder@${channel}`];
98
- process.stdout.write(`[upgrade] npm ${args.join(" ")}\n`);
115
+ /**
116
+ * Run one child to completion, keeping its last output for the failure message.
117
+ *
118
+ * The pipes have to be drained. `npm install -g` writes well past a 64 KB pipe
119
+ * buffer, and a child whose stdout nobody reads blocks on the write and never
120
+ * exits, so the upgrade hung with no output and no way to tell it apart from a
121
+ * slow registry. Draining also gives the failure something to say beyond an
122
+ * exit code.
123
+ */
124
+ async function runChild(command: string, args: ReadonlyArray<string>, label: string): Promise<void> {
99
125
  await new Promise<void>((resolve, reject) => {
100
- const child = spawn("npm", args, { stdio: ["ignore", "pipe", "pipe"] });
101
- streamPrefixed(child.stdout, process.stdout);
102
- streamPrefixed(child.stderr, process.stderr);
126
+ const child = spawn(command, [...args], { stdio: ["ignore", "pipe", "pipe"] });
127
+ let tail = "";
128
+ const keepTail = (chunk: Buffer): void => {
129
+ tail = `${tail}${chunk.toString("utf8")}`.slice(-2000);
130
+ };
131
+ child.stdout?.on("data", keepTail);
132
+ child.stderr?.on("data", keepTail);
103
133
  child.on("error", reject);
104
- child.on("exit", (code) => {
105
- if (code === 0) resolve();
106
- else reject(new Error(`npm exited with code ${code ?? -1}`));
134
+ child.on("close", (code) => {
135
+ if (code === 0) {
136
+ resolve();
137
+ return;
138
+ }
139
+ const lastLine = tail.trimEnd().split("\n").at(-1) ?? "";
140
+ reject(new Error(`${label} exited with code ${code ?? -1}${lastLine ? `: ${lastLine}` : ""}`));
107
141
  });
108
142
  });
109
143
  }
110
144
 
145
+ async function runNpmInstall(channel: Channel): Promise<void> {
146
+ if (process.env.CLIO_CODER_TEST_UPGRADE_FAIL === "npm") {
147
+ throw new Error("npm ERR! 404 Not Found (mock failure)");
148
+ }
149
+ await runChild("npm", ["install", "-g", `@iowarp/clio-coder@${channel}`], "npm install");
150
+ }
151
+
111
152
  async function runDoctorFixAfterInstall(): Promise<void> {
112
- const args = ["doctor", "--fix"];
113
- process.stdout.write(`[upgrade] clio-coder ${args.join(" ")}\n`);
114
- await new Promise<void>((resolve, reject) => {
115
- const child = spawn("clio-coder", args, { stdio: ["ignore", "pipe", "pipe"] });
116
- streamPrefixed(child.stdout, process.stdout);
117
- streamPrefixed(child.stderr, process.stderr);
118
- child.on("error", reject);
119
- child.on("exit", (code) => {
120
- if (code === 0) resolve();
121
- else reject(new Error(`clio-coder doctor --fix exited with code ${code ?? -1}`));
122
- });
123
- });
153
+ if (process.env.CLIO_CODER_TEST_UPGRADE_FAIL === "doctor") {
154
+ throw new Error("mock doctor fix failure");
155
+ }
156
+ await runChild("clio-coder", ["doctor", "--fix"], "clio-coder doctor --fix");
124
157
  }
125
158
 
126
159
  async function runPostInstallUpgrade(opts: UpgradeOptions): Promise<void> {
127
160
  const args = ["upgrade", "--post-install", `--channel=${opts.channel}`];
128
161
  if (opts.skipMigrations) args.push("--skip-migrations");
129
- process.stdout.write(`[upgrade] clio-coder ${args.join(" ")}\n`);
130
- await new Promise<void>((resolve, reject) => {
131
- const child = spawn("clio-coder", args, { stdio: ["ignore", "pipe", "pipe"] });
132
- streamPrefixed(child.stdout, process.stdout);
133
- streamPrefixed(child.stderr, process.stderr);
134
- child.on("error", reject);
135
- child.on("exit", (code) => {
136
- if (code === 0) resolve();
137
- else reject(new Error(`clio-coder upgrade --post-install exited with code ${code ?? -1}`));
138
- });
139
- });
162
+ await runChild("clio-coder", args, "clio-coder upgrade --post-install");
140
163
  }
141
164
 
142
165
  export async function runUpgradeCommand(argv: ReadonlyArray<string>): Promise<number> {
@@ -152,25 +175,36 @@ export async function runUpgradeCommand(argv: ReadonlyArray<string>): Promise<nu
152
175
  return 0;
153
176
  }
154
177
 
178
+ const presenter = createLifecyclePresenter({ json: opts.json });
179
+ presenter.header("Upgrade", "upgrade");
180
+
155
181
  const before = getVersionInfo().clio;
156
182
  const stateDir = clioStateDir();
157
183
  const method = detectInstallMethod();
158
- printHeader("Clio Coder upgrade");
159
- process.stdout.write(`install ${method === "source" ? "source checkout" : "npm"}\n`);
160
- if (method === "npm") process.stdout.write(`channel ${opts.channel}\n`);
161
- process.stdout.write(`current ${before}\n`);
162
- process.stdout.write(`state dir ${stateDir}\n`);
184
+ const methodLabel = method === "source" ? "source checkout" : "npm global";
185
+ presenter.setMethod(methodLabel);
163
186
 
164
187
  const noNetwork = Boolean(process.env.CLIO_CODER_TEST_UPGRADE_NO_NETWORK);
188
+ const lookup = await lookUpAvailableVersion(opts.channel, method, noNetwork);
189
+ const availableVersion = lookup.asked ? lookup.version : null;
190
+
191
+ presenter.step(`Installation method: ${methodLabel}`);
192
+ presenter.step(`Current version: ${before}`);
193
+ // A source checkout is not upgraded from the registry, so the registry is
194
+ // never asked. Reporting that as "registry check failed" told the operator a
195
+ // lookup had gone wrong when none was owed.
196
+ if (availableVersion !== null) presenter.step(`Available version: ${availableVersion}`);
197
+ else if (!lookup.asked) presenter.step(`Available version: not checked (${lookup.reason})`);
198
+ else presenter.step("Available version: unknown (the registry could not be reached)");
199
+ if (method === "npm") presenter.step(`Channel: ${opts.channel}`);
200
+ presenter.step(`State dir: ${shortenPath(stateDir)}`);
201
+
165
202
  const migrations = listMigrations();
166
203
  const migrationIds = migrations.map((m) => m.id);
167
- // What the state root says it is on, as distinct from the binary answering.
168
- // After `npm install -g` the two differ until the refresh below, and that
169
- // difference is the upgrade this command reports.
204
+ const appliedIds = new Set(readMigrationManifest(stateDir).applied);
205
+ const pendingMigrationIds = opts.skipMigrations ? [] : migrationIds.filter((id) => !appliedIds.has(id));
206
+
170
207
  const recorded = readStateInfo()?.version ?? null;
171
- // Both the dry run and the real run print this, so it stays in the mood the
172
- // call site sets with "would refresh" or "refreshed". The null branch used to
173
- // bake in "would write it", which a real upgrade printed after writing it.
174
208
  const describeRefresh = (): string =>
175
209
  recorded === null
176
210
  ? "state metadata (none recorded)"
@@ -178,104 +212,125 @@ export async function runUpgradeCommand(argv: ReadonlyArray<string>): Promise<nu
178
212
  ? `state metadata (already ${before})`
179
213
  : `state metadata ${recorded} -> ${before}`;
180
214
 
215
+ // "Already current" is a claim about a version that was compared. A lookup
216
+ // that was made and came back empty has compared nothing, so it does not get
217
+ // to make it: the run falls through and attempts the install, which is what
218
+ // the operator asked for. A lookup that was never owed (a checkout, or the
219
+ // network seam) leaves the recorded state version to decide.
220
+ const versionIsCurrent =
221
+ (lookup.asked ? lookup.version === before : true) && (recorded === null || recorded === before);
222
+ const hasPendingMigrations = pendingMigrationIds.length > 0;
223
+
224
+ if (versionIsCurrent && !hasPendingMigrations) {
225
+ presenter.warn(`Already on ${before}, with no pending migrations. Nothing to do.`);
226
+ if (method === "source") presenter.commandAdvice(SOURCE_UPGRADE_LEAD, SOURCE_UPGRADE_STEPS.join("\n"));
227
+ if (opts.dryRun) presenter.warn("Dry run: no changes made");
228
+ presenter.done("Done");
229
+ return 0;
230
+ }
231
+
181
232
  if (opts.dryRun) {
182
- if (method === "source") {
183
- printSourceUpgradeSteps();
184
- } else {
185
- process.stdout.write(`[upgrade] would run: npm install -g @iowarp/clio-coder@${opts.channel}\n`);
186
- }
187
- if (opts.skipMigrations) {
188
- process.stdout.write("[upgrade] would skip migrations (--skip-migrations)\n");
189
- } else if (migrationIds.length === 0) {
190
- process.stdout.write("[upgrade] no migrations registered; the manifest would be written as is\n");
191
- } else {
192
- process.stdout.write(`[upgrade] would consider ${migrationIds.length} migration(s):\n`);
193
- for (const id of migrationIds) process.stdout.write(` - ${id}\n`);
233
+ if (method === "source") presenter.commandAdvice(SOURCE_UPGRADE_LEAD, SOURCE_UPGRADE_STEPS.join("\n"));
234
+ else presenter.note(`Would run: npm install -g @iowarp/clio-coder@${opts.channel}`);
235
+ if (opts.skipMigrations) presenter.note("Would skip migrations (--skip-migrations).");
236
+ else if (pendingMigrationIds.length === 0) presenter.note("No pending migrations.");
237
+ else {
238
+ presenter.note(
239
+ `Would apply ${pendingMigrationIds.length} pending migration${pendingMigrationIds.length === 1 ? "" : "s"}:`,
240
+ );
241
+ // As substeps, so a --json consumer sees the plan instead of only the
242
+ // three detected facts the old dry run recorded.
243
+ for (const id of pendingMigrationIds) presenter.substep(id, "–");
194
244
  }
195
- process.stdout.write(`[upgrade] would refresh ${describeRefresh()}\n`);
196
- printOk("dry run complete, no changes made");
245
+ presenter.note(`Would refresh ${describeRefresh()}.`);
246
+ presenter.warn("Dry run: no changes made");
247
+ presenter.done("Done");
197
248
  return 0;
198
249
  }
199
250
 
200
251
  if (opts.postInstall) {
201
- process.stdout.write("[upgrade] running post-install checks with the active clio binary\n");
252
+ presenter.note("Running post-install checks with the active clio-coder binary.");
202
253
  } else if (method === "source") {
203
- process.stdout.write("[upgrade] source checkout install detected; skipping npm install\n");
254
+ presenter.note("Source checkout: no npm install to run.");
204
255
  } else if (noNetwork) {
205
- process.stdout.write("[upgrade] CLIO_CODER_TEST_UPGRADE_NO_NETWORK set, skipping npm install\n");
256
+ presenter.note("CLIO_CODER_TEST_UPGRADE_NO_NETWORK is set; skipping npm install.");
206
257
  } else {
207
258
  try {
208
259
  await runNpmInstall(opts.channel);
260
+ presenter.completedStep(`Installed @iowarp/clio-coder@${opts.channel}`);
209
261
  } catch (err) {
210
- printError(err instanceof Error ? err.message : String(err));
262
+ presenter.fail("npm install failed", err instanceof Error ? err.message : String(err));
263
+ presenter.commandAdvice(
264
+ "To upgrade by hand, run:",
265
+ `npm install -g @iowarp/clio-coder@${opts.channel}\nclio-coder doctor --fix`,
266
+ );
267
+ presenter.finish();
211
268
  return 1;
212
269
  }
213
270
  try {
214
271
  await runPostInstallUpgrade(opts);
215
- printOk(`${before} -> post-install checks complete`);
272
+ presenter.done("Done");
216
273
  return 0;
217
274
  } catch (err) {
218
- printError(err instanceof Error ? err.message : String(err));
275
+ presenter.fail("post-install checks failed", err instanceof Error ? err.message : String(err));
276
+ presenter.commandAdvice("To finish the upgrade by hand, run:", "clio-coder doctor --fix");
277
+ presenter.finish();
219
278
  return 1;
220
279
  }
221
280
  }
222
281
 
223
282
  let appliedCount = 0;
224
- let appliedIds: string[] = [];
225
283
  if (opts.skipMigrations) {
226
- process.stdout.write("[upgrade] skipping migrations (--skip-migrations)\n");
284
+ presenter.note("Skipping migrations (--skip-migrations).");
227
285
  } else {
228
- // Migrations run on the state tree directly rather than through the
229
- // lifecycle domain. Loading that domain pulls in `config`, whose start
230
- // runs the strict settings reader, and a settings-repairing migration is
231
- // precisely the one that cannot get past it: `clio-coder upgrade` on a
232
- // home whose settings.yaml names a retired key failed the domain load and
233
- // never reached the migration that removes the key. A runner that needs
234
- // valid config in order to repair invalid config can never run. The
235
- // domain's `runMigrations` is a passthrough to this same function, so
236
- // nothing is lost by calling it where the circularity does not exist.
237
286
  let result: Awaited<ReturnType<typeof runPending>>;
238
287
  try {
288
+ if (process.env.CLIO_CODER_TEST_UPGRADE_FAIL === "migration") {
289
+ throw new Error("mock migration failure in 2026-09-01-settings-v2");
290
+ }
239
291
  result = await runPending(stateDir);
240
292
  } catch (err) {
241
- // A migration reports why it could not run, but on its own that reads
242
- // as the whole upgrade being impossible. It is not: the rest of the
243
- // upgrade is independent of it, and naming the flag that runs the rest
244
- // is the difference between a stuck operator and a moved one.
245
- printError(
246
- `migration failed: ${err instanceof Error ? err.message : String(err)}`,
247
- "the rest of the upgrade does not depend on it; run `clio-coder upgrade --skip-migrations` to continue, then fix the cause and re-run `clio-coder upgrade`.",
293
+ presenter.fail("migration failed", err instanceof Error ? err.message : String(err));
294
+ presenter.commandAdvice(
295
+ "The rest of the upgrade does not depend on it. To continue, run:",
296
+ "clio-coder upgrade --skip-migrations",
248
297
  );
298
+ presenter.finish();
249
299
  return 1;
250
300
  }
251
- appliedIds = [...result.applied];
252
- appliedCount = appliedIds.length;
253
- if (appliedCount === 0) {
254
- process.stdout.write("[upgrade] no pending migrations\n");
255
- } else {
256
- for (const id of appliedIds) process.stdout.write(`[upgrade] applied migration ${id}\n`);
257
- }
301
+ const applied = [...result.applied];
302
+ appliedCount = applied.length;
303
+ if (appliedCount === 0) presenter.note("No pending migrations.");
304
+ else for (const id of applied) presenter.completedStep(`Applied migration ${id}`);
258
305
  }
259
306
 
260
307
  if (method === "source" || noNetwork) {
261
308
  const refresh = describeRefresh();
262
309
  initializeClioHome();
263
- process.stdout.write(`[upgrade] refreshed ${refresh}\n`);
310
+ presenter.completedStep(`Refreshed ${refresh}`);
264
311
  } else {
265
312
  try {
266
313
  await runDoctorFixAfterInstall();
314
+ presenter.completedStep("Checked the install with clio-coder doctor --fix");
267
315
  } catch (err) {
268
- printError(err instanceof Error ? err.message : String(err));
316
+ presenter.fail("doctor fix failed", err instanceof Error ? err.message : String(err));
317
+ presenter.commandAdvice("To resolve the findings by hand, run:", "clio-coder doctor --fix");
318
+ presenter.finish();
269
319
  return 1;
270
320
  }
271
321
  }
272
322
 
273
- if (method === "source") printSourceUpgradeSteps();
323
+ if (method === "source") presenter.commandAdvice(SOURCE_UPGRADE_LEAD, SOURCE_UPGRADE_STEPS.join("\n"));
274
324
 
275
- // `before` is the binary that ran; on the post-install and local paths that
276
- // is already the new version, and `0.3.1 -> 0.3.1` was a claim about a
277
- // transition that never happened. The version that moved is the recorded one.
278
325
  const after = getVersionInfo().clio;
279
- printOk(`${recorded ?? before} -> ${after} (migrations: ${appliedCount})`);
326
+ // One closing word on every path, with the outcome above it as steps. The
327
+ // summary used to carry the version arrow, so three exits printed three
328
+ // different shapes of last line.
329
+ if (appliedCount > 0 || (recorded ?? before) !== after) {
330
+ presenter.note(
331
+ `Now on ${after}${appliedCount > 0 ? `, ${appliedCount} migration${appliedCount === 1 ? "" : "s"} applied` : ""}.`,
332
+ );
333
+ }
334
+ presenter.done("Done");
280
335
  return 0;
281
336
  }