@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/lsp.ts CHANGED
@@ -7,12 +7,14 @@
7
7
  * - Grouped references and symbols
8
8
  * - Collapsible/expandable views
9
9
  */
10
- import type { RenderResultOptions, ToolRenderer } from "./renderer";
10
+ import type { TspSpan, TspText, TspTone, TspTreeNode } from "@oh-my-pi/pi-wire";
11
+ import type { NativeToolHead, NativeToolView, RenderResultOptions, ToolRenderer, ToolRenderResult } from "./renderer";
11
12
  import type { Component } from "../tui";
12
13
  import { Text } from "../components/text";
13
14
  import { getLanguageFromPath } from "../lang-from-path";
14
15
  import { highlightCode as highlightThemeCode, type Theme } from "../theme/theme";
15
16
  import {
17
+ formatCount,
16
18
  formatExpandHint,
17
19
  formatMoreItems,
18
20
  formatStatusIcon,
@@ -26,6 +28,13 @@ import {
26
28
  } from "../render/render-utils";
27
29
  import { renderStatusLine } from "../render";
28
30
  import { framedToolCard } from "../render/tool-card";
31
+ import { ansi, code, col, compact, keyed, md, node, row, span, text } from "../native/describe";
32
+ import type { NativeNode } from "../native/node";
33
+ import { OwnerMemo } from "../native/memo";
34
+ import { plainText } from "../native/spans";
35
+ import { walkGroupedOutput } from "./grouped-file-output";
36
+ import { diagnosticGlyph, fileHref, fileRow, inlineErrorView } from "./native-view";
37
+ import { activeThemeSymbol } from "../theme/active-symbols";
29
38
 
30
39
  /** Display arguments for an LSP tool request. */
31
40
  export interface LspParams {
@@ -693,10 +702,318 @@ function severityToColor(severity: ParsedDiagnostic["severity"]): "error" | "war
693
702
  }
694
703
  }
695
704
 
