@oh-my-pi/pi-tui 18.4.2 → 18.4.4

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 (463) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/types/apps/cleanse-board.d.ts +17 -0
  3. package/dist/types/apps/git/help.d.ts +16 -0
  4. package/dist/types/apps/git/sidebar.d.ts +18 -0
  5. package/dist/types/apps/live-visualizer.d.ts +10 -0
  6. package/dist/types/apps/ps-top.d.ts +15 -0
  7. package/dist/types/apps/standalone-picker.d.ts +3 -0
  8. package/dist/types/autocomplete.d.ts +8 -0
  9. package/dist/types/chat/advisor-message.d.ts +12 -2
  10. package/dist/types/chat/assistant-message.d.ts +20 -0
  11. package/dist/types/chat/bash-execution.d.ts +9 -0
  12. package/dist/types/chat/chat-transcript-builder.d.ts +6 -1
  13. package/dist/types/chat/collab-prompt-message.d.ts +4 -0
  14. package/dist/types/chat/compaction-summary-message.d.ts +15 -0
  15. package/dist/types/chat/eval-execution.d.ts +8 -0
  16. package/dist/types/chat/execution-shared.d.ts +58 -0
  17. package/dist/types/chat/late-diagnostics-message.d.ts +15 -1
  18. package/dist/types/chat/read-tool-group.d.ts +15 -0
  19. package/dist/types/chat/skill-message.d.ts +9 -0
  20. package/dist/types/chat/stripped-tool-calls-placeholder.d.ts +3 -0
  21. package/dist/types/chat/thinking-display.d.ts +2 -0
  22. package/dist/types/chat/todo-reminder.d.ts +4 -1
  23. package/dist/types/chat/tool-execution.d.ts +25 -1
  24. package/dist/types/chat/transcript-actions.d.ts +37 -0
  25. package/dist/types/chat/transcript-entry.d.ts +3 -1
  26. package/dist/types/chat/user-message.d.ts +25 -0
  27. package/dist/types/chrome/collab-qrcode.d.ts +7 -0
  28. package/dist/types/chrome/context-thresholds.d.ts +11 -0
  29. package/dist/types/chrome/countdown-timer.d.ts +9 -3
  30. package/dist/types/chrome/diff.d.ts +12 -0
  31. package/dist/types/chrome/dynamic-border.d.ts +3 -0
  32. package/dist/types/chrome/format.d.ts +6 -0
  33. package/dist/types/chrome/message-divider.d.ts +13 -0
  34. package/dist/types/chrome/message-frame.d.ts +10 -0
  35. package/dist/types/chrome/message-notice.d.ts +23 -0
  36. package/dist/types/chrome/overlay-box.d.ts +11 -2
  37. package/dist/types/chrome/qrcode.d.ts +7 -0
  38. package/dist/types/chrome/segment-track.d.ts +7 -0
  39. package/dist/types/chrome/selector-helpers.d.ts +0 -6
  40. package/dist/types/chrome/status-notice.d.ts +14 -0
  41. package/dist/types/chrome/streaming-panel.d.ts +3 -0
  42. package/dist/types/chrome/tool-activity.d.ts +3 -0
  43. package/dist/types/chrome/transcript-container.d.ts +13 -0
  44. package/dist/types/chrome/transcript-status.d.ts +15 -3
  45. package/dist/types/components/box.d.ts +7 -0
  46. package/dist/types/components/disclosure.d.ts +9 -0
  47. package/dist/types/components/editor.d.ts +42 -0
  48. package/dist/types/components/form.d.ts +14 -0
  49. package/dist/types/components/image.d.ts +7 -0
  50. package/dist/types/components/input.d.ts +20 -1
  51. package/dist/types/components/key-value-list.d.ts +3 -0
  52. package/dist/types/components/layout/geometry.d.ts +16 -0
  53. package/dist/types/components/layout/row.d.ts +7 -0
  54. package/dist/types/components/layout/split-pane.d.ts +8 -0
  55. package/dist/types/components/layout/stack.d.ts +6 -0
  56. package/dist/types/components/loader.d.ts +48 -0
  57. package/dist/types/components/markdown.d.ts +8 -0
  58. package/dist/types/components/metric.d.ts +7 -0
  59. package/dist/types/components/progress-bar.d.ts +3 -0
  60. package/dist/types/components/scroll-view.d.ts +6 -0
  61. package/dist/types/components/section.d.ts +3 -0
  62. package/dist/types/components/select-list.d.ts +33 -0
  63. package/dist/types/components/settings-list.d.ts +68 -0
  64. package/dist/types/components/spacer.d.ts +4 -0
  65. package/dist/types/components/tab-bar.d.ts +9 -0
  66. package/dist/types/components/table.d.ts +7 -0
  67. package/dist/types/components/text.d.ts +6 -0
  68. package/dist/types/components/tree-view.d.ts +9 -0
  69. package/dist/types/components/truncated-text.d.ts +3 -0
  70. package/dist/types/components/wizard-step.d.ts +6 -0
  71. package/dist/types/hotkeys-markdown.d.ts +24 -0
  72. package/dist/types/index.d.ts +5 -0
  73. package/dist/types/latex-block.d.ts +7 -0
  74. package/dist/types/loop-watchdog.d.ts +9 -0
  75. package/dist/types/native/apply.d.ts +39 -0
  76. package/dist/types/native/backend.d.ts +94 -0
  77. package/dist/types/native/blobs.d.ts +29 -0
  78. package/dist/types/native/describe.d.ts +56 -0
  79. package/dist/types/native/encode.d.ts +50 -0
  80. package/dist/types/native/icons.d.ts +18 -0
  81. package/dist/types/native/memo.d.ts +27 -0
  82. package/dist/types/native/node.d.ts +107 -0
  83. package/dist/types/native/overlay.d.ts +64 -0
  84. package/dist/types/native/picker.d.ts +124 -0
  85. package/dist/types/native/reconcile.d.ts +41 -0
  86. package/dist/types/native/settle.d.ts +11 -0
  87. package/dist/types/native/spans.d.ts +21 -0
  88. package/dist/types/native/state.d.ts +6 -0
  89. package/dist/types/native/tone.d.ts +24 -0
  90. package/dist/types/overlays/advisor-config.d.ts +20 -0
  91. package/dist/types/overlays/agent-hub-renderer.d.ts +27 -11
  92. package/dist/types/overlays/agent-hub.d.ts +10 -0
  93. package/dist/types/overlays/agent-transcript-viewer.d.ts +7 -0
  94. package/dist/types/overlays/agents-hub.d.ts +8 -0
  95. package/dist/types/overlays/annotation-overlay.d.ts +3 -0
  96. package/dist/types/overlays/ask-dialog.d.ts +23 -0
  97. package/dist/types/overlays/bordered-loader.d.ts +3 -0
  98. package/dist/types/overlays/btw-history-panel.d.ts +9 -0
  99. package/dist/types/overlays/btw-panel.d.ts +3 -0
  100. package/dist/types/overlays/cleanse-panel.d.ts +5 -2
  101. package/dist/types/overlays/composer-shape-preview.d.ts +7 -1
  102. package/dist/types/overlays/copy-selector.d.ts +38 -0
  103. package/dist/types/overlays/error-banner.d.ts +9 -0
  104. package/dist/types/overlays/extensions/extension-list.d.ts +1 -0
  105. package/dist/types/overlays/history-search.d.ts +18 -0
  106. package/dist/types/overlays/hook-editor.d.ts +28 -1
  107. package/dist/types/overlays/hook-input.d.ts +3 -0
  108. package/dist/types/overlays/hook-selector.d.ts +10 -0
  109. package/dist/types/overlays/hub-frame.d.ts +18 -0
  110. package/dist/types/overlays/jobs-panel.d.ts +24 -0
  111. package/dist/types/overlays/login-dialog.d.ts +10 -0
  112. package/dist/types/overlays/logout-account-selector.d.ts +4 -0
  113. package/dist/types/overlays/mcp-add-wizard.d.ts +4 -0
  114. package/dist/types/overlays/model-browser.d.ts +69 -0
  115. package/dist/types/overlays/model-hub.d.ts +7 -0
  116. package/dist/types/overlays/model-picker.d.ts +9 -1
  117. package/dist/types/overlays/move-overlay.d.ts +3 -0
  118. package/dist/types/overlays/oauth-selector.d.ts +4 -0
  119. package/dist/types/overlays/omfg-panel.d.ts +3 -0
  120. package/dist/types/overlays/pause-screen.d.ts +12 -0
  121. package/dist/types/overlays/plan-review-overlay.d.ts +5 -0
  122. package/dist/types/overlays/plan-save-overlay.d.ts +10 -0
  123. package/dist/types/overlays/plugin-selector.d.ts +4 -0
  124. package/dist/types/overlays/plugin-settings.d.ts +30 -0
  125. package/dist/types/overlays/queue-mode-selector.d.ts +4 -0
  126. package/dist/types/overlays/reset-usage-selector.d.ts +8 -0
  127. package/dist/types/overlays/rewind-selector.d.ts +5 -0
  128. package/dist/types/overlays/session-info-overlay.d.ts +19 -1
  129. package/dist/types/overlays/session-selector.d.ts +64 -1
  130. package/dist/types/overlays/settings-defs.d.ts +14 -0
  131. package/dist/types/overlays/settings-selector.d.ts +21 -0
  132. package/dist/types/overlays/show-images-selector.d.ts +4 -0
  133. package/dist/types/overlays/snapcompact-shape-preview.d.ts +2 -0
  134. package/dist/types/overlays/stats-notice.d.ts +8 -0
  135. package/dist/types/overlays/theme-selector.d.ts +11 -0
  136. package/dist/types/overlays/thinking-selector.d.ts +4 -0
  137. package/dist/types/overlays/tree-selector.d.ts +60 -2
  138. package/dist/types/overlays/usage-dashboard.d.ts +26 -3
  139. package/dist/types/overlays/usage-row.d.ts +36 -2
  140. package/dist/types/prompt/attachment-chips.d.ts +8 -0
  141. package/dist/types/prompt/composer-attachments.d.ts +15 -3
  142. package/dist/types/prompt/composer.d.ts +18 -1
  143. package/dist/types/prompt/custom-editor.d.ts +48 -2
  144. package/dist/types/prompt/editor-top-gap.d.ts +2 -0
  145. package/dist/types/prompt/macos-spelling.d.ts +6 -0
  146. package/dist/types/prompt/magic-keywords.d.ts +9 -0
  147. package/dist/types/prompt/queued-messages.d.ts +23 -0
  148. package/dist/types/prompt/skill-tokens.d.ts +4 -2
  149. package/dist/types/prompt/welcome.d.ts +16 -0
  150. package/dist/types/render/code-cell.d.ts +10 -0
  151. package/dist/types/render/file-list.d.ts +8 -0
  152. package/dist/types/render/hyperlink.d.ts +14 -0
  153. package/dist/types/render/output-block.d.ts +43 -0
  154. package/dist/types/render/output-pane.d.ts +17 -0
  155. package/dist/types/render/tool-card.d.ts +8 -0
  156. package/dist/types/render/tree-list.d.ts +8 -0
  157. package/dist/types/render/width-aware-text.d.ts +7 -0
  158. package/dist/types/setup/scenes/outro.d.ts +7 -0
  159. package/dist/types/setup/scenes/sign-in.d.ts +16 -9
  160. package/dist/types/setup/scenes/splash.d.ts +8 -0
  161. package/dist/types/setup/scenes/types.d.ts +6 -27
  162. package/dist/types/setup/wizard-overlay.d.ts +9 -0
  163. package/dist/types/status-line/component.d.ts +49 -5
  164. package/dist/types/status-line/context-usage.d.ts +20 -0
  165. package/dist/types/status-line/footer.d.ts +8 -0
  166. package/dist/types/status-line/metrics.d.ts +1 -2
  167. package/dist/types/status-line/segments.d.ts +10 -1
  168. package/dist/types/status-line/types.d.ts +40 -1
  169. package/dist/types/stdin-buffer.d.ts +10 -7
  170. package/dist/types/terminal-capabilities.d.ts +1 -1
  171. package/dist/types/terminal.d.ts +36 -0
  172. package/dist/types/theme/defaults/index.d.ts +100 -0
  173. package/dist/types/theme/schema.d.ts +2 -0
  174. package/dist/types/theme/shimmer.d.ts +8 -0
  175. package/dist/types/theme/theme-class.d.ts +2 -0
  176. package/dist/types/theme/theme.d.ts +33 -1
  177. package/dist/types/tools/ask.d.ts +3 -0
  178. package/dist/types/tools/ast-edit.d.ts +10 -1
  179. package/dist/types/tools/ast-grep.d.ts +10 -1
  180. package/dist/types/tools/autoresearch.d.ts +21 -4
  181. package/dist/types/tools/bash.d.ts +30 -1
  182. package/dist/types/tools/cfg-render.d.ts +5 -1
  183. package/dist/types/tools/debug.d.ts +3 -1
  184. package/dist/types/tools/default-renderer.d.ts +6 -1
  185. package/dist/types/tools/edit.d.ts +14 -1
  186. package/dist/types/tools/eval.d.ts +12 -1
  187. package/dist/types/tools/fetch.d.ts +16 -1
  188. package/dist/types/tools/find.d.ts +15 -1
  189. package/dist/types/tools/github.d.ts +3 -0
  190. package/dist/types/tools/glob.d.ts +14 -1
  191. package/dist/types/tools/goal.d.ts +3 -1
  192. package/dist/types/tools/grep.d.ts +14 -1
  193. package/dist/types/tools/grouped-file-output.d.ts +58 -0
  194. package/dist/types/tools/json-tree.d.ts +20 -0
  195. package/dist/types/tools/lsp.d.ts +3 -10
  196. package/dist/types/tools/mcp.d.ts +16 -1
  197. package/dist/types/tools/memory.d.ts +26 -0
  198. package/dist/types/tools/native-view.d.ts +90 -0
  199. package/dist/types/tools/proc-render.d.ts +7 -1
  200. package/dist/types/tools/read.d.ts +23 -1
  201. package/dist/types/tools/renderer.d.ts +57 -0
  202. package/dist/types/tools/report-tool-issue.d.ts +3 -0
  203. package/dist/types/tools/resolve.d.ts +14 -1
  204. package/dist/types/tools/task.d.ts +3 -0
  205. package/dist/types/tools/think.d.ts +3 -0
  206. package/dist/types/tools/todo.d.ts +12 -0
  207. package/dist/types/tools/vibe.d.ts +3 -1
  208. package/dist/types/tools/wait.d.ts +3 -0
  209. package/dist/types/tools/web-search-types.d.ts +90 -0
  210. package/dist/types/tools/web-search.d.ts +9 -168
  211. package/dist/types/tools/write.d.ts +14 -1
  212. package/dist/types/tools/xdev.d.ts +13 -0
  213. package/dist/types/tui.d.ts +49 -0
  214. package/package.json +9 -9
  215. package/src/apps/autoresearch-dashboard.ts +362 -4
  216. package/src/apps/cleanse-board.ts +219 -1
  217. package/src/apps/cleanse-picker.ts +9 -1
  218. package/src/apps/debug/log-viewer.ts +15 -15
  219. package/src/apps/debug/protocol-probe.ts +2 -20
  220. package/src/apps/git/avatar.ts +2 -22
  221. package/src/apps/git/git-tui.ts +406 -59
  222. package/src/apps/git/help.ts +130 -0
  223. package/src/apps/git/sidebar.ts +491 -0
  224. package/src/apps/live-visualizer.ts +65 -0
  225. package/src/apps/ps-top.ts +448 -17
  226. package/src/apps/session-picker.ts +1 -0
  227. package/src/apps/setup-model-picker.ts +5 -1
  228. package/src/apps/standalone-picker.ts +55 -1
  229. package/src/autocomplete.ts +44 -1
  230. package/src/chat/advisor-message.ts +72 -3
  231. package/src/chat/assistant-message.ts +538 -51
  232. package/src/chat/background-tan-message.ts +4 -4
  233. package/src/chat/bash-execution.ts +81 -0
  234. package/src/chat/cache-invalidation-marker.ts +8 -0
  235. package/src/chat/chat-transcript-builder.ts +37 -6
  236. package/src/chat/collab-prompt-message.ts +15 -3
  237. package/src/chat/compaction-summary-message.ts +74 -1
  238. package/src/chat/custom-message.ts +3 -1
  239. package/src/chat/eval-execution.ts +57 -0
  240. package/src/chat/execution-shared.ts +153 -1
  241. package/src/chat/hook-message.ts +1 -0
  242. package/src/chat/late-diagnostics-message.ts +85 -2
  243. package/src/chat/read-tool-group.ts +341 -1
  244. package/src/chat/served-model-marker.ts +8 -0
  245. package/src/chat/skill-message.ts +63 -0
  246. package/src/chat/stripped-tool-calls-placeholder.ts +18 -10
  247. package/src/chat/thinking-display.ts +73 -11
  248. package/src/chat/todo-reminder.ts +34 -4
  249. package/src/chat/tool-execution.ts +385 -10
  250. package/src/chat/transcript-actions.ts +38 -0
  251. package/src/chat/transcript-browser.ts +2 -9
  252. package/src/chat/transcript-entry.ts +10 -1
  253. package/src/chat/transcript-render-helpers.ts +16 -15
  254. package/src/chat/ttsr-notification.ts +38 -1
  255. package/src/chat/user-message.ts +167 -4
  256. package/src/chrome/collab-qrcode.ts +27 -2
  257. package/src/chrome/context-thresholds.ts +34 -0
  258. package/src/chrome/countdown-timer.ts +24 -1
  259. package/src/chrome/diff.ts +60 -1
  260. package/src/chrome/dynamic-border.ts +7 -0
  261. package/src/chrome/format.ts +12 -0
  262. package/src/chrome/message-divider.ts +33 -1
  263. package/src/chrome/message-frame.ts +53 -10
  264. package/src/chrome/message-notice.ts +71 -0
  265. package/src/chrome/overlay-box.ts +45 -2
  266. package/src/chrome/qrcode.ts +28 -0
  267. package/src/chrome/segment-track.ts +26 -0
  268. package/src/chrome/selector-helpers.ts +1 -17
  269. package/src/chrome/status-notice.ts +46 -0
  270. package/src/chrome/streaming-panel.ts +25 -1
  271. package/src/chrome/tool-activity.ts +20 -0
  272. package/src/chrome/transcript-container.ts +139 -17
  273. package/src/chrome/transcript-status.ts +40 -11
  274. package/src/components/box.ts +51 -0
  275. package/src/components/disclosure.ts +33 -0
  276. package/src/components/editor.ts +239 -36
  277. package/src/components/form.ts +93 -9
  278. package/src/components/image.ts +30 -0
  279. package/src/components/input.ts +77 -26
  280. package/src/components/key-value-list.ts +18 -0
  281. package/src/components/layout/geometry.ts +44 -0
  282. package/src/components/layout/row.ts +30 -0
  283. package/src/components/layout/split-pane.ts +65 -0
  284. package/src/components/layout/stack.ts +27 -0
  285. package/src/components/loader.ts +183 -1
  286. package/src/components/markdown.ts +131 -56
  287. package/src/components/metric.ts +39 -0
  288. package/src/components/progress-bar.ts +28 -0
  289. package/src/components/scroll-view.ts +23 -0
  290. package/src/components/section.ts +16 -0
  291. package/src/components/select-list.ts +174 -25
  292. package/src/components/settings-list.ts +264 -7
  293. package/src/components/spacer.ts +17 -0
  294. package/src/components/tab-bar.ts +42 -0
  295. package/src/components/table.ts +34 -0
  296. package/src/components/text.ts +23 -0
  297. package/src/components/tree-view.ts +65 -0
  298. package/src/components/truncated-text.ts +14 -0
  299. package/src/components/wizard-step.ts +18 -9
  300. package/src/debug-server.ts +14 -7
  301. package/src/hotkeys-markdown.ts +251 -69
  302. package/src/index.ts +6 -0
  303. package/src/latex-block.ts +11 -0
  304. package/src/loop-watchdog.ts +38 -10
  305. package/src/native/apply.ts +275 -0
  306. package/src/native/backend.ts +682 -0
  307. package/src/native/blobs.ts +70 -0
  308. package/src/native/describe.ts +124 -0
  309. package/src/native/encode.ts +233 -0
  310. package/src/native/icons.ts +184 -0
  311. package/src/native/memo.ts +64 -0
  312. package/src/native/node.ts +112 -0
  313. package/src/native/overlay.ts +131 -0
  314. package/src/native/picker.ts +333 -0
  315. package/src/native/reconcile.ts +1063 -0
  316. package/src/native/settle.ts +23 -0
  317. package/src/native/spans.ts +308 -0
  318. package/src/native/state.ts +28 -0
  319. package/src/native/tone.ts +79 -0
  320. package/src/overlays/advisor-config.ts +420 -0
  321. package/src/overlays/agent-hub-renderer.ts +155 -18
  322. package/src/overlays/agent-hub.ts +1037 -44
  323. package/src/overlays/agent-transcript-viewer.ts +129 -0
  324. package/src/overlays/agents-hub.ts +688 -53
  325. package/src/overlays/annotation-overlay.ts +391 -52
  326. package/src/overlays/ask-dialog.ts +435 -24
  327. package/src/overlays/bordered-loader.ts +17 -0
  328. package/src/overlays/btw-history-panel.ts +182 -0
  329. package/src/overlays/btw-panel.ts +68 -2
  330. package/src/overlays/cleanse-panel.ts +105 -15
  331. package/src/overlays/codex-reset-fireworks.ts +65 -5
  332. package/src/overlays/composer-shape-preview.ts +26 -1
  333. package/src/overlays/copy-selector.ts +545 -23
  334. package/src/overlays/error-banner.ts +44 -0
  335. package/src/overlays/extensions/extension-list.ts +23 -17
  336. package/src/overlays/history-search.ts +175 -33
  337. package/src/overlays/hook-editor.ts +113 -6
  338. package/src/overlays/hook-input.ts +22 -1
  339. package/src/overlays/hook-selector.ts +311 -22
  340. package/src/overlays/hub-frame.ts +80 -0
  341. package/src/overlays/jobs-panel.ts +112 -0
  342. package/src/overlays/login-dialog.ts +183 -1
  343. package/src/overlays/logout-account-selector.ts +102 -4
  344. package/src/overlays/mcp-add-wizard.ts +232 -53
  345. package/src/overlays/model-browser.ts +681 -22
  346. package/src/overlays/model-hub.ts +1402 -78
  347. package/src/overlays/model-picker.ts +184 -7
  348. package/src/overlays/move-overlay.ts +45 -0
  349. package/src/overlays/oauth-selector.ts +227 -23
  350. package/src/overlays/omfg-panel.ts +86 -2
  351. package/src/overlays/pause-screen.ts +55 -4
  352. package/src/overlays/plan-review-overlay.ts +352 -0
  353. package/src/overlays/plan-save-overlay.ts +45 -0
  354. package/src/overlays/plugin-selector.ts +21 -1
  355. package/src/overlays/plugin-settings.ts +195 -5
  356. package/src/overlays/queue-mode-selector.ts +19 -1
  357. package/src/overlays/reset-usage-selector.ts +110 -40
  358. package/src/overlays/rewind-selector.ts +458 -44
  359. package/src/overlays/session-account-selector.ts +1 -1
  360. package/src/overlays/session-info-overlay.ts +137 -1
  361. package/src/overlays/session-selector.ts +807 -46
  362. package/src/overlays/settings-defs.ts +41 -0
  363. package/src/overlays/settings-selector.ts +585 -33
  364. package/src/overlays/show-images-selector.ts +18 -1
  365. package/src/overlays/snapcompact-shape-preview.ts +48 -3
  366. package/src/overlays/stats-notice.ts +31 -0
  367. package/src/overlays/theme-selector.ts +31 -1
  368. package/src/overlays/thinking-selector.ts +22 -1
  369. package/src/overlays/tree-selector.ts +570 -110
  370. package/src/overlays/usage-dashboard.ts +587 -12
  371. package/src/overlays/usage-row.ts +161 -25
  372. package/src/prompt/attachment-chips.ts +60 -0
  373. package/src/prompt/composer-attachments.ts +31 -9
  374. package/src/prompt/composer.ts +55 -2
  375. package/src/prompt/custom-editor.ts +302 -4
  376. package/src/prompt/editor-top-gap.ts +8 -0
  377. package/src/prompt/macos-spelling.ts +24 -9
  378. package/src/prompt/magic-keywords.ts +22 -1
  379. package/src/prompt/model-mention-autocomplete.ts +1 -0
  380. package/src/prompt/queued-messages.ts +101 -0
  381. package/src/prompt/skill-tokens.ts +5 -3
  382. package/src/prompt/welcome.ts +213 -6
  383. package/src/render/code-cell.ts +103 -2
  384. package/src/render/file-list.ts +29 -0
  385. package/src/render/hyperlink.ts +32 -0
  386. package/src/render/output-block.ts +110 -0
  387. package/src/render/output-pane.ts +37 -0
  388. package/src/render/tool-card.ts +137 -0
  389. package/src/render/tree-list.ts +39 -0
  390. package/src/render/width-aware-text.ts +20 -0
  391. package/src/setup/scenes/composer.ts +29 -0
  392. package/src/setup/scenes/glyph.ts +15 -0
  393. package/src/setup/scenes/model.ts +36 -8
  394. package/src/setup/scenes/outro.ts +28 -1
  395. package/src/setup/scenes/sign-in.ts +138 -24
  396. package/src/setup/scenes/splash.ts +28 -1
  397. package/src/setup/scenes/theme.ts +88 -3
  398. package/src/setup/scenes/types.ts +7 -28
  399. package/src/setup/startup-splash.ts +46 -9
  400. package/src/setup/wizard-overlay.ts +140 -23
  401. package/src/setup/wizard.ts +1 -1
  402. package/src/status-line/component.ts +414 -18
  403. package/src/status-line/context-usage.ts +279 -50
  404. package/src/status-line/footer.ts +94 -1
  405. package/src/status-line/metrics.ts +3 -6
  406. package/src/status-line/segments.ts +463 -97
  407. package/src/status-line/separators.ts +3 -16
  408. package/src/status-line/types.ts +43 -1
  409. package/src/stdin-buffer.ts +27 -21
  410. package/src/terminal-capabilities.ts +7 -0
  411. package/src/terminal.ts +153 -11
  412. package/src/theme/defaults/dark-neon-noir.json +100 -0
  413. package/src/theme/defaults/index.ts +2 -0
  414. package/src/theme/defaults/light-prism.json +5 -5
  415. package/src/theme/defaults/onyx.json +62 -62
  416. package/src/theme/mermaid-cache.ts +10 -1
  417. package/src/theme/schema.ts +15 -0
  418. package/src/theme/shimmer.ts +33 -0
  419. package/src/theme/theme-class.ts +24 -19
  420. package/src/theme/theme.ts +111 -9
  421. package/src/theme/tui-adapters.ts +14 -1
  422. package/src/tools/ask.ts +157 -1
  423. package/src/tools/ast-edit.ts +174 -1
  424. package/src/tools/ast-grep.ts +82 -2
  425. package/src/tools/autoresearch.ts +149 -1
  426. package/src/tools/bash.ts +233 -62
  427. package/src/tools/cfg-render.ts +66 -1
  428. package/src/tools/debug.ts +78 -1
  429. package/src/tools/default-renderer.ts +35 -1
  430. package/src/tools/edit.ts +357 -31
  431. package/src/tools/eval.ts +257 -1
  432. package/src/tools/fetch.ts +102 -3
  433. package/src/tools/find.ts +127 -1
  434. package/src/tools/github.ts +119 -10
  435. package/src/tools/glob.ts +116 -1
  436. package/src/tools/goal.ts +56 -1
  437. package/src/tools/grep.ts +83 -2
  438. package/src/tools/grouped-file-output.ts +205 -0
  439. package/src/tools/json-tree.ts +116 -1
  440. package/src/tools/lsp.ts +318 -1
  441. package/src/tools/mcp.ts +80 -1
  442. package/src/tools/memory.ts +93 -11
  443. package/src/tools/native-view.ts +292 -0
  444. package/src/tools/proc-render.ts +221 -1
  445. package/src/tools/read.ts +199 -4
  446. package/src/tools/renderer.ts +61 -0
  447. package/src/tools/report-tool-issue.ts +7 -1
  448. package/src/tools/resolve.ts +63 -1
  449. package/src/tools/streaming-output.ts +79 -16
  450. package/src/tools/task.ts +406 -4
  451. package/src/tools/think.ts +19 -1
  452. package/src/tools/todo.ts +89 -0
  453. package/src/tools/vibe.ts +230 -2
  454. package/src/tools/wait.ts +181 -1
  455. package/src/tools/web-search-types.ts +99 -0
  456. package/src/tools/web-search.ts +111 -170
  457. package/src/tools/write.ts +144 -5
  458. package/src/tools/xdev.ts +64 -1
  459. package/src/tui.ts +295 -4
  460. package/dist/types/setup/scenes/providers.d.ts +0 -3
  461. package/dist/types/setup/scenes/web-search.d.ts +0 -22
  462. package/src/setup/scenes/providers.ts +0 -110
  463. package/src/setup/scenes/web-search.ts +0 -165
