@iowarp/clio-coder 0.3.1 → 0.3.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 (601) hide show
  1. package/CHANGELOG.md +233 -373
  2. package/CONTRIBUTING.md +23 -23
  3. package/README.md +284 -613
  4. package/dist/{acp-FPR54DGL.js → acp-P2AQILE2.js} +43 -53
  5. package/dist/{agents-OGPIHPJH.js → agents-72W3BI7I.js} +43 -26
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-IC3K6NIZ.js → auth-5TWEIYDN.js} +20 -12
  8. package/dist/chunk-2DJ2KNFG.js +2095 -0
  9. package/dist/{chunk-IS3ONKU3.js → chunk-2IR2NMPA.js} +6 -4
  10. package/dist/chunk-2SFS6XQE.js +122 -0
  11. package/dist/{chunk-PV4JUBVJ.js → chunk-2TLUCQVG.js} +40 -21
  12. package/dist/chunk-2VTFPG5O.js +48 -0
  13. package/dist/chunk-4BJ5BYCE.js +61 -0
  14. package/dist/{chunk-474KN5II.js → chunk-4BPJXDWC.js} +111 -181
  15. package/dist/chunk-4VP4KH3K.js +962 -0
  16. package/dist/chunk-4XUGQOHA.js +797 -0
  17. package/dist/chunk-4ZG3XFUR.js +77 -0
  18. package/dist/chunk-5B2AEOW5.js +5407 -0
  19. package/dist/{chunk-K2ITRMHZ.js → chunk-5TSRNF4G.js} +6 -138
  20. package/dist/{chunk-4QKXUHSR.js → chunk-5UFT4SUX.js} +70 -20
  21. package/dist/{chunk-OLBBMFRD.js → chunk-5UUP6MWO.js} +24 -62
  22. package/dist/chunk-65DEGPJ6.js +52 -0
  23. package/dist/chunk-6EJMN2Y3.js +17 -0
  24. package/dist/chunk-6N5PTWMY.js +136 -0
  25. package/dist/chunk-6SGHMWE3.js +277 -0
  26. package/dist/chunk-6XLNIQDB.js +27 -0
  27. package/dist/chunk-7CR24IG7.js +242 -0
  28. package/dist/chunk-7MNJORFF.js +22 -0
  29. package/dist/{chunk-KY56HMHH.js → chunk-A3CYT5EX.js} +125 -31
  30. package/dist/chunk-AGYYIBLL.js +1069 -0
  31. package/dist/{chunk-GB6QRBXN.js → chunk-APJ265NV.js} +54 -1187
  32. package/dist/{chunk-673JJUWJ.js → chunk-BMEMKKIT.js} +2 -2
  33. package/dist/chunk-CBCAPZAA.js +229 -0
  34. package/dist/chunk-CMZWFGD2.js +352 -0
  35. package/dist/chunk-COU2UHX6.js +400 -0
  36. package/dist/chunk-DSELYM6W.js +1077 -0
  37. package/dist/chunk-DUYJ5IO6.js +644 -0
  38. package/dist/chunk-ECH6PKUQ.js +39 -0
  39. package/dist/chunk-ED4KHGC3.js +143 -0
  40. package/dist/chunk-EKMEHE4H.js +340 -0
  41. package/dist/chunk-FCSXB6T2.js +338 -0
  42. package/dist/chunk-FJ3H4MN5.js +48 -0
  43. package/dist/{chunk-RPTR2H26.js → chunk-FNTMWMX5.js} +21 -15
  44. package/dist/chunk-FQ4SKYE4.js +29 -0
  45. package/dist/chunk-G4BMMOKF.js +182 -0
  46. package/dist/{chunk-ZPY3JZ5E.js → chunk-GGXXDWE4.js} +183 -1233
  47. package/dist/chunk-HC4CLZ2Y.js +68 -0
  48. package/dist/{chunk-LU4TK2PR.js → chunk-HFSBBKSQ.js} +5 -56
  49. package/dist/{chunk-PIUMUEMV.js → chunk-HKIYEGME.js} +10 -6
  50. package/dist/chunk-I4HZDVNP.js +73 -0
  51. package/dist/chunk-IKCO5N3L.js +162 -0
  52. package/dist/chunk-IR4CFBFN.js +56 -0
  53. package/dist/{chunk-R5KLMSBV.js → chunk-J5Q24KAG.js} +2 -2
  54. package/dist/chunk-J7CWMCQD.js +255 -0
  55. package/dist/{chunk-K5XEMXTI.js → chunk-JVCV3ICN.js} +1 -1
  56. package/dist/chunk-KZWTDYJF.js +217 -0
  57. package/dist/chunk-LBMZMYH2.js +285 -0
  58. package/dist/{chunk-G34LV2PF.js → chunk-LM5TQCJZ.js} +84 -170
  59. package/dist/chunk-LW6DSM3M.js +5135 -0
  60. package/dist/chunk-LWLEKMDQ.js +3482 -0
  61. package/dist/{chunk-H6F6BYOH.js → chunk-LZSJBIVT.js} +7003 -7434
  62. package/dist/{chunk-HQQID6OA.js → chunk-M6SHUN7Q.js} +5 -5
  63. package/dist/{chunk-FST4FYJB.js → chunk-MFFY33HR.js} +99 -140
  64. package/dist/{chunk-BSU2YIWB.js → chunk-MVVUPGPW.js} +131 -136
  65. package/dist/chunk-OAO4GE4M.js +619 -0
  66. package/dist/{chunk-Q3RUPKEJ.js → chunk-OC7FIQPC.js} +58 -189
  67. package/dist/chunk-OKGUZO2U.js +34 -0
  68. package/dist/{chunk-GAEBEQVI.js → chunk-OOJYHWRB.js} +32 -346
  69. package/dist/{chunk-Q5WJOSJ7.js → chunk-OQ33BKR3.js} +2 -1
  70. package/dist/chunk-OQE5J4C6.js +73 -0
  71. package/dist/{chunk-KKNLWXI6.js → chunk-ORBHGJC5.js} +8 -8
  72. package/dist/{chunk-MAR7Y6HW.js → chunk-PAJK6MAQ.js} +23 -16
  73. package/dist/{chunk-M5T5VO65.js → chunk-PIWWS5BL.js} +837 -635
  74. package/dist/chunk-POHLU5DW.js +1186 -0
  75. package/dist/chunk-QKMUKYO7.js +4961 -0
  76. package/dist/chunk-SRDMMSEP.js +16405 -0
  77. package/dist/chunk-SST6Z5JA.js +80 -0
  78. package/dist/chunk-STBPMHSX.js +2456 -0
  79. package/dist/chunk-T6YILFSB.js +80 -0
  80. package/dist/chunk-TZK7PACC.js +174 -0
  81. package/dist/chunk-TZTZS7QK.js +227 -0
  82. package/dist/{chunk-ASND7OZK.js → chunk-UFIIWP2H.js} +13 -13
  83. package/dist/chunk-UOV2BYIW.js +107 -0
  84. package/dist/{chunk-PFEFKVGL.js → chunk-V6RTAOC2.js} +13 -11
  85. package/dist/chunk-VAKQQHWR.js +434 -0
  86. package/dist/chunk-VG7TBQIY.js +128 -0
  87. package/dist/chunk-VJWL6YS5.js +244 -0
  88. package/dist/{chunk-EYOKLTMF.js → chunk-VPAYEGVX.js} +17 -3
  89. package/dist/chunk-WEH5XRJQ.js +32 -0
  90. package/dist/chunk-X4RCMKVQ.js +641 -0
  91. package/dist/{chunk-TEKV33Q5.js → chunk-X6IAEBZR.js} +65 -33
  92. package/dist/chunk-XBXAASKX.js +18 -0
  93. package/dist/chunk-XN3L4EYL.js +46 -0
  94. package/dist/{chunk-RDLVBZEO.js → chunk-YCWGATWI.js} +6 -4
  95. package/dist/chunk-YHZX5GEU.js +193 -0
  96. package/dist/chunk-YXLYO42X.js +91 -0
  97. package/dist/{chunk-NMOX6HFD.js → chunk-ZDOOVTXZ.js} +29 -77
  98. package/dist/chunk-ZI647VB5.js +37 -0
  99. package/dist/{chunk-C4PTHK7P.js → chunk-ZWLZP4ZT.js} +5 -5
  100. package/dist/chunk-ZWMF7253.js +1882 -0
  101. package/dist/cli/index.js +62 -54
  102. package/dist/clio-JOU4FXVA.js +25 -0
  103. package/dist/code-nav-7AX6FYE6.js +600 -0
  104. package/dist/codewiki/build-worker.js +66 -0
  105. package/dist/compile-cache-CVJMMODC.js +18 -0
  106. package/dist/{components-DMAOEKFB.js → components-KELWS457.js} +11 -6
  107. package/dist/{config-IRUQ7SE4.js → config-XCDVKR23.js} +92 -55
  108. package/dist/configure-4GAP54ZW.js +42 -0
  109. package/dist/{context-5RADCKTR.js → context-4UOGGLQ5.js} +71 -35
  110. package/dist/context-5VKGUVJJ.js +866 -0
  111. package/dist/{context-3KWFLHJG.js → context-77FM5DV5.js} +15 -13
  112. package/dist/{context-clear-7TSNPAAI.js → context-clear-XXJRLCJJ.js} +54 -28
  113. package/dist/{context-index-W4RLWOQH.js → context-index-BZ4UYMTC.js} +30 -24
  114. package/dist/dispatch-runner-QPRDDBDX.js +1997 -0
  115. package/dist/{docs-5AWSPS37.js → docs-2C2LTVT2.js} +23 -10
  116. package/dist/{doctor-UC5NAJYQ.js → doctor-HR46URBJ.js} +27 -17
  117. package/dist/{eval-U6TJHRLX.js → eval-XSSNATB4.js} +29 -16
  118. package/dist/{evidence-YEGUW4L3.js → evidence-6HG2PY2B.js} +46 -26
  119. package/dist/{evolve-TXARCTPG.js → evolve-K7YU3NCY.js} +45 -25
  120. package/dist/{extensions-OZFJ3A3G.js → extensions-QVDOHDGJ.js} +16 -7
  121. package/dist/{fleet-6G3DHNYE.js → fleet-VY3HHKN6.js} +163 -54
  122. package/dist/{fleet-preflight-DSNT37JK.js → fleet-preflight-DDN536IT.js} +7 -4
  123. package/dist/{init-KZ5QTF6M.js → init-JYGXI3FK.js} +69 -32
  124. package/dist/{memory-73ESV5YC.js → memory-WFZMGYHX.js} +48 -27
  125. package/dist/{models-A4PVNWJK.js → models-I5QWSEOM.js} +39 -25
  126. package/dist/monitor-GE4ID3IA.js +661 -0
  127. package/dist/{chunk-FCIH3BIZ.js → orchestrator-EM5MC3HM.js} +15979 -12407
  128. package/dist/{paths-C4H6IV77.js → paths-UXLN5YYZ.js} +10 -5
  129. package/dist/{preload-6WVMHX3A.js → preload-P6DGH2PZ.js} +2 -2
  130. package/dist/{reset-BGW6OGMV.js → reset-L2FQEE3E.js} +16 -10
  131. package/dist/{run-YTPEYQOH.js → run-ZU3QMZPZ.js} +101 -61
  132. package/dist/{share-YIFFV4NQ.js → share-S5BZQC5I.js} +15 -8
  133. package/dist/{skills-2V6RA3OQ.js → skills-X5VXCRNQ.js} +34 -14
  134. package/dist/{skills-eval-S2TVJO4F.js → skills-eval-WKIHWTHR.js} +70 -34
  135. package/dist/steer-GGWFUJUD.js +77 -0
  136. package/dist/{targets-TYXLPB23.js → targets-SNCPI2NR.js} +43 -27
  137. package/dist/terminal-lease-BNAHVHBS.js +395 -0
  138. package/dist/{trace-GGOJ6Q6Z.js → trace-PNCASAXC.js} +41 -16
  139. package/dist/{chunk-N6F52NLF.js → tree-sitter-HGKH6LG4.js} +28 -2306
  140. package/dist/{uninstall-LLLT4F4W.js → uninstall-FZCQCDKC.js} +10 -5
  141. package/dist/{upgrade-33G2LMM5.js → upgrade-JQHHPQ4K.js} +45 -25
  142. package/dist/{usage-ZAFSXKKG.js → usage-OR4O5SMZ.js} +62 -31
  143. package/dist/verify-375KUB3Y.js +716 -0
  144. package/dist/web-fetch-2YHJ3KTG.js +638 -0
  145. package/dist/{wiki-generate-NUQCVOQ3.js → wiki-generate-UEXP2ARI.js} +74 -34
  146. package/dist/worker/entry.js +221 -36
  147. package/dist/workspace-G4ZWUIPR.js +22 -0
  148. package/docs/README.md +22 -17
  149. package/docs/acp.md +168 -16
  150. package/docs/alcf-provider.md +1 -1
  151. package/docs/architecture.md +136 -7
  152. package/docs/artifact-versions.md +1 -1
  153. package/docs/built-in-agents.md +1 -1
  154. package/docs/capacity-and-scheduling.md +1 -1
  155. package/docs/commands-and-modes.md +114 -71
  156. package/docs/config-knobs-audit.md +1 -3
  157. package/docs/configuration-and-targets.md +174 -46
  158. package/docs/context-engine.md +29 -6
  159. package/docs/development-pipeline.md +26 -1
  160. package/docs/dispatch-architecture-rationale.md +1 -1
  161. package/docs/documentation-coverage.md +2 -2
  162. package/docs/documentation-guide.md +1 -1
  163. package/docs/environment-variables.md +13 -5
  164. package/docs/eval-runner.md +1 -1
  165. package/docs/evals-internal.md +1 -1
  166. package/docs/evidence-and-memory.md +6 -2
  167. package/docs/evolution.md +2 -2
  168. package/docs/exit-codes-and-output.md +15 -9
  169. package/docs/extensions-and-sharing.md +9 -9
  170. package/docs/fleet-dispatch.md +7 -5
  171. package/docs/git-commit-provenance.md +120 -0
  172. package/docs/glossary.md +1 -1
  173. package/docs/installation-and-lifecycle.md +34 -27
  174. package/docs/middleware-and-components.md +1 -1
  175. package/docs/model-catalog.md +45 -14
  176. package/docs/observability.md +8 -5
  177. package/docs/performance-methodology.md +491 -0
  178. package/docs/pi-boundary.md +72 -0
  179. package/docs/proactive-memory.md +3 -3
  180. package/docs/prompt-envelope-and-tools.md +24 -3
  181. package/docs/provider-adapter-cookbook.md +57 -4
  182. package/docs/release-cut-checklist.md +129 -115
  183. package/docs/safety-model.md +9 -5
  184. package/docs/scientific-validation.md +3 -3
  185. package/docs/session-lifecycle.md +55 -12
  186. package/docs/skills-marketplace.md +12 -8
  187. package/docs/time-conventions.md +1 -1
  188. package/docs/tool-usage.md +3 -3
  189. package/docs/trace-store.md +1 -1
  190. package/docs/troubleshooting.md +10 -7
  191. package/docs/tui-design.md +47 -10
  192. package/docs/worker-dispatch-mechanics.md +1 -1
  193. package/package.json +19 -22
  194. package/skills/coding/ast-grep/SKILL.md +136 -0
  195. package/skills/coding/ast-grep/evals.md +56 -0
  196. package/skills/coding/ast-grep/references/rule_reference.md +297 -0
  197. package/skills/coding/coding-standards/SKILL.md +113 -0
  198. package/skills/coding/coding-standards/evals.md +34 -0
  199. package/skills/coding/prototype/SKILL.md +86 -0
  200. package/skills/coding/prototype/evals.md +42 -0
  201. package/skills/coding/prototype/references/LOGIC.md +67 -0
  202. package/skills/coding/prototype/references/UI.md +112 -0
  203. package/skills/coding/tdd/SKILL.md +101 -0
  204. package/skills/coding/tdd/evals.md +41 -0
  205. package/skills/coding/tdd/references/mocking.md +59 -0
  206. package/skills/coding/tdd/references/tests.md +77 -0
  207. package/skills/context/context-handoff/SKILL.md +126 -0
  208. package/skills/context/context-handoff/evals.md +57 -0
  209. package/skills/context/context-handoff/scripts/new-handoff.sh +26 -0
  210. package/skills/context/context-prime/SKILL.md +95 -0
  211. package/skills/context/context-prime/evals.md +54 -0
  212. package/skills/meta/clio-dev/SKILL.md +91 -0
  213. package/skills/meta/clio-dev/evals.md +45 -0
  214. package/skills/meta/clio-test/SKILL.md +130 -0
  215. package/skills/meta/clio-test/evals.md +43 -0
  216. package/skills/meta/clio-test/references/harness.md +97 -0
  217. package/skills/meta/clio-test/references/test-map.md +59 -0
  218. package/skills/meta/credentials/SKILL.md +125 -0
  219. package/skills/meta/credentials/evals.md +104 -0
  220. package/skills/meta/find-skills/SKILL.md +72 -0
  221. package/skills/meta/find-skills/evals.md +47 -0
  222. package/skills/meta/herdr/SKILL.md +127 -0
  223. package/skills/meta/herdr/evals.md +38 -0
  224. package/skills/meta/skill-craft/SKILL.md +102 -0
  225. package/skills/meta/skill-craft/evals.md +41 -0
  226. package/skills/planning/architecture/SKILL.md +129 -0
  227. package/skills/planning/architecture/evals.md +36 -0
  228. package/skills/planning/backlog/SKILL.md +90 -0
  229. package/skills/planning/backlog/evals.md +43 -0
  230. package/skills/planning/prd/SKILL.md +82 -0
  231. package/skills/planning/prd/evals.md +49 -0
  232. package/skills/planning/product-intent/SKILL.md +112 -0
  233. package/skills/planning/product-intent/evals.md +36 -0
  234. package/skills/planning/tech-spec/SKILL.md +115 -0
  235. package/skills/planning/tech-spec/evals.md +47 -0
  236. package/skills/registry.yaml +136 -0
  237. package/skills/research/arxiv-literature/SKILL.md +104 -0
  238. package/skills/research/arxiv-literature/evals.md +58 -0
  239. package/skills/research/experiment-protocol/SKILL.md +122 -0
  240. package/skills/research/experiment-protocol/evals.md +91 -0
  241. package/skills/research/scientific-debugging/SKILL.md +119 -0
  242. package/skills/research/scientific-debugging/evals.md +138 -0
  243. package/skills/research/scientific-modernization/SKILL.md +138 -0
  244. package/skills/research/scientific-modernization/evals.md +84 -0
  245. package/skills/workflow/design-council/SKILL.md +139 -0
  246. package/skills/workflow/design-council/evals.md +97 -0
  247. package/skills/workflow/grill-me/SKILL.md +186 -0
  248. package/skills/workflow/grill-me/evals.md +78 -0
  249. package/skills/workflow/workflow-distiller/SKILL.md +136 -0
  250. package/skills/workflow/workflow-distiller/evals.md +107 -0
  251. package/src/cli/acp.ts +31 -4
  252. package/src/cli/clio.ts +68 -6
  253. package/src/cli/config-inspect.ts +28 -22
  254. package/src/cli/configure.ts +47 -9
  255. package/src/cli/context-clear.ts +2 -2
  256. package/src/cli/context-index.ts +21 -23
  257. package/src/cli/context.ts +13 -8
  258. package/src/cli/default-target.ts +9 -17
  259. package/src/cli/docs.ts +11 -5
  260. package/src/cli/evidence.ts +4 -1
  261. package/src/cli/extensions.ts +10 -1
  262. package/src/cli/fleet.ts +47 -6
  263. package/src/cli/index.ts +55 -26
  264. package/src/cli/memory.ts +3 -1
  265. package/src/cli/models.ts +1 -1
  266. package/src/cli/modes/json-stream.ts +37 -1
  267. package/src/cli/modes/print.ts +24 -9
  268. package/src/cli/run.ts +2 -2
  269. package/src/cli/skills-eval.ts +23 -8
  270. package/src/cli/skills.ts +19 -4
  271. package/src/cli/targets.ts +4 -0
  272. package/src/cli/text-layout.ts +15 -5
  273. package/src/cli/trace.ts +62 -14
  274. package/src/cli/upgrade.ts +18 -2
  275. package/src/cli/usage.ts +10 -3
  276. package/src/cli/wiki-generate.ts +2 -1
  277. package/src/core/agent-environment.ts +7 -0
  278. package/src/core/bash-exec.ts +72 -1
  279. package/src/core/boot-trace.ts +9 -4
  280. package/src/core/bus-events.ts +20 -4
  281. package/src/core/commit-attribution.ts +157 -0
  282. package/src/core/compile-cache.ts +159 -0
  283. package/src/core/config.ts +131 -2
  284. package/src/core/defaults.ts +39 -5
  285. package/src/core/domain-loader.ts +12 -5
  286. package/src/core/git-commit-attribution.ts +387 -0
  287. package/src/core/incomplete-installation.ts +45 -0
  288. package/src/core/response-schema.ts +1 -1
  289. package/src/core/safe-exec.ts +13 -1
  290. package/src/core/settings-layers.ts +155 -21
  291. package/src/core/skill-activation.ts +1 -1
  292. package/src/core/startup-timer.ts +3 -3
  293. package/src/core/state-file-lock.ts +13 -1
  294. package/src/core/termination.ts +78 -5
  295. package/src/domains/config/classify.ts +15 -3
  296. package/src/domains/config/extension.ts +19 -13
  297. package/src/domains/config/index.ts +10 -0
  298. package/src/domains/config/keybindings.ts +45 -9
  299. package/src/domains/context/bootstrap-prompt.ts +1 -1
  300. package/src/domains/context/bootstrap.ts +111 -18
  301. package/src/domains/context/clear.ts +16 -11
  302. package/src/domains/context/clio-md.ts +111 -9
  303. package/src/domains/context/codewiki/artifact.ts +400 -0
  304. package/src/domains/context/codewiki/build-worker-protocol.ts +24 -0
  305. package/src/domains/context/codewiki/build-worker.ts +54 -0
  306. package/src/domains/context/codewiki/coordinator.ts +182 -0
  307. package/src/domains/context/codewiki/indexer.ts +59 -144
  308. package/src/domains/context/codewiki/paths.ts +67 -0
  309. package/src/domains/context/codewiki/schema.ts +80 -0
  310. package/src/domains/context/codewiki/tree-sitter.ts +1 -1
  311. package/src/domains/context/contract.ts +11 -5
  312. package/src/domains/context/extension.ts +94 -143
  313. package/src/domains/context/fingerprint.ts +3 -1
  314. package/src/domains/context/index.ts +12 -22
  315. package/src/domains/context/project-metadata.ts +19 -0
  316. package/src/domains/context/prompt-context.ts +9 -10
  317. package/src/domains/context/refresh.ts +29 -21
  318. package/src/domains/context/runtime.ts +17 -0
  319. package/src/domains/context/wiki/generate.ts +39 -34
  320. package/src/domains/context/wiki/plan.ts +1 -1
  321. package/src/domains/context/wiki/prompts.ts +21 -8
  322. package/src/domains/dispatch/code-step.ts +20 -1
  323. package/src/domains/dispatch/extension.ts +158 -21
  324. package/src/domains/dispatch/failure-classification.ts +6 -0
  325. package/src/domains/dispatch/fleet-commit-attribution.ts +56 -0
  326. package/src/domains/dispatch/orphan-recovery.ts +50 -8
  327. package/src/domains/dispatch/receipt-integrity.ts +5 -0
  328. package/src/domains/dispatch/state.ts +31 -6
  329. package/src/domains/dispatch/transport.ts +2 -1
  330. package/src/domains/dispatch/types.ts +14 -0
  331. package/src/domains/dispatch/worker-spawn.ts +21 -2
  332. package/src/domains/eval/metrics/context.ts +1 -1
  333. package/src/domains/eval/types.ts +0 -1
  334. package/src/domains/evidence/build.ts +41 -1
  335. package/src/domains/lifecycle/migrations/2026-08-18-lmstudio-runtime-id.ts +52 -0
  336. package/src/domains/lifecycle/migrations/index.ts +24 -4
  337. package/src/domains/middleware/hooks-io.ts +12 -0
  338. package/src/domains/middleware/skills-reminder.ts +30 -15
  339. package/src/domains/prompts/compiler.ts +142 -84
  340. package/src/domains/prompts/contract.ts +18 -2
  341. package/src/domains/prompts/extension.ts +39 -7
  342. package/src/domains/prompts/fragment-loader.ts +0 -1
  343. package/src/domains/prompts/fragments/identity/clio.md +2 -4
  344. package/src/domains/prompts/fragments/identity/docs-routing.md +10 -0
  345. package/src/domains/prompts/fragments/identity/self-awareness.md +1 -45
  346. package/src/domains/prompts/fragments/operating/contract.md +4 -50
  347. package/src/domains/prompts/fragments/operating/delegation.md +42 -0
  348. package/src/domains/prompts/fragments/operating/skills.md +26 -0
  349. package/src/domains/prompts/fragments/operating/worker.md +16 -0
  350. package/src/domains/prompts/fragments/safety/auto-edit.md +5 -5
  351. package/src/domains/prompts/fragments/safety/full-auto.md +3 -3
  352. package/src/domains/prompts/fragments/safety/read-only.md +4 -4
  353. package/src/domains/prompts/fragments/safety/suggest.md +2 -2
  354. package/src/domains/prompts/fragments/wiki/page.md +10 -0
  355. package/src/domains/prompts/fragments/wiki/plan.md +10 -0
  356. package/src/domains/prompts/preload.ts +3 -3
  357. package/src/domains/providers/auth/api-key.ts +1 -1
  358. package/src/domains/providers/auth/backend-file.ts +20 -10
  359. package/src/domains/providers/auth/backend-memory.ts +59 -4
  360. package/src/domains/providers/auth/boot-status.ts +65 -0
  361. package/src/domains/providers/auth/oauth.ts +2 -1
  362. package/src/domains/providers/auth/storage.ts +97 -38
  363. package/src/domains/providers/capabilities.ts +12 -4
  364. package/src/domains/providers/contract.ts +15 -4
  365. package/src/domains/providers/extension.ts +18 -6
  366. package/src/domains/providers/model-runtime-capabilities.ts +15 -4
  367. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +118 -35
  368. package/src/domains/providers/plugins.ts +5 -3
  369. package/src/domains/providers/probe/fingerprint.ts +25 -5
  370. package/src/domains/providers/registry.ts +31 -10
  371. package/src/domains/providers/runtimes/boot-manifest.ts +55 -0
  372. package/src/domains/providers/runtimes/builtins.ts +2 -2
  373. package/src/domains/providers/runtimes/common/lmstudio-http.ts +423 -0
  374. package/src/domains/providers/runtimes/common/local-synth.ts +6 -7
  375. package/src/domains/providers/runtimes/local-native/lmstudio.ts +241 -0
  376. package/src/domains/providers/support.ts +6 -3
  377. package/src/domains/providers/types/local-model-quirks.ts +7 -9
  378. package/src/domains/providers/types/runtime-descriptor.ts +12 -1
  379. package/src/domains/providers/types/target-descriptor.ts +22 -0
  380. package/src/domains/resources/contract.ts +0 -1
  381. package/src/domains/resources/extension.ts +1 -3
  382. package/src/domains/resources/loader.ts +3 -4
  383. package/src/domains/resources/prompts/loader.ts +16 -2
  384. package/src/domains/resources/prompts/substitute.ts +1 -65
  385. package/src/domains/resources/skills/content-hash.ts +2 -0
  386. package/src/domains/resources/skills/install.ts +17 -0
  387. package/src/domains/resources/skills/loader.ts +17 -10
  388. package/src/domains/resources/skills/marketplace.ts +55 -9
  389. package/src/domains/safety/action-classifier.ts +4 -2
  390. package/src/domains/safety/audit.ts +8 -2
  391. package/src/domains/safety/extension.ts +1 -1
  392. package/src/domains/session/compaction/branch-summary.ts +3 -2
  393. package/src/domains/session/compaction/cut-point.ts +2 -1
  394. package/src/domains/session/compaction/tokens.ts +2 -1
  395. package/src/domains/session/context-ledger.ts +14 -0
  396. package/src/domains/session/contract.ts +15 -0
  397. package/src/domains/session/decision-board.ts +190 -0
  398. package/src/domains/session/entries.ts +66 -3
  399. package/src/domains/session/extension.ts +93 -12
  400. package/src/domains/session/retry.ts +10 -18
  401. package/src/domains/session/session-artifacts.ts +107 -0
  402. package/src/domains/session/task-board.ts +207 -13
  403. package/src/domains/session/tree/active-path.ts +44 -5
  404. package/src/domains/session/tree/fork.ts +26 -27
  405. package/src/domains/session/tree/preview.ts +2 -2
  406. package/src/domains/session/workspace/git-probe.ts +17 -11
  407. package/src/domains/user-tasks/store.ts +297 -0
  408. package/src/engine/acp/errors.ts +96 -0
  409. package/src/engine/acp/server.ts +1728 -146
  410. package/src/engine/acp/transport.ts +135 -14
  411. package/src/engine/acp/types.ts +26 -0
  412. package/src/engine/agent.ts +3 -3
  413. package/src/engine/ai.ts +32 -27
  414. package/src/engine/alcf-oauth.ts +26 -19
  415. package/src/engine/api-registry.ts +223 -0
  416. package/src/engine/apis/index.ts +3 -7
  417. package/src/engine/apis/llamacpp-residency.ts +49 -9
  418. package/src/engine/apis/lmstudio-residency.ts +5 -21
  419. package/src/engine/apis/lmstudio.ts +243 -0
  420. package/src/engine/apis/ollama-native.ts +24 -3
  421. package/src/engine/apis/openai-completions.ts +170 -91
  422. package/src/engine/apis/residency.ts +139 -3
  423. package/src/engine/apis/types.ts +16 -0
  424. package/src/engine/env-api-keys.ts +98 -0
  425. package/src/engine/gemma-channel-filter.ts +223 -0
  426. package/src/engine/instrumented-tui.ts +192 -0
  427. package/src/engine/messages.ts +14 -0
  428. package/src/engine/models.ts +42 -0
  429. package/src/engine/oauth.ts +16 -12
  430. package/src/engine/prompt-templates.ts +1 -0
  431. package/src/engine/provider-payload.ts +16 -59
  432. package/src/engine/strip-tokenizer-sentinels.ts +1 -1
  433. package/src/engine/truncate.ts +9 -0
  434. package/src/engine/tui.ts +17 -9
  435. package/src/engine/types.ts +3 -6
  436. package/src/engine/worker-runtime-capabilities.ts +5 -0
  437. package/src/engine/worker-runtime.ts +1 -1
  438. package/src/engine/worker-tools.ts +9 -4
  439. package/src/entry/boot-options.ts +50 -0
  440. package/src/entry/orchestrator.ts +288 -150
  441. package/src/interactive/application-controller.ts +89 -2
  442. package/src/interactive/chat-loop.ts +266 -41
  443. package/src/interactive/chat-panel.ts +715 -278
  444. package/src/interactive/chat-renderer.ts +306 -85
  445. package/src/interactive/clio-editor.ts +3 -8
  446. package/src/interactive/command-fallbacks.ts +2 -2
  447. package/src/interactive/context-overlay.ts +27 -1
  448. package/src/interactive/editor-submit.ts +253 -24
  449. package/src/interactive/export-html/ansi-to-html.ts +161 -0
  450. package/src/interactive/export-html/index.ts +51 -0
  451. package/src/interactive/export-html/template.ts +45 -0
  452. package/src/interactive/export-html/tool-renderer.ts +54 -0
  453. package/src/interactive/footer/dashboard.ts +4 -0
  454. package/src/interactive/footer/notifications.ts +1 -1
  455. package/src/interactive/footer/widgets.ts +42 -22
  456. package/src/interactive/footer-panel.ts +8 -3
  457. package/src/interactive/format-time.ts +14 -2
  458. package/src/interactive/interactive-application.ts +203 -17
  459. package/src/interactive/interactive-event-projection.ts +18 -1
  460. package/src/interactive/interactive-input-runtime.ts +50 -4
  461. package/src/interactive/interactive-presentation.ts +151 -19
  462. package/src/interactive/interactive-shell.ts +268 -14
  463. package/src/interactive/interactive-slash-runtime.ts +184 -117
  464. package/src/interactive/interactive-tickers.ts +38 -7
  465. package/src/interactive/keybinding-manager.ts +1 -1
  466. package/src/interactive/layout.ts +40 -3
  467. package/src/interactive/overlay-frame.ts +1 -1
  468. package/src/interactive/overlay-general-openers.ts +58 -1
  469. package/src/interactive/overlay-key-routing.ts +3 -0
  470. package/src/interactive/overlay-lifecycle.ts +13 -0
  471. package/src/interactive/overlay-permission-lifecycle.ts +2 -1
  472. package/src/interactive/overlay-session-lifecycle.ts +69 -12
  473. package/src/interactive/overlays/ask-user.ts +146 -24
  474. package/src/interactive/overlays/decisions.ts +300 -0
  475. package/src/interactive/overlays/help-reference.ts +15 -10
  476. package/src/interactive/overlays/model-selector.ts +34 -16
  477. package/src/interactive/overlays/session-selector.ts +18 -0
  478. package/src/interactive/overlays/settings.ts +105 -17
  479. package/src/interactive/overlays/skills-hub.ts +4 -4
  480. package/src/interactive/overlays/tree-selector.ts +41 -6
  481. package/src/interactive/render-trace.ts +499 -90
  482. package/src/interactive/renderers/compaction-summary.ts +2 -2
  483. package/src/interactive/renderers/diff.ts +115 -104
  484. package/src/interactive/renderers/mermaid.ts +53 -0
  485. package/src/interactive/renderers/tool-execution.ts +516 -168
  486. package/src/interactive/renderers/worker-entry.ts +20 -4
  487. package/src/interactive/session-switch-settlement.ts +10 -0
  488. package/src/interactive/slash-autocomplete.ts +6 -114
  489. package/src/interactive/slash-commands.ts +135 -47
  490. package/src/interactive/slash-spec.ts +9 -38
  491. package/src/interactive/status/controller.ts +5 -1
  492. package/src/interactive/status/index.ts +12 -1
  493. package/src/interactive/status/reasoning.ts +87 -0
  494. package/src/interactive/status/summary.ts +13 -2
  495. package/src/interactive/stdout-backpressure.ts +99 -0
  496. package/src/interactive/stream-pacer.ts +530 -0
  497. package/src/interactive/stream-pacing-policy.ts +66 -0
  498. package/src/interactive/tasks-overlay.ts +368 -14
  499. package/src/interactive/terminal-lease.ts +485 -0
  500. package/src/interactive/theme/tokens.ts +1 -1
  501. package/src/interactive/transcript-detail.ts +120 -0
  502. package/src/interactive/turn-context.ts +4 -3
  503. package/src/interactive/turn-persistence.ts +30 -13
  504. package/src/interactive/turn-queues.ts +12 -0
  505. package/src/interactive/turn-recovery.ts +25 -8
  506. package/src/interactive/turn-runtime.ts +79 -12
  507. package/src/interactive/turn-state.ts +10 -0
  508. package/src/interactive/view/artifacts.ts +114 -4
  509. package/src/interactive/view/view-overlay.ts +3 -0
  510. package/src/interactive/welcome-dashboard.ts +17 -16
  511. package/src/interactive/worker-receipts.ts +52 -3
  512. package/src/interactive/worker-stream.ts +5 -1
  513. package/src/tools/agent-tools.ts +23 -3
  514. package/src/tools/artifact.ts +2 -2
  515. package/src/tools/ask-user.ts +23 -13
  516. package/src/tools/bash.ts +30 -2
  517. package/src/tools/bootstrap.ts +34 -431
  518. package/src/tools/builtin-tool-catalog.ts +271 -0
  519. package/src/tools/codewiki/code-nav-surface.ts +29 -0
  520. package/src/tools/codewiki/code-nav.ts +8 -22
  521. package/src/tools/codewiki/shared.ts +41 -38
  522. package/src/tools/context/docs-engine.ts +14 -3
  523. package/src/tools/context/index.ts +107 -28
  524. package/src/tools/context/surface.ts +19 -0
  525. package/src/tools/core-bootstrap.ts +168 -0
  526. package/src/tools/credential-present.ts +5 -5
  527. package/src/tools/dispatch-admission.ts +533 -0
  528. package/src/tools/dispatch-background.ts +54 -0
  529. package/src/tools/dispatch-event-text.ts +6 -0
  530. package/src/tools/dispatch-plan.ts +9 -4
  531. package/src/tools/dispatch-run-events.ts +238 -0
  532. package/src/tools/dispatch-runner.ts +2370 -0
  533. package/src/tools/dispatch-scout-admission.ts +295 -0
  534. package/src/tools/dispatch-types.ts +77 -0
  535. package/src/tools/dispatch.ts +67 -3161
  536. package/src/tools/find.ts +4 -2
  537. package/src/tools/grep.ts +2 -2
  538. package/src/tools/lazy-tool.ts +60 -0
  539. package/src/tools/ledger.ts +3 -3
  540. package/src/tools/monitor-surface.ts +36 -0
  541. package/src/tools/monitor.ts +2 -32
  542. package/src/tools/observers.ts +2 -2
  543. package/src/tools/presentation.ts +107 -0
  544. package/src/tools/registry.ts +45 -27
  545. package/src/tools/safe-exec.ts +2 -2
  546. package/src/tools/steer-surface.ts +17 -0
  547. package/src/tools/steer.ts +2 -13
  548. package/src/tools/tasks.ts +108 -11
  549. package/src/tools/truncate.ts +25 -184
  550. package/src/tools/verify/frontend.ts +3 -1
  551. package/src/tools/verify/index.ts +3 -38
  552. package/src/tools/verify/surface.ts +46 -0
  553. package/src/tools/web-fetch-surface.ts +23 -0
  554. package/src/tools/web-fetch.ts +2 -20
  555. package/src/tools/write.ts +7 -2
  556. package/src/worker/entry.ts +39 -2
  557. package/src/worker/spec-contract.ts +26 -5
  558. package/dist/chunk-7SS2CTV2.js +0 -61361
  559. package/dist/chunk-DKGKUHFA.js +0 -924
  560. package/dist/chunk-GEP36Y4X.js +0 -12796
  561. package/dist/chunk-XYWBQRDM.js +0 -137
  562. package/dist/clio-BZVGEUFJ.js +0 -58
  563. package/dist/configure-S7S6F6CL.js +0 -32
  564. package/docs/html/agents_blueprint.html +0 -936
  565. package/docs/html/alcf_blueprint.html +0 -324
  566. package/docs/html/architecture_blueprint.html +0 -850
  567. package/docs/html/commands_blueprint.html +0 -939
  568. package/docs/html/config_knobs_audit_blueprint.html +0 -178
  569. package/docs/html/configuration_blueprint.html +0 -1080
  570. package/docs/html/context_blueprint.html +0 -603
  571. package/docs/html/documentation_blueprint.html +0 -832
  572. package/docs/html/environment_blueprint.html +0 -404
  573. package/docs/html/eval_blueprint.html +0 -743
  574. package/docs/html/evals_internal_blueprint.html +0 -190
  575. package/docs/html/evolution_blueprint.html +0 -674
  576. package/docs/html/extensions_blueprint.html +0 -2065
  577. package/docs/html/fleet_dispatch_blueprint.html +0 -286
  578. package/docs/html/index.html +0 -919
  579. package/docs/html/lifecycle_blueprint.html +0 -723
  580. package/docs/html/memory_blueprint.html +0 -699
  581. package/docs/html/middleware_blueprint.html +0 -664
  582. package/docs/html/models_blueprint.html +0 -2366
  583. package/docs/html/observability_blueprint.html +0 -683
  584. package/docs/html/provider_adapter_blueprint.html +0 -245
  585. package/docs/html/safety_blueprint.html +0 -1386
  586. package/docs/html/shared.css +0 -571
  587. package/docs/html/shared.js +0 -143
  588. package/docs/html/skills_blueprint.html +0 -671
  589. package/docs/html/soak_blueprint.html +0 -182
  590. package/docs/html/tool_usage_blueprint.html +0 -350
  591. package/docs/html/tools_blueprint.html +0 -2249
  592. package/docs/html/trace_blueprint.html +0 -235
  593. package/docs/html/tui_design_blueprint.html +0 -374
  594. package/docs/html/validation_blueprint.html +0 -961
  595. package/docs/html/worker_dispatch_blueprint.html +0 -231
  596. package/src/core/release.ts +0 -2
  597. package/src/domains/providers/runtimes/common/lmstudio-logger.ts +0 -32
  598. package/src/domains/providers/runtimes/local-native/lmstudio-native.ts +0 -491
  599. package/src/engine/apis/lmstudio-native.ts +0 -1438
  600. package/src/engine/apis/thinking-replay.ts +0 -11
  601. package/src/tools/string-enum.ts +0 -15
