@oh-my-pi/pi-tui 18.4.3 → 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 (447) hide show
  1. package/CHANGELOG.md +36 -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/todo-reminder.d.ts +4 -1
  22. package/dist/types/chat/tool-execution.d.ts +25 -1
  23. package/dist/types/chat/transcript-actions.d.ts +37 -0
  24. package/dist/types/chat/transcript-entry.d.ts +3 -1
  25. package/dist/types/chat/user-message.d.ts +25 -0
  26. package/dist/types/chrome/collab-qrcode.d.ts +7 -0
  27. package/dist/types/chrome/context-thresholds.d.ts +11 -0
  28. package/dist/types/chrome/countdown-timer.d.ts +9 -3
  29. package/dist/types/chrome/diff.d.ts +12 -0
  30. package/dist/types/chrome/dynamic-border.d.ts +3 -0
  31. package/dist/types/chrome/format.d.ts +6 -0
  32. package/dist/types/chrome/message-divider.d.ts +13 -0
  33. package/dist/types/chrome/message-frame.d.ts +10 -0
  34. package/dist/types/chrome/message-notice.d.ts +23 -0
  35. package/dist/types/chrome/overlay-box.d.ts +11 -2
  36. package/dist/types/chrome/qrcode.d.ts +7 -0
  37. package/dist/types/chrome/segment-track.d.ts +7 -0
  38. package/dist/types/chrome/selector-helpers.d.ts +0 -6
  39. package/dist/types/chrome/status-notice.d.ts +14 -0
  40. package/dist/types/chrome/streaming-panel.d.ts +3 -0
  41. package/dist/types/chrome/tool-activity.d.ts +3 -0
  42. package/dist/types/chrome/transcript-container.d.ts +13 -0
  43. package/dist/types/chrome/transcript-status.d.ts +15 -3
  44. package/dist/types/components/box.d.ts +7 -0
  45. package/dist/types/components/disclosure.d.ts +9 -0
  46. package/dist/types/components/editor.d.ts +37 -0
  47. package/dist/types/components/form.d.ts +14 -0
  48. package/dist/types/components/image.d.ts +7 -0
  49. package/dist/types/components/input.d.ts +20 -1
  50. package/dist/types/components/key-value-list.d.ts +3 -0
  51. package/dist/types/components/layout/geometry.d.ts +16 -0
  52. package/dist/types/components/layout/row.d.ts +7 -0
  53. package/dist/types/components/layout/split-pane.d.ts +8 -0
  54. package/dist/types/components/layout/stack.d.ts +6 -0
  55. package/dist/types/components/loader.d.ts +48 -0
  56. package/dist/types/components/markdown.d.ts +8 -0
  57. package/dist/types/components/metric.d.ts +7 -0
  58. package/dist/types/components/progress-bar.d.ts +3 -0
  59. package/dist/types/components/scroll-view.d.ts +6 -0
  60. package/dist/types/components/section.d.ts +3 -0
  61. package/dist/types/components/select-list.d.ts +33 -0
  62. package/dist/types/components/settings-list.d.ts +68 -0
  63. package/dist/types/components/spacer.d.ts +4 -0
  64. package/dist/types/components/tab-bar.d.ts +9 -0
  65. package/dist/types/components/table.d.ts +7 -0
  66. package/dist/types/components/text.d.ts +6 -0
  67. package/dist/types/components/tree-view.d.ts +9 -0
  68. package/dist/types/components/truncated-text.d.ts +3 -0
  69. package/dist/types/components/wizard-step.d.ts +6 -0
  70. package/dist/types/hotkeys-markdown.d.ts +24 -0
  71. package/dist/types/index.d.ts +5 -0
  72. package/dist/types/latex-block.d.ts +7 -0
  73. package/dist/types/native/apply.d.ts +39 -0
  74. package/dist/types/native/backend.d.ts +94 -0
  75. package/dist/types/native/blobs.d.ts +29 -0
  76. package/dist/types/native/describe.d.ts +56 -0
  77. package/dist/types/native/encode.d.ts +50 -0
  78. package/dist/types/native/icons.d.ts +18 -0
  79. package/dist/types/native/memo.d.ts +27 -0
  80. package/dist/types/native/node.d.ts +107 -0
  81. package/dist/types/native/overlay.d.ts +64 -0
  82. package/dist/types/native/picker.d.ts +124 -0
  83. package/dist/types/native/reconcile.d.ts +41 -0
  84. package/dist/types/native/settle.d.ts +11 -0
  85. package/dist/types/native/spans.d.ts +21 -0
  86. package/dist/types/native/state.d.ts +6 -0
  87. package/dist/types/native/tone.d.ts +24 -0
  88. package/dist/types/overlays/advisor-config.d.ts +20 -0
  89. package/dist/types/overlays/agent-hub-renderer.d.ts +27 -11
  90. package/dist/types/overlays/agent-hub.d.ts +10 -0
  91. package/dist/types/overlays/agent-transcript-viewer.d.ts +7 -0
  92. package/dist/types/overlays/agents-hub.d.ts +8 -0
  93. package/dist/types/overlays/annotation-overlay.d.ts +3 -0
  94. package/dist/types/overlays/ask-dialog.d.ts +23 -0
  95. package/dist/types/overlays/bordered-loader.d.ts +3 -0
  96. package/dist/types/overlays/btw-history-panel.d.ts +9 -0
  97. package/dist/types/overlays/btw-panel.d.ts +3 -0
  98. package/dist/types/overlays/cleanse-panel.d.ts +5 -2
  99. package/dist/types/overlays/composer-shape-preview.d.ts +7 -1
  100. package/dist/types/overlays/copy-selector.d.ts +38 -0
  101. package/dist/types/overlays/error-banner.d.ts +9 -0
  102. package/dist/types/overlays/extensions/extension-list.d.ts +1 -0
  103. package/dist/types/overlays/history-search.d.ts +18 -0
  104. package/dist/types/overlays/hook-editor.d.ts +28 -1
  105. package/dist/types/overlays/hook-input.d.ts +3 -0
  106. package/dist/types/overlays/hook-selector.d.ts +10 -0
  107. package/dist/types/overlays/hub-frame.d.ts +18 -0
  108. package/dist/types/overlays/jobs-panel.d.ts +24 -0
  109. package/dist/types/overlays/login-dialog.d.ts +10 -0
  110. package/dist/types/overlays/logout-account-selector.d.ts +4 -0
  111. package/dist/types/overlays/mcp-add-wizard.d.ts +4 -0
  112. package/dist/types/overlays/model-browser.d.ts +69 -0
  113. package/dist/types/overlays/model-hub.d.ts +7 -0
  114. package/dist/types/overlays/model-picker.d.ts +7 -0
  115. package/dist/types/overlays/move-overlay.d.ts +3 -0
  116. package/dist/types/overlays/oauth-selector.d.ts +4 -0
  117. package/dist/types/overlays/omfg-panel.d.ts +3 -0
  118. package/dist/types/overlays/pause-screen.d.ts +12 -0
  119. package/dist/types/overlays/plan-review-overlay.d.ts +5 -0
  120. package/dist/types/overlays/plan-save-overlay.d.ts +10 -0
  121. package/dist/types/overlays/plugin-selector.d.ts +4 -0
  122. package/dist/types/overlays/plugin-settings.d.ts +30 -0
  123. package/dist/types/overlays/queue-mode-selector.d.ts +4 -0
  124. package/dist/types/overlays/reset-usage-selector.d.ts +8 -0
  125. package/dist/types/overlays/rewind-selector.d.ts +5 -0
  126. package/dist/types/overlays/session-info-overlay.d.ts +19 -1
  127. package/dist/types/overlays/session-selector.d.ts +64 -1
  128. package/dist/types/overlays/settings-defs.d.ts +14 -0
  129. package/dist/types/overlays/settings-selector.d.ts +21 -0
  130. package/dist/types/overlays/show-images-selector.d.ts +4 -0
  131. package/dist/types/overlays/snapcompact-shape-preview.d.ts +2 -0
  132. package/dist/types/overlays/stats-notice.d.ts +8 -0
  133. package/dist/types/overlays/theme-selector.d.ts +11 -0
  134. package/dist/types/overlays/thinking-selector.d.ts +4 -0
  135. package/dist/types/overlays/tree-selector.d.ts +60 -2
  136. package/dist/types/overlays/usage-dashboard.d.ts +26 -3
  137. package/dist/types/overlays/usage-row.d.ts +36 -2
  138. package/dist/types/prompt/attachment-chips.d.ts +8 -0
  139. package/dist/types/prompt/composer-attachments.d.ts +15 -3
  140. package/dist/types/prompt/composer.d.ts +18 -1
  141. package/dist/types/prompt/custom-editor.d.ts +48 -2
  142. package/dist/types/prompt/editor-top-gap.d.ts +2 -0
  143. package/dist/types/prompt/macos-spelling.d.ts +6 -0
  144. package/dist/types/prompt/magic-keywords.d.ts +9 -0
  145. package/dist/types/prompt/queued-messages.d.ts +23 -0
  146. package/dist/types/prompt/skill-tokens.d.ts +4 -2
  147. package/dist/types/prompt/welcome.d.ts +16 -0
  148. package/dist/types/render/code-cell.d.ts +10 -0
  149. package/dist/types/render/file-list.d.ts +8 -0
  150. package/dist/types/render/hyperlink.d.ts +14 -0
  151. package/dist/types/render/output-block.d.ts +43 -0
  152. package/dist/types/render/output-pane.d.ts +17 -0
  153. package/dist/types/render/tool-card.d.ts +8 -0
  154. package/dist/types/render/tree-list.d.ts +8 -0
  155. package/dist/types/render/width-aware-text.d.ts +7 -0
  156. package/dist/types/setup/scenes/outro.d.ts +7 -0
  157. package/dist/types/setup/scenes/sign-in.d.ts +7 -0
  158. package/dist/types/setup/scenes/splash.d.ts +8 -0
  159. package/dist/types/setup/scenes/types.d.ts +6 -1
  160. package/dist/types/setup/wizard-overlay.d.ts +9 -0
  161. package/dist/types/status-line/component.d.ts +49 -5
  162. package/dist/types/status-line/context-usage.d.ts +20 -0
  163. package/dist/types/status-line/footer.d.ts +8 -0
  164. package/dist/types/status-line/metrics.d.ts +1 -2
  165. package/dist/types/status-line/segments.d.ts +10 -1
  166. package/dist/types/status-line/types.d.ts +40 -1
  167. package/dist/types/terminal-capabilities.d.ts +1 -1
  168. package/dist/types/terminal.d.ts +27 -0
  169. package/dist/types/theme/defaults/index.d.ts +100 -0
  170. package/dist/types/theme/schema.d.ts +2 -0
  171. package/dist/types/theme/shimmer.d.ts +8 -0
  172. package/dist/types/theme/theme-class.d.ts +2 -0
  173. package/dist/types/theme/theme.d.ts +33 -1
  174. package/dist/types/tools/ask.d.ts +3 -0
  175. package/dist/types/tools/ast-edit.d.ts +10 -1
  176. package/dist/types/tools/ast-grep.d.ts +10 -1
  177. package/dist/types/tools/autoresearch.d.ts +21 -4
  178. package/dist/types/tools/bash.d.ts +30 -1
  179. package/dist/types/tools/cfg-render.d.ts +5 -1
  180. package/dist/types/tools/debug.d.ts +3 -1
  181. package/dist/types/tools/default-renderer.d.ts +6 -1
  182. package/dist/types/tools/edit.d.ts +14 -1
  183. package/dist/types/tools/eval.d.ts +12 -1
  184. package/dist/types/tools/fetch.d.ts +16 -1
  185. package/dist/types/tools/find.d.ts +15 -1
  186. package/dist/types/tools/github.d.ts +3 -0
  187. package/dist/types/tools/glob.d.ts +14 -1
  188. package/dist/types/tools/goal.d.ts +3 -1
  189. package/dist/types/tools/grep.d.ts +14 -1
  190. package/dist/types/tools/grouped-file-output.d.ts +58 -0
  191. package/dist/types/tools/json-tree.d.ts +20 -0
  192. package/dist/types/tools/lsp.d.ts +3 -10
  193. package/dist/types/tools/mcp.d.ts +16 -1
  194. package/dist/types/tools/memory.d.ts +26 -0
  195. package/dist/types/tools/native-view.d.ts +90 -0
  196. package/dist/types/tools/proc-render.d.ts +7 -1
  197. package/dist/types/tools/read.d.ts +23 -1
  198. package/dist/types/tools/renderer.d.ts +57 -0
  199. package/dist/types/tools/report-tool-issue.d.ts +3 -0
  200. package/dist/types/tools/resolve.d.ts +14 -1
  201. package/dist/types/tools/task.d.ts +3 -0
  202. package/dist/types/tools/think.d.ts +3 -0
  203. package/dist/types/tools/todo.d.ts +12 -0
  204. package/dist/types/tools/vibe.d.ts +3 -1
  205. package/dist/types/tools/wait.d.ts +3 -0
  206. package/dist/types/tools/web-search.d.ts +8 -0
  207. package/dist/types/tools/write.d.ts +14 -1
  208. package/dist/types/tools/xdev.d.ts +13 -0
  209. package/dist/types/tui.d.ts +49 -0
  210. package/package.json +9 -9
  211. package/src/apps/autoresearch-dashboard.ts +362 -4
  212. package/src/apps/cleanse-board.ts +219 -1
  213. package/src/apps/cleanse-picker.ts +9 -1
  214. package/src/apps/debug/log-viewer.ts +15 -15
  215. package/src/apps/debug/protocol-probe.ts +2 -20
  216. package/src/apps/git/avatar.ts +2 -22
  217. package/src/apps/git/git-tui.ts +406 -59
  218. package/src/apps/git/help.ts +130 -0
  219. package/src/apps/git/sidebar.ts +491 -0
  220. package/src/apps/live-visualizer.ts +65 -0
  221. package/src/apps/ps-top.ts +448 -17
  222. package/src/apps/session-picker.ts +1 -0
  223. package/src/apps/setup-model-picker.ts +5 -1
  224. package/src/apps/standalone-picker.ts +55 -1
  225. package/src/autocomplete.ts +44 -1
  226. package/src/chat/advisor-message.ts +72 -3
  227. package/src/chat/assistant-message.ts +346 -11
  228. package/src/chat/background-tan-message.ts +4 -4
  229. package/src/chat/bash-execution.ts +81 -0
  230. package/src/chat/cache-invalidation-marker.ts +8 -0
  231. package/src/chat/chat-transcript-builder.ts +37 -6
  232. package/src/chat/collab-prompt-message.ts +15 -3
  233. package/src/chat/compaction-summary-message.ts +74 -1
  234. package/src/chat/custom-message.ts +3 -1
  235. package/src/chat/eval-execution.ts +57 -0
  236. package/src/chat/execution-shared.ts +153 -1
  237. package/src/chat/hook-message.ts +1 -0
  238. package/src/chat/late-diagnostics-message.ts +85 -2
  239. package/src/chat/read-tool-group.ts +341 -1
  240. package/src/chat/served-model-marker.ts +8 -0
  241. package/src/chat/skill-message.ts +63 -0
  242. package/src/chat/stripped-tool-calls-placeholder.ts +18 -10
  243. package/src/chat/todo-reminder.ts +34 -4
  244. package/src/chat/tool-execution.ts +385 -10
  245. package/src/chat/transcript-actions.ts +38 -0
  246. package/src/chat/transcript-browser.ts +2 -9
  247. package/src/chat/transcript-entry.ts +10 -1
  248. package/src/chat/transcript-render-helpers.ts +16 -15
  249. package/src/chat/ttsr-notification.ts +38 -1
  250. package/src/chat/user-message.ts +167 -4
  251. package/src/chrome/collab-qrcode.ts +27 -2
  252. package/src/chrome/context-thresholds.ts +34 -0
  253. package/src/chrome/countdown-timer.ts +24 -1
  254. package/src/chrome/diff.ts +60 -1
  255. package/src/chrome/dynamic-border.ts +7 -0
  256. package/src/chrome/format.ts +12 -0
  257. package/src/chrome/message-divider.ts +33 -1
  258. package/src/chrome/message-frame.ts +53 -10
  259. package/src/chrome/message-notice.ts +71 -0
  260. package/src/chrome/overlay-box.ts +45 -2
  261. package/src/chrome/qrcode.ts +28 -0
  262. package/src/chrome/segment-track.ts +26 -0
  263. package/src/chrome/selector-helpers.ts +1 -17
  264. package/src/chrome/status-notice.ts +46 -0
  265. package/src/chrome/streaming-panel.ts +25 -1
  266. package/src/chrome/tool-activity.ts +20 -0
  267. package/src/chrome/transcript-container.ts +37 -0
  268. package/src/chrome/transcript-status.ts +40 -11
  269. package/src/components/box.ts +51 -0
  270. package/src/components/disclosure.ts +33 -0
  271. package/src/components/editor.ts +216 -27
  272. package/src/components/form.ts +93 -9
  273. package/src/components/image.ts +30 -0
  274. package/src/components/input.ts +77 -26
  275. package/src/components/key-value-list.ts +18 -0
  276. package/src/components/layout/geometry.ts +44 -0
  277. package/src/components/layout/row.ts +30 -0
  278. package/src/components/layout/split-pane.ts +65 -0
  279. package/src/components/layout/stack.ts +27 -0
  280. package/src/components/loader.ts +183 -1
  281. package/src/components/markdown.ts +21 -0
  282. package/src/components/metric.ts +39 -0
  283. package/src/components/progress-bar.ts +28 -0
  284. package/src/components/scroll-view.ts +23 -0
  285. package/src/components/section.ts +16 -0
  286. package/src/components/select-list.ts +174 -25
  287. package/src/components/settings-list.ts +264 -7
  288. package/src/components/spacer.ts +17 -0
  289. package/src/components/tab-bar.ts +42 -0
  290. package/src/components/table.ts +34 -0
  291. package/src/components/text.ts +23 -0
  292. package/src/components/tree-view.ts +65 -0
  293. package/src/components/truncated-text.ts +14 -0
  294. package/src/components/wizard-step.ts +18 -9
  295. package/src/debug-server.ts +14 -7
  296. package/src/hotkeys-markdown.ts +251 -69
  297. package/src/index.ts +6 -0
  298. package/src/latex-block.ts +11 -0
  299. package/src/native/apply.ts +275 -0
  300. package/src/native/backend.ts +682 -0
  301. package/src/native/blobs.ts +70 -0
  302. package/src/native/describe.ts +124 -0
  303. package/src/native/encode.ts +233 -0
  304. package/src/native/icons.ts +184 -0
  305. package/src/native/memo.ts +64 -0
  306. package/src/native/node.ts +112 -0
  307. package/src/native/overlay.ts +131 -0
  308. package/src/native/picker.ts +333 -0
  309. package/src/native/reconcile.ts +1063 -0
  310. package/src/native/settle.ts +23 -0
  311. package/src/native/spans.ts +308 -0
  312. package/src/native/state.ts +28 -0
  313. package/src/native/tone.ts +79 -0
  314. package/src/overlays/advisor-config.ts +420 -0
  315. package/src/overlays/agent-hub-renderer.ts +155 -18
  316. package/src/overlays/agent-hub.ts +1037 -44
  317. package/src/overlays/agent-transcript-viewer.ts +129 -0
  318. package/src/overlays/agents-hub.ts +688 -53
  319. package/src/overlays/annotation-overlay.ts +391 -52
  320. package/src/overlays/ask-dialog.ts +435 -24
  321. package/src/overlays/bordered-loader.ts +17 -0
  322. package/src/overlays/btw-history-panel.ts +182 -0
  323. package/src/overlays/btw-panel.ts +68 -2
  324. package/src/overlays/cleanse-panel.ts +105 -15
  325. package/src/overlays/codex-reset-fireworks.ts +65 -5
  326. package/src/overlays/composer-shape-preview.ts +26 -1
  327. package/src/overlays/copy-selector.ts +545 -23
  328. package/src/overlays/error-banner.ts +44 -0
  329. package/src/overlays/extensions/extension-list.ts +23 -17
  330. package/src/overlays/history-search.ts +175 -33
  331. package/src/overlays/hook-editor.ts +113 -6
  332. package/src/overlays/hook-input.ts +22 -1
  333. package/src/overlays/hook-selector.ts +311 -22
  334. package/src/overlays/hub-frame.ts +80 -0
  335. package/src/overlays/jobs-panel.ts +112 -0
  336. package/src/overlays/login-dialog.ts +183 -1
  337. package/src/overlays/logout-account-selector.ts +102 -4
  338. package/src/overlays/mcp-add-wizard.ts +232 -53
  339. package/src/overlays/model-browser.ts +681 -22
  340. package/src/overlays/model-hub.ts +1402 -78
  341. package/src/overlays/model-picker.ts +175 -1
  342. package/src/overlays/move-overlay.ts +45 -0
  343. package/src/overlays/oauth-selector.ts +227 -23
  344. package/src/overlays/omfg-panel.ts +86 -2
  345. package/src/overlays/pause-screen.ts +55 -4
  346. package/src/overlays/plan-review-overlay.ts +352 -0
  347. package/src/overlays/plan-save-overlay.ts +45 -0
  348. package/src/overlays/plugin-selector.ts +21 -1
  349. package/src/overlays/plugin-settings.ts +195 -5
  350. package/src/overlays/queue-mode-selector.ts +19 -1
  351. package/src/overlays/reset-usage-selector.ts +110 -40
  352. package/src/overlays/rewind-selector.ts +458 -44
  353. package/src/overlays/session-account-selector.ts +1 -1
  354. package/src/overlays/session-info-overlay.ts +137 -1
  355. package/src/overlays/session-selector.ts +807 -46
  356. package/src/overlays/settings-defs.ts +41 -0
  357. package/src/overlays/settings-selector.ts +583 -23
  358. package/src/overlays/show-images-selector.ts +18 -1
  359. package/src/overlays/snapcompact-shape-preview.ts +48 -3
  360. package/src/overlays/stats-notice.ts +31 -0
  361. package/src/overlays/theme-selector.ts +31 -1
  362. package/src/overlays/thinking-selector.ts +22 -1
  363. package/src/overlays/tree-selector.ts +570 -110
  364. package/src/overlays/usage-dashboard.ts +587 -12
  365. package/src/overlays/usage-row.ts +161 -25
  366. package/src/prompt/attachment-chips.ts +60 -0
  367. package/src/prompt/composer-attachments.ts +31 -9
  368. package/src/prompt/composer.ts +55 -2
  369. package/src/prompt/custom-editor.ts +302 -4
  370. package/src/prompt/editor-top-gap.ts +8 -0
  371. package/src/prompt/macos-spelling.ts +24 -9
  372. package/src/prompt/magic-keywords.ts +22 -1
  373. package/src/prompt/model-mention-autocomplete.ts +1 -0
  374. package/src/prompt/queued-messages.ts +101 -0
  375. package/src/prompt/skill-tokens.ts +5 -3
  376. package/src/prompt/welcome.ts +213 -6
  377. package/src/render/code-cell.ts +103 -2
  378. package/src/render/file-list.ts +29 -0
  379. package/src/render/hyperlink.ts +32 -0
  380. package/src/render/output-block.ts +110 -0
  381. package/src/render/output-pane.ts +37 -0
  382. package/src/render/tool-card.ts +137 -0
  383. package/src/render/tree-list.ts +39 -0
  384. package/src/render/width-aware-text.ts +20 -0
  385. package/src/setup/scenes/composer.ts +29 -0
  386. package/src/setup/scenes/glyph.ts +15 -0
  387. package/src/setup/scenes/model.ts +36 -8
  388. package/src/setup/scenes/outro.ts +28 -1
  389. package/src/setup/scenes/sign-in.ts +122 -13
  390. package/src/setup/scenes/splash.ts +28 -1
  391. package/src/setup/scenes/theme.ts +88 -3
  392. package/src/setup/scenes/types.ts +7 -1
  393. package/src/setup/startup-splash.ts +46 -9
  394. package/src/setup/wizard-overlay.ts +140 -23
  395. package/src/status-line/component.ts +398 -16
  396. package/src/status-line/context-usage.ts +279 -50
  397. package/src/status-line/footer.ts +94 -1
  398. package/src/status-line/metrics.ts +3 -6
  399. package/src/status-line/segments.ts +463 -97
  400. package/src/status-line/separators.ts +3 -16
  401. package/src/status-line/types.ts +43 -1
  402. package/src/terminal-capabilities.ts +7 -0
  403. package/src/terminal.ts +130 -2
  404. package/src/theme/defaults/dark-neon-noir.json +100 -0
  405. package/src/theme/defaults/index.ts +2 -0
  406. package/src/theme/defaults/light-prism.json +5 -5
  407. package/src/theme/defaults/onyx.json +62 -62
  408. package/src/theme/schema.ts +15 -0
  409. package/src/theme/shimmer.ts +33 -0
  410. package/src/theme/theme-class.ts +24 -19
  411. package/src/theme/theme.ts +111 -9
  412. package/src/tools/ask.ts +157 -1
  413. package/src/tools/ast-edit.ts +174 -1
  414. package/src/tools/ast-grep.ts +82 -2
  415. package/src/tools/autoresearch.ts +149 -1
  416. package/src/tools/bash.ts +180 -49
  417. package/src/tools/cfg-render.ts +66 -1
  418. package/src/tools/debug.ts +78 -1
  419. package/src/tools/default-renderer.ts +35 -1
  420. package/src/tools/edit.ts +247 -2
  421. package/src/tools/eval.ts +257 -1
  422. package/src/tools/fetch.ts +102 -3
  423. package/src/tools/find.ts +127 -1
  424. package/src/tools/github.ts +119 -10
  425. package/src/tools/glob.ts +116 -1
  426. package/src/tools/goal.ts +56 -1
  427. package/src/tools/grep.ts +83 -2
  428. package/src/tools/grouped-file-output.ts +205 -0
  429. package/src/tools/json-tree.ts +116 -1
  430. package/src/tools/lsp.ts +318 -1
  431. package/src/tools/mcp.ts +80 -1
  432. package/src/tools/memory.ts +93 -11
  433. package/src/tools/native-view.ts +292 -0
  434. package/src/tools/proc-render.ts +221 -1
  435. package/src/tools/read.ts +199 -4
  436. package/src/tools/renderer.ts +61 -0
  437. package/src/tools/report-tool-issue.ts +7 -1
  438. package/src/tools/resolve.ts +63 -1
  439. package/src/tools/task.ts +406 -4
  440. package/src/tools/think.ts +19 -1
  441. package/src/tools/todo.ts +89 -0
  442. package/src/tools/vibe.ts +230 -2
  443. package/src/tools/wait.ts +181 -1
  444. package/src/tools/web-search.ts +113 -1
  445. package/src/tools/write.ts +144 -5
  446. package/src/tools/xdev.ts +64 -1
  447. package/src/tui.ts +294 -3