@@ -16,7 +16,10 @@ import { formatArtifactErrorNotice, formatTruncationMetaNotice, type TruncationM
16
16
  import { DynamicBorder } from "../chrome/dynamic-border";
17
17
  import { Ellipsis, truncateToWidth, visibleWidth } from "../utils";
18
18
  import { interruptKey } from "../chrome/keybinding-hints";
19
- import { expandKeyHint } from "../render/render-utils";
19
+ import { DEFAULT_TERMINAL_PREVIEW_LINES, expandKeyHint } from "../render/render-utils";
20
+ import type { TspCardStatus, TspSpan, TspText, TspTone } from "@oh-my-pi/pi-wire";
21
+ import { card, node, span, text } from "../native/describe";
22
+ import type { NativeChild, NativeNode } from "../native/node";
20
23
 
21
24
  /** Output rows shown while an execution is collapsed. */
22
25
  export const PREVIEW_LINES = 20;
@@ -104,6 +107,155 @@ export function buildStatusFooter(opts: {
104
107
  return new Text(`\n${parts.join("\n")}`, 1, 0);
105
108
  }
106
109
 
110
+ const EXECUTION_CARD_STATUS: Record<ExecutionStatus, TspCardStatus> = {
111
+ running: "running",
112
+ complete: "done",
113
+ cancelled: "cancelled",
114
+ error: "error",
115
+ };
116
+
117
+ /** Inputs for {@link describeExecutionCard}. */
118
+ export interface ExecutionCardInput {
119
+ readonly role: string;
120
+ readonly head: TspText;
121
+ /** Excluded from context (`!!`/`$$`): a muted card. */
122
+ readonly muted: boolean;
123
+ readonly status: ExecutionStatus;
124
+ /** `performance.now()` when the run started; drives the live elapsed timer. */
125
+ readonly startedAt: number;
126
+ readonly expanded: boolean;
127
+ /** Body nodes before the output (the eval cell's code). */
128
+ readonly lead?: readonly NativeChild[];
129
+ /** Raw terminal output. */
130
+ readonly output: string;
131
+ readonly images?: readonly NativeChild[];
132
+ readonly exitCode: number | undefined;
133
+ readonly truncation: TruncationMeta | undefined;
134
+ readonly artifactError?: OutputArtifactError;
135
+ }
136
+
137
+ /**
138
+ * Native card shared by user bash/eval runs: the head with a live `elapsed`
139
+ * while running, the output as an `ansi` mini terminal that follows its tail
140
+ * while running, a cancel hint spinner, then exit/truncation notes. The
141
+ * terminal clamps the collapsed body and owns the "N more lines" affordance.
142
+ */
143
+ export function describeExecutionCard(input: ExecutionCardInput): NativeNode {
144
+ const running = input.status === "running";
145
+ const headChildren: NativeChild[] = [text(input.head, { lines: 1, grow: 1 })];
146
+ if (running) {
147
+ headChildren.push(node("elapsed", { age: Math.max(0, Math.round(performance.now() - input.startedAt)) }));
148
+ }
149
+ const children: NativeChild[] = [
150
+ node("row", { gap: "sm", align: "baseline" }, headChildren, "head"),
151
+ ...(input.lead ?? []),
152
+ ];
153
+ if (input.output) {
154
+ children.push(
155
+ node("ansi", { text: input.output, follow: running, preview: { lines: PREVIEW_LINES } }, undefined, "output"),
156
+ );
157
+ }
158
+ if (input.images) children.push(...input.images);
159
+ if (running) {
160
+ children.push(
161
+ node("spinner", { label: [span(`Running… (${interruptKey()} to cancel)`, "muted")] }, undefined, "running"),
162
+ );
163
+ }
164
+ const notes: TspSpan[] = [];
165
+ const note = (value: string, token: string): void => {
166
+ if (notes.length > 0) notes.push(span("\n"));
167
+ notes.push(span(value, token));
168
+ };
169
+ if (input.status === "cancelled") note("(cancelled)", "warning");
170
+ else if (input.status === "error") note(`(exit ${input.exitCode})`, "error");
171
+ if (input.truncation) note(formatTruncationMetaNotice(input.truncation), "warning");
172
+ if (input.artifactError) note(formatArtifactErrorNotice(input.artifactError), "warning");
173
+ if (notes.length > 0) children.push(text(notes, { wrap: "word", key: "notes" }));
174
+ return card(
175
+ {
176
+ role: input.role,
177
+ tone: input.muted ? "muted" : undefined,
178
+ status: EXECUTION_CARD_STATUS[input.status],
179
+ collapsible: true,
180
+ collapsed: !input.expanded,
181
+ preview: { lines: PREVIEW_LINES },
182
+ },
183
+ children,
184
+ );
185
+ }
186
+
187
+ /** Inputs for {@link describeExecutionTool}. */
188
+ export interface ExecutionToolInput {
189
+ readonly role: string;
190
+ /** Tool name for the head icon (`bash`, `eval`). */
191
+ readonly name: string;
192
+ readonly title: string;
193
+ /** The command / cell source, shown once in the head. */
194
+ readonly command: string;
195
+ readonly lang: string;
196
+ /** Excluded from context (`!!`/`$$`). */
197
+ readonly excluded: boolean;
198
+ readonly status: ExecutionStatus;
199
+ /** `performance.now()` when the run started / ended. */
200
+ readonly startedAt: number;
201
+ readonly endedAt: number | undefined;
202
+ readonly expanded: boolean;
203
+ /** Raw terminal output. */
204
+ readonly output: string;
205
+ readonly images?: readonly NativeChild[];
206
+ readonly exitCode: number | undefined;
207
+ readonly truncation: TruncationMeta | undefined;
208
+ readonly artifactError?: OutputArtifactError;
209
+ }
210
+
211
+ /**
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.
216
+ */
217
+ export function describeExecutionTool(input: ExecutionToolInput): NativeNode {
218
+ 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: "omp.tool.notice" }),
228
+ key: "foot",
229
+ });
230
+ }
231
+ const ms = Math.max(0, Math.round((input.endedAt ?? performance.now()) - input.startedAt));
232
+ const badges: { text: string; tone?: TspTone; title?: string }[] = [{ text: "you", tone: "user" }];
233
+ if (input.excluded) badges.push({ text: "not sent", title: "Not sent to the model", tone: "muted" });
234
+ const hasBody = body.length > 0;
235
+ return node(
236
+ "tool",
237
+ {
238
+ role: input.role,
239
+ name: input.name,
240
+ title: input.title,
241
+ target: input.command,
242
+ targetKind: "command",
243
+ lang: input.lang,
244
+ badges,
245
+ status: EXECUTION_CARD_STATUS[input.status],
246
+ age: running ? ms : undefined,
247
+ took: running ? undefined : ms,
248
+ exit: input.status === "error" ? input.exitCode : undefined,
249
+ note: input.status === "cancelled" ? "cancelled" : undefined,
250
+ frame: "card",
251
+ collapsible: hasBody,
252
+ collapsed: hasBody ? !input.expanded : undefined,
253
+ preview: hasBody ? { tail: DEFAULT_TERMINAL_PREVIEW_LINES } : undefined,
254
+ },
255
+ body,
256
+ );
257
+ }
258
+
107
259
  /**
108
260
  * Derive the post-run status from an exit code + cancellation flag using the
109
261
  * same precedence both execution components apply.
@@ -13,6 +13,7 @@ export class HookMessageComponent extends FramedMessageComponent<HookMessage<unk
13
13
  constructor(message: HookMessage<unknown>, customRenderer?: HookMessageRenderer) {
14
14
  super({
15
15
  message,
16
+ role: "omp.hook",
16
17
  collapseAfterLines: HOOK_COLLAPSED_LINES,
17
18
  customRenderer,
18
19
  });
@@ -1,8 +1,16 @@
1
- import { Container } from "../tui";
1
+ import { type Component, Container } from "../tui";
2
+ import { isNativeRendering } from "../native/state";
2
3
  import { Disclosure } from "../components/disclosure";
3
4
  import { Text } from "../components/text";
4
5
  import { formatDiagnostics } from "../render/render-utils";
5
- import { getLanguageFromPath, theme } from "../theme";
6
+ import { getLanguageFromPath, getThemeEpoch, theme } from "../theme";
7
+ import { card, span, text, withHidden } from "../native/describe";
8
+ import { type NativeNode, type NativeUiEvent, rootToggleExpanded } from "../native/node";
9
+ import { plainText } from "../native/spans";
10
+ import { Memo } from "../native/memo";
11
+
12
+ /** Diagnostics shown by the collapsed native card, matching the ANSI tree's collapsed count. */
13
+ const COLLAPSED_DIAGNOSTICS = 5;
6
14
 
