@linxiraos/pi-tui 1.1.27 → 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 (373) hide show
  1. package/CHANGELOG.md +47 -463
  2. package/README.md +7 -5
  3. package/dist/types/app-keybindings.d.ts +1 -1
  4. package/dist/types/apps/cleanse-board.d.ts +1 -1
  5. package/dist/types/apps/debug/log-viewer.d.ts +4 -0
  6. package/dist/types/apps/debug/raw-sse-buffer.d.ts +2 -0
  7. package/dist/types/apps/git/git-tui.d.ts +2 -2
  8. package/dist/types/apps/git/help.d.ts +3 -1
  9. package/dist/types/apps/if-bench-board.d.ts +2 -2
  10. package/dist/types/apps/setup-model-picker.d.ts +1 -1
  11. package/dist/types/autocomplete.d.ts +5 -2
  12. package/dist/types/charts/chart-plan.d.ts +674 -0
  13. package/dist/types/charts/chart-svg.d.ts +59 -0
  14. package/dist/types/charts/table-data.d.ts +175 -0
  15. package/dist/types/chat/assistant-message.d.ts +5 -0
  16. package/dist/types/chat/chat-transcript-builder.d.ts +2 -0
  17. package/dist/types/chat/compaction-summary-message.d.ts +1 -0
  18. package/dist/types/chat/execution-shared.d.ts +6 -5
  19. package/dist/types/chat/fence-figure.d.ts +42 -0
  20. package/dist/types/chat/figure-markdown.d.ts +42 -0
  21. package/dist/types/chat/messages.d.ts +1 -1
  22. package/dist/types/chat/svg-figure.d.ts +33 -0
  23. package/dist/types/chat/svg-source.d.ts +49 -0
  24. package/dist/types/chat/table-chart.d.ts +89 -0
  25. package/dist/types/chat/tool-execution.d.ts +2 -0
  26. package/dist/types/chat/user-message.d.ts +15 -2
  27. package/dist/types/chrome/shared.d.ts +9 -0
  28. package/dist/types/chrome/transcript-container.d.ts +6 -0
  29. package/dist/types/components/box.d.ts +1 -0
  30. package/dist/types/components/disclosure.d.ts +1 -0
  31. package/dist/types/components/editor.d.ts +15 -4
  32. package/dist/types/components/form.d.ts +1 -0
  33. package/dist/types/components/image.d.ts +12 -44
  34. package/dist/types/components/key-value-list.d.ts +1 -0
  35. package/dist/types/components/layout/row.d.ts +1 -0
  36. package/dist/types/components/layout/stack.d.ts +1 -0
  37. package/dist/types/components/markdown.d.ts +36 -3
  38. package/dist/types/components/scroll-view.d.ts +1 -0
  39. package/dist/types/components/section.d.ts +1 -0
  40. package/dist/types/components/table.d.ts +1 -0
  41. package/dist/types/components/text.d.ts +1 -0
  42. package/dist/types/components/tree-view.d.ts +7 -0
  43. package/dist/types/components/truncated-text.d.ts +1 -0
  44. package/dist/types/fuzzy.d.ts +29 -1
  45. package/dist/types/key-hint-format.d.ts +1 -1
  46. package/dist/types/keybinding-matchers.d.ts +3 -0
  47. package/dist/types/keybindings.d.ts +1 -1
  48. package/dist/types/kitty-graphics.d.ts +2 -2
  49. package/dist/types/loop-watchdog.d.ts +8 -7
  50. package/dist/types/multiplexers/cmux.d.ts +16 -0
  51. package/dist/types/multiplexers/herdr.d.ts +26 -0
  52. package/dist/types/multiplexers/notify.d.ts +13 -0
  53. package/dist/types/multiplexers/orca.d.ts +12 -0
  54. package/dist/types/multiplexers/screen.d.ts +9 -0
  55. package/dist/types/multiplexers/tmux.d.ts +29 -0
  56. package/dist/types/multiplexers/types.d.ts +100 -0
  57. package/dist/types/multiplexers/wmux.d.ts +12 -0
  58. package/dist/types/multiplexers/zellij.d.ts +12 -0
  59. package/dist/types/native/backend.d.ts +3 -2
  60. package/dist/types/native/blobs.d.ts +7 -3
  61. package/dist/types/native/encode.d.ts +3 -4
  62. package/dist/types/native/overlay.d.ts +5 -0
  63. package/dist/types/overlays/agent-hub-projection.d.ts +6 -5
  64. package/dist/types/overlays/agent-hub-types.d.ts +9 -0
  65. package/dist/types/overlays/agent-hub.d.ts +2 -0
  66. package/dist/types/overlays/agent-transcript-viewer.d.ts +11 -2
  67. package/dist/types/overlays/agents-hub.d.ts +9 -0
  68. package/dist/types/overlays/annotation-overlay.d.ts +19 -2
  69. package/dist/types/overlays/annotation-types.d.ts +2 -0
  70. package/dist/types/overlays/ask-dialog.d.ts +5 -2
  71. package/dist/types/overlays/history-search.d.ts +10 -0
  72. package/dist/types/overlays/hook-selector.d.ts +9 -4
  73. package/dist/types/overlays/jobs-panel.d.ts +1 -7
  74. package/dist/types/overlays/model-browser.d.ts +54 -7
  75. package/dist/types/overlays/model-hub.d.ts +23 -0
  76. package/dist/types/overlays/oauth-selector.d.ts +0 -1
  77. package/dist/types/overlays/plan-review-overlay.d.ts +3 -2
  78. package/dist/types/overlays/session-observer-registry.d.ts +2 -0
  79. package/dist/types/overlays/session-selector.d.ts +6 -2
  80. package/dist/types/overlays/settings-defs.d.ts +1 -0
  81. package/dist/types/overlays/usage-dashboard.d.ts +8 -4
  82. package/dist/types/overlays/usage-display.d.ts +3 -1
  83. package/dist/types/prompt/composer.d.ts +1 -1
  84. package/dist/types/prompt/custom-editor.d.ts +11 -8
  85. package/dist/types/prompt/image-source.d.ts +2 -1
  86. package/dist/types/prompt/interactive-context-helpers.d.ts +4 -1
  87. package/dist/types/prompt/model-mention-autocomplete.d.ts +1 -1
  88. package/dist/types/prompt/welcome.d.ts +6 -1
  89. package/dist/types/render/composite.d.ts +2 -0
  90. package/dist/types/render/output-pane.d.ts +1 -0
  91. package/dist/types/render/render-utils.d.ts +1 -0
  92. package/dist/types/render/tool-card.d.ts +6 -0
  93. package/dist/types/render/width-aware-text.d.ts +2 -0
  94. package/dist/types/setup/scenes/types.d.ts +1 -0
  95. package/dist/types/status-line/component.d.ts +3 -0
  96. package/dist/types/status-line/host.d.ts +4 -1
  97. package/dist/types/status-line/segments.d.ts +2 -0
  98. package/dist/types/status-line/types.d.ts +14 -3
  99. package/dist/types/terminal-capabilities.d.ts +27 -35
  100. package/dist/types/terminal-multiplexer.d.ts +127 -14
  101. package/dist/types/terminal.d.ts +22 -6
  102. package/dist/types/theme/active-symbols.d.ts +1 -1
  103. package/dist/types/theme/schema.d.ts +11 -2
  104. package/dist/types/theme/symbols.d.ts +1 -1
  105. package/dist/types/theme/theme-class.d.ts +7 -0
  106. package/dist/types/theme/theme.d.ts +1 -1
  107. package/dist/types/theme/tui-adapters.d.ts +3 -0
  108. package/dist/types/tmux.d.ts +11 -4
  109. package/dist/types/tools/daemon.d.ts +1 -1
  110. package/dist/types/tools/eval.d.ts +22 -3
  111. package/dist/types/tools/glob.d.ts +4 -0
  112. package/dist/types/tools/native-view.d.ts +47 -0
  113. package/dist/types/tools/output-meta.d.ts +11 -1
  114. package/dist/types/tools/renderer.d.ts +37 -2
  115. package/dist/types/tools/streaming-output.d.ts +20 -1
  116. package/dist/types/tools/task.d.ts +0 -4
  117. package/dist/types/tools/write.d.ts +9 -2
  118. package/dist/types/tools/yield.d.ts +22 -0
  119. package/dist/types/tui.d.ts +31 -0
  120. package/dist/types/utils.d.ts +6 -0
  121. package/dist/types/vim.d.ts +19 -5
  122. package/package.json +13 -9
  123. package/src/app-keybindings.d.ts +1 -1
  124. package/src/app-keybindings.ts +1 -1
  125. package/src/apps/autoresearch-dashboard.ts +7 -3
  126. package/src/apps/cleanse-board.ts +2 -2
  127. package/src/apps/cleanse-picker.ts +1 -1
  128. package/src/apps/debug/log-viewer.ts +188 -72
  129. package/src/apps/debug/raw-sse-buffer.ts +8 -0
  130. package/src/apps/debug/raw-sse.ts +39 -5
  131. package/src/apps/git/diff-pane.ts +26 -5
  132. package/src/apps/git/git-tui.ts +2 -2
  133. package/src/apps/git/help.ts +29 -20
  134. package/src/apps/if-bench-board.ts +2 -2
  135. package/src/apps/ps-top.ts +2 -2
  136. package/src/apps/setup-model-picker.ts +1 -1
  137. package/src/autocomplete.d.ts +5 -2
  138. package/src/autocomplete.ts +67 -43
  139. package/src/charts/chart-plan.d.ts +674 -0
  140. package/src/charts/chart-plan.ts +5081 -0
  141. package/src/charts/chart-svg.d.ts +59 -0
  142. package/src/charts/chart-svg.ts +4657 -0
  143. package/src/charts/table-data.d.ts +175 -0
  144. package/src/charts/table-data.ts +1478 -0
  145. package/src/chat/advisor-message.ts +11 -0
  146. package/src/chat/assistant-message.d.ts +5 -0
  147. package/src/chat/assistant-message.ts +219 -50
  148. package/src/chat/chat-transcript-builder.d.ts +2 -0
  149. package/src/chat/chat-transcript-builder.ts +5 -3
  150. package/src/chat/compaction-summary-message.d.ts +1 -0
  151. package/src/chat/compaction-summary-message.ts +8 -0
  152. package/src/chat/execution-shared.d.ts +6 -5
  153. package/src/chat/execution-shared.ts +42 -25
  154. package/src/chat/fence-figure.d.ts +42 -0
  155. package/src/chat/fence-figure.ts +80 -0
  156. package/src/chat/figure-markdown.d.ts +42 -0
  157. package/src/chat/figure-markdown.ts +174 -0
  158. package/src/chat/messages.d.ts +1 -1
  159. package/src/chat/messages.ts +1 -1
  160. package/src/chat/read-tool-group.ts +6 -4
  161. package/src/chat/skill-message.ts +6 -0
  162. package/src/chat/svg-figure.d.ts +33 -0
  163. package/src/chat/svg-figure.ts +399 -0
  164. package/src/chat/svg-source.d.ts +49 -0
  165. package/src/chat/svg-source.ts +188 -0
  166. package/src/chat/table-chart.d.ts +89 -0
  167. package/src/chat/table-chart.ts +294 -0
  168. package/src/chat/tool-execution.d.ts +2 -0
  169. package/src/chat/tool-execution.ts +80 -6
  170. package/src/chat/user-message.d.ts +15 -2
  171. package/src/chat/user-message.ts +55 -3
  172. package/src/chrome/shared.ts +53 -0
  173. package/src/chrome/transcript-container.d.ts +6 -0
  174. package/src/chrome/transcript-container.ts +93 -13
  175. package/src/components/box.d.ts +1 -0
  176. package/src/components/box.ts +5 -0
  177. package/src/components/disclosure.d.ts +1 -0
  178. package/src/components/disclosure.ts +8 -0
  179. package/src/components/editor.d.ts +15 -4
  180. package/src/components/editor.ts +294 -46
  181. package/src/components/form.d.ts +1 -0
  182. package/src/components/form.ts +8 -0
  183. package/src/components/image.d.ts +12 -44
  184. package/src/components/image.ts +47 -151
  185. package/src/components/key-value-list.d.ts +1 -0
  186. package/src/components/key-value-list.ts +4 -0
  187. package/src/components/layout/row.d.ts +1 -0
  188. package/src/components/layout/row.ts +7 -0
  189. package/src/components/layout/stack.d.ts +1 -0
  190. package/src/components/layout/stack.ts +7 -0
  191. package/src/components/markdown.d.ts +36 -3
  192. package/src/components/markdown.ts +433 -318
  193. package/src/components/scroll-view.d.ts +1 -0
  194. package/src/components/scroll-view.ts +5 -0
  195. package/src/components/section.d.ts +1 -0
  196. package/src/components/section.ts +5 -0
  197. package/src/components/settings-list.ts +2 -0
  198. package/src/components/table.d.ts +1 -0
  199. package/src/components/table.ts +4 -0
  200. package/src/components/text.d.ts +1 -0
  201. package/src/components/text.ts +7 -0
  202. package/src/components/tree-view.d.ts +7 -0
  203. package/src/components/tree-view.ts +38 -8
  204. package/src/components/truncated-text.d.ts +1 -0
  205. package/src/components/truncated-text.ts +5 -0
  206. package/src/desktop-notify.ts +1 -1
  207. package/src/fuzzy.d.ts +29 -1
  208. package/src/fuzzy.ts +115 -30
  209. package/src/key-hint-format.d.ts +1 -1
  210. package/src/key-hint-format.ts +1 -1
  211. package/src/keybinding-matchers.d.ts +3 -0
  212. package/src/keybinding-matchers.ts +6 -2
  213. package/src/keybindings.d.ts +1 -1
  214. package/src/keybindings.ts +1 -1
  215. package/src/kitty-graphics.d.ts +2 -2
  216. package/src/kitty-graphics.ts +4 -4
  217. package/src/loop-watchdog.d.ts +8 -7
  218. package/src/loop-watchdog.ts +18 -13
  219. package/src/multiplexers/cmux.d.ts +16 -0
  220. package/src/multiplexers/cmux.ts +29 -0
  221. package/src/multiplexers/herdr.d.ts +26 -0
  222. package/src/multiplexers/herdr.ts +64 -0
  223. package/src/multiplexers/notify.d.ts +13 -0
  224. package/src/multiplexers/notify.ts +24 -0
  225. package/src/multiplexers/orca.d.ts +12 -0
  226. package/src/multiplexers/orca.ts +16 -0
  227. package/src/multiplexers/screen.d.ts +9 -0
  228. package/src/multiplexers/screen.ts +15 -0
  229. package/src/multiplexers/tmux.d.ts +29 -0
  230. package/src/multiplexers/tmux.ts +40 -0
  231. package/src/multiplexers/types.d.ts +100 -0
  232. package/src/multiplexers/types.ts +110 -0
  233. package/src/multiplexers/wmux.d.ts +12 -0
  234. package/src/multiplexers/wmux.ts +16 -0
  235. package/src/multiplexers/zellij.d.ts +12 -0
  236. package/src/multiplexers/zellij.ts +24 -0
  237. package/src/native/backend.d.ts +3 -2
  238. package/src/native/backend.ts +174 -18
  239. package/src/native/blobs.d.ts +7 -3
  240. package/src/native/blobs.ts +47 -12
  241. package/src/native/encode.d.ts +3 -4
  242. package/src/native/encode.ts +58 -31
  243. package/src/native/overlay.d.ts +5 -0
  244. package/src/native/overlay.ts +13 -0
  245. package/src/native/reconcile.ts +4 -0
  246. package/src/overlays/agent-hub-projection.d.ts +6 -5
  247. package/src/overlays/agent-hub-projection.ts +124 -13
  248. package/src/overlays/agent-hub-types.d.ts +9 -0
  249. package/src/overlays/agent-hub-types.ts +6 -0
  250. package/src/overlays/agent-hub.ts +44 -29
  251. package/src/overlays/agent-transcript-viewer.ts +91 -23
  252. package/src/overlays/agents-hub.ts +28 -8
  253. package/src/overlays/annotation-overlay.ts +293 -90
  254. package/src/overlays/annotation-types.ts +2 -0
  255. package/src/overlays/ask-dialog.ts +7 -10
  256. package/src/overlays/btw-history-panel.ts +12 -1
  257. package/src/overlays/copy-selector.ts +30 -8
  258. package/src/overlays/extensions/state-manager.ts +52 -12
  259. package/src/overlays/history-search.ts +100 -7
  260. package/src/overlays/hook-selector.ts +12 -5
  261. package/src/overlays/jobs-panel.ts +28 -46
  262. package/src/overlays/model-browser.ts +341 -110
  263. package/src/overlays/model-hub.ts +300 -49
  264. package/src/overlays/move-overlay.ts +28 -14
  265. package/src/overlays/oauth-selector.ts +54 -70
  266. package/src/overlays/plan-review-overlay.ts +194 -70
  267. package/src/overlays/plugin-settings.ts +3 -3
  268. package/src/overlays/report-panel.ts +2 -2
  269. package/src/overlays/rewind-selector.ts +86 -17
  270. package/src/overlays/session-observer-registry.d.ts +2 -0
  271. package/src/overlays/session-observer-registry.ts +10 -2
  272. package/src/overlays/session-selector.ts +64 -26
  273. package/src/overlays/settings-defs.ts +4 -3
  274. package/src/overlays/settings-selector.ts +33 -8
  275. package/src/overlays/snapcompact-shape-preview.ts +2 -3
  276. package/src/overlays/stats-notice.ts +1 -1
  277. package/src/overlays/tree-selector.ts +41 -20
  278. package/src/overlays/usage-dashboard.ts +100 -50
  279. package/src/overlays/usage-display.ts +10 -4
  280. package/src/prompt/attachment-chips.ts +15 -11
  281. package/src/prompt/composer-attachments.ts +6 -4
  282. package/src/prompt/composer.ts +4 -15
  283. package/src/prompt/custom-editor.ts +54 -26
  284. package/src/prompt/image-source.ts +2 -1
  285. package/src/prompt/interactive-context-helpers.ts +30 -18
  286. package/src/prompt/macos-spelling.ts +7 -0
  287. package/src/prompt/magic-keywords.ts +11 -2
  288. package/src/prompt/model-mention-autocomplete.ts +14 -14
  289. package/src/prompt/tips.txt +6 -5
  290. package/src/prompt/welcome.ts +55 -12
  291. package/src/prompt/word-completion.ts +38 -5
  292. package/src/render/composite.d.ts +2 -0
  293. package/src/render/composite.ts +64 -0
  294. package/src/render/output-pane.d.ts +1 -0
  295. package/src/render/output-pane.ts +6 -0
  296. package/src/render/render-utils.d.ts +1 -0
  297. package/src/render/render-utils.ts +11 -0
  298. package/src/render/tool-card.d.ts +6 -0
  299. package/src/render/tool-card.ts +15 -0
  300. package/src/render/width-aware-text.d.ts +2 -0
  301. package/src/render/width-aware-text.ts +5 -0
  302. package/src/setup/scenes/model.ts +2 -1
  303. package/src/setup/scenes/types.ts +1 -0
  304. package/src/status-line/component.ts +292 -78
  305. package/src/status-line/host.ts +4 -1
  306. package/src/status-line/segments.ts +40 -22
  307. package/src/status-line/types.ts +15 -3
  308. package/src/terminal-capabilities.d.ts +27 -35
  309. package/src/terminal-capabilities.ts +75 -189
  310. package/src/terminal-multiplexer.d.ts +127 -14
  311. package/src/terminal-multiplexer.ts +112 -33
  312. package/src/terminal.d.ts +22 -6
  313. package/src/terminal.ts +139 -37
  314. package/src/theme/active-symbols.d.ts +1 -1
  315. package/src/theme/active-symbols.ts +1 -1
  316. package/src/theme/schema-validation.ts +1 -0
  317. package/src/theme/schema.d.ts +11 -2
  318. package/src/theme/schema.ts +14 -1
  319. package/src/theme/session-color.ts +1 -7
  320. package/src/theme/symbols.d.ts +1 -1
  321. package/src/theme/symbols.ts +6 -1
  322. package/src/theme/theme-class.d.ts +7 -0
  323. package/src/theme/theme-class.ts +26 -1
  324. package/src/theme/theme-schema.json +5 -1
  325. package/src/theme/theme.d.ts +1 -1
  326. package/src/theme/theme.ts +8 -4
  327. package/src/theme/tui-adapters.d.ts +3 -0
  328. package/src/theme/tui-adapters.ts +68 -0
  329. package/src/tmux.d.ts +11 -4
  330. package/src/tmux.ts +47 -11
  331. package/src/tools/ast-edit.ts +59 -35
  332. package/src/tools/ast-grep.ts +35 -16
  333. package/src/tools/bash.ts +92 -42
  334. package/src/tools/daemon.d.ts +1 -1
  335. package/src/tools/daemon.ts +1 -1
  336. package/src/tools/default-renderer.ts +35 -19
  337. package/src/tools/edit.ts +142 -120
  338. package/src/tools/eval-format/index.ts +28 -2
  339. package/src/tools/eval-format/javascript.ts +7 -5
  340. package/src/tools/eval.d.ts +22 -3
  341. package/src/tools/eval.ts +364 -208
  342. package/src/tools/fetch.ts +5 -6
  343. package/src/tools/glob.d.ts +4 -0
  344. package/src/tools/glob.ts +33 -65
  345. package/src/tools/grep.ts +81 -48
  346. package/src/tools/index.ts +2 -0
  347. package/src/tools/lsp.ts +81 -59
  348. package/src/tools/mcp.ts +111 -68
  349. package/src/tools/native-view.d.ts +47 -0
  350. package/src/tools/native-view.ts +102 -1
  351. package/src/tools/output-meta.d.ts +11 -1
  352. package/src/tools/output-meta.ts +23 -3
  353. package/src/tools/read.ts +7 -5
  354. package/src/tools/renderer.d.ts +37 -2
  355. package/src/tools/renderer.ts +42 -2
  356. package/src/tools/streaming-output.d.ts +20 -1
  357. package/src/tools/streaming-output.ts +149 -50
  358. package/src/tools/task.d.ts +0 -4
  359. package/src/tools/task.ts +112 -59
  360. package/src/tools/todo.ts +119 -30
  361. package/src/tools/wait.ts +34 -24
  362. package/src/tools/web-search.ts +1 -1
  363. package/src/tools/write.d.ts +9 -2
  364. package/src/tools/write.ts +147 -95
  365. package/src/tools/yield.d.ts +22 -0
  366. package/src/tools/yield.ts +225 -0
  367. package/src/tui.d.ts +31 -0
  368. package/src/tui.ts +309 -160
  369. package/src/utils.d.ts +6 -0
  370. package/src/utils.ts +19 -0
  371. package/src/vim.d.ts +19 -5
  372. package/src/vim.ts +333 -18
  373. package/src/windows-input-mode.ts +8 -0
