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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/types/apps/cleanse-board.d.ts +17 -0
  3. package/dist/types/apps/git/help.d.ts +16 -0
  4. package/dist/types/apps/git/sidebar.d.ts +18 -0
  5. package/dist/types/apps/live-visualizer.d.ts +10 -0
  6. package/dist/types/apps/ps-top.d.ts +15 -0
  7. package/dist/types/apps/standalone-picker.d.ts +3 -0
  8. package/dist/types/autocomplete.d.ts +8 -0
  9. package/dist/types/chat/advisor-message.d.ts +12 -2
  10. package/dist/types/chat/assistant-message.d.ts +20 -0
  11. package/dist/types/chat/bash-execution.d.ts +9 -0
  12. package/dist/types/chat/chat-transcript-builder.d.ts +6 -1
  13. package/dist/types/chat/collab-prompt-message.d.ts +4 -0
  14. package/dist/types/chat/compaction-summary-message.d.ts +15 -0
  15. package/dist/types/chat/eval-execution.d.ts +8 -0
  16. package/dist/types/chat/execution-shared.d.ts +58 -0
  17. package/dist/types/chat/late-diagnostics-message.d.ts +15 -1
  18. package/dist/types/chat/read-tool-group.d.ts +15 -0
  19. package/dist/types/chat/skill-message.d.ts +9 -0
  20. package/dist/types/chat/stripped-tool-calls-placeholder.d.ts +3 -0
  21. package/dist/types/chat/thinking-display.d.ts +2 -0
  22. package/dist/types/chat/todo-reminder.d.ts +4 -1
  23. package/dist/types/chat/tool-execution.d.ts +25 -1
  24. package/dist/types/chat/transcript-actions.d.ts +37 -0
  25. package/dist/types/chat/transcript-entry.d.ts +3 -1
  26. package/dist/types/chat/user-message.d.ts +25 -0
  27. package/dist/types/chrome/collab-qrcode.d.ts +7 -0
  28. package/dist/types/chrome/context-thresholds.d.ts +11 -0
  29. package/dist/types/chrome/countdown-timer.d.ts +9 -3
  30. package/dist/types/chrome/diff.d.ts +12 -0
  31. package/dist/types/chrome/dynamic-border.d.ts +3 -0
  32. package/dist/types/chrome/format.d.ts +6 -0
  33. package/dist/types/chrome/message-divider.d.ts +13 -0
  34. package/dist/types/chrome/message-frame.d.ts +10 -0
  35. package/dist/types/chrome/message-notice.d.ts +23 -0
  36. package/dist/types/chrome/overlay-box.d.ts +11 -2
  37. package/dist/types/chrome/qrcode.d.ts +7 -0
  38. package/dist/types/chrome/segment-track.d.ts +7 -0
  39. package/dist/types/chrome/selector-helpers.d.ts +0 -6
  40. package/dist/types/chrome/status-notice.d.ts +14 -0
  41. package/dist/types/chrome/streaming-panel.d.ts +3 -0
  42. package/dist/types/chrome/tool-activity.d.ts +3 -0
  43. package/dist/types/chrome/transcript-container.d.ts +13 -0
  44. package/dist/types/chrome/transcript-status.d.ts +15 -3
  45. package/dist/types/components/box.d.ts +7 -0
  46. package/dist/types/components/disclosure.d.ts +9 -0
  47. package/dist/types/components/editor.d.ts +42 -0
  48. package/dist/types/components/form.d.ts +14 -0
  49. package/dist/types/components/image.d.ts +7 -0
  50. package/dist/types/components/input.d.ts +20 -1
  51. package/dist/types/components/key-value-list.d.ts +3 -0
  52. package/dist/types/components/layout/geometry.d.ts +16 -0
  53. package/dist/types/components/layout/row.d.ts +7 -0
  54. package/dist/types/components/layout/split-pane.d.ts +8 -0
  55. package/dist/types/components/layout/stack.d.ts +6 -0
  56. package/dist/types/components/loader.d.ts +48 -0
  57. package/dist/types/components/markdown.d.ts +8 -0
  58. package/dist/types/components/metric.d.ts +7 -0
  59. package/dist/types/components/progress-bar.d.ts +3 -0
  60. package/dist/types/components/scroll-view.d.ts +6 -0
  61. package/dist/types/components/section.d.ts +3 -0
  62. package/dist/types/components/select-list.d.ts +33 -0
  63. package/dist/types/components/settings-list.d.ts +68 -0
  64. package/dist/types/components/spacer.d.ts +4 -0
  65. package/dist/types/components/tab-bar.d.ts +9 -0
  66. package/dist/types/components/table.d.ts +7 -0
  67. package/dist/types/components/text.d.ts +6 -0
  68. package/dist/types/components/tree-view.d.ts +9 -0
  69. package/dist/types/components/truncated-text.d.ts +3 -0
  70. package/dist/types/components/wizard-step.d.ts +6 -0
  71. package/dist/types/hotkeys-markdown.d.ts +24 -0
  72. package/dist/types/index.d.ts +5 -0
  73. package/dist/types/latex-block.d.ts +7 -0
  74. package/dist/types/loop-watchdog.d.ts +9 -0
  75. package/dist/types/native/apply.d.ts +39 -0
  76. package/dist/types/native/backend.d.ts +94 -0
  77. package/dist/types/native/blobs.d.ts +29 -0
  78. package/dist/types/native/describe.d.ts +56 -0
  79. package/dist/types/native/encode.d.ts +50 -0
  80. package/dist/types/native/icons.d.ts +18 -0
  81. package/dist/types/native/memo.d.ts +27 -0
  82. package/dist/types/native/node.d.ts +107 -0
  83. package/dist/types/native/overlay.d.ts +64 -0
  84. package/dist/types/native/picker.d.ts +124 -0
  85. package/dist/types/native/reconcile.d.ts +41 -0
  86. package/dist/types/native/settle.d.ts +11 -0
  87. package/dist/types/native/spans.d.ts +21 -0
  88. package/dist/types/native/state.d.ts +6 -0
  89. package/dist/types/native/tone.d.ts +24 -0
  90. package/dist/types/overlays/advisor-config.d.ts +20 -0
  91. package/dist/types/overlays/agent-hub-renderer.d.ts +27 -11
  92. package/dist/types/overlays/agent-hub.d.ts +10 -0
  93. package/dist/types/overlays/agent-transcript-viewer.d.ts +7 -0
  94. package/dist/types/overlays/agents-hub.d.ts +8 -0
  95. package/dist/types/overlays/annotation-overlay.d.ts +3 -0
  96. package/dist/types/overlays/ask-dialog.d.ts +23 -0
  97. package/dist/types/overlays/bordered-loader.d.ts +3 -0
  98. package/dist/types/overlays/btw-history-panel.d.ts +9 -0
  99. package/dist/types/overlays/btw-panel.d.ts +3 -0
  100. package/dist/types/overlays/cleanse-panel.d.ts +5 -2
  101. package/dist/types/overlays/composer-shape-preview.d.ts +7 -1
  102. package/dist/types/overlays/copy-selector.d.ts +38 -0
  103. package/dist/types/overlays/error-banner.d.ts +9 -0
  104. package/dist/types/overlays/extensions/extension-list.d.ts +1 -0
  105. package/dist/types/overlays/history-search.d.ts +18 -0
  106. package/dist/types/overlays/hook-editor.d.ts +28 -1
  107. package/dist/types/overlays/hook-input.d.ts +3 -0
  108. package/dist/types/overlays/hook-selector.d.ts +10 -0
  109. package/dist/types/overlays/hub-frame.d.ts +18 -0
  110. package/dist/types/overlays/jobs-panel.d.ts +24 -0
  111. package/dist/types/overlays/login-dialog.d.ts +10 -0
  112. package/dist/types/overlays/logout-account-selector.d.ts +4 -0
  113. package/dist/types/overlays/mcp-add-wizard.d.ts +4 -0
  114. package/dist/types/overlays/model-browser.d.ts +69 -0
  115. package/dist/types/overlays/model-hub.d.ts +7 -0
  116. package/dist/types/overlays/model-picker.d.ts +9 -1
  117. package/dist/types/overlays/move-overlay.d.ts +3 -0
  118. package/dist/types/overlays/oauth-selector.d.ts +4 -0
  119. package/dist/types/overlays/omfg-panel.d.ts +3 -0
  120. package/dist/types/overlays/pause-screen.d.ts +12 -0
  121. package/dist/types/overlays/plan-review-overlay.d.ts +5 -0
  122. package/dist/types/overlays/plan-save-overlay.d.ts +10 -0
  123. package/dist/types/overlays/plugin-selector.d.ts +4 -0
  124. package/dist/types/overlays/plugin-settings.d.ts +30 -0
  125. package/dist/types/overlays/queue-mode-selector.d.ts +4 -0
  126. package/dist/types/overlays/reset-usage-selector.d.ts +8 -0
  127. package/dist/types/overlays/rewind-selector.d.ts +5 -0
  128. package/dist/types/overlays/session-info-overlay.d.ts +19 -1
  129. package/dist/types/overlays/session-selector.d.ts +64 -1
  130. package/dist/types/overlays/settings-defs.d.ts +14 -0
  131. package/dist/types/overlays/settings-selector.d.ts +21 -0
  132. package/dist/types/overlays/show-images-selector.d.ts +4 -0
  133. package/dist/types/overlays/snapcompact-shape-preview.d.ts +2 -0
  134. package/dist/types/overlays/stats-notice.d.ts +8 -0
  135. package/dist/types/overlays/theme-selector.d.ts +11 -0
  136. package/dist/types/overlays/thinking-selector.d.ts +4 -0
  137. package/dist/types/overlays/tree-selector.d.ts +60 -2
  138. package/dist/types/overlays/usage-dashboard.d.ts +26 -3
  139. package/dist/types/overlays/usage-row.d.ts +36 -2
  140. package/dist/types/prompt/attachment-chips.d.ts +8 -0
  141. package/dist/types/prompt/composer-attachments.d.ts +15 -3
  142. package/dist/types/prompt/composer.d.ts +18 -1
  143. package/dist/types/prompt/custom-editor.d.ts +48 -2
  144. package/dist/types/prompt/editor-top-gap.d.ts +2 -0
  145. package/dist/types/prompt/macos-spelling.d.ts +6 -0
  146. package/dist/types/prompt/magic-keywords.d.ts +9 -0
  147. package/dist/types/prompt/queued-messages.d.ts +23 -0
  148. package/dist/types/prompt/skill-tokens.d.ts +4 -2
  149. package/dist/types/prompt/welcome.d.ts +16 -0
  150. package/dist/types/render/code-cell.d.ts +10 -0
  151. package/dist/types/render/file-list.d.ts +8 -0
  152. package/dist/types/render/hyperlink.d.ts +14 -0
  153. package/dist/types/render/output-block.d.ts +43 -0
  154. package/dist/types/render/output-pane.d.ts +17 -0
  155. package/dist/types/render/tool-card.d.ts +8 -0
  156. package/dist/types/render/tree-list.d.ts +8 -0
  157. package/dist/types/render/width-aware-text.d.ts +7 -0
  158. package/dist/types/setup/scenes/outro.d.ts +7 -0
  159. package/dist/types/setup/scenes/sign-in.d.ts +16 -9
  160. package/dist/types/setup/scenes/splash.d.ts +8 -0
  161. package/dist/types/setup/scenes/types.d.ts +6 -27
  162. package/dist/types/setup/wizard-overlay.d.ts +9 -0
  163. package/dist/types/status-line/component.d.ts +49 -5
  164. package/dist/types/status-line/context-usage.d.ts +20 -0
  165. package/dist/types/status-line/footer.d.ts +8 -0
  166. package/dist/types/status-line/metrics.d.ts +1 -2
  167. package/dist/types/status-line/segments.d.ts +10 -1
  168. package/dist/types/status-line/types.d.ts +40 -1
  169. package/dist/types/stdin-buffer.d.ts +10 -7
  170. package/dist/types/terminal-capabilities.d.ts +1 -1
  171. package/dist/types/terminal.d.ts +36 -0
  172. package/dist/types/theme/defaults/index.d.ts +100 -0
  173. package/dist/types/theme/schema.d.ts +2 -0
  174. package/dist/types/theme/shimmer.d.ts +8 -0
  175. package/dist/types/theme/theme-class.d.ts +2 -0
  176. package/dist/types/theme/theme.d.ts +33 -1
  177. package/dist/types/tools/ask.d.ts +3 -0
  178. package/dist/types/tools/ast-edit.d.ts +10 -1
  179. package/dist/types/tools/ast-grep.d.ts +10 -1
  180. package/dist/types/tools/autoresearch.d.ts +21 -4
  181. package/dist/types/tools/bash.d.ts +30 -1
  182. package/dist/types/tools/cfg-render.d.ts +5 -1
  183. package/dist/types/tools/debug.d.ts +3 -1
  184. package/dist/types/tools/default-renderer.d.ts +6 -1
  185. package/dist/types/tools/edit.d.ts +14 -1
  186. package/dist/types/tools/eval.d.ts +12 -1
  187. package/dist/types/tools/fetch.d.ts +16 -1
  188. package/dist/types/tools/find.d.ts +15 -1
  189. package/dist/types/tools/github.d.ts +3 -0
  190. package/dist/types/tools/glob.d.ts +14 -1
  191. package/dist/types/tools/goal.d.ts +3 -1
  192. package/dist/types/tools/grep.d.ts +14 -1
  193. package/dist/types/tools/grouped-file-output.d.ts +58 -0
  194. package/dist/types/tools/json-tree.d.ts +20 -0
  195. package/dist/types/tools/lsp.d.ts +3 -10
  196. package/dist/types/tools/mcp.d.ts +16 -1
  197. package/dist/types/tools/memory.d.ts +26 -0
  198. package/dist/types/tools/native-view.d.ts +90 -0
  199. package/dist/types/tools/proc-render.d.ts +7 -1
  200. package/dist/types/tools/read.d.ts +23 -1
  201. package/dist/types/tools/renderer.d.ts +57 -0
  202. package/dist/types/tools/report-tool-issue.d.ts +3 -0
  203. package/dist/types/tools/resolve.d.ts +14 -1
  204. package/dist/types/tools/task.d.ts +3 -0
  205. package/dist/types/tools/think.d.ts +3 -0
  206. package/dist/types/tools/todo.d.ts +12 -0
  207. package/dist/types/tools/vibe.d.ts +3 -1
  208. package/dist/types/tools/wait.d.ts +3 -0
  209. package/dist/types/tools/web-search-types.d.ts +90 -0
  210. package/dist/types/tools/web-search.d.ts +9 -168
  211. package/dist/types/tools/write.d.ts +14 -1
  212. package/dist/types/tools/xdev.d.ts +13 -0
  213. package/dist/types/tui.d.ts +49 -0
  214. package/package.json +9 -9
  215. package/src/apps/autoresearch-dashboard.ts +362 -4
  216. package/src/apps/cleanse-board.ts +219 -1
  217. package/src/apps/cleanse-picker.ts +9 -1
  218. package/src/apps/debug/log-viewer.ts +15 -15
  219. package/src/apps/debug/protocol-probe.ts +2 -20
  220. package/src/apps/git/avatar.ts +2 -22
  221. package/src/apps/git/git-tui.ts +406 -59
  222. package/src/apps/git/help.ts +130 -0
  223. package/src/apps/git/sidebar.ts +491 -0
  224. package/src/apps/live-visualizer.ts +65 -0
  225. package/src/apps/ps-top.ts +448 -17
  226. package/src/apps/session-picker.ts +1 -0
  227. package/src/apps/setup-model-picker.ts +5 -1
  228. package/src/apps/standalone-picker.ts +55 -1
  229. package/src/autocomplete.ts +44 -1
  230. package/src/chat/advisor-message.ts +72 -3
  231. package/src/chat/assistant-message.ts +538 -51
  232. package/src/chat/background-tan-message.ts +4 -4
  233. package/src/chat/bash-execution.ts +81 -0
  234. package/src/chat/cache-invalidation-marker.ts +8 -0
  235. package/src/chat/chat-transcript-builder.ts +37 -6
  236. package/src/chat/collab-prompt-message.ts +15 -3
  237. package/src/chat/compaction-summary-message.ts +74 -1
  238. package/src/chat/custom-message.ts +3 -1
  239. package/src/chat/eval-execution.ts +57 -0
  240. package/src/chat/execution-shared.ts +153 -1
  241. package/src/chat/hook-message.ts +1 -0
  242. package/src/chat/late-diagnostics-message.ts +85 -2
  243. package/src/chat/read-tool-group.ts +341 -1
  244. package/src/chat/served-model-marker.ts +8 -0
  245. package/src/chat/skill-message.ts +63 -0
  246. package/src/chat/stripped-tool-calls-placeholder.ts +18 -10
  247. package/src/chat/thinking-display.ts +73 -11
  248. package/src/chat/todo-reminder.ts +34 -4
  249. package/src/chat/tool-execution.ts +385 -10
  250. package/src/chat/transcript-actions.ts +38 -0
  251. package/src/chat/transcript-browser.ts +2 -9
  252. package/src/chat/transcript-entry.ts +10 -1
  253. package/src/chat/transcript-render-helpers.ts +16 -15
  254. package/src/chat/ttsr-notification.ts +38 -1
  255. package/src/chat/user-message.ts +167 -4
  256. package/src/chrome/collab-qrcode.ts +27 -2
  257. package/src/chrome/context-thresholds.ts +34 -0
  258. package/src/chrome/countdown-timer.ts +24 -1
  259. package/src/chrome/diff.ts +60 -1
  260. package/src/chrome/dynamic-border.ts +7 -0
  261. package/src/chrome/format.ts +12 -0
  262. package/src/chrome/message-divider.ts +33 -1
  263. package/src/chrome/message-frame.ts +53 -10
  264. package/src/chrome/message-notice.ts +71 -0
  265. package/src/chrome/overlay-box.ts +45 -2
  266. package/src/chrome/qrcode.ts +28 -0
  267. package/src/chrome/segment-track.ts +26 -0
  268. package/src/chrome/selector-helpers.ts +1 -17
  269. package/src/chrome/status-notice.ts +46 -0
  270. package/src/chrome/streaming-panel.ts +25 -1
  271. package/src/chrome/tool-activity.ts +20 -0
  272. package/src/chrome/transcript-container.ts +139 -17
  273. package/src/chrome/transcript-status.ts +40 -11
  274. package/src/components/box.ts +51 -0
  275. package/src/components/disclosure.ts +33 -0
  276. package/src/components/editor.ts +239 -36
  277. package/src/components/form.ts +93 -9
  278. package/src/components/image.ts +30 -0
  279. package/src/components/input.ts +77 -26
  280. package/src/components/key-value-list.ts +18 -0
  281. package/src/components/layout/geometry.ts +44 -0
  282. package/src/components/layout/row.ts +30 -0
  283. package/src/components/layout/split-pane.ts +65 -0
  284. package/src/components/layout/stack.ts +27 -0
  285. package/src/components/loader.ts +183 -1
  286. package/src/components/markdown.ts +131 -56
  287. package/src/components/metric.ts +39 -0
  288. package/src/components/progress-bar.ts +28 -0
  289. package/src/components/scroll-view.ts +23 -0
  290. package/src/components/section.ts +16 -0
  291. package/src/components/select-list.ts +174 -25
  292. package/src/components/settings-list.ts +264 -7
  293. package/src/components/spacer.ts +17 -0
  294. package/src/components/tab-bar.ts +42 -0
  295. package/src/components/table.ts +34 -0
  296. package/src/components/text.ts +23 -0
  297. package/src/components/tree-view.ts +65 -0
  298. package/src/components/truncated-text.ts +14 -0
  299. package/src/components/wizard-step.ts +18 -9
  300. package/src/debug-server.ts +14 -7
  301. package/src/hotkeys-markdown.ts +251 -69
  302. package/src/index.ts +6 -0
  303. package/src/latex-block.ts +11 -0
  304. package/src/loop-watchdog.ts +38 -10
  305. package/src/native/apply.ts +275 -0
  306. package/src/native/backend.ts +682 -0
  307. package/src/native/blobs.ts +70 -0
  308. package/src/native/describe.ts +124 -0
  309. package/src/native/encode.ts +233 -0
  310. package/src/native/icons.ts +184 -0
  311. package/src/native/memo.ts +64 -0
  312. package/src/native/node.ts +112 -0
  313. package/src/native/overlay.ts +131 -0
  314. package/src/native/picker.ts +333 -0
  315. package/src/native/reconcile.ts +1063 -0
  316. package/src/native/settle.ts +23 -0
  317. package/src/native/spans.ts +308 -0
  318. package/src/native/state.ts +28 -0
  319. package/src/native/tone.ts +79 -0
  320. package/src/overlays/advisor-config.ts +420 -0
  321. package/src/overlays/agent-hub-renderer.ts +155 -18
  322. package/src/overlays/agent-hub.ts +1037 -44
  323. package/src/overlays/agent-transcript-viewer.ts +129 -0
  324. package/src/overlays/agents-hub.ts +688 -53
  325. package/src/overlays/annotation-overlay.ts +391 -52
  326. package/src/overlays/ask-dialog.ts +435 -24
  327. package/src/overlays/bordered-loader.ts +17 -0
  328. package/src/overlays/btw-history-panel.ts +182 -0
  329. package/src/overlays/btw-panel.ts +68 -2
  330. package/src/overlays/cleanse-panel.ts +105 -15
  331. package/src/overlays/codex-reset-fireworks.ts +65 -5
  332. package/src/overlays/composer-shape-preview.ts +26 -1
  333. package/src/overlays/copy-selector.ts +545 -23
  334. package/src/overlays/error-banner.ts +44 -0
  335. package/src/overlays/extensions/extension-list.ts +23 -17
  336. package/src/overlays/history-search.ts +175 -33
  337. package/src/overlays/hook-editor.ts +113 -6
  338. package/src/overlays/hook-input.ts +22 -1
  339. package/src/overlays/hook-selector.ts +311 -22
  340. package/src/overlays/hub-frame.ts +80 -0
  341. package/src/overlays/jobs-panel.ts +112 -0
  342. package/src/overlays/login-dialog.ts +183 -1
  343. package/src/overlays/logout-account-selector.ts +102 -4
  344. package/src/overlays/mcp-add-wizard.ts +232 -53
  345. package/src/overlays/model-browser.ts +681 -22
  346. package/src/overlays/model-hub.ts +1402 -78
  347. package/src/overlays/model-picker.ts +184 -7
  348. package/src/overlays/move-overlay.ts +45 -0
  349. package/src/overlays/oauth-selector.ts +227 -23
  350. package/src/overlays/omfg-panel.ts +86 -2
  351. package/src/overlays/pause-screen.ts +55 -4
  352. package/src/overlays/plan-review-overlay.ts +352 -0
  353. package/src/overlays/plan-save-overlay.ts +45 -0
  354. package/src/overlays/plugin-selector.ts +21 -1
  355. package/src/overlays/plugin-settings.ts +195 -5
  356. package/src/overlays/queue-mode-selector.ts +19 -1
  357. package/src/overlays/reset-usage-selector.ts +110 -40
  358. package/src/overlays/rewind-selector.ts +458 -44
  359. package/src/overlays/session-account-selector.ts +1 -1
  360. package/src/overlays/session-info-overlay.ts +137 -1
  361. package/src/overlays/session-selector.ts +807 -46
  362. package/src/overlays/settings-defs.ts +41 -0
  363. package/src/overlays/settings-selector.ts +585 -33
  364. package/src/overlays/show-images-selector.ts +18 -1
  365. package/src/overlays/snapcompact-shape-preview.ts +48 -3
  366. package/src/overlays/stats-notice.ts +31 -0
  367. package/src/overlays/theme-selector.ts +31 -1
  368. package/src/overlays/thinking-selector.ts +22 -1
  369. package/src/overlays/tree-selector.ts +570 -110
  370. package/src/overlays/usage-dashboard.ts +587 -12
  371. package/src/overlays/usage-row.ts +161 -25
  372. package/src/prompt/attachment-chips.ts +60 -0
  373. package/src/prompt/composer-attachments.ts +31 -9
  374. package/src/prompt/composer.ts +55 -2
  375. package/src/prompt/custom-editor.ts +302 -4
  376. package/src/prompt/editor-top-gap.ts +8 -0
  377. package/src/prompt/macos-spelling.ts +24 -9
  378. package/src/prompt/magic-keywords.ts +22 -1
  379. package/src/prompt/model-mention-autocomplete.ts +1 -0
  380. package/src/prompt/queued-messages.ts +101 -0
  381. package/src/prompt/skill-tokens.ts +5 -3
  382. package/src/prompt/welcome.ts +213 -6
  383. package/src/render/code-cell.ts +103 -2
  384. package/src/render/file-list.ts +29 -0
  385. package/src/render/hyperlink.ts +32 -0
  386. package/src/render/output-block.ts +110 -0
  387. package/src/render/output-pane.ts +37 -0
  388. package/src/render/tool-card.ts +137 -0
  389. package/src/render/tree-list.ts +39 -0
  390. package/src/render/width-aware-text.ts +20 -0
  391. package/src/setup/scenes/composer.ts +29 -0
  392. package/src/setup/scenes/glyph.ts +15 -0
  393. package/src/setup/scenes/model.ts +36 -8
  394. package/src/setup/scenes/outro.ts +28 -1
  395. package/src/setup/scenes/sign-in.ts +138 -24
  396. package/src/setup/scenes/splash.ts +28 -1
  397. package/src/setup/scenes/theme.ts +88 -3
  398. package/src/setup/scenes/types.ts +7 -28
  399. package/src/setup/startup-splash.ts +46 -9
  400. package/src/setup/wizard-overlay.ts +140 -23
  401. package/src/setup/wizard.ts +1 -1
  402. package/src/status-line/component.ts +414 -18
  403. package/src/status-line/context-usage.ts +279 -50
  404. package/src/status-line/footer.ts +94 -1
  405. package/src/status-line/metrics.ts +3 -6
  406. package/src/status-line/segments.ts +463 -97
  407. package/src/status-line/separators.ts +3 -16
  408. package/src/status-line/types.ts +43 -1
  409. package/src/stdin-buffer.ts +27 -21
  410. package/src/terminal-capabilities.ts +7 -0
  411. package/src/terminal.ts +153 -11
  412. package/src/theme/defaults/dark-neon-noir.json +100 -0
  413. package/src/theme/defaults/index.ts +2 -0
  414. package/src/theme/defaults/light-prism.json +5 -5
  415. package/src/theme/defaults/onyx.json +62 -62
  416. package/src/theme/mermaid-cache.ts +10 -1
  417. package/src/theme/schema.ts +15 -0
  418. package/src/theme/shimmer.ts +33 -0
  419. package/src/theme/theme-class.ts +24 -19
  420. package/src/theme/theme.ts +111 -9
  421. package/src/theme/tui-adapters.ts +14 -1
  422. package/src/tools/ask.ts +157 -1
  423. package/src/tools/ast-edit.ts +174 -1
  424. package/src/tools/ast-grep.ts +82 -2
  425. package/src/tools/autoresearch.ts +149 -1
  426. package/src/tools/bash.ts +233 -62
  427. package/src/tools/cfg-render.ts +66 -1
  428. package/src/tools/debug.ts +78 -1
  429. package/src/tools/default-renderer.ts +35 -1
  430. package/src/tools/edit.ts +357 -31
  431. package/src/tools/eval.ts +257 -1
  432. package/src/tools/fetch.ts +102 -3
  433. package/src/tools/find.ts +127 -1
  434. package/src/tools/github.ts +119 -10
  435. package/src/tools/glob.ts +116 -1
  436. package/src/tools/goal.ts +56 -1
  437. package/src/tools/grep.ts +83 -2
  438. package/src/tools/grouped-file-output.ts +205 -0
  439. package/src/tools/json-tree.ts +116 -1
  440. package/src/tools/lsp.ts +318 -1
  441. package/src/tools/mcp.ts +80 -1
  442. package/src/tools/memory.ts +93 -11
  443. package/src/tools/native-view.ts +292 -0
  444. package/src/tools/proc-render.ts +221 -1
  445. package/src/tools/read.ts +199 -4
  446. package/src/tools/renderer.ts +61 -0
  447. package/src/tools/report-tool-issue.ts +7 -1
  448. package/src/tools/resolve.ts +63 -1
  449. package/src/tools/streaming-output.ts +79 -16
  450. package/src/tools/task.ts +406 -4
  451. package/src/tools/think.ts +19 -1
  452. package/src/tools/todo.ts +89 -0
  453. package/src/tools/vibe.ts +230 -2
  454. package/src/tools/wait.ts +181 -1
  455. package/src/tools/web-search-types.ts +99 -0
  456. package/src/tools/web-search.ts +111 -170
  457. package/src/tools/write.ts +144 -5
  458. package/src/tools/xdev.ts +64 -1
  459. package/src/tui.ts +295 -4
  460. package/dist/types/setup/scenes/providers.d.ts +0 -3
  461. package/dist/types/setup/scenes/web-search.d.ts +0 -22
  462. package/src/setup/scenes/providers.ts +0 -110
  463. package/src/setup/scenes/web-search.ts +0 -165