705
+ // =============================================================================
706
+ // Native (TSP) Description
707
+ // =============================================================================
708
+
709
+ /** The head verb for an LSP action (`type_definition` → `Type definition`). */
710
+ function lspActionTitle(action: string | undefined): string {
711
+ if (!action || action === "request") return "LSP";
712
+ const words = action.replace(/_/g, " ");
713
+ return words.charAt(0).toUpperCase() + words.slice(1);
714
+ }
715
+
716
+ /**
717
+ * Native head (§7.3 lsp): the action as the verb; the file (`:line`) as a
718
+ * path target, else the query; then the symbol and option facts, then the
719
+ * result `meta` (a count chip).
720
+ */
721
+ function lspNativeHead(
722
+ request: Partial<LspParams> | undefined,
723
+ fallbackAction: string,
724
+ meta: readonly TspText[] = [],
725
+ ): NativeToolHead {
726
+ const facts: string[] = [];
727
+ const symbol = request?.symbol ? plainText(request.symbol).replaceAll(/\r?\n/g, " ") : undefined;
728
+ let target: string | undefined;
729
+ let targetKind: NativeToolHead["targetKind"];
730
+ if (request?.file) {
731
+ target = request.line !== undefined ? `${shortenPath(request.file)}:${request.line}` : shortenPath(request.file);
732
+ targetKind = "path";
733
+ } else if (request?.query) {
734
+ target = request.query;
735
+ targetKind = "query";
736
+ } else if (request?.line !== undefined) {
737
+ facts.push(`line ${request.line}`);
738
+ }
739
+ if (symbol) facts.push(symbol);
740
+ if (request?.query && target !== request.query) facts.push(`query:${request.query}`);
741
+ if (request?.new_name) facts.push(`\u2192 ${request.new_name}`);
742
+ if (request?.apply !== undefined) facts.push(`apply:${request.apply ? "true" : "false"}`);
743
+ return {
744
+ title: lspActionTitle(request?.action ?? fallbackAction),
745
+ target,
746
+ targetKind,
747
+ href: request?.file ? fileHref(request.file) : undefined,
748
+ meta: [...(facts.length > 0 ? [plainText(facts.join(" \u00b7 "))] : []), ...meta],
749
+ };
750
+ }
751
+
752
+ /** A diagnostics response, parsed: diagnostics, server failures and partial-failure warnings. */
753
+ interface LspDiagnosticsParse {
754
+ diagnostics: ParsedDiagnostic[];
755
+ failures: string[];
756
+ warnings: string[];
757
+ /** Lines neither a diagnostic nor a status line (kept verbatim). */
758
+ other: string[];
759
+ }
760
+
761
+ const DIAGNOSTIC_AT_RE = /^\d+:\d+\s+\[/;
762
+ const DIAGNOSTICS_SUMMARY_RE = /^\d+ \w+\(s\)(?:, \d+ \w+\(s\))*:?$/;
763
+ /** A per-file status line's leading status glyph (`✘`, `⚠`, a Nerd Font glyph, ASCII `[!!]`). */
764
+ const STATUS_GLYPH_RE = /^(?:\[[^\]\s]*\]|[^\p{L}\p{N}\s./~\\]+)\s+/u;
765
+ /** Per-file summaries (`✗ a.ts: 2 error(s)`, `✓ a.ts: no issues`) repeat what the rows and head count. */
766
+ const FILE_SUMMARY_RE = /: (?:no issues|\d+ \w+\(s\)(?:, \d+ \w+\(s\))*)$/;
767
+
768
+ /**
769
+ * Parse a diagnostics response: grouped (`# dir/`, `## file`, ` 12:5 [error] …`)
770
+ * or flat (`file:12:5 [error] …`) diagnostic lines, and the per-file status
771
+ * lines (`✗ file: all language servers failed (…)`, `⚠ …some servers failed`,
772
+ * `✓ file: no issues`, `✗ file: 2 error(s)`).
773
+ */
774
+ function parseLspDiagnostics(lines: readonly string[]): LspDiagnosticsParse {
775
+ const out: LspDiagnosticsParse = { diagnostics: [], failures: [], warnings: [], other: [] };
776
+ let file: string | undefined;
777
+ for (const event of walkGroupedOutput(lines)) {
778
+ if (event.kind !== "line") {
779
+ file = event.kind === "file" ? event.path : undefined;
780
+ continue;
781
+ }
782
+ const line = event.text.trim();
783
+ if (line === "OK" || DIAGNOSTICS_SUMMARY_RE.test(line)) continue;
784
+ // Matched by wording, not glyph: a transcript may outlive the theme that wrote it.
785
+ if (/\ball language servers failed\b/.test(line)) {
786
+ out.failures.push(line.replace(STATUS_GLYPH_RE, ""));
787
+ continue;
788
+ }
789
+ if (/\bsome servers failed\b/.test(line)) {
790
+ out.warnings.push(line.replace(STATUS_GLYPH_RE, ""));
791
+ continue;
792
+ }
793
+ if (FILE_SUMMARY_RE.test(line)) continue;
794
+ const parsed = parseDiagnosticMessage(file && DIAGNOSTIC_AT_RE.test(line) ? `${file}:${line}` : line);
795
+ if (parsed) out.diagnostics.push(parsed);
796
+ else out.other.push(line);
797
+ }
798
+ return out;
799
+ }
800
+
801
+ /** `2 errors · 1 warning` in the severity tones, or undefined when there are none. */
802
+ function diagnosticCounts(diagnostics: readonly ParsedDiagnostic[]): TspSpan[] | undefined {
803
+ const counts: Record<ParsedDiagnostic["severity"], number> = { error: 0, warning: 0, info: 0, hint: 0 };
804
+ for (const d of diagnostics) counts[d.severity]++;
805
+ const spans: TspSpan[] = [];
806
+ for (const severity of ["error", "warning", "info", "hint"] as const) {
807
+ const n = counts[severity];
808
+ if (!n) continue;
809
+ if (spans.length > 0) spans.push(span(" \u00b7 ", "dim"));
810
+ spans.push(span(formatCount(severity, n), severityTone(severity)));
811
+ }
812
+ return spans.length > 0 ? spans : undefined;
813
+ }
814
+
815
+ function severityTone(severity: ParsedDiagnostic["severity"]): TspTone {
816
+ switch (severity) {
817
+ case "error":
818
+ return "error";
819
+ case "warning":
820
+ return "warning";
821
+ case "info":
822
+ return "info";
823
+ default:
824
+ return "muted";
825
+ }
826
+ }
827
+
828
+ /** One diagnostic row (role `omp.tool.diagnostic`): severity icon, mono `file:line:col`, source chip, message. */
829
+ function diagnosticRow(diag: ParsedDiagnostic, key: string): NativeNode {
830
+ const message: TspSpan[] = [span(diag.message)];
831
+ if (diag.code) message.push(span(` ${diag.code}`, "muted"));
832
+ return keyed(
833
+ row(
834
+ compact([
835
+ diagnosticGlyph(diag.severity),
836
+ text([span(`${diag.filePath}:${diag.line}:${diag.col}`, "mono muted")], { wrap: "none" }),
837
+ diag.source ? node("badge", { text: diag.source }) : undefined,
838
+ text(message, { wrap: "word", grow: 1 }),
839
+ ]),
840
+ { role: "omp.tool.diagnostic" },
841
+ ),
842
+ key,
843
+ );
844
+ }
845
+
846
+ /** A server failure / partial-failure row: the status icon and the message, in its tone. */
847
+ function statusRow(message: string, tone: "error" | "warning", key: string): NativeNode {
848
+ return keyed(
849
+ row([diagnosticGlyph(tone), text([span(plainText(message), tone)], { wrap: "word", grow: 1 })], {
850
+ role: tone === "error" ? "omp.tool.error" : "omp.tool.diagnostic",
851
+ }),
852
+ key,
853
+ );
854
+ }
855
+
856
+ /**
857
+ * Diagnostics view: a card when there are diagnostics or failures (rows of
858
+ * severity icon · `file:line:col` · source · message), an inline `No issues`
859
+ * otherwise. A failed server is an error row, never "No issues".
860
+ */
861
+ function describeLspDiagnostics(request: Partial<LspParams> | undefined, fallbackAction: string, lines: string[]) {
862
+ const parsed = parseLspDiagnostics(lines);
863
+ const counts = diagnosticCounts(parsed.diagnostics);
864
+ const failed =
865
+ parsed.failures.length > 0 ? [span(formatCount("server failure", parsed.failures.length), "error")] : undefined;
866
+ const rows: NativeNode[] = [
867
+ ...parsed.failures.map((message, i) => statusRow(message, "error", `x${i}`)),
868
+ ...parsed.diagnostics.map((diag, i) => diagnosticRow(diag, `d${i}`)),
869
+ ...parsed.warnings.map((message, i) => statusRow(message, "warning", `w${i}`)),
870
+ ];
871
+ if (parsed.other.length > 0) rows.push(keyed(code(parsed.other.join("\n"), { wrap: true }), "other"));
872
+ const hasErrors = parsed.failures.length > 0 || parsed.diagnostics.some(d => d.severity === "error");
873
+ const meta = compact<TspText>([counts, failed, !counts && !failed && "No issues"]);
874
+ const head = lspNativeHead(request, fallbackAction, meta);
875
+ if (parsed.diagnostics.length === 0 && parsed.failures.length === 0) {
876
+ return { tool: head, inline: true, body: rows.length > 0 ? rows : undefined } satisfies NativeToolView;
877
+ }
878
+ return {
879
+ tool: head,
880
+ tone: hasErrors ? "error" : "warning",
881
+ body: rows,
882
+ preview: { lines: 8 },
883
+ } satisfies NativeToolView;
884
+ }
885
+
886
+ /** References grouped by file (§7.3): a file row with the count, then the `line:col` positions. */
887
+ function describeLspReferences(lines: string[]): NativeNode[] {
888
+ const byFile = new Map<string, string[]>();
889
+ for (const loc of lines) {
890
+ const match = loc.trim().match(/^(.+):(\d+):(\d+)$/);
891
+ if (!match) continue;
892
+ const [, file, line, col] = match;
893
+ let locs = byFile.get(file);
894
+ if (!locs) {
895
+ locs = [];
896
+ byFile.set(file, locs);
897
+ }
898
+ locs.push(`${line}:${col}`);
899
+ }
900
+ const nodes: NativeNode[] = [];
901
+ for (const [file, locs] of byFile) {
902
+ const name = plainText(file);
903
+ nodes.push(
904
+ keyed(
905
+ col(
906
+ [
907
+ fileRow(name, { chip: { text: String(locs.length), title: formatCount("reference", locs.length) } }),
908
+ text([span(locs.join(" "), "mono muted")], { wrap: "word" }),
909
+ ],
910
+ { gap: "xs" },
911
+ ),
912
+ name,
913
+ ),
914
+ );
915
+ }
916
+ return nodes;
917
+ }
918
+
919
+ function describeLspSymbols(lines: string[]): NativeNode | undefined {
920
+ const roots: TspTreeNode[] = [];
921
+ const stack: { indent: number; children: TspTreeNode[] }[] = [];
922
+ let index = 0;
923
+ for (const line of lines) {
924
+ if (!line.includes("@") || !line.includes("line")) continue;
925
+ const symMatch = line.trim().match(/^(\S+)\s+(.+?)\s*@\s*line\s*(\d+)/);
926
+ if (!symMatch) continue;
927
+ const indent = line.match(/^(\s*)/)?.[1].length ?? 0;
928
+ const children: TspTreeNode[] = [];
929
+ const treeNode: TspTreeNode = {
930
+ id: `${index++}`,
931
+ label: [
932
+ span(plainText(symMatch[1]), "accent"),
933
+ span(" "),
934
+ span(plainText(symMatch[2]), "accent"),
935
+ span(` line ${symMatch[3]}`, "muted"),
936
+ ],
937
+ open: true,
938
+ children,
939
+ };
940
+ while (stack.length > 0 && stack[stack.length - 1].indent >= indent) stack.pop();
941
+ (stack[stack.length - 1]?.children ?? roots).push(treeNode);
942
+ stack.push({ indent, children });
943
+ }
944
+ return roots.length > 0 ? node("tree", { nodes: roots }) : undefined;
945
+ }
946
+
947
+ function describeLspResult(result: ToolRenderResult<LspToolDetails>, args: LspParams | undefined): NativeToolView {
948
+ const request = args ?? result.details?.request;
949
+ const fallbackAction = result.details?.action ?? "request";
950
+ const content = result.content?.[0];
951
+ const text = content?.type === "text" ? (content.text ?? "") : "";
952
+ if (result.isError) return inlineErrorView(lspNativeHead(request, fallbackAction), text || "LSP request failed");
953
+ if (!text) return { tool: lspNativeHead(request, fallbackAction, ["No result"]), tone: "warning", inline: true };
954
+
955
+ const lines = text.split("\n");
956
+ const statusError = activeThemeSymbol("status.error");
957
+ const refMatch = text.match(/(\d+)\s+reference\(s\)/);
958
+ const symbolsMatch = text.match(/Symbols in (.+):/);
959
+
960
+ if (/```(\w*)\n([\s\S]*?)```/.test(text)) {
961
+ return { tool: lspNativeHead(request, fallbackAction), inline: true, body: [md(text)], preview: { lines: 4 } };
962
+ }
963
+ if (
964
+ /\d+\s+(?:error|warning)\(s\)/.test(text) ||
965
+ text.includes(statusError) ||
966
+ (request?.action ?? fallbackAction) === "diagnostics"
967
+ ) {
968
+ return describeLspDiagnostics(request, fallbackAction, lines);
969
+ }
970
+ if (refMatch) {
971
+ const refCount = Number.parseInt(refMatch[1], 10);
972
+ const body = describeLspReferences(lines);
973
+ return {
974
+ tool: lspNativeHead(request, fallbackAction, [formatCount("reference", refCount)]),
975
+ tone: refCount > 0 ? undefined : "warning",
976
+ inline: true,
977
+ body: body.length > 0 ? body : undefined,
978
+ preview: { lines: 8 },
979
+ };
980
+ }
981
+ if (symbolsMatch) {
982
+ const body = describeLspSymbols(lines);
983
+ return {
984
+ tool: lspNativeHead(request, fallbackAction, [`in ${symbolsMatch[1]}`]),
985
+ inline: true,
986
+ body: body ? [body] : undefined,
987
+ preview: { lines: 8 },
988
+ };
989
+ }
990
+ const hasError = text.includes("Error:") || text.includes(statusError);
991
+ const hasSuccess = text.includes(activeThemeSymbol("status.success")) || text.includes("Applied");
992
+ return {
993
+ tool: lspNativeHead(request, fallbackAction),
994
+ tone: hasError && !hasSuccess ? "error" : undefined,
995
+ inline: true,
996
+ body: [ansi(text)],
997
+ preview: { lines: 4 },
998
+ };
999
+ }
1000
+
1001
+ const lspResultMemo = new OwnerMemo<NativeToolView | undefined>();
1002
+
696
1003
  /** Render LSP requests and responses in the transcript. */