7
15
  const EMPTY_ROWS: readonly string[] = [];
8
16
 
@@ -14,6 +22,45 @@ export interface LateDiagnosticsFile {
14
22
  messages?: string[];
15
23
  }
16
24
 
25
+ /** A tool frame (edit/write) that takes late diagnostics for its own paths. */
26
+ interface LateDiagnosticsTarget {
27
+ attachLateDiagnostics(
28
+ files: readonly { path: string; summary: string; errored: boolean; messages: string[] }[],
29
+ ): boolean;
30
+ }
31
+
32
+ /**
33
+ * Native terminals append late diagnostics into the edit/write frame they
34
+ * belong to: each file goes to the most recent tool component in `blocks`
35
+ * that accepts it. Returns the files no frame took (all of them on the ANSI
36
+ * path), for the standalone {@link LateDiagnosticsMessageComponent}.
37
+ */
38
+ export function routeLateDiagnostics(
39
+ blocks: readonly Component[],
40
+ files: readonly LateDiagnosticsFile[],
41
+ ): LateDiagnosticsFile[] {
42
+ if (!isNativeRendering()) return [...files];
43
+ const targets = blocks.filter(
44
+ (block): block is Component & LateDiagnosticsTarget =>
45
+ typeof (block as Partial<LateDiagnosticsTarget>).attachLateDiagnostics === "function",
46
+ );
47
+ const unrouted: LateDiagnosticsFile[] = [];
48
+ for (const file of files) {
49
+ const entry = file.path
50
+ ? {
51
+ path: file.path,
52
+ summary: file.summary ?? "",
53
+ errored: file.errored === true,
54
+ messages: file.messages ?? [],
55
+ }
56
+ : undefined;
57
+ const routed =
58
+ entry !== undefined && targets.findLast(target => target.attachLateDiagnostics([entry])) !== undefined;
59
+ if (!routed) unrouted.push(file);
60
+ }
61
+ return unrouted;
62
+ }
63
+
17
64
  /**
18
65
  * Renders late LSP diagnostics (arrived after edit/write returned) in the
19
66
  * transcript, reusing the same tree renderer the edit/write tools use so the
@@ -26,6 +73,8 @@ export class LateDiagnosticsMessageComponent extends Container {
26
73
  // lazily on its first render. Only the tool-visibility gate stays here.
27
74
  #disclosure: Disclosure | undefined;
28
75
  readonly #files: LateDiagnosticsFile[];
76
+ #expanded = false;
77
+ readonly #native = new Memo();
29
78
 
30
79
  constructor(files: LateDiagnosticsFile[]) {
31
80
  super();
@@ -35,6 +84,7 @@ export class LateDiagnosticsMessageComponent extends Container {
35
84
  }
36
85
 
37
86
  setExpanded(expanded: boolean): void {
87
+ this.#expanded = expanded;
38
88
  this.#disclosure?.setExpanded(expanded);
39
89
  }
40
90
 
@@ -47,6 +97,39 @@ export class LateDiagnosticsMessageComponent extends Container {
47
97
  return super.render(width);
48
98
  }
49
99
 
100
+ handleNativeEvent(event: NativeUiEvent): void {
101
+ const expanded = rootToggleExpanded(event);
102
+ if (expanded !== undefined) this.setExpanded(expanded);
103
+ }
104
+
105
+ /**
106
+ * A severity-toned card (role `omp.diagnostics.late`) with one wrapped line
107
+ * per diagnostic, clamped by the terminal while collapsed.
108
+ */
109
+ override describe(): NativeNode {
110
+ const key = [this.#expanded, this.#toolActivityVisible, getThemeEpoch()];
111
+ return this.#native.get(key, () => {
112
+ const input = this.#diagnosticInput();
113
+ const icon = input?.errored ? theme.status.error : theme.status.warning;
114
+ const head = [span(`${icon} `, input?.errored ? "error" : "warning"), span("Late diagnostics", "toolTitle")];
115
+ if (input?.summary) head.push(span(` (${plainText(input.summary)})`, "dim"));
116
+ const diagnostics = card(
117
+ {
118
+ role: "omp.diagnostics.late",
119
+ tone: input?.errored ? "error" : "warning",
120
+ head,
121
+ collapsible: true,
122
+ collapsed: !this.#expanded,
123
+ preview: { lines: COLLAPSED_DIAGNOSTICS },
124
+ },
125
+ (input?.messages ?? []).map((message, index) =>
126
+ text([span(plainText(message), "mono")], { wrap: "word", key: `d${index}` }),
127
+ ),
128
+ );
129
+ return withHidden(diagnostics, !this.#toolActivityVisible);
130
+ });
131
+ }
132
+
50
133
  override invalidate(): void {
51
134
  this.#rebuild();
52
135
  }