@@ -16,76 +16,76 @@
16
16
  "emerald": "#6fb37f"
17
17
  },
18
18
  "colors": {
19
- "accent": "$vein",
20
- "border": "$band2",
21
- "borderAccent": "$vein",
22
- "borderMuted": "$band1",
23
- "success": "$emerald",
24
- "error": "$ruby",
25
- "warning": "$bronze",
26
- "muted": "$warmGray",
19
+ "accent": "vein",
20
+ "border": "band2",
21
+ "borderAccent": "vein",
22
+ "borderMuted": "band1",
23
+ "success": "emerald",
24
+ "error": "ruby",
25
+ "warning": "bronze",
26
+ "muted": "warmGray",
27
27
  "dim": "#6a6760",
28
28
  "text": "",
29
- "thinkingText": "$warmGray",
30
- "selectedBg": "$band2",
31
- "userMessageBg": "$band1",
29
+ "thinkingText": "warmGray",
30
+ "selectedBg": "band2",
31
+ "userMessageBg": "band1",
32
32
  "userMessageText": "",
33
- "customMessageBg": "$band2",
33
+ "customMessageBg": "band2",
34
34
  "customMessageText": "",
35
- "customMessageLabel": "$vein",
36
- "toolPendingBg": "$band1",
37
- "toolSuccessBg": "$band1",
38
- "toolErrorBg": "$band1",
35
+ "customMessageLabel": "vein",
36
+ "toolPendingBg": "band1",
37
+ "toolSuccessBg": "band1",
38
+ "toolErrorBg": "band1",
39
39
  "toolTitle": "",
40
- "toolOutput": "$warmGray",
41
- "mdHeading": "$vein",
42
- "mdLink": "$bronze",
43
- "mdLinkUrl": "$copper",
44
- "mdCode": "$vein",
45
- "mdCodeBlock": "$cream",
46
- "mdCodeBlockBorder": "$band3",
47
- "mdQuote": "$warmGray",
48
- "mdQuoteBorder": "$veinDim",
49
- "mdHr": "$band2",
50
- "mdListBullet": "$vein",
51
- "toolDiffAdded": "$emerald",
52
- "toolDiffRemoved": "$ruby",
53
- "toolDiffContext": "$warmGray",
40
+ "toolOutput": "warmGray",
41
+ "mdHeading": "vein",
42
+ "mdLink": "bronze",
43
+ "mdLinkUrl": "copper",
44
+ "mdCode": "vein",
45
+ "mdCodeBlock": "cream",
46
+ "mdCodeBlockBorder": "band3",
47
+ "mdQuote": "warmGray",
48
+ "mdQuoteBorder": "veinDim",
49
+ "mdHr": "band2",
50
+ "mdListBullet": "vein",
51
+ "toolDiffAdded": "emerald",
52
+ "toolDiffRemoved": "ruby",
53
+ "toolDiffContext": "warmGray",
54
54
  "syntaxComment": "#6a6760",
55
- "syntaxKeyword": "$vein",
56
- "syntaxFunction": "$bronze",
57
- "syntaxVariable": "$cream",
58
- "syntaxString": "$copper",
59
- "syntaxNumber": "$veinDim",
60
- "syntaxType": "$vein",
61
- "syntaxOperator": "$warmGray",
62
- "syntaxPunctuation": "$warmGray",
63
- "thinkingOff": "$warmGray",
64
- "thinkingMinimal": "$warmGray",
65
- "thinkingLow": "$warmGray",
66
- "thinkingMedium": "$veinDim",
67
- "thinkingHigh": "$vein",
68
- "thinkingXhigh": "$bronze",
69
- "bashMode": "$vein",
70
- "statusLineBg": "$band1",
71
- "statusLineSep": "$band3",
72
- "statusLineModel": "$vein",
73
- "statusLinePath": "$cream",
74
- "statusLineGitClean": "$emerald",
75
- "statusLineGitDirty": "$bronze",
76
- "statusLineContext": "$warmGray",
77
- "statusLineSpend": "$copper",
78
- "statusLineStaged": "$emerald",
79
- "statusLineDirty": "$bronze",
80
- "statusLineUntracked": "$warmGray",
81
- "statusLineOutput": "$cream",
82
- "statusLineCost": "$copper",
83
- "statusLineSubagents": "$vein",
55
+ "syntaxKeyword": "vein",
56
+ "syntaxFunction": "bronze",
57
+ "syntaxVariable": "cream",
58
+ "syntaxString": "copper",
59
+ "syntaxNumber": "veinDim",
60
+ "syntaxType": "vein",
61
+ "syntaxOperator": "warmGray",
62
+ "syntaxPunctuation": "warmGray",
63
+ "thinkingOff": "warmGray",
64
+ "thinkingMinimal": "warmGray",
65
+ "thinkingLow": "warmGray",
66
+ "thinkingMedium": "veinDim",
67
+ "thinkingHigh": "vein",
68
+ "thinkingXhigh": "bronze",
69
+ "bashMode": "vein",
70
+ "statusLineBg": "band1",
71
+ "statusLineSep": "band3",
72
+ "statusLineModel": "vein",
73
+ "statusLinePath": "cream",
74
+ "statusLineGitClean": "emerald",
75
+ "statusLineGitDirty": "bronze",
76
+ "statusLineContext": "warmGray",
77
+ "statusLineSpend": "copper",
78
+ "statusLineStaged": "emerald",
79
+ "statusLineDirty": "bronze",
80
+ "statusLineUntracked": "warmGray",
81
+ "statusLineOutput": "cream",
82
+ "statusLineCost": "copper",
83
+ "statusLineSubagents": "vein",
84
84
  "pythonMode": "#f0c040"
85
85
  },
