@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
@@ -8,6 +8,8 @@ import { type SelectItem, SelectList, type SgrMouseEvent } from "../index";
8
8
  import { getSelectListTheme } from "../theme/theme";
9
9
  import { OverlayPanel } from "../chrome/overlay-box";
10
10
  import { routeSelectListMouseWithTopBorder } from "../chrome/select-list-mouse-routing";
11
+ import type { DescribeContext, NativeNode, NativeUiEvent } from "../native/node";
12
+ import { SelectListSheet } from "../native/picker";
11
13
 
12
14
  export interface PluginSelectorCallbacks {
13
15
  onSelect: (pluginName: string, marketplace: string, scope?: "user" | "project") => void;
@@ -23,6 +25,7 @@ export interface PluginItem {
23
25
 
24
26
  export class PluginSelectorComponent extends OverlayPanel {
25
27
  #selectList: SelectList;
28
+ #sheet: SelectListSheet;
26
29
 
27
30
  constructor(
28
31
  marketplaceCount: number,
@@ -30,7 +33,7 @@ export class PluginSelectorComponent extends OverlayPanel {
30
33
  installedIds: Set<string>,
31
34
  callbacks: PluginSelectorCallbacks,
32
35
  ) {
33
- super("Plugins");
36
+ super("Plugins", "omp.overlay.plugins");
34
37
 
35
38
  const items: SelectItem[] = plugins.map(({ plugin, marketplace, scope }) => {
36
39
  // Encode scope into the value so onSelect can recover it without a parallel Map.
@@ -75,6 +78,23 @@ export class PluginSelectorComponent extends OverlayPanel {
75
78
  };
76
79
 
77
80
  this.addChild(this.#selectList);
81
+ this.#sheet = new SelectListSheet(this.#selectList, {
82
+ title: "Plugins",
83
+ icon: "plus",
84
+ noun: "plugins",
85
+ confirm: "Install",
86
+ decorate: item => (item.hint ? { facts: { marketplace: item.hint } } : undefined),
87
+ columns: [{ id: "marketplace", format: "dim" }],
88
+ });
89
+ }
90
+
91
+ override describe(cx: DescribeContext): NativeNode | null {
92
+ return cx.supports("picker") ? this.#sheet.describe() : super.describe(cx);
93
+ }
94
+
95
+ /** Picker pointer events drive the list exactly as its keys do. */
96
+ handleNativeEvent(event: NativeUiEvent): void {
97
+ this.#sheet.handle(event);
78
98
  }
79
99
 
80
100
  getSelectList(): SelectList {
@@ -22,8 +22,76 @@ import { shortenPath } from "../render/render-utils";
22
22
  import { OverlayPanel } from "../chrome/overlay-box";
23
23
  import { FormField, SelectFormField, TextFormField } from "../components/form";
24
24
  import { formTheme } from "../chrome/form-theme";
25
- import { SettingsFormField } from "../components/settings-list";
25
+ import { type PrefsEditing, SettingsFormField, type SettingsList } from "../components/settings-list";
26
26
  import { editorKey } from "../chrome/keybinding-hints";
27
+ import type { DescribeContext, NativeChild, NativeNode, NativeUiEvent } from "../native/node";
28
+ import { col, node, span, text } from "../native/describe";
29
+ import type { TspPrefsControl, TspPrefsSection } from "@oh-my-pi/pi-wire";
30
+ import { actionHint, hintsRow, overlayCard } from "../native/overlay";
31
+
32
+ const PLUGIN_SETTINGS_ROLE = "omp.overlay.plugin-settings";
33
+ /** A plugin row's control on the native settings page: open the plugin's settings. */
34
+ const PLUGIN_CONFIGURE: TspPrefsControl = { k: "action", label: "Configure", act: "open" };
35
+
36
+ /** The plugins tab as a native settings page draws it (the settings selector puts it in its `prefs` node). */
37
+ export interface PluginPrefsPage {
38
+ lead: string;
39
+ sections: TspPrefsSection[];
40
+ focus: string | null;
41
+ editing: PrefsEditing | null;
42
+ /** An open value editor without a native control, shown over the page. */
43
+ editor?: NativeChild;
44
+ }
45
+
46
+ /**
47
+ * A plugin detail list as native page sections: on/off rows as switches,
48
+ * value rows as an edit button showing the value (the row's editor opens
49
+ * over the page, see {@link prefsDetailEvent}).
50
+ */
51
+ function prefsDetailPage(title: string, lead: string, list: SettingsList | undefined): PluginPrefsPage {
52
+ if (!list) return { lead, sections: [], focus: null, editing: null };
53
+ const sections = list.prefsSections(
54
+ () => ({ id: "plugin", title }),
55
+ (item): TspPrefsControl =>
56
+ item.values?.length === 2 && item.values.includes("true") && item.values.includes("false")
57
+ ? { k: "switch", on: item.currentValue === "true" }
58
+ : { k: "action", label: item.currentValue.trim() || "Edit…", act: "edit" },
59
+ );
60
+ const open = list.openSubmenu;
61
+ return {
62
+ lead,
63
+ sections: sections.map(section => ({
64
+ ...section,
65
+ rows: section.rows.map(row => ({ ...row, label: row.label.trim() })),
66
+ })),
67
+ focus: list.prefsFocus().row ?? null,
68
+ editing: null,
69
+ editor: open ? col([open.component], { role: "omp.prefs.editor" }) : undefined,
70
+ };
71
+ }
72
+
73
+ /** A native page event on a plugin detail list, through the keys' code paths. */
74
+ function prefsDetailEvent(list: SettingsList | undefined, event: NativeUiEvent): void {
75
+ if (!list) return;
76
+ switch (event.type) {
77
+ case "change":
78
+ if (typeof event.value === "boolean") list.applyValue(event.item, String(event.value));
79
+ return;
80
+ case "select":
81
+ list.selectItem(event.item);
82
+ return;
83
+ case "activate":
84
+ list.openSubmenuFor(event.item);
85
+ return;
86
+ case "action":
87
+ if (event.act === "edit" && event.value) list.openSubmenuFor(event.value);
88
+ else if (event.act === "close" && event.value && list.openSubmenu?.id === event.value)
89
+ list.handleInput("\x1b");
90
+ return;
91
+ case "toggle":
92
+ return;
93
+ }
94
+ }
27
95
 
28
96
  /** Setting metadata consumed by the plugin settings UI. */
29
97
  export type PluginSettingSchema = {
@@ -227,12 +295,13 @@ function findEntryByValue(entries: ReadonlyArray<PluginListEntry>, value: string
227
295
  */
228
296
  export class PluginListComponent extends OverlayPanel {
229
297
  readonly #selectList: SelectList;
298
+ #native: NativeNode | undefined;
230
299
 
231
300
  constructor(
232
301
  private readonly entries: ReadonlyArray<PluginListEntry>,
233
302
  callbacks: PluginListCallbacks,
234
303
  ) {
235
- super("Plugins");
304
+ super("Plugins", PLUGIN_SETTINGS_ROLE);
236
305
  this.addChild(new Spacer(1));
237
306
 
238
307
  if (entries.length === 0) {
@@ -283,6 +352,74 @@ export class PluginListComponent extends OverlayPanel {
283
352
  );
284
353
  }
285
354
 
355
+ /** The installed plugins as one native page section: a row per plugin with its status and a Configure button. */
356
+ prefsPage(): PluginPrefsPage {
357
+ const rows = this.entries.map(entry => {
358
+ const id = entryValue(entry);
359
+ if (entry.kind === "npm") {
360
+ const p = entry.plugin;
361
+ const features = p.manifest.features ? Object.keys(p.manifest.features).length : 0;
362
+ const parts = [p.enabled ? "Enabled" : "Disabled", "npm", `v${p.version}`];
363
+ if (features > 0) parts.push(`${p.enabledFeatures?.length ?? features}/${features} features`);
364
+ return { id, label: p.name, hint: parts.join(" · "), control: PLUGIN_CONFIGURE };
365
+ }
366
+ const s = entry.plugin;
367
+ const parts = [marketplaceEnabled(s) ? "Enabled" : "Disabled", "marketplace", s.scope];
368
+ parts.push(`v${s.entries[0]?.version ?? "?"}`);
369
+ return {
370
+ id,
371
+ label: s.id,
372
+ hint: parts.join(" · "),
373
+ warning: s.shadowedBy ? `Shadowed by the ${s.shadowedBy} install` : undefined,
374
+ control: PLUGIN_CONFIGURE,
375
+ };
376
+ });
377
+ return {
378
+ lead:
379
+ rows.length > 0
380
+ ? "Plugins installed for you and this project. Configure one to turn it or its features on and off."
381
+ : "No plugins installed. Install one with omp plugin install <package>, or <name>@<marketplace>.",
382
+ sections: rows.length > 0 ? [{ id: "installed", title: "Installed", rows }] : [],
383
+ focus: this.#selectList.getSelectedItem()?.value ?? null,
384
+ editing: null,
385
+ };
386
+ }
387
+
388
+ /** A native page event: a row click moves the selection, Configure (or a double click) opens the plugin. */
389
+ handlePrefsEvent(event: NativeUiEvent): void {
390
+ if (event.type === "select") this.#selectList.setSelectedValue(event.item);
391
+ else if (event.type === "activate") this.#selectList.handleNativeEvent(event);
392
+ else if (event.type === "action" && event.act === "open" && event.value) {
393
+ this.#selectList.handleNativeEvent({ type: "activate", key: event.key, item: event.value });
394
+ }
395
+ }
396
+
397
+ /** The plugin list (the select list describes itself) and its hints, or install guidance when empty. */
398
+ override describe(_cx: DescribeContext): NativeNode {
399
+ if (this.#native) return this.#native;
400
+ const body =
401
+ this.entries.length === 0
402
+ ? [
403
+ text([span("No plugins installed", "muted")]),
404
+ node("kv", {
405
+ items: [
406
+ { k: "Install npm plugins", v: [span("omp plugin install <package>", "code")] },
407
+ {
408
+ k: "Install marketplace plugins",
409
+ v: [span("omp plugin install <name>@<marketplace>", "code")],
410
+ },
411
+ ],
412
+ }),
413
+ hintsRow([actionHint("tui.select.cancel", "go back")]),
414
+ ]
415
+ : [
416
+ this.#selectList,
417
+ hintsRow([actionHint("tui.select.confirm", "configure"), actionHint("tui.select.cancel", "go back")]),
418
+ ];
419
+ this.#native = overlayCard(PLUGIN_SETTINGS_ROLE, this.title, body);
420
+ return this.#native;
421
+ }
422
+
286
423
  #renderItem(entry: PluginListEntry): SelectItem {
287
424
  const kindBadge = theme.fg("dim", entry.kind === "npm" ? "[npm]" : "[marketplace]");
288
425
 
@@ -357,7 +494,7 @@ export class PluginDetailComponent extends OverlayPanel {
357
494
  private readonly manager: PluginSettingsManager,
358
495
  private readonly callbacks: PluginDetailCallbacks,
359
496
  ) {
360
- super(plugin.name);
497
+ super(plugin.name, PLUGIN_SETTINGS_ROLE);
361
498
 
362
499
  void this.#rebuild();
363
500
  }
@@ -452,6 +589,20 @@ export class PluginDetailComponent extends OverlayPanel {
452
589
  if (!this.#settingsList) return;
453
590
  this.#settingsList.handleInput(data);
454
591
  }
592
+
593
+ /** This plugin's settings as a native page section. */
594
+ prefsPage(): PluginPrefsPage {
595
+ return prefsDetailPage(
596
+ this.plugin.name,
597
+ this.plugin.manifest.description || "Turn the plugin and its features on and off, and change its settings.",
598
+ this.#settingsList?.settingsList,
599
+ );
600
+ }
601
+
602
+ /** A native page event on this plugin's settings. */
603
+ handlePrefsEvent(event: NativeUiEvent): void {
604
+ prefsDetailEvent(this.#settingsList?.settingsList, event);
605
+ }
455
606
  }
456
607
 
457
608
  // =============================================================================
@@ -479,7 +630,7 @@ export class MarketplacePluginDetailComponent extends OverlayPanel {
479
630
  private readonly manager: PluginSettingsManager,
480
631
  private readonly callbacks: MarketplacePluginDetailCallbacks,
481
632
  ) {
482
- super(plugin.id);
633
+ super(plugin.id, PLUGIN_SETTINGS_ROLE);
483
634
  this.#render(undefined, []);
484
635
  void this.#loadConfig();
485
636
  }
@@ -575,6 +726,20 @@ export class MarketplacePluginDetailComponent extends OverlayPanel {
575
726
  handleInput(data: string): void {
576
727
  this.#settingsList.handleInput(data);
577
728
  }
729
+
730
+ /** This plugin's settings as a native page section, with its install facts as the lead. */
731
+ prefsPage(): PluginPrefsPage {
732
+ const entry = this.plugin.entries[0];
733
+ const facts = [`${this.plugin.scope} install`, `v${entry?.version ?? "?"}`];
734
+ if (entry?.installPath) facts.push(shortenPath(entry.installPath));
735
+ if (this.plugin.shadowedBy) facts.push(`shadowed by the ${this.plugin.shadowedBy} install`);
736
+ return prefsDetailPage(this.plugin.id, facts.join(" · "), this.#settingsList?.settingsList);
737
+ }
738
+
739
+ /** A native page event on this plugin's settings. */
740
+ handlePrefsEvent(event: NativeUiEvent): void {
741
+ prefsDetailEvent(this.#settingsList?.settingsList, event);
742
+ }
578
743
  }
579
744
 
580
745
  // =============================================================================
@@ -589,7 +754,7 @@ class ConfigFieldPanel extends OverlayPanel {
589
754
  #field: FormField;
590
755
 
591
756
  constructor(key: string, field: FormField) {
592
- super(key);
757
+ super(key, `${PLUGIN_SETTINGS_ROLE}.field`);
593
758
  this.#field = field;
594
759
  this.addChild(field);
595
760
  }
@@ -765,6 +930,31 @@ export class PluginSettingsComponent extends Container {
765
930
  this.callbacks.requestRender?.();
766
931
  }
767
932
 
933
+ /** The current view (list or a plugin's settings) as a native settings page. */
934
+ prefsPage(): PluginPrefsPage {
935
+ const view = this.#viewComponent;
936
+ if (
937
+ view instanceof PluginListComponent ||
938
+ view instanceof PluginDetailComponent ||
939
+ view instanceof MarketplacePluginDetailComponent
940
+ ) {
941
+ return view.prefsPage();
942
+ }
943
+ return { lead: "Loading installed plugins…", sections: [], focus: null, editing: null };
944
+ }
945
+
946
+ /** Routes a native page event to the current view. */
947
+ handlePrefsEvent(event: NativeUiEvent): void {
948
+ const view = this.#viewComponent;
949
+ if (
950
+ view instanceof PluginListComponent ||
951
+ view instanceof PluginDetailComponent ||
952
+ view instanceof MarketplacePluginDetailComponent
953
+ ) {
954
+ view.handlePrefsEvent(event);
955
+ }
956
+ }
957
+
768
958
  #showPluginDetail(plugin: InstalledPlugin): void {
769
959
  this.#currentView = "npm-detail";
770
960
  this.#currentPlugin = plugin;
@@ -2,19 +2,22 @@ import { type SelectItem, SelectList, type SgrMouseEvent } from "../index";
2
2
  import { getSelectListTheme } from "../theme/theme";
3
3
  import { OverlayPanel } from "../chrome/overlay-box";
4
4
  import { routeSelectListMouseWithTopBorder } from "../chrome/select-list-mouse-routing";
5
+ import type { DescribeContext, NativeNode, NativeUiEvent } from "../native/node";
6
+ import { SelectListSheet } from "../native/picker";
5
7
 
6
8
  /**
7
9
  * Component that renders a queue mode selector with borders
8
10
  */
9
11
  export class QueueModeSelectorComponent extends OverlayPanel {
10
12
  #selectList: SelectList;
13
+ #sheet: SelectListSheet;
11
14
 
12
15
  constructor(
13
16
  currentMode: "all" | "one-at-a-time",
14
17
  onSelect: (mode: "all" | "one-at-a-time") => void,
15
18
  onCancel: () => void,
16
19
  ) {
17
- super("Queue Mode");
20
+ super("Queue Mode", "omp.overlay.queue-mode");
18
21
 
19
22
  const queueModes: SelectItem[] = [
20
23
  {
@@ -43,6 +46,21 @@ export class QueueModeSelectorComponent extends OverlayPanel {
43
46
  };
44
47
 
45
48
  this.addChild(this.#selectList);
49
+ this.#sheet = new SelectListSheet(this.#selectList, {
50
+ title: "Queue mode",
51
+ icon: "list",
52
+ noun: "modes",
53
+ current: [currentMode],
54
+ });
55
+ }
56
+
57
+ override describe(cx: DescribeContext): NativeNode | null {
58
+ return cx.supports("picker") ? this.#sheet.describe() : super.describe(cx);
59
+ }
60
+
61
+ /** Picker pointer events drive the list exactly as its keys do. */
62
+ handleNativeEvent(event: NativeUiEvent): void {
63
+ this.#sheet.handle(event);
46
64
  }
47
65
 
48
66
  getSelectList(): SelectList {
@@ -9,9 +9,33 @@ import { centeredViewportRange } from "../components/scroll-viewport";
9
9
  import { formatUsageResetWindow } from "./usage-display";
10
10
  import { formatKeyHint } from "../app-keybindings";
11
11
  import { editorKey, editorKeys } from "../chrome/keybinding-hints";
12
+ import { node, span, text } from "../native/describe";
13
+ import type { NativeNode, NativeUiEvent } from "../native/node";
14
+ import { actionHint, hintsRow, overlayCard } from "../native/overlay";
12
15
 
13
16
  const RESET_SELECTOR_MAX_VISIBLE = 10;
14
17
 
18
+ const oneLine = (value: string): string => sanitizeText(value.replace(/[\r\n\t]+/g, " "));
19
+
20
+ /** Reset count, usability, expiry and unavailability of an account row, or its error. */
21
+ function accountCountLabel(account: ResetUsageAccount): string {
22
+ if (account.error) return oneLine(account.error);
23
+ let countLabel = `${account.availableCount} saved reset${account.availableCount === 1 ? "" : "s"}`;
24
+ if (account.redeemableCount !== account.availableCount) {
25
+ countLabel += ` · ${account.redeemableCount} usable now`;
26
+ }
27
+ if (account.expiresAt) {
28
+ const expiryMs = Date.parse(account.expiresAt);
29
+ if (!Number.isNaN(expiryMs)) {
30
+ countLabel += expiryMs > Date.now() ? ` · expires in ${formatDuration(expiryMs - Date.now())}` : " · expired";
31
+ }
32
+ }
33
+ if (account.redeemableCount <= 0 && account.unavailableReason) {
34
+ countLabel += ` · ${oneLine(account.unavailableReason)}`;
35
+ }
36
+ return countLabel;
37
+ }
38
+
15
39
  /** One account row with its redeemable rate-limit reset credits. */
16
40
  export interface ResetUsageAccount {
17
41
  label: string;
@@ -47,9 +71,12 @@ export class ResetUsageSelectorComponent extends OverlayPanel {
47
71
  #statusMessage: string | undefined;
48
72
  #onSelectCallback: (account: ResetUsageAccount) => void;
49
73
  #onCancelCallback: () => void;
74
+ #nativeItems: readonly NativeNode[] | undefined;
75
+ #nativeHints: NativeNode | undefined;
76
+ #nativeRoot: NativeNode | undefined;
50
77
 
51
78
  constructor(accounts: ResetUsageAccount[], onSelect: (account: ResetUsageAccount) => void, onCancel: () => void) {
52
- super("Spend a saved rate-limit reset");
79
+ super("Spend a saved rate-limit reset", "omp.overlay.reset-usage");
53
80
  this.#onSelectCallback = onSelect;
54
81
  this.#onCancelCallback = onCancel;
55
82
  const firstRedeemable = accounts.find(account => account.redeemableCount > 0);
@@ -71,8 +98,8 @@ export class ResetUsageSelectorComponent extends OverlayPanel {
71
98
  }
72
99
 
73
100
  #updateList(): void {
101
+ this.#nativeRoot = undefined;
74
102
  this.#listContainer.clear();
75
- const oneLine = (value: string): string => sanitizeText(value.replace(/[\r\n\t]+/g, " "));
76
103
 
77
104
  const items = this.#menu.visibleItems;
78
105
  const total = items.length;
@@ -85,25 +112,7 @@ export class ResetUsageSelectorComponent extends OverlayPanel {
85
112
  if (!account) continue;
86
113
  const isSelected = i === this.#menu.selectedIndex;
87
114
  const redeemable = account.redeemableCount > 0;
88
- let countLabel: string;
89
- if (account.error) {
90
- countLabel = oneLine(account.error);
91
- } else {
92
- countLabel = `${account.availableCount} saved reset${account.availableCount === 1 ? "" : "s"}`;
93
- if (account.redeemableCount !== account.availableCount) {
94
- countLabel += ` · ${account.redeemableCount} usable now`;
95
- }
96
- if (account.expiresAt) {
97
- const expiryMs = Date.parse(account.expiresAt);
98
- if (!Number.isNaN(expiryMs)) {
99
- countLabel +=
100
- expiryMs > Date.now() ? ` · expires in ${formatDuration(expiryMs - Date.now())}` : " · expired";
101
- }
102
- }
103
- if (!redeemable && account.unavailableReason) {
104
- countLabel += ` · ${oneLine(account.unavailableReason)}`;
105
- }
106
- }
115
+ const countLabel = accountCountLabel(account);
107
116
  const countText = account.error
108
117
  ? theme.fg("error", countLabel)
109
118
  : redeemable
@@ -205,25 +214,86 @@ export class ResetUsageSelectorComponent extends OverlayPanel {
205
214
  this.#statusMessage = undefined;
206
215
  this.#updateList();
207
216
  } else if (matchesKey(keyData, "enter") || matchesKey(keyData, "return") || keyData === "\n") {
208
- const account = this.#menu.selectedItem;
209
- if (!account) return;
210
- if (account.redeemableCount <= 0) {
211
- this.#statusMessage = account.unavailableReason
212
- ? `That account's saved resets are unavailable: ${account.unavailableReason}`
213
- : "That account has no saved resets usable right now.";
214
- this.#updateList();
215
- return;
216
- }
217
- const result = this.#menu.requestActivation();
218
- if (result.kind === "pending") {
219
- this.#statusMessage = undefined;
220
- this.#updateList();
221
- return;
222
- }
223
- if (result.kind === "confirmed") {
224
- this.#onSelectCallback(result.item);
225
- return;
226
- }
217
+ this.#activateSelection();
218
+ }
219
+ }
220
+
221
+ #activateSelection(): void {
222
+ const account = this.#menu.selectedItem;
223
+ if (!account) return;
224
+ if (account.redeemableCount <= 0) {
225
+ this.#statusMessage = account.unavailableReason
226
+ ? `That account's saved resets are unavailable: ${account.unavailableReason}`
227
+ : "That account has no saved resets usable right now.";
228
+ this.#updateList();
229
+ return;
230
+ }
231
+ const result = this.#menu.requestActivation();
232
+ if (result.kind === "pending") {
233
+ this.#statusMessage = undefined;
234
+ this.#updateList();
235
+ return;
236
+ }
237
+ if (result.kind === "confirmed") {
238
+ this.#onSelectCallback(result.item);
239
+ }
240
+ }
241
+
242
+ override describe(): NativeNode {
243
+ if (this.#nativeRoot) return this.#nativeRoot;
244
+ this.#nativeItems ??= this.#menu.visibleItems.map(account => {
245
+ const redeemable = account.redeemableCount > 0;
246
+ const detail = [span(`${oneLine(account.providerLabel)} · #${account.target.credentialId}`, "muted")];
247
+ if (account.active) detail.push(span(" (active)", "muted"));
248
+ return node(
249
+ "item",
250
+ {
251
+ label: redeemable ? oneLine(account.label) : [span(oneLine(account.label), "dim")],
252
+ detail,
253
+ value: [span(accountCountLabel(account), account.error ? "error" : redeemable ? "success" : "dim")],
254
+ },
255
+ undefined,
256
+ this.#menu.adapter.getKey(account),
257
+ );
258
+ });
259
+ const pending = this.#menu.visibleItems.find(item => this.#menu.isPending(item));
260
+ const children: NativeNode[] = [
261
+ node(
262
+ "list",
263
+ {
264
+ selected: this.#menu.selectedKey ?? null,
265
+ empty: [span("No provider accounts with saved resets", "muted")],
266
+ max: { lines: RESET_SELECTOR_MAX_VISIBLE },
267
+ },
268
+ this.#nativeItems,
269
+ "list",
270
+ ),
271
+ pending
272
+ ? text([span(oneLine(this.#confirmationMessage(pending)), "warning")])
273
+ : (this.#nativeHints ??= hintsRow([
274
+ actionHint(["tui.select.up", "tui.select.down"], "select"),
275
+ { keys: ["enter"], label: "spend a reset" },
276
+ actionHint("tui.select.cancel", "cancel"),
277
+ ])),
278
+ ];
279
+ if (this.#statusMessage) children.push(text([span(oneLine(this.#statusMessage), "warning")]));
280
+ this.#nativeRoot = overlayCard(this.nativeRole, this.title, children);
281
+ return this.#nativeRoot;
282
+ }
283
+
284
+ /**
285
+ * A click (or double-click) on an account highlights it and presses Enter:
286
+ * moving to another account drops a pending confirmation, so spending a
287
+ * reset still takes a second activation of the same account.
288
+ */
289
+ handleNativeEvent(event: NativeUiEvent): void {
290
+ if ((event.type !== "select" && event.type !== "activate") || event.key !== "list") return;
291
+ if (this.#menu.selectedKey !== event.item) {
292
+ this.#menu.cancelConfirmation();
293
+ this.#menu.setSelectedKey(event.item);
294
+ if (this.#menu.selectedKey !== event.item) return;
295
+ this.#statusMessage = undefined;
227
296
  }
297
+ this.#activateSelection();
228
298
  }
229
299
  }