@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
@@ -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(),
@@ -467,6 +560,7 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
467
560
  recordToolEnd: (_toolName, toolCallId, isError, truncated) =>
468
561
  presentation.recordToolEnd({ toolCallId, isError, truncated }),
469
562
  setStatusLine: (line) => chatPanel.setStatusLine(line),
563
+ setLiveReasoning: (view) => chatPanel.setLiveReasoning(view),
470
564
  setLastTurnSummary: (summary) => presentation.setLastTurnSummary(summary),
471
565
  startTerminalProgress: () => agentProgress.start(),
472
566
  stopTerminalProgress: () => agentProgress.stop(),
@@ -477,6 +571,12 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
477
571
  dismissNotification: (key) => notifications.dismiss(key),
478
572
  appendTranscriptNotice: (level, text) => appendNotice(level, text, busNoticeSink),
479
573
  refreshSettingsOverlay: () => overlayLifecycle.refreshSettingsOverlay(),
574
+ onConfigHotReload: (settings) => {
575
+ const mode = resolveSmoothStreamingMode(settings.terminal.smoothStreaming);
576
+ const autoAllowed = processAutoPacingAllowed(shell.hasObservedBackpressure());
577
+ chatRenderer.setSmoothStreamingMode(mode);
578
+ shell.setStreamPacingActive(mode === "on" || (mode === "auto" && autoAllowed));
579
+ },
480
580
  });
481
581
  // The overlay reads the report this process already produced at boot; it
482
582
  // never probes on a keystroke.
@@ -486,14 +586,22 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
486
586
  io,
487
587
  bus: deps.bus,
488
588
  dispatch: deps.dispatch,
589
+ ...(deps.session ? { session: deps.session } : {}),
489
590
  providers: deps.providers,
490
591
  chat: deps.chat,
491
- chatPanel,
592
+ chatPanel: {
593
+ appendReplayBlock: (...args) => chatRenderer.mutate(() => chatPanel.appendReplayBlock(...args), "slash-output"),
594
+ appendUser: (text) => chatRenderer.mutate(() => chatPanel.appendUser(text), "user-submit"),
595
+ clearFoldOverrides: () => chatRenderer.mutate(() => chatPanel.clearFoldOverrides(), "output-detail"),
596
+ },
597
+ beforeSemanticSubmit: () => chatRenderer.flush(),
598
+ settleVisibleFrame: (reason) => chatRenderer.flushAndCommit(reason),
492
599
  ...(deps.resources ? { resources: deps.resources } : {}),
493
600
  ...(deps.extensions ? { extensions: deps.extensions } : {}),
494
601
  ...(interopSurface ? { interop: interopSurface } : {}),
495
602
  ...(deps.agents ? { agents: deps.agents } : {}),
496
603
  ...(deps.share ? { share: deps.share } : {}),
604
+ ...(deps.userTasks ? { userTasks: deps.userTasks } : {}),
497
605
  ...(deps.getSettings ? { getSettings: deps.getSettings } : {}),
498
606
  ...(deps.writeSettings ? { writeSettings: deps.writeSettings } : {}),
499
607
  ...(deps.commitSetting ? { commitSetting: deps.commitSetting } : {}),
@@ -516,6 +624,7 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
516
624
  openCost: () => openCostOverlayState(),
517
625
  openContextView: () => openContextViewOverlayState(),
518
626
  openTasks: () => openTasksOverlayState(),
627
+ openDecisions: () => openDecisionsOverlayState(),
519
628
  openMemory: () => openMemoryOverlayState(),
520
629
  ...(deps.seedTaskMemory ? { seedTaskMemory: deps.seedTaskMemory } : {}),
521
630
  openView: (filter) => openViewOverlayState(filter),
@@ -545,8 +654,14 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
545
654
  dispatch: deps.dispatch,
546
655
  ...(deps.session ? { session: deps.session } : {}),
547
656
  sessionTranscript,
548
- chatPanel,
657
+ chatPanel: {
658
+ appendReplayBlock: (...args) =>
659
+ chatRenderer.mutate(() => chatPanel.appendReplayBlock(...args), "editor-command-output"),
660
+ },
661
+ beforeSemanticBoundary: () => chatRenderer.flush(),
662
+ settleVisibleFrame: (reason) => chatRenderer.flushAndCommit(reason),
549
663
  dispatchCommand: slashRuntime.dispatchCommand,