86
86
  "export": {
87
- "pageBg": "$stone",
88
- "cardBg": "$band1",
89
- "infoBg": "$band2"
87
+ "pageBg": "stone",
88
+ "cardBg": "band1",
89
+ "infoBg": "band2"
90
90
  }
91
91
  }
@@ -1,4 +1,5 @@
1
1
  import type { MermaidRenderOptions } from "@oh-my-pi/pi-natives";
2
+ import { LRUCache } from "@oh-my-pi/pi-utils/lru";
2
3
  import * as mermaidAscii from "@oh-my-pi/pi-utils/mermaid-ascii";
3
4
 
4
5
  /**
@@ -19,7 +20,15 @@ export interface MermaidResolveOptions extends MermaidRenderOptions {
19
20
  // Memoizes rendered ASCII (and failures) keyed on the render options + the
20
21
  // layout-direction variant + source. Width selection happens per call against
21
22
  // the cached renders, so a terminal resize re-decides without re-rendering.
22
- const cache = new Map<string, string | null>();
23
+ // Bounded by entry count and by UTF-16 length of key (which embeds the whole
24
+ // source) plus rendered ASCII, so long sessions cannot pin every diagram.
25
+ const MERMAID_CACHE_MAX = 256;
26
+ const MERMAID_CACHE_MAX_SIZE = 4 * 1024 * 1024;
27
+ const cache = new LRUCache<string, string | null>({
28
+ max: MERMAID_CACHE_MAX,
29
+ maxSize: MERMAID_CACHE_MAX_SIZE,
30
+ sizeCalculation: (ascii, key) => key.length + (ascii?.length ?? 0),
31
+ });
23
32
 
24
33
  /** Display columns, ignoring ANSI so themed diagrams are measured as drawn. */
