@iowarp/clio-coder 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (595) hide show
  1. package/CHANGELOG.md +90 -2
  2. package/CONTRIBUTING.md +23 -23
  3. package/README.md +284 -613
  4. package/dist/{acp-FPR54DGL.js → acp-BIYHVZIM.js} +43 -53
  5. package/dist/{agents-OGPIHPJH.js → agents-YT6SSRIT.js} +43 -26
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-IC3K6NIZ.js → auth-5TWEIYDN.js} +20 -12
  8. package/dist/{chunk-PV4JUBVJ.js → chunk-2EHAIA3X.js} +40 -21
  9. package/dist/{chunk-IS3ONKU3.js → chunk-2IR2NMPA.js} +6 -4
  10. package/dist/chunk-2SFS6XQE.js +122 -0
  11. package/dist/chunk-2VTFPG5O.js +48 -0
  12. package/dist/{chunk-MAR7Y6HW.js → chunk-3ZXDFGR5.js} +23 -16
  13. package/dist/chunk-4BJ5BYCE.js +61 -0
  14. package/dist/{chunk-474KN5II.js → chunk-4BPJXDWC.js} +111 -181
  15. package/dist/chunk-4KLWL3UC.js +18 -0
  16. package/dist/chunk-4VP4KH3K.js +962 -0
  17. package/dist/chunk-4ZG3XFUR.js +77 -0
  18. package/dist/chunk-5B2AEOW5.js +5407 -0
  19. package/dist/{chunk-K2ITRMHZ.js → chunk-5TSRNF4G.js} +6 -138
  20. package/dist/{chunk-OLBBMFRD.js → chunk-5UUP6MWO.js} +24 -62
  21. package/dist/chunk-65DEGPJ6.js +52 -0
  22. package/dist/chunk-6EJMN2Y3.js +17 -0
  23. package/dist/chunk-6EJV5X2W.js +16405 -0
  24. package/dist/chunk-6N5PTWMY.js +136 -0
  25. package/dist/chunk-6XLNIQDB.js +27 -0
  26. package/dist/{chunk-TEKV33Q5.js → chunk-77VKQEHF.js} +65 -33
  27. package/dist/chunk-7CR24IG7.js +242 -0
  28. package/dist/{chunk-M5T5VO65.js → chunk-7EYHLWU7.js} +837 -635
  29. package/dist/chunk-7MNJORFF.js +22 -0
  30. package/dist/{chunk-KY56HMHH.js → chunk-A3CYT5EX.js} +125 -31
  31. package/dist/chunk-AGYYIBLL.js +1069 -0
  32. package/dist/chunk-AO4RKG4M.js +277 -0
  33. package/dist/{chunk-GB6QRBXN.js → chunk-APJ265NV.js} +54 -1187
  34. package/dist/chunk-ARBGF5F7.js +174 -0
  35. package/dist/{chunk-673JJUWJ.js → chunk-BMEMKKIT.js} +2 -2
  36. package/dist/chunk-CBCAPZAA.js +229 -0
  37. package/dist/chunk-CMZWFGD2.js +352 -0
  38. package/dist/chunk-ECH6PKUQ.js +39 -0
  39. package/dist/chunk-ED4KHGC3.js +143 -0
  40. package/dist/chunk-EKMEHE4H.js +340 -0
  41. package/dist/{chunk-RPTR2H26.js → chunk-EPVUXGXG.js} +21 -15
  42. package/dist/chunk-FCSXB6T2.js +338 -0
  43. package/dist/chunk-FJ3H4MN5.js +48 -0
  44. package/dist/chunk-FQ4SKYE4.js +29 -0
  45. package/dist/chunk-G2DE3C7R.js +644 -0
  46. package/dist/chunk-G4BMMOKF.js +182 -0
  47. package/dist/{chunk-ZPY3JZ5E.js → chunk-GGXXDWE4.js} +183 -1233
  48. package/dist/chunk-HC4CLZ2Y.js +68 -0
  49. package/dist/{chunk-LU4TK2PR.js → chunk-HFSBBKSQ.js} +5 -56
  50. package/dist/{chunk-PIUMUEMV.js → chunk-HKIYEGME.js} +10 -6
  51. package/dist/chunk-I4HZDVNP.js +73 -0
  52. package/dist/{chunk-4QKXUHSR.js → chunk-IGLFWIYI.js} +70 -20
  53. package/dist/chunk-IKCO5N3L.js +162 -0
  54. package/dist/chunk-IR4CFBFN.js +56 -0
  55. package/dist/{chunk-PFEFKVGL.js → chunk-J5HN4RYU.js} +13 -11
  56. package/dist/{chunk-R5KLMSBV.js → chunk-J5Q24KAG.js} +2 -2
  57. package/dist/{chunk-K5XEMXTI.js → chunk-JVCV3ICN.js} +1 -1
  58. package/dist/chunk-KJ5LWLOE.js +1077 -0
  59. package/dist/chunk-LBMZMYH2.js +285 -0
  60. package/dist/{chunk-G34LV2PF.js → chunk-LBNRH5WM.js} +84 -170
  61. package/dist/{chunk-H6F6BYOH.js → chunk-LZSJBIVT.js} +7003 -7434
  62. package/dist/{chunk-HQQID6OA.js → chunk-M6SHUN7Q.js} +5 -5
  63. package/dist/chunk-MAW544W2.js +1882 -0
  64. package/dist/chunk-MBS4V7ZP.js +217 -0
  65. package/dist/{chunk-FST4FYJB.js → chunk-MFFY33HR.js} +99 -140
  66. package/dist/chunk-MNA4JGU4.js +255 -0
  67. package/dist/chunk-MQSRRFWA.js +3428 -0
  68. package/dist/{chunk-BSU2YIWB.js → chunk-MVVUPGPW.js} +131 -136
  69. package/dist/chunk-OAO4GE4M.js +619 -0
  70. package/dist/chunk-OHHN2SO4.js +5135 -0
  71. package/dist/chunk-OKGUZO2U.js +34 -0
  72. package/dist/{chunk-GAEBEQVI.js → chunk-OOJYHWRB.js} +32 -346
  73. package/dist/{chunk-Q5WJOSJ7.js → chunk-OQ33BKR3.js} +2 -1
  74. package/dist/chunk-OQE5J4C6.js +73 -0
  75. package/dist/{chunk-KKNLWXI6.js → chunk-ORBHGJC5.js} +8 -8
  76. package/dist/chunk-POHLU5DW.js +1186 -0
  77. package/dist/chunk-QKMUKYO7.js +4961 -0
  78. package/dist/{chunk-ASND7OZK.js → chunk-QTYWRVRA.js} +13 -13
  79. package/dist/{chunk-EYOKLTMF.js → chunk-SRF2PJNW.js} +17 -3
  80. package/dist/chunk-SST6Z5JA.js +80 -0
  81. package/dist/chunk-STBPMHSX.js +2456 -0
  82. package/dist/chunk-T6YILFSB.js +80 -0
  83. package/dist/chunk-TZTZS7QK.js +227 -0
  84. package/dist/chunk-UOV2BYIW.js +107 -0
  85. package/dist/{chunk-Q3RUPKEJ.js → chunk-V4RXGQ5Q.js} +58 -189
  86. package/dist/chunk-VAKQQHWR.js +434 -0
  87. package/dist/chunk-VG7TBQIY.js +128 -0
  88. package/dist/chunk-VJWL6YS5.js +244 -0
  89. package/dist/chunk-WEH5XRJQ.js +32 -0
  90. package/dist/chunk-WMSVI4G2.js +2095 -0
  91. package/dist/chunk-WVO7V2QY.js +797 -0
  92. package/dist/chunk-X4RCMKVQ.js +641 -0
  93. package/dist/chunk-X75S7HFS.js +374 -0
  94. package/dist/chunk-XN3L4EYL.js +46 -0
  95. package/dist/{chunk-RDLVBZEO.js → chunk-YCWGATWI.js} +6 -4
  96. package/dist/chunk-YHZX5GEU.js +193 -0
  97. package/dist/chunk-YXLYO42X.js +91 -0
  98. package/dist/{chunk-NMOX6HFD.js → chunk-ZDOOVTXZ.js} +29 -77
  99. package/dist/chunk-ZI647VB5.js +37 -0
  100. package/dist/{chunk-C4PTHK7P.js → chunk-ZWLZP4ZT.js} +5 -5
  101. package/dist/cli/index.js +62 -54
  102. package/dist/clio-4LY5K2AC.js +25 -0
  103. package/dist/code-nav-7AX6FYE6.js +600 -0
  104. package/dist/codewiki/build-worker.js +66 -0
  105. package/dist/compile-cache-CVJMMODC.js +18 -0
  106. package/dist/{components-DMAOEKFB.js → components-KELWS457.js} +11 -6
  107. package/dist/{config-IRUQ7SE4.js → config-GTLUW2PR.js} +92 -55
  108. package/dist/configure-R6A64DHX.js +42 -0
  109. package/dist/context-5VKGUVJJ.js +866 -0
  110. package/dist/{context-3KWFLHJG.js → context-JFZEJ7W5.js} +15 -13
  111. package/dist/{context-5RADCKTR.js → context-RW5HC47S.js} +71 -35
  112. package/dist/{context-clear-7TSNPAAI.js → context-clear-6ZHBAZZT.js} +54 -28
  113. package/dist/{context-index-W4RLWOQH.js → context-index-BZ4UYMTC.js} +30 -24
  114. package/dist/dispatch-runner-VKBRCWQC.js +1997 -0
  115. package/dist/{docs-5AWSPS37.js → docs-2C2LTVT2.js} +23 -10
  116. package/dist/{doctor-UC5NAJYQ.js → doctor-KI767GSN.js} +27 -17
  117. package/dist/{eval-U6TJHRLX.js → eval-XSSNATB4.js} +29 -16
  118. package/dist/{evidence-YEGUW4L3.js → evidence-UA6AWDQQ.js} +46 -26
  119. package/dist/{evolve-TXARCTPG.js → evolve-QNTFGV6Z.js} +45 -25
  120. package/dist/{extensions-OZFJ3A3G.js → extensions-QVDOHDGJ.js} +16 -7
  121. package/dist/{fleet-6G3DHNYE.js → fleet-Q7UOMUSG.js} +163 -54
  122. package/dist/{fleet-preflight-DSNT37JK.js → fleet-preflight-DDN536IT.js} +7 -4
  123. package/dist/{init-KZ5QTF6M.js → init-WBB65ZHQ.js} +69 -32
  124. package/dist/{memory-73ESV5YC.js → memory-MD3O64RI.js} +48 -27
  125. package/dist/{models-A4PVNWJK.js → models-BZU34YWD.js} +39 -25
  126. package/dist/monitor-MEQA5C3I.js +661 -0
  127. package/dist/{chunk-FCIH3BIZ.js → orchestrator-CGFKEP27.js} +11832 -8687
  128. package/dist/{paths-C4H6IV77.js → paths-UXLN5YYZ.js} +10 -5
  129. package/dist/{preload-6WVMHX3A.js → preload-P6DGH2PZ.js} +2 -2
  130. package/dist/{reset-BGW6OGMV.js → reset-L2FQEE3E.js} +16 -10
  131. package/dist/{run-YTPEYQOH.js → run-IV4Q6RLN.js} +101 -61
  132. package/dist/{share-YIFFV4NQ.js → share-S5BZQC5I.js} +15 -8
  133. package/dist/{skills-2V6RA3OQ.js → skills-LQEKRDTN.js} +34 -14
  134. package/dist/{skills-eval-S2TVJO4F.js → skills-eval-3DC4HEWS.js} +70 -34
  135. package/dist/steer-GGWFUJUD.js +77 -0
  136. package/dist/{targets-TYXLPB23.js → targets-C4SSGQOB.js} +43 -27
  137. package/dist/terminal-lease-IT5JW2NR.js +395 -0
  138. package/dist/{trace-GGOJ6Q6Z.js → trace-PNCASAXC.js} +41 -16
  139. package/dist/{chunk-N6F52NLF.js → tree-sitter-HGKH6LG4.js} +28 -2306
  140. package/dist/{uninstall-LLLT4F4W.js → uninstall-FZCQCDKC.js} +10 -5
  141. package/dist/{upgrade-33G2LMM5.js → upgrade-7TT7SQ3G.js} +45 -25
  142. package/dist/{usage-ZAFSXKKG.js → usage-GV4PKT3M.js} +62 -31
  143. package/dist/verify-G6V4D2G7.js +716 -0
  144. package/dist/web-fetch-2YHJ3KTG.js +638 -0
  145. package/dist/{wiki-generate-NUQCVOQ3.js → wiki-generate-DQF6Z66B.js} +74 -34
  146. package/dist/worker/entry.js +221 -36
  147. package/dist/workspace-G4ZWUIPR.js +22 -0
  148. package/docs/README.md +22 -17
  149. package/docs/acp.md +168 -16
  150. package/docs/alcf-provider.md +1 -1
  151. package/docs/architecture.md +136 -7
  152. package/docs/artifact-versions.md +1 -1
  153. package/docs/built-in-agents.md +1 -1
  154. package/docs/capacity-and-scheduling.md +1 -1
  155. package/docs/commands-and-modes.md +114 -71
  156. package/docs/config-knobs-audit.md +1 -3
  157. package/docs/configuration-and-targets.md +174 -46
  158. package/docs/context-engine.md +29 -6
  159. package/docs/development-pipeline.md +26 -1
  160. package/docs/dispatch-architecture-rationale.md +1 -1
  161. package/docs/documentation-coverage.md +2 -2
  162. package/docs/documentation-guide.md +1 -1
  163. package/docs/environment-variables.md +13 -5
  164. package/docs/eval-runner.md +1 -1
  165. package/docs/evals-internal.md +1 -1
  166. package/docs/evidence-and-memory.md +6 -2
  167. package/docs/evolution.md +2 -2
  168. package/docs/exit-codes-and-output.md +15 -9
  169. package/docs/extensions-and-sharing.md +9 -9
  170. package/docs/fleet-dispatch.md +7 -5
  171. package/docs/git-commit-provenance.md +120 -0
  172. package/docs/glossary.md +1 -1
  173. package/docs/installation-and-lifecycle.md +34 -27
  174. package/docs/middleware-and-components.md +1 -1
  175. package/docs/model-catalog.md +45 -14
  176. package/docs/observability.md +8 -5
  177. package/docs/performance-methodology.md +491 -0
  178. package/docs/pi-boundary.md +72 -0
  179. package/docs/proactive-memory.md +3 -3
  180. package/docs/prompt-envelope-and-tools.md +24 -3
  181. package/docs/provider-adapter-cookbook.md +57 -4
  182. package/docs/release-cut-checklist.md +129 -115
  183. package/docs/safety-model.md +9 -5
  184. package/docs/scientific-validation.md +3 -3
  185. package/docs/session-lifecycle.md +55 -12
  186. package/docs/skills-marketplace.md +12 -8
  187. package/docs/time-conventions.md +1 -1
  188. package/docs/tool-usage.md +3 -3
  189. package/docs/trace-store.md +1 -1
  190. package/docs/troubleshooting.md +10 -7
  191. package/docs/tui-design.md +47 -10
  192. package/docs/worker-dispatch-mechanics.md +1 -1
  193. package/package.json +19 -22
  194. package/skills/coding/ast-grep/SKILL.md +136 -0
  195. package/skills/coding/ast-grep/evals.md +56 -0
  196. package/skills/coding/ast-grep/references/rule_reference.md +297 -0
  197. package/skills/coding/coding-standards/SKILL.md +113 -0
  198. package/skills/coding/coding-standards/evals.md +34 -0
  199. package/skills/coding/prototype/SKILL.md +86 -0
  200. package/skills/coding/prototype/evals.md +42 -0
  201. package/skills/coding/prototype/references/LOGIC.md +67 -0
  202. package/skills/coding/prototype/references/UI.md +112 -0
  203. package/skills/coding/tdd/SKILL.md +101 -0
  204. package/skills/coding/tdd/evals.md +41 -0
  205. package/skills/coding/tdd/references/mocking.md +59 -0
  206. package/skills/coding/tdd/references/tests.md +77 -0
  207. package/skills/context/context-handoff/SKILL.md +126 -0
  208. package/skills/context/context-handoff/evals.md +57 -0
  209. package/skills/context/context-handoff/scripts/new-handoff.sh +26 -0
  210. package/skills/context/context-prime/SKILL.md +95 -0
  211. package/skills/context/context-prime/evals.md +54 -0
  212. package/skills/meta/clio-dev/SKILL.md +91 -0
  213. package/skills/meta/clio-dev/evals.md +45 -0
  214. package/skills/meta/clio-test/SKILL.md +130 -0
  215. package/skills/meta/clio-test/evals.md +43 -0
  216. package/skills/meta/clio-test/references/harness.md +97 -0
  217. package/skills/meta/clio-test/references/test-map.md +59 -0
  218. package/skills/meta/credentials/SKILL.md +125 -0
  219. package/skills/meta/credentials/evals.md +104 -0
  220. package/skills/meta/find-skills/SKILL.md +72 -0
  221. package/skills/meta/find-skills/evals.md +47 -0
  222. package/skills/meta/herdr/SKILL.md +127 -0
  223. package/skills/meta/herdr/evals.md +38 -0
  224. package/skills/meta/skill-craft/SKILL.md +102 -0
  225. package/skills/meta/skill-craft/evals.md +41 -0
  226. package/skills/planning/architecture/SKILL.md +129 -0
  227. package/skills/planning/architecture/evals.md +36 -0
  228. package/skills/planning/backlog/SKILL.md +90 -0
  229. package/skills/planning/backlog/evals.md +43 -0
  230. package/skills/planning/prd/SKILL.md +82 -0
  231. package/skills/planning/prd/evals.md +49 -0
  232. package/skills/planning/product-intent/SKILL.md +112 -0
  233. package/skills/planning/product-intent/evals.md +36 -0
  234. package/skills/planning/tech-spec/SKILL.md +115 -0
  235. package/skills/planning/tech-spec/evals.md +47 -0
  236. package/skills/registry.yaml +136 -0
  237. package/skills/research/arxiv-literature/SKILL.md +104 -0
  238. package/skills/research/arxiv-literature/evals.md +58 -0
  239. package/skills/research/experiment-protocol/SKILL.md +122 -0
  240. package/skills/research/experiment-protocol/evals.md +91 -0
  241. package/skills/research/scientific-debugging/SKILL.md +119 -0
  242. package/skills/research/scientific-debugging/evals.md +138 -0
  243. package/skills/research/scientific-modernization/SKILL.md +138 -0
  244. package/skills/research/scientific-modernization/evals.md +84 -0
  245. package/skills/workflow/design-council/SKILL.md +139 -0
  246. package/skills/workflow/design-council/evals.md +97 -0
  247. package/skills/workflow/grill-me/SKILL.md +186 -0
  248. package/skills/workflow/grill-me/evals.md +78 -0
  249. package/skills/workflow/workflow-distiller/SKILL.md +136 -0
  250. package/skills/workflow/workflow-distiller/evals.md +107 -0
  251. package/src/cli/acp.ts +31 -4
  252. package/src/cli/clio.ts +68 -6
  253. package/src/cli/config-inspect.ts +28 -22
  254. package/src/cli/configure.ts +47 -9
  255. package/src/cli/context-clear.ts +2 -2
  256. package/src/cli/context-index.ts +21 -23
  257. package/src/cli/context.ts +13 -8
  258. package/src/cli/default-target.ts +9 -17
  259. package/src/cli/docs.ts +11 -5
  260. package/src/cli/evidence.ts +4 -1
  261. package/src/cli/extensions.ts +10 -1
  262. package/src/cli/fleet.ts +47 -6
  263. package/src/cli/index.ts +55 -26
  264. package/src/cli/memory.ts +3 -1
  265. package/src/cli/models.ts +1 -1
  266. package/src/cli/modes/json-stream.ts +37 -1
  267. package/src/cli/modes/print.ts +24 -9
  268. package/src/cli/run.ts +2 -2
  269. package/src/cli/skills-eval.ts +23 -8
  270. package/src/cli/skills.ts +19 -4
  271. package/src/cli/targets.ts +4 -0
  272. package/src/cli/text-layout.ts +15 -5
  273. package/src/cli/trace.ts +62 -14
  274. package/src/cli/upgrade.ts +18 -2
  275. package/src/cli/usage.ts +10 -3
  276. package/src/cli/wiki-generate.ts +2 -1
  277. package/src/core/agent-environment.ts +7 -0
  278. package/src/core/bash-exec.ts +72 -1
  279. package/src/core/boot-trace.ts +9 -4
  280. package/src/core/bus-events.ts +20 -4
  281. package/src/core/commit-attribution.ts +157 -0
  282. package/src/core/compile-cache.ts +159 -0
  283. package/src/core/config.ts +131 -2
  284. package/src/core/defaults.ts +39 -5
  285. package/src/core/domain-loader.ts +12 -5
  286. package/src/core/git-commit-attribution.ts +362 -0
  287. package/src/core/incomplete-installation.ts +45 -0
  288. package/src/core/response-schema.ts +1 -1
  289. package/src/core/safe-exec.ts +13 -1
  290. package/src/core/settings-layers.ts +155 -21
  291. package/src/core/skill-activation.ts +1 -1
  292. package/src/core/startup-timer.ts +3 -3
  293. package/src/core/state-file-lock.ts +13 -1
  294. package/src/core/termination.ts +78 -5
  295. package/src/domains/config/classify.ts +15 -3
  296. package/src/domains/config/extension.ts +19 -13
  297. package/src/domains/config/index.ts +10 -0
  298. package/src/domains/config/keybindings.ts +42 -6
  299. package/src/domains/context/bootstrap-prompt.ts +1 -1
  300. package/src/domains/context/bootstrap.ts +111 -18
  301. package/src/domains/context/clear.ts +16 -11
  302. package/src/domains/context/clio-md.ts +111 -9
  303. package/src/domains/context/codewiki/artifact.ts +400 -0
  304. package/src/domains/context/codewiki/build-worker-protocol.ts +24 -0
  305. package/src/domains/context/codewiki/build-worker.ts +54 -0
  306. package/src/domains/context/codewiki/coordinator.ts +182 -0
  307. package/src/domains/context/codewiki/indexer.ts +59 -144
  308. package/src/domains/context/codewiki/paths.ts +67 -0
  309. package/src/domains/context/codewiki/schema.ts +80 -0
  310. package/src/domains/context/codewiki/tree-sitter.ts +1 -1
  311. package/src/domains/context/contract.ts +11 -5
  312. package/src/domains/context/extension.ts +94 -143
  313. package/src/domains/context/fingerprint.ts +3 -1
  314. package/src/domains/context/index.ts +12 -22
  315. package/src/domains/context/project-metadata.ts +19 -0
  316. package/src/domains/context/prompt-context.ts +9 -10
  317. package/src/domains/context/refresh.ts +29 -21
  318. package/src/domains/context/runtime.ts +17 -0
  319. package/src/domains/context/wiki/generate.ts +39 -34
  320. package/src/domains/context/wiki/plan.ts +1 -1
  321. package/src/domains/context/wiki/prompts.ts +21 -8
  322. package/src/domains/dispatch/code-step.ts +20 -1
  323. package/src/domains/dispatch/extension.ts +158 -21
  324. package/src/domains/dispatch/failure-classification.ts +6 -0
  325. package/src/domains/dispatch/fleet-commit-attribution.ts +56 -0
  326. package/src/domains/dispatch/orphan-recovery.ts +50 -8
  327. package/src/domains/dispatch/receipt-integrity.ts +5 -0
  328. package/src/domains/dispatch/state.ts +31 -6
  329. package/src/domains/dispatch/transport.ts +2 -1
  330. package/src/domains/dispatch/types.ts +14 -0
  331. package/src/domains/dispatch/worker-spawn.ts +21 -2
  332. package/src/domains/eval/metrics/context.ts +1 -1
  333. package/src/domains/eval/types.ts +0 -1
  334. package/src/domains/evidence/build.ts +41 -1
  335. package/src/domains/lifecycle/migrations/2026-08-18-lmstudio-runtime-id.ts +52 -0
  336. package/src/domains/lifecycle/migrations/index.ts +24 -4
  337. package/src/domains/middleware/hooks-io.ts +12 -0
  338. package/src/domains/middleware/skills-reminder.ts +30 -15
  339. package/src/domains/prompts/compiler.ts +142 -84
  340. package/src/domains/prompts/contract.ts +18 -2
  341. package/src/domains/prompts/extension.ts +39 -7
  342. package/src/domains/prompts/fragment-loader.ts +0 -1
  343. package/src/domains/prompts/fragments/identity/clio.md +2 -4
  344. package/src/domains/prompts/fragments/identity/docs-routing.md +10 -0
  345. package/src/domains/prompts/fragments/identity/self-awareness.md +1 -45
  346. package/src/domains/prompts/fragments/operating/contract.md +4 -50
  347. package/src/domains/prompts/fragments/operating/delegation.md +42 -0
  348. package/src/domains/prompts/fragments/operating/skills.md +26 -0
  349. package/src/domains/prompts/fragments/operating/worker.md +16 -0
  350. package/src/domains/prompts/fragments/safety/auto-edit.md +5 -5
  351. package/src/domains/prompts/fragments/safety/full-auto.md +3 -3
  352. package/src/domains/prompts/fragments/safety/read-only.md +4 -4
  353. package/src/domains/prompts/fragments/safety/suggest.md +2 -2
  354. package/src/domains/prompts/fragments/wiki/page.md +10 -0
  355. package/src/domains/prompts/fragments/wiki/plan.md +10 -0
  356. package/src/domains/prompts/preload.ts +3 -3
  357. package/src/domains/providers/auth/api-key.ts +1 -1
  358. package/src/domains/providers/auth/backend-file.ts +20 -10
  359. package/src/domains/providers/auth/backend-memory.ts +59 -4
  360. package/src/domains/providers/auth/boot-status.ts +65 -0
  361. package/src/domains/providers/auth/oauth.ts +2 -1
  362. package/src/domains/providers/auth/storage.ts +97 -38
  363. package/src/domains/providers/capabilities.ts +12 -4
  364. package/src/domains/providers/contract.ts +15 -4
  365. package/src/domains/providers/extension.ts +18 -6
  366. package/src/domains/providers/model-runtime-capabilities.ts +15 -4
  367. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +118 -35
  368. package/src/domains/providers/plugins.ts +5 -3
  369. package/src/domains/providers/probe/fingerprint.ts +25 -5
  370. package/src/domains/providers/registry.ts +31 -10
  371. package/src/domains/providers/runtimes/boot-manifest.ts +55 -0
  372. package/src/domains/providers/runtimes/builtins.ts +2 -2
  373. package/src/domains/providers/runtimes/common/lmstudio-http.ts +423 -0
  374. package/src/domains/providers/runtimes/common/local-synth.ts +6 -7
  375. package/src/domains/providers/runtimes/local-native/lmstudio.ts +241 -0
  376. package/src/domains/providers/support.ts +6 -3
  377. package/src/domains/providers/types/local-model-quirks.ts +7 -9
  378. package/src/domains/providers/types/runtime-descriptor.ts +12 -1
  379. package/src/domains/providers/types/target-descriptor.ts +22 -0
  380. package/src/domains/resources/contract.ts +0 -1
  381. package/src/domains/resources/extension.ts +1 -3
  382. package/src/domains/resources/loader.ts +3 -4
  383. package/src/domains/resources/prompts/loader.ts +16 -2
  384. package/src/domains/resources/prompts/substitute.ts +1 -65
  385. package/src/domains/resources/skills/content-hash.ts +2 -0
  386. package/src/domains/resources/skills/install.ts +17 -0
  387. package/src/domains/resources/skills/loader.ts +17 -10
  388. package/src/domains/resources/skills/marketplace.ts +55 -9
  389. package/src/domains/safety/action-classifier.ts +4 -2
  390. package/src/domains/safety/audit.ts +8 -2
  391. package/src/domains/safety/extension.ts +1 -1
  392. package/src/domains/session/compaction/branch-summary.ts +3 -2
  393. package/src/domains/session/compaction/cut-point.ts +2 -1
  394. package/src/domains/session/compaction/tokens.ts +2 -1
  395. package/src/domains/session/context-ledger.ts +14 -0
  396. package/src/domains/session/contract.ts +15 -0
  397. package/src/domains/session/decision-board.ts +190 -0
  398. package/src/domains/session/entries.ts +66 -3
  399. package/src/domains/session/extension.ts +93 -12
  400. package/src/domains/session/retry.ts +10 -18
  401. package/src/domains/session/session-artifacts.ts +107 -0
  402. package/src/domains/session/task-board.ts +207 -13
  403. package/src/domains/session/tree/active-path.ts +44 -5
  404. package/src/domains/session/tree/fork.ts +26 -27
  405. package/src/domains/session/tree/preview.ts +2 -2
  406. package/src/domains/session/workspace/git-probe.ts +17 -11
  407. package/src/domains/user-tasks/store.ts +297 -0
  408. package/src/engine/acp/errors.ts +96 -0
  409. package/src/engine/acp/server.ts +1728 -146
  410. package/src/engine/acp/transport.ts +135 -14
  411. package/src/engine/acp/types.ts +26 -0
  412. package/src/engine/agent.ts +3 -3
  413. package/src/engine/ai.ts +32 -27
  414. package/src/engine/alcf-oauth.ts +26 -19
  415. package/src/engine/api-registry.ts +223 -0
  416. package/src/engine/apis/index.ts +3 -7
  417. package/src/engine/apis/llamacpp-residency.ts +49 -9
  418. package/src/engine/apis/lmstudio-residency.ts +5 -21
  419. package/src/engine/apis/lmstudio.ts +243 -0
  420. package/src/engine/apis/ollama-native.ts +24 -3
  421. package/src/engine/apis/openai-completions.ts +170 -91
  422. package/src/engine/apis/residency.ts +139 -3
  423. package/src/engine/apis/types.ts +16 -0
  424. package/src/engine/env-api-keys.ts +98 -0
  425. package/src/engine/gemma-channel-filter.ts +223 -0
  426. package/src/engine/instrumented-tui.ts +192 -0
  427. package/src/engine/messages.ts +14 -0
  428. package/src/engine/models.ts +42 -0
  429. package/src/engine/oauth.ts +16 -12
  430. package/src/engine/prompt-templates.ts +1 -0
  431. package/src/engine/provider-payload.ts +16 -59
  432. package/src/engine/strip-tokenizer-sentinels.ts +1 -1
  433. package/src/engine/truncate.ts +9 -0
  434. package/src/engine/tui.ts +17 -9
  435. package/src/engine/types.ts +3 -6
  436. package/src/engine/worker-runtime-capabilities.ts +5 -0
  437. package/src/engine/worker-runtime.ts +1 -1
  438. package/src/engine/worker-tools.ts +9 -4
  439. package/src/entry/boot-options.ts +50 -0
  440. package/src/entry/orchestrator.ts +288 -150
  441. package/src/interactive/application-controller.ts +89 -2
  442. package/src/interactive/chat-loop.ts +266 -41
  443. package/src/interactive/chat-panel.ts +173 -47
  444. package/src/interactive/chat-renderer.ts +262 -72
  445. package/src/interactive/clio-editor.ts +3 -8
  446. package/src/interactive/command-fallbacks.ts +2 -2
  447. package/src/interactive/context-overlay.ts +27 -1
  448. package/src/interactive/editor-submit.ts +228 -24
  449. package/src/interactive/export-html/ansi-to-html.ts +161 -0
  450. package/src/interactive/export-html/index.ts +51 -0
  451. package/src/interactive/export-html/template.ts +45 -0
  452. package/src/interactive/export-html/tool-renderer.ts +54 -0
  453. package/src/interactive/footer/dashboard.ts +4 -0
  454. package/src/interactive/footer/notifications.ts +1 -1
  455. package/src/interactive/footer/widgets.ts +20 -2
  456. package/src/interactive/footer-panel.ts +2 -2
  457. package/src/interactive/format-time.ts +14 -2
  458. package/src/interactive/interactive-application.ts +201 -17
  459. package/src/interactive/interactive-event-projection.ts +6 -1
  460. package/src/interactive/interactive-input-runtime.ts +50 -4
  461. package/src/interactive/interactive-presentation.ts +151 -19
  462. package/src/interactive/interactive-shell.ts +268 -14
  463. package/src/interactive/interactive-slash-runtime.ts +176 -114
  464. package/src/interactive/interactive-tickers.ts +38 -7
  465. package/src/interactive/keybinding-manager.ts +1 -1
  466. package/src/interactive/layout.ts +40 -3
  467. package/src/interactive/overlay-frame.ts +1 -1
  468. package/src/interactive/overlay-general-openers.ts +58 -1
  469. package/src/interactive/overlay-key-routing.ts +3 -0
  470. package/src/interactive/overlay-lifecycle.ts +13 -0
  471. package/src/interactive/overlay-permission-lifecycle.ts +2 -1
  472. package/src/interactive/overlay-session-lifecycle.ts +69 -12
  473. package/src/interactive/overlays/decisions.ts +300 -0
  474. package/src/interactive/overlays/help-reference.ts +15 -10
  475. package/src/interactive/overlays/model-selector.ts +34 -16
  476. package/src/interactive/overlays/session-selector.ts +18 -0
  477. package/src/interactive/overlays/settings.ts +105 -17
  478. package/src/interactive/overlays/skills-hub.ts +4 -4
  479. package/src/interactive/overlays/tree-selector.ts +41 -6
  480. package/src/interactive/render-trace.ts +499 -90
  481. package/src/interactive/renderers/compaction-summary.ts +2 -2
  482. package/src/interactive/renderers/diff.ts +115 -104
  483. package/src/interactive/renderers/mermaid.ts +53 -0
  484. package/src/interactive/renderers/tool-execution.ts +386 -133
  485. package/src/interactive/renderers/worker-entry.ts +20 -4
  486. package/src/interactive/session-switch-settlement.ts +10 -0
  487. package/src/interactive/slash-autocomplete.ts +6 -114
  488. package/src/interactive/slash-commands.ts +135 -47
  489. package/src/interactive/slash-spec.ts +9 -38
  490. package/src/interactive/status/controller.ts +5 -1
  491. package/src/interactive/stdout-backpressure.ts +99 -0
  492. package/src/interactive/stream-pacer.ts +530 -0
  493. package/src/interactive/stream-pacing-policy.ts +66 -0
  494. package/src/interactive/tasks-overlay.ts +368 -14
  495. package/src/interactive/terminal-lease.ts +485 -0
  496. package/src/interactive/theme/tokens.ts +1 -1
  497. package/src/interactive/turn-context.ts +4 -3
  498. package/src/interactive/turn-persistence.ts +30 -13
  499. package/src/interactive/turn-queues.ts +12 -0
  500. package/src/interactive/turn-recovery.ts +25 -8
  501. package/src/interactive/turn-runtime.ts +79 -12
  502. package/src/interactive/turn-state.ts +10 -0
  503. package/src/interactive/view/artifacts.ts +114 -4
  504. package/src/interactive/view/view-overlay.ts +3 -0
  505. package/src/interactive/welcome-dashboard.ts +17 -16
  506. package/src/interactive/worker-receipts.ts +52 -3
  507. package/src/interactive/worker-stream.ts +5 -1
  508. package/src/tools/agent-tools.ts +23 -3
  509. package/src/tools/artifact.ts +2 -2
  510. package/src/tools/ask-user.ts +23 -13
  511. package/src/tools/bash.ts +30 -2
  512. package/src/tools/bootstrap.ts +34 -431
  513. package/src/tools/builtin-tool-catalog.ts +265 -0
  514. package/src/tools/codewiki/code-nav-surface.ts +29 -0
  515. package/src/tools/codewiki/code-nav.ts +8 -22
  516. package/src/tools/codewiki/shared.ts +41 -38
  517. package/src/tools/context/docs-engine.ts +14 -3
  518. package/src/tools/context/index.ts +107 -28
  519. package/src/tools/context/surface.ts +19 -0
  520. package/src/tools/core-bootstrap.ts +168 -0
  521. package/src/tools/credential-present.ts +5 -5
  522. package/src/tools/dispatch-admission.ts +533 -0
  523. package/src/tools/dispatch-background.ts +54 -0
  524. package/src/tools/dispatch-event-text.ts +6 -0
  525. package/src/tools/dispatch-plan.ts +9 -4
  526. package/src/tools/dispatch-run-events.ts +238 -0
  527. package/src/tools/dispatch-runner.ts +2370 -0
  528. package/src/tools/dispatch-scout-admission.ts +295 -0
  529. package/src/tools/dispatch-types.ts +77 -0
  530. package/src/tools/dispatch.ts +67 -3161
  531. package/src/tools/find.ts +4 -2
  532. package/src/tools/grep.ts +2 -2
  533. package/src/tools/lazy-tool.ts +60 -0
  534. package/src/tools/ledger.ts +3 -3
  535. package/src/tools/monitor-surface.ts +36 -0
  536. package/src/tools/monitor.ts +2 -32
  537. package/src/tools/observers.ts +2 -2
  538. package/src/tools/registry.ts +39 -27
  539. package/src/tools/safe-exec.ts +2 -2
  540. package/src/tools/steer-surface.ts +17 -0
  541. package/src/tools/steer.ts +2 -13
  542. package/src/tools/tasks.ts +108 -11
  543. package/src/tools/truncate.ts +25 -184
  544. package/src/tools/verify/frontend.ts +3 -1
  545. package/src/tools/verify/index.ts +3 -38
  546. package/src/tools/verify/surface.ts +46 -0
  547. package/src/tools/web-fetch-surface.ts +23 -0
  548. package/src/tools/web-fetch.ts +2 -20
  549. package/src/tools/write.ts +7 -2
  550. package/src/worker/entry.ts +39 -2
  551. package/src/worker/spec-contract.ts +26 -5
  552. package/dist/chunk-7SS2CTV2.js +0 -61361
  553. package/dist/chunk-DKGKUHFA.js +0 -924
  554. package/dist/chunk-GEP36Y4X.js +0 -12796
  555. package/dist/chunk-XYWBQRDM.js +0 -137
  556. package/dist/clio-BZVGEUFJ.js +0 -58
  557. package/dist/configure-S7S6F6CL.js +0 -32
  558. package/docs/html/agents_blueprint.html +0 -936
  559. package/docs/html/alcf_blueprint.html +0 -324
  560. package/docs/html/architecture_blueprint.html +0 -850
  561. package/docs/html/commands_blueprint.html +0 -939
  562. package/docs/html/config_knobs_audit_blueprint.html +0 -178
  563. package/docs/html/configuration_blueprint.html +0 -1080
  564. package/docs/html/context_blueprint.html +0 -603
  565. package/docs/html/documentation_blueprint.html +0 -832
  566. package/docs/html/environment_blueprint.html +0 -404
  567. package/docs/html/eval_blueprint.html +0 -743
  568. package/docs/html/evals_internal_blueprint.html +0 -190
  569. package/docs/html/evolution_blueprint.html +0 -674
  570. package/docs/html/extensions_blueprint.html +0 -2065
  571. package/docs/html/fleet_dispatch_blueprint.html +0 -286
  572. package/docs/html/index.html +0 -919
  573. package/docs/html/lifecycle_blueprint.html +0 -723
  574. package/docs/html/memory_blueprint.html +0 -699
  575. package/docs/html/middleware_blueprint.html +0 -664
  576. package/docs/html/models_blueprint.html +0 -2366
  577. package/docs/html/observability_blueprint.html +0 -683
  578. package/docs/html/provider_adapter_blueprint.html +0 -245
  579. package/docs/html/safety_blueprint.html +0 -1386
  580. package/docs/html/shared.css +0 -571
  581. package/docs/html/shared.js +0 -143
  582. package/docs/html/skills_blueprint.html +0 -671
  583. package/docs/html/soak_blueprint.html +0 -182
  584. package/docs/html/tool_usage_blueprint.html +0 -350
  585. package/docs/html/tools_blueprint.html +0 -2249
  586. package/docs/html/trace_blueprint.html +0 -235
  587. package/docs/html/tui_design_blueprint.html +0 -374
  588. package/docs/html/validation_blueprint.html +0 -961
  589. package/docs/html/worker_dispatch_blueprint.html +0 -231
  590. package/src/core/release.ts +0 -2
  591. package/src/domains/providers/runtimes/common/lmstudio-logger.ts +0 -32
  592. package/src/domains/providers/runtimes/local-native/lmstudio-native.ts +0 -491
  593. package/src/engine/apis/lmstudio-native.ts +0 -1438
  594. package/src/engine/apis/thinking-replay.ts +0 -11
  595. package/src/tools/string-enum.ts +0 -15