697
1004
  export const lspToolRenderer = {
698
1005
  renderCall,
699
1006
  renderResult,
1007
+ describeCall(args: LspParams): NativeToolView {
1008
+ return { tool: lspNativeHead(args, "request"), inline: true };
1009
+ },
1010
+ describeResult(
1011
+ result: ToolRenderResult<LspToolDetails>,
1012
+ _options: RenderResultOptions,
1013
+ args?: LspParams,
1014
+ ): NativeToolView | undefined {
1015
+ return lspResultMemo.get(result, [], () => describeLspResult(result, args));
1016
+ },
700
1017
  mergeCallAndResult: true,
701
1018
  inline: true,
702
1019
  } satisfies ToolRenderer<LspParams, LspToolDetails>;
package/src/tools/mcp.ts CHANGED
@@ -6,9 +6,16 @@
6
6
  */
7
7
  import { type Component, Markdown } from "../index";
8
8
 
9
- import type { RenderResultOptions } from "./renderer";
9
+ import type { NativeToolHead, NativeToolView, RenderResultOptions } from "./renderer";
10
+ import { INTENT_FIELD } from "@oh-my-pi/pi-wire";
11
+ import { ansi, md } from "../native/describe";
12
+ import type { NativeChild } from "../native/node";
13
+ import { OwnerMemo } from "../native/memo";
14
+ import { plainText } from "../native/spans";
15
+ import { errorText, noteText, truncationNotice } from "./native-view";
10
16
  import { getMarkdownTheme, type Theme } from "../theme/theme";