25
34
  const DISPLAY_WIDTH = { countAnsiEscapeCodes: false } as const;
@@ -165,4 +165,19 @@ export type ThemeBg =
165
165
  | "toolErrorBg"
166
166
  | "statusLineBg";
167
167
 
168
+ const VALID_THEME_BGS: ReadonlySet<string> = new Set([
169
+ "selectedBg",
170
+ "userMessageBg",
171
+ "customMessageBg",
172
+ "toolPendingBg",
173
+ "toolSuccessBg",
174
+ "toolErrorBg",
175
+ "statusLineBg",
176
+ ] satisfies ThemeBg[]);
177
+
178
+ /** Check if a string is a valid ThemeBg value */
179
+ export function isValidThemeBg(color: string): color is ThemeBg {
180
+ return VALID_THEME_BGS.has(color);
181
+ }
182
+
168
183
  export type ColorMode = "truecolor" | "256color";
@@ -1,3 +1,7 @@
1
+ import type { TspSpan } from "@oh-my-pi/pi-wire";
2
+ import { node } from "../native/describe";
3
+ import type { NativeNode } from "../native/node";
4
+ import { isNativeRendering } from "../native/state";
1
5
  import type { Theme, ThemeColor } from "./theme";
2
6
  import { FG_RESET } from "./color";
