@linxiraos/pi-tui 1.1.26 → 1.2.0

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 (423) hide show
  1. package/CHANGELOG.md +51 -491
  2. package/README.md +13 -7
  3. package/dist/types/active-terminal.d.ts +30 -0
  4. package/dist/types/app-keybindings.d.ts +7 -2
  5. package/dist/types/apps/cleanse-board.d.ts +1 -1
  6. package/dist/types/apps/debug/log-viewer.d.ts +4 -0
  7. package/dist/types/apps/debug/raw-sse-buffer.d.ts +2 -0
  8. package/dist/types/apps/git/git-tui.d.ts +5 -4
  9. package/dist/types/apps/git/help.d.ts +3 -1
  10. package/dist/types/apps/if-bench-board.d.ts +2 -2
  11. package/dist/types/apps/setup-model-picker.d.ts +1 -1
  12. package/dist/types/autocomplete.d.ts +5 -2
  13. package/dist/types/charts/chart-plan.d.ts +674 -0
  14. package/dist/types/charts/chart-svg.d.ts +59 -0
  15. package/dist/types/charts/table-data.d.ts +175 -0
  16. package/dist/types/chat/assistant-message.d.ts +11 -1
  17. package/dist/types/chat/chat-transcript-builder.d.ts +3 -0
  18. package/dist/types/chat/compaction-summary-message.d.ts +1 -0
  19. package/dist/types/chat/execution-shared.d.ts +6 -5
  20. package/dist/types/chat/fence-figure.d.ts +42 -0
  21. package/dist/types/chat/figure-markdown.d.ts +42 -0
  22. package/dist/types/chat/messages.d.ts +1 -1
  23. package/dist/types/chat/svg-figure.d.ts +33 -0
  24. package/dist/types/chat/svg-source.d.ts +49 -0
  25. package/dist/types/chat/table-chart.d.ts +89 -0
  26. package/dist/types/chat/tool-execution.d.ts +2 -0
  27. package/dist/types/chat/user-message.d.ts +17 -4
  28. package/dist/types/chrome/shared.d.ts +9 -0
  29. package/dist/types/chrome/status-notice.d.ts +15 -3
  30. package/dist/types/chrome/transcript-container.d.ts +6 -0
  31. package/dist/types/components/box.d.ts +1 -0
  32. package/dist/types/components/disclosure.d.ts +1 -0
  33. package/dist/types/components/editor.d.ts +23 -5
  34. package/dist/types/components/form.d.ts +1 -0
  35. package/dist/types/components/image.d.ts +26 -44
  36. package/dist/types/components/input.d.ts +2 -1
  37. package/dist/types/components/key-value-list.d.ts +1 -0
  38. package/dist/types/components/layout/row.d.ts +1 -0
  39. package/dist/types/components/layout/stack.d.ts +1 -0
  40. package/dist/types/components/loader.d.ts +5 -6
  41. package/dist/types/components/markdown.d.ts +47 -5
  42. package/dist/types/components/scroll-view.d.ts +1 -0
  43. package/dist/types/components/section.d.ts +1 -0
  44. package/dist/types/components/table.d.ts +1 -0
  45. package/dist/types/components/text.d.ts +1 -0
  46. package/dist/types/components/tree-view.d.ts +7 -0
  47. package/dist/types/components/truncated-text.d.ts +1 -0
  48. package/dist/types/fuzzy.d.ts +29 -1
  49. package/dist/types/key-hint-format.d.ts +9 -1
  50. package/dist/types/keybinding-matchers.d.ts +3 -0
  51. package/dist/types/keybindings.d.ts +1 -1
  52. package/dist/types/kitty-graphics.d.ts +2 -2
  53. package/dist/types/loop-watchdog.d.ts +8 -7
  54. package/dist/types/multiplexers/cmux.d.ts +16 -0
  55. package/dist/types/multiplexers/herdr.d.ts +26 -0
  56. package/dist/types/multiplexers/notify.d.ts +13 -0
  57. package/dist/types/multiplexers/orca.d.ts +12 -0
  58. package/dist/types/multiplexers/screen.d.ts +9 -0
  59. package/dist/types/multiplexers/tmux.d.ts +29 -0
  60. package/dist/types/multiplexers/types.d.ts +100 -0
  61. package/dist/types/multiplexers/wmux.d.ts +12 -0
  62. package/dist/types/multiplexers/zellij.d.ts +12 -0
  63. package/dist/types/native/apply.d.ts +4 -3
  64. package/dist/types/native/backend.d.ts +5 -4
  65. package/dist/types/native/blobs.d.ts +7 -3
  66. package/dist/types/native/encode.d.ts +8 -6
  67. package/dist/types/native/node.d.ts +36 -5
  68. package/dist/types/native/overlay.d.ts +8 -3
  69. package/dist/types/native/settle.d.ts +4 -3
  70. package/dist/types/overlays/agent-hub-projection.d.ts +6 -5
  71. package/dist/types/overlays/agent-hub-types.d.ts +9 -0
  72. package/dist/types/overlays/agent-hub.d.ts +3 -0
  73. package/dist/types/overlays/agent-transcript-viewer.d.ts +12 -2
  74. package/dist/types/overlays/agents-hub.d.ts +9 -0
  75. package/dist/types/overlays/annotation-overlay.d.ts +19 -2
  76. package/dist/types/overlays/annotation-types.d.ts +2 -0
  77. package/dist/types/overlays/ask-dialog.d.ts +5 -2
  78. package/dist/types/overlays/btw-history-panel.d.ts +13 -1
  79. package/dist/types/overlays/copy-selector.d.ts +1 -0
  80. package/dist/types/overlays/history-search.d.ts +10 -0
  81. package/dist/types/overlays/hook-selector.d.ts +9 -4
  82. package/dist/types/overlays/hub-frame.d.ts +4 -1
  83. package/dist/types/overlays/jobs-panel.d.ts +1 -7
  84. package/dist/types/overlays/model-browser.d.ts +54 -7
  85. package/dist/types/overlays/model-hub.d.ts +37 -0
  86. package/dist/types/overlays/oauth-selector.d.ts +0 -1
  87. package/dist/types/overlays/plan-review-overlay.d.ts +3 -2
  88. package/dist/types/overlays/report-panel.d.ts +68 -0
  89. package/dist/types/overlays/rewind-selector.d.ts +1 -0
  90. package/dist/types/overlays/session-observer-registry.d.ts +2 -0
  91. package/dist/types/overlays/session-selector.d.ts +6 -2
  92. package/dist/types/overlays/settings-defs.d.ts +1 -0
  93. package/dist/types/overlays/thinking-selector.d.ts +2 -2
  94. package/dist/types/overlays/usage-dashboard.d.ts +12 -8
  95. package/dist/types/overlays/usage-display.d.ts +3 -1
  96. package/dist/types/prompt/composer-cache.d.ts +0 -16
  97. package/dist/types/prompt/composer.d.ts +18 -3
  98. package/dist/types/prompt/custom-editor.d.ts +25 -13
  99. package/dist/types/prompt/image-source.d.ts +2 -1
  100. package/dist/types/prompt/interactive-context-helpers.d.ts +5 -1
  101. package/dist/types/prompt/model-mention-autocomplete.d.ts +1 -1
  102. package/dist/types/prompt/welcome.d.ts +7 -2
  103. package/dist/types/render/composite.d.ts +2 -0
  104. package/dist/types/render/output-pane.d.ts +1 -0
  105. package/dist/types/render/render-utils.d.ts +1 -0
  106. package/dist/types/render/tool-card.d.ts +6 -0
  107. package/dist/types/render/width-aware-text.d.ts +2 -0
  108. package/dist/types/setup/scenes/types.d.ts +1 -0
  109. package/dist/types/space-hold.d.ts +40 -25
  110. package/dist/types/status-line/component.d.ts +3 -0
  111. package/dist/types/status-line/context-usage.d.ts +7 -5
  112. package/dist/types/status-line/host.d.ts +4 -1
  113. package/dist/types/status-line/segments.d.ts +2 -0
  114. package/dist/types/status-line/types.d.ts +14 -3
  115. package/dist/types/terminal-capabilities.d.ts +41 -36
  116. package/dist/types/terminal-multiplexer.d.ts +127 -14
  117. package/dist/types/terminal.d.ts +23 -16
  118. package/dist/types/theme/active-symbols.d.ts +1 -1
  119. package/dist/types/theme/schema.d.ts +11 -2
  120. package/dist/types/theme/symbols.d.ts +1 -1
  121. package/dist/types/theme/theme-class.d.ts +7 -0
  122. package/dist/types/theme/theme.d.ts +1 -1
  123. package/dist/types/theme/tui-adapters.d.ts +3 -0
  124. package/dist/types/thinking.d.ts +1 -1
  125. package/dist/types/tmux.d.ts +11 -4
  126. package/dist/types/tools/bash.d.ts +7 -2
  127. package/dist/types/tools/daemon.d.ts +1 -1
  128. package/dist/types/tools/eval.d.ts +22 -3
  129. package/dist/types/tools/glob.d.ts +4 -0
  130. package/dist/types/tools/native-view.d.ts +47 -0
  131. package/dist/types/tools/output-meta.d.ts +11 -1
  132. package/dist/types/tools/renderer.d.ts +37 -2
  133. package/dist/types/tools/streaming-output.d.ts +20 -1
  134. package/dist/types/tools/task.d.ts +2 -3
  135. package/dist/types/tools/write.d.ts +9 -2
  136. package/dist/types/tools/yield.d.ts +22 -0
  137. package/dist/types/tui.d.ts +36 -0
  138. package/dist/types/utils.d.ts +6 -0
  139. package/dist/types/vim.d.ts +19 -5
  140. package/dist/types/windows-input-mode.d.ts +33 -1
  141. package/package.json +13 -9
  142. package/src/active-terminal.d.ts +30 -0
  143. package/src/active-terminal.ts +80 -0
  144. package/src/app-keybindings.d.ts +7 -2
  145. package/src/app-keybindings.ts +7 -2
  146. package/src/apps/autoresearch-dashboard.ts +7 -3
  147. package/src/apps/cleanse-board.ts +2 -2
  148. package/src/apps/cleanse-picker.ts +1 -1
  149. package/src/apps/debug/log-viewer.ts +188 -72
  150. package/src/apps/debug/raw-sse-buffer.ts +8 -0
  151. package/src/apps/debug/raw-sse.ts +39 -5
  152. package/src/apps/git/diff-pane.ts +96 -23
  153. package/src/apps/git/git-tui.ts +23 -16
  154. package/src/apps/git/help.ts +29 -20
  155. package/src/apps/git/sidebar.ts +8 -3
  156. package/src/apps/if-bench-board.ts +2 -2
  157. package/src/apps/ps-top.ts +2 -2
  158. package/src/apps/setup-model-picker.ts +1 -1
  159. package/src/autocomplete.d.ts +5 -2
  160. package/src/autocomplete.ts +67 -43
  161. package/src/bracketed-paste.ts +10 -3
  162. package/src/charts/chart-plan.d.ts +674 -0
  163. package/src/charts/chart-plan.ts +5081 -0
  164. package/src/charts/chart-svg.d.ts +59 -0
  165. package/src/charts/chart-svg.ts +4657 -0
  166. package/src/charts/table-data.d.ts +175 -0
  167. package/src/charts/table-data.ts +1478 -0
  168. package/src/chat/advisor-message.ts +11 -0
  169. package/src/chat/assistant-message.d.ts +11 -1
  170. package/src/chat/assistant-message.ts +245 -54
  171. package/src/chat/chat-transcript-builder.d.ts +3 -0
  172. package/src/chat/chat-transcript-builder.ts +9 -3
  173. package/src/chat/compaction-summary-message.d.ts +1 -0
  174. package/src/chat/compaction-summary-message.ts +8 -0
  175. package/src/chat/execution-shared.d.ts +6 -5
  176. package/src/chat/execution-shared.ts +42 -25
  177. package/src/chat/fence-figure.d.ts +42 -0
  178. package/src/chat/fence-figure.ts +80 -0
  179. package/src/chat/figure-markdown.d.ts +42 -0
  180. package/src/chat/figure-markdown.ts +174 -0
  181. package/src/chat/messages.d.ts +1 -1
  182. package/src/chat/messages.ts +1 -1
  183. package/src/chat/read-tool-group.ts +6 -4
  184. package/src/chat/skill-message.ts +6 -0
  185. package/src/chat/svg-figure.d.ts +33 -0
  186. package/src/chat/svg-figure.ts +399 -0
  187. package/src/chat/svg-source.d.ts +49 -0
  188. package/src/chat/svg-source.ts +188 -0
  189. package/src/chat/table-chart.d.ts +89 -0
  190. package/src/chat/table-chart.ts +294 -0
  191. package/src/chat/tool-execution.d.ts +2 -0
  192. package/src/chat/tool-execution.ts +86 -7
  193. package/src/chat/user-message.d.ts +17 -4
  194. package/src/chat/user-message.ts +71 -8
  195. package/src/chrome/shared.ts +53 -0
  196. package/src/chrome/status-notice.ts +25 -7
  197. package/src/chrome/transcript-container.d.ts +6 -0
  198. package/src/chrome/transcript-container.ts +162 -19
  199. package/src/components/box.d.ts +1 -0
  200. package/src/components/box.ts +5 -0
  201. package/src/components/disclosure.d.ts +1 -0
  202. package/src/components/disclosure.ts +8 -0
  203. package/src/components/editor.d.ts +23 -5
  204. package/src/components/editor.ts +316 -47
  205. package/src/components/form.d.ts +1 -0
  206. package/src/components/form.ts +8 -0
  207. package/src/components/image.d.ts +26 -44
  208. package/src/components/image.ts +115 -152
  209. package/src/components/input.d.ts +2 -1
  210. package/src/components/input.ts +17 -7
  211. package/src/components/key-value-list.d.ts +1 -0
  212. package/src/components/key-value-list.ts +4 -0
  213. package/src/components/layout/row.d.ts +1 -0
  214. package/src/components/layout/row.ts +7 -0
  215. package/src/components/layout/stack.d.ts +1 -0
  216. package/src/components/layout/stack.ts +7 -0
  217. package/src/components/loader.d.ts +5 -6
  218. package/src/components/loader.ts +10 -17
  219. package/src/components/markdown.d.ts +47 -5
  220. package/src/components/markdown.ts +786 -303
  221. package/src/components/scroll-view.d.ts +1 -0
  222. package/src/components/scroll-view.ts +5 -0
  223. package/src/components/section.d.ts +1 -0
  224. package/src/components/section.ts +5 -0
  225. package/src/components/settings-list.ts +2 -0
  226. package/src/components/table.d.ts +1 -0
  227. package/src/components/table.ts +4 -0
  228. package/src/components/text.d.ts +1 -0
  229. package/src/components/text.ts +7 -0
  230. package/src/components/tree-view.d.ts +7 -0
  231. package/src/components/tree-view.ts +38 -8
  232. package/src/components/truncated-text.d.ts +1 -0
  233. package/src/components/truncated-text.ts +5 -0
  234. package/src/desktop-notify.ts +3 -2
  235. package/src/fuzzy.d.ts +29 -1
  236. package/src/fuzzy.ts +115 -30
  237. package/src/hotkeys-markdown.ts +9 -2
  238. package/src/key-hint-format.d.ts +9 -1
  239. package/src/key-hint-format.ts +26 -11
  240. package/src/keybinding-matchers.d.ts +3 -0
  241. package/src/keybinding-matchers.ts +6 -2
  242. package/src/keybindings.d.ts +1 -1
  243. package/src/keybindings.ts +1 -1
  244. package/src/kitty-graphics.d.ts +2 -2
  245. package/src/kitty-graphics.ts +11 -5
  246. package/src/loop-watchdog.d.ts +8 -7
  247. package/src/loop-watchdog.ts +18 -13
  248. package/src/multiplexers/cmux.d.ts +16 -0
  249. package/src/multiplexers/cmux.ts +29 -0
  250. package/src/multiplexers/herdr.d.ts +26 -0
  251. package/src/multiplexers/herdr.ts +64 -0
  252. package/src/multiplexers/notify.d.ts +13 -0
  253. package/src/multiplexers/notify.ts +24 -0
  254. package/src/multiplexers/orca.d.ts +12 -0
  255. package/src/multiplexers/orca.ts +16 -0
  256. package/src/multiplexers/screen.d.ts +9 -0
  257. package/src/multiplexers/screen.ts +15 -0
  258. package/src/multiplexers/tmux.d.ts +29 -0
  259. package/src/multiplexers/tmux.ts +40 -0
  260. package/src/multiplexers/types.d.ts +100 -0
  261. package/src/multiplexers/types.ts +110 -0
  262. package/src/multiplexers/wmux.d.ts +12 -0
  263. package/src/multiplexers/wmux.ts +16 -0
  264. package/src/multiplexers/zellij.d.ts +12 -0
  265. package/src/multiplexers/zellij.ts +24 -0
  266. package/src/native/apply.d.ts +4 -3
  267. package/src/native/apply.ts +4 -3
  268. package/src/native/backend.d.ts +5 -4
  269. package/src/native/backend.ts +199 -22
  270. package/src/native/blobs.d.ts +7 -3
  271. package/src/native/blobs.ts +47 -12
  272. package/src/native/encode.d.ts +8 -6
  273. package/src/native/encode.ts +76 -34
  274. package/src/native/node.d.ts +36 -5
  275. package/src/native/node.ts +31 -5
  276. package/src/native/overlay.d.ts +8 -3
  277. package/src/native/overlay.ts +17 -4
  278. package/src/native/reconcile.ts +16 -4
  279. package/src/native/settle.d.ts +4 -3
  280. package/src/native/settle.ts +4 -3
  281. package/src/overlays/agent-hub-projection.d.ts +6 -5
  282. package/src/overlays/agent-hub-projection.ts +124 -13
  283. package/src/overlays/agent-hub-types.d.ts +9 -0
  284. package/src/overlays/agent-hub-types.ts +6 -0
  285. package/src/overlays/agent-hub.ts +48 -29
  286. package/src/overlays/agent-transcript-viewer.ts +93 -23
  287. package/src/overlays/agents-hub.ts +28 -8
  288. package/src/overlays/annotation-overlay.ts +293 -90
  289. package/src/overlays/annotation-types.ts +2 -0
  290. package/src/overlays/ask-dialog.ts +10 -17
  291. package/src/overlays/btw-history-panel.ts +136 -39
  292. package/src/overlays/copy-selector.d.ts +1 -0
  293. package/src/overlays/copy-selector.ts +32 -8
  294. package/src/overlays/extensions/extension-dashboard.ts +4 -4
  295. package/src/overlays/extensions/state-manager.ts +52 -12
  296. package/src/overlays/history-search.ts +100 -7
  297. package/src/overlays/hook-selector.ts +12 -5
  298. package/src/overlays/hub-frame.ts +19 -1
  299. package/src/overlays/jobs-panel.ts +33 -52
  300. package/src/overlays/model-browser.ts +367 -122
  301. package/src/overlays/model-hub.ts +435 -59
  302. package/src/overlays/move-overlay.ts +28 -14
  303. package/src/overlays/oauth-selector.ts +54 -70
  304. package/src/overlays/pause-screen.ts +2 -2
  305. package/src/overlays/plan-review-overlay.ts +208 -70
  306. package/src/overlays/plugin-settings.ts +3 -3
  307. package/src/overlays/report-panel.ts +191 -0
  308. package/src/overlays/rewind-selector.ts +88 -17
  309. package/src/overlays/session-observer-registry.d.ts +2 -0
  310. package/src/overlays/session-observer-registry.ts +10 -2
  311. package/src/overlays/session-selector.ts +64 -26
  312. package/src/overlays/settings-defs.ts +5 -4
  313. package/src/overlays/settings-selector.ts +33 -8
  314. package/src/overlays/snapcompact-shape-preview.ts +2 -3
  315. package/src/overlays/stats-notice.ts +1 -1
  316. package/src/overlays/thinking-selector.ts +11 -10
  317. package/src/overlays/tree-selector.ts +41 -20
  318. package/src/overlays/usage-dashboard.ts +117 -58
  319. package/src/overlays/usage-display.ts +10 -4
  320. package/src/overlays/usage-row.ts +22 -8
  321. package/src/prompt/attachment-chips.ts +15 -11
  322. package/src/prompt/composer-attachments.ts +6 -4
  323. package/src/prompt/composer-cache.ts +7 -86
  324. package/src/prompt/composer.ts +37 -26
  325. package/src/prompt/custom-editor.ts +282 -105
  326. package/src/prompt/image-source.ts +2 -1
  327. package/src/prompt/interactive-context-helpers.ts +32 -18
  328. package/src/prompt/macos-spelling.ts +7 -0
  329. package/src/prompt/magic-keywords.ts +11 -2
  330. package/src/prompt/model-mention-autocomplete.ts +14 -14
  331. package/src/prompt/queued-messages.ts +6 -4
  332. package/src/prompt/tips.txt +13 -9
  333. package/src/prompt/welcome.ts +64 -46
  334. package/src/prompt/word-completion.ts +38 -5
  335. package/src/render/composite.d.ts +2 -0
  336. package/src/render/composite.ts +64 -0
  337. package/src/render/output-pane.d.ts +1 -0
  338. package/src/render/output-pane.ts +6 -0
  339. package/src/render/render-utils.d.ts +1 -0
  340. package/src/render/render-utils.ts +16 -1
  341. package/src/render/tool-card.d.ts +6 -0
  342. package/src/render/tool-card.ts +15 -0
  343. package/src/render/width-aware-text.d.ts +2 -0
  344. package/src/render/width-aware-text.ts +5 -0
  345. package/src/setup/scenes/model.ts +2 -1
  346. package/src/setup/scenes/types.ts +1 -0
  347. package/src/space-hold.d.ts +40 -25
  348. package/src/space-hold.ts +156 -52
  349. package/src/status-line/component.ts +292 -78
  350. package/src/status-line/context-usage.ts +21 -46
  351. package/src/status-line/host.ts +4 -1
  352. package/src/status-line/segments.ts +40 -22
  353. package/src/status-line/types.ts +15 -3
  354. package/src/terminal-capabilities.d.ts +41 -36
  355. package/src/terminal-capabilities.ts +137 -213
  356. package/src/terminal-multiplexer.d.ts +127 -14
  357. package/src/terminal-multiplexer.ts +112 -33
  358. package/src/terminal.d.ts +23 -16
  359. package/src/terminal.ts +203 -99
  360. package/src/theme/active-symbols.d.ts +1 -1
  361. package/src/theme/active-symbols.ts +1 -1
  362. package/src/theme/schema-validation.ts +1 -0
  363. package/src/theme/schema.d.ts +11 -2
  364. package/src/theme/schema.ts +14 -1
  365. package/src/theme/session-color.ts +1 -7
  366. package/src/theme/symbols.d.ts +1 -1
  367. package/src/theme/symbols.ts +11 -4
  368. package/src/theme/theme-class.d.ts +7 -0
  369. package/src/theme/theme-class.ts +26 -1
  370. package/src/theme/theme-schema.json +5 -1
  371. package/src/theme/theme.d.ts +1 -1
  372. package/src/theme/theme.ts +8 -4
  373. package/src/theme/tui-adapters.d.ts +3 -0
  374. package/src/theme/tui-adapters.ts +68 -0
  375. package/src/thinking.d.ts +1 -1
  376. package/src/thinking.ts +1 -1
  377. package/src/tmux.d.ts +11 -4
  378. package/src/tmux.ts +47 -11
  379. package/src/tools/ast-edit.ts +59 -35
  380. package/src/tools/ast-grep.ts +35 -16
  381. package/src/tools/bash.d.ts +7 -2
  382. package/src/tools/bash.ts +116 -47
  383. package/src/tools/daemon.d.ts +1 -1
  384. package/src/tools/daemon.ts +1 -1
  385. package/src/tools/default-renderer.ts +35 -19
  386. package/src/tools/edit.ts +142 -120
  387. package/src/tools/eval-format/index.ts +28 -2
  388. package/src/tools/eval-format/javascript.ts +7 -5
  389. package/src/tools/eval.d.ts +22 -3
  390. package/src/tools/eval.ts +364 -208
  391. package/src/tools/fetch.ts +5 -6
  392. package/src/tools/glob.d.ts +4 -0
  393. package/src/tools/glob.ts +33 -65
  394. package/src/tools/grep.ts +81 -48
  395. package/src/tools/index.ts +2 -0
  396. package/src/tools/lsp.ts +81 -59
  397. package/src/tools/mcp.ts +111 -68
  398. package/src/tools/native-view.d.ts +47 -0
  399. package/src/tools/native-view.ts +102 -1
  400. package/src/tools/output-meta.d.ts +11 -1
  401. package/src/tools/output-meta.ts +23 -3
  402. package/src/tools/read.ts +7 -5
  403. package/src/tools/renderer.d.ts +37 -2
  404. package/src/tools/renderer.ts +42 -2
  405. package/src/tools/streaming-output.d.ts +20 -1
  406. package/src/tools/streaming-output.ts +154 -50
  407. package/src/tools/task.d.ts +2 -3
  408. package/src/tools/task.ts +115 -62
  409. package/src/tools/todo.ts +119 -30
  410. package/src/tools/wait.ts +34 -24
  411. package/src/tools/web-search.ts +1 -1
  412. package/src/tools/write.d.ts +9 -2
  413. package/src/tools/write.ts +147 -95
  414. package/src/tools/yield.d.ts +22 -0
  415. package/src/tools/yield.ts +225 -0
  416. package/src/tui.d.ts +36 -0
  417. package/src/tui.ts +666 -217
  418. package/src/utils.d.ts +6 -0
  419. package/src/utils.ts +19 -0
  420. package/src/vim.d.ts +19 -5
  421. package/src/vim.ts +333 -18
  422. package/src/windows-input-mode.d.ts +33 -1
  423. package/src/windows-input-mode.ts +212 -6