@@ -1,17 +1,38 @@
1
1
  import * as path from "node:path";
2
+ import { pathToFileURL } from "node:url";
2
3
  import type { AssistantMessage, Usage } from "@oh-my-pi/pi-ai";
3
4
  import { type Component } from "../tui";
4
5
  import { Container } from "../tui";
5
6
  import { Text } from "../components/text";
6
7
  import { getLanguageFromPath, theme } from "../theme";
7
8
  import { parseLineRanges, selectorLineRanges } from "../tools/line-ranges";
8
- import { type ReadRenderArgs, type ReadToolDetails, readSourceFsPath, splitPathAndSel } from "../tools/read";
9
+ import {
10
+ type ReadRenderArgs,
11
+ type ReadToolDetails,
12
+ readContentCode,
13
+ readSourceFsPath,
14
+ splitPathAndSel,
15
+ } from "../tools/read";
9
16
  import { PREVIEW_LIMITS, shortenPath } from "../render/render-utils";
10
17
  import { fileHyperlink, renderCodeCell } from "../render";
11
18
  import { canonicalizeMessage } from "./thinking-display";
12
19
  import { internalUrlSchemeSpec, splitUrlScheme } from "../tools/url-scheme-host";
13
20
  import type { ToolExecutionHandle } from "./tool-execution";