664
+ dispatchCommandAsync: slashRuntime.admitCommand,
550
665
  collapseLaunchpadBeforeSubmit: () => presentation.collapseWelcomeDashboard(),
551
666
  expandSubmit: (text) => expandInteractiveSubmitAsync(text, deps.resources),
552
667
  notify,
@@ -560,6 +675,7 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
560
675
  contextActivityStore,
561
676
  getOverlayState: () => overlayLifecycle?.getState() ?? "closed",
562
677
  isFooterExpanded: () => footer.isExpanded(),
678
+ ...(deps.getTaskBoard ? { getTaskBoard: deps.getTaskBoard } : {}),
563
679
  });
564
680
  /**
565
681
  * The one transcript reset. The chat panel and the worker fold are two views
@@ -569,8 +685,10 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
569
685
  * because the subscriptions that own the fold are built below.
570
686
  */
571
687
  const resetTranscript = (): void => {
572
- chatPanel.reset();
573
- interactiveSubscriptions.workers.reset();
688
+ chatRenderer.reset(() => {
689
+ chatPanel.reset();
690
+ interactiveSubscriptions.workers.reset();
691
+ });
574
692
  };
575
693
  overlayLifecycle = createOverlayLifecycle({
576
694
  app: deps,
@@ -599,6 +717,7 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
599
717
  openContextViewOverlayState,
600
718
  openContextResetOverlayState,
601
719
  openTasksOverlayState,
720
+ openDecisionsOverlayState,
602
721
  openMemoryOverlayState,
603
722
  openViewOverlayState,
604
723
  openModelOverlayState,
@@ -633,17 +752,20 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
633
752
  const current = editor.getText();
634
753
  editor.setText([restored.join("\n\n"), current].filter((part) => part.trim().length > 0).join("\n\n"));
635
754
  }
755
+ chatRenderer.flush();
636
756
  deps.chat.cancel();
637
757
  deps.toolRegistry?.cancelParkedCalls("run cancelled by operator");
638
758
  footer.refresh();
639
759
  tui.requestRender();
640
760
  };
641
761
 