package/src/cli/index.ts CHANGED
@@ -5,14 +5,21 @@
5
5
  // a crashed boot are both legible to `ps`, `pgrep -f`, and htop.
6
6
  process.title = "clio-coder";
7
7
 
8
+ import { AI_AGENT_NAME } from "../core/agent-environment.js";
9
+
10
+ // Pi and other agent-aware developer tools use this generic marker to
11
+ // attribute subprocess activity without knowing Clio-specific variables.
12
+ // Set it unconditionally so every child inherits the actual spawning agent.
13
+ process.env.AI_AGENT = AI_AGENT_NAME;
14
+
8
15
  // Only argument parsing and boot tracing load statically. Every subcommand is
9
16
  // imported dynamically through the command registry (see `dispatch`), so a bare `clio`
10
17
  // (interactive) or `clio-coder --version` pays for its own module graph and nothing
11
18
  // else — this is the highest-value cut of the cold module-load tax. Code
12
19
  // splitting (tsup.config.ts) keeps each command's transitive heavy externals in
13
20
  // its own chunk.
14
- import { fileURLToPath } from "node:url";
15
21
  import { traceBoot } from "../core/boot-trace.js";
22
+ import { incompleteInstallationAdvice } from "../core/incomplete-installation.js";
16
23
  import { extractGlobalFlags, parseFlags, printError } from "./argv.js";