14
21
  import { formatUsageRow } from "../overlays/usage-row";
22
+ import { formatCount } from "@oh-my-pi/pi-utils";
23
+ import type { TspCardStatus, TspSpan, TspText } from "@oh-my-pi/pi-wire";
24
+ import type { NativeToolHead } from "../tools/renderer";
25
+ import { card, code, keyed, node, span, text, withHidden } from "../native/describe";
26
+ import {
27
+ type DescribeContext,
28
+ type NativeChild,
29
+ type NativeNode,
30
+ type NativeUiEvent,
31
+ rootToggleExpanded,
32
+ } from "../native/node";
33
+ import { plainText } from "../native/spans";
34
+ import { Memo } from "../native/memo";
35
+ import { fileHref, fileRow, inlineErrorView } from "../tools/native-view";
15
36
 
16
37
  /**
17
38
  * Extract the read call's target path. `path` is the canonical arg; `file_path`
@@ -117,6 +138,21 @@ type ReadUsageRow = {
117
138
  /** Number of code lines to show in collapsed preview mode */
118
139
  const COLLAPSED_PREVIEW_LINES = PREVIEW_LIMITS.OUTPUT_COLLAPSED;
119
140
 
141
+ /**
142
+ * Collapsed clamp for a data-first group whose previews are already trimmed
143
+ * to {@link COLLAPSED_PREVIEW_LINES}: large enough never to cut the trimmed
144
+ * body, so collapsed shows every file and the head of each preview.
145
+ */
146
+ const TRIMMED_BODY_PREVIEW = { lines: 1000 } as const;
147
+
148
+ /** Native item tone per read status; successful reads stay neutral. */
149
+ const READ_STATUS_TONE: Record<ReadEntry["status"], "pending" | "warning" | "error" | undefined> = {
150
+ success: undefined,
151
+ pending: "pending",
152
+ warning: "warning",
153
+ error: "error",
154
+ };
155
+
120
156
  type ReadDisplayTarget = {
121
157
  entry: ReadEntry;
122
158
  targetPath: string;
@@ -329,6 +365,10 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
329
365
  // run broke, seal(), or an expansion toggle — and the transcript's
330
366
  // width-epoch resolution and committed-render bypass must observe it.
331
367
  #blockVersion = 0;
368
+ #displayVersion = 0;
369
+ readonly #native = new Memo();
370
+ /** Content previews toggled in the terminal, by tool call id. */
371
+ #previewCollapsed = new Map<string, boolean>();
332
372
 
333
373
  constructor(options: ReadToolGroupOptions = {}) {
334
374
  super();
@@ -503,6 +543,7 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
503
543
  setExpanded(expanded: boolean): void {
504
544
  if (this.#expanded !== expanded) this.#blockVersion++;
505
545
  this.#expanded = expanded;
546
+ this.#previewCollapsed.clear();
506
547
  this.#updateDisplay();
507
548
  }
508
549
 
@@ -515,7 +556,306 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
515
556
  return this;
516
557
  }
517
558
 
559
+ /**
560
+ * Mirrors the terminal's toggles: the `tool` head (the group's root) is
561
+ * `Ctrl+O`'s expansion; a fallback preview card collapses on its own
562
+ * (`setExpanded` resets those).
563
+ */
564
+ handleNativeEvent(event: NativeUiEvent): void {
565
+ const expanded = rootToggleExpanded(event);
566
+ if (expanded !== undefined) {
567
+ this.setExpanded(expanded);
568
+ return;
569
+ }
570
+ if (event.type !== "toggle" || !event.key.startsWith("p")) return;
571
+ const toolCallId = event.key.slice(1);
572
+ if (!this.#entries.has(toolCallId)) return;
573
+ this.#previewCollapsed.set(toolCallId, event.collapsed);
574
+ this.#displayVersion++;
575
+ }
576
+
577
+ /**
578
+ * The read run as one inline `tool` on terminals that list the kind, else
579
+ * the fallback: a bare `card` (role `omp.tool.read`) with `Read <path>` or
580
+ * `Read (N)` in the head, a `list` of path items (status tone, link,
581
+ * correction and conflict detail, nested usage) and, with content previews
582
+ * on, a `code` block per read clamped by the card's preview while collapsed.
583
+ */
584
+ override describe(cx?: DescribeContext): NativeNode {
585
+ const dataFirst = cx?.supports("tool") === true;
586
+ const key = [dataFirst, this.#displayVersion, this.#toolActivityVisible, this.#sealed];
587
+ return this.#native.get(key, () =>
588
+ withHidden(dataFirst ? this.#describeTool() : this.#describeGroup(), !this.#toolActivityVisible),
589
+ );
590
+ }
591
+
592
+ /**
593
+ * The data-first read (§7.3 read, read group, read error): one inline
594
+ * `tool` (role `omp.tool.read`). One file: `Read path:13-36`, a failure's
595
+ * message in the head. Several: `Read 3 files` over one 22px row per file
596
+ * (glyph, dim dir, strong name, range). Content previews are numbered
597
+ * `code` (a section per file in a group), trimmed while collapsed.
598
+ */
599
+ #describeTool(): NativeNode {
600
+ const entries = [...this.#entries.values()];
601
+ const rows = this.#buildSummaryRows(this.#displayTargetsForEntries(entries));
602
+ const status = this.#groupStatus(entries);
603
+ const previews = entries.filter(entry => entry.status !== "error" && this.#shouldRenderPreview(entry));
604
+ const body: NativeChild[] = [];
605
+ let head: NativeToolHead;
606
+ // Previews (and a long error message) are what a collapse hides; plain rows always show.
607
+ let collapsible = previews.length > 0;
608
+ if (rows.length <= 1) {
609
+ const row = rows[0];
610
+ const error = row && this.#statusForTargets(row.targets) === "error" ? this.#errorFor(row) : undefined;
611
+ const rowHead: NativeToolHead = row ? this.#nativeRowHead(row) : { target: "…", targetKind: "path" };
612
+ if (error !== undefined) {
613
+ const view = inlineErrorView(rowHead, error);
614
+ head = view.tool ?? rowHead;
615
+ if (view.body) {
616
+ body.push(...view.body);
617
+ collapsible = true;
618
+ }
619
+ } else {
620
+ head = rowHead;
621
+ }
622
+ for (const entry of previews) body.push(...this.#nativePreview(entry));
623
+ for (const [i, usage] of (this.#usageRowsBySummaryRow(rows).get(0) ?? []).entries()) {
624
+ body.push(this.#nativeUsage(usage, `u${i}`));
625
+ }
626
+ } else {
627
+ head = { target: formatCount("file", rows.length), targetKind: "text" };
628
+ const summaryRows = this.#buildSummaryRows(
629
+ this.#displayTargetsForEntries(entries.filter(entry => !previews.includes(entry))),
630
+ );
631
+ const usageByRow = this.#usageRowsBySummaryRow(summaryRows);
632
+ for (const [index, row] of summaryRows.entries()) {
633
+ body.push(this.#nativeFileRow(row));
634
+ for (const [i, usage] of (usageByRow.get(index) ?? []).entries()) {
635
+ body.push(this.#nativeUsage(usage, `u${index}.${i}`));
636
+ }
637
+ }
638
+ for (const entry of previews) {
639
+ const split = splitPathAndSel(entry.path);
640
+ const name = shortenPath(split.path);
641
+ const sectionHead: TspSpan[] = [span(name || "…", "path")];
642
+ if (split.sel) sectionHead.push(span(`:${split.sel}`, "muted"));
643
+ body.push(node("section", { head: sectionHead }, this.#nativePreview(entry), `p${entry.toolCallId}`));
644
+ const usage = this.#usageRows.get(entry.toolCallId);
645
+ if (usage) body.push(this.#nativeUsage(usage, `u${entry.toolCallId}`));
646
+ }
647
+ }
648
+ return node(
649
+ "tool",
650
+ {
651
+ ...head,
652
+ role: "omp.tool.read",
653
+ name: "read",
654
+ title: "Read",
655
+ status,
656
+ tone: status === "error" ? "error" : undefined,
657
+ frame: "inline",
658
+ collapsible,
659
+ collapsed: collapsible ? !this.#expanded : undefined,
660
+ preview: collapsible ? TRIMMED_BODY_PREVIEW : undefined,
661
+ },
662
+ body,
663
+ );
664
+ }
665
+
666
+ /** Head data for one summary row: the path (+ selector) target, its link, correction and conflicts. */
667
+ #nativeRowHead(row: ReadSummaryRow): NativeToolHead {
668
+ const split = splitPathAndSel(row.targetPath);
669
+ const filePath = shortenPath(split.sel ? split.path : row.targetPath);
670
+ const correctedFrom = this.#correctedFromForTargets(row.targets);
671
+ const conflicts = this.#conflictCountForTargets(row.targets);
672
+ return {
673
+ target: filePath ? `${filePath}${split.sel ? `:${split.sel}` : ""}` : "…",
674
+ targetKind: "path",
675
+ href: fileHref(linkPathForTargets(row.targets)),
676
+ meta: correctedFrom ? [`corrected from ${shortenPath(correctedFrom)}`] : undefined,
677
+ badges: conflicts
678
+ ? [{ text: `${conflicts} conflict${conflicts === 1 ? "" : "s"}`, tone: "warning" }]
679
+ : undefined,
680
+ };
681
+ }
682
+
683
+ /** One 22px group row: status glyph, path and range, conflicts chip, then the correction or error message. */
684
+ #nativeFileRow(row: ReadSummaryRow): NativeNode {
685
+ const split = splitPathAndSel(row.targetPath);
686
+ const status = this.#statusForTargets(row.targets);
687
+ const correctedFrom = this.#correctedFromForTargets(row.targets);
688
+ const conflicts = this.#conflictCountForTargets(row.targets);
689
+ const error = status === "error" ? this.#errorFor(row) : undefined;
690
+ const detail: TspText | undefined =
691
+ error !== undefined
692
+ ? [span(`— ${error.split("\n", 1)[0]}`, "error")]
693
+ : correctedFrom
694
+ ? `corrected from ${shortenPath(correctedFrom)}`
695
+ : undefined;
696
+ return fileRow(shortenPath(split.sel ? split.path : row.targetPath), {
697
+ range: split.sel ? `:${split.sel}` : undefined,
698
+ href: fileHref(linkPathForTargets(row.targets)),
699
+ icon: status === "error" ? "x-circle" : undefined,
700
+ tone: READ_STATUS_TONE[status],
701
+ chip: conflicts ? { text: `${conflicts} conflict${conflicts === 1 ? "" : "s"}` } : undefined,
702
+ detail,
703
+ title: error,
704
+ key: row.targetPath,
705
+ });
706
+ }
707
+
708
+ /** The failure message of a row's failed read (its result text, `Error:` prefix dropped). */
709
+ #errorFor(row: ReadSummaryRow): string {
710
+ const failed = row.targets.find(target => target.entry.status === "error")?.entry;
711
+ return (
712
+ plainText(failed?.contentText ?? "")
713
+ .replace(/^Error:\s*/, "")
714
+ .trim() || "Read failed"
715
+ );
716
+ }
717
+
718
+ /** One read's content as numbered `code`, trimmed to its first lines (plus a count) while collapsed. */
719
+ #nativePreview(entry: ReadEntry): NativeChild[] {
720
+ const split = splitPathAndSel(entry.path);
721
+ const lines = (entry.contentText ?? "").split("\n");
722
+ const shown = this.#expanded ? lines.length : Math.min(lines.length, COLLAPSED_PREVIEW_LINES);
723
+ const blocks: NativeChild[] = readContentCode(
724
+ lines.slice(0, shown).join("\n"),
725
+ entry.codeStartLine ?? firstSelectorLine(split.sel) ?? 1,
726
+ entry.codeLineNumbers?.slice(0, shown),
727
+ getLanguageFromPath(split.path),
728
+ );
729
+ const hidden = lines.length - shown;
730
+ if (hidden > 0) {
731
+ blocks.push(
732
+ keyed(text([span(formatCount("more line", hidden), "muted")], { role: "omp.tool.stats" }), "more"),
733
+ );
734
+ }
735
+ return blocks;
736
+ }
737
+
738
+ #describeGroup(): NativeNode {
739
+ const entries = [...this.#entries.values()];
740
+ const rows = this.#buildSummaryRows(this.#displayTargetsForEntries(entries));
741
+ const usageByRow = this.#usageRowsBySummaryRow(rows);
742
+ const previews = entries.filter(entry => this.#shouldRenderPreview(entry));
743
+ const status = this.#groupStatus(entries);
744
+ const title = span("Read", "toolTitle");
745
+ const children: NativeChild[] = [];
746
+ let head: TspSpan[] = [title];
747
+ if (rows.length === 1) {
748
+ head = [title, span(" "), ...this.#nativePathSpans(rows[0]!)];
749
+ if (previews.length === 0) {
750
+ for (const usage of usageByRow.get(0) ?? []) children.push(this.#nativeUsage(usage, "u0"));
751
+ }
752
+ } else if (rows.length > 1) {
753
+ head = [title, span(` (${rows.length})`, "dim")];
754
+ const summaryTargets = this.#displayTargetsForEntries(
755
+ entries.filter(entry => !this.#shouldRenderPreview(entry)),
756
+ );
757
+ const summaryRows = this.#buildSummaryRows(summaryTargets);
758
+ const summaryUsage = this.#usageRowsBySummaryRow(summaryRows);
759
+ const items = summaryRows.map((row, index) => {
760
+ const usage = (summaryUsage.get(index) ?? []).map(usageRow =>
761
+ plainText(
762
+ formatUsageRow(
763
+ usageRow.usage,
764
+ usageRow.durationMs,
765
+ usageRow.ttftMs,
766
+ usageRow.timestamp,
767
+ usageRow.turnElapsedMs,
768
+ ),
769
+ ),
770
+ );
771
+ return node(
772
+ "item",
773
+ {
774
+ label: this.#nativePathSpans(row),
775
+ tone: READ_STATUS_TONE[this.#statusForTargets(row.targets)],
776
+ detail: usage.length > 0 ? [span(usage.join(" · "), "dim")] : undefined,
777
+ },
778
+ [],
779
+ row.targetPath,
780
+ );
781
+ });
782
+ if (items.length > 0) children.push(node("list", {}, items));
783
+ }
784
+ for (const entry of previews) {
785
+ const split = splitPathAndSel(entry.path);
786
+ const pathValue = shortenPath(entry.path);
787
+ children.push(
788
+ node(
789
+ "card",
790
+ {
791
+ role: "omp.tool.read.preview",
792
+ tone: READ_STATUS_TONE[entry.status],
793
+ head: pathValue ? [title, span(" "), span(pathValue, "path")] : [title],
794
+ collapsible: true,
795
+ collapsed: this.#previewCollapsed.get(entry.toolCallId) ?? !this.#expanded,
796
+ preview: { lines: COLLAPSED_PREVIEW_LINES },
797
+ },
798
+ [
799
+ code(entry.contentText ?? "", {
800
+ lang: getLanguageFromPath(split.path),
801
+ start: entry.codeStartLine,
802
+ numbers: true,
803
+ }),
804
+ ],
805
+ `p${entry.toolCallId}`,
806
+ ),
807
+ );
808
+ const usage = this.#usageRows.get(entry.toolCallId);
809
+ if (usage) children.push(this.#nativeUsage(usage, `u${entry.toolCallId}`));
810
+ }
811
+ return card(
812
+ {
813
+ role: "omp.tool.read",
814
+ // A group is plain rows: the per-file previews are the only frames.
815
+ variant: "bare",
816
+ status,
817
+ tone: status === "error" ? "error" : status === "running" ? "pending" : undefined,
818
+ head,
819
+ },
820
+ children,
821
+ );
822
+ }
823
+
824
+ #groupStatus(entries: readonly ReadEntry[]): TspCardStatus {
825
+ let rank = 0;
826
+ for (const entry of entries) rank = Math.max(rank, READ_STATUS_RANK[entry.status]);
827
+ if (rank === READ_STATUS_RANK.error) return "error";
828
+ if (rank === READ_STATUS_RANK.pending) return this.#sealed ? "cancelled" : "running";
829
+ return "done";
830
+ }
831
+
832
+ /** Path spans for a summary row: linked path, selector, correction note and conflict badge. */
833
+ #nativePathSpans(row: ReadSummaryRow): TspSpan[] {
834
+ const split = splitPathAndSel(row.targetPath);
835
+ const filePath = shortenPath(split.sel ? split.path : row.targetPath);
836
+ const linkPath = linkPathForTargets(row.targets);
837
+ const spans: TspSpan[] = [];
838
+ if (filePath) {
839
+ const href = linkPath && path.isAbsolute(linkPath) ? pathToFileURL(linkPath).href : undefined;
840
+ spans.push(span(filePath, "path", href ? { href } : undefined));
841
+ } else {
842
+ spans.push(span("…", "toolOutput"));
843
+ }
844
+ if (split.sel) spans.push(span(`:${split.sel}`, "accent"));
845
+ const correctedFrom = this.#correctedFromForTargets(row.targets);
846
+ if (correctedFrom) spans.push(span(` (corrected from ${shortenPath(correctedFrom)})`, "dim"));
847
+ const conflicts = this.#conflictCountForTargets(row.targets);
848
+ if (conflicts) spans.push(span(` (⚠ ${conflicts} conflict${conflicts === 1 ? "" : "s"})`, "warning"));
849
+ return spans;
850
+ }
851
+
852
+ #nativeUsage(usage: ReadUsageRow, key: string): NativeNode {
853
+ const line = formatUsageRow(usage.usage, usage.durationMs, usage.ttftMs, usage.timestamp, usage.turnElapsedMs);
854
+ return text([span(plainText(line), "dim")], { wrap: "word", key, role: "omp.usage" });
855
+ }
856
+
518
857
  #updateDisplay(): void {
858
+ this.#displayVersion++;
519
859
  const entries = [...this.#entries.values()];
520
860
  const displayTargets = this.#displayTargetsForEntries(entries);
521
861
  const displayRows = this.#buildSummaryRows(displayTargets);