@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
@@ -1,125 +1,534 @@
1
- import { appendFileSync, mkdirSync, openSync, writeSync } from "node:fs";
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { appendFile } from "node:fs/promises";
2
3
  import { dirname } from "node:path";
4
+ import type { TuiRenderObserver, TuiRenderPhase } from "../engine/tui.js";
3
5
 
4
- /**
5
- * Opt-in per-frame render instrument. Off unless CLIO_CODER_RENDER_TRACE names a
6
- * file, and it costs one `performance.now()` plus a buffered line per frame
7
- * when it is on.
8
- *
9
- * It exists because "the TUI is janky with a fast model" is not a number.
10
- * Two costs hide behind that sentence and they call for different fixes: time
11
- * spent building the frame (chat-panel render, markdown, wrapping) and time
12
- * spent writing it (bytes to the terminal, full redraws instead of diffs). A
13
- * row per frame carrying both, plus the gap since the previous frame, tells
14
- * them apart.
15
- */
16
- export interface RenderTraceRow {
17
- /** ms since the trace opened. */
6
+ /** The trace format is append-only JSONL so partial sessions remain readable. */
7
+ export const RENDER_TRACE_VERSION = 2;
8
+
9
+ export type RenderInputAction = "editor" | "overlay" | "scroll" | "submit" | "no-visual-change";
10
+ export type VisibleEventKind = "text" | "thinking";
11
+
12
+ export interface RenderTraceCommit {
13
+ writeId: number;
18
14
  at: number;
19
- /** ms since the previous frame's write, or null for the first. */
20
- sinceLastMs: number | null;
21
- /** Bytes handed to the terminal for this frame. */
22
15
  bytes: number;
23
- /** Chat-panel render time attributed to this frame, when one was recorded. */
24
- panelMs: number | null;
25
- panelCacheHit: boolean | null;
26
- panelEntries: number | null;
27
- /** Stream deltas applied since the previous frame. */
28
- deltas: number;
29
- /** ms from the first unrendered delta to this frame, or null when none arrived. */
30
- deltaLagMs: number | null;
16
+ enqueueMs: number;
17
+ returned: boolean;
18
+ backpressured: boolean;
31
19
  }
32
20
 
33
- export interface RenderTrace {
34
- recordPanelRender(metrics: { durationMs: number; cacheHit: boolean; entriesRendered: number }): void;
35
- /** One streamed text/thinking delta reached the panel. */
36
- recordDelta(): void;
37
- recordFrame(bytes: number): void;
38
- close(): void;
21
+ export interface RenderTraceFrameRecord {
22
+ type: "frame";
23
+ version: typeof RENDER_TRACE_VERSION;
24
+ frameId: number;
25
+ mode: "regular" | "fullscreen";
26
+ columns: number;
27
+ rows: number;
28
+ beginAt: number;
29
+ endAt: number;
30
+ durationMs: number;
31
+ sinceLastCommitMs: number | null;
32
+ panelHighWater: number;
33
+ inputHighWater: number;
34
+ panel: { durationMs: number; cacheHit: boolean; entriesRendered: number } | null;
35
+ pipeline: {
36
+ componentMs: number;
37
+ overlayCompositionMs: number;
38
+ normalizationMs: number;
39
+ cursorExtractionMs: number;
40
+ /** Viewport selection, diffing, ANSI construction, and cursor work not exposed as narrower pi-tui hooks. */
41
+ viewportDiffAnsiCursorMs: number;
42
+ terminalEnqueueMs: number;
43
+ };
44
+ commits: RenderTraceCommit[];
45
+ }
46
+
47
+ export type RenderTraceRecord =
48
+ | { type: "trace_start"; version: typeof RENDER_TRACE_VERSION; at: number }
49
+ | {
50
+ type: "event_ingress";
51
+ version: typeof RENDER_TRACE_VERSION;
52
+ eventSeq: number;
53
+ generation: number;
54
+ kind: VisibleEventKind;
55
+ contentIndex: number;
56
+ at: number;
57
+ codeUnitStart: number;
58
+ codeUnitEnd: number;
59
+ graphemeStart: number;
60
+ graphemeEnd: number;
61
+ bytes: number;
62
+ }
63
+ | {
64
+ type: "queue";
65
+ version: typeof RENDER_TRACE_VERSION;
66
+ eventSeq: number;
67
+ action: "admit" | "dequeue";
68
+ at: number;
69
+ depth: number;
70
+ }
71
+ | {
72
+ type: "panel";
73
+ version: typeof RENDER_TRACE_VERSION;
74
+ eventSeq: number;
75
+ at: number;
76
+ highWater: number;
77
+ }
78
+ | {
79
+ type: "input_ingress";
80
+ version: typeof RENDER_TRACE_VERSION;
81
+ inputSeq: number;
82
+ action: RenderInputAction;
83
+ at: number;
84
+ bytes: number;
85
+ visualExpected: boolean;
86
+ }
87
+ | RenderTraceFrameRecord
88
+ | {
89
+ type: "terminal_write";
90
+ version: typeof RENDER_TRACE_VERSION;
91
+ writeId: number;
92
+ frameId: number | null;
93
+ at: number;
94
+ bytes: number;
95
+ enqueueMs: number;
96
+ returned: boolean;
97
+ backpressured: boolean;
98
+ }
99
+ | {
100
+ type: "terminal_drain";
101
+ version: typeof RENDER_TRACE_VERSION;
102
+ writeId: number;
103
+ frameId: number | null;
104
+ at: number;
105
+ waitMs: number;
106
+ }
107
+ | { type: "trace_drop"; version: typeof RENDER_TRACE_VERSION; at: number; records: number };
108
+
109
+ interface TraceWriter {
110
+ enqueue(record: RenderTraceRecord): void;
111
+ close(): Promise<void>;
112
+ }
113
+
114
+ interface AsyncTraceWriterOptions {
115
+ maxRecords?: number;
116
+ batchRecords?: number;
117
+ append?: (path: string, payload: string) => Promise<void>;
118
+ recordTime?: () => number;
119
+ appendTimeoutMs?: number;
39
120
  }
40
121
 
41
122
  /**
42
- * Rows buffered before a synchronous append. Small enough that a session read
43
- * mid-run sees the frames it just produced, which the first measuring attempt
44
- * did not: a 64-row buffer that only ever flushed once described startup and
45
- * said nothing about the streaming turn it was opened for.
123
+ * One bounded producer queue and at most one asynchronous append in flight.
124
+ * JSON serialization is the only render-stack work; filesystem I/O never runs
125
+ * in a render callback, and a slow disk cannot grow an unbounded promise chain.
46
126
  */
47
- const FLUSH_EVERY = 8;
127
+ function createAsyncTraceWriter(path: string, options: AsyncTraceWriterOptions = {}): TraceWriter {
128
+ const maxRecords = options.maxRecords ?? 4_096;
129
+ const batchRecords = options.batchRecords ?? 128;
130
+ const append = options.append ?? ((target, payload) => appendFile(target, payload, "utf8"));
131
+ const recordTime = options.recordTime ?? (() => performance.now());
132
+ // Stage 0 deliberately commits immediately before a large synchronous ESM
133
+ // evaluation. A 500 ms timer could become runnable before the already-finished
134
+ // append callback when that evaluation held the event loop, falsely disabling
135
+ // the trace after its first frame. Five seconds still bounds a genuinely
136
+ // wedged filesystem while surviving boot-time callback starvation.
137
+ const appendTimeoutMs = options.appendTimeoutMs ?? 5_000;
138
+ const pending: string[] = [];
139
+ let dropped = 0;
140
+ let inFlight = false;
141
+ let scheduled = false;
142
+ let failed = false;
143
+ let closing = false;
144
+ let closePromise: Promise<void> | null = null;
145
+ let resolveClose: (() => void) | null = null;
146
+
147
+ const settleClose = (): void => {
148
+ if (closing && !inFlight && pending.length === 0) resolveClose?.();
149
+ };
150
+ const pump = (): void => {
151
+ scheduled = false;
152
+ if (failed || inFlight || pending.length === 0) {
153
+ settleClose();
154
+ return;
155
+ }
156
+ inFlight = true;
157
+ const payload = pending.splice(0, batchRecords).join("");
158
+ let appendTimer: NodeJS.Timeout | null = null;
159
+ const appendDeadline = new Promise<never>((_resolve, reject) => {
160
+ appendTimer = setTimeout(() => reject(new Error("render trace append timed out")), appendTimeoutMs);
161
+ });
162
+ void Promise.race([append(path, payload), appendDeadline])
163
+ .catch(() => {
164
+ failed = true;
165
+ pending.length = 0;
166
+ })
167
+ .finally(() => {
168
+ if (appendTimer) clearTimeout(appendTimer);
169
+ inFlight = false;
170
+ if (pending.length > 0 && !failed) queueMicrotask(pump);
171
+ else settleClose();
172
+ });
173
+ };
174
+ const schedule = (): void => {
175
+ if (scheduled || inFlight || failed) return;
176
+ scheduled = true;
177
+ queueMicrotask(pump);
178
+ };
179
+
180
+ return {
181
+ enqueue(record): void {
182
+ if (failed || closing) return;
183
+ if (pending.length >= maxRecords) {
184
+ pending.shift();
185
+ dropped += 1;
186
+ }
187
+ pending.push(`${JSON.stringify(record)}\n`);
188
+ schedule();
189
+ },
190
+ close(): Promise<void> {
191
+ if (closePromise) return closePromise;
192
+ if (dropped > 0 && !failed) {
193
+ pending.push(
194
+ `${JSON.stringify({ type: "trace_drop", version: RENDER_TRACE_VERSION, at: recordTime(), records: dropped })}\n`,
195
+ );
196
+ }
197
+ closing = true;
198
+ closePromise = new Promise((resolve) => {
199
+ resolveClose = resolve;
200
+ });
201
+ if (failed) {
202
+ pending.length = 0;
203
+ resolveClose?.();
204
+ } else {
205
+ schedule();
206
+ settleClose();
207
+ }
208
+ return closePromise;
209
+ },
210
+ };
211
+ }
212
+
213
+ interface FrameState {
214
+ frameId: number;
215
+ mode: "regular" | "fullscreen";
216
+ columns: number;
217
+ rows: number;
218
+ beginAt: number;
219
+ panelHighWater: number;
220
+ inputHighWater: number;
221
+ panel: { durationMs: number; cacheHit: boolean; entriesRendered: number } | null;
222
+ phases: Record<"component" | TuiRenderPhase, number>;
223
+ commits: RenderTraceCommit[];
224
+ }
225
+
226
+ export interface RenderTrace extends TuiRenderObserver {
227
+ recordPanelRender(metrics: { durationMs: number; cacheHit: boolean; entriesRendered: number }): void;
228
+ beginGeneration(): void;
229
+ recordVisibleEvent(fields: { kind: VisibleEventKind; contentIndex: number; delta: string }): number;
230
+ recordQueue(eventSeq: number, action: "admit" | "dequeue"): void;
231
+ recordPanelApplied(eventSeq: number): void;
232
+ recordInputIngress(action: RenderInputAction, bytes: number, visualExpected?: boolean): number;
233
+ beginComponentRender(): unknown;
234
+ endComponentRender(token: unknown): void;
235
+ recordTerminalWrite(fields: { bytes: number; enqueueMs: number; returned: boolean }): number;
236
+ recordTerminalDrain(writeId: number): void;
237
+ currentFrameId(): number | null;
238
+ onFirstFrameCommit(listener: (frameId: number) => void): void;
239
+ close(): Promise<void>;
240
+ }
241
+
242
+ function rounded(value: number): number {
243
+ return Math.round(value * 1_000) / 1_000;
244
+ }
245
+
246
+ function graphemeCount(text: string): number {
247
+ const segmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
248
+ let count = 0;
249
+ for (const _part of segmenter.segment(text)) count += 1;
250
+ return count;
251
+ }
48
252
 
49
253
  export function renderTracePath(env: NodeJS.ProcessEnv = process.env): string | null {
50
254
  const raw = env.CLIO_CODER_RENDER_TRACE?.trim();
51
255
  return raw && raw.length > 0 ? raw : null;
52
256
  }
53
257
 
54
- export function createRenderTrace(path: string, now: () => number = () => performance.now()): RenderTrace {
258
+ export function createRenderTrace(
259
+ path: string,
260
+ now: () => number = () => performance.now(),
261
+ writerOptions: AsyncTraceWriterOptions = {},
262
+ ): RenderTrace {
263
+ // Initialization happens before the terminal/TUI starts, never in a frame.
55
264
  mkdirSync(dirname(path), { recursive: true });
56
- // Truncate on open so a trace is one session, never an append of several.
57
- writeSync(openSync(path, "w"), "");
265
+ writeFileSync(path, "", "utf8");
58
266
  const openedAt = now();
59
- let lastFrameAt: number | null = null;
60
- // The panel renders during the frame that is about to be written, so its
61
- // metrics are held until that write attributes them.
62
- let pendingPanel: { durationMs: number; cacheHit: boolean; entriesRendered: number } | null = null;
63
- let pendingDeltas = 0;
64
- let firstPendingDeltaAt: number | null = null;
65
- let buffer: string[] = [];
66
-
67
- const flush = (): void => {
68
- if (buffer.length === 0) return;
69
- const payload = buffer.join("");
70
- buffer = [];
71
- try {
72
- appendFileSync(path, payload);
73
- } catch {
74
- // A trace that cannot be written must not take the session down.
75
- }
76
- };
267
+ const at = (): number => rounded(now() - openedAt);
268
+ const writer = createAsyncTraceWriter(path, { ...writerOptions, recordTime: at });
269
+ let frameSeq = 0;
270
+ let writeSeq = 0;
271
+ let eventSeq = 0;
272
+ let inputSeq = 0;
273
+ let generation = 0;
274
+ let panelHighWater = 0;
275
+ let inputHighWater = 0;
276
+ let queueDepth = 0;
277
+ let currentFrame: FrameState | null = null;
278
+ let pendingPanel: FrameState["panel"] = null;
279
+ let lastCommitAt: number | null = null;
280
+ let firstCommitListener: ((frameId: number) => void) | null = null;
281
+ let firstCommitDelivered = false;
282
+ const ranges = new Map<string, { codeUnits: number; graphemes: number }>();
283
+ const pendingDrains = new Map<number, { frameId: number | null; at: number }>();
77
284
 
78
- return {
285
+ writer.enqueue({ type: "trace_start", version: RENDER_TRACE_VERSION, at: 0 });
286
+
287
+ const trace: RenderTrace = {
79
288
  recordPanelRender(metrics): void {
80
289
  pendingPanel = metrics;
81
290
  },
82
- recordDelta(): void {
83
- pendingDeltas += 1;
84
- firstPendingDeltaAt ??= now() - openedAt;
291
+ beginGeneration(): void {
292
+ generation += 1;
293
+ ranges.clear();
294
+ },
295
+ recordVisibleEvent(fields): number {
296
+ eventSeq += 1;
297
+ const key = `${generation}:${fields.kind}:${fields.contentIndex}`;
298
+ const previous = ranges.get(key) ?? { codeUnits: 0, graphemes: 0 };
299
+ const graphemes = graphemeCount(fields.delta);
300
+ const next = { codeUnits: previous.codeUnits + fields.delta.length, graphemes: previous.graphemes + graphemes };
301
+ ranges.set(key, next);
302
+ writer.enqueue({
303
+ type: "event_ingress",
304
+ version: RENDER_TRACE_VERSION,
305
+ eventSeq,
306
+ generation,
307
+ kind: fields.kind,
308
+ contentIndex: fields.contentIndex,
309
+ at: at(),
310
+ codeUnitStart: previous.codeUnits,
311
+ codeUnitEnd: next.codeUnits,
312
+ graphemeStart: previous.graphemes,
313
+ graphemeEnd: next.graphemes,
314
+ bytes: Buffer.byteLength(fields.delta, "utf8"),
315
+ });
316
+ return eventSeq;
85
317
  },
86
- recordFrame(bytes): void {
87
- const at = now() - openedAt;
88
- const row: RenderTraceRow = {
89
- at: Math.round(at * 1000) / 1000,
90
- sinceLastMs: lastFrameAt === null ? null : Math.round((at - lastFrameAt) * 1000) / 1000,
318
+ recordQueue(sequence, action): void {
319
+ queueDepth = Math.max(0, queueDepth + (action === "admit" ? 1 : -1));
320
+ writer.enqueue({
321
+ type: "queue",
322
+ version: RENDER_TRACE_VERSION,
323
+ eventSeq: sequence,
324
+ action,
325
+ at: at(),
326
+ depth: queueDepth,
327
+ });
328
+ },
329
+ recordPanelApplied(sequence): void {
330
+ panelHighWater = Math.max(panelHighWater, sequence);
331
+ writer.enqueue({
332
+ type: "panel",
333
+ version: RENDER_TRACE_VERSION,
334
+ eventSeq: sequence,
335
+ at: at(),
336
+ highWater: panelHighWater,
337
+ });
338
+ },
339
+ recordInputIngress(action, bytes, visualExpected = action !== "no-visual-change"): number {
340
+ inputSeq += 1;
341
+ if (visualExpected) inputHighWater = inputSeq;
342
+ writer.enqueue({
343
+ type: "input_ingress",
344
+ version: RENDER_TRACE_VERSION,
345
+ inputSeq,
346
+ action,
347
+ at: at(),
91
348
  bytes,
92
- panelMs: pendingPanel ? Math.round(pendingPanel.durationMs * 1000) / 1000 : null,
93
- panelCacheHit: pendingPanel ? pendingPanel.cacheHit : null,
94
- panelEntries: pendingPanel ? pendingPanel.entriesRendered : null,
95
- deltas: pendingDeltas,
96
- deltaLagMs: firstPendingDeltaAt === null ? null : Math.round((at - firstPendingDeltaAt) * 1000) / 1000,
349
+ visualExpected,
350
+ });
351
+ return inputSeq;
352
+ },
353
+ beginFrame(fields): FrameState {
354
+ frameSeq += 1;
355
+ const frame: FrameState = {
356
+ frameId: frameSeq,
357
+ ...fields,
358
+ beginAt: at(),
359
+ panelHighWater,
360
+ inputHighWater,
361
+ panel: pendingPanel,
362
+ phases: { component: 0, overlay: 0, normalization: 0, cursor: 0 },
363
+ commits: [],
97
364
  };
98
- lastFrameAt = at;
99
365
  pendingPanel = null;
100
- pendingDeltas = 0;
101
- firstPendingDeltaAt = null;
102
- buffer.push(`${JSON.stringify(row)}\n`);
103
- if (buffer.length >= FLUSH_EVERY) flush();
366
+ currentFrame = frame;
367
+ return frame;
368
+ },
369
+ endFrame(frameToken): void {
370
+ const frame = frameToken as FrameState;
371
+ const endAt = at();
372
+ const terminalEnqueueMs = frame.commits.reduce((sum, commit) => sum + commit.enqueueMs, 0);
373
+ const measured =
374
+ frame.phases.component +
375
+ frame.phases.overlay +
376
+ frame.phases.normalization +
377
+ frame.phases.cursor +
378
+ terminalEnqueueMs;
379
+ const record: RenderTraceFrameRecord = {
380
+ type: "frame",
381
+ version: RENDER_TRACE_VERSION,
382
+ frameId: frame.frameId,
383
+ mode: frame.mode,
384
+ columns: frame.columns,
385
+ rows: frame.rows,
386
+ beginAt: frame.beginAt,
387
+ endAt,
388
+ durationMs: rounded(Math.max(0, endAt - frame.beginAt)),
389
+ sinceLastCommitMs:
390
+ lastCommitAt === null || frame.commits.length === 0
391
+ ? null
392
+ : rounded(Math.max(0, (frame.commits[0]?.at ?? endAt) - lastCommitAt)),
393
+ panelHighWater: frame.panelHighWater,
394
+ inputHighWater: frame.inputHighWater,
395
+ panel: frame.panel,
396
+ pipeline: {
397
+ componentMs: rounded(frame.phases.component),
398
+ overlayCompositionMs: rounded(frame.phases.overlay),
399
+ normalizationMs: rounded(frame.phases.normalization),
400
+ cursorExtractionMs: rounded(frame.phases.cursor),
401
+ viewportDiffAnsiCursorMs: rounded(Math.max(0, endAt - frame.beginAt - measured)),
402
+ terminalEnqueueMs: rounded(terminalEnqueueMs),
403
+ },
404
+ commits: frame.commits,
405
+ };
406
+ writer.enqueue(record);
407
+ if (frame.commits.length > 0) {
408
+ lastCommitAt = frame.commits.at(-1)?.at ?? endAt;
409
+ if (!firstCommitDelivered) {
410
+ firstCommitDelivered = true;
411
+ firstCommitListener?.(frame.frameId);
412
+ }
413
+ }
414
+ if (currentFrame === frame) currentFrame = null;
415
+ },
416
+ beginPhase(_frame, _phase): number {
417
+ return now();
418
+ },
419
+ endPhase(frameToken, phase, phaseToken): void {
420
+ const frame = frameToken as FrameState;
421
+ frame.phases[phase] += Math.max(0, now() - (phaseToken as number));
104
422
  },
105
- close(): void {
106
- flush();
423
+ beginComponentRender(): number | null {
424
+ return currentFrame ? now() : null;
107
425
  },
426
+ endComponentRender(token): void {
427
+ if (currentFrame === null || token === null) return;
428
+ currentFrame.phases.component += Math.max(0, now() - (token as number));
429
+ },
430
+ recordTerminalWrite(fields): number {
431
+ writeSeq += 1;
432
+ const frameId = currentFrame?.frameId ?? null;
433
+ const commit: RenderTraceCommit = {
434
+ writeId: writeSeq,
435
+ at: at(),
436
+ bytes: fields.bytes,
437
+ enqueueMs: rounded(fields.enqueueMs),
438
+ returned: fields.returned,
439
+ backpressured: !fields.returned,
440
+ };
441
+ currentFrame?.commits.push(commit);
442
+ writer.enqueue({ type: "terminal_write", version: RENDER_TRACE_VERSION, frameId, ...commit });
443
+ if (!fields.returned) pendingDrains.set(writeSeq, { frameId, at: commit.at });
444
+ return writeSeq;
445
+ },
446
+ recordTerminalDrain(writeId): void {
447
+ const pending = pendingDrains.get(writeId);
448
+ if (!pending) return;
449
+ pendingDrains.delete(writeId);
450
+ const drainAt = at();
451
+ writer.enqueue({
452
+ type: "terminal_drain",
453
+ version: RENDER_TRACE_VERSION,
454
+ writeId,
455
+ frameId: pending.frameId,
456
+ at: drainAt,
457
+ waitMs: rounded(Math.max(0, drainAt - pending.at)),
458
+ });
459
+ },
460
+ currentFrameId: () => currentFrame?.frameId ?? null,
461
+ onFirstFrameCommit(listener): void {
462
+ firstCommitListener = listener;
463
+ },
464
+ close: () => writer.close(),
465
+ };
466
+ return trace;
467
+ }
468
+
469
+ /** Time the root component without replacing its identity or layout markers. */
470
+ export function traceComponentRenders<TComponent extends { render(width: number): string[] }>(
471
+ component: TComponent,
472
+ trace: Pick<RenderTrace, "beginComponentRender" | "endComponentRender">,
473
+ ): () => void {
474
+ const original = component.render;
475
+ const wrapped = function (this: TComponent, width: number): string[] {
476
+ const token = trace.beginComponentRender();
477
+ try {
478
+ return original.call(this, width);
479
+ } finally {
480
+ trace.endComponentRender(token);
481
+ }
482
+ };
483
+ component.render = wrapped;
484
+ return () => {
485
+ if (component.render === wrapped) component.render = original;
108
486
  };
109
487
  }
110
488
 
111
489
  /**
112
- * Wrap a terminal so every frame's byte count reaches the trace. pi-tui emits
113
- * exactly one `write` per rendered frame, so counting writes counts frames.
490
+ * Observe the real Node stdout boundary. This catches writes made by terminal
491
+ * helpers that bypass `Terminal.write()` and records the Writable boolean plus
492
+ * the matching `drain`, while preserving Node's overloaded write contract.
114
493
  */
115
- export function traceTerminalWrites<TTerminal extends { write(data: string): void }>(
116
- terminal: TTerminal,
117
- trace: Pick<RenderTrace, "recordFrame">,
118
- ): TTerminal {
119
- const original = terminal.write.bind(terminal);
120
- terminal.write = (data: string): void => {
121
- trace.recordFrame(Buffer.byteLength(data, "utf8"));
122
- original(data);
494
+ export function traceProcessStdout(
495
+ trace: Pick<RenderTrace, "recordTerminalWrite" | "recordTerminalDrain">,
496
+ now: () => number = () => performance.now(),
497
+ stdout: Pick<typeof process.stdout, "write" | "once"> = process.stdout,
498
+ ): () => void {
499
+ const original = stdout.write;
500
+ const pendingDrainWrites: number[] = [];
501
+ let drainListening = false;
502
+ const wrapped = function (this: typeof stdout, ...args: unknown[]): boolean {
503
+ const chunk = args[0];
504
+ const start = now();
505
+ const returned = Reflect.apply(original, this, args) as boolean;
506
+ const enqueueMs = Math.max(0, now() - start);
507
+ let bytes = 0;
508
+ try {
509
+ bytes = Buffer.isBuffer(chunk)
510
+ ? chunk.byteLength
511
+ : ArrayBuffer.isView(chunk)
512
+ ? chunk.byteLength
513
+ : Buffer.byteLength(String(chunk), typeof args[1] === "string" ? (args[1] as BufferEncoding) : "utf8");
514
+ } catch {
515
+ bytes = Buffer.byteLength(String(chunk), "utf8");
516
+ }
517
+ const writeId = trace.recordTerminalWrite({ bytes, enqueueMs, returned });
518
+ if (!returned) {
519
+ pendingDrainWrites.push(writeId);
520
+ if (!drainListening) {
521
+ drainListening = true;
522
+ stdout.once("drain", () => {
523
+ drainListening = false;
524
+ for (const pendingWriteId of pendingDrainWrites.splice(0)) trace.recordTerminalDrain(pendingWriteId);
525
+ });
526
+ }
527
+ }
528
+ return returned;
529
+ } as typeof stdout.write;
530
+ stdout.write = wrapped;
531
+ return () => {
532
+ if (stdout.write === wrapped) stdout.write = original;
123
533
  };
124
- return terminal;
125
534
  }
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Two output shapes live here:
5
5
  * 1. `renderCompactionSummaryLine` is the inline one-liner chat-loop
6
- * emits after an auto-compaction or `/compact` run. It uses the same
6
+ * emits after an auto-compaction or `/context compact` run. It uses the same
7
7
  * `[context engine] <stage>:` shape as the observation-mask notice.
8
8
  * 2. `renderCompactionSummaryEntry` renders a persisted
9
9
  * `CompactionSummaryEntry` as a framed, indented block the chat panel
@@ -39,7 +39,7 @@ export interface CompactionSummaryLineInput {
39
39
  }
40
40
 
41
41
  /**
42
- * One-line notice the `/compact` handler writes to stdout. Example:
42
+ * One-line notice the `/context compact` handler writes to stdout. Example:
43
43
  * [context engine] llm_summary: 42 messages summarized to 1823 chars; ~31420 tokens before
44
44
  * Split-turn runs carry a `(split turn)` suffix so the user knows the cut
45
45
  * landed mid-turn and upstream context may need a re-read.