17
24
 
18
25
  const HELP = `Clio Coder command line
@@ -56,7 +63,7 @@ Usage:
56
63
  clio-coder trace query or view the durable dispatch trace mirror
57
64
  clio-coder extensions install, list, enable, disable, or remove extension packages
58
65
  clio-coder skills list, inspect, validate, or install skills
59
- clio-coder docs [topic] serve bundled HTML docs on 127.0.0.1 (--no-open to skip browser)
66
+ clio-coder docs [topic] serve the HTML docs of a source checkout on 127.0.0.1 (--no-open to skip browser)
60
67
  clio-coder dev <command> harness instruments; run 'clio-coder dev' for the list
61
68
  clio-coder --help, -h this message
62
69
  clio-coder --help --all this message plus every command under 'clio-coder dev'
@@ -160,6 +167,7 @@ async function main(argv: string[]): Promise<number> {
160
167
  ...(skillPaths.length > 0 ? { skillPaths } : {}),
161
168
  };
162
169
  if (!subcommand) {
170
+ await enableBootCompileCache();
163
171
  const { runClioCommand } = await import("./clio.js");
164
172
  return runClioCommand(bootOptions);
165
173
  }
@@ -167,6 +175,21 @@ async function main(argv: string[]): Promise<number> {
167
175
  return dispatch(subcommand, subArgs, bootOptions);
168
176
  }
169
177
 
178
+ /**
179
+ * Cache the boot-path module graphs' bytecode. Only the three long-lived
180
+ * entrypoints that already write state enable it (interactive, `run`, `acp`);
181
+ * read-only and dry-run commands such as `paths` and bare `doctor` document
182
+ * that they create nothing, and enabling the cache creates its directory, so
183
+ * a dispatch-wide enable would break that promise on every initialized home.
184
+ * A help invocation of a boot command is itself zero-side-effect, so the
185
+ * guard runs before enablement, not after the module's own help check.
186
+ */
187
+ async function enableBootCompileCache(subArgs: ReadonlyArray<string> = []): Promise<void> {
188
+ if (subArgs.includes("--help") || subArgs.includes("-h")) return;
189
+ const { enableClioCompileCache } = await import("../core/compile-cache.js");
190
+ enableClioCompileCache();
191
+ }
192
+
170
193
  /**
171
194
  * The dispatcher is also the command-recognition source used by top-level
172
195
  * value flags. Every dynamic import stays a literal so tsup can split command
@@ -177,7 +200,13 @@ const extensionsCommand: CommandHandler = async (subArgs) =>
177
200
  (await import("./extensions.js")).runExtensionsCommand(subArgs);
178
201
 
179
202
  const COMMAND_HANDLERS = new Map<string, CommandHandler>([
180
- ["acp", async (subArgs, bootOptions) => (await import("./acp.js")).runAcpCommand(subArgs, bootOptions)],
203
+ [
204
+ "acp",
205
+ async (subArgs, bootOptions) => {
206
+ await enableBootCompileCache(subArgs);
207
+ return (await import("./acp.js")).runAcpCommand(subArgs, bootOptions);
208
+ },
209
+ ],
181
210
  ["auth", async (subArgs) => (await import("./auth.js")).runAuthCommand(subArgs)],
182
211
  ["config", async (subArgs) => (await import("./config.js")).runConfigCommand(subArgs)],
183
212
  ["configure", async (subArgs) => (await import("./configure.js")).runConfigureCommand(subArgs)],
@@ -219,7 +248,13 @@ const COMMAND_HANDLERS = new Map<string, CommandHandler>([
219
248
  ["export", async (subArgs) => (await import("./share.js")).runExportCommand(subArgs)],
220
249
  ["import", async (subArgs) => (await import("./share.js")).runImportCommand(subArgs)],
221
250
  ["context", async (subArgs) => (await import("./context.js")).runContextCommand(subArgs)],
222
- ["run", async (subArgs, bootOptions) => (await import("./run.js")).runClioRun(subArgs, bootOptions)],
251
+ [
252
+ "run",
253
+ async (subArgs, bootOptions) => {
254
+ await enableBootCompileCache(subArgs);
255
+ return (await import("./run.js")).runClioRun(subArgs, bootOptions);
256
+ },
257
+ ],
223
258
  ["doctor", async (subArgs) => (await import("./doctor.js")).runDoctorCommand(subArgs)],
224
259
  ["paths", async (subArgs) => (await import("./paths.js")).runPathsCommand(subArgs)],
225
260
  ["reset", async (subArgs) => (await import("./reset.js")).runResetCommand(subArgs)],
@@ -232,6 +267,16 @@ const COMMAND_HANDLERS = new Map<string, CommandHandler>([
232
267
  // Internal: the native worker stream server (WorkerSpec on stdin,
233
268
  // NDJSON on stdout). The entry module runs main() on import and owns
234
269
  // process exit; this settles only on a pre-run import failure.
270
+ // This is how SSH placement launches a worker on the remote install,
271
+ // where no local spawn boundary injected NODE_COMPILE_CACHE, so the
272
+ // worker graph enables the remote cache itself before it loads. The
273
+ // enable is in-process only: no environment variable is set, so the
274
+ // worker's own children inherit nothing. Nothing on this path
275
+ // injected the provenance pair either, so any marker present is
276
+ // foreign; strip it (and only it) so the entry's consume can never
277
+ // match and delete an operator's own NODE_COMPILE_CACHE.
278
+ Reflect.deleteProperty(process.env, "CLIO_CODER_INJECTED_COMPILE_CACHE");
279
+ await enableBootCompileCache();
235
280
  await import("../worker/entry.js");
236
281
  return 0;
237
282
  },
@@ -257,27 +302,6 @@ function isCommandToken(token: string): boolean {
257
302
  * this repository can act on. The filter on our own output directory keeps a
258
303
  * module error raised by a user's extension or hook reporting itself normally.
259
304
  */
260
- function incompleteInstallationAdvice(err: unknown): string | null {
261
- if ((err as NodeJS.ErrnoException | undefined)?.code !== "ERR_MODULE_NOT_FOUND") return null;
262
- const message = err instanceof Error ? err.message : String(err);
263
- let outputDir: string;
264
- try {
265
- outputDir = fileURLToPath(new URL("../", import.meta.url));
266
- } catch {
267
- return null;
268
- }
269
- if (!message.includes(outputDir)) return null;
270
- return [
271
- `${message}`,
272
- "",
273
- "This Clio Coder installation is incomplete: the command's own module is missing from",
274
- `${outputDir}`,
275
- "Reinstall to restore it, using the line that matches how you installed:",
276
- " npm install -g @iowarp/clio-coder # npm install",
277
- " npm run install:local # source checkout",
278
- ].join("\n");
279
- }
280
-
281
305
  /**
282
306
  * Route a subcommand to its registered handler, importing only that command's
283
307
  * module. Unknown names fail before loading any command graph.
@@ -295,7 +319,12 @@ async function dispatch(subcommand: string, subArgs: string[], bootOptions: CliB
295
319
  }
296
320
  }
297
321
  printError(`unknown subcommand: ${subcommand}`);
298
- process.stdout.write(helpText(false));
322
+ // The usage that explains a rejection belongs with the rejection on stderr.
323
+ // Writing it to stdout meant a mistyped command still produced a full page on
324
+ // the stream the caller was capturing for output, next to an error on the one
325
+ // it was probably not reading. `clio-coder --help` is the request for this
326
+ // text, and it still answers on stdout with exit 0.
327
+ process.stderr.write(helpText(false));
299
328
  return 2;
300
329
  }
301
330
 
package/src/cli/memory.ts CHANGED
@@ -92,7 +92,9 @@ export async function runMemoryCommand(args: ReadonlyArray<string>): Promise<num
92
92
  parsed = parseMemoryArgs(args);
93
93
  } catch (error) {
94
94
  printError(error instanceof Error ? error.message : String(error));
95
- process.stdout.write(HELP);
95
+ // Usage that accompanies an error goes to stderr with it; see the same
96
+ // note in evidence.ts.
97
+ process.stderr.write(HELP);
96
98
  return 2;
97
99
  }
98
100
  if (parsed.help) {
package/src/cli/models.ts CHANGED
@@ -117,7 +117,7 @@ export async function runModelsCommand(args: ReadonlyArray<string>): Promise<num
117
117
  return 0;
118
118
  }
119
119
 
120
- function collectRows(entries: ReadonlyArray<TargetStatus>, providers: ProvidersContract): ModelRow[] {
120
+ export function collectRows(entries: ReadonlyArray<TargetStatus>, providers: ProvidersContract): ModelRow[] {
121
121
  const rows: ModelRow[] = [];
122
122
  for (const status of entries) {
123
123
  const runtimeId = status.runtime?.id ?? status.target.runtime;
@@ -14,6 +14,13 @@
14
14
  * the `message_end` that follows.
15
15
  * - `text_delta` / `thinking_delta` carry the increment, not the growing
16
16
  * partial text.
17
+ * - `message_end` keeps the message's accounting (role, model, usage, stop
18
+ * reason, tool calls) and replaces the assistant `text` and `thinking`
19
+ * blocks the deltas already carried with a marker naming their length.
20
+ * Without this the stream carried every assistant token twice: measured on
21
+ * one run, 41,094 bytes of deltas alongside 24,600 bytes of `message_end`
22
+ * re-stating the same thinking and text. `user` and `toolResult` messages
23
+ * pass through whole, because nothing else on the stream carries them.
17
24
  * - `agent_end` carries its segment's usage and message count, not a second
18
25
  * copy of every message already streamed.
19
26
  * - `turn_end` keeps its assistant message (stop reason and usage live
@@ -34,13 +41,42 @@ export function projectHeadlessJsonEvent(event: ChatLoopEvent): unknown | null {
34
41
  if (event.type === "thinking_delta") {
35
42
  return { type: event.type, contentIndex: event.contentIndex, delta: event.delta };
36
43
  }
44
+ if (event.type === "message_end") {
45
+ return { ...event, message: withoutStreamedContent(event.message) };
46
+ }
37
47
  if (event.type === "agent_end") return segmentSummary(event.type, event.messages);
38
48
  if (event.type === "turn_end") {
39
- return { type: event.type, message: event.message };
49
+ return { type: event.type, message: withoutStreamedContent(event.message) };
40
50
  }
41
51
  return event;
42
52
  }
43
53
 
54
+ /**
55
+ * Replace the content blocks a reader has already received as deltas.
56
+ *
57
+ * Only an assistant message streams: its `text` and `thinking` blocks arrive
58
+ * incrementally as `text_delta` and `thinking_delta` keyed by the same
59
+ * `contentIndex` this array is indexed by, so a reader reassembles them itself.
60
+ * `toolCall` blocks never stream and are kept whole. A `user` or `toolResult`
61
+ * message is returned untouched, because no delta ever carried it.
62
+ */
63
+ function withoutStreamedContent<T>(message: T): T {
64
+ if (!isRecord(message) || message.role !== "assistant" || !Array.isArray(message.content)) return message;
65
+ const content = message.content.map((block: unknown) => {
66
+ if (!isRecord(block)) return block;
67
+ if (block.type === "text" && typeof block.text === "string") {
68
+ const { text: _text, ...rest } = block;
69
+ return { ...rest, streamed: true, textLength: block.text.length };
70
+ }
71
+ if (block.type === "thinking" && typeof block.thinking === "string") {
72
+ const { thinking: _thinking, ...rest } = block;
73
+ return { ...rest, streamed: true, thinkingLength: block.thinking.length };
74
+ }
75
+ return block;
76
+ });
77
+ return { ...message, content } as T;
78
+ }
79
+
44
80
  /**
45
81
  * Projection for the dispatch `--json` stream, whose events come off a worker
46
82
  * rather than out of the chat loop.
@@ -211,14 +211,29 @@ function countToolStats(stats: Map<string, ToolCallStat>): number {
211
211
  return count;
212
212
  }
213
213
 
214
- const TERMINAL_JSON_EVENT_TYPES = new Set([
215
- "agent_start",
216
- "agent_end",
217
- "message_end",
218
- "notice",
219
- "tool_execution_start",
220
- "tool_execution_end",
221
- ]);
214
+ function prefixHeadlessFailure(chat: ChatLoop, message: string): string {
215
+ const snapshot = chat.lastRunSnapshot?.();
216
+ if (!snapshot) return message;
217
+ const url = snapshot.targetUrl ?? "endpoint unavailable";
218
+ return `target '${snapshot.targetId}' (${snapshot.runtimeId} ${url}): ${message}`;
219
+ }
220
+
221
+ /**
222
+ * The events `--json-events terminal` lets through, alongside the `turn_start`
223
+ * and `turn_end` frames this mode synthesizes itself.
224
+ *
225
+ * The mode's contract is the run receipt and nothing else. It used to admit
226
+ * `message_end`, which is the largest event on the stream and carries the
227
+ * injected system reminders, the operator's prompt, and every thinking block:
228
+ * "Say OK." produced 39.8 KB. `agent_start` and the two `tool_execution_*`
229
+ * events are per-step progress, which is what `--json-events full` is for.
230
+ *
231
+ * `turn_end` is deliberately absent even though the mode emits one. The
232
+ * synthesized frame carries `startedAt`, `endedAt`, and `exitCode`; the streamed
233
+ * event of the same name carries the turn's assistant message instead. Letting
234
+ * both through would put two different shapes behind one `type` on one stream.
235
+ */
236
+ const TERMINAL_JSON_EVENT_TYPES = new Set(["agent_end", "notice"]);
222
237
 
223
238
  function isMainAgentRunKind(value: string): value is RunKind {
224
239
  return value === "http" || value === "sdk" || value === "subprocess";
@@ -542,7 +557,7 @@ export async function runHeadlessMainAgent(chat: ChatLoop, options: HeadlessMain
542
557
  stderrMessage = result.abortReason;
543
558
  } else if (result.error) {
544
559
  terminal = { exitCode: 1, outcome: "failed", status: "failed", failureMessage: result.error };
545
- stderrMessage = result.error;
560
+ stderrMessage = prefixHeadlessFailure(chat, result.error);
546
561
  } else if (result.text.length === 0 && !result.sawTerminatingToolResult) {
547
562
  const failureMessage =
548
563
  result.lastNotice !== null
package/src/cli/run.ts CHANGED
@@ -7,7 +7,7 @@ import type { AgentsContract } from "../domains/agents/contract.js";
7
7
  import { AgentsDomainModule } from "../domains/agents/index.js";
8
8
  import type { ConfigContract } from "../domains/config/contract.js";
9
9
  import { ConfigDomainModule } from "../domains/config/index.js";
10
- import { createContextDomainModule } from "../domains/context/index.js";
10
+ import { createContextDomainModule } from "../domains/context/runtime.js";
11
11
  import type { DispatchContract, DispatchRequest } from "../domains/dispatch/contract.js";
12
12
  import { agentRoleFactsResolver, requestExecutionRole } from "../domains/dispatch/execution-role.js";
13
13
  import { createDispatchDomainModule } from "../domains/dispatch/index.js";
@@ -28,7 +28,7 @@ import { SafetyDomainModule } from "../domains/safety/index.js";
28
28
  import { SchedulingDomainModule } from "../domains/scheduling/index.js";
29
29
  import { SessionDomainModule } from "../domains/session/index.js";
30
30
  import type { ImageContent } from "../engine/types.js";
31
- import { assistantTextFromEvent } from "../tools/dispatch.js";
31
+ import { assistantTextFromEvent } from "../tools/dispatch-event-text.js";
32
32
  import { isToolProfileName } from "../tools/profiles.js";
33
33
  import { parseRunCliArgs, type RunCliArgs } from "./args.js";
34
34
  import { runClioCommand } from "./clio.js";
@@ -33,7 +33,7 @@ import { formatColumns, printError } from "./shared.js";
33
33
  * `evals.md` with RED-GREEN scenarios; this lane executes them instead of
34
34
  * trusting the prose: per scenario one baseline headless run (no skills), one
35
35
  * treatment run (the skill loaded via the explicit --skill path and invoked
36
- * with /skill:<name>), then one judge run that scores each Expected bullet
36
+ * with /skill <name>), then one judge run that scores each Expected bullet
37
37
  * pass/fail from the two transcripts.
38
38
  *
39
39
  * Deltas from the task-file eval harness, recorded rather than papered over:
@@ -302,10 +302,12 @@ function describeArmPolicyOutcome(allowNetwork: boolean): string {
302
302
  type EvalArm = "baseline" | "treatment" | "judge";
303
303
 
304
304
  /**
305
- * The argv for one arm's child `clio-coder run`. Every arm streams terminal JSON
306
- * events (a turn that ends on a terminating tool carries its content there,
307
- * not in text mode) and runs with discovery off so only the explicit --skill
308
- * of the treatment arm loads.
305
+ * The argv for one arm's child `clio-coder run`. Every arm streams the full JSON
306
+ * event sequence because the evaluator scores assistant messages and tool
307
+ * evidence, while terminal mode is intentionally receipt-only. A turn that ends
308
+ * on a terminating tool carries its content in the full event stream rather
309
+ * than text mode. Discovery stays off so only the treatment arm's explicit
310
+ * skill loads.
309
311
  *
310
312
  * @internal Exported for contract tests.
311
313
  */
@@ -314,7 +316,7 @@ export function armRunArgs(
314
316
  prompt: string,
315
317
  options: { target?: string | undefined; skillBaseDir?: string | undefined } = {},
316
318
  ): string[] {
317
- const args = ["run", "--json", "--json-events", "terminal", "--no-skills"];
319
+ const args = ["run", "--json", "--json-events", "full", "--no-skills"];
318
320
  if (arm !== "judge") args.push("--autonomy", ARM_AUTONOMY);
319
321
  if (options.skillBaseDir !== undefined) args.push("--skill", options.skillBaseDir);
320
322
  if (options.target !== undefined) args.push("--target", options.target);
@@ -465,7 +467,7 @@ async function runScenario(
465
467
  childEnv,
466
468
  );
467
469
  const treatment = await captureHeadlessRun(
468
- armRunArgs("treatment", `/skill:${skillName} ${scenario.setup}`, { target, skillBaseDir }),
470
+ armRunArgs("treatment", `/skill ${skillName} ${scenario.setup}`, { target, skillBaseDir }),
469
471
  runWorkspaces.treatment,
470
472
  timeoutMs,
471
473
  childEnv,
@@ -817,6 +819,7 @@ export function parseRunStdout(stdout: string): { sessionId: string | null; tran
817
819
  const lines: string[] = [];
818
820
  let finalText = "";
819
821
  let sawJson = false;
822
+ const streamedText = new Map<number, string>();
820
823
  // Tool calls whose result is the skill's own SKILL.md. Correlated by
821
824
  // toolCallId, which both the start and end events carry.
822
825
  const skillBodyCallIds = new Set<string>();
@@ -834,6 +837,11 @@ export function parseRunStdout(stdout: string): { sessionId: string | null; tran
834
837
  sessionId = event.id;
835
838
  continue;
836
839
  }
840
+ if (event.type === "text_delta" && typeof event.delta === "string") {
841
+ const contentIndex = typeof event.contentIndex === "number" ? event.contentIndex : 0;
842
+ streamedText.set(contentIndex, `${streamedText.get(contentIndex) ?? ""}${event.delta}`);
843
+ continue;
844
+ }
837
845
  if (event.type === "tool_execution_start") {
838
846
  const tool = readString(event.toolName) ?? readString(event.tool) ?? "tool";
839
847
  const args = event.args ?? event.arguments ?? event.input;
@@ -865,13 +873,20 @@ export function parseRunStdout(stdout: string): { sessionId: string | null; tran
865
873
  }
866
874
  if (event.type === "message_end" && isRecord(event.message) && event.message.role === "assistant") {
867
875
  const content = Array.isArray(event.message.content) ? event.message.content : [];
868
- const text = content
876
+ const completedText = content
869
877
  .filter((item): item is { type: "text"; text: string } => {
870
878
  return isRecord(item) && item.type === "text" && typeof item.text === "string";
871
879
  })
872
880
  .map((item) => item.text)
873
881
  .join("")
874
882
  .trim();
883
+ const streamed = [...streamedText.entries()]
884
+ .sort(([left], [right]) => left - right)
885
+ .map(([, text]) => text)
886
+ .join("")
887
+ .trim();
888
+ streamedText.clear();
889
+ const text = completedText.length > 0 ? completedText : streamed;
875
890
  if (text.length > 0) {
876
891
  lines.push(`ASSISTANT: ${text}`);
877
892
  finalText = text;
package/src/cli/skills.ts CHANGED
@@ -27,8 +27,10 @@ Commands:
27
27
  clio-coder skills sync [--force]
28
28
  clio-coder skills eval <name|path> [--scenario <id>] [--target <id>] [--workspace <path>] [--timeout <seconds>] [--trust-fixtures] [--allow-network] [--json]
29
29
 
30
- search covers installed skills plus the local marketplace (a repo skills/
31
- catalog, CLIO_CODER_SKILL_CATALOG_DIR, or the skill-marketplace.json index).
30
+ search covers installed skills plus the local marketplace: CLIO_CODER_SKILL_CATALOG_DIR,
31
+ a repo skills/ catalog, or the catalog and skill-marketplace.json index the
32
+ installed clio-coder package carries. Installing from the shipped catalog copies
33
+ local files and needs no network.
32
34
 
33
35
  install resolves a bare name through that marketplace; a path or GitHub URL
34
36
  installs directly, and an existing local path always wins over a same-named
@@ -198,6 +200,9 @@ function skillRows(skills: ReadonlyArray<Skill>): string[][] {
198
200
  skill.trusted ? "trusted" : "untrusted",
199
201
  skill.disableModelInvocation ? "manual" : "model",
200
202
  skill.hash.slice(0, 12),
203
+ // Blank for the ordinary operator-installed case; a worker install is
204
+ // the anomaly worth a column, so it is the only value that ever prints.
205
+ skill.provenance?.installedBy ?? "",
201
206
  skill.description,
202
207
  ]);
203
208
  }
@@ -208,7 +213,7 @@ function printList(skills: ReadonlyArray<Skill>): void {
208
213
  return;
209
214
  }
210
215
  process.stdout.write(
211
- formatColumns([["name", "scope", "source", "trust", "invoke", "hash", "description"], ...skillRows(skills)]),
216
+ formatColumns([["name", "scope", "source", "trust", "invoke", "hash", "by", "description"], ...skillRows(skills)]),
212
217
  );
213
218
  }
214
219
 
@@ -222,6 +227,9 @@ function printInspect(skill: Skill): void {
222
227
  process.stdout.write(`trusted: ${skill.trusted}\n`);
223
228
  process.stdout.write(`disableModelInvocation: ${skill.disableModelInvocation}\n`);
224
229
  process.stdout.write(`hash: ${skill.hash}\n`);
230
+ if (skill.provenance?.installedBy) {
231
+ process.stdout.write(`installed-by: ${skill.provenance.installedBy}\n`);
232
+ }
225
233
  if (skill.diagnostics.length > 0) {
226
234
  process.stdout.write("diagnostics:\n");
227
235
  for (const diag of skill.diagnostics) process.stdout.write(` ${diag.type}: ${diag.message}\n`);
@@ -249,10 +257,17 @@ export async function runSkillsCommand(argv: ReadonlyArray<string>): Promise<num
249
257
  process.stderr.write(HELP);
250
258
  return 2;
251
259
  }
252
- if (parsed.help || !parsed.command) {
260
+ if (parsed.help) {
253
261
  process.stdout.write(HELP);
254
262
  return 0;
255
263
  }
264
+ // A bare `clio-coder skills` is a missing required argument, which the
265
+ // exit-code contract puts at 2 with the usage on stderr. See the same note in
266
+ // extensions.ts.
267
+ if (!parsed.command) {
268
+ process.stderr.write(HELP);
269
+ return 2;
270
+ }
256
271
  switch (parsed.command) {
257
272
  case "list": {
258
273
  const list = loadSkills({ cwd: process.cwd() });
@@ -1101,6 +1101,7 @@ interface SerializedStatus {
1101
1101
  probeCapabilities?: TargetStatus["probeCapabilities"];
1102
1102
  probeModelId?: TargetStatus["probeModelId"];
1103
1103
  probeNotes?: TargetStatus["probeNotes"];
1104
+ probeSurfaces?: TargetStatus["probeSurfaces"];
1104
1105
  discoveredModels: TargetStatus["discoveredModels"];
1105
1106
  discoveredModelsSource?: TargetStatus["discoveredModelsSource"];
1106
1107
  discoveredModelStates?: TargetStatus["discoveredModelStates"];
@@ -1146,5 +1147,8 @@ function serializeStatus(
1146
1147
  if (status.probeNotes !== undefined) {
1147
1148
  out.probeNotes = status.probeNotes;
1148
1149
  }
1150
+ if (status.probeSurfaces !== undefined) {
1151
+ out.probeSurfaces = status.probeSurfaces;
1152
+ }
1149
1153
  return out;
1150
1154
  }
@@ -14,12 +14,22 @@
14
14
  */
15
15
 
16
16
  /** Columns to lay out for, with a floor that keeps arithmetic non-negative. */
17
- export function terminalColumns(stream: { columns?: number | undefined } = process.stdout): number {
17
+ export function terminalColumns(
18
+ stream: { columns?: number | undefined } = process.stdout,
19
+ env: { COLUMNS?: string | undefined } = process.env,
20
+ ): number {
18
21
  const columns = stream.columns;
19
- // A pipe reports no width. 80 is the conventional answer and is also the
20
- // width the fixed-width rows were implicitly written for.
21
- if (typeof columns !== "number" || !Number.isFinite(columns)) return 80;
22
- return Math.max(20, Math.floor(columns));
22
+ if (typeof columns === "number" && Number.isFinite(columns)) return Math.max(20, Math.floor(columns));
23
+ // A pipe reports no width, and the fallback used to end there: `clio-coder
24
+ // targets | less` was pinned to 80 with no way to widen it, which cut the
25
+ // port off every url and ellipsized the model column, the two the table
26
+ // exists to tell apart. $COLUMNS is what a shell exports for exactly this,
27
+ // so an operator or a CI job can say how wide the capture is.
28
+ const declared = Number(env.COLUMNS);
29
+ if (Number.isFinite(declared) && declared > 0) return Math.max(20, Math.floor(declared));
30
+ // 80 is the conventional answer and is also the width the fixed-width rows
31
+ // were implicitly written for.
32
+ return 80;
23
33
  }
