@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
@@ -11,6 +11,7 @@
11
11
  */
12
12
 
13
13
  import type { Model } from "@oh-my-pi/pi-ai";
14
+ import type { TspPickerAction, TspPickerColumn, TspPickerItem, TspPickerScope, TspSpan } from "@oh-my-pi/pi-wire";
14
15
  import {
15
16
  type Component,
16
17
  Editor,
@@ -25,8 +26,13 @@ import {
25
26
  visibleWidth,
26
27
  wrapTextWithAnsi,
27
28
  } from "../index";
29
+ import { code, col, md, node, row, span, text } from "../native/describe";
30
+ import type { DescribeContext, NativeChild, NativeNode, NativeUiEvent } from "../native/node";
31
+ import { actionHint, type NativeHint, hintsRow } from "../native/overlay";
32
+ import { CLOSE_ACTION, type PickerEvent, picker, pickerEvent, pickerQuery } from "../native/picker";
28
33
  import type { AgentSource } from "../tools/task";
29
34
  import { shortenPath } from "../render/render-utils";
35
+ import { sanitizeDisplaySingleLine } from "./extensions/display-text";
30
36
  import { getEditorTheme, theme } from "../theme";
31
37
  import { matchesAppFollowUp, matchesSelectCancel, matchesSelectDown, matchesSelectUp } from "../keybinding-matchers";
32
38
  import { formatKeyHint, formatKeyHints } from "../app-keybindings";
@@ -39,6 +45,8 @@ import {
39
45
  sortModelItems,
40
46
  } from "./model-browser";
41
47
  import {
48
+ describeHubFrame,
49
+ describeHubSidebar,
42
50
  HubFrame,
43
51
  moveStripSelection,
44
52
  type SidebarEntry as HubSidebarEntry,
@@ -72,6 +80,14 @@ const SOURCE_LABEL: Record<AgentSource, string> = {
72
80
  bundled: "Bundled",
73
81
  };
74
82
  const SOURCE_ORDER: Record<AgentSource, number> = { project: 0, user: 1, bundled: 2 };
83
+ const SOURCES = ["project", "user", "bundled"] as const satisfies readonly AgentSource[];
84
+ /** Per-agent override columns of the config picker; lower priorities hide first. */
85
+ const AGENT_COLUMNS: readonly TspPickerColumn[] = [
86
+ { id: "model", head: "Model", format: "text", priority: 4, min: 8 },
87
+ { id: "prewalk", head: "Prewalk", format: "text", priority: 2 },
88
+ { id: "advisor", head: "Advisor", format: "text", priority: 3 },
89
+ ];
90
+ const SOURCE_COLUMN: TspPickerColumn = { id: "source", head: "Source", format: "dim", priority: 1 };
75
91
 
76
92
  interface SidebarEntry extends HubSidebarEntry<"all" | "source" | "new" | "separator"> {
77
93
  source?: AgentSource;
@@ -160,6 +176,11 @@ function parseGeneratedAgentSpec(raw: string): GeneratedAgentSpec {
160
176
  return { identifier, whenToUse, systemPrompt };
161
177
  }
162
178
 
179
+ /** Stable native list-item id of an agent-list row. */
180
+ function listRowId(rowDef: ListRow): string {
181
+ return rowDef.kind === "new" ? "new" : `agent:${rowDef.agent.source}:${rowDef.agent.name}`;
182
+ }
183
+
163
184
  function matchAgent(agent: HubAgent, query: string): boolean {
164
185
  const text = `${agent.name} ${agent.description} ${SOURCE_LABEL[agent.source]} ${agent.overrideModel ?? ""}`;
165
186
  return query
@@ -187,7 +208,8 @@ export class AgentsHubComponent implements Component {
187
208
  #rowIndex = 0;
188
209
  #rowHover: number | null = null;
189
210
  #listScroll = 0;
190
- #searchQuery = "";
211
+ /** Type-to-filter field for the agent list (chrome-less; the hub draws `search:`). */
212
+ readonly #search = Object.assign(new Input(), { prompt: "" });
191
213
  #notice: string | null = null;
192
214
  #loadError: string | null = null;
193
215
 
@@ -205,6 +227,12 @@ export class AgentsHubComponent implements Component {
205
227
  #createError: string | null = null;
206
228
  #createStreamingText = "";
207
229
 
230
+ /** Bumped on every visible-state change; the described node is rebuilt when it moves. */
231
+ #nativeVersion = 0;
232
+ #nativeCache: { version: number; sheet: boolean; node: NativeNode } | undefined;
233
+ /** Collapsed state of the generated system-prompt card (native only). */
234
+ #promptCollapsed = true;
235
+
208
236
  #renderBodyPane = (width: number, height: number | undefined): readonly string[] => {
209
237
  const rows = Math.max(1, Math.floor(height ?? 10));
210
238
  const lines: string[] = [this.#statusRow(width)];
@@ -260,9 +288,16 @@ export class AgentsHubComponent implements Component {
260
288
 
261
289
  dispose(): void {}
262
290
  invalidate(): void {
291
+ this.#nativeVersion++;
263
292
  this.#frame.invalidate();
264
293
  }
265
294
 
295
+ /** Request a repaint after a state change, invalidating the described node. */
296
+ #requestRender(): void {
297
+ this.#nativeVersion++;
298
+ this.#tui.requestRender();
299
+ }
300
+
266
301
  // ═══════════════════════════════════════════════════════════════════════
267
302
  // Data pipeline
268
303
  // ═══════════════════════════════════════════════════════════════════════
@@ -288,7 +323,7 @@ export class AgentsHubComponent implements Component {
288
323
  this.#buildRows();
289
324
  this.#loadError = error instanceof Error ? error.message : String(error);
290
325
  }
291
- this.#tui.requestRender();
326
+ this.#requestRender();
292
327
  }
293
328
 
294
329
  #buildSidebar(): void {
@@ -324,7 +359,8 @@ export class AgentsHubComponent implements Component {
324
359
  const entry = this.#activeEntry();
325
360
  const scoped =
326
361
  entry.kind === "source" ? this.#allAgents.filter(agent => agent.source === entry.source) : this.#allAgents;
327
- const filtered = this.#searchQuery ? scoped.filter(agent => matchAgent(agent, this.#searchQuery)) : scoped;
362
+ const query = this.#search.getValue();
363
+ const filtered = query ? scoped.filter(agent => matchAgent(agent, query)) : scoped;
328
364
  this.#rows = [...filtered.map(agent => ({ kind: "agent", agent }) as ListRow), { kind: "new" }];
329
365
  }
330
366
 
@@ -345,7 +381,7 @@ export class AgentsHubComponent implements Component {
345
381
  agent.disabled = !agent.disabled;
346
382
  this.#deps.setAgentDisabled(agent.name, { disabled: agent.disabled });
347
383
  this.#notice = `${agent.name} ${agent.disabled ? "disabled" : "enabled"}`;
348
- this.#tui.requestRender();
384
+ this.#requestRender();
349
385
  }
350
386
 
351
387
  #overrideFor(agent: HubAgent, property: PropertyKind): string | undefined {
@@ -374,7 +410,7 @@ export class AgentsHubComponent implements Component {
374
410
  }
375
411
  this.#deps.setAgentOverride(property, agent.name, trimmed);
376
412
  this.#notice = this.#describeProperty(agent, property);
377
- this.#tui.requestRender();
413
+ this.#requestRender();
378
414
  }
379
415
 
380
416
  /** One-line effective description used for notices and the status row. */
@@ -567,7 +603,7 @@ export class AgentsHubComponent implements Component {
567
603
  #cancelAssign(): void {
568
604
  this.#assigning = null;
569
605
  this.#browser.setQuery("");
570
- this.#tui.requestRender();
606
+ this.#requestRender();
571
607
  }
572
608
 
573
609
  // ═══════════════════════════════════════════════════════════════════════
@@ -592,7 +628,7 @@ export class AgentsHubComponent implements Component {
592
628
  this.#createDescription = value;
593
629
  };
594
630
  this.#createInput = editor;
595
- this.#tui.requestRender();
631
+ this.#requestRender();
596
632
  }
597
633
 
598
634
  #clearCreateFlow(): void {
@@ -609,14 +645,14 @@ export class AgentsHubComponent implements Component {
609
645
  this.#createDescription = description;
610
646
  if (!description) {
611
647
  this.#createError = "Description is required.";
612
- this.#tui.requestRender();
648
+ this.#requestRender();
613
649
  return;
614
650
  }
615
651
  this.#createGenerating = true;
616
652
  this.#createError = null;
617
653
  this.#createSpec = null;
618
654
  this.#createStreamingText = "";
619
- this.#tui.requestRender();
655
+ this.#requestRender();
620
656
  try {
621
657
  const spec = await this.#runAgentCreationArchitect(description);
622
658
  this.#createSpec = spec;
@@ -625,14 +661,14 @@ export class AgentsHubComponent implements Component {
625
661
  this.#createError = error instanceof Error ? error.message : String(error);
626
662
  } finally {
627
663
  this.#createGenerating = false;
628
- this.#tui.requestRender();
664
+ this.#requestRender();
629
665
  }
630
666
  }
631
667
 
632
668
  async #runAgentCreationArchitect(description: string): Promise<GeneratedAgentSpec> {
633
669
  const raw = await this.#deps.generateAgent(description, text => {
634
670
  this.#createStreamingText += text;
635
- this.#tui.requestRender();
671
+ this.#requestRender();
636
672
  });
637
673
  return parseGeneratedAgentSpec(raw);
638
674
  }
@@ -651,21 +687,22 @@ export class AgentsHubComponent implements Component {
651
687
  // ═══════════════════════════════════════════════════════════════════════
652
688
 
653
689
  handleInput(data: string): void {
690
+ this.#nativeVersion++;
654
691
  if (data.startsWith("\x1b[<")) {
655
692
  routeSgrMouseInput(data, event => this.#routeMouseEvent(event));
656
- this.#tui.requestRender();
693
+ this.#requestRender();
657
694
  return;
658
695
  }
659
696
 
660
697
  if (this.#strip) {
661
698
  this.#handleStripInput(data);
662
- this.#tui.requestRender();
699
+ this.#requestRender();
663
700
  return;
664
701
  }
665
702
 
666
703
  if (this.#createActive) {
667
704
  this.#handleCreateInput(data);
668
- this.#tui.requestRender();
705
+ this.#requestRender();
669
706
  return;
670
707
  }
671
708
 
@@ -674,11 +711,11 @@ export class AgentsHubComponent implements Component {
674
711
  this.#cancelAssign();
675
712
  return;
676
713
  }
677
- if (this.#searchQuery.length > 0) {
678
- this.#searchQuery = "";
714
+ if (this.#search.getValue()) {
715
+ this.#search.setValue("");
679
716
  this.#buildRows();
680
717
  this.#clampRowIndex();
681
- this.#tui.requestRender();
718
+ this.#requestRender();
682
719
  return;
683
720
  }
684
721
  this.#callbacks.onCancel();
@@ -687,7 +724,7 @@ export class AgentsHubComponent implements Component {
687
724
 
688
725
  if (this.#assigning) {
689
726
  this.#browser.handleInput(data);
690
- this.#tui.requestRender();
727
+ this.#requestRender();
691
728
  return;
692
729
  }
693
730
 
@@ -698,29 +735,29 @@ export class AgentsHubComponent implements Component {
698
735
 
699
736
  if (matchesKey(data, "tab") || matchesKey(data, "shift+tab")) {
700
737
  this.#focus = this.#focus === "scope" ? "list" : "scope";
701
- this.#tui.requestRender();
738
+ this.#requestRender();
702
739
  return;
703
740
  }
704
741
  if (matchesKey(data, "left")) {
705
742
  this.#focus = "scope";
706
- this.#tui.requestRender();
743
+ this.#requestRender();
707
744
  return;
708
745
  }
709
746
  if (matchesKey(data, "right")) {
710
747
  this.#focus = "list";
711
- this.#tui.requestRender();
748
+ this.#requestRender();
712
749
  return;
713
750
  }
714
751
 
715
752
  if (this.#focus === "scope") {
716
753
  if (matchesSelectUp(data)) {
717
754
  this.#moveSidebar(-1);
718
- this.#tui.requestRender();
755
+ this.#requestRender();
719
756
  return;
720
757
  }
721
758
  if (matchesSelectDown(data)) {
722
759
  this.#moveSidebar(1);
723
- this.#tui.requestRender();
760
+ this.#requestRender();
724
761
  return;
725
762
  }
726
763
  if (matchesKey(data, "enter") || matchesKey(data, "return") || data === "\n") {
@@ -729,48 +766,47 @@ export class AgentsHubComponent implements Component {
729
766
  } else {
730
767
  this.#focus = "list";
731
768
  }
732
- this.#tui.requestRender();
769
+ this.#requestRender();
733
770
  return;
734
771
  }
735
772
  }
736
773
 
737
774
  if (matchesSelectUp(data)) {
738
775
  this.#rowIndex = Math.max(0, this.#rowIndex - 1);
739
- this.#tui.requestRender();
776
+ this.#requestRender();
740
777
  return;
741
778
  }
742
779
  if (matchesSelectDown(data)) {
743
780
  this.#rowIndex = Math.min(this.#rows.length - 1, this.#rowIndex + 1);
744
- this.#tui.requestRender();
781
+ this.#requestRender();
745
782
  return;
746
783
  }
747
784
  if (matchesKey(data, "enter") || matchesKey(data, "return") || data === "\n") {
748
785
  this.#activateRow(this.#rows[this.#rowIndex]);
749
- this.#tui.requestRender();
786
+ this.#requestRender();
750
787
  return;
751
788
  }
752
- if (data === " " && this.#searchQuery.length === 0) {
789
+ if (data === " " && !this.#search.getValue()) {
753
790
  const agent = this.#selectedAgent();
754
791
  if (agent) this.#toggleAgent(agent);
755
792
  return;
756
793
  }
757
- if (matchesKey(data, "backspace")) {
758
- if (this.#searchQuery.length > 0) {
759
- this.#searchQuery = this.#searchQuery.slice(0, -1);
760
- this.#buildRows();
761
- this.#clampRowIndex();
762
- this.#tui.requestRender();
763
- }
764
- return;
765
- }
766
- // Type-to-filter: any printable character extends the query.
767
- if (data.length === 1 && data >= " " && data !== "\x7f") {
768
- this.#searchQuery += data;
794
+ // Type-to-filter: every other key edits the search field.
795
+ const before = this.#search.getValue();
796
+ if (!this.#search.handleInput(data)) return;
797
+ const value = this.#search.getValue();
798
+ if (value === before) {
799
+ this.#requestRender();
800
+ } else if (value.length < before.length) {
801
+ this.#buildRows();
802
+ this.#clampRowIndex();
803
+ this.#requestRender();
804
+ } else {
769
805
  this.#focus = "list";
770
806
  this.#buildRows();
771
807
  this.#rowIndex = 0;
772
808
  this.#listScroll = 0;
773
- this.#tui.requestRender();
809
+ this.#requestRender();
774
810
  }
775
811
  }
776
812
 
@@ -787,16 +823,7 @@ export class AgentsHubComponent implements Component {
787
823
  const strip = this.#strip;
788
824
  if (!strip) return;
789
825
  if (matchesSelectCancel(data)) {
790
- // A property strip steps back up to the agent strip instead of closing.
791
- if (strip.kind === "chips" && strip.property) {
792
- this.#openAgentStrip(strip.agent);
793
- return;
794
- }
795
- if (strip.kind === "pattern") {
796
- this.#openPropertyStrip(strip.agent, strip.property);
797
- return;
798
- }
799
- this.#closeStrip();
826
+ this.#stripBack(strip);
800
827
  return;
801
828
  }
802
829
  if (strip.kind === "pattern") {
@@ -814,6 +841,19 @@ export class AgentsHubComponent implements Component {
814
841
  }
815
842
  }
816
843
 
844
+ /** Esc on a strip: a property strip steps back up to the agent strip, the agent strip closes. */
845
+ #stripBack(strip: StripState): void {
846
+ if (strip.kind === "chips" && strip.property) {
847
+ this.#openAgentStrip(strip.agent);
848
+ return;
849
+ }
850
+ if (strip.kind === "pattern") {
851
+ this.#openPropertyStrip(strip.agent, strip.property);
852
+ return;
853
+ }
854
+ this.#closeStrip();
855
+ }
856
+
817
857
  #handleCreateInput(data: string): void {
818
858
  if (this.#createSpec) {
819
859
  if (matchesSelectCancel(data)) {
@@ -831,7 +871,7 @@ export class AgentsHubComponent implements Component {
831
871
  if (matchesKey(data, "enter") || matchesKey(data, "return") || data === "\n") {
832
872
  void this.#saveGeneratedAgent().catch(error => {
833
873
  this.#createError = error instanceof Error ? error.message : String(error);
834
- this.#tui.requestRender();
874
+ this.#requestRender();
835
875
  });
836
876
  }
837
877
  return;
@@ -990,7 +1030,10 @@ export class AgentsHubComponent implements Component {
990
1030
 
991
1031
  #renderList(width: number, rows: number): string[] {
992
1032
  const lines: string[] = [];
993
- const searchText = this.#searchQuery ? theme.fg("accent", this.#searchQuery) : theme.fg("dim", "type to filter");
1033
+ const query = this.#search.getValue();
1034
+ const searchText = query
1035
+ ? theme.fg("accent", this.#search.render(visibleWidth(query) + 1)[0] ?? "")
1036
+ : theme.fg("dim", "type to filter");
994
1037
  lines.push(truncateToWidth(` ${theme.fg("muted", "search:")} ${searchText}`, width));
995
1038
  lines.push("");
996
1039
  this.#listRowStart = lines.length;
@@ -1200,6 +1243,598 @@ export class AgentsHubComponent implements Component {
1200
1243
  return this.#frame.renderChips(width, prefix, strip);
1201
1244
  }
1202
1245
 
1246
+ // ═══════════════════════════════════════════════════════════════════════
1247
+ // Native (TSP) description
1248
+ // ═══════════════════════════════════════════════════════════════════════
1249
+
1250
+ /**
1251
+ * The agent list (and its chip strips) is a `picker` sheet. The pattern
1252
+ * input, the model browser and the create wizard stay the generic overlay.
1253
+ */
1254
+ nativeSheet(cx: DescribeContext): boolean {
1255
+ return cx.supports("picker") && !this.#createActive && !this.#assigning && this.#strip?.kind !== "pattern";
1256
+ }
1257
+
1258
+ describe(cx: DescribeContext): NativeNode {
1259
+ const sheet = this.nativeSheet(cx);
1260
+ const cached = this.#nativeCache;
1261
+ if (cached?.version === this.#nativeVersion && cached.sheet === sheet) return cached.node;
1262
+ if (sheet) {
1263
+ const described = this.#describePicker();
1264
+ this.#nativeCache = { version: this.#nativeVersion, sheet, node: described };
1265
+ return described;
1266
+ }
1267
+ const footer: NativeChild[] = [];
1268
+ const strip = this.#describeStrip();
1269
+ if (strip) footer.push(strip);
1270
+ footer.push(hintsRow(this.#footerHints()));
1271
+ const described = describeHubFrame(
1272
+ "omp.hub.agents",
1273
+ "Agents",
1274
+ describeHubSidebar(this.#entries, this.#activeEntryId, this.#sidebarStyle, "scopes"),
1275
+ this.#describeBody(),
1276
+ node("col", { gap: "xs" }, footer, "footer"),
1277
+ );
1278
+ this.#nativeCache = { version: this.#nativeVersion, sheet, node: described };
1279
+ return described;
1280
+ }
1281
+
1282
+ handleNativeEvent(event: NativeUiEvent): void {
1283
+ const target = event.key.slice(event.key.lastIndexOf("/") + 1);
1284
+ const pick = pickerEvent(event);
1285
+ if (pick) {
1286
+ this.#handlePickerEvent(pick);
1287
+ this.#requestRender();
1288
+ return;
1289
+ }
1290
+ if (event.type === "toggle") {
1291
+ if (target !== "prompt") return;
1292
+ this.#promptCollapsed = event.collapsed;
1293
+ } else if (event.type === "select" || event.type === "activate") {
1294
+ const activate = event.type === "activate";
1295
+ if (target === "strip") {
1296
+ const strip = this.#strip;
1297
+ const index = Number(event.item);
1298
+ if (strip?.kind !== "chips" || !Number.isInteger(index) || !strip.chips[index]) return;
1299
+ strip.index = index;
1300
+ if (activate) this.#activateStripChip();
1301
+ } else if (target === "agents") {
1302
+ // Like the mouse path: the list is inert under a strip, the create flow, or the model browser.
1303
+ if (this.#strip || this.#createActive || this.#assigning) return;
1304
+ const index = this.#rows.findIndex(rowDef => listRowId(rowDef) === event.item);
1305
+ if (index < 0) return;
1306
+ this.#focus = "list";
1307
+ this.#rowIndex = index;
1308
+ if (activate) this.#activateRow(this.#rows[index]);
1309
+ } else if (target === "scopes") {
1310
+ if (this.#strip || this.#createActive || this.#assigning) return;
1311
+ const entry = this.#entries.find(candidate => candidate.id === event.item);
1312
+ if (!entry || entry.kind === "separator") return;
1313
+ if (entry.kind === "new") {
1314
+ this.#beginCreateFlow();
1315
+ } else {
1316
+ this.#activeEntryId = entry.id;
1317
+ this.#buildRows();
1318
+ this.#rowIndex = 0;
1319
+ this.#listScroll = 0;
1320
+ this.#focus = activate ? "list" : "scope";
1321
+ }
1322
+ } else {
1323
+ return;
1324
+ }
1325
+ } else {
1326
+ return;
1327
+ }
1328
+ this.#requestRender();
1329
+ }
1330
+
1331
+ /** Picker pointer events: each runs the path of the key it stands for. */
1332
+ #handlePickerEvent(pick: PickerEvent): void {
1333
+ const strip = this.#strip;
1334
+ if (pick.kind !== "action") {
1335
+ if (strip) return; // the list is inert under a strip, like the mouse path
1336
+ const index = this.#rows.findIndex(rowDef => listRowId(rowDef) === pick.item);
1337
+ if (index < 0) return;
1338
+ this.#focus = "list";
1339
+ this.#rowIndex = index;
1340
+ if (pick.kind === "activate") this.#activateRow(this.#rows[index]);
1341
+ return;
1342
+ }
1343
+ if (pick.act === "close") {
1344
+ this.#callbacks.onCancel();
1345
+ return;
1346
+ }
1347
+ if (strip?.kind === "chips") {
1348
+ if (pick.act === "strip") {
1349
+ const index = Number(pick.value);
1350
+ if (!Number.isInteger(index) || !strip.chips[index]) return;
1351
+ strip.index = index;
1352
+ this.#activateStripChip();
1353
+ } else if (pick.act === "apply") {
1354
+ this.#activateStripChip();
1355
+ } else if (pick.act === "back") {
1356
+ this.#stripBack(strip);
1357
+ }
1358
+ return;
1359
+ }
1360
+ const agent = this.#selectedAgent();
1361
+ switch (pick.act) {
1362
+ case "scope": {
1363
+ const entry = this.#entries.find(candidate => candidate.id === pick.value);
1364
+ if (!entry || entry.kind === "separator" || entry.kind === "new") return;
1365
+ this.#activeEntryId = entry.id;
1366
+ this.#buildRows();
1367
+ this.#rowIndex = 0;
1368
+ this.#listScroll = 0;
1369
+ this.#focus = "scope";
1370
+ return;
1371
+ }
1372
+ case "configure":
1373
+ this.#activateRow(this.#rows[this.#rowIndex]);
1374
+ return;
1375
+ case "toggle":
1376
+ if (agent) this.#toggleAgent(agent);
1377
+ return;
1378
+ case "model":
1379
+ if (agent) this.#openPropertyStrip(agent, "model");
1380
+ return;
1381
+ case "new":
1382
+ this.#beginCreateFlow();
1383
+ return;
1384
+ case "reload":
1385
+ void this.#reload();
1386
+ return;
1387
+ }
1388
+ }
1389
+
1390
+ /** The config hub as a `picker` (§9.1): source scopes, override columns, prompt preview. */
1391
+ #describePicker(): NativeNode {
1392
+ const counts: Record<AgentSource, number> = { project: 0, user: 0, bundled: 0 };
1393
+ for (const agent of this.#allAgents) counts[agent.source]++;
1394
+ const scopes: TspPickerScope[] = [
1395
+ { id: "all", label: "All agents", icon: "users", count: this.#allAgents.length },
1396
+ ...SOURCES.map((source): TspPickerScope => ({
1397
+ id: `source:${source}`,
1398
+ label: SOURCE_LABEL[source],
1399
+ icon: source === "project" ? "folder" : source === "user" ? "user" : "box",
1400
+ count: counts[source],
1401
+ group: "Source",
1402
+ disabled: counts[source] === 0 ? `No ${source} agents` : undefined,
1403
+ })),
1404
+ ];
1405
+ const entry = this.#activeEntry();
1406
+ const strip = this.#strip?.kind === "chips" ? this.#strip : null;
1407
+ const agent = this.#selectedAgent();
1408
+ let actions: TspPickerAction[];
1409
+ if (strip) {
1410
+ actions = [
1411
+ { id: "apply", label: strip.property ? "Apply" : "Open", keys: ["enter"], primary: true },
1412
+ { id: "back", label: strip.property ? "Back" : "Cancel", keys: ["esc"], end: true },
1413
+ ];
1414
+ } else {
1415
+ const noAgent = agent ? undefined : "Select an agent";
1416
+ actions = [
1417
+ { id: "configure", label: agent ? "Configure" : "Create", keys: ["enter"], primary: true },
1418
+ {
1419
+ id: "toggle",
1420
+ label: "Toggle",
1421
+ keys: ["space"],
1422
+ on: agent ? !agent.disabled : undefined,
1423
+ disabled: noAgent,
1424
+ },
1425
+ { id: "model", label: "Model", disabled: noAgent },
1426
+ { id: "new", label: "New agent" },
1427
+ { id: "reload", label: "Reload", keys: ["ctrl", "r"] },
1428
+ CLOSE_ACTION,
1429
+ ];
1430
+ }
1431
+ const selectedRow = this.#rows[this.#rowIndex];
1432
+ return picker(
1433
+ {
1434
+ title: "Agents",
1435
+ subtitle: this.#notice ?? undefined,
1436
+ icon: "users",
1437
+ noun: "agents",
1438
+ size: "lg",
1439
+ layout: "rows",
1440
+ preview: "side",
1441
+ ...pickerQuery(this.#search),
1442
+ placeholder: "Search agents…",
1443
+ scopes,
1444
+ scope: entry.kind === "source" ? entry.id : "all",
1445
+ columns: entry.kind === "source" ? AGENT_COLUMNS : [...AGENT_COLUMNS, SOURCE_COLUMN],
1446
+ items: this.#rows.map(rowDef => this.#pickerItem(rowDef)),
1447
+ selected: selectedRow ? listRowId(selectedRow) : null,
1448
+ total: entry.kind === "source" && entry.source ? counts[entry.source] : this.#allAgents.length,
1449
+ state: this.#loadError ? "error" : "ready",
1450
+ message: this.#loadError ?? undefined,
1451
+ strip: strip
1452
+ ? {
1453
+ label: strip.property ? `${strip.agent.name} · ${strip.property}` : strip.agent.name,
1454
+ items: strip.chips.map((chip, index) => ({
1455
+ id: String(index),
1456
+ label: this.#stripChipLabel(strip.agent, chip),
1457
+ on: this.#stripChipOn(strip.agent, strip.property, chip),
1458
+ })),
1459
+ selected: String(strip.index),
1460
+ }
1461
+ : null,
1462
+ actions,
1463
+ focus: strip ? "strip" : this.#focus === "scope" ? "scopes" : "list",
1464
+ },
1465
+ this.#describePreview(selectedRow),
1466
+ );
1467
+ }
1468
+
1469
+ #pickerItem(rowDef: ListRow): TspPickerItem {
1470
+ if (rowDef.kind === "new") {
1471
+ return { id: listRowId(rowDef), label: "New agent…", icon: "plus", tone: "muted" };
1472
+ }
1473
+ const agent = rowDef.agent;
1474
+ const prewalk = this.#deps.effectivePrewalkPattern(agent);
1475
+ const advisor = this.#deps.effectiveAdvisorPattern(agent);
1476
+ return {
1477
+ id: listRowId(rowDef),
1478
+ label: agent.name,
1479
+ mono: true,
1480
+ detail: sanitizeDisplaySingleLine(agent.description),
1481
+ dot: agent.disabled ? "muted" : "success",
1482
+ disabled: agent.disabled ? "Disabled · space to enable" : undefined,
1483
+ facts: {
1484
+ model: agent.overrideModel ? agent.overrideModel : [span("auto", "dim")],
1485
+ prewalk: prewalk ?? [span("off", "dim")],
1486
+ advisor: advisor ?? [span("off", "dim")],
1487
+ source: SOURCE_LABEL[agent.source],
1488
+ },
1489
+ };
1490
+ }
1491
+
1492
+ /** Chip text of a configuration strip, without the ANSI state glyphs (the chip's `on` carries state). */
1493
+ #stripChipLabel(agent: HubAgent, chip: StripChip): string {
1494
+ const action = chip.action;
1495
+ if (action.kind === "toggle") return agent.disabled ? "Enable" : "Disable";
1496
+ if (action.kind === "property") return `${action.property}: ${this.#propertySummary(agent, action.property)}`;
1497
+ return chip.label;
1498
+ }
1499
+
1500
+ #stripChipOn(agent: HubAgent, property: PropertyKind | undefined, chip: StripChip): boolean | undefined {
1501
+ const action = chip.action;
1502
+ if (action.kind !== "set" || action.property === "model" || !property) return undefined;
1503
+ return this.#overrideFor(agent, property)?.toLowerCase() === action.value;
1504
+ }
1505
+
1506
+ /** Preview of the selected agent: description, effective settings, system prompt. */
1507
+ #describePreview(rowDef: ListRow | undefined): NativeChild[] {
1508
+ if (!rowDef) return [];
1509
+ if (rowDef.kind === "new") {
1510
+ return [
1511
+ text("New agent", { role: "omp.picker.title" }),
1512
+ md(
1513
+ "Describe what the agent should do; the architect drafts its name, when to use it and its system prompt.",
1514
+ ),
1515
+ ];
1516
+ }
1517
+ const agent = rowDef.agent;
1518
+ const patterns = this.#deps.effectiveModelPatterns(agent);
1519
+ const resolved = this.#deps.resolvePatterns(patterns);
1520
+ const model: TspSpan[] = [patterns.length > 0 ? span(patterns.join(","), "mono") : span("session model", "dim")];
1521
+ if (resolved) model.push(span(" → ", "dim"), span(resolved, "mono success"));
1522
+ const prewalk = this.#deps.effectivePrewalkPattern(agent);
1523
+ const advisor = this.#deps.effectiveAdvisorPattern(agent);
1524
+ const facts: { k: string; v: TspSpan[] | string }[] = [
1525
+ { k: "Model", v: model },
1526
+ { k: "Prewalk", v: [prewalk ? span(prewalk, "mono") : span("off", "dim")] },
1527
+ { k: "Advisor", v: [advisor ? span(advisor, "mono") : span("off", "dim")] },
1528
+ { k: "Status", v: [agent.disabled ? span("Disabled", "warning") : span("Enabled", "success")] },
1529
+ { k: "Source", v: SOURCE_LABEL[agent.source] },
1530
+ ];
1531
+ if (agent.filePath) {
1532
+ // Bundled agents live in the binary (`embedded:…`): nothing to open.
1533
+ const href = agent.filePath.startsWith("/") ? { href: `file://${agent.filePath}` } : undefined;
1534
+ facts.push({ k: "File", v: [span(shortenPath(agent.filePath), "path", href)] });
1535
+ }
1536
+ const out: NativeChild[] = [
1537
+ node("text", { text: agent.name, role: "omp.picker.title" }, undefined, "title"),
1538
+ node("md", { text: agent.description }, undefined, "description"),
1539
+ node("kv", { items: facts, layout: "grid" }, undefined, "facts"),
1540
+ ];
1541
+ if (agent.systemPrompt.trim()) {
1542
+ out.push(
1543
+ node(
1544
+ "section",
1545
+ { head: "System prompt", role: "omp.agents.prompt" },
1546
+ [code(agent.systemPrompt, { lang: "md", wrap: true })],
1547
+ "prompt",
1548
+ ),
1549
+ );
1550
+ }
1551
+ return out;
1552
+ }
1553
+
1554
+ #describeBody(): NativeNode {
1555
+ const children: NativeChild[] = [
1556
+ node("text", { spans: this.#statusSpans(), truncate: "end" }, undefined, "status"),
1557
+ ];
1558
+ if (this.#createActive) {
1559
+ children.push(...this.#describeCreate());
1560
+ } else if (this.#assigning) {
1561
+ this.#browser.setFocused(true);
1562
+ children.push(this.#browser);
1563
+ } else {
1564
+ children.push(...this.#describeList());
1565
+ }
1566
+ return node("col", { gap: "sm", grow: 1 }, children, "body");
1567
+ }
1568
+
1569
+ #statusSpans(): TspSpan[] {
1570
+ if (this.#loadError) return [span(this.#loadError, "error")];
1571
+ if (this.#assigning) {
1572
+ const { agent, property } = this.#assigning;
1573
+ const what = property === "model" ? "model override" : `${property} model`;
1574
+ return [span(`Picking ${what} for `, "accent"), span(agent.name, "accent strong")];
1575
+ }
1576
+ if (this.#createActive) return [span("New agent — describe it and let the architect draft it", "accent")];
1577
+ if (this.#notice) return [span(this.#notice, "success")];
1578
+ const entry = this.#activeEntry();
1579
+ const scopeLabel = entry.kind === "source" ? `${entry.label} agents` : "All agents";
1580
+ const count = this.#rows.filter(rowDef => rowDef.kind === "agent").length;
1581
+ return [span(`${scopeLabel} · ${count}`, "muted")];
1582
+ }
1583
+
1584
+ #describeList(): NativeNode[] {
1585
+ const search = node(
1586
+ "text",
1587
+ {
1588
+ spans: [
1589
+ span("search: ", "muted"),
1590
+ this.#search.getValue() ? span(this.#search.getValue(), "accent") : span("type to filter", "dim"),
1591
+ ],
1592
+ truncate: "end",
1593
+ },
1594
+ undefined,
1595
+ "search",
1596
+ );
1597
+ const items = this.#rows.map(rowDef =>
1598
+ rowDef.kind === "new"
1599
+ ? node("item", { label: [span("+ New agent…", "dim")] }, undefined, listRowId(rowDef))
1600
+ : this.#describeAgentItem(rowDef.agent),
1601
+ );
1602
+ const selectedRow = this.#rows[this.#rowIndex];
1603
+ const list = node(
1604
+ "list",
1605
+ {
1606
+ selected: selectedRow ? listRowId(selectedRow) : null,
1607
+ filter: this.#search.getValue() || undefined,
1608
+ virtual: true,
1609
+ grow: 1,
1610
+ tone: this.#focus === "list" ? "accent" : undefined,
1611
+ aria: "Agents",
1612
+ },
1613
+ items,
1614
+ "agents",
1615
+ );
1616
+ return [search, list, this.#describeDetail()];
1617
+ }
1618
+
1619
+ #describeAgentItem(agent: HubAgent): NativeNode {
1620
+ const value: TspSpan[] = [];
1621
+ const badge = (t: string, s: string): void => {
1622
+ if (value.length > 0) value.push(span(" "));
1623
+ value.push(span(t, s));
1624
+ };
1625
+ if (agent.overrideModel) badge(agent.overrideModel, "warning");
1626
+ const prewalk = this.#deps.effectivePrewalkPattern(agent);
1627
+ if (prewalk) badge(`pre:${prewalk}`, "dim");
1628
+ const advisor = this.#deps.effectiveAdvisorPattern(agent);
1629
+ if (advisor) badge(`adv:${advisor}`, "dim");
1630
+ return node(
1631
+ "item",
1632
+ {
1633
+ label: [
1634
+ agent.disabled ? span(`${theme.status.disabled} `, "dim") : span(`${theme.status.enabled} `, "success"),
1635
+ span(agent.name, agent.disabled ? "dim" : "strong"),
1636
+ ],
1637
+ detail: [span(SOURCE_LABEL[agent.source].toLowerCase(), "dim")],
1638
+ value: value.length > 0 ? value : undefined,
1639
+ tone: agent.disabled ? "muted" : undefined,
1640
+ },
1641
+ undefined,
1642
+ listRowId({ kind: "agent", agent }),
1643
+ );
1644
+ }
1645
+
1646
+ /** Selected-agent detail block under the list. */
1647
+ #describeDetail(): NativeNode {
1648
+ const agent = this.#selectedAgent();
1649
+ if (!agent) {
1650
+ return node("section", {}, [text([span("Select an agent to inspect", "dim")])], "detail");
1651
+ }
1652
+ const patterns = this.#deps.effectiveModelPatterns(agent);
1653
+ const resolved = this.#deps.resolvePatterns(patterns);
1654
+ const model: TspSpan[] = [patterns.length > 0 ? span(patterns.join(",")) : span("(session model)", "dim")];
1655
+ if (resolved) model.push(span(" → ", "dim"), span(resolved, "success"));
1656
+ const prewalk = this.#deps.effectivePrewalkPattern(agent);
1657
+ const advisor = this.#deps.effectiveAdvisorPattern(agent);
1658
+ const children: NativeChild[] = [
1659
+ text([span(agent.description, "dim")], { wrap: "word", lines: 2 }),
1660
+ node("kv", {
1661
+ items: [
1662
+ { k: [span("model", "muted")], v: model },
1663
+ { k: [span("prewalk", "muted")], v: [prewalk ? span(prewalk, "success") : span("off", "dim")] },
1664
+ { k: [span("advisor", "muted")], v: [advisor ? span(advisor, "success") : span("off", "dim")] },
1665
+ ],
1666
+ layout: "inline",
1667
+ }),
1668
+ ];
1669
+ if (agent.filePath) children.push(text([span(shortenPath(agent.filePath), "path dim")], { truncate: "middle" }));
1670
+ return node("section", { head: [span(agent.name, "accent strong")] }, children, "detail");
1671
+ }
1672
+
1673
+ #describeCreate(): NativeChild[] {
1674
+ const nodes: NativeChild[] = [];
1675
+ const spec = this.#createSpec;
1676
+ if (spec) {
1677
+ nodes.push(
1678
+ text([span("Review generated agent", "accent strong")]),
1679
+ node("kv", {
1680
+ items: [
1681
+ { k: [span("Identifier", "muted")], v: [span(spec.identifier, "code")] },
1682
+ { k: [span("Scope", "muted")], v: [span(this.#createScope, "accent")] },
1683
+ ],
1684
+ }),
1685
+ node("section", { head: [span("whenToUse", "muted")] }, [text(spec.whenToUse, { wrap: "word", lines: 6 })]),
1686
+ node(
1687
+ "card",
1688
+ {
1689
+ head: [span("System prompt", "muted")],
1690
+ collapsible: true,
1691
+ collapsed: this.#promptCollapsed,
1692
+ preview: { lines: 8 },
1693
+ },
1694
+ [md(spec.systemPrompt)],
1695
+ "prompt",
1696
+ ),
1697
+ );
1698
+ } else {
1699
+ nodes.push(
1700
+ text([span("Create new agent", "accent strong")]),
1701
+ text([span("Describe what the agent should do; scope: ", "muted"), span(this.#createScope, "accent")], {
1702
+ wrap: "word",
1703
+ }),
1704
+ );
1705
+ if (this.#createInput && !this.#createGenerating) {
1706
+ nodes.push(this.#createInput);
1707
+ }
1708
+ if (this.#createGenerating) {
1709
+ nodes.push(node("spinner", { label: "Generating…" }, undefined, "generating"));
1710
+ if (this.#createStreamingText) {
1711
+ nodes.push(
1712
+ node("code", { text: this.#createStreamingText, lang: "json", wrap: true }, undefined, "stream"),
1713
+ );
1714
+ }
1715
+ }
1716
+ }
1717
+ if (this.#createError) {
1718
+ nodes.push(node("text", { text: this.#createError, tone: "error", wrap: "word" }, undefined, "error"));
1719
+ }
1720
+ return nodes;
1721
+ }
1722
+
1723
+ /** Styled spans of one footer chip, from its action rather than its ANSI label. */
1724
+ #chipSpans(agent: HubAgent, property: PropertyKind | undefined, chip: StripChip): TspSpan[] {
1725
+ const action = chip.action;
1726
+ switch (action.kind) {
1727
+ case "toggle":
1728
+ return chip.label === "enable"
1729
+ ? [span(`${theme.status.enabled} enable`, "success")]
1730
+ : [span(`${theme.status.disabled} disable`, "dim")];
1731
+ case "property":
1732
+ return [span(action.property, "accent"), span(`: ${this.#propertySummary(agent, action.property)}`, "dim")];
1733
+ case "set": {
1734
+ if (action.property === "model") return [span(chip.label, "warning")];
1735
+ const current = property ? this.#overrideFor(agent, property)?.toLowerCase() : undefined;
1736
+ return current === action.value
1737
+ ? [span(`${theme.status.enabled} ${chip.label}`, "accent")]
1738
+ : [span(chip.label, "muted")];
1739
+ }
1740
+ case "pick":
1741
+ return [span(chip.label, "accent")];
1742
+ case "pattern":
1743
+ return [span(chip.label, "muted")];
1744
+ }
1745
+ }
1746
+
1747
+ #describeStrip(): NativeNode | undefined {
1748
+ const strip = this.#strip;
1749
+ if (!strip) return undefined;
1750
+ if (strip.kind === "pattern") {
1751
+ return node(
1752
+ "row",
1753
+ { gap: "sm", align: "center" },
1754
+ [text([span(`${strip.agent.name} ${strip.property} pattern:`, "accent")]), col([strip.input], { grow: 1 })],
1755
+ "pattern",
1756
+ );
1757
+ }
1758
+ const prefix: TspSpan[] = strip.property
1759
+ ? [span(strip.agent.name, "accent"), span(` · ${strip.property} →`, "dim")]
1760
+ : [span(strip.agent.name, "accent"), span(" →", "dim")];
1761
+ return row(
1762
+ [
1763
+ text(prefix),
1764
+ node(
1765
+ "tabs",
1766
+ {
1767
+ items: strip.chips.map((chip, index) => ({
1768
+ id: String(index),
1769
+ label: this.#chipSpans(strip.agent, strip.property, chip),
1770
+ })),
1771
+ active: String(strip.index),
1772
+ actions: { click: "activate" },
1773
+ },
1774
+ undefined,
1775
+ "strip",
1776
+ ),
1777
+ ],
1778
+ { gap: "sm", align: "center" },
1779
+ );
1780
+ }
1781
+
1782
+ #footerHints(): (NativeHint | undefined)[] {
1783
+ const cancel = (label: string) => actionHint("tui.select.cancel", label);
1784
+ const upDown = (label: string) => actionHint(["tui.select.up", "tui.select.down"], label);
1785
+ const strip = this.#strip;
1786
+ if (strip) {
1787
+ if (strip.kind === "pattern") {
1788
+ const values = strip.property === "model" ? "a model pattern" : '"on", "off", or a model pattern';
1789
+ return [
1790
+ { keys: ["enter"], label: `${values} (role aliases like @smol and :level suffixes work; empty clears)` },
1791
+ cancel("back"),
1792
+ ];
1793
+ }
1794
+ return [
1795
+ { keys: ["left", "right"], label: "choose" },
1796
+ { keys: ["enter"], label: strip.property ? "apply" : "open" },
1797
+ cancel(strip.property ? "back" : "cancel"),
1798
+ ];
1799
+ }
1800
+ if (this.#assigning) {
1801
+ return [
1802
+ { keys: ["enter"], label: "pick" },
1803
+ upDown("models"),
1804
+ { keys: [], label: "type to search" },
1805
+ cancel("cancel"),
1806
+ ];
1807
+ }
1808
+ if (this.#createActive) {
1809
+ if (this.#createSpec) {
1810
+ return [
1811
+ { keys: ["enter"], label: "save" },
1812
+ { keys: ["tab"], label: "scope" },
1813
+ { keys: ["r"], label: "regenerate" },
1814
+ cancel("cancel"),
1815
+ ];
1816
+ }
1817
+ if (this.#createGenerating) return [];
1818
+ return [
1819
+ { keys: boundKeys("app.message.followUp", ["ctrl+q", "ctrl+enter"]), label: "generate" },
1820
+ { keys: ["enter"], label: "newline" },
1821
+ { keys: ["tab"], label: "scope" },
1822
+ cancel("cancel"),
1823
+ ];
1824
+ }
1825
+ if (this.#focus === "scope") {
1826
+ return [upDown("scopes"), { keys: ["right", "enter"], label: "agents" }, cancel("close")];
1827
+ }
1828
+ return [
1829
+ { keys: ["enter"], label: "configure" },
1830
+ { keys: ["space"], label: "enable/disable" },
1831
+ upDown("rows"),
1832
+ { keys: [], label: "type to search" },
1833
+ { keys: ["ctrl+r"], label: "reload" },
1834
+ cancel("close"),
1835
+ ];
1836
+ }
1837
+
1203
1838
  render(width: number): readonly string[] {
1204
1839
  return this.#frame.render(width, this.#terminalRows(), this.#entries, this.#renderFooter(width - 4));
1205
1840
  }