@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
@@ -1,3 +1,6 @@
1
+ import { styleSpans } from "../native/spans";
2
+ import { node, text } from "../native/describe";
3
+ import type { DescribeContext, NativeNode } from "../native/node";
1
4
  import type { Component } from "../tui";
2
5
  import { Ellipsis, getWidthConfigEpoch, truncateToWidth, visibleWidth } from "../utils";
3
6
  import { Text } from "./text";
@@ -85,6 +88,7 @@ export class MetricRow implements Component {
85
88
  readonly #options: MetricRowOptions;
86
89
  readonly #text: Text;
87
90
  #cache: { width: number; epoch: number; source: readonly string[]; lines: readonly string[] } | undefined;
91
+ #native: NativeNode | undefined;
88
92
 
89
93
  constructor(metrics: readonly MetricSpec[], options: MetricRowOptions = {}) {
90
94
  this.#metrics = metrics;
@@ -96,12 +100,47 @@ export class MetricRow implements Component {
96
100
  if (this.#metrics === metrics) return false;
97
101
  this.#metrics = metrics;
98
102
  this.#cache = undefined;
103
+ this.#native = undefined;
99
104
  return true;
100
105
  }
101
106
 
102
107
  invalidate(): void {
103
108
  this.#text.invalidate();
104
109
  this.#cache = undefined;
110
+ this.#native = undefined;
111
+ }
112
+
113
+ /**
114
+ * `drop` overflow becomes a transparent `status` strip whose segments keep
115
+ * the metric priorities (the terminal drops the lowest first); the other
116
+ * modes are one text run that wraps or truncates.
117
+ */
118
+ describe(_cx: DescribeContext): NativeNode {
119
+ if (this.#native) return this.#native;
120
+ const options = this.#options;
121
+ if (options.overflow === "drop") {
122
+ const segs: NativeNode[] = [];
123
+ this.#metrics.forEach((metric, index) => {
124
+ const formatted = formatMetric(metric);
125
+ if (formatted === undefined) return;
126
+ segs.push(
127
+ node(
128
+ "seg",
129
+ { side: "left", priority: metric.priority ?? 0, spans: styleSpans(formatted, options.style) },
130
+ undefined,
131
+ String(index),
132
+ ),
133
+ );
134
+ });
135
+ this.#native = node("status", { transparent: true }, segs);
136
+ return this.#native;
137
+ }
138
+ const joined = formatMetricRow(this.#metrics, { separator: options.separator });
139
+ this.#native =
140
+ options.overflow === "wrap"
141
+ ? text(styleSpans(joined, options.style), { wrap: "word" })
142
+ : text(styleSpans(joined, options.style), { wrap: "none", truncate: "end" });
143
+ return this.#native;
105
144
  }
106
145
 
107
146
  render(width: number): readonly string[] {
@@ -1,3 +1,6 @@
1
+ import { compactText, styledSpans } from "../native/spans";
2
+ import { node } from "../native/describe";
3
+ import type { DescribeContext, NativeNode } from "../native/node";
1
4
  import type { Component } from "../tui";
2
5
  import { Ellipsis, getWidthConfigEpoch, truncateToWidth, visibleWidth } from "../utils";
3
6
 
@@ -87,6 +90,7 @@ export class ProgressBar implements Component {
87
90
  #value: number | undefined;
88
91
  readonly #options: ProgressBarOptions;
89
92
  #cache: { width: number; epoch: number; value: number | undefined; lines: readonly string[] } | undefined;
93
+ #native: NativeNode | undefined;
90
94
 
91
95
  constructor(value: number | undefined, options: ProgressBarOptions) {
92
96
  this.#value = value;
@@ -97,11 +101,35 @@ export class ProgressBar implements Component {
97
101
  if (Object.is(this.#value, value)) return false;
98
102
  this.#value = value;
99
103
  this.#cache = undefined;
104
+ this.#native = undefined;
100
105
  return true;
101
106
  }
102
107
 
103
108
  invalidate(): void {
104
109
  this.#cache = undefined;
110
+ this.#native = undefined;
111
+ }
112
+
113
+ /** A native `progress` bar (indeterminate when the value is unknown); prefix, suffix and percentage label it. */
114
+ describe(_cx: DescribeContext): NativeNode {
115
+ if (this.#native) return this.#native;
116
+ const options = this.#options;
117
+ const fraction = progressFraction(this.#value, options.min, options.max);
118
+ const parts: string[] = [];
119
+ // Frame punctuation (`[`, `]`, `▕`) around the bar is the terminal's chrome now; only wording labels it.
120
+ const frame = /^[^\p{L}\p{N}]+|[^\p{L}\p{N}%)]+$/gu;
121
+ const prefix = singleLine(options.prefix ?? "").replace(frame, "");
122
+ const suffix = singleLine(options.suffix ?? "").replace(frame, "");
123
+ if (prefix) parts.push(prefix);
124
+ if (suffix) parts.push(suffix);
125
+ if (fraction !== undefined && options.showPercentage === true) {
126
+ parts.push(singleLine(options.formatPercentage?.(fraction) ?? `${Math.round(fraction * 100)}%`));
127
+ }
128
+ this.#native = node("progress", {
129
+ value: fraction ?? null,
130
+ label: parts.length > 0 ? compactText(styledSpans(parts.join(" "))) : undefined,
131
+ });
132
+ return this.#native;
105
133
  }
106
134
 
107
135
  render(width: number): readonly string[] {
@@ -1,4 +1,7 @@
1
1
  import { matchesKey } from "../keys";
2
+ import { rowsText } from "../native/spans";
3
+ import { col } from "../native/describe";
4
+ import type { DescribeContext, NativeNode } from "../native/node";
2
5
  import type { Component } from "../tui";
3
6
  import { Ellipsis, getWidthConfigEpoch, padding, replaceTabs, truncateToWidth, visibleWidth } from "../utils";
4
7
  import {
@@ -126,6 +129,7 @@ export class ScrollView implements Component {
126
129
  #rangeSnapshot: RangeSnapshot | undefined;
127
130
  #cache: RenderCache | undefined;
128
131
  #disposed = false;
132
+ #native: { content: readonly string[] | Component; height: number; node: NativeNode } | undefined;
129
133
 
130
134
  constructor(content: readonly string[] | Component, options: ScrollViewOptions) {
131
135
  this.#child = isComponent(content) ? content : undefined;
@@ -400,6 +404,7 @@ export class ScrollView implements Component {
400
404
  invalidate(): void {
401
405
  if (this.#disposed) return;
402
406
  this.#cache = undefined;
407
+ this.#native = undefined;
403
408
  this.#child?.invalidate?.();
404
409
  }
405
410
 
@@ -415,6 +420,24 @@ export class ScrollView implements Component {
415
420
  child?.dispose?.();
416
421
  }
417
422
 
423
+ /**
424
+ * The whole content in a `col` capped at the viewport height: the
425
+ * terminal scrolls it natively and draws its own scrollbar.
426
+ */
427
+ describe(_cx: DescribeContext): NativeNode {
428
+ const content = this.#child ?? this.#lines;
429
+ const cached = this.#native;
430
+ if (cached?.content === content && cached.height === this.#height) return cached.node;
431
+ const described = this.#disposed
432
+ ? col([], { hidden: true })
433
+ : col([this.#child ?? rowsText(this.#lines)], {
434
+ max: { h: `${this.#height}lines` },
435
+ hidden: this.#height === 0 ? true : undefined,
436
+ });
437
+ this.#native = { content, height: this.#height, node: described };
438
+ return described;
439
+ }
440
+
418
441
  render(width: number): readonly string[] {
419
442
  if (this.#disposed) return EMPTY_LINES;
420
443
  const safeWidth = normalizedRows(width);
@@ -1,3 +1,6 @@
1
+ import { compactText, rowsText, styledSpans } from "../native/spans";
2
+ import { node } from "../native/describe";
3
+ import type { DescribeContext, NativeNode } from "../native/node";
1
4
  import type { Component } from "../tui";
2
5
  import { Ellipsis, getWidthConfigEpoch, replaceTabs, truncateToWidth, visibleWidth } from "../utils";
3
6
 
@@ -37,6 +40,7 @@ export class Section implements Component {
37
40
  readonly #options: SectionOptions;
38
41
  #cache: { width: number; epoch: number; child: readonly string[]; lines: readonly string[] } | undefined;
39
42
  #disposed = false;
43
+ #native: { title: string; node: NativeNode } | undefined;
40
44
 
41
45
  constructor(options: SectionOptions) {
42
46
  this.#options = options;
@@ -53,6 +57,18 @@ export class Section implements Component {
53
57
  if (isComponent(this.#options.body)) this.#options.body.dispose?.();
54
58
  }
55
59
 
60
+ /** A `section` headed by the styled title; the rule is the terminal's. */
61
+ describe(_cx: DescribeContext): NativeNode {
62
+ const options = this.#options;
63
+ const rawTitle = singleLine(options.title);
64
+ const title = options.titleStyle?.(rawTitle) ?? rawTitle;
65
+ if (this.#native?.title === title) return this.#native.node;
66
+ const body = isComponent(options.body) ? options.body : rowsText(options.body);
67
+ const described = node("section", { head: compactText(styledSpans(title)) }, [body]);
68
+ this.#native = { title, node: described };
69
+ return described;
70
+ }
71
+
56
72
  render(width: number): readonly string[] {
57
73
  const renderWidth = finiteWidth(width);
58
74
  const epoch = getWidthConfigEpoch();
@@ -1,8 +1,14 @@
1
1
  import { popLoopPhase, pushLoopPhase } from "@oh-my-pi/pi-utils";
2
+ import { Input } from "./input";
2
3
  import { getMenuWindow, MenuSelection } from "./menu-selection";
3
4
  import { getKeybindings } from "../keybindings";
4
5
  import { extractPrintableText, matchesKey } from "../keys";
5
6
  import { type MouseRoutable, routeSelectListMouse, type SgrMouseEvent } from "../mouse";
7
+ import { col, node, span } from "../native/describe";
8
+ import { sameItems, sameProps } from "../native/memo";
9
+ import { plainLine } from "../native/spans";
10
+ import type { TspProps } from "@oh-my-pi/pi-wire";
11
+ import type { DescribeContext, NativeChild, NativeNode, NativeUiEvent } from "../native/node";
6
12
  import type { SymbolTheme } from "../symbols";
7
13
  import type { Component } from "../tui";
8
14
  import { Ellipsis, padding, replaceTabs, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "../utils";
@@ -23,12 +29,25 @@ function sanitizeSingleLine(text: string): string {
23
29
 
24
30
  const clamp = (value: number, min: number, max: number): number => Math.max(min, Math.min(value, max));
25
31
 
32
+ /** Described `item` node cached on the item, rebuilt only when its visible fields change. */
33
+ const kNativeItem = Symbol("selectList.nativeItem");
34
+
35
+ interface NativeDescribedItem extends SelectItem {
36
+ [kNativeItem]?: { signature: string; node: NativeNode };
37
+ }
38
+
26
39
  export interface SelectItem {
27
40
  value: string;
28
41
  label: string;
29
42
  description?: string;
30
43
  /** Optional type-indicator glyph rendered in an aligned column before the label */
31
44
  icon?: string;
45
+ /** Named icon a TSP terminal draws from its own set (replaces the {@link icon} glyph natively). */
46
+ iconName?: string;
47
+ /** Native detail text when it differs from the ANSI {@link description} (which may embed {@link state}). */
48
+ nativeDetail?: string;
49
+ /** Live state drawn right-aligned natively ("demo/demo", "off"). */
50
+ state?: string;
32
51
  /** Dim hint text shown inline after cursor when this item is selected */
33
52
  hint?: string;
34
53
  /** Disabled rows stay visible but are skipped by navigation and cannot activate. */
@@ -153,6 +172,12 @@ export class SelectList implements Component, MouseRoutable {
153
172
  #hoveredIndex: number | null = null;
154
173
  /** Per-render map of 0-based output line → filtered-item index. */
155
174
  #hitRows: (number | undefined)[] = [];
175
+ #nativeList?: { props: TspProps<"list">; items: readonly NativeNode[]; node: NativeNode };
176
+ #nativeRoot?: { list: NativeNode; status: string; node: NativeNode };
177
+ /** Typed text marked at the start of native item labels (an autocomplete popup's query). */
178
+ #nativeMark: string | undefined;
179
+ /** The type-to-filter field; its value is pushed into the selection's query. */
180
+ readonly #search = new Input();
156
181
 
157
182
  onSelect?: (item: SelectItem) => void;
158
183
  onCancel?: () => void;
@@ -172,6 +197,7 @@ export class SelectList implements Component, MouseRoutable {
172
197
  requiresConfirmation: item => item.confirmation !== undefined,
173
198
  filter: layout.filterItems,
174
199
  });
200
+ this.#search.prompt = "";
175
201
  }
176
202
  /** Return item, selection, and filter state for debug inspection. */
177
203
  debugState(): Record<string, unknown> {
@@ -193,8 +219,10 @@ export class SelectList implements Component, MouseRoutable {
193
219
  this.#maxVisible = Math.max(1, Math.trunc(rows));
194
220
  }
195
221
 
222
+ /** Replace the filter text (caret to end) and refilter. */
196
223
  setFilter(filter: string): void {
197
- this.#setFilter(filter, true);
224
+ this.#search.setValue(filter);
225
+ this.#setFilter(this.#search.getValue(), true);
198
226
  }
199
227
 
200
228
  /** Replace controlled items while retaining the selected value when possible. */
@@ -215,6 +243,26 @@ export class SelectList implements Component, MouseRoutable {
215
243
  return this.#selection.query;
216
244
  }
217
245
 
246
+ /**
247
+ * What a native `picker` shows: the filtered items in order, the selected
248
+ * and pending values, the query and its caret (UTF-16 offset).
249
+ */
250
+ pickerView(): {
251
+ readonly items: readonly SelectItem[];
252
+ readonly selected: string | null;
253
+ readonly pending: string | null;
254
+ readonly query: string;
255
+ readonly cursor: number;
256
+ } {
257
+ return {
258
+ items: this.#selection.visibleItems,
259
+ selected: this.#selection.selectedKey ?? null,
260
+ pending: this.#selection.pendingKey ?? null,
261
+ query: this.#selection.query,
262
+ cursor: this.#search.getCursor(),
263
+ };
264
+ }
265
+
218
266
  /** Resolve a 0-based rendered-line index to a filtered-item index. */
219
267
  hitTest(line: number): number | undefined {
220
268
  return this.#hitRows[line];
@@ -242,6 +290,95 @@ export class SelectList implements Component, MouseRoutable {
242
290
  routeSelectListMouse(this, event, line);
243
291
  }
244
292
 
293
+ /**
294
+ * A `list` of `item`s keyed by item value, with the selection, the search
295
+ * query and the empty/no-match text, plus a status line (search query,
296
+ * pending confirmation, host status) under it when one applies.
297
+ */
298
+ describe(_cx: DescribeContext): NativeNode {
299
+ const items: NativeNode[] = [];
300
+ for (const item of this.#selection.visibleItems) items.push(this.#describeItem(item));
301
+ const query = this.#selection.query;
302
+ const cachedMax = this.#nativeList?.props.max;
303
+ const props: TspProps<"list"> = {
304
+ selected: this.#selection.selectedKey ?? null,
305
+ filter: this.#nativeMark === undefined ? query.trim() || undefined : undefined,
306
+ empty:
307
+ query.trim().length > 0
308
+ ? (this.layout.noMatchText ?? "No matching items")
309
+ : (this.layout.emptyText ?? "No items"),
310
+ max:
311
+ typeof cachedMax === "object" && cachedMax.lines === this.#maxVisible
312
+ ? cachedMax
313
+ : { lines: this.#maxVisible },
314
+ };
315
+ const cachedList = this.#nativeList;
316
+ const list =
317
+ cachedList && sameProps(cachedList.props, props) && sameItems(cachedList.items, items)
318
+ ? cachedList.node
319
+ : node("list", props, items, "list");
320
+ if (list !== cachedList?.node) this.#nativeList = { props, items, node: list };
321
+
322
+ const status = this.#shouldRenderSearchStatus() ? plainLine(this.#statusText()) : "";
323
+ const cachedRoot = this.#nativeRoot;
324
+ if (cachedRoot && cachedRoot.list === list && cachedRoot.status === status) return cachedRoot.node;
325
+ const children: NativeChild[] = [list];
326
+ if (status) children.push(node("text", { spans: [span(status, "muted")], wrap: "none" }, undefined, "status"));
327
+ const root = col(children, { role: "omp.select" });
328
+ this.#nativeRoot = { list, status, node: root };
329
+ return root;
330
+ }
331
+
332
+ /**
333
+ * Mark `typed` where it leads a native item label (`{s:"mark"}`), for lists
334
+ * whose items were matched against text outside the list (autocomplete).
335
+ * The list then sends no `filter`: the marks already say what matched.
336
+ */
337
+ setNativeMark(typed: string): void {
338
+ this.#nativeMark = typed;
339
+ }
340
+
341
+ /** Pointer select/activate on an item does what a click does today: select it and request activation. */
342
+ handleNativeEvent(event: NativeUiEvent): void {
343
+ if (event.type !== "select" && event.type !== "activate") return;
344
+ const index = this.#selection.visibleItems.findIndex(item => item.value === event.item);
345
+ if (index >= 0) this.clickItem(index);
346
+ }
347
+
348
+ #describeItem(item: NativeDescribedItem): NativeNode {
349
+ const pending = this.#selection.isPending(item);
350
+ const label = plainLine(this.#sanitizedLabel(item));
351
+ const description = plainLine((pending ? item.confirmation : this.#sanitizedDescription(item)) ?? "");
352
+ const detail = pending || item.nativeDetail === undefined ? description : plainLine(item.nativeDetail);
353
+ const icon = item.icon && item.iconName === undefined ? plainLine(item.icon) : "";
354
+ const state = item.state ? plainLine(item.state) : "";
355
+ const mark = this.#nativeMark ?? "";
356
+ const marked = mark.length > 0 && label.toLowerCase().startsWith(mark.toLowerCase()) ? mark.length : 0;
357
+ const signature =
358
+ `${label}\0${detail}\0${icon}\0${item.iconName}\0${state}\0${marked}\0` +
359
+ `${item.disabled === true}\0${pending}`;
360
+ const cached = item[kNativeItem];
361
+ if (cached?.signature === signature) return cached.node;
362
+ const name = marked === 0 ? [span(label)] : [span(label.slice(0, marked), "mark")];
363
+ if (marked > 0 && marked < label.length) name.push(span(label.slice(marked)));
364
+ const described = node(
365
+ "item",
366
+ {
367
+ // A named icon comes from the terminal's set; a bare glyph leads the label.
368
+ icon: item.iconName,
369
+ label: icon ? [span(`${icon} `, "muted"), ...name] : name,
370
+ detail: detail ? [span(detail, pending ? "warning" : "muted")] : undefined,
371
+ value: state ? [span(state, "muted")] : undefined,
372
+ disabled: item.disabled === true ? true : undefined,
373
+ tone: pending ? "warning" : undefined,
374
+ },
375
+ undefined,
376
+ item.value,
377
+ );
378
+ item[kNativeItem] = { signature, node: described };
379
+ return described;
380
+ }
381
+
245
382
  invalidate(): void {
246
383
  // No cached state to invalidate currently
247
384
  }
@@ -356,14 +493,15 @@ export class SelectList implements Component, MouseRoutable {
356
493
  return;
357
494
  }
358
495
 
359
- if (this.#handleSearchInput(keyData)) return;
360
- if (this.#selection.visibleItems.length === 0) return;
361
-
496
+ // Typed text filters even when it collides with a navigation binding; then
497
+ // host navigation; every other key is the search field's.
498
+ if (extractPrintableText(keyData) !== undefined && this.#handleSearchInput(keyData)) return;
499
+ const wrap = this.layout.wrapNavigation !== false;
362
500
  let selectionChanged = false;
363
501
  if (kb.matches(keyData, "tui.select.up")) {
364
- selectionChanged = this.#selection.move(-1, this.layout.wrapNavigation !== false);
502
+ selectionChanged = this.#selection.move(-1, wrap);
365
503
  } else if (kb.matches(keyData, "tui.select.down")) {
366
- selectionChanged = this.#selection.move(1, this.layout.wrapNavigation !== false);
504
+ selectionChanged = this.#selection.move(1, wrap);
367
505
  } else if (kb.matches(keyData, "tui.select.pageUp")) {
368
506
  selectionChanged = this.#selection.move(-this.#maxVisible);
369
507
  } else if (kb.matches(keyData, "tui.select.pageDown")) {
@@ -373,7 +511,9 @@ export class SelectList implements Component, MouseRoutable {
373
511
  } else if (matchesKey(keyData, "end")) {
374
512
  selectionChanged = this.#selection.moveToBoundary("last");
375
513
  } else if (kb.matches(keyData, "tui.select.confirm") || keyData === "\n") {
376
- this.#activateSelected();
514
+ if (this.#selection.visibleItems.length > 0) this.#activateSelected();
515
+ } else {
516
+ this.#handleSearchInput(keyData);
377
517
  }
378
518
  if (selectionChanged) this.#notifySelectionChange();
379
519
  }
@@ -570,6 +710,21 @@ export class SelectList implements Component, MouseRoutable {
570
710
  }
571
711
 
572
712
  #renderStatusLine(width: number): string {
713
+ const avail = Math.max(1, width - 2);
714
+ if (
715
+ this.layout.statusText === undefined &&
716
+ this.#selection.pendingKey === undefined &&
717
+ this.#selection.query.length > 0
718
+ ) {
719
+ const label = truncateToWidth(" Search: ", avail, Ellipsis.Omit);
720
+ const fieldWidth = avail - visibleWidth(label);
721
+ const styled = this.theme.scrollInfo(label);
722
+ return fieldWidth > 0 ? styled + this.#search.render(fieldWidth)[0].trimEnd() : styled;
723
+ }
724
+ return this.theme.scrollInfo(truncateToWidth(this.#statusText(), avail, Ellipsis.Omit));
725
+ }
726
+
727
+ #statusText(): string {
573
728
  const pendingItem =
574
729
  this.#selection.pendingKey === undefined
575
730
  ? undefined
@@ -582,12 +737,10 @@ export class SelectList implements Component, MouseRoutable {
582
737
  totalCount: this.#selection.items.length,
583
738
  pendingItem,
584
739
  });
585
- const statusText =
586
- this.layout.statusText !== undefined
587
- ? (custom ?? "")
588
- : (pendingItem?.confirmation ??
740
+ return this.layout.statusText !== undefined
741
+ ? (custom ?? "")
742
+ : (pendingItem?.confirmation ??
589
743
  (query ? ` Search: ${query}` : this.#canEditSearch() ? " Type to search" : ""));
590
- return this.theme.scrollInfo(truncateToWidth(statusText, Math.max(1, width - 2), Ellipsis.Omit));
591
744
  }
592
745
 
593
746
  #shouldRenderSearchStatus(): boolean {
@@ -608,21 +761,17 @@ export class SelectList implements Component, MouseRoutable {
608
761
  #handleSearchInput(keyData: string): boolean {
609
762
  if (!this.#canEditSearch()) return false;
610
763
 
611
- const kb = getKeybindings();
612
- if (kb.matches(keyData, "tui.editor.deleteCharBackward")) {
613
- if (this.#selection.query.length === 0) return false;
614
- const chars = [...this.#selection.query];
615
- chars.pop();
616
- this.#setFilter(chars.join(""), true);
617
- return true;
764
+ const before = this.#search.getValue();
765
+ if (before.length === 0) {
766
+ if (getKeybindings().matches(keyData, "tui.editor.deleteCharBackward")) return false;
767
+ const printableText = extractPrintableText(keyData);
768
+ if (printableText !== undefined && printableText.trim().length === 0) return false;
618
769
  }
619
770
 
620
- const printableText = extractPrintableText(keyData);
621
- if (printableText === undefined) return false;
622
- if (this.#selection.query.length === 0 && printableText.trim().length === 0) return false;
623
-
624
- this.#setFilter(this.#selection.query + printableText, true);
625
- return true;
771
+ const consumed = this.#search.handleInput(keyData);
772
+ const after = this.#search.getValue();
773
+ if (after !== before) this.#setFilter(after, true);
774
+ return consumed;
626
775
  }
627
776
 
628
777
  #setFilter(filter: string, notify: boolean): void {