24
34
 
25
35
  /** Shorten to `width`, marking the cut so a truncated value never reads as complete. */
package/src/cli/trace.ts CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  } from "../domains/observability/trace-store.js";
15
15
 
16
16
  const HELP = `Usage:
17
- clio-coder trace runs [--db PATH] [--limit N]
17
+ clio-coder trace runs [--db PATH] [--limit N] [--json]
18
18
  clio-coder trace phases <runId> [--db PATH]
19
19
  clio-coder trace tail <runId> [--follow] [--db PATH]
20
20
  clio-coder trace procs <runId> [--db PATH]
@@ -33,6 +33,7 @@ interface ParsedTraceArgs {
33
33
  follow: boolean;
34
34
  limit: number;
35
35
  port: number;
36
+ json: boolean;
36
37
  }
37
38
 
38
39
  function parseTraceArgs(args: string[]): ParsedTraceArgs {
@@ -42,9 +43,11 @@ function parseTraceArgs(args: string[]): ParsedTraceArgs {
42
43
  let follow = false;
43
44
  let limit = 50;
44
45
  let port = 0;
46
+ let json = false;
45
47
  for (let index = 0; index < args.length; index += 1) {
46
48
  const arg = args[index];
47
49
  if (arg === "--follow") follow = true;
50
+ else if (arg === "--json") json = true;
48
51
  else if (arg === "--db" || arg === "--limit" || arg === "--port") {
49
52
  const value = args[index + 1];
50
53
  if (value === undefined) throw new Error(`${arg} requires a value`);
@@ -62,7 +65,33 @@ function parseTraceArgs(args: string[]): ParsedTraceArgs {
62
65
  else if (arg?.startsWith("-")) throw new Error(`unknown trace flag: ${arg}`);
63
66
  else if (arg !== undefined) positional.push(arg);
64
67
  }
65
- return { positional, db, dbExplicit, follow, limit, port };
68
+ return { positional, db, dbExplicit, follow, limit, port, json };
69
+ }
70
+
71
+ /** Every subcommand `trace` answers to. Anything else is a usage error. */
72
+ const TRACE_COMMANDS = new Set(["runs", "phases", "tail", "procs", "sql", "ui"]);
73
+
74
+ /** The subcommands whose first positional is a run id. */
75
+ const TRACE_COMMANDS_NEEDING_RUN_ID = new Set(["phases", "tail", "procs"]);
76
+
77
+ /**
78
+ * Reject a malformed invocation before the database is consulted.
79
+ *
80
+ * The no-database path below is a courtesy that exits 0, because a state tree
81
+ * nothing has written to is the empty state rather than a failure. Running it
82
+ * ahead of this check meant that on a fresh install every typed subcommand
83
+ * succeeded: `trace bogus`, `trace phases` with no run id, and `trace sql` with
84
+ * no query all exited 0 with the same "no trace database yet" line, so a CI step
85
+ * gated on one of them went on to the next line. The same invocations against a
86
+ * home that had a database exited 2, which is the documented behavior.
87
+ */
88
+ function invocationError(command: string, runId: string | undefined): number | null {
89
+ if (!TRACE_COMMANDS.has(command)) {
90
+ process.stderr.write(`unknown trace command: ${command}\n${HELP}`);
91
+ return 2;
92
+ }
93
+ if (TRACE_COMMANDS_NEEDING_RUN_ID.has(command) && !runId) return missingRunId(command);
94
+ return null;
66
95
  }
67
96
 
68
97
  export async function runTraceCommand(args: string[]): Promise<number> {
@@ -86,6 +115,14 @@ export async function runTraceCommand(args: string[]): Promise<number> {
86
115
  process.stdout.write(HELP);
87
116
  return command === "help" ? 0 : 2;
88
117
  }
118
+ const sqlQuery = parsed.positional.slice(1).join(" ");
119
+ const usageError = invocationError(command, runId);
120
+ if (usageError !== null) return usageError;
121
+ if (command === "sql" && !sqlQuery) {
122
+ process.stderr.write("trace sql requires a SELECT query\n");
123
+ return 2;
124
+ }
125
+
89
126
  if (command === "ui") return runTraceUi(parsed.db, parsed.port);
90
127
 
91
128
  // A database that was never written is the empty state, not a failure. Handing
@@ -104,29 +141,40 @@ export async function runTraceCommand(args: string[]): Promise<number> {
104
141
  return 1;
105
142
  }
106
143
  try {
144
+ // Every case below is reachable only after `invocationError` accepted the
145
+ // command and its required positional, so the run id is present wherever
146
+ // this reads one.
107
147
  switch (command) {
108
- case "runs":
109
- printRuns(reader.runs(parsed.limit));
148
+ case "runs": {
149
+ const rows = reader.runs(parsed.limit);
150
+ if (parsed.json) process.stdout.write(`${JSON.stringify(rows, jsonBigInt, 2)}\n`);
151
+ else printRuns(rows);
110
152
  return 0;
153
+ }
111
154
  case "phases":
112
- if (!runId) return missingRunId(command);
113
- printPhases(reader.phases(runId));
155
+ printPhases(reader.phases(runId ?? ""));
114
156
  return 0;
115
157
  case "tail":
116
- if (!runId) return missingRunId(command);
117
- await tail(reader, runId, parsed.follow);
158
+ await tail(reader, runId ?? "", parsed.follow);
118
159
  return 0;
119
160
  case "procs":
120
- if (!runId) return missingRunId(command);
121
- printProcesses(reader.processes(runId));
161
+ printProcesses(reader.processes(runId ?? ""));
122
162
  return 0;
123
163
  case "sql": {
124
- const query = parsed.positional.slice(1).join(" ");
125
- if (!query) {
126
- process.stderr.write("trace sql requires a SELECT query\n");
164
+ // The database opened cleanly above, so anything the store objects to
165
+ // here is the query the operator typed: a mutating statement, more
166
+ // than one statement, or SQL that will not parse. All three are usage
167
+ // errors. Refusing `DELETE FROM runs` with exit 1 said "the command
168
+ // failed" when the truth is "that is not a query this accepts", and
169
+ // the exit-code contract puts a mutation keyword at 2.
170
+ let rows: unknown;
171
+ try {
172
+ rows = reader.select(sqlQuery);
173
+ } catch (error) {
174
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
127
175
  return 2;
128
176
  }
129
- process.stdout.write(`${JSON.stringify(reader.select(query), jsonBigInt, 2)}\n`);
177
+ process.stdout.write(`${JSON.stringify(rows, jsonBigInt, 2)}\n`);
130
178
  return 0;
131
179
  }
132
180
  default:
@@ -172,9 +172,12 @@ export async function runUpgradeCommand(argv: ReadonlyArray<string>): Promise<nu
172
172
  // After `npm install -g` the two differ until the refresh below, and that
173
173
  // difference is the upgrade this command reports.
174
174
  const recorded = readStateInfo()?.version ?? null;
175
+ // Both the dry run and the real run print this, so it stays in the mood the
176
+ // call site sets with "would refresh" or "refreshed". The null branch used to
177
+ // bake in "would write it", which a real upgrade printed after writing it.
175
178
  const describeRefresh = (): string =>
176
179
  recorded === null
177
- ? "state metadata (none recorded; would write it)"
180
+ ? "state metadata (none recorded)"
178
181
  : recorded === before
179
182
  ? `state metadata (already ${before})`
180
183
  : `state metadata ${recorded} -> ${before}`;
@@ -233,7 +236,20 @@ export async function runUpgradeCommand(argv: ReadonlyArray<string>): Promise<nu
233
236
  printError("lifecycle domain unavailable");
234
237
  return 1;
235
238
  }
236
- const result = await lifecycle.runMigrations(stateDir);
239
+ let result: Awaited<ReturnType<LifecycleContract["runMigrations"]>>;
240
+ try {
241
+ result = await lifecycle.runMigrations(stateDir);
242
+ } catch (err) {
243
+ // A migration reports why it could not run, but on its own that reads
244
+ // as the whole upgrade being impossible. It is not: the rest of the
245
+ // upgrade is independent of it, and naming the flag that runs the rest
246
+ // is the difference between a stuck operator and a moved one.
247
+ printError(
248
+ `migration failed: ${err instanceof Error ? err.message : String(err)}`,
249
+ "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`.",
250
+ );
251
+ return 1;
252
+ }
237
253
  appliedIds = [...result.applied];
238
254
  appliedCount = appliedIds.length;
239
255
  if (appliedCount === 0) {