@iowarp/clio-coder 0.3.1 → 0.3.2

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 (595) hide show
  1. package/CHANGELOG.md +90 -2
  2. package/CONTRIBUTING.md +23 -23
  3. package/README.md +284 -613
  4. package/dist/{acp-FPR54DGL.js → acp-BIYHVZIM.js} +43 -53
  5. package/dist/{agents-OGPIHPJH.js → agents-YT6SSRIT.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-PV4JUBVJ.js → chunk-2EHAIA3X.js} +40 -21
  9. package/dist/{chunk-IS3ONKU3.js → chunk-2IR2NMPA.js} +6 -4
  10. package/dist/chunk-2SFS6XQE.js +122 -0
  11. package/dist/chunk-2VTFPG5O.js +48 -0
  12. package/dist/{chunk-MAR7Y6HW.js → chunk-3ZXDFGR5.js} +23 -16
  13. package/dist/chunk-4BJ5BYCE.js +61 -0
  14. package/dist/{chunk-474KN5II.js → chunk-4BPJXDWC.js} +111 -181
  15. package/dist/chunk-4KLWL3UC.js +18 -0
  16. package/dist/chunk-4VP4KH3K.js +962 -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-OLBBMFRD.js → chunk-5UUP6MWO.js} +24 -62
  21. package/dist/chunk-65DEGPJ6.js +52 -0
  22. package/dist/chunk-6EJMN2Y3.js +17 -0
  23. package/dist/chunk-6EJV5X2W.js +16405 -0
  24. package/dist/chunk-6N5PTWMY.js +136 -0
  25. package/dist/chunk-6XLNIQDB.js +27 -0
  26. package/dist/{chunk-TEKV33Q5.js → chunk-77VKQEHF.js} +65 -33
  27. package/dist/chunk-7CR24IG7.js +242 -0
  28. package/dist/{chunk-M5T5VO65.js → chunk-7EYHLWU7.js} +837 -635
  29. package/dist/chunk-7MNJORFF.js +22 -0
  30. package/dist/{chunk-KY56HMHH.js → chunk-A3CYT5EX.js} +125 -31
  31. package/dist/chunk-AGYYIBLL.js +1069 -0
  32. package/dist/chunk-AO4RKG4M.js +277 -0
  33. package/dist/{chunk-GB6QRBXN.js → chunk-APJ265NV.js} +54 -1187
  34. package/dist/chunk-ARBGF5F7.js +174 -0
  35. package/dist/{chunk-673JJUWJ.js → chunk-BMEMKKIT.js} +2 -2
  36. package/dist/chunk-CBCAPZAA.js +229 -0
  37. package/dist/chunk-CMZWFGD2.js +352 -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-RPTR2H26.js → chunk-EPVUXGXG.js} +21 -15
  42. package/dist/chunk-FCSXB6T2.js +338 -0
  43. package/dist/chunk-FJ3H4MN5.js +48 -0
  44. package/dist/chunk-FQ4SKYE4.js +29 -0
  45. package/dist/chunk-G2DE3C7R.js +644 -0
  46. package/dist/chunk-G4BMMOKF.js +182 -0
  47. package/dist/{chunk-ZPY3JZ5E.js → chunk-GGXXDWE4.js} +183 -1233
  48. package/dist/chunk-HC4CLZ2Y.js +68 -0
  49. package/dist/{chunk-LU4TK2PR.js → chunk-HFSBBKSQ.js} +5 -56
  50. package/dist/{chunk-PIUMUEMV.js → chunk-HKIYEGME.js} +10 -6
  51. package/dist/chunk-I4HZDVNP.js +73 -0
  52. package/dist/{chunk-4QKXUHSR.js → chunk-IGLFWIYI.js} +70 -20
  53. package/dist/chunk-IKCO5N3L.js +162 -0
  54. package/dist/chunk-IR4CFBFN.js +56 -0
  55. package/dist/{chunk-PFEFKVGL.js → chunk-J5HN4RYU.js} +13 -11
  56. package/dist/{chunk-R5KLMSBV.js → chunk-J5Q24KAG.js} +2 -2
  57. package/dist/{chunk-K5XEMXTI.js → chunk-JVCV3ICN.js} +1 -1
  58. package/dist/chunk-KJ5LWLOE.js +1077 -0
  59. package/dist/chunk-LBMZMYH2.js +285 -0
  60. package/dist/{chunk-G34LV2PF.js → chunk-LBNRH5WM.js} +84 -170
  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-MAW544W2.js +1882 -0
  64. package/dist/chunk-MBS4V7ZP.js +217 -0
  65. package/dist/{chunk-FST4FYJB.js → chunk-MFFY33HR.js} +99 -140
  66. package/dist/chunk-MNA4JGU4.js +255 -0
  67. package/dist/chunk-MQSRRFWA.js +3428 -0
  68. package/dist/{chunk-BSU2YIWB.js → chunk-MVVUPGPW.js} +131 -136
  69. package/dist/chunk-OAO4GE4M.js +619 -0
  70. package/dist/chunk-OHHN2SO4.js +5135 -0
  71. package/dist/chunk-OKGUZO2U.js +34 -0
  72. package/dist/{chunk-GAEBEQVI.js → chunk-OOJYHWRB.js} +32 -346
  73. package/dist/{chunk-Q5WJOSJ7.js → chunk-OQ33BKR3.js} +2 -1
  74. package/dist/chunk-OQE5J4C6.js +73 -0
  75. package/dist/{chunk-KKNLWXI6.js → chunk-ORBHGJC5.js} +8 -8
  76. package/dist/chunk-POHLU5DW.js +1186 -0
  77. package/dist/chunk-QKMUKYO7.js +4961 -0
  78. package/dist/{chunk-ASND7OZK.js → chunk-QTYWRVRA.js} +13 -13
  79. package/dist/{chunk-EYOKLTMF.js → chunk-SRF2PJNW.js} +17 -3
  80. package/dist/chunk-SST6Z5JA.js +80 -0
  81. package/dist/chunk-STBPMHSX.js +2456 -0
  82. package/dist/chunk-T6YILFSB.js +80 -0
  83. package/dist/chunk-TZTZS7QK.js +227 -0
  84. package/dist/chunk-UOV2BYIW.js +107 -0
  85. package/dist/{chunk-Q3RUPKEJ.js → chunk-V4RXGQ5Q.js} +58 -189
  86. package/dist/chunk-VAKQQHWR.js +434 -0
  87. package/dist/chunk-VG7TBQIY.js +128 -0
  88. package/dist/chunk-VJWL6YS5.js +244 -0
  89. package/dist/chunk-WEH5XRJQ.js +32 -0
  90. package/dist/chunk-WMSVI4G2.js +2095 -0
  91. package/dist/chunk-WVO7V2QY.js +797 -0
  92. package/dist/chunk-X4RCMKVQ.js +641 -0
  93. package/dist/chunk-X75S7HFS.js +374 -0
  94. package/dist/chunk-XN3L4EYL.js +46 -0
  95. package/dist/{chunk-RDLVBZEO.js → chunk-YCWGATWI.js} +6 -4
  96. package/dist/chunk-YHZX5GEU.js +193 -0
  97. package/dist/chunk-YXLYO42X.js +91 -0
  98. package/dist/{chunk-NMOX6HFD.js → chunk-ZDOOVTXZ.js} +29 -77
  99. package/dist/chunk-ZI647VB5.js +37 -0
  100. package/dist/{chunk-C4PTHK7P.js → chunk-ZWLZP4ZT.js} +5 -5
  101. package/dist/cli/index.js +62 -54
  102. package/dist/clio-4LY5K2AC.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-GTLUW2PR.js} +92 -55
  108. package/dist/configure-R6A64DHX.js +42 -0
  109. package/dist/context-5VKGUVJJ.js +866 -0
  110. package/dist/{context-3KWFLHJG.js → context-JFZEJ7W5.js} +15 -13
  111. package/dist/{context-5RADCKTR.js → context-RW5HC47S.js} +71 -35
  112. package/dist/{context-clear-7TSNPAAI.js → context-clear-6ZHBAZZT.js} +54 -28
  113. package/dist/{context-index-W4RLWOQH.js → context-index-BZ4UYMTC.js} +30 -24
  114. package/dist/dispatch-runner-VKBRCWQC.js +1997 -0
  115. package/dist/{docs-5AWSPS37.js → docs-2C2LTVT2.js} +23 -10
  116. package/dist/{doctor-UC5NAJYQ.js → doctor-KI767GSN.js} +27 -17
  117. package/dist/{eval-U6TJHRLX.js → eval-XSSNATB4.js} +29 -16
  118. package/dist/{evidence-YEGUW4L3.js → evidence-UA6AWDQQ.js} +46 -26
  119. package/dist/{evolve-TXARCTPG.js → evolve-QNTFGV6Z.js} +45 -25
  120. package/dist/{extensions-OZFJ3A3G.js → extensions-QVDOHDGJ.js} +16 -7
  121. package/dist/{fleet-6G3DHNYE.js → fleet-Q7UOMUSG.js} +163 -54
  122. package/dist/{fleet-preflight-DSNT37JK.js → fleet-preflight-DDN536IT.js} +7 -4
  123. package/dist/{init-KZ5QTF6M.js → init-WBB65ZHQ.js} +69 -32
  124. package/dist/{memory-73ESV5YC.js → memory-MD3O64RI.js} +48 -27
  125. package/dist/{models-A4PVNWJK.js → models-BZU34YWD.js} +39 -25
  126. package/dist/monitor-MEQA5C3I.js +661 -0
  127. package/dist/{chunk-FCIH3BIZ.js → orchestrator-CGFKEP27.js} +11832 -8687
  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-IV4Q6RLN.js} +101 -61
  132. package/dist/{share-YIFFV4NQ.js → share-S5BZQC5I.js} +15 -8
  133. package/dist/{skills-2V6RA3OQ.js → skills-LQEKRDTN.js} +34 -14
  134. package/dist/{skills-eval-S2TVJO4F.js → skills-eval-3DC4HEWS.js} +70 -34
  135. package/dist/steer-GGWFUJUD.js +77 -0
  136. package/dist/{targets-TYXLPB23.js → targets-C4SSGQOB.js} +43 -27
  137. package/dist/terminal-lease-IT5JW2NR.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-7TT7SQ3G.js} +45 -25
  142. package/dist/{usage-ZAFSXKKG.js → usage-GV4PKT3M.js} +62 -31
  143. package/dist/verify-G6V4D2G7.js +716 -0
  144. package/dist/web-fetch-2YHJ3KTG.js +638 -0
  145. package/dist/{wiki-generate-NUQCVOQ3.js → wiki-generate-DQF6Z66B.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 +362 -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 +42 -6
  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 +173 -47
  444. package/src/interactive/chat-renderer.ts +262 -72
  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 +228 -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 +20 -2
  456. package/src/interactive/footer-panel.ts +2 -2
  457. package/src/interactive/format-time.ts +14 -2
  458. package/src/interactive/interactive-application.ts +201 -17
  459. package/src/interactive/interactive-event-projection.ts +6 -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 +176 -114
  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/decisions.ts +300 -0
  474. package/src/interactive/overlays/help-reference.ts +15 -10
  475. package/src/interactive/overlays/model-selector.ts +34 -16
  476. package/src/interactive/overlays/session-selector.ts +18 -0
  477. package/src/interactive/overlays/settings.ts +105 -17
  478. package/src/interactive/overlays/skills-hub.ts +4 -4
  479. package/src/interactive/overlays/tree-selector.ts +41 -6
  480. package/src/interactive/render-trace.ts +499 -90
  481. package/src/interactive/renderers/compaction-summary.ts +2 -2
  482. package/src/interactive/renderers/diff.ts +115 -104
  483. package/src/interactive/renderers/mermaid.ts +53 -0
  484. package/src/interactive/renderers/tool-execution.ts +386 -133
  485. package/src/interactive/renderers/worker-entry.ts +20 -4
  486. package/src/interactive/session-switch-settlement.ts +10 -0
  487. package/src/interactive/slash-autocomplete.ts +6 -114
  488. package/src/interactive/slash-commands.ts +135 -47
  489. package/src/interactive/slash-spec.ts +9 -38
  490. package/src/interactive/status/controller.ts +5 -1
  491. package/src/interactive/stdout-backpressure.ts +99 -0
  492. package/src/interactive/stream-pacer.ts +530 -0
  493. package/src/interactive/stream-pacing-policy.ts +66 -0
  494. package/src/interactive/tasks-overlay.ts +368 -14
  495. package/src/interactive/terminal-lease.ts +485 -0
  496. package/src/interactive/theme/tokens.ts +1 -1
  497. package/src/interactive/turn-context.ts +4 -3
  498. package/src/interactive/turn-persistence.ts +30 -13
  499. package/src/interactive/turn-queues.ts +12 -0
  500. package/src/interactive/turn-recovery.ts +25 -8
  501. package/src/interactive/turn-runtime.ts +79 -12
  502. package/src/interactive/turn-state.ts +10 -0
  503. package/src/interactive/view/artifacts.ts +114 -4
  504. package/src/interactive/view/view-overlay.ts +3 -0
  505. package/src/interactive/welcome-dashboard.ts +17 -16
  506. package/src/interactive/worker-receipts.ts +52 -3
  507. package/src/interactive/worker-stream.ts +5 -1
  508. package/src/tools/agent-tools.ts +23 -3
  509. package/src/tools/artifact.ts +2 -2
  510. package/src/tools/ask-user.ts +23 -13
  511. package/src/tools/bash.ts +30 -2
  512. package/src/tools/bootstrap.ts +34 -431
  513. package/src/tools/builtin-tool-catalog.ts +265 -0
  514. package/src/tools/codewiki/code-nav-surface.ts +29 -0
  515. package/src/tools/codewiki/code-nav.ts +8 -22
  516. package/src/tools/codewiki/shared.ts +41 -38
  517. package/src/tools/context/docs-engine.ts +14 -3
  518. package/src/tools/context/index.ts +107 -28
  519. package/src/tools/context/surface.ts +19 -0
  520. package/src/tools/core-bootstrap.ts +168 -0
  521. package/src/tools/credential-present.ts +5 -5
  522. package/src/tools/dispatch-admission.ts +533 -0
  523. package/src/tools/dispatch-background.ts +54 -0
  524. package/src/tools/dispatch-event-text.ts +6 -0
  525. package/src/tools/dispatch-plan.ts +9 -4
  526. package/src/tools/dispatch-run-events.ts +238 -0
  527. package/src/tools/dispatch-runner.ts +2370 -0
  528. package/src/tools/dispatch-scout-admission.ts +295 -0
  529. package/src/tools/dispatch-types.ts +77 -0
  530. package/src/tools/dispatch.ts +67 -3161
  531. package/src/tools/find.ts +4 -2
  532. package/src/tools/grep.ts +2 -2
  533. package/src/tools/lazy-tool.ts +60 -0
  534. package/src/tools/ledger.ts +3 -3
  535. package/src/tools/monitor-surface.ts +36 -0
  536. package/src/tools/monitor.ts +2 -32
  537. package/src/tools/observers.ts +2 -2
  538. package/src/tools/registry.ts +39 -27
  539. package/src/tools/safe-exec.ts +2 -2
  540. package/src/tools/steer-surface.ts +17 -0
  541. package/src/tools/steer.ts +2 -13
  542. package/src/tools/tasks.ts +108 -11
  543. package/src/tools/truncate.ts +25 -184
  544. package/src/tools/verify/frontend.ts +3 -1
  545. package/src/tools/verify/index.ts +3 -38
  546. package/src/tools/verify/surface.ts +46 -0
  547. package/src/tools/web-fetch-surface.ts +23 -0
  548. package/src/tools/web-fetch.ts +2 -20
  549. package/src/tools/write.ts +7 -2
  550. package/src/worker/entry.ts +39 -2
  551. package/src/worker/spec-contract.ts +26 -5
  552. package/dist/chunk-7SS2CTV2.js +0 -61361
  553. package/dist/chunk-DKGKUHFA.js +0 -924
  554. package/dist/chunk-GEP36Y4X.js +0 -12796
  555. package/dist/chunk-XYWBQRDM.js +0 -137
  556. package/dist/clio-BZVGEUFJ.js +0 -58
  557. package/dist/configure-S7S6F6CL.js +0 -32
  558. package/docs/html/agents_blueprint.html +0 -936
  559. package/docs/html/alcf_blueprint.html +0 -324
  560. package/docs/html/architecture_blueprint.html +0 -850
  561. package/docs/html/commands_blueprint.html +0 -939
  562. package/docs/html/config_knobs_audit_blueprint.html +0 -178
  563. package/docs/html/configuration_blueprint.html +0 -1080
  564. package/docs/html/context_blueprint.html +0 -603
  565. package/docs/html/documentation_blueprint.html +0 -832
  566. package/docs/html/environment_blueprint.html +0 -404
  567. package/docs/html/eval_blueprint.html +0 -743
  568. package/docs/html/evals_internal_blueprint.html +0 -190
  569. package/docs/html/evolution_blueprint.html +0 -674
  570. package/docs/html/extensions_blueprint.html +0 -2065
  571. package/docs/html/fleet_dispatch_blueprint.html +0 -286
  572. package/docs/html/index.html +0 -919
  573. package/docs/html/lifecycle_blueprint.html +0 -723
  574. package/docs/html/memory_blueprint.html +0 -699
  575. package/docs/html/middleware_blueprint.html +0 -664
  576. package/docs/html/models_blueprint.html +0 -2366
  577. package/docs/html/observability_blueprint.html +0 -683
  578. package/docs/html/provider_adapter_blueprint.html +0 -245
  579. package/docs/html/safety_blueprint.html +0 -1386
  580. package/docs/html/shared.css +0 -571
  581. package/docs/html/shared.js +0 -143
  582. package/docs/html/skills_blueprint.html +0 -671
  583. package/docs/html/soak_blueprint.html +0 -182
  584. package/docs/html/tool_usage_blueprint.html +0 -350
  585. package/docs/html/tools_blueprint.html +0 -2249
  586. package/docs/html/trace_blueprint.html +0 -235
  587. package/docs/html/tui_design_blueprint.html +0 -374
  588. package/docs/html/validation_blueprint.html +0 -961
  589. package/docs/html/worker_dispatch_blueprint.html +0 -231
  590. package/src/core/release.ts +0 -2
  591. package/src/domains/providers/runtimes/common/lmstudio-logger.ts +0 -32
  592. package/src/domains/providers/runtimes/local-native/lmstudio-native.ts +0 -491
  593. package/src/engine/apis/lmstudio-native.ts +0 -1438
  594. package/src/engine/apis/thinking-replay.ts +0 -11
  595. package/src/tools/string-enum.ts +0 -15
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Adapt Clio's shared TUI transcript projection to semantic HTML tool rows.
3
+ * pi-coding-agent 0.84.0 uses the same TUI-render-then-ANSI-convert pattern in
4
+ * `dist/core/export-html/tool-renderer.js`; Clio keeps its own transcript model
5
+ * and tool renderers, so the adaptation operates on their rendered lines.
6
+ */
7
+ import { stripTerminalSequences } from "../../engine/tui.js";
8
+ import { ansiLinesToHtml, escapeHtml } from "./ansi-to-html.js";
9
+
10
+ interface TranscriptBlock {
11
+ kind: "tool" | "transcript";
12
+ toolName?: string;
13
+ lines: string[];
14
+ }
15
+
16
+ function toolNameFromHeader(line: string): string | null {
17
+ const plain = stripTerminalSequences(line);
18
+ return /^\s*▸\s+([^\s(]+)/u.exec(plain)?.[1] ?? null;
19
+ }
20
+
21
+ function isToolBodyLine(line: string): boolean {
22
+ return /^\s*[│╰]/u.test(stripTerminalSequences(line));
23
+ }
24
+
25
+ function blocksFromLines(lines: ReadonlyArray<string>): TranscriptBlock[] {
26
+ const blocks: TranscriptBlock[] = [];
27
+ for (const line of lines) {
28
+ const name = toolNameFromHeader(line);
29
+ if (name !== null) {
30
+ blocks.push({ kind: "tool", toolName: name, lines: [line] });
31
+ continue;
32
+ }
33
+ const previous = blocks[blocks.length - 1];
34
+ if (previous?.kind === "tool" && isToolBodyLine(line)) {
35
+ previous.lines.push(line);
36
+ continue;
37
+ }
38
+ if (previous?.kind === "transcript") previous.lines.push(line);
39
+ else blocks.push({ kind: "transcript", lines: [line] });
40
+ }
41
+ return blocks;
42
+ }
43
+
44
+ export function renderTranscriptHtml(lines: ReadonlyArray<string>): string {
45
+ return blocksFromLines(lines)
46
+ .map((block) => {
47
+ const body = ansiLinesToHtml(block.lines);
48
+ if (block.kind === "tool") {
49
+ return `<section class="tool-row" data-tool="${escapeHtml(block.toolName ?? "unknown")}">${body}</section>`;
50
+ }
51
+ return `<div class="transcript-row">${body}</div>`;
52
+ })
53
+ .join("\n");
54
+ }
@@ -112,6 +112,8 @@ export interface FooterDashboardDeps {
112
112
  getNotifications?: () => ReadonlyArray<Notification>;
113
113
  /** Whether the Ctrl+G leader is armed and waiting for its next key. */
114
114
  getLeaderArmed?: () => boolean;
115
+ /** Whether a Ctrl+C armed the double tap and its window is still open. */
116
+ getShutdownArmed?: () => boolean;
115
117
  dismissKeyLabel?: string;
116
118
  now?: () => number;
117
119
  resolveCurrentBranch?: (cwd: string) => Promise<string | null>;
@@ -172,6 +174,7 @@ function renderFooterCompactLines(state: FooterDashboardRenderState, width: numb
172
174
  state.sessionCost,
173
175
  state.session.outputVerbosity,
174
176
  state.session.leaderArmed ?? false,
177
+ state.session.shutdownArmed ?? false,
175
178
  ),
176
179
  ].map((line) => fitDashboardLine(line, safeWidth));
177
180
  }
@@ -435,6 +438,7 @@ export function buildFooterDashboard(deps: FooterDashboardDeps): FooterDashboard
435
438
  toolProfile,
436
439
  outputVerbosity: settings?.terminal.outputVerbosity ?? "default",
437
440
  leaderArmed: deps.getLeaderArmed?.() ?? false,
441
+ shutdownArmed: deps.getShutdownArmed?.() ?? false,
438
442
  memoryIntervention: taskMemory
439
443
  ? {
440
444
  enabled: taskMemory.enabled,
@@ -266,7 +266,7 @@ export function formatNotificationPanel(
266
266
  const lines: string[] = [rule(theme, width, { left: "notices" })];
267
267
  for (const entry of entries.slice(0, maxRows)) {
268
268
  const glyph = theme.fg(notificationToken(entry.level), notificationGlyph(entry.level));
269
- lines.push(fitFooterText(`${glyph} ${theme.fg("muted", entry.text)}`, width));
269
+ lines.push(fitFooterText(`${glyph} ${theme.fg("muted", entry.text)}`, width, GLYPH.ellipsis));
270
270
  }
271
271
  const overflow = entries.length - maxRows;
272
272
  const hint = overflow > 0 ? `+${overflow} more · ${dismiss} dismiss` : `${dismiss} dismiss`;
@@ -72,6 +72,13 @@ export interface SessionFacts {
72
72
  * it against.
73
73
  */
74
74
  leaderArmed?: boolean;
75
+ /**
76
+ * A Ctrl+C landed on an idle empty prompt and the 500ms window that quits is
77
+ * open. Shown for the same reason as the leader above: the arming press left
78
+ * the frame identical to the idle frame, so the operator had no way to learn
79
+ * that a second press quits, and no way to tell the first press registered.
80
+ */
81
+ shutdownArmed?: boolean;
75
82
  /** Proactive-memory status; kept as one atomic fact row in the expanded dashboard. */
76
83
  memoryIntervention?: {
77
84
  enabled: boolean;
@@ -373,6 +380,7 @@ export function compactSecondaryLine(
373
380
  sessionCost: CostAggregate | null = null,
374
381
  outputVerbosity?: OutputVerbosity | null,
375
382
  leaderArmed = false,
383
+ shutdownArmed = false,
376
384
  ): string {
377
385
  const safeWidth = Math.max(1, Math.floor(width));
378
386
  const barCells = compactContextBarWidth(safeWidth);
@@ -402,6 +410,7 @@ export function compactSecondaryLine(
402
410
  compactMetricChipLimit(safeWidth),
403
411
  outputVerbosity,
404
412
  leaderArmed,
413
+ shutdownArmed,
405
414
  );
406
415
  // At the smallest widths the context meter consumes the entire secondary
407
416
  // row, so keep a compact mode marker on the left instead of silently hiding
@@ -1106,6 +1115,7 @@ export function buildHarnessStatePill(
1106
1115
  * detail used to spend all of it, so a session holding 9.7k measured tokens
1107
1116
  * showed none of them.
1108
1117
  */
1118
+ const CHIP_RANK_SHUTDOWN = -2;
1109
1119
  const CHIP_RANK_LEADER = -1;
1110
1120
  const CHIP_RANK_TOTALS = 0;
1111
1121
  const CHIP_RANK_DETAIL = 1;
@@ -1155,12 +1165,13 @@ export function buildMetricStrip(
1155
1165
  maxChipsCount = 6,
1156
1166
  outputVerbosity?: OutputVerbosity | null,
1157
1167
  leaderArmed = false,
1168
+ shutdownArmed = false,
1158
1169
  ): string {
1159
1170
  const safeMaxWidth = Math.max(0, Math.floor(maxWidth));
1160
1171
  if (safeMaxWidth <= 0) return "";
1161
1172
  const isStreaming = status.phase !== "idle" && status.phase !== "ended";
1162
1173
  const meaningfulVerbosity = outputVerbosity && outputVerbosity !== "default" ? outputVerbosity : null;
1163
- if (!isStreaming && !lastTurn && !meaningfulVerbosity && !leaderArmed) return "";
1174
+ if (!isStreaming && !lastTurn && !meaningfulVerbosity && !leaderArmed && !shutdownArmed) return "";
1164
1175
 
1165
1176
  const candidates: Array<string | null> = [];
1166
1177
  /** Per-turn detail that ranks below the session totals when the strip is cut. */
@@ -1236,7 +1247,14 @@ export function buildMetricStrip(
1236
1247
  const chipLimit = Math.max(0, Math.floor(maxChipsCount));
1237
1248
  const chips: RankedChip[] = [];
1238
1249
  // Ranked above every measurement: the strip is cut by dropping the
1239
- // lowest-ranked chip, and this one is the answer to "did that key register".
1250
+ // lowest-ranked chip, and these two are the answer to "did that key
1251
+ // register". The quit hint outranks the leader because its window is
1252
+ // 500ms wide and the leader's is open until the next keystroke.
1253
+ // Two rungs rather than one: the strip drops a chip it cannot fit whole, and
1254
+ // a terminal narrow enough to lose the sentence is exactly the one where the
1255
+ // operator most needs to be told the press registered.
1256
+ const shutdownHint = safeMaxWidth >= 20 ? "Ctrl+C again to quit" : "Ctrl+C again";
1257
+ pushChip(chips, shutdownArmed ? theme.fg("warning", shutdownHint) : null, CHIP_RANK_SHUTDOWN);
1240
1258
  pushChip(chips, leaderArmed ? theme.fg("accent", "leader armed") : null, CHIP_RANK_LEADER);
1241
1259
  for (const chip of candidates) pushChip(chips, chip, CHIP_RANK_DETAIL);
1242
1260
  pushChip(chips, totalChip, CHIP_RANK_TOTALS);
@@ -95,9 +95,9 @@ export interface FooterPanel {
95
95
  refresh(): void;
96
96
  }
97
97
 
98
- export function fitFooterText(text: string, width: number): string {
98
+ export function fitFooterText(text: string, width: number, ellipsis = ""): string {
99
99
  const safeWidth = Math.max(1, Math.floor(width));
100
- return visibleWidth(text) > safeWidth ? truncateToWidth(text, safeWidth, "", true) : text;
100
+ return visibleWidth(text) > safeWidth ? truncateToWidth(text, safeWidth, ellipsis, true) : text;
101
101
  }
102
102
 
103
103
  const CONTEXT_PERCENT_FIELD_WIDTH = 6;
@@ -35,8 +35,20 @@ let dateFormatter = new Intl.DateTimeFormat("en-CA", DATE_OPTIONS);
35
35
  function syncZone(): void {
36
36
  if (process.env.TZ === builtForZone) return;
37
37
  builtForZone = process.env.TZ;
38
- clockFormatter = new Intl.DateTimeFormat("en-GB", CLOCK_OPTIONS);
39
- dateFormatter = new Intl.DateTimeFormat("en-CA", DATE_OPTIONS);
38
+ // The zone is passed explicitly, not left for Intl to pick up from
39
+ // process.env.TZ implicitly, because it doesn't reliably do so: under a
40
+ // shared test process that constructs many formatters across many zones,
41
+ // a rebuilt formatter was observed to resolve to America/Chicago while
42
+ // process.env.TZ read Asia/Kolkata at the exact moment of construction
43
+ // and of the .format() call right after (issue #84, tests/contracts
44
+ // instrumentation traced it to Intl's own zone resolution, not a stale
45
+ // env var). An explicit timeZone option bypasses whatever cached default
46
+ // resolution goes stale there, so this is correct regardless of whether
47
+ // that turns out to be a V8/ICU bug that ever gets fixed. Do not "simplify"
48
+ // this back to relying on process.env.TZ implicitly.
49
+ const zone = builtForZone === undefined ? undefined : { timeZone: builtForZone };
50
+ clockFormatter = new Intl.DateTimeFormat("en-GB", { ...CLOCK_OPTIONS, ...zone });
51
+ dateFormatter = new Intl.DateTimeFormat("en-CA", { ...DATE_OPTIONS, ...zone });
40
52
  }
41
53
 
42
54
  function toEpochMs(instant: Instant): number | null {
@@ -14,14 +14,16 @@ import type { ObservabilityContract } from "../domains/observability/index.js";
14
14
  import type { ProvidersContract, ThinkingLevel } from "../domains/providers/index.js";
15
15
  import type { ResourcesContract } from "../domains/resources/index.js";
16
16
  import type { FleetNodeSnapshot } from "../domains/scheduling/cluster.js";
17
+ import type { DecisionLedgerEntry } from "../domains/session/entries.js";
17
18
  import type { SessionContract, SessionEntry, TaskBoardSnapshot } from "../domains/session/index.js";
18
19
  import type { ShareContract } from "../domains/share/index.js";
20
+ import type { UserTasksStore } from "../domains/user-tasks/store.js";
19
21
  import { createAgentProgress } from "../engine/tui.js";
20
22
  import type { ImageContent } from "../engine/types.js";
21
23
  import type { AskUserHandler } from "../tools/ask-user.js";
22
24
  import type { ToolRegistry } from "../tools/registry.js";
23
25
  import { APPLICATION_DOUBLE_TAP_MS, type ApplicationController } from "./application-controller.js";
24
- import type { ChatLoop } from "./chat-loop.js";
26
+ import type { ChatLoop, ChatLoopEvent } from "./chat-loop.js";
25
27
  import { emitCommandNotice } from "./command-fallbacks.js";
26
28
  import { appendNotice } from "./command-output.js";
27
29
  import { createDispatchSteering } from "./dispatch-steering.js";
@@ -29,12 +31,13 @@ import { createEditorSubmitController } from "./editor-submit.js";
29
31
  import { createInteractiveEventProjection } from "./interactive-event-projection.js";
30
32
  import { createInteractiveInputRuntime } from "./interactive-input-runtime.js";
31
33
  import { createInteractivePresentation } from "./interactive-presentation.js";
32
- import { createProcessInteractiveShell } from "./interactive-shell.js";
34
+ import { createProcessInteractiveShell, getActiveRenderTrace } from "./interactive-shell.js";
33
35
  import { createInteractiveSlashRuntime, resolveAvailableThinkingLevels } from "./interactive-slash-runtime.js";
34
36
  import { createInteractiveSubscriptions } from "./interactive-subscriptions.js";
35
37
  import { createInteractiveTickers } from "./interactive-tickers.js";
36
38
  import { createOverlayLifecycle, type OverlayLifecycleController, type OverlayState } from "./overlay-lifecycle.js";
37
39
  import { interopOverlaySurface } from "./overlays/interop.js";
40
+ import { settleChatBeforeSessionSwitch } from "./session-switch-settlement.js";
38
41
  import { createSessionTranscript } from "./session-transcript.js";
39
42
  import type {
40
43
  ContextClearCommandOptions,
@@ -42,6 +45,8 @@ import type {
42
45
  RunIo,
43
46
  TaskMemorySeedCommandResult,
44
47
  } from "./slash-commands.js";
48
+ import { processAutoPacingAllowed, resolveSmoothStreamingMode } from "./stream-pacing-policy.js";
49
+ import type { TerminalLease } from "./terminal-lease.js";
45
50
  import { createWorkspaceFacts } from "./workspace-facts.js";
46
51
 
47
52
  export {
@@ -105,6 +110,12 @@ export interface InteractiveDeps {
105
110
  agents?: AgentsContract;
106
111
  observability: ObservabilityContract;
107
112
  chat: ChatLoop;
113
+ /** Fired once after the first real TUI render transaction issued all of its terminal writes. */
114
+ onFirstFrameCommit?: (frameId: number) => void;
115
+ /** Existing Stage 0 owner to hydrate in place. */
116
+ terminalLease?: TerminalLease;
117
+ /** Fired after the first committed frame containing the hydrated Stage 1 root. */
118
+ onHydratedFrameCommit?: (frameId: number | null) => void;
108
119
  /** Startup notices collected before the TUI is ready; rendered in the transcript. */
109
120
  initialNotices?: ReadonlyArray<string>;
110
121
  resources?: ResourcesContract;
@@ -124,6 +135,12 @@ export interface InteractiveDeps {
124
135
  readSessionEntries?: () => ReadonlyArray<SessionEntry>;
125
136
  /** Live session task board for the footer tasks row and the /tasks overlay. */
126
137
  getTaskBoard?: () => TaskBoardSnapshot | null;
138
+ /** Settled interview snapshots folded from the active session branch. */
139
+ getDecisionBoard?: () => ReadonlyArray<DecisionLedgerEntry>;
140
+ /** Append an acknowledged operator-authored decision revision. */
141
+ supersedeDecision?: (interviewId: string, key: string, correction?: string) => unknown;
142
+ /** Project-scoped operator task inbox used by `/tasks` subcommands. */
143
+ userTasks?: UserTasksStore;
127
144
  /** Live, read-only task-memory state for status surfaces and the /memory overlay. */
128
145
  getTaskMemoryStatus?: () => TaskMemoryOperatorStatus;
129
146
  /** Newest structured handoff available for an opt-in seed, when enabled. */
@@ -174,7 +191,7 @@ export interface InteractiveDeps {
174
191
  */
175
192
  onForkSession?: (parentTurnId: string) => void;
176
193
  /**
177
- * Run /compact for the current session. Resolves the compaction model
194
+ * Run `/context compact` for the current session. Resolves the compaction model
178
195
  * (settings.compaction.model with fallback to the orchestrator target),
179
196
  * reads session entries, streams a summary via the session compaction
180
197
  * engine, and persists a compactionSummary entry.
@@ -256,6 +273,8 @@ export interface KeyBindingDeps {
256
273
  requestShutdown: () => void;
257
274
  toggleStatus: () => void;
258
275
  toggleDispatchBoard: () => void;
276
+ openTasks: () => void;
277
+ openDecisions: () => void;
259
278
  backgroundDispatch: () => void;
260
279
  openModelSelector: () => void;
261
280
  openTree: () => void;
@@ -269,6 +288,7 @@ export interface KeyBindingDeps {
269
288
  toggleAllThinkingExpansion: () => void;
270
289
  openExternalEditor: () => void;
271
290
  queueFollowUp: () => void;
291
+ interruptWithMessage: () => void;
272
292
  restoreQueuedFollowUps: () => void;
273
293
  }
274
294
 
@@ -314,6 +334,9 @@ export function dispatchInteractiveAction(id: ClioKeybinding, deps: KeyBindingDe
314
334
  case "clio.message.followUp":
315
335
  deps.queueFollowUp();
316
336
  return true;
337
+ case "clio.message.interrupt":
338
+ deps.interruptWithMessage();
339
+ return true;
317
340
  case "clio.message.dequeue":
318
341
  deps.restoreQueuedFollowUps();
319
342
  return true;
@@ -335,6 +358,12 @@ export function dispatchInteractiveAction(id: ClioKeybinding, deps: KeyBindingDe
335
358
  case "clio.dispatchBoard.toggle":
336
359
  deps.toggleDispatchBoard();
337
360
  return true;
361
+ case "clio.tasks.open":
362
+ deps.openTasks();
363
+ return true;
364
+ case "clio.decisions.open":
365
+ deps.openDecisions();
366
+ return true;
338
367
  case "clio.dispatch.background":
339
368
  deps.backgroundDispatch();
340
369
  return true;
@@ -363,6 +392,8 @@ export function routeInteractiveKey(data: string, deps: KeyBindingDeps): boolean
363
392
  "clio.thinking.cycle",
364
393
  "clio.session.tree",
365
394
  "clio.dispatchBoard.toggle",
395
+ "clio.tasks.open",
396
+ "clio.decisions.open",
366
397
  "clio.dispatch.background",
367
398
  "clio.model.select",
368
399
  // Match cycleBackward before cycleForward so a user rebind where one key
@@ -379,8 +410,48 @@ export function routeInteractiveKey(data: string, deps: KeyBindingDeps): boolean
379
410
  }
380
411
 
381
412
  export async function createInteractiveApplication(deps: InteractiveDeps): Promise<number> {
382
- const shell = createProcessInteractiveShell();
413
+ const initialSmoothStreaming = resolveSmoothStreamingMode(deps.getSettings?.().terminal.smoothStreaming ?? "off");
414
+ const initialAutoPacingAllowed = processAutoPacingAllowed(false);
415
+ const lease = deps.terminalLease;
416
+ const shell =
417
+ lease?.shell ??
418
+ createProcessInteractiveShell({
419
+ tuiMode: deps.getSettings?.().terminal.tuiMode ?? "regular",
420
+ streamPacingActive:
421
+ initialSmoothStreaming === "on" || (initialSmoothStreaming === "auto" && initialAutoPacingAllowed),
422
+ ...(deps.onFirstFrameCommit ? { onFirstFrameCommit: deps.onFirstFrameCommit } : {}),
423
+ });
383
424
  const { terminal, tui } = shell;
425
+ const renderTrace = getActiveRenderTrace();
426
+ const visibleEventIngress = new WeakMap<
427
+ object,
428
+ { sequence: number; traceSequence: number; generation: number; ingressAt: number }
429
+ >();
430
+ let visibleEventSequence = 0;
431
+ let visibleEventGeneration = 0;
432
+ const recordChatEventIngress = (event: ChatLoopEvent): void => {
433
+ if (event.type === "agent_start") {
434
+ visibleEventGeneration += 1;
435
+ renderTrace?.beginGeneration();
436
+ return;
437
+ }
438
+ if (event.type !== "text_delta" && event.type !== "thinking_delta") return;
439
+ visibleEventSequence += 1;
440
+ const ingress = {
441
+ sequence: visibleEventSequence,
442
+ traceSequence: visibleEventSequence,
443
+ generation: visibleEventGeneration,
444
+ ingressAt: performance.now(),
445
+ };
446
+ visibleEventIngress.set(event, ingress);
447
+ if (renderTrace) {
448
+ ingress.traceSequence = renderTrace.recordVisibleEvent({
449
+ kind: event.type === "text_delta" ? "text" : "thinking",
450
+ contentIndex: event.contentIndex,
451
+ delta: event.delta,
452
+ });
453
+ }
454
+ };
384
455
  let applicationController: ApplicationController;
385
456
  const workspaceFacts = createWorkspaceFacts({
386
457
  cwd: process.cwd(),
@@ -406,9 +477,20 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
406
477
  * the footer reads it and the input runtime that flips it is built later.
407
478
  */
408
479
  let leaderArmed = false;
480
+ /**
481
+ * A Ctrl+C armed the double tap and its 500ms window is still open. Owned
482
+ * here for the same reason as the leader flag above.
483
+ */
484
+ let shutdownArmed = false;
409
485
  const presentation = createInteractivePresentation({
410
486
  bus: deps.bus,
411
487
  getLeaderArmed: () => leaderArmed,
488
+ getShutdownArmed: () => shutdownArmed,
489
+ resolveVisibleEventSequence: (event) => visibleEventIngress.get(event)?.traceSequence ?? null,
490
+ resolveStreamIngress: (event) => visibleEventIngress.get(event) ?? null,
491
+ commitFrame: (reason) => shell.commitCurrentFrame(reason === "teardown" ? 300 : 30_000),
492
+ hasObservedBackpressure: () => shell.hasObservedBackpressure(),
493
+ onSmoothStreamingMode: (_mode, pacingActive) => shell.setStreamPacingActive(pacingActive),
412
494
  providers: deps.providers,
413
495
  dispatch: deps.dispatch,
414
496
  observability: deps.observability,
@@ -417,7 +499,14 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
417
499
  sessionTranscript,
418
500
  tui,
419
501
  terminal,
420
- mount: (root, editor) => shell.mount(root, editor),
502
+ ...(!lease ? { mount: (root, editor) => shell.mount(root, editor) } : {}),
503
+ ...(lease
504
+ ? {
505
+ editor: lease.editor,
506
+ keybindings: lease.keybindings,
507
+ bootPending: lease.pending,
508
+ }
509
+ : {}),
421
510
  ...(deps.getSettings ? { getSettings: deps.getSettings } : {}),
422
511
  ...(deps.resources ? { resources: deps.resources } : {}),
423
512
  ...(deps.session ? { session: deps.session } : {}),
@@ -448,8 +537,8 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
448
537
  const agentProgress = createAgentProgress(terminal);
449
538
  const busNoticeSink = {
450
539
  appendReplayBlock: (renderBlock: Parameters<typeof chatPanel.appendReplayBlock>[0]) =>
451
- chatPanel.appendReplayBlock(renderBlock),
452
- requestRender: () => tui.requestRender(),
540
+ chatRenderer.mutate(() => chatPanel.appendReplayBlock(renderBlock), "bus-notice"),
541
+ requestRender: () => {},
453
542
  };
454
543
  const eventProjection = createInteractiveEventProjection({
455
544
  bus: deps.bus,
@@ -458,6 +547,10 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
458
547
  ...(deps.initialNotices ? { initialNotices: deps.initialNotices } : {}),
459
548
  ...(deps.getSettings ? { getSettings: deps.getSettings } : {}),
460
549
  getTerminalColumns: () => terminal.columns,
550
+ onChatEventIngress: (event) => {
551
+ recordChatEventIngress(event);
552
+ presentation.recordChatEvent(event);
553
+ },
461
554
  applyChatEvent: (event) => chatRenderer.applyEvent(event),
462
555
  setFollowUpMessages: (messages) => followUpQueuePanel.setMessages(messages),
463
556
  isAskUserWaiting: () => overlayLifecycle.isAskUserWaiting(),
@@ -477,6 +570,12 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
477
570
  dismissNotification: (key) => notifications.dismiss(key),
478
571
  appendTranscriptNotice: (level, text) => appendNotice(level, text, busNoticeSink),
479
572
  refreshSettingsOverlay: () => overlayLifecycle.refreshSettingsOverlay(),
573
+ onConfigHotReload: (settings) => {
574
+ const mode = resolveSmoothStreamingMode(settings.terminal.smoothStreaming);
575
+ const autoAllowed = processAutoPacingAllowed(shell.hasObservedBackpressure());
576
+ chatRenderer.setSmoothStreamingMode(mode);
577
+ shell.setStreamPacingActive(mode === "on" || (mode === "auto" && autoAllowed));
578
+ },
480
579
  });
481
580
  // The overlay reads the report this process already produced at boot; it
482
581
  // never probes on a keystroke.
@@ -486,14 +585,21 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
486
585
  io,
487
586
  bus: deps.bus,
488
587
  dispatch: deps.dispatch,
588
+ ...(deps.session ? { session: deps.session } : {}),
489
589
  providers: deps.providers,
490
590
  chat: deps.chat,
491
- chatPanel,
591
+ chatPanel: {
592
+ appendReplayBlock: (...args) => chatRenderer.mutate(() => chatPanel.appendReplayBlock(...args), "slash-output"),
593
+ appendUser: (text) => chatRenderer.mutate(() => chatPanel.appendUser(text), "user-submit"),
594
+ },
595
+ beforeSemanticSubmit: () => chatRenderer.flush(),
596
+ settleVisibleFrame: (reason) => chatRenderer.flushAndCommit(reason),
492
597
  ...(deps.resources ? { resources: deps.resources } : {}),
493
598
  ...(deps.extensions ? { extensions: deps.extensions } : {}),
494
599
  ...(interopSurface ? { interop: interopSurface } : {}),
495
600
  ...(deps.agents ? { agents: deps.agents } : {}),
496
601
  ...(deps.share ? { share: deps.share } : {}),
602
+ ...(deps.userTasks ? { userTasks: deps.userTasks } : {}),
497
603
  ...(deps.getSettings ? { getSettings: deps.getSettings } : {}),
498
604
  ...(deps.writeSettings ? { writeSettings: deps.writeSettings } : {}),
499
605
  ...(deps.commitSetting ? { commitSetting: deps.commitSetting } : {}),
@@ -516,6 +622,7 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
516
622
  openCost: () => openCostOverlayState(),
517
623
  openContextView: () => openContextViewOverlayState(),
518
624
  openTasks: () => openTasksOverlayState(),
625
+ openDecisions: () => openDecisionsOverlayState(),
519
626
  openMemory: () => openMemoryOverlayState(),
520
627
  ...(deps.seedTaskMemory ? { seedTaskMemory: deps.seedTaskMemory } : {}),
521
628
  openView: (filter) => openViewOverlayState(filter),
@@ -545,8 +652,14 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
545
652
  dispatch: deps.dispatch,
546
653
  ...(deps.session ? { session: deps.session } : {}),
547
654
  sessionTranscript,
548
- chatPanel,
655
+ chatPanel: {
656
+ appendReplayBlock: (...args) =>
657
+ chatRenderer.mutate(() => chatPanel.appendReplayBlock(...args), "editor-command-output"),
658
+ },
659
+ beforeSemanticBoundary: () => chatRenderer.flush(),
660
+ settleVisibleFrame: (reason) => chatRenderer.flushAndCommit(reason),
549
661
  dispatchCommand: slashRuntime.dispatchCommand,
662
+ dispatchCommandAsync: slashRuntime.admitCommand,
550
663
  collapseLaunchpadBeforeSubmit: () => presentation.collapseWelcomeDashboard(),
551
664
  expandSubmit: (text) => expandInteractiveSubmitAsync(text, deps.resources),
552
665
  notify,
@@ -560,6 +673,7 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
560
673
  contextActivityStore,
561
674
  getOverlayState: () => overlayLifecycle?.getState() ?? "closed",
562
675
  isFooterExpanded: () => footer.isExpanded(),
676
+ ...(deps.getTaskBoard ? { getTaskBoard: deps.getTaskBoard } : {}),
563
677
  });
564
678
  /**
565
679
  * The one transcript reset. The chat panel and the worker fold are two views
@@ -569,8 +683,10 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
569
683
  * because the subscriptions that own the fold are built below.
570
684
  */
571
685
  const resetTranscript = (): void => {
572
- chatPanel.reset();
573
- interactiveSubscriptions.workers.reset();
686
+ chatRenderer.reset(() => {
687
+ chatPanel.reset();
688
+ interactiveSubscriptions.workers.reset();
689
+ });
574
690
  };
575
691
  overlayLifecycle = createOverlayLifecycle({
576
692
  app: deps,
@@ -599,6 +715,7 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
599
715
  openContextViewOverlayState,
600
716
  openContextResetOverlayState,
601
717
  openTasksOverlayState,
718
+ openDecisionsOverlayState,
602
719
  openMemoryOverlayState,
603
720
  openViewOverlayState,
604
721
  openModelOverlayState,
@@ -633,17 +750,20 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
633
750
  const current = editor.getText();
634
751
  editor.setText([restored.join("\n\n"), current].filter((part) => part.trim().length > 0).join("\n\n"));
635
752
  }
753
+ chatRenderer.flush();
636
754
  deps.chat.cancel();
637
755
  deps.toolRegistry?.cancelParkedCalls("run cancelled by operator");
638
756
  footer.refresh();
639
757
  tui.requestRender();
640
758
  };
641
759
 
642
- const startNewSession = (): void => {
760
+ const startNewSession = async (): Promise<void> => {
643
761
  if (!deps.onNewSession) {
644
762
  emitCommandNotice(slashRuntime.notice, "error", "new", "session contract unavailable");
645
763
  return;
646
764
  }
765
+ const settlement = settleChatBeforeSessionSwitch(deps.chat);
766
+ if (settlement) await settlement;
647
767
  deps.onNewSession();
648
768
  deps.observability.resetSession();
649
769
  presentation.resetForNewSession();
@@ -686,7 +806,7 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
686
806
  // The reducer mutates one state object per assignment, so the panel is
687
807
  // handed that object rather than a copy: a streamed delta reaches the
688
808
  // screen by invalidating a cached render, not by rebuilding the entry.
689
- applyWorkerState: (state) => chatPanel.applyWorkerState(state),
809
+ applyWorkerState: (state) => chatRenderer.mutate(() => chatPanel.applyWorkerState(state), "worker-state"),
690
810
  recordWorkerRun: (fields) => {
691
811
  // A `/run` is an operator action that produced durable state, so it
692
812
  // opens a session the same way a local `!bash` line does. Persistence
@@ -722,6 +842,9 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
722
842
  onLeaderStateChange: (pending) => {
723
843
  leaderArmed = pending;
724
844
  },
845
+ onShutdownArmedChange: (armed) => {
846
+ shutdownArmed = armed;
847
+ },
725
848
  dispatchBoard,
726
849
  steerSelectedDispatch,
727
850
  cancelSelectedDispatch,
@@ -732,7 +855,25 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
732
855
  editorSubmit,
733
856
  requestRender: () => tui.requestRender(),
734
857
  notifications,
735
- chatPanel,
858
+ chatPanel: {
859
+ toggleLastToolExpanded: () => chatPanel.toggleLastToolExpanded(),
860
+ toggleAllToolsExpanded: () => chatPanel.toggleAllToolsExpanded(),
861
+ toggleLiveToolOutput: () => chatPanel.toggleLiveToolOutput(),
862
+ toggleLastThinking: () => {
863
+ let changed = false;
864
+ chatRenderer.mutate(() => {
865
+ changed = chatPanel.toggleLastThinking();
866
+ }, "thinking-visibility");
867
+ return changed;
868
+ },
869
+ toggleAllThinking: () => {
870
+ let changed = false;
871
+ chatRenderer.mutate(() => {
872
+ changed = chatPanel.toggleAllThinking();
873
+ }, "thinking-visibility");
874
+ return changed;
875
+ },
876
+ },
736
877
  shutdown: {
737
878
  stopTickers: presentation.stopTickers,
738
879
  disposeInteractiveTickers: interactiveTickers.dispose,
@@ -745,11 +886,54 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
745
886
  disposeChat: () => deps.chat.dispose(),
746
887
  disposeSubscriptions: interactiveSubscriptions.dispose,
747
888
  },
748
- stopUi: () => shell.stop(),
889
+ beforeStopUi: (() => {
890
+ let settlement: Promise<void> | null = null;
891
+ return () => {
892
+ settlement ??= chatRenderer.flushAndCommit("teardown").finally(() => chatRenderer.dispose());
893
+ return settlement;
894
+ };
895
+ })(),
896
+ stopUi: () => {
897
+ if (lease) void lease.close();
898
+ else shell.stop();
899
+ },
749
900
  cancelParkedCalls: (reason) => deps.toolRegistry?.cancelParkedCalls(reason),
750
- onShutdown: deps.onShutdown,
751
- registerInputListener: (listener) => tui.addInputListener(listener),
901
+ onShutdown: async () => {
902
+ try {
903
+ await deps.onShutdown();
904
+ } finally {
905
+ if (lease) await lease.close();
906
+ else await shell.settle();
907
+ }
908
+ },
909
+ registerInputListener: (listener) => {
910
+ if (lease) lease.registerApplicationInput(listener);
911
+ else tui.addInputListener(listener);
912
+ },
913
+ ...(lease
914
+ ? {
915
+ signals: lease.applicationSignals,
916
+ // The lease registered its exactly-once drain before hydration.
917
+ registerTerminalTeardown: () => {},
918
+ }
919
+ : {}),
920
+ ...(renderTrace
921
+ ? {
922
+ onInputIngress: (action, data) =>
923
+ renderTrace.recordInputIngress(action, Buffer.byteLength(data, "utf8"), action !== "no-visual-change"),
924
+ }
925
+ : {}),
752
926
  });
753
927
 
928
+ if (lease) {
929
+ const adopted = lease.adopt({
930
+ root: presentation.root,
931
+ editorChrome: presentation.editorChrome,
932
+ admitSubmission: (submission) => editorSubmit.admitCapturedText(submission.rawText, lease.abortSignal),
933
+ ...(deps.onHydratedFrameCommit ? { onHydratedFrame: deps.onHydratedFrameCommit } : {}),
934
+ });
935
+ if (!adopted) void applicationController.shutdown();
936
+ }
937
+
754
938
  return applicationController.run;
755
939
  }
@@ -57,6 +57,8 @@ export interface InteractiveEventProjectionDeps {
57
57
  getSettings?: () => Readonly<ClioSettings>;
58
58
  getTerminalColumns: () => number;
59
59
  now?: () => number;
60
+ /** Canonical synchronous ingress hook, before any projection branch consumes the event. */
61
+ onChatEventIngress?: (event: ChatLoopEvent) => void;
60
62
  applyChatEvent: (event: ChatLoopEvent) => void;
61
63
  setFollowUpMessages: (messages: QueuedChatMessage[]) => void;
62
64
  isAskUserWaiting: () => boolean;
@@ -75,6 +77,7 @@ export interface InteractiveEventProjectionDeps {
75
77
  dismissNotification: (key: string) => void;
76
78
  appendTranscriptNotice: (level: InteractiveTranscriptNoticeLevel, text: string) => void;
77
79
  refreshSettingsOverlay: () => void;
80
+ onConfigHotReload?: (settings: Readonly<ClioSettings>) => void;
78
81
  }
79
82
 
80
83
  export interface InteractiveEventProjection {
@@ -123,6 +126,7 @@ export function createInteractiveEventProjection(deps: InteractiveEventProjectio
123
126
  const remainingUnsubscribers: Array<() => void> = [];
124
127
  primaryUnsubscribers.push(
125
128
  deps.chat.onEvent((event) => {
129
+ deps.onChatEventIngress?.(event);
126
130
  if (event.type === "notice") {
127
131
  if (event.surface === "transcript") {
128
132
  deps.applyChatEvent(event);
@@ -310,7 +314,8 @@ export function createInteractiveEventProjection(deps: InteractiveEventProjectio
310
314
  deps.refreshFooter();
311
315
  deps.requestRender();
312
316
  }),
313
- deps.bus.on(BusChannels.ConfigHotReload, () => {
317
+ deps.bus.on(BusChannels.ConfigHotReload, (payload) => {
318
+ deps.onConfigHotReload?.(payload.settings);
314
319
  deps.refreshSettingsOverlay();
315
320
  }),
316
321
  deps.bus.on(BusChannels.ConfigReloadFailed, (payload) => {