3
7
 
@@ -151,6 +155,28 @@ export function shimmerEnabled(): boolean {
151
155
  return activeMode !== "disabled";
152
156
  }
153
157
 
158
+ /**
159
+ * Describe shimmering segments for a TSP terminal, which clocks the sweep
160
+ * itself: a `shimmer` node in the active mode, or plain spans in the mid tier
161
+ * color when shimmer is disabled. Palette tiers given as theme colors travel as
162
+ * token names; raw-ANSI tiers are dropped (the terminal's theme decides).
163
+ */
164
+ export function describeShimmer(segments: readonly ShimmerSegment[], key?: string): NativeNode {
165
+ const spans: TspSpan[] = [];
166
+ for (const { text: value, palette } of segments) {
167
+ if (value.length === 0) continue;
168
+ const mid = (palette ?? DEFAULT_SHIMMER_PALETTE).mid;
169
+ spans.push(typeof mid === "string" ? { t: value, s: mid } : { t: value });
170
+ }
171
+ if (activeMode === "disabled") return node("text", { spans }, undefined, key);
172
+ const palette = segments[0]?.palette ?? DEFAULT_SHIMMER_PALETTE;
173
+ const tokens: { low?: string; mid?: string; high?: string } = {};
174
+ if (typeof palette.low === "string") tokens.low = palette.low;
175
+ if (typeof palette.mid === "string") tokens.mid = palette.mid;
176
+ if (typeof palette.high === "string") tokens.high = palette.high;
177
+ return node("shimmer", { spans, mode: activeMode, palette: tokens }, undefined, key);
178
+ }
179
+
154
180
  /**
155
181
  * Apply a shimmer sweep across one or more segments, treating them as a
156
182
  * single continuous string for band positioning. Each segment can supply
@@ -165,6 +191,13 @@ export function shimmerEnabled(): boolean {
165
191
  * - No per-char allocations beyond the run buffer.
166
192
  */
