@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
@@ -0,0 +1,112 @@
1
+ /**
2
+ * The describe contract: how components hand the Tern Surface Protocol (TSP)
3
+ * backend a semantic description instead of rendered rows.
4
+ *
5
+ * A component opts in with `describe(cx)`, returning a {@link NativeNode}: a
6
+ * wire node without ids. Children are either nested nodes or other
7
+ * components; a component child is a describe boundary the reconciler visits
8
+ * on its own, so each component owns a stable id prefix and can be skipped
9
+ * when it returns the same node object it returned last time (the same
10
+ * reference contract as `render()`). A component without `describe` becomes a
11
+ * `rows` fallback node rendered through `render(cx.cols)`.
12
+ *
13
+ * See `packages/wire/src/tsp.ts` for the wire vocabulary and
14
+ * `crates/tern/SURFACE_PROTOCOL.md` (Stencil repository) for the spec.
15
+ */
16
+ import type { TspEvent, TspKind, TspProps, TspSpan } from "@oh-my-pi/pi-wire";
17
+ import type { Component } from "../tui";
18
+
19
+ /** A described node: a wire node minus its id, with components allowed as children. */
20
+ export type NativeNode = {
21
+ [K in TspKind]: {
22
+ readonly k: K;
23
+ readonly p?: TspProps<K>;
24
+ readonly c?: readonly NativeChild[];
25
+ /**
26
+ * Identity among its siblings inside the owning component (defaults to
27
+ * the child index). Give keys to children that can be inserted, removed
28
+ * or reordered so their ids and terminal-side view state survive.
29
+ */
30
+ readonly key?: string;
31
+ };
32
+ }[TspKind];
33
+
34
+ /** A child slot: a described node, or a component that describes itself. */
35
+ export type NativeChild = NativeNode | Component;
36
+
37
+ /** What a component may consult while describing itself. Never a clock: motion is terminal-clocked. */
38
+ export interface DescribeContext {
39
+ /** Surface width in cells; only for `rows` fallback and ANSI wrap hints. */
40
+ readonly cols: number;
41
+ /** The terminal asked for reduced motion. */
42
+ readonly reduceMotion: boolean;
43
+ /** The terminal's appearance is dark. */
44
+ readonly dark: boolean;
45
+ /** Whether the terminal renders `kind` natively (else describe something simpler or let it fall back). */
46
+ supports(kind: TspKind): boolean;
47
+ /**
48
+ * Whether the terminal's `hello` advertised protocol feature `name`
49
+ * (`aside`: a `prefs` page in `layer` docks as a sheet at the pane's right
50
+ * edge, the transcript narrowed beside it).
51
+ */
52
+ feature(name: string): boolean;
53
+ }
54
+
55
+ /** The regions a frame provider fills when it describes a whole surface. */
56
+ export interface NativeSurface {
57
+ /** The flowing document (transcript). */
58
+ readonly main: readonly NativeChild[];
59
+ /** Sticky bottom chrome while live (editor, status line, HUDs). */
60
+ readonly dock: readonly NativeChild[];
61
+ }
62
+
63
+ /**
64
+ * A user action on a node a component described, routed back to that
65
+ * component. `key` is the node's key path inside the component (`""` for the
66
+ * component's root node, `"body/3"` for a nested keyed child).
67
+ */
68
+ export type NativeUiEvent =
69
+ | { readonly type: "toggle"; readonly key: string; readonly collapsed: boolean }
70
+ | { readonly type: "select"; readonly key: string; readonly item: string }
71
+ | { readonly type: "activate"; readonly key: string; readonly item: string }
72
+ | {
73
+ readonly type: "action";
74
+ readonly key: string;
75
+ readonly act: string;
76
+ /** Scope/tab/strip id, sort column, or the prefs row an action control belongs to. */
77
+ readonly value?: string;
78
+ readonly mods: readonly string[];
79
+ }
80
+ /** A typed value changed by pointer (prefs rows, picker toggles); `null` resets to the default. */
81
+ | {
82
+ readonly type: "change";
83
+ readonly key: string;
84
+ readonly item: string;
85
+ readonly value: boolean | number | string | readonly string[] | null;
86
+ };
87
+
88
+ /** The expanded state a `toggle` on the component's root node asks for, else undefined. */
89
+ export function rootToggleExpanded(event: NativeUiEvent): boolean | undefined {
90
+ return event.type === "toggle" && event.key === "" ? !event.collapsed : undefined;
91
+ }
92
+
93
+ /** The last segment of an event keypath (`"split/sidebar/toc"` → `"toc"`). */
94
+ export function leafKey(path: string): string {
95
+ return path.slice(path.lastIndexOf("/") + 1);
96
+ }
97
+
98
+ /** Terminal-level events the backend doesn't route to a single component. */
99
+ export type NativeTerminalEvent = Extract<TspEvent, { ev: "theme" | "motion" | "visible" | "resize" }>;
100
+
101
+ /** Implemented by components that react to user actions on their described nodes. */
102
+ export interface NativeEventTarget {
103
+ handleNativeEvent(event: NativeUiEvent): void;
104
+ }
105
+
106
+ /** Implemented by frame providers (the composer) that describe the whole surface. */
107
+ export interface NativeSurfaceProvider {
108
+ describeSurface(cx: DescribeContext): NativeSurface;
109
+ }
110
+
111
+ /** Re-exported for describe helpers. */
112
+ export type { TspSpan };
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Overlay chrome for `describe()`: root cards, key-hint footers, selectable
3
+ * lists and annotation callouts.
4
+ *
5
+ * The overlay frame itself (glass, ring, placement) is the terminal's: the
6
+ * engine wraps every overlay-stack component in an `overlay` node. An overlay
7
+ * component's root is a `card` whose `head` carries the title.
8
+ */
9
+ import type { TspProps, TspSpan, TspText } from "@oh-my-pi/pi-wire";
10
+ import type { KeyName } from "../key-hint-format";
11
+ import { getKeybindings, type Keybinding } from "../keybindings";
12
+ import { card, kbd, list, node, row, span, text } from "./describe";
13
+ import type { NativeChild, NativeNode } from "./node";
14
+
15
+ /** One footer hint: the keys that trigger it and what it does. */
16
+ export interface NativeHint {
17
+ /** Key ids (`"ctrl+o"`, `"escape"`); alternatives render side by side. */
18
+ readonly keys: readonly KeyName[];
19
+ readonly label: string;
20
+ }
21
+
22
+ /**
23
+ * A hint for the primary keys of one or more keybinding actions
24
+ * (`actionHint(["tui.select.up", "tui.select.down"], "navigate")`);
25
+ * `undefined` when every action is unbound.
26
+ */
27
+ export function actionHint(actions: Keybinding | readonly Keybinding[], label: string): NativeHint | undefined {
28
+ const keys: KeyName[] = [];
29
+ const bindings = getKeybindings();
30
+ for (const action of typeof actions === "string" ? [actions] : actions) {
31
+ const [key] = bindings.getKeys(action);
32
+ if (key) keys.push(key);
33
+ }
34
+ return keys.length > 0 ? { keys, label } : undefined;
35
+ }
36
+
37
+ /**
38
+ * A wrapping row of `kbd` keycaps with muted labels: the footer hint strip of
39
+ * a selector. `undefined` entries (unbound actions) are skipped. Build it once
40
+ * per hint-set change and reuse the node (memoization contract).
41
+ */
42
+ export function hintsRow(hints: readonly (NativeHint | undefined)[], key = "hints"): NativeNode {
43
+ const children: NativeChild[] = [];
44
+ for (const hint of hints) {
45
+ if (!hint) continue;
46
+ const group: NativeChild[] = hint.keys.map(k => kbd(k));
47
+ group.push(text([span(hint.label, "muted")]));
48
+ children.push(row(group, { gap: "xs", align: "center" }));
49
+ }
50
+ return node("row", { gap: "md", wrap: true, role: "omp.overlay.hints" }, children, key);
51
+ }
52
+
53
+ /** A wrapping footer: a status line (`✓ Clean`, `⚠ Cancelled`) followed by key hints. */
54
+ export function statusHintsRow(status: TspText, hints: readonly (NativeHint | undefined)[]): NativeNode {
55
+ return row([text(status), hintsRow(hints)], { gap: "md", wrap: true, align: "center" });
56
+ }
57
+
58
+ /**
59
+ * Root card of an overlay. `head` is the overlay title (whitespace runs
60
+ * collapse; empty means no head); `role` is `omp.overlay.<name>`.
61
+ */
62
+ export function overlayCard(
63
+ role: string,
64
+ head: TspText | undefined,
65
+ children: readonly NativeChild[],
66
+ props?: Omit<TspProps<"card">, "head" | "role">,
67
+ ): NativeNode {
68
+ const title = typeof head === "string" ? head.replace(/\s+/g, " ").trim() : head;
69
+ return card({ ...props, role, head: title === "" ? undefined : title }, children);
70
+ }
71
+
72
+ /** A selectable list: click selects, double-click activates. */
73
+ export function selectList(key: string, items: readonly NativeChild[], p: TspProps<"list">): NativeNode {
74
+ return list(items, { ...p, actions: { click: "select", dblclick: "activate" } }, key);
75
+ }
76
+
77
+ /** The index encoded in an item key built as `<prefix><index>`, or -1 when it isn't one. */
78
+ export function itemIndex(item: string, prefix: string): number {
79
+ if (!item.startsWith(prefix)) return -1;
80
+ const index = Number(item.slice(prefix.length));
81
+ return Number.isInteger(index) && index >= 0 ? index : -1;
82
+ }
83
+
84
+ /** Options of an {@link actionButton}. */
85
+ export interface ActionButtonOptions {
86
+ /** Sibling identity key (defaults to the action id); `leafKey(event.key)` reports it back. */
87
+ readonly key?: string;
88
+ /** Key id of the keyboard path the button mirrors, drawn as a keycap inside it (`"r"`, `"ctrl+g"`). */
89
+ readonly keys?: string;
90
+ /** `accent` = the view's hero action, `error` = destructive. */
91
+ readonly tone?: "accent" | "error";
92
+ /** Tooltip; defaults to the label plus the keycap (`"Refresh r"`). */
93
+ readonly title?: string;
94
+ /** Target of an `open` action (URL or `file://` path). */
95
+ readonly href?: string;
96
+ }
97
+
98
+ /**
99
+ * A native button (role `omp.btn`): a label plus an optional keycap. A click
100
+ * sends `act` back as an `action` event (or runs a terminal-local `open`/`copy`),
101
+ * which the component routes to the same code path as the key.
102
+ */
103
+ export function actionButton(label: string, act: string, options: ActionButtonOptions = {}): NativeNode {
104
+ const children: NativeChild[] = [text(label)];
105
+ if (options.keys) children.push(kbd(options.keys));
106
+ return node(
107
+ "row",
108
+ {
109
+ role: "omp.btn",
110
+ gap: "xs",
111
+ align: "center",
112
+ actions: { click: act },
113
+ title: options.title ?? (options.keys ? `${label} ${options.keys}` : label),
114
+ ...(options.tone ? { tone: options.tone } : {}),
115
+ ...(options.href ? { href: options.href } : {}),
116
+ },
117
+ children,
118
+ options.key ?? act,
119
+ );
120
+ }
121
+
122
+ /** A row of {@link actionButton}s (role `omp.actions`); `null` entries become the spacer that end-aligns what follows. */
123
+ export function actionBar(buttons: readonly (NativeNode | null)[], key = "actions"): NativeNode {
124
+ const children = buttons.map(button => button ?? node("spacer", { grow: 1 }));
125
+ return node("row", { role: "omp.actions", gap: "sm", align: "center" }, children, key);
126
+ }
127
+
128
+ /** Spans of an annotation callout: a dim `label:` then the note. */
129
+ export function noteSpans(label: string, note: string): TspSpan[] {
130
+ return [span(`${label}: `, "dim"), span(note, "accent")];
131
+ }
@@ -0,0 +1,333 @@
1
+ /**
2
+ * Builders for the data-first `picker` kind (Stencil repo,
3
+ * `crates/tern/NATIVE_REDESIGN.md` §4): the model hub, session selector,
4
+ * rewind, tree, copy, history search and the small selectors send their data
5
+ * and Tern draws the sheet (head, scopes, tabs, fact columns, rows, preview,
6
+ * action bar).
7
+ *
8
+ * A picker is its own sheet: the component returns `nativeSheet(cx)` true
9
+ * (usually `cx.supports("picker")`) so the backend puts it directly in
10
+ * `layer`, and `describe()` returns {@link picker}. When the terminal lacks
11
+ * the kind, components keep describing their generic composition.
12
+ *
13
+ * Keys stay the program's: a search field is an {@link Input} (every editor
14
+ * text binding works), sent through {@link pickerQuery} with its caret.
15
+ * Pointer events arrive as `select`/`activate` with
16
+ * the item id and `action` with an action id (plus `value` for
17
+ * `scope`/`tab`/`strip`). {@link pickerEvent} folds them into one shape.
18
+ */
19
+ import type { TspPickerAction, TspPickerItem, TspPickerProps } from "@oh-my-pi/pi-wire";
20
+ import type { KeyName } from "../key-hint-format";
21
+ import { getKeybindings, type Keybinding } from "../keybindings";
22
+ import type { Input } from "../components/input";
23
+ import type { SelectItem, SelectList } from "../components/select-list";
24
+ import { col, node } from "./describe";
25
+ import type { NativeChild, NativeNode, NativeUiEvent } from "./node";
26
+
27
+ /** The picker sheet; `preview` children fill its preview pane. */
28
+ export function picker(p: TspPickerProps, preview?: readonly NativeChild[]): NativeNode {
29
+ return node("picker", p, preview);
30
+ }
31
+
32
+ /**
33
+ * A picker's search field from the {@link Input} that edits it: the text and
34
+ * its caret. `null` hides the field. Memoized pickers MUST key on the caret
35
+ * too, or motion keys (word jumps, line start) never reach the screen.
36
+ */
37
+ export function pickerQuery(input: Input | null): Pick<TspPickerProps, "query" | "cursor"> {
38
+ return input ? { query: input.getValue(), cursor: input.getCursor() } : { query: null };
39
+ }
40
+
41
+ /** Key of the picker child a dock/editor-mounted selector describes; its events arrive at this keypath. */
42
+ export const PICKER_KEY = "picker";
43
+
44
+ /**
45
+ * The root a selector mounted in the editor slot describes: a column holding
46
+ * the picker as child {@link PICKER_KEY}, which the reconciler hoists into
47
+ * `layer`. Route its events with `pickerEvent(event, PICKER_KEY)`.
48
+ */
49
+ export function dockedPicker(p: TspPickerProps, preview?: readonly NativeChild[]): NativeNode {
50
+ return col([node("picker", p, preview, PICKER_KEY)]);
51
+ }
52
+
53
+ /** Keycap names for one key id (`"alt+enter"` → `["alt", "enter"]`, `"escape"` → `["esc"]`). */
54
+ export function pickerKeys(key: KeyName | string): string[] {
55
+ if (key === "+") return ["+"];
56
+ const parts = key.endsWith("++") ? [...key.slice(0, -2).split("+"), "+"] : key.split("+");
57
+ return parts.filter(part => part.length > 0).map(part => (part === "escape" ? "esc" : part));
58
+ }
59
+
60
+ /** The keycaps of a keybinding's primary key, empty when unbound. */
61
+ export function bindingKeys(binding: Keybinding): string[] {
62
+ const [key] = getKeybindings().getKeys(binding);
63
+ return key ? pickerKeys(key) : [];
64
+ }
65
+
66
+ /** An action-bar button; `keys` is a key id (`"alt+enter"`), a keybinding's keycaps, or none. */
67
+ export function pickerAction(
68
+ id: string,
69
+ label: string,
70
+ keys?: KeyName | string | readonly string[],
71
+ opts?: Omit<TspPickerAction, "id" | "label" | "keys">,
72
+ ): TspPickerAction {
73
+ const caps = keys === undefined ? undefined : typeof keys === "string" ? pickerKeys(keys) : keys;
74
+ return { id, label, ...(caps && caps.length > 0 ? { keys: caps } : {}), ...opts };
75
+ }
76
+
77
+ /** The right-aligned `Close esc` every picker ends with; Tern's backdrop and head `esc` send it too. */
78
+ export const CLOSE_ACTION: TspPickerAction = { id: "close", label: "Close", keys: ["esc"], end: true };
79
+
80
+ /** A `time` fact: the compact age of `at` (`now`, `5m`, `2h`, `3d`, `2w`, `6mo`, `1y`). */
81
+ export function pickerAge(at: Date | number, now = Date.now()): string {
82
+ const seconds = Math.max(0, Math.floor((now - (typeof at === "number" ? at : at.getTime())) / 1000));
83
+ if (seconds < 60) return "now";
84
+ const minutes = Math.floor(seconds / 60);
85
+ if (minutes < 60) return `${minutes}m`;
86
+ const hours = Math.floor(minutes / 60);
87
+ if (hours < 24) return `${hours}h`;
88
+ const days = Math.floor(hours / 24);
89
+ if (days < 7) return `${days}d`;
90
+ if (days < 30) return `${Math.floor(days / 7)}w`;
91
+ if (days < 365) return `${Math.floor(days / 30)}mo`;
92
+ return `${Math.floor(days / 365)}y`;
93
+ }
94
+
95
+ /**
96
+ * Search `hits` for a label: disjoint, ordered UTF-16 ranges of every
97
+ * case-insensitive occurrence of any of the (lowercase) `tokens`.
98
+ */
99
+ export function pickerHits(label: string, tokens: readonly string[]): [number, number][] {
100
+ if (tokens.length === 0) return [];
101
+ const lower = label.toLowerCase();
102
+ const ranges: [number, number][] = [];
103
+ for (const token of tokens) {
104
+ if (token.length === 0) continue;
105
+ for (let from = lower.indexOf(token); from !== -1; from = lower.indexOf(token, from + token.length)) {
106
+ ranges.push([from, from + token.length]);
107
+ }
108
+ }
109
+ ranges.sort((a, b) => a[0] - b[0]);
110
+ const merged: [number, number][] = [];
111
+ for (const [start, end] of ranges) {
112
+ const last = merged.at(-1);
113
+ if (last && start <= last[1]) last[1] = Math.max(last[1], end);
114
+ else merged.push([start, end]);
115
+ }
116
+ return merged;
117
+ }
118
+
119
+ const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
120
+
121
+ /** The absolute local time behind a `time` fact, for its tooltip (`28 Sep 2026, 18:02`). */
122
+ export function pickerDate(at: Date | number): string {
123
+ const d = typeof at === "number" ? new Date(at) : at;
124
+ const hh = String(d.getHours()).padStart(2, "0");
125
+ const mm = String(d.getMinutes()).padStart(2, "0");
126
+ return `${d.getDate()} ${MONTHS[d.getMonth()]} ${d.getFullYear()}, ${hh}:${mm}`;
127
+ }
128
+
129
+ /** A picker pointer event, folded: which item, or which action with its value. */
130
+ export type PickerEvent =
131
+ | { readonly kind: "select" | "activate"; readonly item: string }
132
+ | { readonly kind: "action"; readonly act: string; readonly value: string | undefined };
133
+
134
+ /**
135
+ * The picker event `event` carries, or undefined when it is not for the
136
+ * picker at keypath `key`: `""` for a root picker, else the picker child's
137
+ * key (a hoisted child's keypath carries a `^` marker, ignored here).
138
+ */
139
+ export function pickerEvent(event: NativeUiEvent, key = ""): PickerEvent | undefined {
140
+ if (event.key.replaceAll("^", "") !== key) return undefined;
141
+ switch (event.type) {
142
+ case "select":
143
+ case "activate":
144
+ return { kind: event.type, item: event.item };
145
+ case "action":
146
+ return { kind: "action", act: event.act, value: event.value };
147
+ default:
148
+ return undefined;
149
+ }
150
+ }
151
+
152
+ /**
153
+ * {@link pickerHits} for fuzzy-filtered lists: each whitespace token of
154
+ * `query` marks its first case-insensitive substring, else its characters as
155
+ * a greedy in-order subsequence (the fuzzy matcher's shape). Undefined when
156
+ * nothing matches.
157
+ */
158
+ export function pickerFuzzyHits(label: string, query: string): [number, number][] | undefined {
159
+ const tokens = query
160
+ .toLowerCase()
161
+ .split(/\s+/)
162
+ .filter(token => token.length > 0);
163
+ if (tokens.length === 0) return undefined;
164
+ const lower = label.toLowerCase();
165
+ const marked = new Uint8Array(lower.length);
166
+ for (const token of tokens) {
167
+ const at = lower.indexOf(token);
168
+ if (at >= 0) {
169
+ marked.fill(1, at, at + token.length);
170
+ continue;
171
+ }
172
+ let from = 0;
173
+ for (const ch of token) {
174
+ const index = lower.indexOf(ch, from);
175
+ if (index < 0) break;
176
+ marked[index] = 1;
177
+ from = index + ch.length;
178
+ }
179
+ }
180
+ const ranges: [number, number][] = [];
181
+ for (let i = 0; i < marked.length; i++) {
182
+ if (!marked[i]) continue;
183
+ const start = i;
184
+ while (i < marked.length && marked[i]) i++;
185
+ ranges.push([start, i]);
186
+ }
187
+ return ranges.length > 0 ? ranges : undefined;
188
+ }
189
+
190
+ /** The `md` sheet a short {@link SelectList} selector becomes (thinking level, hook options, queue mode, …). */
191
+ export interface SelectPickerOptions {
192
+ readonly title: string;
193
+ readonly subtitle?: string;
194
+ readonly icon?: string;
195
+ readonly noun?: string;
196
+ /** Show omp's filter text as the search field (lists that filter as you type). */
197
+ readonly searchable?: boolean;
198
+ /** Per-item extras (a thinking-level dot, a swatch mark, a budget fact). */
199
+ readonly decorate?: (item: SelectItem) => Partial<Omit<TspPickerItem, "id">> | undefined;
200
+ readonly columns?: TspPickerProps["columns"];
201
+ /** Values in use now (the current theme, the current level). */
202
+ readonly current?: readonly string[];
203
+ /** The primary action's label (`Apply`, `Select`). */
204
+ readonly confirm?: string;
205
+ }
206
+
207
+ /**
208
+ * Picker props for a {@link SelectList}: its filtered items in order, the
209
+ * selection, the pending-confirmation strip, and `Select ⏎` / `Close esc`.
210
+ * Memoize on {@link SelectList.pickerView}'s parts: the builder allocates.
211
+ */
212
+ export function selectListPicker(list: SelectList, o: SelectPickerOptions): TspPickerProps {
213
+ const view = list.pickerView();
214
+ const items: TspPickerItem[] = view.items.map(item => ({
215
+ id: item.value,
216
+ label: item.label,
217
+ ...(item.description ? { detail: item.description } : {}),
218
+ ...(item.disabled ? { disabled: true as const } : {}),
219
+ ...o.decorate?.(item),
220
+ }));
221
+ const pending = view.pending === null ? undefined : view.items.find(item => item.value === view.pending);
222
+ return {
223
+ title: o.title,
224
+ ...(o.subtitle ? { subtitle: o.subtitle } : {}),
225
+ ...(o.icon ? { icon: o.icon } : {}),
226
+ noun: o.noun ?? "options",
227
+ size: "md",
228
+ layout: "rows",
229
+ preview: "none",
230
+ ...(o.searchable ? { query: view.query, cursor: view.cursor } : { query: null }),
231
+ items,
232
+ selected: view.selected,
233
+ ...(o.current ? { current: o.current } : {}),
234
+ ...(o.columns ? { columns: o.columns } : {}),
235
+ actions: [pickerAction("confirm", o.confirm ?? "Select", "enter", { primary: true }), CLOSE_ACTION],
236
+ confirm:
237
+ pending?.confirmation !== undefined ? { text: pending.confirmation, act: "confirm", label: "Confirm" } : null,
238
+ };
239
+ }
240
+
241
+ /**
242
+ * Routes a picker event to a {@link SelectList}: a row click selects (and
243
+ * previews, through `onSelectionChange`), a second click or `confirm`
244
+ * activates, `close`/`cancel` cancels. Returns whether it handled the event.
245
+ */
246
+ export function routeSelectListPicker(list: SelectList, event: NativeUiEvent, key = ""): boolean {
247
+ const ev = pickerEvent(event, key);
248
+ if (!ev) return false;
249
+ const view = list.pickerView();
250
+ if (ev.kind === "action") {
251
+ if (ev.act === "close" || ev.act === "cancel") {
252
+ list.onCancel?.();
253
+ return true;
254
+ }
255
+ if (ev.act === "confirm" && view.selected !== null) {
256
+ const index = view.items.findIndex(item => item.value === view.selected);
257
+ if (index >= 0) list.clickItem(index);
258
+ return true;
259
+ }
260
+ return false;
261
+ }
262
+ const index = view.items.findIndex(item => item.value === ev.item);
263
+ if (index < 0) return false;
264
+ if (ev.kind === "activate") {
265
+ list.clickItem(index);
266
+ } else {
267
+ list.setSelectedIndex(index);
268
+ list.onSelectionChange?.(view.items[index]!);
269
+ }
270
+ return true;
271
+ }
272
+
273
+ /**
274
+ * A {@link SelectList} described as a picker, memoized: the node is rebuilt
275
+ * only when the list's filtered items, selection, pending confirmation or
276
+ * query change (or {@link invalidate} is called after `options` inputs move).
277
+ */
278
+ export class SelectListSheet {
279
+ readonly list: SelectList;
280
+ #options: () => SelectPickerOptions;
281
+ #memo:
282
+ | {
283
+ readonly items: readonly SelectItem[];
284
+ readonly selected: string | null;
285
+ readonly pending: string | null;
286
+ readonly query: string;
287
+ readonly cursor: number;
288
+ readonly node: NativeNode;
289
+ }
290
+ | undefined;
291
+
292
+ /** Described as {@link dockedPicker} (editor-slot selectors) rather than a root picker. */
293
+ readonly #docked: boolean;
294
+
295
+ constructor(
296
+ list: SelectList,
297
+ options: SelectPickerOptions | (() => SelectPickerOptions),
298
+ { docked = true }: { docked?: boolean } = {},
299
+ ) {
300
+ this.list = list;
301
+ this.#options = typeof options === "function" ? options : () => options;
302
+ this.#docked = docked;
303
+ }
304
+
305
+ /** Drop the memo (decorations or options changed outside the list). */
306
+ invalidate(): void {
307
+ this.#memo = undefined;
308
+ }
309
+
310
+ describe(): NativeNode {
311
+ const view = this.list.pickerView();
312
+ const memo = this.#memo;
313
+ if (
314
+ memo !== undefined &&
315
+ memo.items === view.items &&
316
+ memo.selected === view.selected &&
317
+ memo.pending === view.pending &&
318
+ memo.query === view.query &&
319
+ memo.cursor === view.cursor
320
+ ) {
321
+ return memo.node;
322
+ }
323
+ const props = selectListPicker(this.list, this.#options());
324
+ const result = this.#docked ? dockedPicker(props) : picker(props);
325
+ this.#memo = { ...view, node: result };
326
+ return result;
327
+ }
328
+
329
+ /** Route a picker event onto the list; see {@link routeSelectListPicker}. */
330
+ handle(event: NativeUiEvent): boolean {
331
+ return routeSelectListPicker(this.list, event, this.#docked ? PICKER_KEY : "");
332
+ }
333
+ }