11
17
  import {
18
+ describeJsonTree,
12
19
  formatArgsInline,
13
20
  JSON_TREE_MAX_DEPTH_COLLAPSED,
14
21
  JSON_TREE_MAX_DEPTH_EXPANDED,
@@ -230,6 +237,78 @@ export function renderMCPResult(
230
237
  );
231
238
  }
232
239
 
240
+ /** Visible MCP argument entries (streaming/intent bookkeeping keys dropped). */
241
+ function visibleMcpArgs(args: Record<string, unknown> | undefined): [string, unknown][] {
242
+ if (!args || typeof args !== "object") return [];
243
+ return Object.entries(args).filter(([key]) => key !== INTENT_FIELD && key !== "__partialJson");
244
+ }
245
+
246
+ /** Inline args summary budget in characters (a data cap, not a width). */
247
+ const MCP_ARGS_SUMMARY_CHARS = 160;
248
+
249
+ /** Native MCP head: the tool title with a one-line args summary as target. */
250
+ function mcpHead(title: string, args: Record<string, unknown> | undefined): NativeToolHead {
251
+ const entries = visibleMcpArgs(args);
252
+ const summary =
253
+ entries.length > 0
254
+ ? formatArgsInline(Object.fromEntries(entries), MCP_ARGS_SUMMARY_CHARS, { characterBudget: true })
255
+ : "";
256
+ return { title, target: summary ? plainText(summary) : undefined, targetKind: "text" };
257
+ }
258
+
259
+ /** Native MCP call view: the head only, inline while pending. */
260
+ export function describeMCPCall(args: Record<string, unknown>, label: string): NativeToolView {
261
+ return { tool: mcpHead(label, args), inline: true };
262
+ }
263
+
264
+ const mcpResultMemo = new OwnerMemo<NativeToolView | undefined>();
265
+
266
+ /**
267
+ * Native MCP result view: JSON output as a JSON tree, Markdown when the
268
+ * preference is on, otherwise the raw text as tool output. The head's args
269
+ * summary stands in for the ANSI card's Args tree.
270
+ */
271
+ export function describeMCPResult(
272
+ result: { content: Array<{ type: string; text?: string }>; details?: MCPToolDetails; isError?: boolean },
273
+ _options: RenderResultOptions,
274
+ args?: Record<string, unknown>,
275
+ ): NativeToolView | undefined {
276
+ return mcpResultMemo.get(result, [renderMarkdownResults, JSON.stringify(args ?? null)], () => {
277
+ const textContent = (result.content ?? [])
278
+ .filter(block => block.type === "text")
279
+ .map(block => block.text ?? "")
280
+ .filter(text => text.length > 0)
281
+ .join("\n\n");
282
+ const output = stripOutputNotice(textContent, result.details?.meta).trimEnd();
283
+ const isError = result.isError ?? result.details?.isError ?? false;
284
+ const title = result.details ? `${result.details.serverName}/${result.details.mcpToolName}` : "MCP";
285
+ const body: NativeChild[] = [];
286
+ let parsed: unknown;
287
+ let isJson = false;
288
+ if (output.startsWith("{") || output.startsWith("[")) {
289
+ try {
290
+ parsed = JSON.parse(output);
291
+ isJson = true;
292
+ } catch {
293
+ // Bracketed non-JSON text falls through to Markdown/raw output.
294
+ }
295
+ }
296
+ if (!output) body.push(noteText("(no output)"));
297
+ else if (isError) body.push(errorText(output));
298
+ else if (isJson) body.push(describeJsonTree(parsed));
299
+ else if (renderMarkdownResults) body.push(md(output));
300
+ else body.push(ansi(output));
301
+ const warning = truncationNotice(result.details?.meta);
302
+ if (warning) body.push(warning);
303
+ return {
304
+ tool: mcpHead(title, args),
305
+ tone: isError ? "error" : undefined,
306
+ body,
307
+ preview: { lines: 4 },
308
+ };
309
+ });
310
+ }
311
+
233
312
  import type { OutputMeta } from "./output-meta";