@@ -136,25 +136,41 @@ export const astGrepToolRenderer = {
136
136
  // Resolve hyperlinks over the whole output so nested directory headers
137
137
  // reconstruct across the blank-line groups the tree list collapses by.
138
138
  const contexts = classifyGroupedLines(allLines, details?.cwd ?? details?.searchPath, details?.searchPath);
139
- const styledLines = allLines.map((line, index) => {
139
+ // Style lazily: the collapsed tree list only renders the first few groups,
140
+ // so a large result never styles/hyperlinks rows nobody sees.
141
+ const styledLines: (string | undefined)[] = Array.from({ length: allLines.length }, () => undefined);
142
+ const styleLine = (index: number): string => {
143
+ const cached = styledLines[index];
144
+ if (cached !== undefined) return cached;
145
+ const line = allLines[index]!;
140
146
  const ctx = contexts[index]!;
147
+ let styled: string;
141
148
  if (ctx.kind === "dir") {
142
- const styled = uiTheme.fg("accent", line);
143
- return ctx.headerPath ? fileHyperlink(ctx.headerPath, styled) : styled;
149
+ const accent = uiTheme.fg("accent", line);
150
+ styled = ctx.headerPath ? fileHyperlink(ctx.headerPath, accent) : accent;
151
+ } else if (ctx.kind === "file") {
152
+ const tinted = uiTheme.fg(ctx.depth === 1 ? "accent" : "dim", line);
153
+ styled = ctx.headerPath ? fileHyperlink(ctx.headerPath, tinted) : tinted;
154
+ } else {
155
+ styled = uiTheme.fg(line.startsWith(" meta:") ? "dim" : "toolOutput", line);
144
156
  }
145
- if (ctx.kind === "file") {
146
- const styled = uiTheme.fg(ctx.depth === 1 ? "accent" : "dim", line);
147
- return ctx.headerPath ? fileHyperlink(ctx.headerPath, styled) : styled;
148
- }
149
- if (line.startsWith(" meta:")) return uiTheme.fg("dim", line);
150
- return uiTheme.fg("toolOutput", line);
157
+ styledLines[index] = styled;
158
+ return styled;
159
+ };
160
+ const matchGroups = groupLineIndicesByBlank(allLines).filter(indices => {
161
+ const first = allLines[indices[0]!]!;
162
+ return !first.startsWith("Result limit reached") && !first.startsWith("Parse issues:");
151
163
  });
152
- const matchGroups = groupLineIndicesByBlank(allLines)
153
- .filter(indices => {
154
- const first = allLines[indices[0]!]!;
155
- return !first.startsWith("Result limit reached") && !first.startsWith("Parse issues:");
156
- })
157
- .map(indices => indices.map(index => styledLines[index]!));
164
+ // Line offset at which each group starts. A collapsed tree list stops at the
165
+ // first group that overflows its line budget, so groups starting at or past
166
+ // the budget are never shown — hand it same-length placeholders instead of
167
+ // styling them (renderTreeList only needs their line counts).
168
+ const groupStarts: number[] = [];
169
+ let groupStart = 0;
170
+ for (const group of matchGroups) {
171
+ groupStarts.push(groupStart);
172
+ groupStart += group.length;
173
+ }
158
174
 
159
175
  const extraLines: string[] = [];
160
176
  if (limitReached) {
@@ -178,7 +194,10 @@ export const astGrepToolRenderer = {
178
194
  maxCollapsed: matchGroups.length,
179
195
  maxCollapsedLines: COLLAPSED_MATCH_LIMIT,
180
196
  itemType: "match",
181
- renderItem: group => group,
197
+ renderItem: (group, context) =>
198
+ !options.expanded && groupStarts[context.index]! >= COLLAPSED_MATCH_LIMIT
199
+ ? Array.from({ length: group.length }, () => "")
200
+ : group.map(styleLine),
182
201
  },
183
202
  uiTheme,
184
203
  );
package/src/tools/bash.ts CHANGED
@@ -25,9 +25,9 @@ import type {
25
25
  RenderResultOptions,
26
26
  ToolRenderer,
27
27
  } from "./renderer";
28
- import { ansi, compact, keyed } from "../native/describe";
29
- import type { NativeChild } from "../native/node";
30
- import { footnoteText, resultText } from "./native-view";
28
+ import { INTENT_FIELD, type TspTone } from "@linxiraos/pi-wire";
29
+ import { plainText } from "../native/spans";
30
+ import { resultText, runBox, runFoot, runInput, runOutput, type RunState } from "./native-view";
31
31
 
32
32
  /** Default collapsed shell output preview height. */
33
33
  export const BASH_DEFAULT_PREVIEW_LINES = DEFAULT_TERMINAL_PREVIEW_LINES;
@@ -367,34 +367,41 @@ function bashStatsParts(
367
367
  }
368
368
 
369
369
  /**
370
- * Native head facts of a shell call: title, the command once (`cd`/env
371
- * prefix included), a `background` badge for a backgrounded job, the
372
- * `exit N` chip and a `timed out` note only when the deadline hit.
370
+ * Native head facts of a shell call: title, the model's intent as the target
371
+ * (none without one), the command line for Copy command, the `exit N` chip
372
+ * and a `timed out` note only when the deadline hit. The command itself and a
373
+ * backgrounded job's state draw in the run box.
373
374
  */
374
375
  function shellToolHead(
375
376
  title: string,
376
377
  command: string,
378
+ intent: string | undefined,
377
379
  details: BashToolDetails | undefined,
378
380
  settled: boolean,
379
381
  ): NativeToolHead {
380
382
  const exit = settled && details?.exitCode !== undefined && details.exitCode !== 0 ? details.exitCode : undefined;
381
383
  return {
382
384
  title,
383
- target: command,
384
- targetKind: "command",
385
- lang: "bash",
386
- badges:
387
- details?.async?.state === "running"
388
- ? [{ text: "background", title: `Backgrounded as job ${details.async.jobId}` }]
389
- : undefined,
385
+ target: intent,
386
+ targetKind: intent ? "text" : undefined,
387
+ command,
390
388
  exit,
391
389
  note: settled && details?.timedOut === true ? "timed out" : undefined,
392
390
  };
393
391
  }
394
392
 
395
- /** The quiet final line's facts under shell output: service state and the full-output artifact. */
393
+ /** The model's intent line (`i` arg) as plain head text, or undefined when absent. */
394
+ function callIntent(args: unknown): string | undefined {
395
+ if (!args || typeof args !== "object" || !(INTENT_FIELD in args)) return undefined;
396
+ const value = args[INTENT_FIELD];
397
+ if (typeof value !== "string") return undefined;
398
+ return plainText(value).trim() || undefined;
399
+ }
400
+
401
+ /** The run foot's facts under shell output: background job, service state and the full-output artifact. */
396
402
  function shellFootParts(details: BashToolDetails | undefined, artifactId: string | undefined): string[] {
397
403
  const parts: string[] = [];
404
+ if (details?.async?.state === "running") parts.push(`Job ${details.async.jobId}`);
398
405
  const service = details?.service;
399
406
  if (service) {
400
407
  parts.push(`Service ${service.name}`, service.state);
@@ -405,6 +412,27 @@ function shellFootParts(details: BashToolDetails | undefined, artifactId: string
405
412
  return parts;
406
413
  }
407
414
 
415
+ /** The command line as a run's input: wrapped shell source. */
416
+ const SHELL_INPUT = { role: "zeta.tool.bash.command", lang: "bash", wrap: true } as const;
417
+
418
+ /** Box tint per run state: failed runs read as errors, timed-out ones as warnings. */
419
+ const RUN_BOX_TONE: Partial<Record<RunState, TspTone>> = { failed: "error", "timed-out": "warning" };
420
+
421
+ /** The foot state of a shell call from its result. */
422
+ function shellRunState(
423
+ details: BashToolDetails | undefined,
424
+ isError: boolean,
425
+ isPartial: boolean,
426
+ cancelled: boolean,
427
+ ): RunState {
428
+ if (cancelled) return "cancelled";
429
+ if (isPartial) return "running";
430
+ if (details?.timedOut === true) return "timed-out";
431
+ if (details?.async?.state === "running") return "background";
432
+ if (isError || (details?.exitCode !== undefined && details.exitCode !== 0)) return "failed";
433
+ return "done";
434
+ }
435
+
408
436
  function toBashRenderArgs<TArgs>(args: TArgs | undefined, config: ShellRendererConfig<TArgs>): BashRenderArgs {
409
437
  return {
410
438
  command: config.resolveCommand?.(args),
@@ -494,6 +522,15 @@ export function createShellRenderer<TArgs>(config: ShellRendererConfig<TArgs>) {
494
522
  let cachedIsPartial: boolean | undefined;
495
523
  let cachedPreviewWindow: number | undefined;
496
524
  let cachedSnapshot: ToolCardSnapshot | undefined;
525
+ const dropSnapshot = () => {
526
+ cachedSnapshot = undefined;
527
+ cachedWidth = undefined;
528
+ cachedPreviewLines = undefined;
529
+ cachedExpanded = undefined;
530
+ cachedRawOutput = undefined;
531
+ cachedIsPartial = undefined;
532
+ cachedPreviewWindow = undefined;
533
+ };
497
534
 
498
535
  return framedToolCard(
499
536
  uiTheme,
@@ -596,25 +633,26 @@ export function createShellRenderer<TArgs>(config: ShellRendererConfig<TArgs>) {
596
633
  cachedSnapshot = snapshot;
597
634
  return snapshot;
598
635
  },
599
- {
600
- onInvalidate: () => {
601
- cachedSnapshot = undefined;
602
- cachedWidth = undefined;
603
- cachedPreviewLines = undefined;
604
- cachedExpanded = undefined;
605
- cachedRawOutput = undefined;
606
- cachedIsPartial = undefined;
607
- cachedPreviewWindow = undefined;
608
- },
609
- },
636
+ { onInvalidate: dropSnapshot, onReleaseRenderCaches: dropSnapshot },
610
637
  );
611
638
  },
612
639
  describeCall(args: TArgs, options: RenderResultOptions): NativeToolView {
613
640
  const command = formatBashCommandText(toBashRenderArgs(args, config));
614
- // The command shows once, in the head; the body is only the output.
641
+ // No foot until the command starts; once it runs (before any output) the clock shows.
642
+ const started = options.executionStarted === true;
615
643
  return {
616
- tool: shellToolHead(config.resolveTitle(args, options), command, undefined, false),
617
- preview: { tail: BASH_DEFAULT_PREVIEW_LINES },
644
+ tool: shellToolHead(config.resolveTitle(args, options), command, callIntent(args), undefined, false),
645
+ body: [
646
+ runBox(
647
+ [
648
+ runInput(command, SHELL_INPUT),
649
+ started &&
650
+ runFoot({ state: options.cancelled ? "cancelled" : "running", elapsedMs: options.elapsedMs }),
651
+ ],
652
+ { key: "run" },
653
+ ),
654
+ ],
655
+ preview: "children",
618
656
  };
619
657
  },
620
658
 
@@ -638,22 +676,34 @@ export function createShellRenderer<TArgs>(config: ShellRendererConfig<TArgs>) {
638
676
  const showingFullOutput = expanded && renderContext?.isFullOutput === true;
639
677
  const command = formatBashCommandText(toBashRenderArgs(args, config));
640
678
  const previewLines = renderContext?.previewLines ?? BASH_DEFAULT_PREVIEW_LINES;
641
- // Wall time is the head timer, the timeout a note only when hit, the exit a head chip:
642
- // what is left (service state, artifact, truncation) is one quiet final line.
679
+ const state = shellRunState(details, isError, isPartial, options.cancelled === true);
680
+ // Settled: the measured wall time wins. A background job outlives the call: its run time is unknown here.
681
+ const elapsedMs =
682
+ state === "background"
683
+ ? undefined
684
+ : isPartial
685
+ ? options.elapsedMs
686
+ : (details?.wallTimeMs ?? options.elapsedMs);
643
687
  const meta = details?.meta;
644
- const body: NativeChild[] = compact([
645
- output.trim().length > 0 &&
646
- keyed(ansi(output, { follow: isPartial, role: "zeta.tool.bash.output" }), "output"),
647
- footnoteText(shellFootParts(details, stripped.artifactId), {
648
- ...meta,
649
- truncation: showingFullOutput ? undefined : meta?.truncation,
650
- }),
651
- ]);
688
+ const box = runBox(
689
+ [
690
+ runInput(command, SHELL_INPUT),
691
+ output.trim().length > 0 && runOutput(output, { role: "zeta.tool.bash.output", previewLines }),
692
+ runFoot({
693
+ state,
694
+ exitCode: details?.exitCode,
695
+ elapsedMs,
696
+ facts: shellFootParts(details, stripped.artifactId),
697
+ meta: { ...meta, truncation: showingFullOutput ? undefined : meta?.truncation },
698
+ }),
699
+ ],
700
+ { key: "run", tone: RUN_BOX_TONE[state] },
701
+ );
652
702
  return {
653
- tool: shellToolHead(config.resolveTitle(args, options), command, details, !isPartial),
654
- body,
655
- tone: !isPartial && isError && details?.timedOut === true ? "warning" : undefined,
656
- preview: { tail: previewLines },
703
+ tool: shellToolHead(config.resolveTitle(args, options), command, callIntent(args), details, !isPartial),
704
+ body: [box],
705
+ tone: state === "timed-out" ? "warning" : undefined,
706
+ preview: "children",
657
707
  };
658
708
  },
659
709
  mergeCallAndResult: true,
@@ -1,4 +1,4 @@
1
- /** Launch-broker daemon types shared by services, `proc://`, and `omp ps`. */
1
+ /** Launch-broker daemon types shared by services, `proc://`, and `zetacode ps`. */
2
2
  /** Stable lifecycle states exposed by the launch broker. */
3
3
  export type DaemonState = "starting" | "running" | "ready" | "restarting" | "stopping" | "exited" | "failed";
4
4
  /** Restart behavior applied after an unexpected daemon exit. */
@@ -1,4 +1,4 @@
1
- /** Launch-broker daemon types shared by services, `proc://`, and `omp ps`. */
1
+ /** Launch-broker daemon types shared by services, `proc://`, and `zetacode ps`. */
2
2
 
3
3
  /** Stable lifecycle states exposed by the launch broker. */
4
4
  export type DaemonState = "starting" | "running" | "ready" | "restarting" | "stopping" | "exited" | "failed";
@@ -39,19 +39,8 @@ export interface DefaultToolRenderInput {
39
39
  options: RenderResultOptions;
40
40
  }
41
41
 
42
- /** Header/body assembly shared by the string and Component APIs. */
43
- interface DefaultToolSnapshot {
44
- status: StatusLineOptions;
45
- phase: ToolCardPhase;
46
- body: readonly string[];
47
- }
48
-
49
- /** Compute the single header/body assembly behind both default-tool entry points. */
50
- function buildDefaultToolSnapshot(
51
- input: DefaultToolRenderInput,
52
- uiTheme: Theme,
53
- contentWidth: number,
54
- ): DefaultToolSnapshot {
42
+ /** Spinner-dependent header state; cheap, recomputed every frame. */
43
+ function buildDefaultToolStatus(input: DefaultToolRenderInput): { status: StatusLineOptions; phase: ToolCardPhase } {
55
44
  const { options, result } = input;
56
45
  const status: StatusLineOptions = {
57
46
  icon: options.isPartial
@@ -76,7 +65,12 @@ function buildDefaultToolSnapshot(
76
65
  : result?.isError
77
66
  ? "error"
78
67
  : "success";
68
+ return { status, phase };
69
+ }
79
70
 
71
+ /** Args preview plus JSON-tree/raw output body; depends only on args, output, expansion and width. */
72
+ function buildDefaultToolBody(input: DefaultToolRenderInput, uiTheme: Theme, contentWidth: number): string[] {
73
+ const { options, result } = input;
80
74
  const body: string[] = [];
81
75
  const args = isRecord(input.args) ? input.args : undefined;
82
76
  if (!options.expanded && args && Object.keys(args).length > 0) {
@@ -149,7 +143,7 @@ function buildDefaultToolSnapshot(
149
143
  }
150
144
  }
151
145
 
152
- return { status, phase, body };
146
+ return body;
153
147
  }
154
148
 
155
149
  /** Format one generic tool call/result card at the available content width. */
@@ -158,8 +152,8 @@ export function formatDefaultToolExecution(
158
152
  contentWidth: number,
159
153
  uiTheme: Theme,
160
154
  ): string {
161
- const snapshot = buildDefaultToolSnapshot(input, uiTheme, contentWidth);
162
- return [renderStatusLine(snapshot.status, uiTheme), ...snapshot.body].join("\n");
155
+ const { status } = buildDefaultToolStatus(input);
156
+ return [renderStatusLine(status, uiTheme), ...buildDefaultToolBody(input, uiTheme, contentWidth)].join("\n");
163
157
  }
164
158
 
165
159
  /** Inline args summary budget in characters (a data cap, not a width). */
@@ -195,12 +189,34 @@ export function describeDefaultToolExecution(input: DefaultToolRenderInput): Nat
195
189
 
196
190
  /** Render the generic fallback as the state-tinted card used by direct custom tools. */
197
191
  export function renderDefaultToolExecution(input: DefaultToolRenderInput, uiTheme: Theme): Component {
192
+ // The body (JSON parse + tree walk or output styling) is spinner-invariant;
193
+ // rebuild it only when its inputs change instead of on every animated frame.
194
+ let memo:
195
+ | { args: unknown; output: string | undefined; expanded: boolean; contentWidth: number; body: readonly string[] }
196
+ | undefined;
198
197
  return plainToolCard(
199
198
  uiTheme,
200
199
  ({ contentWidth }) => {
201
- const snapshot = buildDefaultToolSnapshot(input, uiTheme, contentWidth);
202
- return { status: snapshot.status, phase: snapshot.phase, body: snapshot.body };
200
+ const { status, phase } = buildDefaultToolStatus(input);
201
+ const output = input.result?.output;
202
+ const expanded = input.options.expanded;
203
+ if (
204
+ memo === undefined ||
205
+ memo.args !== input.args ||
206
+ memo.output !== output ||
207
+ memo.expanded !== expanded ||
208
+ memo.contentWidth !== contentWidth
209
+ ) {
210
+ memo = {
211
+ args: input.args,
212
+ output,
213
+ expanded,
214
+ contentWidth,
215
+ body: buildDefaultToolBody(input, uiTheme, contentWidth),
216
+ };
217
+ }
218
+ return { status, phase, body: memo.body };
203
219
  },
204
- { paddingX: 1, paddingY: 1, ignoreTight: true },
220
+ { paddingX: 1, paddingY: 1, ignoreTight: true, onInvalidate: () => (memo = undefined) },
205
221
  );
206
222
  }