@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
@@ -0,0 +1,89 @@
1
+ import type { Tokens } from "@linxiraos/pi-utils/marked";
2
+ import { type ChartPlan } from "../charts/chart-plan";
3
+ import { type TableAnalysis } from "../charts/table-data";
4
+ import type { ImageBudget } from "../components/image";
5
+ import type { NativeNode } from "../native/node";
6
+ import type { Component } from "../tui";
7
+ /**
8
+ * `smart`: a model refines the local guess where meaning decides (kind,
9
+ * columns, row names, ordering, polarity, focus, title; see {@link shouldJudge});
10
+ * `always`: the local best guess charts every table it reads as numeric;
11
+ * `off`: tables stay tables.
12
+ */
13
+ export type TableChartMode = "smart" | "always" | "off";
14
+ /** A table the host's planner picks a chart for ({@link shouldJudge}). */
15
+ export interface TableChartRequest {
16
+ /** The table's Markdown source. */
17
+ readonly markdown: string;
18
+ readonly table: TableAnalysis;
19
+ /** The local best guess; the planner may keep it. */
20
+ readonly guess: ChartPlan;
21
+ }
22
+ /**
23
+ * Picks the chart for a multi-series table under `smart`: a plan, or `null`
24
+ * for no chart. A rejection falls back to the local guess.
25
+ */
26
+ export type TableChartPlanner = (request: TableChartRequest) => Promise<ChartPlan | null>;
27
+ /** A drawn chart, ready to resolve against the theme. */
28
+ export interface TableChart {
29
+ /** SVG colored with figure tokens (`var(--accent)`, …). */
30
+ readonly svg: string;
31
+ readonly alt: string;
32
+ /** Size in SVG user units. */
33
+ readonly width: number;
34
+ readonly height: number;
35
+ }
36
+ /** The chart under a table: drawn, none, or a smart pick on its way (the promise settles once the cache holds it). */
37
+ export type ChartLookup = TableChart | null | Promise<void>;
38
+ /** One run of a Markdown block: prose (ending at a charted table), or the chart drawn after that table. */
39
+ export type ChartSegment = {
40
+ readonly kind: "markdown";
41
+ readonly text: string;
42
+ } | {
43
+ readonly kind: "chart";
44
+ readonly table: Tokens.Table;
45
+ };
46
+ /** Set how tables become charts (the host's `tui.autoGraph`) and its `smart` planner; the host rebuilds the transcript after. */
47
+ export declare function setTableCharts(mode: TableChartMode, planner?: TableChartPlanner): void;
48
+ /** How assistant tables currently become charts. */
49
+ export declare function tableChartMode(): TableChartMode;
50
+ /** Whether `markdown` may hold a table {@link splitTableCharts} would chart. */
51
+ export declare function hasChartTable(markdown: string): boolean;
52
+ /**
53
+ * Split `markdown` after each top-level table that has (or may get) a chart.
54
+ * A table still streaming at the block's tail is left whole: rows may follow.
55
+ */
56
+ export declare function splitTableCharts(markdown: string, streaming: boolean): ChartSegment[];
57
+ /**
58
+ * The chart for `table` under the current mode, read once per table source.
59
+ * Under `smart` the first lookup of a multi-series table asks the planner.
60
+ */
61
+ export declare function lookupTableChart(table: Tokens.Table): ChartLookup;
62
+ /**
63
+ * A native `image` node drawing `chart` from its SVG — no raster — resolved
64
+ * against the active theme; rebuilt when the theme changes.
65
+ */
66
+ export declare function describeTableChart(chart: TableChart, key: string): NativeNode;
67
+ export interface TableChartFigureOptions {
68
+ /** Shared inline-image budget. */
69
+ budget?: ImageBudget;
70
+ /** The chart's rows changed outside a text update: its pick or raster landed. */
71
+ onChange: () => void;
72
+ }
73
+ /**
74
+ * The chart under one table, as a terminal image a blank row below it. Looks
75
+ * the chart up on first render — a block rebuilt mid-stream never asks for a
76
+ * pick it drops — and renders nothing until it is drawn, or when the table
77
+ * gets no chart.
78
+ */
79
+ export declare class TableChartFigure implements Component {
80
+ #private;
81
+ constructor(options: TableChartFigureOptions);
82
+ /** Point the figure at `table`. */
83
+ update(table: Tokens.Table): void;
84
+ /** Whether the chart is still being looked up, picked or drawn. */
85
+ get pending(): boolean;
86
+ render(width: number): readonly string[];
87
+ invalidate(): void;
88
+ dispose(): void;
89
+ }
@@ -0,0 +1,294 @@
1
+ /**
2
+ * Charts drawn under numeric tables in assistant answers (the host's
3
+ * `tui.autoGraph`). {@link splitTableCharts} cuts a Markdown block after each
4
+ * top-level table that gets a chart; {@link lookupTableChart} plans, builds
5
+ * and draws that chart — locally under `always`, through the host's
6
+ * model-backed {@link TableChartPlanner} under `smart` for the tables
7
+ * {@link shouldJudge} picks — and caches it per table source. {@link TableChartFigure} shows it
8
+ * as a rasterized terminal image; {@link describeTableChart} hands a TSP
9
+ * terminal the SVG itself. Both resolve the figure tokens against the live
10
+ * theme, so a chart follows theme switches like the prose around it.
11
+ */
12
+ import { logger } from "@linxiraos/pi-utils";
13
+ import type { Token, Tokens } from "@linxiraos/pi-utils/marked";
14
+ import { type ChartPlan, buildChart, planChart, shouldJudge, worthCharting } from "../charts/chart-plan";
15
+ import { chartAlt, renderChartSvg } from "../charts/chart-svg";
16
+ import { analyzeTable, type TableAnalysis } from "../charts/table-data";
17
+ import type { ImageBudget } from "../components/image";
18
+ import { lexDocument } from "../components/markdown";
19
+ import { keyed } from "../native/describe";
20
+ import { nativeImageNode } from "../native/blobs";
21
+ import type { NativeNode } from "../native/node";
22
+ import { getThemeEpoch } from "../theme";
23
+ import type { Component } from "../tui";
24
+ import { SvgFigure, svgFigurePalette } from "./svg-figure";
25
+ import { prepareSvg } from "./svg-source";
26
+
27
+ /**
28
+ * `smart`: a model refines the local guess where meaning decides (kind,
29
+ * columns, row names, ordering, polarity, focus, title; see {@link shouldJudge});
30
+ * `always`: the local best guess charts every table it reads as numeric;
31
+ * `off`: tables stay tables.
32
+ */
33
+ export type TableChartMode = "smart" | "always" | "off";
34
+
35
+ /** A table the host's planner picks a chart for ({@link shouldJudge}). */
36
+ export interface TableChartRequest {
37
+ /** The table's Markdown source. */
38
+ readonly markdown: string;
39
+ readonly table: TableAnalysis;
40
+ /** The local best guess; the planner may keep it. */
41
+ readonly guess: ChartPlan;
42
+ }
43
+
44
+ /**
45
+ * Picks the chart for a multi-series table under `smart`: a plan, or `null`
46
+ * for no chart. A rejection falls back to the local guess.
47
+ */
48
+ export type TableChartPlanner = (request: TableChartRequest) => Promise<ChartPlan | null>;
49
+
50
+ /** A drawn chart, ready to resolve against the theme. */
51
+ export interface TableChart {
52
+ /** SVG colored with figure tokens (`var(--accent)`, …). */
53
+ readonly svg: string;
54
+ readonly alt: string;
55
+ /** Size in SVG user units. */
56
+ readonly width: number;
57
+ readonly height: number;
58
+ }
59
+
60
+ /** The chart under a table: drawn, none, or a smart pick on its way (the promise settles once the cache holds it). */
61
+ export type ChartLookup = TableChart | null | Promise<void>;
62
+
63
+ /** One run of a Markdown block: prose (ending at a charted table), or the chart drawn after that table. */
64
+ export type ChartSegment =
65
+ | { readonly kind: "markdown"; readonly text: string }
66
+ | { readonly kind: "chart"; readonly table: Tokens.Table };
67
+
68
+ /** Tables cached per source; a long session keeps its recent charts without growing without bound. */
69
+ const CACHE_LIMIT = 256;
70
+ /** SVG user units per terminal column (16 per row on 1:2 cells), sizing native images. */
71
+ const UNITS_PER_COLUMN = 8;
72
+ /** A GFM delimiter row (`|---|:--:|`), the cheap test before lexing a block. */
73
+ const DELIMITER_ROW = /^ {0,3}\|?[ \t]*:?-+:?[ \t]*\|/m;
74
+
75
+ /** A table read once per source: its local guess and, once known, its chart. */
76
+ interface ChartEntry {
77
+ readonly analysis: TableAnalysis;
78
+ readonly guess: ChartPlan | undefined;
79
+ /** The host's planner picks this table's chart. */
80
+ readonly smart: boolean;
81
+ /** `undefined` until drawn (or judged chartless). */
82
+ chart?: TableChart | null;
83
+ pending?: Promise<void>;
84
+ }
85
+
86
+ let chartMode: TableChartMode = "off";
87
+ let chartPlanner: TableChartPlanner | undefined;
88
+ const charts = new Map<string, ChartEntry>();
89
+ /** The theme-resolved image node owning a chart's native bytes. */
90
+ const kNativeImage = Symbol("tableChart.nativeImage");
91
+
92
+ interface NativeTagged extends TableChart {
93
+ [kNativeImage]?: { epoch: number; image: NativeNode };
94
+ }
95
+
96
+ /** Set how tables become charts (the host's `tui.autoGraph`) and its `smart` planner; the host rebuilds the transcript after. */
97
+ export function setTableCharts(mode: TableChartMode, planner?: TableChartPlanner): void {
98
+ chartMode = mode;
99
+ chartPlanner = planner;
100
+ charts.clear();
101
+ }
102
+
103
+ /** How assistant tables currently become charts. */
104
+ export function tableChartMode(): TableChartMode {
105
+ return chartMode;
106
+ }
107
+
108
+ /** Whether `markdown` may hold a table {@link splitTableCharts} would chart. */
109
+ export function hasChartTable(markdown: string): boolean {
110
+ return chartMode !== "off" && markdown.includes("|") && DELIMITER_ROW.test(markdown);
111
+ }
112
+
113
+ /**
114
+ * Split `markdown` after each top-level table that has (or may get) a chart.
115
+ * A table still streaming at the block's tail is left whole: rows may follow.
116
+ */
117
+ export function splitTableCharts(markdown: string, streaming: boolean): ChartSegment[] {
118
+ if (chartMode === "off") return [{ kind: "markdown", text: markdown }];
119
+ const tokens = lexDocument(markdown);
120
+ const segments: ChartSegment[] = [];
121
+ let prose = "";
122
+ tokens.forEach((token, index) => {
123
+ prose += token.raw;
124
+ if (!isTable(token)) return;
125
+ const closed = !streaming || tokens.slice(index + 1).some(next => next.type !== "space");
126
+ const entry = closed ? chartEntry(token) : undefined;
127
+ if (!entry?.guess || entry.chart === null) return;
128
+ segments.push({ kind: "markdown", text: prose }, { kind: "chart", table: token });
129
+ prose = "";
130
+ });
131
+ if (prose.trim() || segments.length === 0) segments.push({ kind: "markdown", text: prose });
132
+ return segments;
133
+ }
134
+
135
+ function isTable(token: Token): token is Tokens.Table {
136
+ return token.type === "table";
137
+ }
138
+
139
+ /**
140
+ * The chart for `table` under the current mode, read once per table source.
141
+ * Under `smart` the first lookup of a multi-series table asks the planner.
142
+ */
143
+ export function lookupTableChart(table: Tokens.Table): ChartLookup {
144
+ if (chartMode === "off") return null;
145
+ const entry = chartEntry(table);
146
+ if (entry.chart !== undefined) return entry.chart;
147
+ if (entry.pending) return entry.pending;
148
+ const { analysis, guess } = entry;
149
+ entry.pending = chartPlanner!({ markdown: table.raw, table: analysis, guess: guess! }).then(
150
+ plan => {
151
+ entry.chart = plan ? drawChart(analysis, plan) : null;
152
+ },
153
+ (error: unknown) => {
154
+ logger.debug("Smart table chart failed; drawing the local guess", { error: String(error) });
155
+ entry.chart = drawChart(analysis, guess!, true);
156
+ },
157
+ );
158
+ return entry.pending;
159
+ }
160
+
161
+ /**
162
+ * `table` read under the current mode, cached per source. A table the local
163
+ * guess decides is drawn at once; a smart pick waits for its first lookup.
164
+ */
165
+ function chartEntry(table: Tokens.Table): ChartEntry {
166
+ const key = table.raw;
167
+ const cached = charts.get(key);
168
+ if (cached) {
169
+ // Re-insert so eviction drops the least recently read table.
170
+ charts.delete(key);
171
+ charts.set(key, cached);
172
+ return cached;
173
+ }
174
+ if (charts.size >= CACHE_LIMIT) charts.delete(charts.keys().next().value!);
175
+ const analysis = analyzeTable(
176
+ table.header.map(cell => cell.text),
177
+ table.rows.map(row => row.map(cell => cell.text)),
178
+ );
179
+ const guess = planChart(analysis);
180
+ const smart = chartMode === "smart" && chartPlanner !== undefined && shouldJudge(analysis, guess);
181
+ const entry: ChartEntry = { analysis, guess, smart };
182
+ if (!smart) entry.chart = guess ? drawChart(analysis, guess, true) : null;
183
+ charts.set(key, entry);
184
+ return entry;
185
+ }
186
+
187
+ /**
188
+ * Draw `plan`. A guess must also pass {@link worthCharting}; a model's pick
189
+ * already judged the chart worth drawing.
190
+ */
191
+ function drawChart(analysis: TableAnalysis, plan: ChartPlan, guessed = false): TableChart | null {
192
+ const spec = buildChart(analysis, plan);
193
+ if (!spec || (guessed && !worthCharting(spec))) return null;
194
+ return { ...renderChartSvg(spec), alt: chartAlt(spec) };
195
+ }
196
+
197
+ /**
198
+ * A native `image` node drawing `chart` from its SVG — no raster — resolved
199
+ * against the active theme; rebuilt when the theme changes.
200
+ */
201
+ export function describeTableChart(chart: TableChart, key: string): NativeNode {
202
+ const epoch = getThemeEpoch();
203
+ const tagged: NativeTagged = chart;
204
+ let entry = tagged[kNativeImage];
205
+ if (entry?.epoch !== epoch) {
206
+ const svg = prepareSvg(chart.svg, svgFigurePalette());
207
+ entry = {
208
+ epoch,
209
+ image: nativeImageNode(new TextEncoder().encode(svg), "image/svg+xml", {
210
+ alt: chart.alt,
211
+ w: chart.width,
212
+ h: chart.height,
213
+ max: { w: `${Math.round(chart.width / UNITS_PER_COLUMN)}ch` },
214
+ }),
215
+ };
216
+ tagged[kNativeImage] = entry;
217
+ }
218
+ return keyed(entry.image, key);
219
+ }
220
+
221
+ export interface TableChartFigureOptions {
222
+ /** Shared inline-image budget. */
223
+ budget?: ImageBudget;
224
+ /** The chart's rows changed outside a text update: its pick or raster landed. */
225
+ onChange: () => void;
226
+ }
227
+
228
+ /**
229
+ * The chart under one table, as a terminal image a blank row below it. Looks
230
+ * the chart up on first render — a block rebuilt mid-stream never asks for a
231
+ * pick it drops — and renders nothing until it is drawn, or when the table
232
+ * gets no chart.
233
+ */
234
+ export class TableChartFigure implements Component {
235
+ readonly #options: TableChartFigureOptions;
236
+ readonly #figure: SvgFigure;
237
+ #table: Tokens.Table | undefined;
238
+ /** `undefined` while not looked up or waiting for a pick. */
239
+ #chart: TableChart | null | undefined;
240
+ #waiting = false;
241
+ #disposed = false;
242
+
243
+ constructor(options: TableChartFigureOptions) {
244
+ this.#options = options;
245
+ this.#figure = new SvgFigure({ budget: options.budget, onChange: options.onChange });
246
+ }
247
+
248
+ /** Point the figure at `table`. */
249
+ update(table: Tokens.Table): void {
250
+ if (table.raw === this.#table?.raw) return;
251
+ this.#table = table;
252
+ this.#chart = undefined;
253
+ this.#waiting = false;
254
+ }
255
+
256
+ /** Whether the chart is still being looked up, picked or drawn. */
257
+ get pending(): boolean {
258
+ return this.#table !== undefined && (this.#chart === undefined || (this.#chart !== null && this.#figure.pending));
259
+ }
260
+
261
+ render(width: number): readonly string[] {
262
+ if (this.#chart === undefined && !this.#waiting) this.#resolve();
263
+ if (!this.#chart) return [];
264
+ const rows = this.#figure.render(width);
265
+ return rows.length ? ["", ...rows] : rows;
266
+ }
267
+
268
+ invalidate(): void {
269
+ this.#figure.invalidate();
270
+ }
271
+
272
+ dispose(): void {
273
+ this.#disposed = true;
274
+ this.#figure.dispose();
275
+ }
276
+
277
+ #resolve(): void {
278
+ const table = this.#table;
279
+ if (!table) return;
280
+ const found = lookupTableChart(table);
281
+ if (found instanceof Promise) {
282
+ this.#waiting = true;
283
+ void found.then(() => {
284
+ if (this.#disposed || this.#table !== table) return;
285
+ this.#waiting = false;
286
+ this.#resolve();
287
+ this.#options.onChange();
288
+ });
289
+ return;
290
+ }
291
+ this.#chart = found;
292
+ if (found) this.#figure.update(found.svg, true);
293
+ }
294
+ }
@@ -90,6 +90,8 @@ export declare class ToolExecutionComponent extends Container {
90
90
  * component-scoped so the TUI reuses every other root subtree (issue #4377).
91
91
  */
92
92
  tickSpinner(frame: number): void;
93
+ /** Whether the result's figure still waits for its raster; the transcript holds retirement meanwhile. */
94
+ isTranscriptBlockPending(): boolean;
93
95
  /**
94
96
  * Whether this block is ready to retire as immutable history. Partial
95
97
  * results, including detached background tasks, remain active and mutable
@@ -48,6 +48,7 @@ import {
48
48
  import type { XdevMountedState } from "../tools/xdev";
49
49
  import { isFramedBlockComponent, markFramedBlockComponent, renderStatusLine, WidthAwareText } from "../render/index";
50
50
  import { cachedPngConversion, convertImageToPngShared, imagePayloadKey } from "./image-loading";
51
+ import { FenceFigure } from "./fence-figure";
51
52
  import { sanitizeWithOptionalSixelPassthrough } from "../render/sixel";
52
53
  import { renderDiff } from "../chrome/diff";
53
54
  import { type AnimationFrame, trimBlankEdges } from "../chrome/transcript-container";
@@ -110,10 +111,13 @@ function resolveEditModeForTool(toolName: string, tool: AgentTool | undefined):
110
111
 
111
112
  type ToolRendererStage = "call" | "result";
112
113
 
113
- /** A renderer's preview as the fallback card's clamp (`tail` becomes a head clamp of the same size). */
114
+ /**
115
+ * A renderer's preview as the fallback card's clamp (`tail` becomes a head
116
+ * clamp of the same size; `children` leaves the clamping to the body's own previews).
117
+ */
114
118
  function cardPreview(preview: NativeToolView["preview"]): TspPreview | undefined {
115
119
  if (preview === undefined) return { lines: DEFAULT_TERMINAL_PREVIEW_LINES };
116
- if (preview === "none") return undefined;
120
+ if (preview === "none" || preview === "children") return undefined;
117
121
  if (preview !== "auto" && "tail" in preview) return { lines: preview.tail };
118
122
  return preview;
119
123
  }
@@ -169,6 +173,24 @@ class SafeToolRendererComponent implements Component {
169
173
  invalidate.call(this.#component);
170
174
  }
171
175
 
176
+ releaseRenderCaches(): void {
177
+ const release = this.#component.releaseRenderCaches;
178
+ if (release === undefined) return;
179
+ try {
180
+ release.call(this.#component);
181
+ } catch (err) {
182
+ if (!this.#warned) {
183
+ this.#warned = true;
184
+ logger.warn("Tool renderer failed", {
185
+ tool: this.#toolName,
186
+ stage: this.#stage,
187
+ phase: "releaseRenderCaches",
188
+ error: String(err),
189
+ });
190
+ }
191
+ }
192
+ }
193
+
172
194
  setIgnoreTight(ignore: boolean): void {
173
195
  const setIgnoreTight = this.#component.setIgnoreTight;
174
196
  if (setIgnoreTight === undefined) return;
@@ -301,6 +323,8 @@ export class ToolExecutionComponent extends Container {
301
323
  #multiFileBoxes: (Box | Spacer)[] = []; // Extra boxes for multi-file edit results
302
324
  #imageComponents: Image[] = [];
303
325
  #imageSpacers: Spacer[] = [];
326
+ /** The renderer's {@link ToolRenderer.figure} drawing; kept across rebuilds while its language is unchanged, so it redraws in place and its raster survives them. */
327
+ #figure: FenceFigure | undefined;
304
328
  readonly #instanceId = ++toolExecutionInstanceSeq;
305
329
  #toolName: string;
306
330
  #toolLabel: string;
@@ -759,6 +783,11 @@ export class ToolExecutionComponent extends Container {
759
783
  }
760
784
  }
761
785
 
786
+ /** Whether the result's figure still waits for its raster; the transcript holds retirement meanwhile. */
787
+ isTranscriptBlockPending(): boolean {
788
+ return this.#toolActivityVisible && this.#figure?.pending === true;
789
+ }
790
+
762
791
  /**
763
792
  * Whether this block is ready to retire as immutable history. Partial
764
793
  * results, including detached background tasks, remain active and mutable
@@ -941,11 +970,13 @@ export class ToolExecutionComponent extends Container {
941
970
 
942
971
  /**
943
972
  * The native `collapsed` prop: the transcript's expand state, except that a
944
- * call streaming its body (edit, write) stays open until it settles, then
973
+ * view that asks to be {@link NativeToolView.open} never starts folded, and
974
+ * a call streaming its body (edit, write) stays open until it settles, then
945
975
  * folds like a finished thought. The user's own toggle still wins meanwhile:
946
976
  * the terminal keeps local collapse state until this prop changes.
947
977
  */
948
- #nativeCollapsed(status: TspCardStatus): boolean {
978
+ #nativeCollapsed(status: TspCardStatus, view: NativeToolView): boolean {
979
+ if (view.open) return false;
949
980
  const live = status === "pending" || status === "running";
950
981
  return !this.#expanded && !(live && streamsBody(this.#toolName));
951
982
  }
@@ -997,6 +1028,7 @@ export class ToolExecutionComponent extends Container {
997
1028
  target: head?.target,
998
1029
  targetKind: head?.targetKind,
999
1030
  lang: head?.lang,
1031
+ command: head?.command,
1000
1032
  href: head?.href,
1001
1033
  meta: head?.meta,
1002
1034
  badges: badges.length > 0 ? badges : undefined,
@@ -1008,7 +1040,7 @@ export class ToolExecutionComponent extends Container {
1008
1040
  intent: typeof intent === "string" && intent ? plainText(intent) : undefined,
1009
1041
  frame: inline ? "inline" : "card",
1010
1042
  collapsible: hasBody,
1011
- collapsed: hasBody ? this.#nativeCollapsed(status) : undefined,
1043
+ collapsed: hasBody ? this.#nativeCollapsed(status, view) : undefined,
1012
1044
  preview: hasBody ? (preview === "auto" ? { lines: DEFAULT_TERMINAL_PREVIEW_LINES } : preview) : undefined,
1013
1045
  tools: view.tools,
1014
1046
  tone: view.tone,
@@ -1076,7 +1108,7 @@ export class ToolExecutionComponent extends Container {
1076
1108
  tone: view.tone ?? NATIVE_STATUS_TONE[status],
1077
1109
  status,
1078
1110
  collapsible: hasBody,
1079
- collapsed: hasBody ? this.#nativeCollapsed(status) : undefined,
1111
+ collapsed: hasBody ? this.#nativeCollapsed(status, view) : undefined,
1080
1112
  preview: hasBody ? cardPreview(view.preview) : undefined,
1081
1113
  },
1082
1114
  children,
@@ -1096,11 +1128,14 @@ export class ToolExecutionComponent extends Container {
1096
1128
  * A renderer that throws falls back to the generic card.
1097
1129
  */
1098
1130
  #nativeView(): NativeToolView {
1131
+ const status = this.#nativeStatus();
1099
1132
  const options: RenderResultContextOptions = {
1100
1133
  expanded: this.#expanded,
1101
1134
  isPartial: this.#isPartial,
1102
1135
  argsComplete: this.#argsComplete,
1103
1136
  executionStarted: this.#executionStarted,
1137
+ elapsedMs: this.#elapsedMs(status),
1138
+ cancelled: status === "cancelled",
1104
1139
  renderContext: this.#buildRenderContext(),
1105
1140
  };
1106
1141
  // Custom tools (MCP, extensions) carry their own describe hooks, mirroring
@@ -1132,6 +1167,7 @@ export class ToolExecutionComponent extends Container {
1132
1167
  body: [...(callView.body ?? []), ...(resultView.body ?? [])],
1133
1168
  tone: resultView.tone ?? callView.tone,
1134
1169
  preview: resultView.preview ?? callView.preview,
1170
+ open: resultView.open ?? callView.open,
1135
1171
  inline: resultView.inline ?? callView.inline,
1136
1172
  tools: resultView.tools ?? callView.tools,
1137
1173
  };
@@ -1611,6 +1647,7 @@ export class ToolExecutionComponent extends Container {
1611
1647
  this.removeChild(spacer);
1612
1648
  }
1613
1649
  this.#imageSpacers = [];
1650
+ this.#syncFigure();
1614
1651
 
1615
1652
  if (this.#result) {
1616
1653
  const imageBlocks = this.#getAllImageBlocks();
@@ -1639,7 +1676,12 @@ export class ToolExecutionComponent extends Container {
1639
1676
  imageData,
1640
1677
  imageMimeType,
1641
1678
  { fallbackColor: (s: string) => theme.fg("toolOutput", s) },
1642
- { ...resolveImageOptions(), budget: this.#ui.imageBudget, imageKey: `te${this.#instanceId}:${i}` },
1679
+ {
1680
+ ...resolveImageOptions(),
1681
+ budget: this.#ui.imageBudget,
1682
+ imageKey: `te${this.#instanceId}:${i}`,
1683
+ requestRender: () => this.#ui.requestRender(),
1684
+ },
1643
1685
  );
1644
1686
  this.#imageComponents.push(imageComponent);
1645
1687
  this.addChild(imageComponent);
@@ -1649,6 +1691,43 @@ export class ToolExecutionComponent extends Container {
1649
1691
  this.#renderedImageCount = this.#imageComponents.length;
1650
1692
  }
1651
1693
 
1694
+ /**
1695
+ * Mount the built-in renderer's figure under the card and feed it the fence
1696
+ * as it stands: the mounted one stays while its language is unchanged, so it
1697
+ * redraws in place as the args stream.
1698
+ */
1699
+ #syncFigure(): void {
1700
+ const result = this.#result;
1701
+ const renderer = this.#tool?.renderCall || this.#tool?.renderResult ? undefined : this.#renderer;
1702
+ const fence =
1703
+ this.#isBenignSkip() || isNativeRendering()
1704
+ ? undefined
1705
+ : renderer?.figure?.(
1706
+ this.#args,
1707
+ result && { content: result.content, details: result.details, isError: result.isError },
1708
+ this.#renderState,
1709
+ );
1710
+ const drawable = fence !== undefined && FenceFigure.draws(fence, { showImages: this.#showImages });
1711
+ let figure = this.#figure;
1712
+ if (figure && (!drawable || figure.lang !== fence.lang)) {
1713
+ this.removeChild(figure);
1714
+ figure.dispose();
1715
+ figure = this.#figure = undefined;
1716
+ }
1717
+ if (!drawable) return;
1718
+ if (!figure) {
1719
+ figure = this.#figure = new FenceFigure(fence.lang, {
1720
+ budget: this.#ui.imageBudget,
1721
+ onChange: () => {
1722
+ this.#blockVersion++;
1723
+ this.#ui.requestRender();
1724
+ },
1725
+ });
1726
+ this.addChild(figure);
1727
+ }
1728
+ figure.update(fence);
1729
+ }
1730
+
1652
1731
  #getCallArgsForRender(): unknown {
1653
1732
  const renderArgs = this.#args;
1654
1733
  if (!isEditLikeToolName(this.#toolName)) {
@@ -1,10 +1,11 @@
1
+ import type { AnimationFrame, TranscriptPresentationTarget } from "../chrome/transcript-container";
1
2
  import { type Component, Container } from "../tui";
2
3
  import type { ImageContent } from "@linxiraos/pi-ai";
3
4
  import type { ReactionTarget } from "./reaction";
4
- import { type NativeNode, type NativeUiEvent } from "../native/node";
5
+ import { type DescribeContext, type NativeNode, type NativeUiEvent } from "../native/node";
5
6
  /** How a user bubble styles its prose and chips (see {@link userBubbleColor}). */
6
7
  export interface UserBubbleOptions {
7
- /** Materialized `file://` targets per attached image, indexed by chip number. */
8
+ /** Filesystem paths for attached image chips, indexed by chip number. */
8
9
  imageLinks?: readonly (string | undefined)[];
9
10
  /** The message's attached images in chip order (`#1` first); a native bubble shows them. */
10
11
  images?: readonly ImageContent[];
@@ -30,9 +31,10 @@ export declare function userBubbleColor(options?: UserBubbleOptions, tokenRegex?
30
31
  * (see {@link ReactionTarget}) drawn right-aligned in the bubble's top padding row;
31
32
  * a live-steered message carries a `*` marker left-aligned in the same row.
32
33
  */
33
- export declare class UserMessageComponent extends Container implements ReactionTarget {
34
+ export declare class UserMessageComponent extends Container implements ReactionTarget, TranscriptPresentationTarget {
34
35
  #private;
35
36
  constructor(text: string, options?: UserBubbleOptions);
37
+ releaseRenderCaches(): void;
36
38
  setReaction(emoji: string): void;
37
39
  /**
38
40
  * A head-less user-toned frame with the prompt as markdown under its
@@ -42,9 +44,19 @@ export declare class UserMessageComponent extends Container implements ReactionT
42
44
  * agent's reaction are chips at the bottom-right, so a reaction landing
43
45
  * later updates the frame in place, even deep in scrollback.
44
46
  */
45
- describe(): NativeNode;
47
+ describe(cx?: DescribeContext): NativeNode;
46
48
  /** Hover toolbar clicks: zeta's own copy and rewind commands. */
47
49
  handleNativeEvent(event: NativeUiEvent): void;
50
+ /** Apply the transcript allocator's current viewport reservation. */
51
+ setTranscriptAllocation(rows: number, _frame?: AnimationFrame): void;
52
+ isTranscriptBlockFinalized(): boolean;
53
+ /**
54
+ * Single-row emergency representation for the overflow transcript layout:
55
+ * renders the first content line instead of the blank top padding row, and
56
+ * omits OSC 133 shell integration markers so moving live blocks across the
57
+ * viewport does not leave stale prompt marks on lines it no longer occupies.
58
+ */
59
+ renderTranscriptBlockEmergencyRow(width: number): string | undefined;
48
60
  render(width: number): readonly string[];
49
61
  }
50
62
  /**
@@ -75,6 +87,7 @@ export declare class CollapsedSyntheticMessageComponent implements Component {
75
87
  handleNativeEvent(event: NativeUiEvent): void;
76
88
  setIgnoreTight(ignore: boolean): this;
77
89
  invalidate(): void;
90
+ releaseRenderCaches(): void;
78
91
  dispose(): void;
79
92
  render(width: number): readonly string[];
80
93
  }