167
193
  export function shimmerSegments(segments: readonly ShimmerSegment[], theme: ShimmerTheme): string {
194
+ // A TSP terminal animates shimmer from described nodes; a frame painted
195
+ // here would freeze mid-sweep, so the text goes out unstyled.
196
+ if (isNativeRendering()) {
197
+ let out = "";
198
+ for (const { text: value } of segments) out += value;
199
+ return out;
200
+ }
168
201
  const mode = activeMode;
169
202
 
170
203
  // Disabled: no animation or code-point scan. Preserve the all-empty result,
@@ -140,6 +140,26 @@ const underlineStyler = chalk.underline;
140
140
  const strikethroughStyler = chalk.strikethrough;
141
141
  const inverseStyler = chalk.inverse;
142
142
 
143
+ /** Theme token of a thinking/effort level name (`off`…`max`); unknown levels (`auto`) map to `thinkingOff`. */
144
+ export function thinkingLevelToken(level: string): ThemeColor {
145
+ switch (level) {
146
+ case "minimal":
147
+ return "thinkingMinimal";
148
+ case "low":
149
+ return "thinkingLow";
150
+ case "medium":
151
+ return "thinkingMedium";
152
+ case "high":
153
+ return "thinkingHigh";
154
+ case "xhigh":
155
+ return "thinkingXhigh";
156
+ case "max":
157
+ return "thinkingMax";
158
+ default:
159
+ return "thinkingOff";
160
+ }
161
+ }
162
+
143
163
  export class Theme {
144
164
  #fgColors: Record<ThemeColor, string>;
145
165
  #bgColors: Record<ThemeBg, string>;
@@ -419,25 +439,10 @@ export class Theme {
419
439
 
420
440
  /** Border color for a thinking/effort level name (`off`…`max`); unknown levels fall back to `thinkingOff`. */
421
441
  getThinkingBorderColor(level: string): (str: string) => string {
422
- switch (level) {
423
- case "off":
424
- return (str: string) => this.fg("thinkingOff", str);
425
- case "minimal":
426
- return (str: string) => this.fg("thinkingMinimal", str);
427
- case "low":
428
- return (str: string) => this.fg("thinkingLow", str);
429
- case "medium":
430
- return (str: string) => this.fg("thinkingMedium", str);
431
- case "high":
432
- return (str: string) => this.fg("thinkingHigh", str);
433
- case "xhigh":
434
- return (str: string) => this.fg("thinkingXhigh", str);
435
- case "max":
436
- // thinkingMax is optional; themes without it resolve to the xhigh color.
437
- return (str: string) => this.fg(this.#fgColors.thinkingMax ? "thinkingMax" : "thinkingXhigh", str);
438
- default:
439
- return (str: string) => this.fg("thinkingOff", str);
440
- }
442
+ const token = thinkingLevelToken(level);
443
+ // thinkingMax is optional; themes without it resolve to the xhigh color.
444
+ const color = token === "thinkingMax" && !this.#fgColors.thinkingMax ? "thinkingXhigh" : token;
445
+ return (str: string) => this.fg(color, str);
441
446
  }
442
447
 
443
448
  getBashModeBorderColor(): (str: string) => string {
@@ -7,8 +7,16 @@ import { getCustomThemesDir } from "@oh-my-pi/pi-utils/dirs";
7
7
  import * as logger from "@oh-my-pi/pi-utils/logger";
8
8
  import { setActiveSymbolTheme } from "./active-symbols";
9
9
  import { ansi256ToHex, resolveThemeColors, resolveVarRefs } from "./color";
10
- import { type CreateThemeOptions, getBuiltinThemes, loadTheme, loadThemeJson, loadThemeSync } from "./loader";
11
- import type { ThemeColor, ThemeJson } from "./schema";
10
+ import {
11
+ type CreateThemeOptions,
12
+ createTheme,
13
+ getBuiltinThemes,
14
+ loadTheme,
15
+ loadThemeJson,
16
+ loadThemeJsonSync,
17
+ loadThemeSync,
18
+ } from "./loader";
19
+ import { isValidThemeBg, isValidThemeColor, type ThemeColor, type ThemeJson } from "./schema";
12
20
  import type { SymbolPreset } from "./symbols";
13
21
  import type { Theme } from "./theme-class";
14
22
 
@@ -84,6 +92,8 @@ function getDefaultTheme(): string {
84
92
  /** Active theme; imports remain live across initialization, previews, and theme switches. */
85
93
  export var theme: Theme;
86
94
  var currentThemeName: string | undefined;
95
+ /** Theme shown by `previewTheme` until the next non-preview assignment. */
96
+ var previewThemeName: string | undefined;
87
97
 
88
98
  type ThemeBinding = (value: Theme) => void;
89
99
  var themeBindings: Set<ThemeBinding> | undefined;
@@ -98,8 +108,10 @@ export function bindTheme(binding: ThemeBinding): () => void {
98
108
  };
99
109
  }
100
110
 
101
- function assignTheme(value: Theme): void {
111
+ /** `previewName` marks a theme-selector preview; any other assignment ends it. */
112
+ function assignTheme(value: Theme, previewName?: string): void {
102
113
  theme = value;
114
+ previewThemeName = previewName;
103
115
  setActiveSymbolTheme(value);
104
116
  if (themeBindings) {
105
117
  for (const binding of themeBindings) binding(value);
@@ -121,6 +133,9 @@ export interface ThemeChangeEvent {
121
133
  }
122
134
 
123
135
  var currentSymbolPresetOverride: SymbolPreset | undefined;
136
+ // Process-local preset forced while a Tern Surface Protocol surface is live;
137
+ // wins over the user's preset and is never persisted.
138
+ var nativeSymbolPreset: SymbolPreset | undefined;
124
139
  var currentColorBlindMode: boolean = false;
125
140
  var themeWatcher: fs.FSWatcher | undefined;
126
141
  var themeReloadTimer: NodeJS.Timeout | undefined;
@@ -134,7 +149,7 @@ let themeEpoch = 0;
134
149
 
135
150
  function getCurrentThemeOptions(): CreateThemeOptions {
136
151
  return {
137
- symbolPresetOverride: currentSymbolPresetOverride,
152
+ symbolPresetOverride: nativeSymbolPreset ?? currentSymbolPresetOverride,
138
153
  colorBlindMode: currentColorBlindMode,
139
154
  };
140
155
  }
@@ -162,10 +177,7 @@ export function initThemeSync(
162
177
  lightTheme?: string,
163
178
  ): void {
164
179
  const name = configureTheme(symbolPreset, colorBlindMode, darkTheme, lightTheme);
165
- const options: CreateThemeOptions = {
166
- symbolPresetOverride: currentSymbolPresetOverride,
167
- colorBlindMode: currentColorBlindMode,
168
- };
180
+ const options = getCurrentThemeOptions();
169
181
  try {
170
182
  assignTheme(loadThemeSync(name, options));
171
183
  } catch (error) {
@@ -255,7 +267,8 @@ export async function previewTheme(
255
267
  if (requestId !== themeLoadRequestId) {
256
268
  return { success: false, error: "Theme preview superseded by a newer request" };
257
269
  }
258
- assignTheme(loadedTheme);
270
+ // Previewing the active theme again (selector cancel) ends the preview.
271
+ assignTheme(loadedTheme, name === currentThemeName ? undefined : name);
259
272
  notifyThemeChange(event);
260
273
  return { success: true };
261
274
  } catch (error) {
@@ -337,6 +350,30 @@ export function getSymbolPresetOverride(): SymbolPreset | undefined {
337
350
  return currentSymbolPresetOverride;
338
351
  }
339
352
 
353
+ /**
354
+ * Force `preset` while a Tern Surface Protocol surface is live (the terminal's
355
+ * font carries every Nerd Font glyph, so icons need no Glyph Protocol
356
+ * registration); `undefined` restores the user's preset. Process-local and
357
+ * never persisted. Rebuilds the active theme synchronously so the next frame
358
+ * already uses it, and notifies theme listeners like a preset change. Returns
359
+ * whether the active theme was rebuilt (callers invalidate render caches).
360
+ */
361
+ export function setNativeSymbolPreset(preset: SymbolPreset | undefined): boolean {
362
+ if (nativeSymbolPreset === preset) return false;
363
+ nativeSymbolPreset = preset;
364
+ if (!currentThemeName || typeof theme === "undefined") return false;
365
+ ++themeLoadRequestId;
366
+ try {
367
+ assignTheme(loadThemeSync(currentThemeName, getCurrentThemeOptions()));
368
+ } catch (error) {
369
+ // In-memory themes can't be rebuilt by name; they keep their symbols.
370
+ logger.debug("Native symbol preset: theme rebuild skipped", { theme: currentThemeName, error: String(error) });
371
+ return false;
372
+ }
373
+ notifyThemeChange({ ephemeral: true });
374
+ return true;
375
+ }
376
+
340
377
  /**
341
378
  * Set color blind mode, recreating the theme with the new setting.
342
379
  * When enabled, uses blue instead of green for diff additions.
@@ -770,6 +807,71 @@ export async function getResolvedThemeColors(themeName?: string): Promise<Record
770
807
  return cssColors;
771
808
  }
772
809
 
810
+ /** One appearance variant of {@link NativeThemePalette}: token name → `#rrggbb`. */
811
+ export type NativeThemeVariant = Record<string, string>;
812
+
813
+ /** omp's resolved theme for a Tern Surface Protocol terminal (the `t` verb body minus `sf`). */
814
+ export interface NativeThemePalette {
815
+ dark?: NativeThemeVariant;
816
+ light?: NativeThemeVariant;
817
+ name: { dark?: string; light?: string };
818
+ }
819
+
820
+ /**
821
+ * Cheap identity of everything {@link getNativeThemePalette} depends on;
822
+ * recompute the palette only when it changes.
823
+ */
824
+ export function getNativeThemePaletteKey(): string {
825
+ return `${themeEpoch}|${autoDetectedTheme}|${autoDarkTheme}|${autoLightTheme}|${currentThemeName}|${previewThemeName}|${currentColorBlindMode}`;
826
+ }
827
+
828
+ /** Every token of theme `name` as hex (terminal-default tokens omitted), plus its export colours. */
829
+ function nativeThemeVariant(name: string): { light: boolean; colors: NativeThemeVariant } {
830
+ const themeJson = loadThemeJsonSync(name);
831
+ const built = createTheme(themeJson, getCurrentThemeOptions());
832
+ const raw = resolveThemeColors(themeJson.colors, themeJson.vars);
833
+ const colors: NativeThemeVariant = {};
834
+ for (const key in raw) {
835
+ // Terminal-default tokens stay unset; keys outside the schema are ignored like the theme does.
836
+ if (raw[key as keyof typeof raw] === "") continue;
837
+ if (isValidThemeColor(key)) colors[key] = built.getColorHex(key);
838
+ else if (isValidThemeBg(key)) colors[key] = built.getBgHex(key);
839
+ }
840
+ const exported = resolveThemeExportColors(themeJson);
841
+ for (const key of ["pageBg", "cardBg", "infoBg"] as const) {
842
+ const value = exported[key];
843
+ if (value) colors[key] = value;
844
+ }
845
+ return { light: isLightThemeJson(themeJson), colors };
846
+ }
847
+
848
+ /**
849
+ * omp's theme for a native surface: with auto theme, the configured dark and
850
+ * light themes; otherwise (or while the theme selector previews one) the
851
+ * active theme under its own appearance only. Themes without a loadable
852
+ * definition (in-memory instances) contribute nothing.
853
+ */
854
+ export function getNativeThemePalette(): NativeThemePalette {
855
+ const palette: NativeThemePalette = { name: {} };
856
+ const add = (name: string, as?: "dark" | "light"): void => {
857
+ try {
858
+ const variant = nativeThemeVariant(name);
859
+ const slot = as ?? (variant.light ? "light" : "dark");
860
+ palette[slot] = variant.colors;
861
+ palette.name[slot] = name;
862
+ } catch (error) {
863
+ logger.debug("Native theme palette: theme not loadable", { name, error: String(error) });
864
+ }
865
+ };
866
+ const single = previewThemeName ?? (autoDetectedTheme ? undefined : currentThemeName);
867
+ if (single !== undefined) add(single);
868
+ else {
869
+ add(autoDarkTheme, "dark");
870
+ add(autoLightTheme, "light");
871
+ }
872
+ return palette;
873
+ }
874
+
773
875
  /**
774
876
  * Check if a theme is a "light" theme by analyzing its status-line background
775
877
  * luminance. Loads theme JSON synchronously (built-in or custom file on disk)
@@ -59,7 +59,20 @@ function getHighlightColors(t: Theme): NativeHighlightColors {
59
59
  * the 33ms frame budget and starving the spinner/render timers (the "TUI freeze").
60
60
  */
61
61
  const HIGHLIGHT_CACHE_MAX = 256;
62
- const highlightCache = new LRUCache<string, string>({ max: HIGHLIGHT_CACHE_MAX });
62
+ // Size-bound like markdown's render cache: a streaming block (bash command,
63
+ // eval cell) inserts one full `code + highlighted` pair per growth frame, so a
64
+ // count cap alone would retain 256 near-copies of a large payload. Sizes are
65
+ // UTF-16 code units of key + value (ANSI output runs several times the source
66
+ // length). The per-entry cap stays generous so a large but settled code body
67
+ // repainting every frame still hits; only payloads past it re-highlight.
68
+ const HIGHLIGHT_CACHE_MAX_SIZE = 8 * 1024 * 1024;
69
+ const HIGHLIGHT_CACHE_MAX_ENTRY_SIZE = 1024 * 1024;
70
+ const highlightCache = new LRUCache<string, string>({
71
+ max: HIGHLIGHT_CACHE_MAX,
72
+ maxSize: HIGHLIGHT_CACHE_MAX_SIZE,
73
+ maxEntrySize: HIGHLIGHT_CACHE_MAX_ENTRY_SIZE,
74
+ sizeCalculation: (value, key) => Math.max(1, key.length + value.length),
75
+ });
63
76
  let highlightCacheTheme: Theme | undefined;
64
77
 
65
78
  function highlightCached(code: string, validLang: string | undefined, highlightTheme: Theme): string | null {
package/src/tools/ask.ts CHANGED
@@ -1,4 +1,10 @@
1
- import type { ToolRenderer } from "./renderer";
1
+ import type { NativeToolHead, NativeToolView, ToolRenderer, ToolRenderResult } from "./renderer";
2
+ import type { TspSpan } from "@oh-my-pi/pi-wire";
3
+ import { compact, md, node, row, span, text } from "../native/describe";
4
+ import type { NativeChild, NativeNode } from "../native/node";
5
+ import { OwnerMemo } from "../native/memo";
6
+ import { plainText } from "../native/spans";
7
+ import { noteText, resultText } from "./native-view";
2
8
 
3
9
  import {
4
10
  type Component,
@@ -281,8 +287,158 @@ function renderAnswerOptionLines(
281
287
  return out;
282
288
  }
283
289
 
290
+ function askHead(question: string | undefined, meta?: string): NativeToolHead {
291
+ const first = question ? plainText(sanitizeCarriageReturns(question)).trim().split("\n")[0] : "";
292
+ return { title: "Ask", target: first || undefined, targetKind: "text", meta: meta ? [meta] : undefined };
293
+ }
294
+
295
+ /** One question of a multi-question result: the question as markdown over its answers. */
296
+ function describeQuestionSection(id: string, question: string, rest: readonly NativeChild[]): NativeNode {
297
+ return node("section", {}, [md(plainText(question)), ...rest], id);
298
+ }
299
+
300
+ /** An answer row: a success check before the chosen label, or a quiet unchosen label. */
301
+ function answerRow(key: string, label: TspSpan[], chosen: boolean): NativeNode {
302
+ return row(
303
+ compact([chosen ? node("icon", { name: "check", tone: "success" }) : undefined, text(label, { wrap: "word" })]),
304
+ { gap: "sm", align: "baseline", role: chosen ? "omp.tool.answer" : "omp.tool.answer.off", key },
305
+ );
306
+ }
307
+
308
+ /**
309
+ * Answered option list: every offered option marked chosen or not, plus any
310
+ * quoted custom answer and a muted note. A lone "Cancelled" line when nothing was chosen.
311
+ */
312
+ function describeAnswers(
313
+ options: string[] | undefined,
314
+ selectedOptions: string[] | undefined,
315
+ customInput: string | undefined,
316
+ note: string | undefined,
317
+ selectedIndices: ReadonlySet<number> | undefined,
318
+ ): NativeChild[] {
319
+ const selected = new Set(selectedOptions ?? []);
320
+ if (selected.size === 0 && customInput === undefined && note === undefined) {
321
+ return [text([span("Cancelled", "warning")], { tone: "warning" })];
322
+ }
323
+ const labels = options && options.length > 0 ? options : (selectedOptions ?? []);
324
+ const rows = labels.map((label, index) => {
325
+ const isSelected = selectedIndices !== undefined ? selectedIndices.has(index) : selected.has(label);
326
+ return answerRow(`${index}`, [span(plainText(label), isSelected ? "toolOutput" : "muted")], isSelected);
327
+ });
328
+ if (customInput !== undefined) {
329
+ rows.push(answerRow("custom", [span(`\u201c${plainText(customInput)}\u201d`, "toolOutput")], true));
330
+ }
331
+ return compact([
332
+ ...rows,
333
+ note !== undefined
334
+ ? text([span(plainText(note), "muted")], { wrap: "word", role: "omp.tool.context" })
335
+ : undefined,
336
+ ]);
337
+ }
338
+
339
+ /** Pending ask: an inline head naming the question; the ask dialog owns the form. */
340
+ function describeAskCall(args: AskRenderArgs): NativeToolView {
341
+ const questions = normalizeRenderQuestions(args.questions);
342
+ const first = questions?.[0]?.question ?? (typeof args.question === "string" ? args.question : undefined);
343
+ const more = questions && questions.length > 1 ? `${questions.length} questions` : undefined;
344
+ return {
345
+ tool: askHead(first, more),
346
+ inline: true,
347
+ body: [text([span("Waiting for your answer…", "muted")])],
348
+ };
349
+ }
350
+
351
+ function describeAskResult(result: ToolRenderResult<AskToolDetails>, args: AskRenderArgs | undefined): NativeToolView {
352
+ const rawDetails = result.details;
353
+ const fallback = plainText(sanitizeCarriageReturns(resultText(result)));
354
+ const argQuestion =
355
+ normalizeRenderQuestions(args?.questions)?.[0]?.question ??
356
+ (typeof args?.question === "string" ? args.question : undefined);
357
+ if (!rawDetails) {
358
+ return { tool: askHead(argQuestion), tone: "warning", body: fallback ? [noteText(fallback)] : undefined };
359
+ }
360
+ const details = sanitizeAskResultDetails(rawDetails);
361
+
362
+ if (details.chatRedirect) {
363
+ return {
364
+ tool: askHead(details.questions?.[0] ?? argQuestion, "chat redirect"),
365
+ tone: "info",
366
+ body: (details.questions ?? []).map(q => md(plainText(q))),
367
+ };
368
+ }
369
+
370
+ if (details.results && details.results.length > 0) {
371
+ const results = details.results;
372
+ const rawResults = rawDetails.results ?? [];
373
+ const answered = results.some(
374
+ r =>
375
+ r.customInput !== undefined || r.note !== undefined || (r.selectedOptions && r.selectedOptions.length > 0),
376
+ );
377
+ return {
378
+ tool: askHead(results[0]?.question, results.length > 1 ? `${results.length} questions` : undefined),
379
+ tone: answered ? undefined : "warning",
380
+ // Sanitizing preserves order and length, so raw indices align with `r`.
381
+ body: results.map((r, index) =>
382
+ describeQuestionSection(
383
+ r.id,
384
+ r.question,
385
+ describeAnswers(
386
+ r.options,
387
+ r.selectedOptions,
388
+ r.customInput,
389
+ r.note,
390
+ selectedIndicesFor(rawResults[index]?.options, rawResults[index]?.selectedOptions),
391
+ ),
392
+ ),
393
+ ),
394
+ };
395
+ }
396
+
397
+ if (!details.question) {
398
+ return { tool: askHead(argQuestion), body: fallback ? [text(fallback, { wrap: "word" })] : undefined };
399
+ }
400
+
401
+ const answered =
402
+ details.customInput !== undefined ||
403
+ details.note !== undefined ||
404
+ (details.selectedOptions && details.selectedOptions.length > 0);
405
+ return {
406
+ tool: askHead(details.question),
407
+ tone: answered ? undefined : "warning",
408
+ body: compact([
409
+ md(plainText(details.question)),
410
+ ...describeAnswers(
411
+ details.options,
412
+ details.selectedOptions,
413
+ details.customInput,
414
+ details.note,
415
+ selectedIndicesFor(rawDetails.options, rawDetails.selectedOptions),
416
+ ),
417
+ details.timedOut
418
+ ? text([span("auto-selected after timeout — not a user choice", "muted")], {
419
+ wrap: "word",
420
+ role: "omp.tool.notice",
421
+ })
422
+ : undefined,
423
+ ]),
424
+ };
425
+ }
426
+
427
+ const askCallMemo = new OwnerMemo<NativeToolView | undefined>();
428
+ const askResultMemo = new OwnerMemo<NativeToolView | undefined>();
429
+
284
430
  /** Render question forms and their recorded answers. */
285
431
  export const askToolRenderer = {
432
+ describeCall(args: AskRenderArgs): NativeToolView | undefined {
433
+ return askCallMemo.get(args, [JSON.stringify(args)], () => describeAskCall(args));
434
+ },
435
+ describeResult(
436
+ result: ToolRenderResult<AskToolDetails>,
437
+ _options?: RenderResultOptions,
438
+ args?: AskRenderArgs,
439
+ ): NativeToolView | undefined {
440
+ return askResultMemo.get(result, [], () => describeAskResult(result, args));
441
+ },
286
442
  mergeCallAndResult: true,
287
443
  renderCall(args: AskRenderArgs, _options: RenderResultOptions, uiTheme: Theme): Component {
288
444
  const label = formatTitle("Ask", uiTheme);