@@ -80,8 +80,11 @@ export interface ChatTranscriptBuilderDeps {
80
80
  cwd: string;
81
81
  hideThinkingBlock?: () => boolean;
82
82
  proseOnlyThinking?: () => boolean;
83
+ expandThinkingBlocks?: () => boolean;
83
84
  /** Session-scoped resolved destinations for model-authored Markdown links. */
84
85
  linkTargets?: ReadonlyMap<string, string>;
86
+ /** Draw charts under numeric tables; false for transcripts that are not the main session's. Default: true. */
87
+ tableCharts?: boolean;
85
88
  requestRender: () => void;
86
89
  }
87
90
 
@@ -220,9 +223,7 @@ export class ChatTranscriptBuilder {
220
223
  }
221
224
  if (previous.canBeDisplacedBy(nextToolName)) {
222
225
  this.#todoSnapshot = null;
223
- if (this.container.canRemoveBlock(previous)) {
224
- this.container.removeChild(previous);
225
- }
226
+ this.container.removeChild(previous);
226
227
  previous.seal();
227
228
  return;
228
229
  }
@@ -404,6 +405,7 @@ export class ChatTranscriptBuilder {
404
405
  #appendAssistantMessage(message: Extract<AgentMessage, { role: "assistant" }>): void {
405
406
  const hideThinkingBlock = this.#deps.hideThinkingBlock?.() ?? false;
406
407
  const proseOnlyThinking = this.#deps.proseOnlyThinking ? this.#deps.proseOnlyThinking() : true;
408
+ const expandThinkingBlocks = this.#deps.expandThinkingBlocks?.() ?? false;
407
409
  const timeline = splitAssistantMessageToolTimeline(message);
408
410
  const assistantComponent = new AssistantMessageComponent(
409
411
  timeline.beforeTools,
@@ -413,9 +415,11 @@ export class ChatTranscriptBuilder {
413
415
  this.#deps.ui.imageBudget,
414
416
  proseOnlyThinking,
415
417
  this.#deps.linkTargets,
418
+ expandThinkingBlocks,
416
419
  );
417
420
  assistantComponent.setImagesVisible(displayPreferences.showImages);
418
421
  assistantComponent.setToolResultImagesVisible(!displayPreferences.hideToolActivity);
422
+ assistantComponent.setTableChartsVisible(this.#deps.tableCharts !== false);
419
423
  this.#trackExpandable(assistantComponent);
420
424
  assistantComponent.pickReactionTarget(this.container.children);
421
425
  this.container.addChild(assistantComponent);
@@ -450,9 +454,11 @@ export class ChatTranscriptBuilder {
450
454
  undefined,
451
455
  proseOnlyThinking,
452
456
  this.#deps.linkTargets,
457
+ expandThinkingBlocks,
453
458
  );
454
459
  component.setImagesVisible(displayPreferences.showImages);
455
460
  component.setToolResultImagesVisible(!displayPreferences.hideToolActivity);
461
+ component.setTableChartsVisible(this.#deps.tableCharts !== false);
456
462
  this.#trackExpandable(component);
457
463
  this.container.addChild(component);
458
464
  lastAssistantComponent = component;
@@ -31,6 +31,7 @@ declare class SummaryMessageComponent implements Component {
31
31
  handleNativeEvent(event: NativeUiEvent): void;
32
32
  setIgnoreTight(ignore: boolean): this;
33
33
  invalidate(): void;
34
+ releaseRenderCaches(): void;
34
35
  dispose(): void;
35
36
  render(width: number): readonly string[];
36
37
  }
@@ -53,6 +53,10 @@ class DividerSummary implements Component {
53
53
  this.#cache = undefined;
54
54
  }
55
55
 
56
+ releaseRenderCaches(): void {
57
+ this.#cache = undefined;
58
+ }
59
+
56
60
  render(width: number): readonly string[] {
57
61
  width = Math.max(1, width);
58
62
  if (this.#cache?.width === width) return this.#cache.lines;
@@ -150,6 +154,10 @@ class SummaryMessageComponent implements Component {
150
154
  if (this.#ignoreTight !== undefined) this.#disclosure.setIgnoreTight(this.#ignoreTight);
151
155
  }
152
156
 
157
+ releaseRenderCaches(): void {
158
+ this.#disclosure.releaseRenderCaches();
159
+ }
160
+
153
161
  dispose(): void {
154
162
  if (this.#disposed) return;
155
163
  this.#disposed = true;
@@ -78,7 +78,7 @@ export interface ExecutionToolInput {
78
78
  /** Tool name for the head icon (`bash`, `eval`). */
79
79
  readonly name: string;
80
80
  readonly title: string;
81
- /** The command / cell source, shown once in the head. */
81
+ /** The command / cell source: the run box's input and the head's Copy command. */
82
82
  readonly command: string;
83
83
  readonly lang: string;
84
84
  /** Excluded from context (`!!`/`$$`). */
@@ -96,10 +96,11 @@ export interface ExecutionToolInput {
96
96
  readonly artifactError?: OutputArtifactError;
97
97
  }
98
98
  /**
99
- * A user `!`/`$` run as the agent's `tool` frame (§6.6): the command in the
100
- * head with a `you` badge (plus `not sent` when excluded from context), the
101
- * timer, exit chip and cancelled note; the body is the output as an `ansi`
102
- * mini terminal following its tail, then one quiet truncation line.
99
+ * A user `!`/`$` run as the agent's `tool` frame (§6.6): a head with a `you`
100
+ * badge (plus `not sent` when excluded from context) and the command for Copy
101
+ * command; the body is one run box — the source, the output as an `ansi` mini
102
+ * terminal following its tail, and the foot (state, time, truncation) — with
103
+ * any images below it. Timer, exit chip and cancelled note stay head data.
103
104
  */
104
105
  export declare function describeExecutionTool(input: ExecutionToolInput): NativeNode;
105
106
  /**
@@ -20,6 +20,7 @@ import { DEFAULT_TERMINAL_PREVIEW_LINES, expandKeyHint } from "../render/render-
20
20
  import type { TspCardStatus, TspSpan, TspText, TspTone } from "@linxiraos/pi-wire";
21
21
  import { card, node, span, text } from "../native/describe";
22
22
  import type { NativeChild, NativeNode } from "../native/node";
23
+ import { runBox, runFoot, runInput, runOutput, type RunState } from "../tools/native-view";
23
24
 
24
25
  /** Output rows shown while an execution is collapsed. */
25
26
  export const PREVIEW_LINES = 20;
@@ -190,7 +191,7 @@ export interface ExecutionToolInput {
190
191
  /** Tool name for the head icon (`bash`, `eval`). */
191
192
  readonly name: string;
192
193
  readonly title: string;
193
- /** The command / cell source, shown once in the head. */
194
+ /** The command / cell source: the run box's input and the head's Copy command. */
194
195
  readonly command: string;
195
196
  readonly lang: string;
196
197
  /** Excluded from context (`!!`/`$$`). */
@@ -208,39 +209,55 @@ export interface ExecutionToolInput {
208
209
  readonly artifactError?: OutputArtifactError;
209
210
  }
210
211
 
212
+ const EXECUTION_RUN_STATE: Record<ExecutionStatus, RunState> = {
213
+ running: "running",
214
+ complete: "done",
215
+ cancelled: "cancelled",
216
+ error: "failed",
217
+ };
218
+
211
219
  /**
212
- * A user `!`/`$` run as the agent's `tool` frame (§6.6): the command in the
213
- * head with a `you` badge (plus `not sent` when excluded from context), the
214
- * timer, exit chip and cancelled note; the body is the output as an `ansi`
215
- * mini terminal following its tail, then one quiet truncation line.
220
+ * A user `!`/`$` run as the agent's `tool` frame (§6.6): a head with a `you`
221
+ * badge (plus `not sent` when excluded from context) and the command for Copy
222
+ * command; the body is one run box — the source, the output as an `ansi` mini
223
+ * terminal following its tail, and the foot (state, time, truncation) — with
224
+ * any images below it. Timer, exit chip and cancelled note stay head data.
216
225
  */
217
226
  export function describeExecutionTool(input: ExecutionToolInput): NativeNode {
218
227
  const running = input.status === "running";
219
- const body: NativeChild[] = [];
220
- if (input.output) body.push(node("ansi", { text: input.output, follow: running }, undefined, "output"));
221
- if (input.images) body.push(...input.images);
222
- const notes: string[] = [];
223
- if (input.truncation) notes.push(formatTruncationMetaNotice(input.truncation));
224
- if (input.artifactError) notes.push(formatArtifactErrorNotice(input.artifactError));
225
- if (notes.length > 0) {
226
- body.push({
227
- ...text([span(notes.join(" · "), "muted")], { wrap: "word", role: "zeta.tool.notice" }),
228
- key: "foot",
229
- });
230
- }
228
+ const shell = input.name === "bash";
231
229
  const ms = Math.max(0, Math.round((input.endedAt ?? performance.now()) - input.startedAt));
230
+ const state = EXECUTION_RUN_STATE[input.status];
231
+ const box = runBox(
232
+ [
233
+ runInput(input.command, {
234
+ role: shell ? "zeta.tool.bash.command" : "zeta.tool.eval.input",
235
+ lang: input.lang,
236
+ wrap: shell,
237
+ }),
238
+ input.output.length > 0 &&
239
+ runOutput(input.output, {
240
+ role: shell ? "zeta.tool.bash.output" : "zeta.tool.eval.output",
241
+ previewLines: DEFAULT_TERMINAL_PREVIEW_LINES,
242
+ }),
243
+ runFoot({
244
+ state,
245
+ exitCode: input.exitCode,
246
+ elapsedMs: ms,
247
+ meta: { truncation: input.truncation, artifactError: input.artifactError },
248
+ }),
249
+ ],
250
+ { key: "run", tone: state === "failed" ? "error" : undefined },
251
+ );
232
252
  const badges: { text: string; tone?: TspTone; title?: string }[] = [{ text: "you", tone: "user" }];
233
253
  if (input.excluded) badges.push({ text: "not sent", title: "Not sent to the model", tone: "muted" });
234
- const hasBody = body.length > 0;
235
254
  return node(
236
255
  "tool",
237
256
  {
238
257
  role: input.role,
239
258
  name: input.name,
240
259
  title: input.title,
241
- target: input.command,
242
- targetKind: "command",
243
- lang: input.lang,
260
+ command: input.command,
244
261
  badges,
245
262
  status: EXECUTION_CARD_STATUS[input.status],
246
263
  age: running ? ms : undefined,
@@ -248,11 +265,11 @@ export function describeExecutionTool(input: ExecutionToolInput): NativeNode {
248
265
  exit: input.status === "error" ? input.exitCode : undefined,
249
266
  note: input.status === "cancelled" ? "cancelled" : undefined,
250
267
  frame: "card",
251
- collapsible: hasBody,
252
- collapsed: hasBody ? !input.expanded : undefined,
253
- preview: hasBody ? { tail: DEFAULT_TERMINAL_PREVIEW_LINES } : undefined,
268
+ collapsible: true,
269
+ collapsed: !input.expanded,
270
+ preview: "children",
254
271
  },
255
- body,
272
+ [box, ...(input.images ?? [])],
256
273
  );
257
274
  }
258
275
 
@@ -0,0 +1,42 @@
1
+ /**
2
+ * A tool call's {@link ToolFigure} drawn under its card, the way assistant
3
+ * Markdown draws that fence: ```svg as an inline image ({@link SvgFigure}),
4
+ * redrawn as the body streams; ```mermaid as ASCII art once the body is
5
+ * final. The card already shows the source, so unlike the assistant's fence
6
+ * it never falls back to code: {@link FenceFigure.draws} turns down fences
7
+ * this terminal shows as code, and an svg that does not rasterize stays blank.
8
+ */
9
+ import type { ImageBudget } from "../components/image";
10
+ import type { ToolFigure } from "../tools/renderer";
11
+ import type { Component } from "../tui";
12
+ /** Fence languages a {@link FenceFigure} draws. */
13
+ export type FenceFigureLang = "svg" | "mermaid";
14
+ export interface FenceFigureOptions {
15
+ /** Shared inline-image budget for an svg's rasters. */
16
+ budget?: ImageBudget;
17
+ /** The figure's rows changed outside a render: a raster landed. */
18
+ onChange: () => void;
19
+ }
20
+ export declare class FenceFigure implements Component {
21
+ #private;
22
+ /**
23
+ * Whether this terminal draws `figure` now: an svg where inline images show
24
+ * (`showImages` and a graphics protocol), a closed mermaid fence when
25
+ * diagram rendering is on and the source renders.
26
+ */
27
+ static draws(figure: ToolFigure, options: {
28
+ showImages: boolean;
29
+ }): figure is ToolFigure & {
30
+ readonly lang: FenceFigureLang;
31
+ };
32
+ readonly lang: FenceFigureLang;
33
+ constructor(lang: FenceFigureLang, options: FenceFigureOptions);
34
+ /** Feed the fence as it stands; its `lang` is this figure's. */
35
+ update(figure: ToolFigure): void;
36
+ /** Whether a closed svg's raster is still on its way. */
37
+ get pending(): boolean;
38
+ /** The drawing; no rows while an svg draws, or when it does not. */
39
+ render(width: number): readonly string[];
40
+ invalidate(): void;
41
+ dispose(): void;
42
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * A tool call's {@link ToolFigure} drawn under its card, the way assistant
3
+ * Markdown draws that fence: ```svg as an inline image ({@link SvgFigure}),
4
+ * redrawn as the body streams; ```mermaid as ASCII art once the body is
5
+ * final. The card already shows the source, so unlike the assistant's fence
6
+ * it never falls back to code: {@link FenceFigure.draws} turns down fences
7
+ * this terminal shows as code, and an svg that does not rasterize stays blank.
8
+ */
9
+ import type { ImageBudget } from "../components/image";
10
+ import { fencedCode, Markdown } from "../components/markdown";
11
+ import { TERMINAL } from "../terminal-capabilities";
12
+ import { getMarkdownTheme } from "../theme";
13
+ import type { ToolFigure } from "../tools/renderer";
14
+ import type { Component } from "../tui";
15
+ import { SvgFigure, svgFigureRendering } from "./svg-figure";
16
+
17
+ /** Fence languages a {@link FenceFigure} draws. */
18
+ export type FenceFigureLang = "svg" | "mermaid";
19
+
20
+ export interface FenceFigureOptions {
21
+ /** Shared inline-image budget for an svg's rasters. */
22
+ budget?: ImageBudget;
23
+ /** The figure's rows changed outside a render: a raster landed. */
24
+ onChange: () => void;
25
+ }
26
+
27
+ export class FenceFigure implements Component {
28
+ /**
29
+ * Whether this terminal draws `figure` now: an svg where inline images show
30
+ * (`showImages` and a graphics protocol), a closed mermaid fence when
31
+ * diagram rendering is on and the source renders.
32
+ */
33
+ static draws(
34
+ figure: ToolFigure,
35
+ options: { showImages: boolean },
36
+ ): figure is ToolFigure & { readonly lang: FenceFigureLang } {
37
+ if (figure.lang === "svg") return options.showImages && TERMINAL.imageProtocol !== null && svgFigureRendering();
38
+ if (figure.lang !== "mermaid" || !figure.closed) return false;
39
+ return getMarkdownTheme().resolveMermaidAscii?.(figure.source.trimEnd()) != null;
40
+ }
41
+
42
+ readonly lang: FenceFigureLang;
43
+ readonly #svg: SvgFigure | undefined;
44
+ #source = "";
45
+ /** The mermaid fence as assistant Markdown renders it; rebuilt after a theme change. */
46
+ #diagram: Markdown | undefined;
47
+
48
+ constructor(lang: FenceFigureLang, options: FenceFigureOptions) {
49
+ this.lang = lang;
50
+ if (lang === "svg") this.#svg = new SvgFigure({ budget: options.budget, onChange: options.onChange });
51
+ }
52
+
53
+ /** Feed the fence as it stands; its `lang` is this figure's. */
54
+ update(figure: ToolFigure): void {
55
+ if (figure.source !== this.#source) this.#diagram = undefined;
56
+ this.#source = figure.source;
57
+ this.#svg?.update(figure.source, figure.closed);
58
+ }
59
+
60
+ /** Whether a closed svg's raster is still on its way. */
61
+ get pending(): boolean {
62
+ return this.#svg?.pending === true;
63
+ }
64
+
65
+ /** The drawing; no rows while an svg draws, or when it does not. */
66
+ render(width: number): readonly string[] {
67
+ if (this.#svg) return this.#svg.render(width);
68
+ this.#diagram ??= new Markdown(fencedCode("mermaid", this.#source), 1, 0, getMarkdownTheme());
69
+ return this.#diagram.render(width);
70
+ }
71
+
72
+ invalidate(): void {
73
+ this.#svg?.invalidate();
74
+ this.#diagram = undefined;
75
+ }
76
+
77
+ dispose(): void {
78
+ this.#svg?.dispose();
79
+ }
80
+ }
@@ -0,0 +1,42 @@
1
+ import type { ImageBudget } from "../components/image";
2
+ import type { Markdown } from "../components/markdown";
3
+ import { Container } from "../tui";
4
+ export interface FigureMarkdownOptions {
5
+ /** Markdown for one prose run (and a failed figure's code fallback); FigureMarkdown drives its transience. */
6
+ markdown: (text: string) => Markdown;
7
+ /** Draw charts under numeric tables; off for transcripts that are not the main session's. */
8
+ charts: boolean;
9
+ /** Shared inline-image budget for the figures. */
10
+ budget?: ImageBudget;
11
+ /** A figure's rows changed outside a text update (raster landed, fell back to code). */
12
+ onChange: () => void;
13
+ }
14
+ /**
15
+ * Assistant Markdown whose top-level ```svg fences are lifted out of the prose
16
+ * and drawn as images ({@link SvgFigure}), and whose numeric tables get a chart
17
+ * drawn under them ({@link TableChartFigure}), with ordinary {@link Markdown}
18
+ * for the prose between them. Stands in for Markdown on an assistant text
19
+ * block that holds an svg fence or a chartable table: {@link setText} streams
20
+ * in place, reusing every part whose kind is unchanged, and
21
+ * {@link transientRenderCache} marks the block's tail as still streaming — the
22
+ * last prose run renders transient, the last figure throttles its rasters
23
+ * until its fence closes, and a table at the tail waits for its last row.
24
+ */
25
+ export declare class FigureMarkdown extends Container {
26
+ #private;
27
+ constructor(text: string, options: FigureMarkdownOptions);
28
+ /** Replace the source; returns whether it changed. */
29
+ setText(text: string): boolean;
30
+ get transientRenderCache(): boolean;
31
+ set transientRenderCache(value: boolean);
32
+ /**
33
+ * The trimmed prose ahead of the first figure, or "" when the block opens
34
+ * with one. These are the only rows plain Markdown reproduces byte for
35
+ * byte, so they are all a transcript may publish ahead of the figure.
36
+ */
37
+ get leadingProse(): string;
38
+ /** Whether a figure's final source still waits for its raster, or a chart for its pick or raster. */
39
+ get pending(): boolean;
40
+ /** Rebuild the prose runs through the Markdown factory after its theme changed; figures keep their rasters. */
41
+ restyle(): void;
42
+ }
@@ -0,0 +1,174 @@
1
+ import type { Tokens } from "@linxiraos/pi-utils/marked";
2
+ import type { ImageBudget } from "../components/image";
3
+ import type { Markdown } from "../components/markdown";
4
+ import { Spacer } from "../components/spacer";
5
+ import { Container } from "../tui";
6
+ import { SvgFigure, svgFigureRendering } from "./svg-figure";
7
+ import { type FigureSegment, splitSvgFences } from "./svg-source";
8
+ import { type ChartSegment, hasChartTable, splitTableCharts, TableChartFigure } from "./table-chart";
9
+
10
+ export interface FigureMarkdownOptions {
11
+ /** Markdown for one prose run (and a failed figure's code fallback); FigureMarkdown drives its transience. */
12
+ markdown: (text: string) => Markdown;
13
+ /** Draw charts under numeric tables; off for transcripts that are not the main session's. */
14
+ charts: boolean;
15
+ /** Shared inline-image budget for the figures. */
16
+ budget?: ImageBudget;
17
+ /** A figure's rows changed outside a text update (raster landed, fell back to code). */
18
+ onChange: () => void;
19
+ }
20
+
21
+ type Part =
22
+ | { readonly kind: "markdown"; readonly md: Markdown; text: string }
23
+ | { readonly kind: "svg"; readonly figure: SvgFigure; source: string; closed: boolean }
24
+ | { readonly kind: "chart"; readonly figure: TableChartFigure; table: Tokens.Table };
25
+
26
+ /**
27
+ * Assistant Markdown whose top-level ```svg fences are lifted out of the prose
28
+ * and drawn as images ({@link SvgFigure}), and whose numeric tables get a chart
29
+ * drawn under them ({@link TableChartFigure}), with ordinary {@link Markdown}
30
+ * for the prose between them. Stands in for Markdown on an assistant text
31
+ * block that holds an svg fence or a chartable table: {@link setText} streams
32
+ * in place, reusing every part whose kind is unchanged, and
33
+ * {@link transientRenderCache} marks the block's tail as still streaming — the
34
+ * last prose run renders transient, the last figure throttles its rasters
35
+ * until its fence closes, and a table at the tail waits for its last row.
36
+ */
37
+ export class FigureMarkdown extends Container {
38
+ readonly #options: FigureMarkdownOptions;
39
+ #text = "";
40
+ #transient = false;
41
+ #parts: Part[] = [];
42
+
43
+ constructor(text: string, options: FigureMarkdownOptions) {
44
+ super();
45
+ this.#options = options;
46
+ this.setText(text);
47
+ }
48
+
49
+ /** Replace the source; returns whether it changed. */
50
+ setText(text: string): boolean {
51
+ if (text === this.#text) return false;
52
+ this.#text = text;
53
+ this.#reconcile();
54
+ return true;
55
+ }
56
+
57
+ get transientRenderCache(): boolean {
58
+ return this.#transient;
59
+ }
60
+
61
+ set transientRenderCache(value: boolean) {
62
+ if (this.#transient === value) return;
63
+ this.#transient = value;
64
+ // The end of the stream completes a tail table, which may now get its chart.
65
+ this.#reconcile();
66
+ }
67
+
68
+ /**
69
+ * The trimmed prose ahead of the first figure, or "" when the block opens
70
+ * with one. These are the only rows plain Markdown reproduces byte for
71
+ * byte, so they are all a transcript may publish ahead of the figure.
72
+ */
73
+ get leadingProse(): string {
74
+ const first = this.#parts[0];
75
+ return first?.kind === "markdown" ? first.text : "";
76
+ }
77
+
78
+ /** Whether a figure's final source still waits for its raster, or a chart for its pick or raster. */
79
+ get pending(): boolean {
80
+ return this.#parts.some(part => part.kind !== "markdown" && part.figure.pending);
81
+ }
82
+
83
+ /** Rebuild the prose runs through the Markdown factory after its theme changed; figures keep their rasters. */
84
+ restyle(): void {
85
+ this.#parts = this.#parts.map(part =>
86
+ part.kind === "markdown" ? { kind: "markdown", md: this.#options.markdown(part.text), text: part.text } : part,
87
+ );
88
+ this.#mount();
89
+ this.#syncTails();
90
+ }
91
+
92
+ #reconcile(): void {
93
+ const previous = this.#parts;
94
+ const segments = this.#segments();
95
+ let reshaped = previous.length !== segments.length;
96
+ this.#parts = segments.map((segment, index): Part => {
97
+ const old = previous[index];
98
+ if (segment.kind === "chart") {
99
+ if (old?.kind === "chart") {
100
+ old.table = segment.table;
101
+ return old;
102
+ }
103
+ reshaped = true;
104
+ const { budget, onChange } = this.#options;
105
+ return { kind: "chart", figure: new TableChartFigure({ budget, onChange }), table: segment.table };
106
+ }
107
+ if (segment.kind === "markdown") {
108
+ const text = segment.text.trim();
109
+ if (old?.kind === "markdown") {
110
+ old.md.setText(text);
111
+ old.text = text;
112
+ return old;
113
+ }
114
+ reshaped = true;
115
+ return { kind: "markdown", md: this.#options.markdown(text), text };
116
+ }
117
+ if (old?.kind === "svg") {
118
+ old.source = segment.source;
119
+ old.closed = segment.closed;
120
+ return old;
121
+ }
122
+ reshaped = true;
123
+ const { markdown, budget, onChange } = this.#options;
124
+ return {
125
+ kind: "svg",
126
+ figure: new SvgFigure({ markdown, budget, onChange }),
127
+ source: segment.source,
128
+ closed: segment.closed,
129
+ };
130
+ });
131
+ if (reshaped) {
132
+ for (const old of previous) {
133
+ if (old.kind !== "markdown" && !this.#parts.includes(old)) old.figure.dispose();
134
+ }
135
+ this.#mount();
136
+ }
137
+ this.#syncTails();
138
+ }
139
+
140
+ /**
141
+ * The block as prose, ```svg fences (when figures are on) and charts after
142
+ * complete tables (when charts are on); only the last run can still stream.
143
+ */
144
+ #segments(): (FigureSegment | ChartSegment)[] {
145
+ const fences: FigureSegment[] = svgFigureRendering()
146
+ ? splitSvgFences(this.#text)
147
+ : [{ kind: "markdown", text: this.#text }];
148
+ if (!this.#options.charts || !hasChartTable(this.#text)) return fences;
149
+ const last = fences.length - 1;
150
+ return fences.flatMap((segment, index): (FigureSegment | ChartSegment)[] =>
151
+ segment.kind === "markdown" ? splitTableCharts(segment.text, this.#transient && index === last) : [segment],
152
+ );
153
+ }
154
+
155
+ /** Mount the parts as children, a blank row between neighbours; a chart draws its own when it has rows. */
156
+ #mount(): void {
157
+ this.clear();
158
+ this.#parts.forEach((part, index) => {
159
+ if (index > 0 && part.kind !== "chart") this.addChild(new Spacer(1));
160
+ this.addChild(part.kind === "markdown" ? part.md : part.figure);
161
+ });
162
+ }
163
+
164
+ /** Push sources and streaming state down: only the last part can still be streaming. */
165
+ #syncTails(): void {
166
+ const last = this.#parts.length - 1;
167
+ this.#parts.forEach((part, index) => {
168
+ const streaming = this.#transient && index === last;
169
+ if (part.kind === "markdown") part.md.transientRenderCache = streaming;
170
+ else if (part.kind === "svg") part.figure.update(part.source, part.closed || !streaming);
171
+ else part.figure.update(part.table);
172
+ });
173
+ }
174
+ }
@@ -64,7 +64,7 @@ export interface SkillPromptDetails {
64
64
  * `ui-helpers.addMessageToChat` (renderers), `AgentHubOverlayComponent
65
65
  * #buildTranscriptLines`, `runPrintMode`, and `AcpAgent#replayAssistantMessage`
66
66
  * (fallback error emission) read it via `isSilentAbort`. */
67
- export declare const SILENT_ABORT_MARKER = "__omp.silent_abort__";
67
+ export declare const SILENT_ABORT_MARKER = "__zeta.silent_abort__";
68
68
  /** Type-guard for silent aborts. Renderers MUST call this helper so structured
69
69
  * `errorId` and legacy persisted marker messages stay in lockstep. */
70
70
  export declare function isSilentAbort(message: Pick<AssistantMessage, "errorId" | "errorMessage">): boolean;
@@ -86,7 +86,7 @@ export interface SkillPromptDetails {
86
86
  * `ui-helpers.addMessageToChat` (renderers), `AgentHubOverlayComponent
87
87
  * #buildTranscriptLines`, `runPrintMode`, and `AcpAgent#replayAssistantMessage`
88
88
  * (fallback error emission) read it via `isSilentAbort`. */
89
- export const SILENT_ABORT_MARKER = "__omp.silent_abort__";
89
+ export const SILENT_ABORT_MARKER = "__zeta.silent_abort__";
90
90
 
91
91
  /** Type-guard for silent aborts. Renderers MUST call this helper so structured
92
92
  * `errorId` and legacy persisted marker messages stay in lockstep. */
@@ -1143,6 +1143,10 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
1143
1143
  const title = pathDisplay ? `Read ${pathDisplay}` : "Read";
1144
1144
  let cachedWidth: number | undefined;
1145
1145
  let cachedLines: string[] | undefined;
1146
+ const dropCache = () => {
1147
+ cachedWidth = undefined;
1148
+ cachedLines = undefined;
1149
+ };
1146
1150
  const expanded = this.#expanded;
1147
1151
  const component: Component = {
1148
1152
  render: (width: number) => {
@@ -1164,10 +1168,8 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
1164
1168
  cachedWidth = width;
1165
1169
  return cachedLines;
1166
1170
  },
1167
- invalidate: () => {
1168
- cachedWidth = undefined;
1169
- cachedLines = undefined;
1170
- },
1171
+ invalidate: dropCache,
1172
+ releaseRenderCaches: dropCache,
1171
1173
  };
1172
1174
  this.addChild(component);
1173
1175
  }
@@ -286,6 +286,12 @@ class SkillCallout implements Component {
286
286
  this.#lines = undefined;
287
287
  }
288
288
 
289
+ releaseRenderCaches(): void {
290
+ this.#source = undefined;
291
+ this.#lines = undefined;
292
+ this.#box.releaseRenderCaches();
293
+ }
294
+
289
295
  render(width: number): readonly string[] {
290
296
  const inner = this.#box.render(Math.max(1, width - 1));
291
297
  if (this.#source === inner && this.#lines !== undefined) return this.#lines;
@@ -0,0 +1,33 @@
1
+ import { type ImageBudget } from "../components/image";
2
+ import { type Markdown } from "../components/markdown";
3
+ import type { Component } from "../tui";
4
+ /** The active theme's color per figure token, for resolving a figure with `prepareSvg`. */
5
+ export declare function svgFigurePalette(): Record<string, string>;
6
+ /** Turn lifting ```svg fences into images on or off (the host's `tui.renderSvg`); the host rebuilds the transcript after. */
7
+ export declare function setSvgFigureRendering(enabled: boolean): void;
8
+ /** Whether assistant ```svg fences render as images where the terminal can show them. */
9
+ export declare function svgFigureRendering(): boolean;
10
+ export interface SvgFigureOptions {
11
+ /**
12
+ * Markdown for the fenced-code fallback shown when the final source does not
13
+ * render. Without it the figure decorates content shown elsewhere (a chart
14
+ * under its table): it stays blank until drawn, and when it cannot be.
15
+ */
16
+ markdown?: (text: string) => Markdown;
17
+ /** Shared inline-image budget; superseded rasters are released from it. */
18
+ budget?: ImageBudget;
19
+ /** The figure's rows changed outside a text update: a raster landed or rendering fell back to code. */
20
+ onChange: () => void;
21
+ }
22
+ export declare class SvgFigure implements Component {
23
+ #private;
24
+ constructor(options: SvgFigureOptions);
25
+ /** Feed the fence body; `final` once the fence closed or the message stopped streaming. */
26
+ update(source: string, final: boolean): void;
27
+ /** Whether the final source still waits for its raster (or for failing to render). */
28
+ get pending(): boolean;
29
+ render(width: number): readonly string[];
30
+ invalidate(): void;
31
+ dispose(): void;
32
+ debugState(): Record<string, unknown>;
33
+ }