@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
@@ -9,7 +9,8 @@ import type { ClioSettings } from "../core/config.js";
9
9
  import type { MiddlewareToolChoiceControl } from "../domains/middleware/index.js";
10
10
  import type { ObservabilityContract } from "../domains/observability/contract.js";
11
11
  import type { SessionTurnUsage } from "../domains/observability/trace-store.js";
12
- import type { SessionContract } from "../domains/session/contract.js";
12
+ import type { SessionContract, TurnInput } from "../domains/session/contract.js";
13
+ import type { ClioTurnRecord } from "../engine/session.js";
13
14
  import type { AgentEvent, AgentMessage, Usage } from "../engine/types.js";
14
15
  import {
15
16
  type AssistantCallTiming,
@@ -98,6 +99,28 @@ export function createTurnPersistence(deps: TurnPersistenceDeps): TurnPersistenc
98
99
  const { state } = deps;
99
100
  const persistedAssistantMessages = new WeakSet<object>();
100
101
 
102
+ // --- ledger appends -------------------------------------------------------
103
+ // Every turn this loop writes parents onto `state.lastTurnId`, the loop's own
104
+ // copy of the session leaf. session.append refuses a parent that is not the
105
+ // session's current leaf, and a refusal used to leave that copy stale, so
106
+ // every later submit failed the same way until the operator ran /resume.
107
+ // A stale copy has one known producer: a caller of resetForSession that
108
+ // passed a leaf captured before another turn landed. Whatever produced it,
109
+ // the right parent is the session's real leaf, so re-sync to it and append
110
+ // once more; a second refusal is a genuine session fault and propagates.
111
+ const appendTurn = (session: SessionContract, turn: Omit<TurnInput, "parentId">): ClioTurnRecord => {
112
+ try {
113
+ return session.append({ ...turn, parentId: state.lastTurnId } as TurnInput);
114
+ } catch (err) {
115
+ const current = session.current();
116
+ if (!current) throw err;
117
+ const leaf = session.tree(current.id).leafId;
118
+ if (leaf === state.lastTurnId) throw err;
119
+ state.lastTurnId = leaf;
120
+ return session.append({ ...turn, parentId: leaf } as TurnInput);
121
+ }
122
+ };
123
+
101
124
  // --- trace mirror ---------------------------------------------------------
102
125
  // One open runs/phases pair per operator turn, opened by the user row that
103
126
  // starts the turn and closed by the assistant row that ends it. Every helper
@@ -227,9 +250,8 @@ export function createTurnPersistence(deps: TurnPersistenceDeps): TurnPersistenc
227
250
  return;
228
251
  }
229
252
  if (message && typeof message === "object") persistedAssistantMessages.add(message as object);