package/src/tools/vibe.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  import type { Component } from "../tui";
2
2
  import { Text } from "../components/text";
3
- import { shimmerEnabled, shimmerText } from "../theme/shimmer";
3
+ import { describeShimmer, shimmerEnabled, shimmerText } from "../theme/shimmer";
4
+ import type { TspCardStatus, TspSpan, TspTone } from "@oh-my-pi/pi-wire";
5
+ import { compact, elapsed, node, row, span, text } from "../native/describe";
6
+ import type { NativeChild, NativeNode } from "../native/node";
7
+ import { OwnerMemo } from "../native/memo";
8
+ import { plainText } from "../native/spans";
9
+ import { errorView, noteText, resultText, toolHead } from "./native-view";
4
10
  import type { Theme } from "../theme/theme";
5
11
  import { oneLineLabel } from "./task";
6
12
  import { renderStatusLine } from "../render/index";
@@ -14,7 +20,7 @@ import {
14
20
  type ToolUIStatus,
15
21
  truncateToWidth,
16
22
  } from "../render/render-utils";
17
- import type { RenderResultOptions, ToolRenderer } from "./renderer";
23
+ import type { NativeToolView, RenderResultOptions, ToolRenderer, ToolRenderResult } from "./renderer";
18
24
  /** Operation represented by a worker-session tool result. */