234
313
 
235
314
  let renderMarkdownResults = false;
@@ -1,4 +1,4 @@
1
- import type { ToolRenderer } from "./renderer";
1
+ import type { NativeToolView, ToolRenderer } from "./renderer";
2
2
  /**
3
3
  * Inline TUI renderers for the long-term memory tools (`retain`, `recall`,
4
4
  * `reflect`).
@@ -23,6 +23,10 @@ import {
23
23
  replaceTabs,
24
24
  type ToolUIStatus,
25
25
  } from "../render/render-utils";
26
+ import { item, list, md, span, text } from "../native/describe";
27
+ import { OwnerMemo } from "../native/memo";
28
+ import { plainText } from "../native/spans";
29
+ import { errorView, resultText, toolHead } from "./native-view";
26
30
 
27
31
  // Each stored memory renders as `<bullet> <content>`; the bullet glyph comes
28
32
  // from the active theme (`•` by default, a nerd-font dot under nerd themes).
@@ -48,10 +52,6 @@ function retainContents(args: RetainRenderArgs | undefined): string[] {
48
52
  return contents;
49
53
  }
50
54
 
51
- function resultText(result: { content?: Array<{ type: string; text?: string }> }): string {
52
- return (result.content?.find(c => c.type === "text")?.text ?? "").trim();
53
- }
54
-
55
55
  /** Single-line query header used by `recall`/`reflect` calls and results. */