@@ -1,9 +1,9 @@
1
- import { runBashCommand } from "../core/bash-exec.js";
1
+ import { combineBashOutput, runBashCommand } from "../core/bash-exec.js";
2
+ import type { PendingSkillRequest } from "../core/skill-activation.js";
2
3
  import type { DispatchContract } from "../domains/dispatch/contract.js";
3
4
  import type { SessionContract, SessionEntry } from "../domains/session/index.js";
4
5
  import type { ChatLoop } from "./chat-loop.js";
5
6
  import type { ChatPanel } from "./chat-panel.js";
6
- import { renderBashExecutionEntry } from "./chat-renderer.js";
7
7
  import { bashExecutionEntryInput, parseEditorBashCommand } from "./editor-bash.js";
8
8
  import {
9
9
  formatSteerCandidates,
@@ -12,7 +12,8 @@ import {
12
12
  resolveSteerTarget,
13
13
  } from "./editor-steer.js";
14
14
  import { type ExternalEditResult, editTextExternally, resolveExternalEditor } from "./external-editor.js";
15
- import { parseSlashCommand, type RunIo, type SlashCommand } from "./slash-commands.js";
15
+ import { type BashTranscriptExecution, renderBashTranscriptExecution } from "./renderers/tool-execution.js";
16
+ import { parseSlashCommand, type RunIo, type SlashCommand, type SlashCommandDispatchResult } from "./slash-commands.js";
16
17
 
17
18
  const EDITOR_BASH_TIMEOUT_MS = 300_000;
18
19
 
@@ -26,13 +27,8 @@ const EDITOR_BASH_TIMEOUT_MS = 300_000;
26
27
  * operator can see which flag the usage line is complaining about and fix that
27
28
  * one token.
28
29
  *
29
- * `unknown-command` used to be restored on the same reasoning and it does not
30
- * hold. The token matched no command at all, so there is nothing to correct
31
- * against, and the restored text has no cursor placement of its own: the next
32
- * keystrokes land in front of the leftover `/token`, which no longer parses as
33
- * a command, so the whole concatenation goes to the model as a chat message the
34
- * operator never wrote. An empty line after "is not a command" costs a retype
35
- * and says exactly what happened.
30
+ * `unknown-command` cannot be decided here: a prompt template can still claim
31
+ * it during dispatch. Its post-dispatch verdict is handled at the call site.
36
32
  *
37
33
  * A command that ran and failed has done work, and chat text belongs to the
38
34
  * transcript, so both also leave the line empty.
@@ -44,6 +40,10 @@ function isRejectedCommand(command: SlashCommand): boolean {
44
40
  export interface EditorSubmitExpansion {
45
41
  text: string;
46
42
  images: ReadonlyArray<unknown>;
43
+ /** Paths the draft referenced inline; the idle path hands them to the chat loop for rule scoping. */
44
+ workingContextPaths?: ReadonlyArray<string>;
45
+ /** Skill requests parsed out of the draft; the idle path hands them to the chat loop as the pending-skill policy. */
46
+ pendingSkillRequests?: ReadonlyArray<PendingSkillRequest>;
47
47
  }
48
48
 
49
49
  export interface EditorSubmitEditor {
@@ -58,13 +58,18 @@ export interface EditorSubmitUi {
58
58
  requestRender(force?: boolean): void;
59
59
  }
60
60
 
61
- type EditorSubmitChat = Pick<ChatLoop, "clearQueuedFollowUps" | "isStreaming" | "queueFollowUp">;
61
+ type EditorSubmitChat = Pick<
62
+ ChatLoop,
63
+ "clearQueuedFollowUps" | "interruptRefusal" | "isStreaming" | "queueFollowUp" | "submit" | "whenSettled"
64
+ >;
62
65
  type EditorSubmitDispatch = Pick<DispatchContract, "snapshot" | "steer">;
63
66
  type EditorSubmitSession = Pick<SessionContract, "appendEntry" | "current" | "tree">;
64
67
 
65
68
  export interface EditorSubmitSessionTranscript {
66
69
  ensureSessionForLocalEntry(): void;
67
70
  refreshChatContextFromSession(leafTurnId: string | null): void;
71
+ /** Count a prompt the operator submitted; the idle path does this through the slash runtime. */
72
+ recordSubmittedTurn(): void;
68
73
  }
69
74
 
70
75
  export interface EditorSubmitDeps {
@@ -76,7 +81,10 @@ export interface EditorSubmitDeps {
76
81
  session?: EditorSubmitSession;
77
82
  sessionTranscript: EditorSubmitSessionTranscript;
78
83
  chatPanel: Pick<ChatPanel, "appendReplayBlock">;
79
- dispatchCommand: (text: string) => void;
84
+ beforeSemanticBoundary?: (reason: string) => void;
85
+ settleVisibleFrame?: (reason: string) => Promise<void>;
86
+ dispatchCommand: (text: string) => SlashCommandDispatchResult;
87
+ dispatchCommandAsync?: (text: string, signal?: AbortSignal) => Promise<void>;
80
88
  /** Idempotently collapses a fresh-session launchpad before any handler can append output. */
81
89
  collapseLaunchpadBeforeSubmit?: () => void;
82
90
  expandSubmit: (text: string) => Promise<EditorSubmitExpansion>;
@@ -93,15 +101,27 @@ export interface EditorSubmitController {
93
101
  openExternalEditorForInput(): void;
94
102
  handleEditorSteerMention(mention: { target: string; text: string }): boolean;
95
103
  submitEditorText(text: string): void;
104
+ /** Admit an immutable boot record without reading or mutating the live draft. */
105
+ admitCapturedText(text: string, signal?: AbortSignal): Promise<void>;
96
106
  queueFollowUpFromEditor(): void;
107
+ /**
108
+ * Interrupt mode: cancel the active run and deliver the draft now. Idle, it
109
+ * is a plain send. The chat loop owns cancel → settle → submit and the two
110
+ * refusals (attached dispatch, parked permission ask), which degrade the
111
+ * message to next-slot delivery with a notice.
112
+ */
113
+ interruptFromEditor(): void;
97
114
  restoreQueuedFollowUpsToEditor(): void;
98
115
  hasActiveEditorBash(): boolean;
99
116
  cancelActiveEditorBash(): boolean;
100
117
  }
101
118
 
119
+ type EditorSteerSubmission = "unhandled" | "accepted" | "rejected";
120
+
102
121
  /** Owns editor submission and the one local bash process attached to it. */
103
122
  export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubmitController {
104
123
  let activeEditorBash: AbortController | null = null;
124
+ let activeEditorBashSettlement: Promise<void> | null = null;
105
125
 
106
126
  const runEditorBash = (text: string): boolean => {
107
127
  const parsed = parseEditorBashCommand(text);
@@ -126,13 +146,39 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
126
146
  activeEditorBash = null;
127
147
  return true;
128
148
  }
149
+ const startedAt = performance.now();
150
+ const execution: BashTranscriptExecution = {
151
+ command: parsed.command,
152
+ output: "",
153
+ running: true,
154
+ totalBytes: 0,
155
+ excludeFromContext: parsed.excludeFromContext,
156
+ };
157
+ deps.chatPanel.appendReplayBlock(
158
+ (width) =>
159
+ renderBashTranscriptExecution(
160
+ {
161
+ ...execution,
162
+ ...(execution.running ? { elapsedMs: Math.max(0, performance.now() - startedAt) } : {}),
163
+ },
164
+ width,
165
+ ),
166
+ () => execution.running,
167
+ );
168
+ deps.ui.requestRender();
129
169
 
130
- void (async () => {
170
+ let settlement!: Promise<void>;
171
+ settlement = (async () => {
131
172
  try {
132
173
  const result = await (deps.runBash ?? runBashCommand)(parsed.command, {
133
174
  cwd: deps.getCwd?.() ?? process.cwd(),
134
175
  timeoutMs: EDITOR_BASH_TIMEOUT_MS,
135
176
  signal: abort.signal,
177
+ onUpdate: (progress) => {
178
+ execution.output = combineBashOutput(progress);
179
+ execution.totalBytes = progress.outputBytes;
180
+ deps.ui.requestRender();
181
+ },
136
182
  });
137
183
  const input = bashExecutionEntryInput({
138
184
  command: parsed.command,
@@ -149,17 +195,34 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
149
195
  timestamp: deps.nowIso?.() ?? new Date().toISOString(),
150
196
  } as SessionEntry);
151
197
  if (entry.kind === "bashExecution") {
152
- deps.chatPanel.appendReplayBlock((width) => renderBashExecutionEntry(entry, width));
198
+ execution.output = entry.output;
199
+ execution.running = false;
200
+ execution.exitCode = entry.exitCode;
201
+ execution.cancelled = entry.cancelled;
202
+ execution.truncated = entry.truncated;
203
+ execution.fullOutputPath = entry.fullOutputPath;
204
+ execution.totalBytes = Math.max(execution.totalBytes ?? 0, Buffer.byteLength(combineBashOutput(result), "utf8"));
153
205
  }
154
- deps.sessionTranscript.refreshChatContextFromSession(parentTurnId);
206
+ // `parentTurnId` was the leaf when the command started and stays the
207
+ // entry's anchor. The chat leaf is a different question: a prompt
208
+ // may have landed while the command ran, so restore the leaf the
209
+ // session has now, not the one captured then. Restoring the stale
210
+ // one wedged every later submit on a parent that was no longer
211
+ // the leaf.
212
+ deps.sessionTranscript.refreshChatContextFromSession(deps.session?.tree().leafId ?? parentTurnId);
155
213
  } catch (err) {
156
214
  const msg = err instanceof Error ? err.message : String(err);
215
+ execution.running = false;
216
+ execution.error = msg;
157
217
  deps.io.stderr(`[bash] ${msg}\n`);
158
218
  } finally {
159
219
  if (activeEditorBash === abort) activeEditorBash = null;
220
+ if (activeEditorBashSettlement === settlement) activeEditorBashSettlement = null;
160
221
  deps.ui.requestRender();
161
222
  }
162
223
  })();
224
+ activeEditorBashSettlement = settlement;
225
+ void settlement;
163
226
  return true;
164
227
  };
165
228
 
@@ -186,14 +249,14 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
186
249
  deps.ui.requestRender(true);
187
250
  };
188
251
 
189
- const handleEditorSteerMention = (mention: { target: string; text: string }): boolean => {
252
+ const submitEditorSteerMention = (mention: { target: string; text: string }): EditorSteerSubmission => {
190
253
  let running: RunningDispatchRef[] = [];
191
254
  try {
192
255
  running = deps.dispatch.snapshot().running.map((run) => ({ runId: run.runId, agentId: run.agentId }));
193
256
  } catch {
194
257
  running = [];
195
258
  }
196
- if (running.length === 0) return false;
259
+ if (running.length === 0) return "unhandled";
197
260
  const resolution = resolveSteerTarget(mention.target, running);
198
261
  if (resolution.kind === "match") {
199
262
  try {
@@ -203,11 +266,12 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
203
266
  `steer queued for ${resolution.run.agentId} (${resolution.run.runId}); awaiting worker acknowledgement`,
204
267
  `steer:${resolution.run.runId}`,
205
268
  );
269
+ return "accepted";
206
270
  } catch (err) {
207
271
  const msg = err instanceof Error ? err.message : String(err);
208
272
  deps.notify("error", `steer to @${mention.target} failed: ${msg}`, `steer:${mention.target}`);
273
+ return "rejected";
209
274
  }
210
- return true;
211
275
  }
212
276
  if (resolution.kind === "ambiguous") {
213
277
  deps.notify(
@@ -215,34 +279,127 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
215
279
  `@${mention.target} matches ${resolution.candidates.length} runs: ${formatSteerCandidates(resolution.candidates)}; use a runId prefix`,
216
280
  `steer:${mention.target}`,
217
281
  );
218
- return true;
282
+ return "rejected";
219
283
  }
220
284
  deps.notify(
221
285
  "warning",
222
286
  `no running dispatch matches @${mention.target}; running: ${formatSteerCandidates(running)}`,
223
287
  `steer:${mention.target}`,
224
288
  );
225
- return true;
289
+ return "rejected";
226
290
  };
227
291
 
292
+ const handleEditorSteerMention = (mention: { target: string; text: string }): boolean =>
293
+ submitEditorSteerMention(mention) !== "unhandled";
294
+
228
295
  const submitEditorText = (text: string): void => {
229
296
  const trimmed = text.trim();
230
297
  if (trimmed.length === 0) return;
231
298
  deps.collapseLaunchpadBeforeSubmit?.();
232
299
  if (parseEditorBashCommand(text)) {
233
- if (!deps.chat.isStreaming() && !activeEditorBash) deps.editor.setText("");
300
+ if (!deps.chat.isStreaming() && !activeEditorBash) {
301
+ deps.editor.addToHistory(text);
302
+ deps.editor.setText("");
303
+ } else {
304
+ // Pi Editor clears the buffer before invoking onSubmit. A command
305
+ // refused by either admission guard is still a draft, so put it back
306
+ // for the operator instead of silently discarding it.
307
+ deps.editor.setText(text);
308
+ }
234
309
  if (runEditorBash(text)) deps.ui.requestRender();
235
310
  return;
236
311
  }
237
312
  const steerMention = parseEditorSteerMention(trimmed);
238
- if (steerMention && handleEditorSteerMention(steerMention)) {
313
+ if (steerMention) {
314
+ const submission = submitEditorSteerMention(steerMention);
315
+ if (submission !== "unhandled") {
316
+ if (submission === "accepted") {
317
+ deps.editor.addToHistory(text);
318
+ deps.editor.setText("");
319
+ } else {
320
+ // Resolution and dispatch failures are correctable rejections. Pi
321
+ // has already cleared the editor, so explicitly restore the draft.
322
+ deps.editor.setText(text);
323
+ }
324
+ deps.ui.requestRender();
325
+ return;
326
+ }
327
+ }
328
+ const command = parseSlashCommand(trimmed);
329
+ if (isRejectedCommand(command)) {
330
+ deps.editor.setText(text);
331
+ deps.dispatchCommand(trimmed);
332
+ } else if (command.kind === "unknown-command") {
333
+ const result = deps.dispatchCommand(trimmed);
334
+ if (result === "rejected") {
335
+ deps.editor.setText(text);
336
+ } else {
337
+ deps.editor.addToHistory(text);
338
+ deps.editor.setText("");
339
+ }
340
+ } else {
239
341
  deps.editor.addToHistory(text);
240
342
  deps.editor.setText("");
343
+ deps.dispatchCommand(trimmed);
344
+ }
345
+ deps.ui.requestRender();
346
+ };
347
+
348
+ const awaitWithAbort = async (promise: Promise<void>, signal?: AbortSignal): Promise<void> => {
349
+ if (!signal) return await promise;
350
+ signal.throwIfAborted();
351
+ let abort: (() => void) | null = null;
352
+ try {
353
+ await Promise.race([
354
+ promise,
355
+ new Promise<never>((_resolve, reject) => {
356
+ abort = () => reject(signal.reason ?? new DOMException("aborted", "AbortError"));
357
+ signal.addEventListener("abort", abort, { once: true });
358
+ }),
359
+ ]);
360
+ } finally {
361
+ if (abort) signal.removeEventListener("abort", abort);
362
+ }
363
+ };
364
+
365
+ const admitCapturedText = async (text: string, signal?: AbortSignal): Promise<void> => {
366
+ const trimmed = text.trim();
367
+ if (trimmed.length === 0) return;
368
+ signal?.throwIfAborted();
369
+ deps.collapseLaunchpadBeforeSubmit?.();
370
+ if (parseEditorBashCommand(text)) {
371
+ while (deps.chat.isStreaming()) await awaitWithAbort(deps.chat.whenSettled(), signal);
372
+ while (activeEditorBashSettlement) await awaitWithAbort(activeEditorBashSettlement, signal);
373
+ signal?.throwIfAborted();
374
+ deps.editor.addToHistory(text);
375
+ runEditorBash(text);
241
376
  deps.ui.requestRender();
242
377
  return;
243
378
  }
244
- deps.editor.setText(isRejectedCommand(parseSlashCommand(trimmed)) ? text : "");
245
- deps.dispatchCommand(trimmed);
379
+ const steerMention = parseEditorSteerMention(trimmed);
380
+ if (steerMention) {
381
+ const submission = submitEditorSteerMention(steerMention);
382
+ if (submission !== "unhandled") {
383
+ if (submission === "rejected") {
384
+ throw new Error("queued boot steer was not admitted; preserving it for recovery");
385
+ }
386
+ deps.editor.addToHistory(text);
387
+ deps.ui.requestRender();
388
+ return;
389
+ }
390
+ }
391
+ const command = parseSlashCommand(trimmed);
392
+ if (isRejectedCommand(command)) {
393
+ signal?.throwIfAborted();
394
+ if (deps.dispatchCommandAsync) await deps.dispatchCommandAsync(trimmed, signal);
395
+ else deps.dispatchCommand(trimmed);
396
+ deps.ui.requestRender();
397
+ throw new Error("queued boot command needs correction; preserving it for recovery");
398
+ }
399
+ deps.editor.addToHistory(text);
400
+ signal?.throwIfAborted();
401
+ if (deps.dispatchCommandAsync) await deps.dispatchCommandAsync(trimmed, signal);
402
+ else deps.dispatchCommand(trimmed);
246
403
  deps.ui.requestRender();
247
404
  };
248
405
 
@@ -261,6 +418,7 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
261
418
  deps.io.stderr("[follow-up] image references cannot be queued while a response is streaming\n");
262
419
  return;
263
420
  }
421
+ deps.beforeSemanticBoundary?.("follow-up-submit");
264
422
  if (!deps.chat.queueFollowUp(submitted.text)) {
265
423
  deps.io.stderr("[follow-up] no active response to queue against\n");
266
424
  return;
@@ -274,6 +432,50 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
274
432
  });
275
433
  };
276
434
 
435
+ const interruptFromEditor = (): void => {
436
+ const text = deps.editor.getText().trim();
437
+ if (text.length === 0) return;
438
+ if (!deps.chat.isStreaming()) {
439
+ deps.editor.setText("");
440
+ submitEditorText(text);
441
+ deps.ui.requestRender();
442
+ return;
443
+ }
444
+ void (async () => {
445
+ const submitted = await deps.expandSubmit(text);
446
+ if (submitted.images.length > 0) {
447
+ deps.io.stderr("[interrupt] image references cannot be sent while a response is streaming\n");
448
+ return;
449
+ }
450
+ deps.editor.addToHistory(text);
451
+ // Same restore Esc performs: when the interrupt will really cancel the
452
+ // run, the queued steers and follow-ups come back to the editor rather
453
+ // than vanishing with the cancelled run. A refused interrupt cancels
454
+ // nothing, so the queue stays put.
455
+ const restored = deps.chat.interruptRefusal() === null ? deps.chat.clearQueuedFollowUps() : [];
456
+ deps.editor.setText(restored.join("\n\n"));
457
+ deps.ui.requestRender();
458
+ // An interrupt is a fresh prompt, so it carries what the idle path
459
+ // carries: the launchpad collapse, the submitted-turn count, and the
460
+ // expansion's working-context paths and pending skill requests. Only
461
+ // images stay behind, rejected above, as they are for a follow-up.
462
+ deps.collapseLaunchpadBeforeSubmit?.();
463
+ deps.sessionTranscript.recordSubmittedTurn();
464
+ const paths = submitted.workingContextPaths ?? [];
465
+ const skillRequests = submitted.pendingSkillRequests ?? [];
466
+ deps.beforeSemanticBoundary?.("interrupt-submit");
467
+ await deps.chat.submit(submitted.text, {
468
+ steering: "interrupt",
469
+ ...(paths.length > 0 ? { workingContextPaths: paths } : {}),
470
+ ...(skillRequests.length > 0 ? { pendingSkillRequests: skillRequests } : {}),
471
+ });
472
+ await deps.settleVisibleFrame?.("interrupt-submit-return");
473
+ })().catch((err) => {
474
+ const msg = err instanceof Error ? err.message : String(err);
475
+ deps.io.stderr(`[interrupt] ${msg}\n`);
476
+ });
477
+ };
478
+
277
479
  const restoreQueuedFollowUpsToEditor = (): void => {
278
480
  const restored = deps.chat.clearQueuedFollowUps();
279
481
  if (restored.length === 0) {
@@ -291,7 +493,9 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
291
493
  openExternalEditorForInput,
292
494
  handleEditorSteerMention,
293
495
  submitEditorText,
496
+ admitCapturedText,
294
497
  queueFollowUpFromEditor,
498
+ interruptFromEditor,
295
499
  restoreQueuedFollowUpsToEditor,
296
500
  hasActiveEditorBash: () => activeEditorBash !== null,
297
501
  cancelActiveEditorBash: () => {
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Terminal ANSI to HTML conversion adapted from pi-coding-agent 0.84.0's
3
+ * `dist/core/export-html/ansi-to-html.js`.
4
+ *
5
+ * Clio's transcript also contains OSC 133 shell-integration markers and may
6
+ * contain other non-SGR terminal controls. Those controls are discarded here;
7
+ * only SGR presentation survives as inline HTML styles.
8
+ */
9
+
10
+ const ANSI_COLORS = [
11
+ "rgb(0,0,0)",
12
+ "rgb(128,0,0)",
13
+ "rgb(0,128,0)",
14
+ "rgb(128,128,0)",
15
+ "rgb(0,0,128)",
16
+ "rgb(128,0,128)",
17
+ "rgb(0,128,128)",
18
+ "rgb(192,192,192)",
19
+ "rgb(128,128,128)",
20
+ "rgb(255,0,0)",
21
+ "rgb(0,255,0)",
22
+ "rgb(255,255,0)",
23
+ "rgb(0,0,255)",
24
+ "rgb(255,0,255)",
25
+ "rgb(0,255,255)",
26
+ "rgb(255,255,255)",
27
+ ] as const;
28
+
29
+ interface TextStyle {
30
+ fg: string | null;
31
+ bg: string | null;
32
+ bold: boolean;
33
+ dim: boolean;
34
+ italic: boolean;
35
+ underline: boolean;
36
+ }
37
+
38
+ function color256ToHex(index: number): string {
39
+ const bounded = Math.max(0, Math.min(255, index));
40
+ if (bounded < 16) return ANSI_COLORS[bounded] ?? ANSI_COLORS[0];
41
+ if (bounded < 232) {
42
+ const cubeIndex = bounded - 16;
43
+ const component = (value: number): number => (value === 0 ? 0 : 55 + value * 40);
44
+ return `rgb(${component(Math.floor(cubeIndex / 36))},${component(Math.floor((cubeIndex % 36) / 6))},${component(cubeIndex % 6)})`;
45
+ }
46
+ const gray = 8 + (bounded - 232) * 10;
47
+ return `rgb(${gray},${gray},${gray})`;
48
+ }
49
+
50
+ export function escapeHtml(text: string): string {
51
+ return text
52
+ .replace(/&/gu, "&amp;")
53
+ .replace(/</gu, "&lt;")
54
+ .replace(/>/gu, "&gt;")
55
+ .replace(/"/gu, "&quot;")
56
+ .replace(/'/gu, "&#039;");
57
+ }
58
+
59
+ function createEmptyStyle(): TextStyle {
60
+ return { fg: null, bg: null, bold: false, dim: false, italic: false, underline: false };
61
+ }
62
+
63
+ function styleToInlineCss(style: TextStyle): string {
64
+ const parts: string[] = [];
65
+ if (style.fg) parts.push(`color:${style.fg}`);
66
+ if (style.bg) parts.push(`background-color:${style.bg}`);
67
+ if (style.bold) parts.push("font-weight:bold");
68
+ if (style.dim) parts.push("opacity:0.6");
69
+ if (style.italic) parts.push("font-style:italic");
70
+ if (style.underline) parts.push("text-decoration:underline");
71
+ return parts.join(";");
72
+ }
73
+
74
+ function hasStyle(style: TextStyle): boolean {
75
+ return style.fg !== null || style.bg !== null || style.bold || style.dim || style.italic || style.underline;
76
+ }
77
+
78
+ function applySgrCode(params: number[], style: TextStyle): void {
79
+ let index = 0;
80
+ while (index < params.length) {
81
+ const code = params[index] ?? 0;
82
+ if (code === 0) Object.assign(style, createEmptyStyle());
83
+ else if (code === 1) style.bold = true;
84
+ else if (code === 2) style.dim = true;
85
+ else if (code === 3) style.italic = true;
86
+ else if (code === 4) style.underline = true;
87
+ else if (code === 22) {
88
+ style.bold = false;
89
+ style.dim = false;
90
+ } else if (code === 23) style.italic = false;
91
+ else if (code === 24) style.underline = false;
92
+ else if (code >= 30 && code <= 37) style.fg = ANSI_COLORS[code - 30] ?? null;
93
+ else if (code === 38) {
94
+ if (params[index + 1] === 5 && params[index + 2] !== undefined) {
95
+ style.fg = color256ToHex(params[index + 2] ?? 0);
96
+ index += 2;
97
+ } else if (params[index + 1] === 2 && params[index + 4] !== undefined) {
98
+ style.fg = `rgb(${params[index + 2]},${params[index + 3]},${params[index + 4]})`;
99
+ index += 4;
100
+ }
101
+ } else if (code === 39) style.fg = null;
102
+ else if (code >= 40 && code <= 47) style.bg = ANSI_COLORS[code - 40] ?? null;
103
+ else if (code === 48) {
104
+ if (params[index + 1] === 5 && params[index + 2] !== undefined) {
105
+ style.bg = color256ToHex(params[index + 2] ?? 0);
106
+ index += 2;
107
+ } else if (params[index + 1] === 2 && params[index + 4] !== undefined) {
108
+ style.bg = `rgb(${params[index + 2]},${params[index + 3]},${params[index + 4]})`;
109
+ index += 4;
110
+ }
111
+ } else if (code === 49) style.bg = null;
112
+ else if (code >= 90 && code <= 97) style.fg = ANSI_COLORS[code - 90 + 8] ?? null;
113
+ else if (code >= 100 && code <= 107) style.bg = ANSI_COLORS[code - 100 + 8] ?? null;
114
+ index += 1;
115
+ }
116
+ }
117
+
118
+ // CSI, OSC, DCS/SOS/PM/APC, and single-character ESC sequences. SGR CSI
119
+ // sequences are interpreted; every other terminal control is removed.
120
+ const ESC = String.fromCharCode(27);
121
+ const BEL = String.fromCharCode(7);
122
+ const TERMINAL_SEQUENCE = new RegExp(
123
+ `${ESC}(?:\\[([0-?]*[ -/]*)([@-~])|\\][^${BEL}${ESC}]*(?:${BEL}|${ESC}\\\\)|[PX^_][\\s\\S]*?${ESC}\\\\|[@-_])`,
124
+ "gu",
125
+ );
126
+
127
+ export function ansiToHtml(text: string): string {
128
+ const style = createEmptyStyle();
129
+ let result = "";
130
+ let lastIndex = 0;
131
+ let spanOpen = false;
132
+ TERMINAL_SEQUENCE.lastIndex = 0;
133
+ let match = TERMINAL_SEQUENCE.exec(text);
134
+ while (match !== null) {
135
+ result += escapeHtml(text.slice(lastIndex, match.index));
136
+ if (match[2] === "m") {
137
+ if (spanOpen) result += "</span>";
138
+ const raw = match[1] ?? "";
139
+ const params = raw.length > 0 ? raw.split(";").map((part) => Number.parseInt(part, 10) || 0) : [0];
140
+ applySgrCode(params, style);
141
+ spanOpen = hasStyle(style);
142
+ if (spanOpen) result += `<span style="${styleToInlineCss(style)}">`;
143
+ }
144
+ lastIndex = match.index + match[0].length;
145
+ match = TERMINAL_SEQUENCE.exec(text);
146
+ }
147
+ result += escapeHtml(text.slice(lastIndex));
148
+ if (spanOpen) result += "</span>";
149
+ // A raw C0 control is never meaningful inside the exported document. Tabs
150
+ // remain useful in preformatted tool output and are safe in HTML text.
151
+ return Array.from(result)
152
+ .filter((character) => {
153
+ const code = character.charCodeAt(0);
154
+ return code === 9 || (code >= 32 && code !== 127);
155
+ })
156
+ .join("");
157
+ }
158
+
159
+ export function ansiLinesToHtml(lines: ReadonlyArray<string>): string {
160
+ return lines.map((line) => `<div class="ansi-line">${ansiToHtml(line) || "&nbsp;"}</div>`).join("\n");
161
+ }
@@ -0,0 +1,51 @@
1
+ import { htmlTemplate } from "./template.js";
2
+ import { renderTranscriptHtml } from "./tool-renderer.js";
3
+
4
+ export const MAX_HTML_EXPORT_BYTES = 2 * 1024 * 1024;
5
+ const TEMPLATE_RESERVE_BYTES = 8 * 1024;
6
+
7
+ export interface HtmlSessionExportInput {
8
+ sessionId: string;
9
+ exportedAt: string;
10
+ ansiLines: ReadonlyArray<string>;
11
+ maxBytes?: number;
12
+ }
13
+
14
+ /**
15
+ * Build the bounded, self-contained HTML document used by `/export`.
16
+ * Whole rendered rows are admitted until the byte budget is full, so the
17
+ * result never cuts an ANSI sequence, Unicode scalar, span, or tool section.
18
+ */
19
+ export function renderSessionHtml(input: HtmlSessionExportInput): string {
20
+ const maxBytes = input.maxBytes ?? MAX_HTML_EXPORT_BYTES;
21
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < TEMPLATE_RESERVE_BYTES * 2) {
22
+ throw new Error(`HTML export size limit must be at least ${TEMPLATE_RESERVE_BYTES * 2} bytes`);
23
+ }
24
+ const lineBudget = maxBytes - TEMPLATE_RESERVE_BYTES;
25
+ const selected: string[] = [];
26
+ let renderedBytes = 0;
27
+ let truncated = false;
28
+ for (const line of input.ansiLines) {
29
+ const rendered = renderTranscriptHtml([line]);
30
+ const bytes = Buffer.byteLength(rendered, "utf8") + 1;
31
+ if (renderedBytes + bytes > lineBudget) {
32
+ truncated = true;
33
+ break;
34
+ }
35
+ selected.push(line);
36
+ renderedBytes += bytes;
37
+ }
38
+ const html = htmlTemplate({
39
+ sessionId: input.sessionId,
40
+ exportedAt: input.exportedAt,
41
+ transcriptHtml: renderTranscriptHtml(selected),
42
+ truncated,
43
+ });
44
+ if (Buffer.byteLength(html, "utf8") > maxBytes) {
45
+ throw new Error(`HTML export exceeded its ${maxBytes}-byte size limit`);
46
+ }
47
+ return html;
48
+ }
49
+
50
+ export { ansiLinesToHtml, ansiToHtml } from "./ansi-to-html.js";
51
+ export { renderTranscriptHtml } from "./tool-renderer.js";
@@ -0,0 +1,45 @@
1
+ import { escapeHtml } from "./ansi-to-html.js";
2
+
3
+ export interface HtmlTemplateInput {
4
+ sessionId: string;
5
+ exportedAt: string;
6
+ transcriptHtml: string;
7
+ truncated: boolean;
8
+ }
9
+
10
+ /** A self-contained document: no scripts, fonts, stylesheets, or remote URLs. */
11
+ export function htmlTemplate(input: HtmlTemplateInput): string {
12
+ const title = `Clio session ${input.sessionId}`;
13
+ return `<!doctype html>
14
+ <html lang="en">
15
+ <head>
16
+ <meta charset="utf-8">
17
+ <meta name="viewport" content="width=device-width, initial-scale=1">
18
+ <title>${escapeHtml(title)}</title>
19
+ <style>
20
+ :root { color-scheme: dark; --page: rgb(16,23,25); --card: rgb(23,33,36); --tool: rgb(18,28,31); --text: rgb(220,231,233); --muted: rgb(138,153,164); --frame: rgb(47,93,90); --accent: rgb(70,229,208); }
21
+ * { box-sizing: border-box; }
22
+ body { margin: 0; background: var(--page); color: var(--text); font: 14px/1.45 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; }
23
+ main { width: min(112ch, calc(100% - 32px)); margin: 32px auto; }
24
+ header { margin-bottom: 20px; padding: 18px 20px; border: 1px solid var(--frame); border-radius: 10px; background: var(--card); }
25
+ h1 { margin: 0 0 6px; color: var(--accent); font: 600 20px/1.3 system-ui, sans-serif; }
26
+ header p { margin: 0; color: var(--muted); }
27
+ .transcript { white-space: pre-wrap; overflow-wrap: anywhere; }
28
+ .ansi-line { min-height: 1.45em; }
29
+ .transcript-row { padding: 0 12px; }
30
+ .tool-row { margin: 8px 0; padding: 9px 12px; border-left: 2px solid var(--frame); border-radius: 0 7px 7px 0; background: var(--tool); }
31
+ .truncated { margin-top: 18px; padding: 10px 12px; border: 1px solid rgb(128,96,52); border-radius: 7px; color: rgb(255,180,84); }
32
+ @media print { :root { color-scheme: light; --page: rgb(255,255,255); --card: rgb(244,247,247); --tool: rgb(247,249,249); --text: rgb(23,33,36); --muted: rgb(82,96,103); --frame: rgb(145,170,168); --accent: rgb(8,125,114); } main { width: 100%; margin: 0; } }
33
+ </style>
34
+ </head>
35
+ <body>
36
+ <main>
37
+ <header><h1>${escapeHtml(title)}</h1><p>Exported ${escapeHtml(input.exportedAt)}</p></header>
38
+ <section class="transcript" aria-label="Session transcript">
39
+ ${input.transcriptHtml}
40
+ </section>
41
+ ${input.truncated ? ' <p class="truncated">The transcript was truncated to keep this HTML export within its size limit.</p>\n' : ""} </main>
42
+ </body>
43
+ </html>
44
+ `;
45
+ }