19
25
  export type VibeOp = "spawn" | "send" | "wait" | "kill" | "list";
20
26
 
@@ -294,9 +300,206 @@ function describeCall(op: VibeOp, args: VibeRenderArgs | undefined): string {
294
300
  }
295
301
  }
296
302
 
303
+ // =============================================================================
304
+ // Native (TSP) Description — the terminal clocks spinners, shimmer and timers
305
+ // =============================================================================
306
+
307
+ /** Untruncated head detail for a vibe call (native twin of the ANSI call label). */
308
+ function vibeNativeLabel(op: VibeOp, args: VibeRenderArgs | undefined): string {
309
+ switch (op) {
310
+ case "spawn":
311
+ return `spawn ${args?.cli ?? "?"}${args?.name ? ` · ${args.name}` : ""}`;
312
+ case "send":
313
+ return `send → ${args?.session ?? "?"}`;
314
+ case "wait":
315
+ return args?.sessions?.length ? `wait on ${args.sessions.join(", ")}` : "wait on running sessions";
316
+ case "kill":
317
+ return `kill ${args?.session ?? "?"}`;
318
+ case "list":
319
+ return "sessions";
320
+ }
321
+ }
322
+
323
+ /** The director's composed message as `>`-prefixed wrapped text, or undefined when empty. */
324
+ function vibeComposer(message: string): NativeNode | undefined {
325
+ const trimmed = plainText(message).trim();
326
+ if (!trimmed) return undefined;
327
+ return text([span("> ", "accent"), span(trimmed, "toolOutput")], { wrap: "word", role: "omp.vibe.composer" });
328
+ }
329
+
330
+ function vibeScreenStatus(
331
+ screen: VibeScreenSnapshot,
332
+ settled: "completed" | "failed" | "cancelled" | undefined,
333
+ ): [TspCardStatus, TspTone] {
334
+ if (settled === "failed") return ["error", "error"];
335
+ if (settled === "cancelled") return ["cancelled", "warning"];
336
+ if (settled === "completed") return ["done", "success"];
337
+ switch (screen.state) {
338
+ case "running":
339
+ return ["running", "accent"];
340
+ case "starting":
341
+ return ["pending", "accent"];
342
+ case "idle":
343
+ return ["done", "success"];
344
+ case "dead":
345
+ return ["cancelled", "muted"];
346
+ }
347
+ }
348
+
349
+ /** One worker "TV" as a nested card: identity head, roster meta, live trace, output tail. */
350
+ function describeVibeScreen(
351
+ screen: VibeScreenSnapshot,
352
+ settled: "completed" | "failed" | "cancelled" | undefined,
353
+ nowMs: number,
354
+ ): NativeNode {
355
+ const live = screen.state === "running" || screen.state === "starting";
356
+ const [status, tone] = vibeScreenStatus(screen, settled);
357
+ const head: TspSpan[] = [
358
+ live && shimmerEnabled()
359
+ ? span(screen.id, "accent", { fx: "shimmer" })
360
+ : span(screen.id, live ? "accent" : "toolOutput"),
361
+ span(` ${settled ?? screen.state}`, "dim"),
362
+ span(` ${screen.turns}t${screen.queued > 0 ? `+${screen.queued}q` : ""}`, "muted"),
363
+ ];
364
+ if (screen.model) head.push(span(` ${plainText(screen.model)}`, "muted"));
365
+ const body: NativeChild[] = [
366
+ row(
367
+ compact([
368
+ node("badge", { text: screen.cli, tone }),
369
+ screen.turnStartedAt !== undefined ? elapsed(nowMs - screen.turnStartedAt, !live) : undefined,
370
+ ]),
371
+ { gap: "sm" },
372
+ ),
373
+ ];
374
+ if (live) {
375
+ if (screen.turnMessage) {
376
+ body.push(text([span("> ", "accent"), span(plainText(screen.turnMessage), "dim")], { truncate: "end" }));
377
+ }
378
+ for (const line of screen.trace.slice(-TV_TRACE_EXPANDED)) {
379
+ body.push(text([span(plainText(line), "dim")], { truncate: "end" }));
380
+ }
381
+ const detail = screen.lastIntent ?? screen.currentToolArgs;
382
+ if (screen.currentTool) {
383
+ body.push(describeShimmer([{ text: plainText(`${screen.currentTool}${detail ? `: ${detail}` : ""}`) }]));
384
+ } else if (screen.lastIntent) {
385
+ body.push(text([span(plainText(screen.lastIntent), "muted")], { truncate: "end" }));
386
+ }
387
+ for (const line of screen.outputTail.slice(-TV_OUTPUT_EXPANDED)) {
388
+ if (line.trim().length > 0) body.push(text([span(plainText(line), "muted")], { truncate: "end" }));
389
+ }
390
+ } else if (screen.lastActivity) {
391
+ body.push(text([span(plainText(screen.lastActivity), "muted")], { truncate: "end" }));
392
+ }
393
+ if (settled) {
394
+ body.push(
395
+ text([
396
+ span(
397
+ `turn ${settled} — result delivered`,
398
+ settled === "completed" ? "success" : settled === "failed" ? "error" : "warning",
399
+ ),
400
+ ]),
401
+ );
402
+ }
403
+ return node(
404
+ "card",
405
+ {
406
+ role: "omp.vibe.screen",
407
+ status,
408
+ tone,
409
+ head,
410
+ collapsible: true,
411
+ preview: { lines: 1 + TV_TRACE_COLLAPSED + TV_OUTPUT_COLLAPSED + 1 },
412
+ inset: true,
413
+ },
414
+ body,
415
+ screen.id,
416
+ );
417
+ }
418
+
419
+ function describeVibeResult(
420
+ op: VibeOp,
421
+ result: ToolRenderResult<VibeToolDetails>,
422
+ args: VibeRenderArgs | undefined,
423
+ ): NativeToolView {
424
+ const details = result.details;
425
+ const label = vibeNativeLabel(op, args);
426
+ if (result.isError) return { ...errorView("Vibe", resultText(result) || "vibe failed", label), inline: true };
427
+ if (!details) {
428
+ const fallback = resultText(result).trim();
429
+ return { head: toolHead("Vibe", label), inline: true, body: fallback ? [noteText(fallback)] : [] };
430
+ }
431
+
432
+ if (op === "spawn" || op === "send") {
433
+ const message = op === "spawn" ? (args?.prompt ?? "") : (args?.message ?? "");
434
+ const head: TspSpan[] =
435
+ op === "spawn"
436
+ ? [
437
+ ...toolHead("Vibe", "spawn"),
438
+ span(" "),
439
+ span(details.spawned?.cli ?? args?.cli ?? "?", "accent strong"),
440
+ span(" "),
441
+ span(plainText(details.spawned?.id ?? args?.name ?? ""), "accent"),
442
+ ]
443
+ : [...toolHead("Vibe", "send →"), span(" "), span(plainText(args?.session ?? "?"), "accent")];
444
+ const ack: TspSpan =
445
+ op === "spawn"
446
+ ? span(`turn started${details.spawned ? ` (job ${details.spawned.jobId})` : ""}`, "success")
447
+ : details.send?.mode === "steered"
448
+ ? span("steered into the running turn", "success")
449
+ : details.send?.mode === "queued"
450
+ ? span("mid-turn — queued as the next turn", "warning")
451
+ : span(`turn started${details.send?.jobId ? ` (job ${details.send.jobId})` : ""}`, "success");
452
+ return {
453
+ head,
454
+ inline: true,
455
+ tone: details.send?.mode === "queued" ? "warning" : undefined,
456
+ body: compact([vibeComposer(message), text([ack], { wrap: "word" })]),
457
+ preview: { lines: 3 },
458
+ };
459
+ }
460
+
461
+ if (op === "kill") {
462
+ const note = details.killed?.cancelledTurn ? "in-flight turn cancelled" : undefined;
463
+ return { head: toolHead("Vibe", `kill ${details.killed?.id ?? args?.session ?? "?"}`, note), inline: true };
464
+ }
465
+
466
+ const screens = details.screens;
467
+ const hiddenKilled = details.hiddenKilled?.length ?? 0;
468
+ const killedMeta = hiddenKilled > 0 ? span(` · ${hiddenKilled} killed hidden`, "dim") : undefined;
469
+ if (screens.length === 0) {
470
+ const gist = hiddenKilled > 0 ? "no live sessions" : resultText(result).trim() || "no sessions";
471
+ const head = toolHead("Vibe", op, gist);
472
+ if (killedMeta) head.push(killedMeta);
473
+ return { head, tone: "warning", inline: true };
474
+ }
475
+ const settledById = new Map(details.wait?.settled.map(entry => [entry.id, entry.status] as const) ?? []);
476
+ const running = screens.filter(screen => screen.state === "running" || screen.state === "starting").length;
477
+ const title =
478
+ op === "wait"
479
+ ? details.wait?.waiting === true
480
+ ? "wait — watching the wall"
481
+ : "wait"
482
+ : `sessions (${screens.length})`;
483
+ const head: TspSpan[] = toolHead("Vibe", title);
484
+ if (running > 0) head.push(span(` · ${running} on air`, "accent"));
485
+ if (settledById.size > 0) head.push(span(` · ${settledById.size} settled`, "success"));
486
+ if (details.wait?.timedOut) head.push(span(" · timed out", "warning"));
487
+ if (killedMeta) head.push(killedMeta);
488
+ const nowMs = Date.now();
489
+ return {
490
+ head,
491
+ inline: true,
492
+ tone: details.wait?.timedOut ? "warning" : undefined,
493
+ body: screens.map(screen => describeVibeScreen(screen, settledById.get(screen.id), nowMs)),
494
+ preview: "auto",
495
+ };
496
+ }
497
+
297
498
  /** Build the shared vibe renderer for one tool name. */