56
56
  function queryHeader(
57
57
  title: string,
@@ -85,6 +85,24 @@ function retainComponent(contents: string[], header: string, getExpanded: () =>
85
85
  });
86
86
  }
87
87
 
88
+ /** Retained memories as a list, clamped to the collapsed item budget. */
89
+ function describeRetain(contents: string[], summary?: string): NativeToolView {
90
+ return {
91
+ head: toolHead("Retain", summary),
92
+ inline: true,
93
+ body:
94
+ contents.length > 0
95
+ ? [list(contents.map((content, i) => item(String(i), { label: plainText(content) })))]
96
+ : [],
97
+ preview: { lines: PREVIEW_LIMITS.COLLAPSED_ITEMS },
98
+ };
99
+ }
100
+
101
+ const retainCallMemo = new OwnerMemo<NativeToolView | undefined>();
102
+ const retainResultMemo = new OwnerMemo<NativeToolView | undefined>();
103
+ const recallResultMemo = new OwnerMemo<NativeToolView | undefined>();
104
+ const reflectResultMemo = new OwnerMemo<NativeToolView | undefined>();
105
+
88
106
  /** Render retained memory items and their storage summary. */
89
107
  export const retainToolRenderer = {
90
108
  inline: true,
@@ -101,12 +119,12 @@ export const retainToolRenderer = {
101
119
  args?: RetainRenderArgs,
102
120
  ): Component {
103
121
  if (result.isError) {
104
- return new Text(formatErrorMessage(resultText(result) || "Retain failed", theme), 0, 0);
122
+ return new Text(formatErrorMessage(resultText(result).trim() || "Retain failed", theme), 0, 0);
105
123
  }
106
124
  const contents = retainContents(args);
107
125
  // `summary` is the tool's own "N memories stored/queued." line; drop the
108
126
  // trailing period so it reads cleanly as a status meta segment.
109
- const summary = resultText(result).replace(/\.$/, "");
127
+ const summary = resultText(result).trim().replace(/\.$/, "");
110
128
  const header = renderStatusLine(
111
129
  {
112
130
  iconOverride: theme.styledSymbol("tool.memory", "accent"),
@@ -117,6 +135,21 @@ export const retainToolRenderer = {
117
135
  );
118
136
  return retainComponent(contents, header, () => options.expanded, theme);
119
137
  },
138
+ describeCall(args: RetainRenderArgs): NativeToolView | undefined {
139
+ const contents = retainContents(args);
140
+ return retainCallMemo.get(args, [contents.join("\0")], () => describeRetain(contents));
141
+ },
142
+ describeResult(
143
+ result: { content: Array<{ type: string; text?: string }>; details?: MemoryRetainDetails; isError?: boolean },
144
+ _options: RenderResultOptions,
145
+ args?: RetainRenderArgs,
146
+ ): NativeToolView | undefined {
147
+ return retainResultMemo.get(result, [], () => {
148
+ if (result.isError)
149
+ return { ...errorView("Retain", resultText(result).trim() || "Retain failed"), inline: true };
150
+ return describeRetain(retainContents(args), resultText(result).trim().replace(/\.$/, ""));
151
+ });
152
+ },
120
153
  } satisfies ToolRenderer<RetainRenderArgs, MemoryRetainDetails>;
121
154
 
122
155
  /** Render recalled memories with an expandable body. */
@@ -133,9 +166,9 @@ export const recallToolRenderer = {
133
166
  args?: QueryRenderArgs,
134
167
  ): Component {
135
168
  if (result.isError) {
136
- return new Text(formatErrorMessage(resultText(result) || "Recall failed", theme), 0, 0);
169
+ return new Text(formatErrorMessage(resultText(result).trim() || "Recall failed", theme), 0, 0);
137
170
  }
138
- const text = resultText(result);
171
+ const text = resultText(result).trim();
139
172
  const match = text.match(/^Found (\d+) relevant/);
140
173
  const found = match ? Number(match[1]) : 0;
141
174
  const meta = [found > 0 ? `${found} found` : "no matches"];
@@ -165,6 +198,34 @@ export const recallToolRenderer = {
165
198
  },
166
199
  );
167
200
  },
201
+ describeCall(args: QueryRenderArgs): NativeToolView {
202
+ return { head: toolHead("Recall", args.query?.trim()), inline: true };
203
+ },
204
+ describeResult(
205
+ result: { content: Array<{ type: string; text?: string }>; isError?: boolean },
206
+ _options: RenderResultOptions,
207
+ args?: QueryRenderArgs,
208
+ ): NativeToolView | undefined {
209
+ return recallResultMemo.get(result, [], () => {
210
+ const query = args?.query?.trim();
211
+ const output = resultText(result).trim();
212
+ if (result.isError) return { ...errorView("Recall", output || "Recall failed", query), inline: true };
213
+ const found = Number(output.match(/^Found (\d+) relevant/)?.[1] ?? 0);
214
+ if (found === 0) return { head: toolHead("Recall", query, "no matches"), tone: "warning", inline: true };
215
+ // Collapsed keeps to the header; expanding reveals the recalled memories.
216
+ const memories = output
217
+ .replace(/^[^\n]*\n+/, "")
218
+ .split("\n")
219
+ .slice(0, PREVIEW_LIMITS.OUTPUT_EXPANDED)
220
+ .join("\n");
221
+ return {
222
+ head: toolHead("Recall", query, `${found} found`),
223
+ inline: true,
224
+ body: memories.trim() ? [text([span(plainText(memories), "muted")], { wrap: "word" })] : [],
225
+ preview: { lines: 0 },
226
+ };
227
+ });
228
+ },
168
229
  } satisfies ToolRenderer<QueryRenderArgs, unknown>;