642
- const startNewSession = (): void => {
762
+ const startNewSession = async (): Promise<void> => {
643
763
  if (!deps.onNewSession) {
644
764
  emitCommandNotice(slashRuntime.notice, "error", "new", "session contract unavailable");
645
765
  return;
646
766
  }
767
+ const settlement = settleChatBeforeSessionSwitch(deps.chat);
768
+ if (settlement) await settlement;
647
769
  deps.onNewSession();
648
770
  deps.observability.resetSession();
649
771
  presentation.resetForNewSession();
@@ -686,7 +808,7 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
686
808
  // The reducer mutates one state object per assignment, so the panel is
687
809
  // handed that object rather than a copy: a streamed delta reaches the
688
810
  // screen by invalidating a cached render, not by rebuilding the entry.
689
- applyWorkerState: (state) => chatPanel.applyWorkerState(state),
811
+ applyWorkerState: (state) => chatRenderer.mutate(() => chatPanel.applyWorkerState(state), "worker-state"),
690
812
  recordWorkerRun: (fields) => {
691
813
  // A `/run` is an operator action that produced durable state, so it
692
814
  // opens a session the same way a local `!bash` line does. Persistence
@@ -722,6 +844,9 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
722
844
  onLeaderStateChange: (pending) => {
723
845
  leaderArmed = pending;
724
846
  },
847
+ onShutdownArmedChange: (armed) => {
848
+ shutdownArmed = armed;
849
+ },
725
850
  dispatchBoard,
726
851
  steerSelectedDispatch,
727
852
  cancelSelectedDispatch,
@@ -732,7 +857,25 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
732
857
  editorSubmit,
733
858
  requestRender: () => tui.requestRender(),
734
859
  notifications,
735
- chatPanel,
860
+ chatPanel: {
861
+ toggleLastToolExpanded: () => chatPanel.toggleLastToolExpanded(),
862
+ toggleAllToolsExpanded: () => chatPanel.toggleAllToolsExpanded(),
863
+ toggleLiveToolOutput: () => chatPanel.toggleLiveToolOutput(),
864
+ toggleLastThinking: () => {
865
+ let changed = false;
866
+ chatRenderer.mutate(() => {
867
+ changed = chatPanel.toggleLastThinking();
868
+ }, "thinking-visibility");
869
+ return changed;
870
+ },
871
+ toggleAllThinking: () => {
872
+ let changed = false;
873
+ chatRenderer.mutate(() => {
874
+ changed = chatPanel.toggleAllThinking();
875
+ }, "thinking-visibility");
876
+ return changed;
877
+ },
878
+ },
736
879
  shutdown: {
737
880
  stopTickers: presentation.stopTickers,
738
881
  disposeInteractiveTickers: interactiveTickers.dispose,
@@ -745,11 +888,54 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
745
888
  disposeChat: () => deps.chat.dispose(),
746
889
  disposeSubscriptions: interactiveSubscriptions.dispose,
747
890
  },
748
- stopUi: () => shell.stop(),
891
+ beforeStopUi: (() => {
892
+ let settlement: Promise<void> | null = null;
893
+ return () => {
894
+ settlement ??= chatRenderer.flushAndCommit("teardown").finally(() => chatRenderer.dispose());
895
+ return settlement;
896
+ };
897
+ })(),
898
+ stopUi: () => {
899
+ if (lease) void lease.close();
900
+ else shell.stop();
901
+ },
749
902
  cancelParkedCalls: (reason) => deps.toolRegistry?.cancelParkedCalls(reason),
750
- onShutdown: deps.onShutdown,
751
- registerInputListener: (listener) => tui.addInputListener(listener),
903
+ onShutdown: async () => {
904
+ try {
905
+ await deps.onShutdown();
906
+ } finally {
907
+ if (lease) await lease.close();
908
+ else await shell.settle();
909
+ }
910
+ },
911
+ registerInputListener: (listener) => {
912
+ if (lease) lease.registerApplicationInput(listener);
913
+ else tui.addInputListener(listener);
914
+ },
915
+ ...(lease
916
+ ? {
917
+ signals: lease.applicationSignals,
918
+ // The lease registered its exactly-once drain before hydration.
919
+ registerTerminalTeardown: () => {},
920
+ }
921
+ : {}),
922
+ ...(renderTrace
923
+ ? {
924
+ onInputIngress: (action, data) =>
925
+ renderTrace.recordInputIngress(action, Buffer.byteLength(data, "utf8"), action !== "no-visual-change"),
926
+ }
927
+ : {}),
752
928
  });
753
929
 
930
+ if (lease) {
931
+ const adopted = lease.adopt({
932
+ root: presentation.root,
933
+ editorChrome: presentation.editorChrome,
934
+ admitSubmission: (submission) => editorSubmit.admitCapturedText(submission.rawText, lease.abortSignal),
935
+ ...(deps.onHydratedFrameCommit ? { onHydratedFrame: deps.onHydratedFrameCommit } : {}),
936
+ });
937
+ if (!adopted) void applicationController.shutdown();
938
+ }
939
+
754
940
  return applicationController.run;
755
941
  }