298
499
  export function createVibeToolRenderer(op: VibeOp) {
299
500
  const composerOp = op === "spawn" || op === "send";
501
+ const callMemo = new OwnerMemo<NativeToolView | undefined>();
502
+ const resultMemo = new OwnerMemo<NativeToolView | undefined>();
300
503
  return {
301
504
  inline: true,
302
505
  mergeCallAndResult: true,
@@ -429,5 +632,30 @@ export function createVibeToolRenderer(op: VibeOp) {
429
632
  return lines;
430
633
  });
431
634
  },
635
+
636
+ describeCall(args: VibeRenderArgs): NativeToolView | undefined {
637
+ const message = op === "spawn" ? (args?.prompt ?? "") : op === "send" ? (args?.message ?? "") : "";
638
+ return callMemo.get(args, [vibeNativeLabel(op, args), message], () => {
639
+ const head = toolHead("Vibe", vibeNativeLabel(op, args));
640
+ if (!composerOp) return { head, inline: true };
641
+ return {
642
+ head,
643
+ inline: true,
644
+ body: compact([
645
+ vibeComposer(message),
646
+ node("spinner", { label: [span(op === "spawn" ? "booting CLI…" : "delivering…", "dim")] }),
647
+ ]),
648
+ preview: { lines: 3 },
649
+ };
650
+ });
651
+ },
652
+
653
+ describeResult(
654
+ result: ToolRenderResult<VibeToolDetails>,
655
+ _options: RenderResultOptions,
656
+ args?: VibeRenderArgs,
657
+ ): NativeToolView | undefined {
658
+ return resultMemo.get(result, [], () => describeVibeResult(op, result, args));
659
+ },
432
660
  } satisfies ToolRenderer<VibeRenderArgs, VibeToolDetails>;