169
230
 
170
231
  /** Render synthesized memory reflections. */
@@ -181,7 +242,7 @@ export const reflectToolRenderer = {
181
242
  args?: QueryRenderArgs,
182
243
  ): Component {
183
244
  if (result.isError) {
184
- return new Text(formatErrorMessage(resultText(result) || "Reflect failed", theme), 0, 0);
245
+ return new Text(formatErrorMessage(resultText(result).trim() || "Reflect failed", theme), 0, 0);
185
246
  }
186
247
  const header = queryHeader(
187
248
  "Reflect",
@@ -191,7 +252,7 @@ export const reflectToolRenderer = {
191
252
  undefined,
192
253
  theme.styledSymbol("tool.memory", "accent"),
193
254
  );
194
- const answer = resultText(result);
255
+ const answer = resultText(result).trim();
195
256
  const answerLines = answer.split("\n").filter(line => line.trim().length > 0);
196
257
  return createCachedComponent(
197
258
  () => options.expanded,
@@ -212,6 +273,27 @@ export const reflectToolRenderer = {
212
273
  },
213
274
  );
214
275
  },
276
+ describeCall(args: QueryRenderArgs): NativeToolView {
277
+ return { head: toolHead("Reflect", args.query?.trim()), inline: true };
278
+ },
279
+ describeResult(
280
+ result: { content: Array<{ type: string; text?: string }>; isError?: boolean },
281
+ _options: RenderResultOptions,
282
+ args?: QueryRenderArgs,
283
+ ): NativeToolView | undefined {
284
+ return reflectResultMemo.get(result, [], () => {
285
+ const query = args?.query?.trim();
286
+ const answer = resultText(result).trim();
287
+ if (result.isError) return { ...errorView("Reflect", answer || "Reflect failed", query), inline: true };
288
+ const shown = answer.split("\n").slice(0, PREVIEW_LIMITS.OUTPUT_EXPANDED).join("\n").trim();
289
+ return {
290
+ head: toolHead("Reflect", query),
291
+ inline: true,
292
+ body: shown ? [md(shown, { role: "omp.memory.reflect" })] : [],
293
+ preview: { lines: PREVIEW_LIMITS.OUTPUT_COLLAPSED },
294
+ };
295
+ });
296
+ },
215
297
  } satisfies ToolRenderer<QueryRenderArgs, unknown>;
216
298
 
217
299
  /** Number of memories accepted by retain. */