230
- const turn = deps.session.append({
253
+ const turn = appendTurn(deps.session, {
231
254
  kind: "assistant",
232
- parentId: state.lastTurnId,
233
255
  payload,
234
256
  });
235
257
  state.lastTurnId = turn.id;
@@ -268,9 +290,8 @@ export function createTurnPersistence(deps: TurnPersistenceDeps): TurnPersistenc
268
290
  if (settings.orchestrator.model) input.model = settings.orchestrator.model;
269
291
  deps.session.create(input);
270
292
  }
271
- const userTurn = deps.session.append({
293
+ const userTurn = appendTurn(deps.session, {
272
294
  kind: "user",
273
- parentId: state.lastTurnId,
274
295
  payload: { text },
275
296
  });
276
297
  state.lastTurnId = userTurn.id;
@@ -282,9 +303,8 @@ export function createTurnPersistence(deps: TurnPersistenceDeps): TurnPersistenc
282
303
 
283
304
  appendToolCallTurn(event): void {
284
305
  if (!deps.session) return;
285
- const turn = deps.session.append({
306
+ const turn = appendTurn(deps.session, {
286
307
  kind: "tool_call",
287
- parentId: state.lastTurnId,
288
308
  payload: {
289
309
  toolCallId: event.toolCallId,
290
310
  name: event.toolName,
@@ -318,9 +338,8 @@ export function createTurnPersistence(deps: TurnPersistenceDeps): TurnPersistenc
318
338
  // instead of re-deriving it from result text.
319
339
  if (event.outcome !== undefined) payload.outcome = event.outcome;
320
340
  if (event.blockReason !== undefined) payload.blockReason = event.blockReason;
321
- const turn = deps.session.append({
341
+ const turn = appendTurn(deps.session, {
322
342
  kind: "tool_result",
323
- parentId: state.lastTurnId,
324
343
  payload,
325
344
  });
326
345
  state.lastTurnId = turn.id;
@@ -350,9 +369,8 @@ export function createTurnPersistence(deps: TurnPersistenceDeps): TurnPersistenc
350
369
 
351
370
  appendTerminalToolAssistantTurn(terminal): void {
352
371
  if (!deps.session) return;
353
- const turn = deps.session.append({
372
+ const turn = appendTurn(deps.session, {
354
373
  kind: "assistant",
355
- parentId: state.lastTurnId,
356
374
  payload: {
357
375
  text: "",
358
376
  stopReason: "stop",
@@ -385,9 +403,8 @@ export function createTurnPersistence(deps: TurnPersistenceDeps): TurnPersistenc
385
403
  payload.synthetic = true;
386
404
  payload.source = "middleware_request_continuation";
387
405
  }
388
- const userTurn = deps.session.append({
406
+ const userTurn = appendTurn(deps.session, {
389
407
  kind: "user",
390
- parentId: state.lastTurnId,
391
408
  payload,
392
409
  });
393
410
  state.lastTurnId = userTurn.id;
@@ -10,8 +10,20 @@
10
10
  import type { AgentMessage } from "../engine/types.js";
11
11
  import type { ChatTurnState } from "./turn-state.js";
12
12
 
13
+ /** Which engine queue a queued message rides: the steering queue or the follow-up queue. */
13
14
  export type QueuedMessageKind = "steer" | "follow-up";
14
15
 
16
+ /**
17
+ * Operator-chosen delivery point for a message submitted while a run is
18
+ * active. `next-slot` rides the steering queue and lands between tool batches,
19
+ * mid-run. `end-of-turn` rides the follow-up queue and lands when the whole run
20
+ * settles and the agent would hand control back. `interrupt` cancels the
21
+ * in-flight work and delivers now; it never enters a queue.
22
+ */
23
+ export type SteeringMode = "interrupt" | "next-slot" | "end-of-turn";
24
+
25
+ export const DEFAULT_STEERING_MODE: SteeringMode = "next-slot";
26
+
15
27
  export interface QueuedChatMessage {
16
28
  text: string;
17
29
  kind: QueuedMessageKind;
@@ -79,9 +79,10 @@ export interface TurnRecovery {
79
79
  * that landed in the same window wins: `activeInterruptReason` is set only by
80
80
  * `ChatLoop.cancel`, so the stall reason is dropped rather than retried.
81
81
  *
82
- * The failure's assistant message is rewritten in place because it is the same
83
- * object the ledger persists and the transcript renders; without it the turn
84
- * would read "[aborted] Request was aborted." instead of naming the stall.
82
+ * The runtime event seam calls `rewriteStallAbortMessage` before publishing or
83
+ * persisting `message_end`, so the provider's one terminal message becomes the
84
+ * corrected ledger row. This post-settlement pass covers engines that settle
85
+ * without emitting that event and consumes the watchdog reason in either case.
85
86
  */
86
87
  export function reclassifyStallAbort(
87
88
  state: ChatTurnState,
@@ -90,14 +91,30 @@ export function reclassifyStallAbort(
90
91
  const reason = state.streamStallReason;
91
92
  state.streamStallReason = null;
92
93
  if (reason === null || failure.stopReason !== "aborted" || state.activeInterruptReason !== null) return failure;
93
- if (failure.message) {
94
- const message = failure.message as { stopReason?: unknown; errorMessage?: unknown };
95
- message.stopReason = "error";
96
- message.errorMessage = reason;
97
- }
94
+ if (failure.message) rewriteStallAbortMessage(state, failure.message, reason);
98
95
  return { ...failure, stopReason: "error", errorMessage: reason };
99
96
  }
100
97
 
98
+ /** Rewrite the provider's terminal abort object before its event is emitted and persisted. */
99
+ export function rewriteStallAbortMessage(
100
+ state: ChatTurnState,
101
+ message: AgentMessage,
102
+ reason = state.streamStallReason,
103
+ ): boolean {
104
+ if (
105
+ reason === null ||
106
+ state.activeInterruptReason !== null ||
107
+ message.role !== "assistant" ||
108
+ (message as { stopReason?: unknown }).stopReason !== "aborted"
109
+ ) {
110
+ return false;
111
+ }
112
+ const failure = message as { stopReason?: unknown; errorMessage?: unknown };
113
+ failure.stopReason = "error";
114
+ failure.errorMessage = reason;
115
+ return true;
116
+ }
117
+
101
118
  export function createTurnRecovery(deps: TurnRecoveryDeps): TurnRecovery {
102
119
  const { state, persistence, context } = deps;
103
120
  let retryCountdown: RetryCountdownHandle | null = null;
@@ -11,7 +11,6 @@ import type { MiddlewareToolChoiceControl } from "../domains/middleware/index.js
11
11
  import type { ObservabilityContract } from "../domains/observability/contract.js";
12
12
  import {
13
13
  applyModelCapabilityPatch,
14
- firstRuntimeResolutionError,
15
14
  modelResidencyForStatus,
16
15
  type ProvidersContract,
17
16
  refineRuntimeTargetWithModelHints,
@@ -35,6 +34,7 @@ import {
35
34
  type AssistantCallTiming,
36
35
  type BackendCacheVerdict,
37
36
  backendCacheVerdict,
37
+ estimatedUsageForInterruptedTurn,
38
38
  extractText,
39
39
  extractThinking,
40
40
  fallbackIdentityPrompt,
@@ -52,6 +52,22 @@ import type { AgentRuntime, ChatLoopTarget, ChatTurnState } from "./turn-state.j
52
52
 
53
53
  const LOCAL_API_KEY_FALLBACK = "clio-local-target";
54
54
 
55
+ /**
56
+ * A turn that never started, with a machine-readable reason attached. The
57
+ * operator-facing message is unchanged prose; `reason` exists because the ACP
58
+ * server has to tell a client *why* Clio refused to admit the prompt, and
59
+ * parsing that out of the prose would bind a wire contract to a sentence.
60
+ */
61
+ export class TurnAdmissionError extends Error {
62
+ constructor(
63
+ message: string,
64
+ readonly reason: string,
65
+ ) {
66
+ super(message);
67
+ this.name = "TurnAdmissionError";
68
+ }
69
+ }
70
+
55
71
  /**
56
72
  * Say that the first request will pay for a load, before it does.
57
73
  *
@@ -177,8 +193,11 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
177
193
  requireOutputBudget: true,
178
194
  });
179
195
  if (!resolved.ok) {
180
- const message = firstRuntimeResolutionError(resolved.diagnostics) ?? resolved.diagnostics[0]?.message;
181
- throw new Error(`[Clio Coder] ${message ?? "orchestrator target resolution failed"}`);
196
+ const failure = resolved.diagnostics.find((entry) => entry.severity === "error") ?? resolved.diagnostics[0];
197
+ throw new TurnAdmissionError(
198
+ `[Clio Coder] ${failure?.message ?? "orchestrator target resolution failed"}`,
199
+ failure?.code ?? "admission-failed",
200
+ );
182
201
  }
183
202
  for (const message of runtimeResolutionWarnings(resolved.diagnostics)) {
184
203
  const key = `${targetId}|${wireModelId}|${message}`;
@@ -331,8 +350,9 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
331
350
  if (!target) return null;
332
351
  context.emitContextWindowWarningTransition(target.runtimeResolution?.contextWindowDetails?.warning ?? null);
333
352
  if (!deps.knownTargets().has(target.target.id)) {
334
- throw new Error(
353
+ throw new TurnAdmissionError(
335
354
  `[Clio Coder] orchestrator target=${target.target.id} unknown. Run \`clio-coder targets\` to see configured targets.`,
355
+ "target-unknown",
336
356
  );
337
357
  }
338
358
  if (
@@ -400,6 +420,7 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
400
420
  state.runtime.agent.abort();
401
421
  cleanupSessionResources(state.runtime.agent.sessionId);
402
422
  }
423
+ let getCurrentAgentSignal: () => AbortSignal | undefined = () => undefined;
403
424
  const handle = deps.createAgent({
404
425
  initialState: {
405
426
  systemPrompt: fallbackIdentityPrompt(),
@@ -428,10 +449,16 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
428
449
  if (!targetRequiresAuth(target.target, target.runtime)) {
429
450
  return LOCAL_API_KEY_FALLBACK;
430
451
  }
431
- const resolved = await deps.providers.auth.resolveForTarget(target.target, target.runtime);
452
+ const signal = getCurrentAgentSignal();
453
+ const resolved = await deps.providers.auth.resolveForTarget(
454
+ target.target,
455
+ target.runtime,
456
+ signal ? { signal } : undefined,
457
+ );
432
458
  return resolved.apiKey;
433
459
  },
434
460
  });
461
+ getCurrentAgentSignal = () => handle.agent.signal;
435
462
 
436
463
  // Build the runtime object before subscribing so the callback closes
437
464
  // over the same heap object the hot-swap path mutates. Reading
@@ -543,6 +570,11 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
543
570
  // message of the run (prompts, assistant, tool results) via message_end,
544
571
  // so the slice from here is the run's real message window.
545
572
  let runStartMessageCount = 0;
573
+ // Estimated spend of each cancelled call, keyed by the engine's message
574
+ // object: message_end publishes it, agent_end re-reports it on the same
575
+ // object from agent state, and a suppressed hollow abort hands it to the
576
+ // closing turn. Weak so a settled run's messages are not retained.
577
+ const interruptedUsageByMessage = new WeakMap<object, Record<string, unknown>>();
546
578
 
547
579
  handle.agent.subscribe(async (event) => {
548
580
  // Wall anchor for the one field a human reads back (`recordedAt`);
@@ -608,7 +640,36 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
608
640
  enrichedEvent = { ...event, lockedSynthesisSanitized: true } as typeof event;
609
641
  }
610
642
  }
611
- const publicEvent = enrichedEvent;
643
+ let publicEvent = enrichedEvent;
644
+ if (enrichedEvent.type === "message_end" && enrichedEvent.message?.role === "assistant") {
645
+ const interruptedUsage = estimatedUsageForInterruptedTurn(enrichedEvent.message, context.promptSideTokens());
646
+ if (interruptedUsage !== null) {
647
+ // Persistence records the same estimate, but it does so after the
648
+ // public event has already fed status. Copy it onto the public event
649
+ // only: the raw engine message and observability/cost path must remain
650
+ // provider-reported. Remember it by message identity so the public
651
+ // agent_end window below reports the same figure.
652
+ interruptedUsageByMessage.set(enrichedEvent.message as object, interruptedUsage);
653
+ publicEvent = {
654
+ ...enrichedEvent,
655
+ message: { ...enrichedEvent.message, usage: interruptedUsage as unknown as Usage },
656
+ } as typeof enrichedEvent;
657
+ }
658
+ }
659
+ if (enrichedEvent.type === "agent_end") {
660
+ // The aborted message in the run window still carries the provider's
661
+ // untouched zeros. The footer's settled summary and the transcript's
662
+ // `turn · in/out` receipt both rebuild from this window, so give them
663
+ // the estimate the message_end published; the raw window feeds
664
+ // observability and the cache summary below unchanged.
665
+ const reported = enrichedEvent.messages.map((message) => {
666
+ const estimate = interruptedUsageByMessage.get(message as object);
667
+ return estimate === undefined ? message : ({ ...message, usage: estimate as unknown as Usage } as typeof message);
668
+ });
669
+ if (reported.some((message, index) => message !== enrichedEvent.messages[index])) {
670
+ publicEvent = { ...enrichedEvent, messages: reported } as typeof enrichedEvent;
671
+ }
672
+ }
612
673
  if (publicEvent?.type === "agent_start") {
613
674
  runStartMessageCount = localRuntime.agent.state.messages.length;
614
675
  streamStartedAt = eventClock;
@@ -644,11 +705,11 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
644
705
  if (hasDelta && firstAssistantDeltaAt === null) firstAssistantDeltaAt = eventClock;
645
706
  if (hasDelta && apiCallFirstDeltaAt === null) apiCallFirstDeltaAt = eventClock;
646
707
  }
647
- if (publicEvent?.type === "agent_end") {
648
- context.noteRunCacheSummary(publicEvent.messages, runFirstCallVerdict);
708
+ if (enrichedEvent.type === "agent_end") {
709
+ context.noteRunCacheSummary(enrichedEvent.messages, runFirstCallVerdict);
649
710
  }
650
- if (publicEvent?.type === "agent_end" && deps.observability) {
651
- const summary = sumRunUsage(publicEvent.messages);
711
+ if (enrichedEvent.type === "agent_end" && deps.observability) {
712
+ const summary = sumRunUsage(enrichedEvent.messages);
652
713
  if (summary.hadUsage && (summary.tokens > 0 || summary.costUsd > 0)) {
653
714
  deps.observability.recordTokens(
654
715
  localRuntime.targetId,
@@ -687,9 +748,15 @@ export function createTurnRuntime(deps: TurnRuntimeDeps): TurnRuntime {
687
748
  // persistence does.
688
749
  if (
689
750
  state.activeInterruptReason !== null &&
690
- publicEvent?.type === "message_end" &&
691
- isEmptyAbortedAssistantMessage(publicEvent.message)
751
+ enrichedEvent.type === "message_end" &&
752
+ isEmptyAbortedAssistantMessage(enrichedEvent.message)
692
753
  ) {
754
+ // The ledger drops this message too, so the spend the cancelled call
755
+ // streamed as thinking would otherwise vanish from the durable record.
756
+ // Hand it to the closing turn the interrupt persists when the run
757
+ // settles; the public agent_end window above still feeds status.
758
+ const estimate = interruptedUsageByMessage.get(enrichedEvent.message as object);
759
+ if (estimate !== undefined) state.interruptedUsage = estimate;
693
760
  return;
694
761
  }
695
762
  if (publicEvent) deps.emit(publicEvent);
@@ -39,6 +39,7 @@ export interface AgentRuntime {
39
39
 
40
40
  export interface ChatLoopRunSnapshot {
41
41
  targetId: string;
42
+ targetUrl: string | null;
42
43
  runtimeId: string;
43
44
  runtimeKind: RuntimeDescriptor["kind"];
44
45
  wireModelId: string;
@@ -74,6 +75,14 @@ export interface ChatTurnState {
74
75
  * start of each submit.
75
76
  */
76
77
  activeInterruptReason: string | null;
78
+ /**
79
+ * Estimated spend of the cancelled call whose hollow aborted message the
80
+ * interrupt suppressed (thinking streamed, no text). The message never reaches
81
+ * the ledger, so the closing turn persisted in submit's finally carries this
82
+ * instead of an estimate derived from its own notice text. Cleared with
83
+ * `activeInterruptReason`.
84
+ */
85
+ interruptedUsage: Record<string, unknown> | null;
77
86
  /**
78
87
  * Loop-guard synthesis lockout: once the guard locks a turn, the remaining
79
88
  * model rounds are forced text-only at the request level (tool_choice none
@@ -108,6 +117,7 @@ export function createTurnState(initialThinkingLevel: ThinkingLevel): ChatTurnSt
108
117
  replayedContextMessages: [],
109
118
  activeUserTurnId: null,
110
119
  activeInterruptReason: null,
120
+ interruptedUsage: null,
111
121
  synthesisToolLock: false,
112
122
  toolProseAbortReason: null,
113
123
  streamStallReason: null,
@@ -1,6 +1,6 @@
1
1
  import { createReadStream, readFileSync, statSync } from "node:fs";
2
- import { readFile, stat } from "node:fs/promises";
3
- import { basename, isAbsolute, join, resolve } from "node:path";
2
+ import { readFile, realpath, stat } from "node:fs/promises";
3
+ import { basename, isAbsolute, join, relative, resolve, sep } from "node:path";
4
4
  import type { DispatchContract } from "../../domains/dispatch/contract.js";
5
5
  import {
6
6
  isReceiptIntegrity,
@@ -31,6 +31,8 @@ import {
31
31
  readPromptCompileManifest,
32
32
  type SessionPromptCompileRecord,
33
33
  } from "../../domains/session/prompt-manifest.js";
34
+ import { foldSessionArtifacts, resolveSessionArtifactPath } from "../../domains/session/session-artifacts.js";
35
+ import { filterEntriesToActivePath } from "../../domains/session/tree/active-path.js";
34
36
  import { formatUsd } from "../footer/widgets.js";
35
37
  import { formatFooterTokens } from "../footer-panel.js";
36
38
  import { clockLocal } from "../format-time.js";
@@ -42,6 +44,7 @@ export type ViewArtifactCategory =
42
44
  | "receipt"
43
45
  | "dispatch"
44
46
  | "task-ledger"
47
+ | "workspace"
45
48
  | "tool-output"
46
49
  | "protected-artifact"
47
50
  | "compaction"
@@ -91,6 +94,7 @@ export const VIEW_ARTIFACT_CATEGORIES: readonly ViewArtifactCategory[] = [
91
94
  "receipt",
92
95
  "dispatch",
93
96
  "task-ledger",
97
+ "workspace",
94
98
  "tool-output",
95
99
  "protected-artifact",
96
100
  "compaction",
@@ -815,6 +819,8 @@ function renderTaskLedgerGoals(lines: string[], heading: string, goals: Readonly
815
819
  for (const goal of goals) {
816
820
  const parent = goal.parentGoalId ? ` parent ${goal.parentGoalId}` : "";
817
821
  lines.push(`- [${goal.status}] ${goal.id} ${goal.title}${parent}`);
822
+ if (goal.origin) lines.push(` - origin: ${goal.origin}`);
823
+ if (goal.userTaskId) lines.push(` - operator task: ${goal.userTaskId}`);
818
824
  if (goal.description) lines.push(` - description: ${goal.description}`);
819
825
  }
820
826
  }
@@ -842,6 +848,7 @@ function renderTaskLedgerMarkdown(entry: TaskLedgerEntry): string[] {
842
848
  `- timestamp: ${entry.timestamp}`,
843
849
  `- status: ${taskLedgerStatusSummary(entry)}`,
844
850
  ];
851
+ if (entry.boardId) lines.push(`- board id: ${entry.boardId}`);
845
852
  renderTaskLedgerGoals(lines, "## Board Goals", entry.goals);
846
853
  renderTaskLedgerGoals(lines, "## Subgoals", entry.subgoals);
847
854
  lines.push("", "## Active Runs");
@@ -873,9 +880,24 @@ export class TaskLedgerArtifactProvider implements ArtifactProvider {
873
880
  ...(path ? { path } : {}),
874
881
  searchText: [
875
882
  entry.turnId,
883
+ entry.boardId ?? "",
876
884
  ...entry.activeRunIds,
877
- ...entry.goals.flatMap((goal) => [goal.id, goal.title, goal.description ?? "", goal.parentGoalId ?? ""]),
878
- ...entry.subgoals.flatMap((goal) => [goal.id, goal.title, goal.description ?? "", goal.parentGoalId ?? ""]),
885
+ ...entry.goals.flatMap((goal) => [
886
+ goal.id,
887
+ goal.title,
888
+ goal.description ?? "",
889
+ goal.parentGoalId ?? "",
890
+ goal.origin ?? "agent",
891
+ goal.userTaskId ?? "",
892
+ ]),
893
+ ...entry.subgoals.flatMap((goal) => [
894
+ goal.id,
895
+ goal.title,
896
+ goal.description ?? "",
897
+ goal.parentGoalId ?? "",
898
+ goal.origin ?? "agent",
899
+ goal.userTaskId ?? "",
900
+ ]),
879
901
  ...entry.requiredValidationEvidence.flatMap((item) => [
880
902
  item.id,
881
903
  item.description,
@@ -892,6 +914,93 @@ export class TaskLedgerArtifactProvider implements ArtifactProvider {
892
914
  }
893
915
  }
894
916
 
917
+ function workspaceArtifactFormat(path: string): ViewArtifactFormat {
918
+ const lower = path.toLowerCase();
919
+ return lower.endsWith(".md") || lower.endsWith(".markdown") ? "markdown" : "text";
920
+ }
921
+
922
+ class WorkspaceArtifactContainmentError extends Error {}
923
+
924
+ async function canonicalWorkspaceArtifactPath(path: string, workspace: string): Promise<string> {
925
+ // Resolve both sides from the live filesystem for every load. The artifact
926
+ // row is durable, but neither an earlier lexical check nor an earlier realpath
927
+ // result is authority after a symlink has changed.
928
+ const canonicalWorkspace = await realpath(workspace);
929
+ const canonicalTarget = await realpath(path);
930
+ const rel = relative(canonicalWorkspace, canonicalTarget);
931
+ if (rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute(rel)) {
932
+ throw new WorkspaceArtifactContainmentError("canonical target is outside the recorded workspace");
933
+ }
934
+ return canonicalTarget;
935
+ }
936
+
937
+ async function loadWorkspaceArtifact(
938
+ path: string,
939
+ workspace: string,
940
+ recordedAt: string,
941
+ ): Promise<ViewArtifactLoadResult> {
942
+ try {
943
+ const canonicalPath = await canonicalWorkspaceArtifactPath(path, workspace);
944
+ const { lines } = await readTextFileLinesCapped(canonicalPath);
945
+ return { lines, format: workspaceArtifactFormat(path) };
946
+ } catch (error) {
947
+ const err = error as NodeJS.ErrnoException;
948
+ if (err.code === "ENOENT") {
949
+ return { lines: [`file no longer on disk (recorded at ${recordedAt})`], format: "text" };
950
+ }
951
+ if (error instanceof WorkspaceArtifactContainmentError) {
952
+ return { lines: [`refusing to read ${path}: ${error.message}`], format: "text" };
953
+ }
954
+ const message = error instanceof Error ? error.message : String(error);
955
+ return { lines: [`unable to read ${path}: ${message}`], format: "text" };
956
+ }
957
+ }
958
+
959
+ /** Files successfully produced by artifact/write/edit on the active session branch. */
960
+ export class WorkspaceArtifactProvider implements ArtifactProvider {
961
+ readonly category = "workspace" as const;
962
+ private readonly entries: ReadonlyArray<SessionEntry>;
963
+
964
+ constructor(private readonly deps: ArtifactProviderDeps) {
965
+ const entries = [...sessionEntries(deps)];
966
+ this.entries = filterEntriesToActivePath(entries, deps.sessionMeta?.pinnedLeafTurnId ?? undefined);
967
+ }
968
+
969
+ async list(): Promise<ViewArtifact[]> {
970
+ const workspace = this.deps.sessionMeta?.cwd;
971
+ if (!workspace) return [];
972
+ return foldSessionArtifacts(this.entries, { workspace }).flatMap((artifact) => {
973
+ const path = resolveSessionArtifactPath(artifact.path, workspace);
974
+ if (path === null) return [];
975
+ const kind = artifact.artifactKind ? ` · ${artifact.artifactKind}` : "";
976
+ const overwriteLabel = `${artifact.overwrites} overwrite${artifact.overwrites === 1 ? "" : "s"}`;
977
+ return [
978
+ {
979
+ id: `workspace:${path}`,
980
+ category: this.category,
981
+ title: safeTitle(`${artifact.path} · ${artifact.tool}${kind}`, artifact.path),
982
+ timestamp: parseTime(artifact.timestamp),
983
+ sizeBytes: maybeSizeBytes(path),
984
+ path,
985
+ description: `${artifact.tool}${kind} · ${overwriteLabel}`,
986
+ toolName: artifact.tool,
987
+ searchText: [
988
+ artifact.path,
989
+ path,
990
+ basename(path),
991
+ artifact.tool,
992
+ artifact.artifactKind ?? "",
993
+ overwriteLabel,
994
+ String(artifact.overwrites),
995
+ artifact.turnId,
996
+ ].filter(isNonEmptyString),
997
+ load: () => loadWorkspaceArtifact(path, workspace, artifact.timestamp),
998
+ },
999
+ ];
1000
+ });
1001
+ }
1002
+ }
1003
+
895
1004
  export class ToolOutputArtifactProvider implements ArtifactProvider {
896
1005
  readonly category = "tool-output" as const;
897
1006
 
@@ -1310,6 +1419,7 @@ export function createDefaultArtifactProviders(deps: ArtifactProviderDeps): Arti
1310
1419
  new ReceiptArtifactProvider(deps),
1311
1420
  new DispatchArtifactProvider(deps),
1312
1421
  new TaskLedgerArtifactProvider(deps),
1422
+ new WorkspaceArtifactProvider(deps),
1313
1423
  new ToolOutputArtifactProvider(deps),
1314
1424
  new ProtectedArtifactProvider(deps),
1315
1425
  new CompactionArtifactProvider(deps),
@@ -109,6 +109,8 @@ function categoryLabel(category: ViewArtifactCategory): string {
109
109
  return "Dispatch outputs";
110
110
  case "task-ledger":
111
111
  return "Task ledgers";
112
+ case "workspace":
113
+ return "Workspace outputs";
112
114
  case "tool-output":
113
115
  return "Tool outputs";
114
116
  case "protected-artifact":
@@ -125,6 +127,7 @@ function categoryLabel(category: ViewArtifactCategory): string {
125
127
  const VIEW_ARTIFACT_CATEGORY_SET = new Set<ViewArtifactCategory>(VIEW_ARTIFACT_CATEGORIES);
126
128
  const BARE_CATEGORY_FILTERS = new Set<ViewArtifactCategory>([
127
129
  "task-ledger",
130
+ "workspace",
128
131
  "protected-artifact",
129
132
  "compaction",
130
133
  "prompt-manifest",
@@ -2,17 +2,16 @@ import { existsSync, readdirSync, statSync } from "node:fs";
2
2
  import { basename, join } from "node:path";
3
3
  import type { ClioSettings } from "../core/config.js";
4
4
  import { readClioVersion } from "../core/package-root.js";
5
- import { EXPERIMENTAL_RELEASE_WARNING } from "../core/release.js";
5
+ import { loadProjectClioMd } from "../domains/context/clio-md.js";
6
+ import { readCodewiki, readCodewikiAsync } from "../domains/context/codewiki/artifact.js";
7
+ import { renderCodewikiDigest } from "../domains/context/codewiki/digest.js";
8
+ import { listWikiPages } from "../domains/context/wiki/layout.js";
6
9
  import {
7
- listWikiPages,
8
- readCodewiki,
9
- readCodewikiAsync,
10
- renderCodewikiDigest,
11
10
  type WikiStaleness,
12
11
  wikiCompleteness,
13
12
  wikiStaleness,
14
13
  wikiStalenessAsync,
15
- } from "../domains/context/index.js";
14
+ } from "../domains/context/wiki/staleness.js";
16
15
  import type { TaskMemoryOperatorStatus } from "../domains/memory/index.js";
17
16
  import type { ObservabilityContract } from "../domains/observability/index.js";
18
17
  import {
@@ -172,7 +171,9 @@ function entryPointExcerpt(codewikiDigest: string): string[] {
172
171
  const NO_WIKI_STATUS = "no wiki; run clio-coder context wiki";
173
172
 
174
173
  function clioMdStatusFor(cwd: string): string {
175
- return existsSync(join(cwd, "CLIO-CODER.md")) ? "ok" : "none";
174
+ const loaded = loadProjectClioMd(cwd);
175
+ if (loaded.errors.length > 0) return "malformed";
176
+ return loaded.files.length > 0 ? "ok" : "none";
176
177
  }
177
178
 
178
179
  /** Shape the wiki rows from a staleness verdict the caller already paid for. */
@@ -370,7 +371,10 @@ function nextValue(stats: WelcomeDashboardStats): string {
370
371
  /**
371
372
  * The launchpad has one fixed row per decision the operator needs to make.
372
373
  * Repository facts may replace text inside NEXT, never rows. After submission,
373
- * the session header is exactly one line for every width and fact state.
374
+ * the session header is exactly one line for every width and fact state, and
375
+ * it carries the same three facts in order: where Clio is working, which
376
+ * route answers, and what the context is ready for. Maturity caveats belong
377
+ * in the README, not in a line the operator reads on every turn.
374
378
  */
375
379
  export function buildWelcomeDashboardLines(
376
380
  stats: WelcomeDashboardStats,
@@ -380,21 +384,18 @@ export function buildWelcomeDashboardLines(
380
384
  const theme = clioTheme();
381
385
  const safeWidth = Math.max(1, width);
382
386
  const title = `${brandMark(theme)} ${theme.style("title", "Clio Coder", { bold: true })} ${theme.fg("dim", `v${readClioVersion()}`)}`;
383
- const experimental = theme.style("warning", EXPERIMENTAL_RELEASE_WARNING, { bold: true });
384
387
  const tag = (label: string): string => sectionTag(theme, "accentDeep", label, 9);
385
388
  const row = (label: string, value: string): string => ` ${tag(label)} ${value}`;
389
+ const workspace = theme.fg("muted", workspaceValue(stats));
390
+ const route = theme.fg(stats.currentAvailable ? "success" : "warning", routeValue(stats));
391
+ const next = theme.fg(stats.clioMdStatus === "ok" && !stats.factsPending ? "success" : "warning", nextValue(stats));
386
392
 
387
393
  if (mode === "session") {
388
- const header = `${title} · ${experimental} · ${theme.fg("muted", nextValue(stats))}`;
394
+ const header = [title, workspace, route, theme.fg("muted", nextValue(stats))].join(" · ");
389
395
  return [truncateToWidth(header, safeWidth, GLYPH.ellipsis, true)];
390
396
  }
391
397
 
392
- const body = [
393
- ` ${experimental}`,
394
- row("WORKSPACE", theme.fg("muted", workspaceValue(stats))),
395
- row("ROUTE", theme.fg(stats.currentAvailable ? "success" : "warning", routeValue(stats))),
396
- row("NEXT", theme.fg(stats.clioMdStatus === "ok" && !stats.factsPending ? "success" : "warning", nextValue(stats))),
397
- ];
398
+ const body = [row("WORKSPACE", workspace), row("ROUTE", route), row("NEXT", next)];
398
399
  if (safeWidth >= MID_MIN) return frame(theme, title, body, safeWidth);
399
400
  return [title, ...body].map((line) => truncateToWidth(line, safeWidth, GLYPH.ellipsis, true));
400
401
  }