433
661
  }
package/src/tools/wait.ts CHANGED
@@ -26,6 +26,13 @@ import {
26
26
  import type { StructuredSubagentOutput } from "./task";
27
27
  import type { RenderResultOptions, ToolRenderer, ToolActivitySummary } from "./renderer";
28
28
  import type { IrcDeliveryReceipt, IrcMessage } from "./irc";
29
+ import type { TspSpan } from "@oh-my-pi/pi-wire";
30
+ import { card as cardNode, compact, elapsed, md, node, row, span, text } from "../native/describe";
31
+ import type { NativeNode } from "../native/node";
32
+ import { OwnerMemo } from "../native/memo";
33
+ import { plainText } from "../native/spans";
34
+ import { errorView, resultText, toolHead } from "./native-view";
35
+ import type { NativeToolView, ToolRenderResult } from "./renderer";
29
36
 
30
37
  /** Whether a wait snapshot contains only running jobs and no cancellations. */
31
38
  export function isWaitingPollDetails(details: unknown): boolean {
@@ -541,7 +548,7 @@ export function createIrcMessageCard(
541
548
  if (card.replyTo) meta.push("reply");
542
549
  const age = messageAge(card.timestamp);
543
550
  if (age) meta.push(age);
544
- return createCachedComponent(
551
+ const component = createCachedComponent(
545
552
  getExpanded,
546
553
  (width, expanded) => {
547
554
  const lines = [renderStatusLine({ iconOverride: ircGlyph(uiTheme), title, meta }, uiTheme)];
@@ -552,8 +559,163 @@ export function createIrcMessageCard(
552
559
  },
553
560
  { paddingX: 1 },
554
561
  );
562
+ // Terminal-local collapse replaces `getExpanded`; the node never changes after creation.
563
+ const described = cardNode(
564
+ {
565
+ role: `omp.irc.${card.kind}`,
566
+ tone: "info",
567
+ head: [
568
+ span(plainText(title), "toolTitle strong"),
569
+ ...meta.filter(part => part !== age).map(part => span(` ${part}`, "muted")),
570
+ ],
571
+ collapsible: body.trim().length > 0,
572
+ preview: { lines: 3 },
573
+ },
574
+ compact([
575
+ card.timestamp
576
+ ? row([elapsed(Date.now() - card.timestamp), text([span("ago", "dim")])], { gap: "xs" })
577
+ : undefined,
578
+ body.trim() ? md(body) : undefined,
579
+ ]),
580
+ );
581
+ return Object.assign(component, { describe: () => described });
582
+ }
583
+
584
+ /** One job row: type badge, id + label, terminal-clocked duration (live while running), preview below. */
585
+ function describeJob(job: JobSnapshot): NativeNode {
586
+ const running = job.status === "running";
587
+ const label = job.label.trim() !== job.id ? plainText(job.label.split(/\r?\n/)[0] ?? "") : "";
588
+ const spans: TspSpan[] = [
589
+ span(plainText(job.id), running ? "accent" : "toolOutput", running ? { fx: "shimmer" } : undefined),
590
+ ];
591
+ if (label) spans.push(span(` ${label}`, "toolOutput"));
592
+ if (job.exitCode !== undefined) spans.push(span(` exit ${job.exitCode}`, job.exitCode === 0 ? "muted" : "error"));
593
+ const tone =
594
+ job.status === "completed"
595
+ ? "success"
596
+ : job.status === "failed"
597
+ ? "error"
598
+ : job.status === "cancelled"
599
+ ? "warning"
600
+ : "accent";
601
+ const artifactError = job.meta?.artifactError ?? job.artifactError;
602
+ const preview = flattenStructuredPreview(
603
+ stripTaskResultEnvelope(
604
+ stripOutputNotice(job.errorText?.trim() || job.resultText?.trim() || "", job.meta).trim(),
605
+ ),
606
+ );
607
+ return node(
608
+ "col",
609
+ { role: "omp.wait.job", tone },
610
+ compact([
611
+ row(
612
+ [
613
+ node("badge", { text: job.type, tone }),
614
+ text(spans, { truncate: "end", grow: 1 }),
615
+ elapsed(job.durationMs, !running),
616
+ ],
617
+ { gap: "sm" },
618
+ ),
619
+ artifactError && text([span(formatArtifactErrorNotice(artifactError), "warning")], { wrap: "word" }),
620
+ preview
621
+ ? text([span(plainText(preview), job.errorText ? "error" : "dim")], {
622
+ wrap: "word",
623
+ lines: PREVIEW_LINES_EXPANDED,
624
+ })
625
+ : undefined,
626
+ ]),
627
+ job.id,
628
+ );
555
629
  }
556
630
 
631
+ function describeJobsResult(
632
+ result: ToolRenderResult<CoordinationDetails>,
633
+ isPartial: boolean,
634
+ ): NativeToolView | undefined {
635
+ let jobs = result.details?.jobs ?? [];
636
+ const agents = result.details?.agents ?? [];
637
+ if (jobs.length === 0 && agents.length === 0) {
638
+ return {
639
+ head: toolHead("Wait"),
640
+ tone: "warning",
641
+ body: [text([span(plainText(resultText(result) || "No jobs to process"), "dim")])],
642
+ };
643
+ }
644
+ if (!isPartial && agents.length === 0) {
645
+ jobs = jobs.filter(job => job.status !== "running");
646
+ if (jobs.length === 0) return undefined;
647
+ }
648
+ const counts = { completed: 0, failed: 0, cancelled: 0, running: 0 };
649
+ for (const job of jobs) counts[job.status]++;
650
+ const noun = jobs.length === 1 ? "job" : "jobs";
651
+ const title =
652
+ jobs.length === 0
653
+ ? `${agents.length} running agent${agents.length === 1 ? "" : "s"} — no jobs`
654
+ : counts.running > 0
655
+ ? counts.running === jobs.length
656
+ ? `waiting on ${jobs.length} ${noun}`
657
+ : `waiting on ${counts.running} of ${jobs.length} ${noun}`
658
+ : `${jobs.length} ${noun} settled`;
659
+ const head: TspSpan[] = [span(title, "toolTitle strong")];
660
+ if (counts.completed > 0) head.push(span(` ${counts.completed} done`, "success"));
661
+ if (counts.failed > 0) head.push(span(` ${counts.failed} failed`, "error"));
662
+ if (counts.cancelled > 0) head.push(span(` ${counts.cancelled} cancelled`, "warning"));
663
+ const order: Record<JobSnapshot["status"], number> = { running: 0, failed: 1, cancelled: 2, completed: 3 };
664
+ const sorted = [...jobs].sort((a, b) => order[a.status] - order[b.status] || b.durationMs - a.durationMs);
665
+ const body: NativeNode[] = sorted.map(describeJob);
666
+ for (const agent of agents) {
667
+ const spans: TspSpan[] = [span(plainText(agent.id), "muted")];
668
+ if (agent.activity) spans.push(span(` ${plainText(agent.activity)}`, "toolOutput"));
669
+ if (agent.parentId) spans.push(span(` ← ${plainText(agent.parentId)}`, "dim"));
670
+ body.push(
671
+ node(
672
+ "row",
673
+ { gap: "sm", role: "omp.wait.agent" },
674
+ [
675
+ node("badge", {
676
+ text: agent.live ? "agent" : "agent · no turn",
677
+ tone: agent.live ? "accent" : "warning",
678
+ }),
679
+ text(spans, { truncate: "end", grow: 1 }),
680
+ elapsed(agent.ageMs, !agent.live),
681
+ ],
682
+ `agent:${agent.id}`,
683
+ ),
684
+ );
685
+ }
686
+ return {
687
+ head,
688
+ tone: counts.failed > 0 ? "warning" : counts.running > 0 || agents.length > 0 ? "info" : "success",
689
+ body,
690
+ };
691
+ }
692
+
693
+ /** Received-message view: sender head, terminal-clocked age, markdown body. */
694
+ function describeMessage(
695
+ from: string,
696
+ ts: number | undefined,
697
+ bodyText: string,
698
+ meta: readonly string[],
699
+ ): NativeToolView {
700
+ const head: TspSpan[] = [span(`IRC ← ${plainText(from)}`, "toolTitle strong")];
701
+ for (const part of meta) head.push(span(` ${part}`, "muted"));
702
+ return {
703
+ head,
704
+ tone: "info",
705
+ preview: { lines: BODY_LINES_COLLAPSED + 1 },
706
+ body: compact([
707
+ ts
708
+ ? row([text([span("received", "dim")]), elapsed(Date.now() - ts), text([span("ago", "dim")])], {
709
+ gap: "xs",
710
+ })
711
+ : undefined,
712
+ bodyText.trim() ? md(bodyText) : undefined,
713
+ ]),
714
+ };
715
+ }
716
+
717
+ const waitResultMemo = new OwnerMemo<NativeToolView | undefined>();
718
+
557
719
  /** Render either a received message or a background-job snapshot. */
558
720
  export const waitToolRenderer = {
559
721
  inline: true,
@@ -562,6 +724,24 @@ export const waitToolRenderer = {
562
724
  return { label: "Wait", detail: "Background work or peer message" };
563
725
  },
564
726
  renderCall: waitRenderCall,
727
+ describeCall(): NativeToolView {
728
+ return { head: toolHead("Wait"), inline: true };
729
+ },
730
+ describeResult(
731
+ result: ToolRenderResult<CoordinationDetails>,
732
+ options: RenderResultOptions,
733
+ ): NativeToolView | undefined {
734
+ return waitResultMemo.get(result, [options.isPartial], () => {
735
+ if (result.isError) return errorView("Wait", resultText(result));
736
+ const details = result.details;
737
+ if (details?.interrupted) {
738
+ return { head: toolHead("Wait", "interrupted by message"), tone: "info", inline: true };
739
+ }
740
+ const waited = details?.waited;
741
+ if (!waited) return describeJobsResult(result, options.isPartial);
742
+ return describeMessage(waited.from, waited.ts, waited.body, waited.replyTo ? ["reply"] : []);
743
+ });
744
+ },
565
745
  renderResult(
566
746
  result: { content: Array<{ type: string; text?: string }>; details?: CoordinationDetails; isError?: boolean },
567
747
  options: RenderResultOptions,
@@ -1,4 +1,4 @@
1
- import type { ToolRenderer } from "./renderer";
1
+ import type { NativeToolView, ToolRenderer, ToolRenderResult } from "./renderer";
2
2
  /**
3
3
  * Web Search TUI Rendering
4
4
  *
@@ -23,6 +23,11 @@ import {
23
23
  import { renderStatusLine, renderTreeList, urlHyperlink } from "../render";
24
24
  import { framedToolCard } from "../render/tool-card";
25
25
  import { getSearchProviderLabel, type SearchResponse } from "./web-search-types";
26
+ import { compact, md, node, span, text } from "../native/describe";
27
+ import type { NativeChild } from "../native/node";
28
+ import { OwnerMemo } from "../native/memo";
29
+ import { plainText } from "../native/spans";
30
+ import { errorText, noteText, resultText } from "./native-view";
26
31
 
27
32
  const MAX_COLLAPSED_ITEMS = PREVIEW_LIMITS.COLLAPSED_ITEMS;
28
33
 
@@ -241,9 +246,116 @@ export function renderSearchCall(
241
246
  return new Text(text, 0, 0);
242
247
  }
243
248
 
249
+ type SearchRenderArgs = { query?: string; [key: string]: unknown };
250
+
251
+ const SEARCH_TITLE = "Web search";
252
+
253
+ function searchHead(query: string | undefined, meta?: string, badge?: { text: string; title?: string }) {
254
+ return {
255
+ title: SEARCH_TITLE,
256
+ target: query ? plainText(query) : undefined,
257
+ targetKind: "query" as const,
258
+ meta: meta ? [meta] : undefined,
259
+ badges: badge ? [badge] : undefined,
260
+ };
261
+ }
262
+
263
+ /** One cited source row: domain-initial mark, linked title, muted `domain · age`. */
264
+ function sourceRow(src: SearchResponse["sources"][number], index: number): NativeChild {
265
+ const url = typeof src.url === "string" ? src.url : "";
266
+ const title = typeof src.title === "string" && src.title.trim() ? src.title : url.trim() ? url : "Untitled";
267
+ const domain = url ? getDomain(url) : "";
268
+ const age =
269
+ formatAge(src.ageSeconds).replace(/ ago$/, "") ||
270
+ (typeof src.publishedDate === "string" ? src.publishedDate : "");
271
+ const meta = [domain, age].filter(Boolean).join(" · ");
272
+ const initial = (domain.replace(/^www\./, "")[0] ?? "?").toUpperCase();
273
+ return node(
274
+ "row",
275
+ { gap: "sm", align: "baseline", role: "omp.tool.source", href: url || undefined },
276
+ compact([
277
+ node("badge", { text: initial, title: domain || undefined }),
278
+ text([span(plainText(title), "link", url ? { href: url } : undefined)], { lines: 1, truncate: "end" }),
279
+ meta ? text([span(plainText(meta), "muted")], { lines: 1 }) : undefined,
280
+ ]),
281
+ `${index}:${url}`,
282
+ );
283
+ }
284
+
285
+ function describeSearchResult(
286
+ result: ToolRenderResult<SearchRenderDetails>,
287
+ args: SearchRenderArgs | undefined,
288
+ ): NativeToolView {
289
+ const details = result.details;
290
+ const argQuery = typeof args?.query === "string" ? args.query : undefined;
291
+ if (details?.error) {
292
+ const provider = details.response?.provider;
293
+ const label = provider && provider !== "none" ? getSearchProviderLabel(provider) : undefined;
294
+ return {
295
+ tool: searchHead(argQuery, label),
296
+ tone: "error",
297
+ body: [errorText(plainText(details.error).trim() || "Web search failed")],
298
+ };
299
+ }
300
+
301
+ const rawText = resultText(result).trim();
302
+ const response = details?.response;
303
+ if (!response) {
304
+ return {
305
+ tool: searchHead(argQuery),
306
+ tone: "warning",
307
+ body: [noteText(rawText || "No response data")],
308
+ };
309
+ }
310
+
311
+ const sources = Array.isArray(response.sources) ? response.sources : [];
312
+ const searchQueries = Array.isArray(response.searchQueries)
313
+ ? response.searchQueries.filter(entry => typeof entry === "string")
314
+ : [];
315
+ const providerLabel = response.provider !== "none" ? getSearchProviderLabel(response.provider) : "None";
316
+ const query = argQuery || searchQueries[0];
317
+ const answer = (typeof response.answer === "string" ? response.answer.trim() : "") || rawText;
318
+
319
+ const authShort =
320
+ response.authMode === "oauth" ? "OAuth" : response.authMode === "api_key" ? "API" : response.authMode;
321
+ let providerInfo = response.model ? `${response.model} @ ${providerLabel}` : providerLabel;
322
+ if (authShort) providerInfo += ` (${authShort})`;
323
+ const usage = response.usage;
324
+ const usageParts: string[] = [];
325
+ if (usage?.inputTokens !== undefined) usageParts.push(`in ${usage.inputTokens}`);
326
+ if (usage?.outputTokens !== undefined) usageParts.push(`out ${usage.outputTokens}`);
327
+ if (usage?.totalTokens !== undefined) usageParts.push(`total ${usage.totalTokens}`);
328
+ if (usage?.searchRequests !== undefined) usageParts.push(`search ${usage.searchRequests}`);
329
+ const tooltip = plainText([providerInfo, usageParts.join(" · ")].filter(Boolean).join("\n"));
330
+ const badge = response.model ? { text: plainText(response.model), title: tooltip } : undefined;
331
+
332
+ return {
333
+ tool: searchHead(query, `${providerLabel} · ${formatCount("source", sources.length)}`, badge),
334
+ tone: sources.length > 0 ? undefined : "warning",
335
+ body: compact([
336
+ answer ? { ...md(plainText(answer), { title: tooltip }), key: "answer" } : noteText("No answer text returned"),
337
+ sources.length > 0
338
+ ? node("col", { role: "omp.tool.files" }, sources.map(sourceRow), "sources")
339
+ : noteText("No sources returned"),
340
+ ]),
341
+ };
342
+ }
343
+
344
+ const searchResultMemo = new OwnerMemo<NativeToolView | undefined>();
345
+
244
346
  /** Render web search queries, answers, and cited sources. */
245
347
  export const webSearchToolRenderer = {
246
348
  renderCall: renderSearchCall,
247
349
  renderResult: renderSearchResult,
350
+ describeCall(args: SearchRenderArgs): NativeToolView {
351
+ return { tool: searchHead(typeof args.query === "string" ? args.query : undefined), inline: true };
352
+ },
353
+ describeResult(
354
+ result: ToolRenderResult<SearchRenderDetails>,
355
+ _options: RenderResultOptions,
356
+ args?: SearchRenderArgs,
357
+ ): NativeToolView | undefined {
358
+ return searchResultMemo.get(result, [args?.query ?? ""], () => describeSearchResult(result, args));
359
+ },
248
360
  mergeCallAndResult: true,
249
361
  } satisfies ToolRenderer<{ query?: string; [key: string]: unknown }, SearchRenderDetails>;