@@ -28,6 +28,8 @@ import {
28
28
  import {
29
29
  type AgentStatus,
30
30
  INLINE_STATUS_INDENT_COLS,
31
+ type ReasoningUsageView,
32
+ reasoningFromTally,
31
33
  resolveInlineVerb,
32
34
  type StatusPhase,
33
35
  spinnerFrame,
@@ -57,6 +59,8 @@ export interface InteractiveEventProjectionDeps {
57
59
  getSettings?: () => Readonly<ClioSettings>;
58
60
  getTerminalColumns: () => number;
59
61
  now?: () => number;
62
+ /** Canonical synchronous ingress hook, before any projection branch consumes the event. */
63
+ onChatEventIngress?: (event: ChatLoopEvent) => void;
60
64
  applyChatEvent: (event: ChatLoopEvent) => void;
61
65
  setFollowUpMessages: (messages: QueuedChatMessage[]) => void;
62
66
  isAskUserWaiting: () => boolean;
@@ -65,6 +69,11 @@ export interface InteractiveEventProjectionDeps {
65
69
  recordToolStart: (toolName: string, toolCallId: string) => void;
66
70
  recordToolEnd: (toolName: string, toolCallId: string, isError: boolean, truncated: boolean) => void;
67
71
  setStatusLine: (line: InteractiveStatusLine | null) => void;
72
+ /**
73
+ * Publish the live turn's reasoning projection to the transcript. Optional so
74
+ * a host without a chat panel still gets every other projection.
75
+ */
76
+ setLiveReasoning?: (view: ReasoningUsageView | null) => void;
68
77
  setLastTurnSummary: (summary: TurnSummary) => void;
69
78
  startTerminalProgress: () => void;
70
79
  stopTerminalProgress: () => void;
@@ -75,6 +84,7 @@ export interface InteractiveEventProjectionDeps {
75
84
  dismissNotification: (key: string) => void;
76
85
  appendTranscriptNotice: (level: InteractiveTranscriptNoticeLevel, text: string) => void;
77
86
  refreshSettingsOverlay: () => void;
87
+ onConfigHotReload?: (settings: Readonly<ClioSettings>) => void;
78
88
  }
79
89
 
80
90
  export interface InteractiveEventProjection {
@@ -123,6 +133,7 @@ export function createInteractiveEventProjection(deps: InteractiveEventProjectio
123
133
  const remainingUnsubscribers: Array<() => void> = [];
124
134
  primaryUnsubscribers.push(
125
135
  deps.chat.onEvent((event) => {
136
+ deps.onChatEventIngress?.(event);
126
137
  if (event.type === "notice") {
127
138
  if (event.surface === "transcript") {
128
139
  deps.applyChatEvent(event);
@@ -173,6 +184,11 @@ export function createInteractiveEventProjection(deps: InteractiveEventProjectio
173
184
  let statusInlineFrame = 0;
174
185
  primaryUnsubscribers.push(
175
186
  deps.status.subscribe((status) => {
187
+ // One projection of the run tally reaches the transcript, so the live
188
+ // line, the turn receipt, and the footer state the same number.
189
+ deps.setLiveReasoning?.(
190
+ status.phase === "idle" || status.phase === "ended" ? null : reasoningFromTally(status.runTally),
191
+ );
176
192
  if (status.phase === "idle") {
177
193
  deps.setStatusLine(null);
178
194
  } else if (status.phase === "ended") {
@@ -310,7 +326,8 @@ export function createInteractiveEventProjection(deps: InteractiveEventProjectio
310
326
  deps.refreshFooter();
311
327
  deps.requestRender();
312
328
  }),
313
- deps.bus.on(BusChannels.ConfigHotReload, () => {
329
+ deps.bus.on(BusChannels.ConfigHotReload, (payload) => {
330
+ deps.onConfigHotReload?.(payload.settings);
314
331
  deps.refreshSettingsOverlay();
315
332
  }),
316
333
  deps.bus.on(BusChannels.ConfigReloadFailed, (payload) => {
@@ -1,6 +1,6 @@
1
1
  import { getTerminationCoordinator } from "../core/termination.js";
2
2
  import type { ClioKeybinding } from "../domains/config/keybindings.js";
3
- import { isKeyRelease } from "../engine/tui.js";
3
+ import { isKeyRelease, type Keybinding } from "../engine/tui.js";
4
4
  import {
5
5
  type ApplicationClock,
6
6
  type ApplicationController,
@@ -12,6 +12,7 @@ import {
12
12
  } from "./application-controller.js";
13
13
  import { createLeaderKeyController, type LeaderTarget } from "./leader-key.js";
14
14
  import { type OverlayState, routeOverlayKey } from "./overlay-lifecycle.js";
15
+ import type { RenderInputAction } from "./render-trace.js";
15
16
 
16
17
  export interface InteractiveInputKeyActionDeps {
17
18
  matches: (data: string, id: ClioKeybinding) => boolean;
@@ -20,6 +21,8 @@ export interface InteractiveInputKeyActionDeps {
20
21
  requestShutdown: () => void;
21
22
  toggleStatus: () => void;
22
23
  toggleDispatchBoard: () => void;
24
+ openTasks: () => void;
25
+ openDecisions: () => void;
23
26
  backgroundDispatch: () => void;
24
27
  openModelSelector: () => void;
25
28
  openTree: () => void;
@@ -33,12 +36,13 @@ export interface InteractiveInputKeyActionDeps {
33
36
  toggleAllThinkingExpansion: () => void;
34
37
  openExternalEditor: () => void;
35
38
  queueFollowUp: () => void;
39
+ interruptWithMessage: () => void;
36
40
  restoreQueuedFollowUps: () => void;
37
41
  }
38
42
 
39
43
  export interface InteractiveInputRuntimeDeps {
40
44
  keybindings: {
41
- matches(data: string, id: ClioKeybinding): boolean;
45
+ matches(data: string, id: Keybinding): boolean;
42
46
  leaderTargets(): ReadonlyArray<LeaderTarget>;
43
47
  };
44
48
  dispatchAction: (id: ClioKeybinding, deps: InteractiveInputKeyActionDeps) => boolean;
@@ -61,10 +65,14 @@ export interface InteractiveInputRuntimeDeps {
61
65
  toggleDispatchBoardOverlay(): void;
62
66
  openModelOverlayState(): void;
63
67
  openTreeOverlayState(): void;
68
+ openTasksOverlayState(): void;
69
+ openDecisionsOverlayState(): void;
64
70
  };
65
71
  refreshFooter: () => void;
66
72
  /** Armed/disarmed transitions of the Ctrl+G leader, for the footer indicator. */
67
73
  onLeaderStateChange?: (pending: boolean) => void;
74
+ /** Armed/disarmed transitions of the Ctrl+C double tap, for the same indicator row. */
75
+ onShutdownArmedChange?: (armed: boolean) => void;
68
76
  dispatchBoard: {
69
77
  selectPrevious(): void;
70
78
  selectNext(): void;
@@ -78,6 +86,7 @@ export interface InteractiveInputRuntimeDeps {
78
86
  editorSubmit: {
79
87
  openExternalEditorForInput(): void;
80
88
  queueFollowUpFromEditor(): void;
89
+ interruptFromEditor(): void;
81
90
  restoreQueuedFollowUpsToEditor(): void;
82
91
  };
83
92
  requestRender: () => void;
@@ -106,12 +115,14 @@ export interface InteractiveInputRuntimeDeps {
106
115
  disposeSubscriptions(): void;
107
116
  };
108
117
  stopUi: () => void;
118
+ beforeStopUi?: () => Promise<void>;
109
119
  cancelParkedCalls: (reason: string) => void;
110
120
  onShutdown: () => Promise<void>;
111
121
  reportShutdownFailure?: (step: string, error: unknown) => void;
112
122
  /** Defaults to the process termination coordinator's drain phase. */
113
- registerTerminalTeardown?: (teardown: () => void) => void;
123
+ registerTerminalTeardown?: (teardown: () => void | Promise<void>) => void;
114
124
  registerInputListener: (listener: (data: string) => ApplicationInputResult) => void;
125
+ onInputIngress?: (action: RenderInputAction, data: string) => void;
115
126
  intervalsToClear?: ReadonlyArray<ApplicationIntervalHandle>;
116
127
  clock?: ApplicationClock;
117
128
  signals?: ApplicationSignalCoordinator;
@@ -133,6 +144,8 @@ export function createInteractiveInputRuntime(deps: InteractiveInputRuntimeDeps)
133
144
  requestShutdown: () => void controller.shutdown(),
134
145
  toggleStatus: deps.overlay.toggleFooterDashboardState,
135
146
  toggleDispatchBoard: deps.overlay.toggleDispatchBoardOverlay,
147
+ openTasks: deps.overlay.openTasksOverlayState,
148
+ openDecisions: deps.overlay.openDecisionsOverlayState,
136
149
  backgroundDispatch: deps.actions.backgroundActiveDispatch,
137
150
  openModelSelector: deps.overlay.openModelOverlayState,
138
151
  openTree: deps.overlay.openTreeOverlayState,
@@ -161,6 +174,7 @@ export function createInteractiveInputRuntime(deps: InteractiveInputRuntimeDeps)
161
174
  },
162
175
  openExternalEditor: deps.editorSubmit.openExternalEditorForInput,
163
176
  queueFollowUp: deps.editorSubmit.queueFollowUpFromEditor,
177
+ interruptWithMessage: deps.editorSubmit.interruptFromEditor,
164
178
  restoreQueuedFollowUps: deps.editorSubmit.restoreQueuedFollowUpsToEditor,
165
179
  });
166
180
  const leaderKeys = createLeaderKeyController({
@@ -212,6 +226,9 @@ export function createInteractiveInputRuntime(deps: InteractiveInputRuntimeDeps)
212
226
  },
213
227
  (input, id) => deps.keybindings.matches(input, id),
214
228
  ),
229
+ matchesEditorHistory: (data) =>
230
+ deps.keybindings.matches(data, "tui.editor.historyPrevious") ||
231
+ deps.keybindings.matches(data, "tui.editor.historyNext"),
215
232
  matchesAction: (data, id) => deps.keybindings.matches(data, id),
216
233
  dispatchAction: (id) => deps.dispatchAction(id, keyActionDeps()),
217
234
  cancelActiveEditorBash: deps.cancelActiveEditorBash,
@@ -220,6 +237,13 @@ export function createInteractiveInputRuntime(deps: InteractiveInputRuntimeDeps)
220
237
  getEditorText: () => deps.editor.getText(),
221
238
  clearEditor: () => deps.editor.setText(""),
222
239
  requestRender: deps.requestRender,
240
+ // The footer pulls the flag when it refreshes, so the refresh has to land
241
+ // before the controller asks for the frame. The controller owns the render
242
+ // request on this path, which is why this hook does not make one.
243
+ onShutdownArmedChange: (armed) => {
244
+ deps.onShutdownArmedChange?.(armed);
245
+ deps.refreshFooter();
246
+ },
223
247
  closeOverlay: () => deps.overlay.closeOverlay(),
224
248
  listNotifications: () => deps.notifications.list(),
225
249
  dismissNotification: (id) => deps.notifications.dismiss(id),
@@ -242,6 +266,7 @@ export function createInteractiveInputRuntime(deps: InteractiveInputRuntimeDeps)
242
266
  () => deps.shutdown.disposeSubscriptions(),
243
267
  ],
244
268
  stopUi: deps.stopUi,
269
+ ...(deps.beforeStopUi ? { beforeStopUi: deps.beforeStopUi } : {}),
245
270
  cancelParkedCalls: deps.cancelParkedCalls,
246
271
  onShutdown: deps.onShutdown,
247
272
  registerTerminalTeardown:
@@ -256,6 +281,27 @@ export function createInteractiveInputRuntime(deps: InteractiveInputRuntimeDeps)
256
281
  );
257
282
  }),
258
283
  });
259
- deps.registerInputListener(controller.handleInput);
284
+ deps.registerInputListener((data) => {
285
+ deps.onInputIngress?.(classifyInputAction(data, deps), data);
286
+ return controller.handleInput(data);
287
+ });
260
288
  return controller;
261
289
  }
290
+
291
+ function classifyInputAction(data: string, deps: InteractiveInputRuntimeDeps): RenderInputAction {
292
+ if (data.length === 0 || isKeyRelease(data)) return "no-visual-change";
293
+ if (deps.keybindings.matches(data, "tui.input.submit")) return "submit";
294
+ const sgrMousePrefix = `${String.fromCharCode(27)}[<`;
295
+ if (
296
+ data.startsWith(`${sgrMousePrefix}64;`) ||
297
+ data.startsWith(`${sgrMousePrefix}65;`) ||
298
+ deps.keybindings.matches(data, "tui.altScreen.pageUp") ||
299
+ deps.keybindings.matches(data, "tui.altScreen.pageDown") ||
300
+ deps.keybindings.matches(data, "tui.editor.pageUp") ||
301
+ deps.keybindings.matches(data, "tui.editor.pageDown")
302
+ ) {
303
+ return "scroll";
304
+ }
305
+ if (deps.overlay.getState() !== "closed") return "overlay";
306
+ return "editor";
307
+ }