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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/types/apps/cleanse-board.d.ts +17 -0
  3. package/dist/types/apps/git/help.d.ts +16 -0
  4. package/dist/types/apps/git/sidebar.d.ts +18 -0
  5. package/dist/types/apps/live-visualizer.d.ts +10 -0
  6. package/dist/types/apps/ps-top.d.ts +15 -0
  7. package/dist/types/apps/standalone-picker.d.ts +3 -0
  8. package/dist/types/autocomplete.d.ts +8 -0
  9. package/dist/types/chat/advisor-message.d.ts +12 -2
  10. package/dist/types/chat/assistant-message.d.ts +20 -0
  11. package/dist/types/chat/bash-execution.d.ts +9 -0
  12. package/dist/types/chat/chat-transcript-builder.d.ts +6 -1
  13. package/dist/types/chat/collab-prompt-message.d.ts +4 -0
  14. package/dist/types/chat/compaction-summary-message.d.ts +15 -0
  15. package/dist/types/chat/eval-execution.d.ts +8 -0
  16. package/dist/types/chat/execution-shared.d.ts +58 -0
  17. package/dist/types/chat/late-diagnostics-message.d.ts +15 -1
  18. package/dist/types/chat/read-tool-group.d.ts +15 -0
  19. package/dist/types/chat/skill-message.d.ts +9 -0
  20. package/dist/types/chat/stripped-tool-calls-placeholder.d.ts +3 -0
  21. package/dist/types/chat/thinking-display.d.ts +2 -0
  22. package/dist/types/chat/todo-reminder.d.ts +4 -1
  23. package/dist/types/chat/tool-execution.d.ts +25 -1
  24. package/dist/types/chat/transcript-actions.d.ts +37 -0
  25. package/dist/types/chat/transcript-entry.d.ts +3 -1
  26. package/dist/types/chat/user-message.d.ts +25 -0
  27. package/dist/types/chrome/collab-qrcode.d.ts +7 -0
  28. package/dist/types/chrome/context-thresholds.d.ts +11 -0
  29. package/dist/types/chrome/countdown-timer.d.ts +9 -3
  30. package/dist/types/chrome/diff.d.ts +12 -0
  31. package/dist/types/chrome/dynamic-border.d.ts +3 -0
  32. package/dist/types/chrome/format.d.ts +6 -0
  33. package/dist/types/chrome/message-divider.d.ts +13 -0
  34. package/dist/types/chrome/message-frame.d.ts +10 -0
  35. package/dist/types/chrome/message-notice.d.ts +23 -0
  36. package/dist/types/chrome/overlay-box.d.ts +11 -2
  37. package/dist/types/chrome/qrcode.d.ts +7 -0
  38. package/dist/types/chrome/segment-track.d.ts +7 -0
  39. package/dist/types/chrome/selector-helpers.d.ts +0 -6
  40. package/dist/types/chrome/status-notice.d.ts +14 -0
  41. package/dist/types/chrome/streaming-panel.d.ts +3 -0
  42. package/dist/types/chrome/tool-activity.d.ts +3 -0
  43. package/dist/types/chrome/transcript-container.d.ts +13 -0
  44. package/dist/types/chrome/transcript-status.d.ts +15 -3
  45. package/dist/types/components/box.d.ts +7 -0
  46. package/dist/types/components/disclosure.d.ts +9 -0
  47. package/dist/types/components/editor.d.ts +42 -0
  48. package/dist/types/components/form.d.ts +14 -0
  49. package/dist/types/components/image.d.ts +7 -0
  50. package/dist/types/components/input.d.ts +20 -1
  51. package/dist/types/components/key-value-list.d.ts +3 -0
  52. package/dist/types/components/layout/geometry.d.ts +16 -0
  53. package/dist/types/components/layout/row.d.ts +7 -0
  54. package/dist/types/components/layout/split-pane.d.ts +8 -0
  55. package/dist/types/components/layout/stack.d.ts +6 -0
  56. package/dist/types/components/loader.d.ts +48 -0
  57. package/dist/types/components/markdown.d.ts +8 -0
  58. package/dist/types/components/metric.d.ts +7 -0
  59. package/dist/types/components/progress-bar.d.ts +3 -0
  60. package/dist/types/components/scroll-view.d.ts +6 -0
  61. package/dist/types/components/section.d.ts +3 -0
  62. package/dist/types/components/select-list.d.ts +33 -0
  63. package/dist/types/components/settings-list.d.ts +68 -0
  64. package/dist/types/components/spacer.d.ts +4 -0
  65. package/dist/types/components/tab-bar.d.ts +9 -0
  66. package/dist/types/components/table.d.ts +7 -0
  67. package/dist/types/components/text.d.ts +6 -0
  68. package/dist/types/components/tree-view.d.ts +9 -0
  69. package/dist/types/components/truncated-text.d.ts +3 -0
  70. package/dist/types/components/wizard-step.d.ts +6 -0
  71. package/dist/types/hotkeys-markdown.d.ts +24 -0
  72. package/dist/types/index.d.ts +5 -0
  73. package/dist/types/latex-block.d.ts +7 -0
  74. package/dist/types/loop-watchdog.d.ts +9 -0
  75. package/dist/types/native/apply.d.ts +39 -0
  76. package/dist/types/native/backend.d.ts +94 -0
  77. package/dist/types/native/blobs.d.ts +29 -0
  78. package/dist/types/native/describe.d.ts +56 -0
  79. package/dist/types/native/encode.d.ts +50 -0
  80. package/dist/types/native/icons.d.ts +18 -0
  81. package/dist/types/native/memo.d.ts +27 -0
  82. package/dist/types/native/node.d.ts +107 -0
  83. package/dist/types/native/overlay.d.ts +64 -0
  84. package/dist/types/native/picker.d.ts +124 -0
  85. package/dist/types/native/reconcile.d.ts +41 -0
  86. package/dist/types/native/settle.d.ts +11 -0
  87. package/dist/types/native/spans.d.ts +21 -0
  88. package/dist/types/native/state.d.ts +6 -0
  89. package/dist/types/native/tone.d.ts +24 -0
  90. package/dist/types/overlays/advisor-config.d.ts +20 -0
  91. package/dist/types/overlays/agent-hub-renderer.d.ts +27 -11
  92. package/dist/types/overlays/agent-hub.d.ts +10 -0
  93. package/dist/types/overlays/agent-transcript-viewer.d.ts +7 -0
  94. package/dist/types/overlays/agents-hub.d.ts +8 -0
  95. package/dist/types/overlays/annotation-overlay.d.ts +3 -0
  96. package/dist/types/overlays/ask-dialog.d.ts +23 -0
  97. package/dist/types/overlays/bordered-loader.d.ts +3 -0
  98. package/dist/types/overlays/btw-history-panel.d.ts +9 -0
  99. package/dist/types/overlays/btw-panel.d.ts +3 -0
  100. package/dist/types/overlays/cleanse-panel.d.ts +5 -2
  101. package/dist/types/overlays/composer-shape-preview.d.ts +7 -1
  102. package/dist/types/overlays/copy-selector.d.ts +38 -0
  103. package/dist/types/overlays/error-banner.d.ts +9 -0
  104. package/dist/types/overlays/extensions/extension-list.d.ts +1 -0
  105. package/dist/types/overlays/history-search.d.ts +18 -0
  106. package/dist/types/overlays/hook-editor.d.ts +28 -1
  107. package/dist/types/overlays/hook-input.d.ts +3 -0
  108. package/dist/types/overlays/hook-selector.d.ts +10 -0
  109. package/dist/types/overlays/hub-frame.d.ts +18 -0
  110. package/dist/types/overlays/jobs-panel.d.ts +24 -0
  111. package/dist/types/overlays/login-dialog.d.ts +10 -0
  112. package/dist/types/overlays/logout-account-selector.d.ts +4 -0
  113. package/dist/types/overlays/mcp-add-wizard.d.ts +4 -0
  114. package/dist/types/overlays/model-browser.d.ts +69 -0
  115. package/dist/types/overlays/model-hub.d.ts +7 -0
  116. package/dist/types/overlays/model-picker.d.ts +9 -1
  117. package/dist/types/overlays/move-overlay.d.ts +3 -0
  118. package/dist/types/overlays/oauth-selector.d.ts +4 -0
  119. package/dist/types/overlays/omfg-panel.d.ts +3 -0
  120. package/dist/types/overlays/pause-screen.d.ts +12 -0
  121. package/dist/types/overlays/plan-review-overlay.d.ts +5 -0
  122. package/dist/types/overlays/plan-save-overlay.d.ts +10 -0
  123. package/dist/types/overlays/plugin-selector.d.ts +4 -0
  124. package/dist/types/overlays/plugin-settings.d.ts +30 -0
  125. package/dist/types/overlays/queue-mode-selector.d.ts +4 -0
  126. package/dist/types/overlays/reset-usage-selector.d.ts +8 -0
  127. package/dist/types/overlays/rewind-selector.d.ts +5 -0
  128. package/dist/types/overlays/session-info-overlay.d.ts +19 -1
  129. package/dist/types/overlays/session-selector.d.ts +64 -1
  130. package/dist/types/overlays/settings-defs.d.ts +14 -0
  131. package/dist/types/overlays/settings-selector.d.ts +21 -0
  132. package/dist/types/overlays/show-images-selector.d.ts +4 -0
  133. package/dist/types/overlays/snapcompact-shape-preview.d.ts +2 -0
  134. package/dist/types/overlays/stats-notice.d.ts +8 -0
  135. package/dist/types/overlays/theme-selector.d.ts +11 -0
  136. package/dist/types/overlays/thinking-selector.d.ts +4 -0
  137. package/dist/types/overlays/tree-selector.d.ts +60 -2
  138. package/dist/types/overlays/usage-dashboard.d.ts +26 -3
  139. package/dist/types/overlays/usage-row.d.ts +36 -2
  140. package/dist/types/prompt/attachment-chips.d.ts +8 -0
  141. package/dist/types/prompt/composer-attachments.d.ts +15 -3
  142. package/dist/types/prompt/composer.d.ts +18 -1
  143. package/dist/types/prompt/custom-editor.d.ts +48 -2
  144. package/dist/types/prompt/editor-top-gap.d.ts +2 -0
  145. package/dist/types/prompt/macos-spelling.d.ts +6 -0
  146. package/dist/types/prompt/magic-keywords.d.ts +9 -0
  147. package/dist/types/prompt/queued-messages.d.ts +23 -0
  148. package/dist/types/prompt/skill-tokens.d.ts +4 -2
  149. package/dist/types/prompt/welcome.d.ts +16 -0
  150. package/dist/types/render/code-cell.d.ts +10 -0
  151. package/dist/types/render/file-list.d.ts +8 -0
  152. package/dist/types/render/hyperlink.d.ts +14 -0
  153. package/dist/types/render/output-block.d.ts +43 -0
  154. package/dist/types/render/output-pane.d.ts +17 -0
  155. package/dist/types/render/tool-card.d.ts +8 -0
  156. package/dist/types/render/tree-list.d.ts +8 -0
  157. package/dist/types/render/width-aware-text.d.ts +7 -0
  158. package/dist/types/setup/scenes/outro.d.ts +7 -0
  159. package/dist/types/setup/scenes/sign-in.d.ts +16 -9
  160. package/dist/types/setup/scenes/splash.d.ts +8 -0
  161. package/dist/types/setup/scenes/types.d.ts +6 -27
  162. package/dist/types/setup/wizard-overlay.d.ts +9 -0
  163. package/dist/types/status-line/component.d.ts +49 -5
  164. package/dist/types/status-line/context-usage.d.ts +20 -0
  165. package/dist/types/status-line/footer.d.ts +8 -0
  166. package/dist/types/status-line/metrics.d.ts +1 -2
  167. package/dist/types/status-line/segments.d.ts +10 -1
  168. package/dist/types/status-line/types.d.ts +40 -1
  169. package/dist/types/stdin-buffer.d.ts +10 -7
  170. package/dist/types/terminal-capabilities.d.ts +1 -1
  171. package/dist/types/terminal.d.ts +36 -0
  172. package/dist/types/theme/defaults/index.d.ts +100 -0
  173. package/dist/types/theme/schema.d.ts +2 -0
  174. package/dist/types/theme/shimmer.d.ts +8 -0
  175. package/dist/types/theme/theme-class.d.ts +2 -0
  176. package/dist/types/theme/theme.d.ts +33 -1
  177. package/dist/types/tools/ask.d.ts +3 -0
  178. package/dist/types/tools/ast-edit.d.ts +10 -1
  179. package/dist/types/tools/ast-grep.d.ts +10 -1
  180. package/dist/types/tools/autoresearch.d.ts +21 -4
  181. package/dist/types/tools/bash.d.ts +30 -1
  182. package/dist/types/tools/cfg-render.d.ts +5 -1
  183. package/dist/types/tools/debug.d.ts +3 -1
  184. package/dist/types/tools/default-renderer.d.ts +6 -1
  185. package/dist/types/tools/edit.d.ts +14 -1
  186. package/dist/types/tools/eval.d.ts +12 -1
  187. package/dist/types/tools/fetch.d.ts +16 -1
  188. package/dist/types/tools/find.d.ts +15 -1
  189. package/dist/types/tools/github.d.ts +3 -0
  190. package/dist/types/tools/glob.d.ts +14 -1
  191. package/dist/types/tools/goal.d.ts +3 -1
  192. package/dist/types/tools/grep.d.ts +14 -1
  193. package/dist/types/tools/grouped-file-output.d.ts +58 -0
  194. package/dist/types/tools/json-tree.d.ts +20 -0
  195. package/dist/types/tools/lsp.d.ts +3 -10
  196. package/dist/types/tools/mcp.d.ts +16 -1
  197. package/dist/types/tools/memory.d.ts +26 -0
  198. package/dist/types/tools/native-view.d.ts +90 -0
  199. package/dist/types/tools/proc-render.d.ts +7 -1
  200. package/dist/types/tools/read.d.ts +23 -1
  201. package/dist/types/tools/renderer.d.ts +57 -0
  202. package/dist/types/tools/report-tool-issue.d.ts +3 -0
  203. package/dist/types/tools/resolve.d.ts +14 -1
  204. package/dist/types/tools/task.d.ts +3 -0
  205. package/dist/types/tools/think.d.ts +3 -0
  206. package/dist/types/tools/todo.d.ts +12 -0
  207. package/dist/types/tools/vibe.d.ts +3 -1
  208. package/dist/types/tools/wait.d.ts +3 -0
  209. package/dist/types/tools/web-search-types.d.ts +90 -0
  210. package/dist/types/tools/web-search.d.ts +9 -168
  211. package/dist/types/tools/write.d.ts +14 -1
  212. package/dist/types/tools/xdev.d.ts +13 -0
  213. package/dist/types/tui.d.ts +49 -0
  214. package/package.json +9 -9
  215. package/src/apps/autoresearch-dashboard.ts +362 -4
  216. package/src/apps/cleanse-board.ts +219 -1
  217. package/src/apps/cleanse-picker.ts +9 -1
  218. package/src/apps/debug/log-viewer.ts +15 -15
  219. package/src/apps/debug/protocol-probe.ts +2 -20
  220. package/src/apps/git/avatar.ts +2 -22
  221. package/src/apps/git/git-tui.ts +406 -59
  222. package/src/apps/git/help.ts +130 -0
  223. package/src/apps/git/sidebar.ts +491 -0
  224. package/src/apps/live-visualizer.ts +65 -0
  225. package/src/apps/ps-top.ts +448 -17
  226. package/src/apps/session-picker.ts +1 -0
  227. package/src/apps/setup-model-picker.ts +5 -1
  228. package/src/apps/standalone-picker.ts +55 -1
  229. package/src/autocomplete.ts +44 -1
  230. package/src/chat/advisor-message.ts +72 -3
  231. package/src/chat/assistant-message.ts +538 -51
  232. package/src/chat/background-tan-message.ts +4 -4
  233. package/src/chat/bash-execution.ts +81 -0
  234. package/src/chat/cache-invalidation-marker.ts +8 -0
  235. package/src/chat/chat-transcript-builder.ts +37 -6
  236. package/src/chat/collab-prompt-message.ts +15 -3
  237. package/src/chat/compaction-summary-message.ts +74 -1
  238. package/src/chat/custom-message.ts +3 -1
  239. package/src/chat/eval-execution.ts +57 -0
  240. package/src/chat/execution-shared.ts +153 -1
  241. package/src/chat/hook-message.ts +1 -0
  242. package/src/chat/late-diagnostics-message.ts +85 -2
  243. package/src/chat/read-tool-group.ts +341 -1
  244. package/src/chat/served-model-marker.ts +8 -0
  245. package/src/chat/skill-message.ts +63 -0
  246. package/src/chat/stripped-tool-calls-placeholder.ts +18 -10
  247. package/src/chat/thinking-display.ts +73 -11
  248. package/src/chat/todo-reminder.ts +34 -4
  249. package/src/chat/tool-execution.ts +385 -10
  250. package/src/chat/transcript-actions.ts +38 -0
  251. package/src/chat/transcript-browser.ts +2 -9
  252. package/src/chat/transcript-entry.ts +10 -1
  253. package/src/chat/transcript-render-helpers.ts +16 -15
  254. package/src/chat/ttsr-notification.ts +38 -1
  255. package/src/chat/user-message.ts +167 -4
  256. package/src/chrome/collab-qrcode.ts +27 -2
  257. package/src/chrome/context-thresholds.ts +34 -0
  258. package/src/chrome/countdown-timer.ts +24 -1
  259. package/src/chrome/diff.ts +60 -1
  260. package/src/chrome/dynamic-border.ts +7 -0
  261. package/src/chrome/format.ts +12 -0
  262. package/src/chrome/message-divider.ts +33 -1
  263. package/src/chrome/message-frame.ts +53 -10
  264. package/src/chrome/message-notice.ts +71 -0
  265. package/src/chrome/overlay-box.ts +45 -2
  266. package/src/chrome/qrcode.ts +28 -0
  267. package/src/chrome/segment-track.ts +26 -0
  268. package/src/chrome/selector-helpers.ts +1 -17
  269. package/src/chrome/status-notice.ts +46 -0
  270. package/src/chrome/streaming-panel.ts +25 -1
  271. package/src/chrome/tool-activity.ts +20 -0
  272. package/src/chrome/transcript-container.ts +139 -17
  273. package/src/chrome/transcript-status.ts +40 -11
  274. package/src/components/box.ts +51 -0
  275. package/src/components/disclosure.ts +33 -0
  276. package/src/components/editor.ts +239 -36
  277. package/src/components/form.ts +93 -9
  278. package/src/components/image.ts +30 -0
  279. package/src/components/input.ts +77 -26
  280. package/src/components/key-value-list.ts +18 -0
  281. package/src/components/layout/geometry.ts +44 -0
  282. package/src/components/layout/row.ts +30 -0
  283. package/src/components/layout/split-pane.ts +65 -0
  284. package/src/components/layout/stack.ts +27 -0
  285. package/src/components/loader.ts +183 -1
  286. package/src/components/markdown.ts +131 -56
  287. package/src/components/metric.ts +39 -0
  288. package/src/components/progress-bar.ts +28 -0
  289. package/src/components/scroll-view.ts +23 -0
  290. package/src/components/section.ts +16 -0
  291. package/src/components/select-list.ts +174 -25
  292. package/src/components/settings-list.ts +264 -7
  293. package/src/components/spacer.ts +17 -0
  294. package/src/components/tab-bar.ts +42 -0
  295. package/src/components/table.ts +34 -0
  296. package/src/components/text.ts +23 -0
  297. package/src/components/tree-view.ts +65 -0
  298. package/src/components/truncated-text.ts +14 -0
  299. package/src/components/wizard-step.ts +18 -9
  300. package/src/debug-server.ts +14 -7
  301. package/src/hotkeys-markdown.ts +251 -69
  302. package/src/index.ts +6 -0
  303. package/src/latex-block.ts +11 -0
  304. package/src/loop-watchdog.ts +38 -10
  305. package/src/native/apply.ts +275 -0
  306. package/src/native/backend.ts +682 -0
  307. package/src/native/blobs.ts +70 -0
  308. package/src/native/describe.ts +124 -0
  309. package/src/native/encode.ts +233 -0
  310. package/src/native/icons.ts +184 -0
  311. package/src/native/memo.ts +64 -0
  312. package/src/native/node.ts +112 -0
  313. package/src/native/overlay.ts +131 -0
  314. package/src/native/picker.ts +333 -0
  315. package/src/native/reconcile.ts +1063 -0
  316. package/src/native/settle.ts +23 -0
  317. package/src/native/spans.ts +308 -0
  318. package/src/native/state.ts +28 -0
  319. package/src/native/tone.ts +79 -0
  320. package/src/overlays/advisor-config.ts +420 -0
  321. package/src/overlays/agent-hub-renderer.ts +155 -18
  322. package/src/overlays/agent-hub.ts +1037 -44
  323. package/src/overlays/agent-transcript-viewer.ts +129 -0
  324. package/src/overlays/agents-hub.ts +688 -53
  325. package/src/overlays/annotation-overlay.ts +391 -52
  326. package/src/overlays/ask-dialog.ts +435 -24
  327. package/src/overlays/bordered-loader.ts +17 -0
  328. package/src/overlays/btw-history-panel.ts +182 -0
  329. package/src/overlays/btw-panel.ts +68 -2
  330. package/src/overlays/cleanse-panel.ts +105 -15
  331. package/src/overlays/codex-reset-fireworks.ts +65 -5
  332. package/src/overlays/composer-shape-preview.ts +26 -1
  333. package/src/overlays/copy-selector.ts +545 -23
  334. package/src/overlays/error-banner.ts +44 -0
  335. package/src/overlays/extensions/extension-list.ts +23 -17
  336. package/src/overlays/history-search.ts +175 -33
  337. package/src/overlays/hook-editor.ts +113 -6
  338. package/src/overlays/hook-input.ts +22 -1
  339. package/src/overlays/hook-selector.ts +311 -22
  340. package/src/overlays/hub-frame.ts +80 -0
  341. package/src/overlays/jobs-panel.ts +112 -0
  342. package/src/overlays/login-dialog.ts +183 -1
  343. package/src/overlays/logout-account-selector.ts +102 -4
  344. package/src/overlays/mcp-add-wizard.ts +232 -53
  345. package/src/overlays/model-browser.ts +681 -22
  346. package/src/overlays/model-hub.ts +1402 -78
  347. package/src/overlays/model-picker.ts +184 -7
  348. package/src/overlays/move-overlay.ts +45 -0
  349. package/src/overlays/oauth-selector.ts +227 -23
  350. package/src/overlays/omfg-panel.ts +86 -2
  351. package/src/overlays/pause-screen.ts +55 -4
  352. package/src/overlays/plan-review-overlay.ts +352 -0
  353. package/src/overlays/plan-save-overlay.ts +45 -0
  354. package/src/overlays/plugin-selector.ts +21 -1
  355. package/src/overlays/plugin-settings.ts +195 -5
  356. package/src/overlays/queue-mode-selector.ts +19 -1
  357. package/src/overlays/reset-usage-selector.ts +110 -40
  358. package/src/overlays/rewind-selector.ts +458 -44
  359. package/src/overlays/session-account-selector.ts +1 -1
  360. package/src/overlays/session-info-overlay.ts +137 -1
  361. package/src/overlays/session-selector.ts +807 -46
  362. package/src/overlays/settings-defs.ts +41 -0
  363. package/src/overlays/settings-selector.ts +585 -33
  364. package/src/overlays/show-images-selector.ts +18 -1
  365. package/src/overlays/snapcompact-shape-preview.ts +48 -3
  366. package/src/overlays/stats-notice.ts +31 -0
  367. package/src/overlays/theme-selector.ts +31 -1
  368. package/src/overlays/thinking-selector.ts +22 -1
  369. package/src/overlays/tree-selector.ts +570 -110
  370. package/src/overlays/usage-dashboard.ts +587 -12
  371. package/src/overlays/usage-row.ts +161 -25
  372. package/src/prompt/attachment-chips.ts +60 -0
  373. package/src/prompt/composer-attachments.ts +31 -9
  374. package/src/prompt/composer.ts +55 -2
  375. package/src/prompt/custom-editor.ts +302 -4
  376. package/src/prompt/editor-top-gap.ts +8 -0
  377. package/src/prompt/macos-spelling.ts +24 -9
  378. package/src/prompt/magic-keywords.ts +22 -1
  379. package/src/prompt/model-mention-autocomplete.ts +1 -0
  380. package/src/prompt/queued-messages.ts +101 -0
  381. package/src/prompt/skill-tokens.ts +5 -3
  382. package/src/prompt/welcome.ts +213 -6
  383. package/src/render/code-cell.ts +103 -2
  384. package/src/render/file-list.ts +29 -0
  385. package/src/render/hyperlink.ts +32 -0
  386. package/src/render/output-block.ts +110 -0
  387. package/src/render/output-pane.ts +37 -0
  388. package/src/render/tool-card.ts +137 -0
  389. package/src/render/tree-list.ts +39 -0
  390. package/src/render/width-aware-text.ts +20 -0
  391. package/src/setup/scenes/composer.ts +29 -0
  392. package/src/setup/scenes/glyph.ts +15 -0
  393. package/src/setup/scenes/model.ts +36 -8
  394. package/src/setup/scenes/outro.ts +28 -1
  395. package/src/setup/scenes/sign-in.ts +138 -24
  396. package/src/setup/scenes/splash.ts +28 -1
  397. package/src/setup/scenes/theme.ts +88 -3
  398. package/src/setup/scenes/types.ts +7 -28
  399. package/src/setup/startup-splash.ts +46 -9
  400. package/src/setup/wizard-overlay.ts +140 -23
  401. package/src/setup/wizard.ts +1 -1
  402. package/src/status-line/component.ts +414 -18
  403. package/src/status-line/context-usage.ts +279 -50
  404. package/src/status-line/footer.ts +94 -1
  405. package/src/status-line/metrics.ts +3 -6
  406. package/src/status-line/segments.ts +463 -97
  407. package/src/status-line/separators.ts +3 -16
  408. package/src/status-line/types.ts +43 -1
  409. package/src/stdin-buffer.ts +27 -21
  410. package/src/terminal-capabilities.ts +7 -0
  411. package/src/terminal.ts +153 -11
  412. package/src/theme/defaults/dark-neon-noir.json +100 -0
  413. package/src/theme/defaults/index.ts +2 -0
  414. package/src/theme/defaults/light-prism.json +5 -5
  415. package/src/theme/defaults/onyx.json +62 -62
  416. package/src/theme/mermaid-cache.ts +10 -1
  417. package/src/theme/schema.ts +15 -0
  418. package/src/theme/shimmer.ts +33 -0
  419. package/src/theme/theme-class.ts +24 -19
  420. package/src/theme/theme.ts +111 -9
  421. package/src/theme/tui-adapters.ts +14 -1
  422. package/src/tools/ask.ts +157 -1
  423. package/src/tools/ast-edit.ts +174 -1
  424. package/src/tools/ast-grep.ts +82 -2
  425. package/src/tools/autoresearch.ts +149 -1
  426. package/src/tools/bash.ts +233 -62
  427. package/src/tools/cfg-render.ts +66 -1
  428. package/src/tools/debug.ts +78 -1
  429. package/src/tools/default-renderer.ts +35 -1
  430. package/src/tools/edit.ts +357 -31
  431. package/src/tools/eval.ts +257 -1
  432. package/src/tools/fetch.ts +102 -3
  433. package/src/tools/find.ts +127 -1
  434. package/src/tools/github.ts +119 -10
  435. package/src/tools/glob.ts +116 -1
  436. package/src/tools/goal.ts +56 -1
  437. package/src/tools/grep.ts +83 -2
  438. package/src/tools/grouped-file-output.ts +205 -0
  439. package/src/tools/json-tree.ts +116 -1
  440. package/src/tools/lsp.ts +318 -1
  441. package/src/tools/mcp.ts +80 -1
  442. package/src/tools/memory.ts +93 -11
  443. package/src/tools/native-view.ts +292 -0
  444. package/src/tools/proc-render.ts +221 -1
  445. package/src/tools/read.ts +199 -4
  446. package/src/tools/renderer.ts +61 -0
  447. package/src/tools/report-tool-issue.ts +7 -1
  448. package/src/tools/resolve.ts +63 -1
  449. package/src/tools/streaming-output.ts +79 -16
  450. package/src/tools/task.ts +406 -4
  451. package/src/tools/think.ts +19 -1
  452. package/src/tools/todo.ts +89 -0
  453. package/src/tools/vibe.ts +230 -2
  454. package/src/tools/wait.ts +181 -1
  455. package/src/tools/web-search-types.ts +99 -0
  456. package/src/tools/web-search.ts +111 -170
  457. package/src/tools/write.ts +144 -5
  458. package/src/tools/xdev.ts +64 -1
  459. package/src/tui.ts +295 -4
  460. package/dist/types/setup/scenes/providers.d.ts +0 -3
  461. package/dist/types/setup/scenes/web-search.d.ts +0 -22
  462. package/src/setup/scenes/providers.ts +0 -110
  463. package/src/setup/scenes/web-search.ts +0 -165
@@ -1,11 +1,18 @@
1
- import { TERMINAL } from "../terminal-capabilities";
2
- import type { Component } from "../tui";
3
- import { padding, replaceTabs, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "../utils";
4
1
  import { APP_NAME } from "@oh-my-pi/pi-utils/dirs";
5
- import { theme } from "../theme/theme";
2
+ import type { TspSpan } from "@oh-my-pi/pi-wire";
6
3
  import { formatDoubleTap, formatKeyHint, formatKeyHints, type KeyName } from "../app-keybindings";
7
4
  import { editorKey } from "../chrome/keybinding-hints";
8
5
  import { getKeybindings, type Keybinding } from "../keybindings";
6
+ import { registerNativeBlob } from "../native/blobs";
7
+ import { card, col, kbd, keyed, node, row, span, text } from "../native/describe";
8
+ import type { DescribeContext, NativeChild, NativeNode, NativeUiEvent } from "../native/node";
9
+ import { runTranscriptAction } from "../chat/transcript-actions";
10
+ import { plainLine } from "../native/spans";
11
+ import { isNativeRendering } from "../native/state";
12
+ import { TERMINAL } from "../terminal-capabilities";
13
+ import { theme } from "../theme/theme";
14
+ import type { Component } from "../tui";
15
+ import { padding, replaceTabs, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "../utils";
9
16
  import tipsText from "./tips.txt" with { type: "text" };
10
17
 
11
18
  /** Tips embedded at build time, one per line; blanks dropped. Key placeholders
@@ -84,7 +91,12 @@ function renderNewTag(phase: number, encoding: ColorEncoding): string {
84
91
  /** Key placeholders in tips.txt: `{key:shift+tab}`, `{keys:up,down}`, `{tap:left}`, `{action:tui.editor.undo}`. */
85
92
  const TIP_KEY_PLACEHOLDER = /\{(key|keys|tap|action):([^}]+)\}/g;
86
93
 
87
- const MODIFIER_NAMES: Record<string, true | undefined> = { ctrl: true, shift: true, alt: true, super: true };
94
+ const MODIFIER_NAMES: Record<string, true | undefined> = {
95
+ ctrl: true,
96
+ shift: true,
97
+ alt: true,
98
+ super: true,
99
+ };
88
100
 
89
101
  /** A `+`-joined chord whose leading parts are modifiers (`ctrl+o`, `shift`, `left`). */
90
102
  function isKeyName(key: string): key is KeyName {
@@ -154,6 +166,8 @@ export function renderWelcomeTip(tip: string, boxWidth: number, phase = 0): stri
154
166
  export interface RecentSession {
155
167
  name: string;
156
168
  timeAgo: string;
169
+ /** Session file; a native click on the row resumes it. */
170
+ path?: string;
157
171
  }
158
172
 
159
173
  export interface LspServerInfo {
@@ -180,6 +194,7 @@ export class WelcomeComponent implements Component {
180
194
  // Bypassed while the intro animation runs (every frame differs).
181
195
  #cachedWidth = -1;
182
196
  #cachedLines: string[] | undefined;
197
+ #native: { tip: string | undefined; node: NativeNode } | undefined;
183
198
 
184
199
  constructor(
185
200
  private version: string,
@@ -201,7 +216,152 @@ export class WelcomeComponent implements Component {
201
216
  invalidate(): void {
202
217
  this.#cachedWidth = -1;
203
218
  this.#cachedLines = undefined;
219
+ this.#native = undefined;
204
220
  }
221
+
222
+ /**
223
+ * A `card` (`omp.welcome`) titled with the app version. The brand column
224
+ * (`omp.welcome.brand`: greeting, the animated SVG mark, model, provider) sits
225
+ * beside the info column (`omp.welcome.info`: prompt-sigil keycaps, LSP
226
+ * servers, recent sessions); the tip of the session closes the card. Roles
227
+ * carry the look (gradient logo, type scale, column hairline); a "[NEW]" tip
228
+ * carries a terminal-clocked shimmering tag.
229
+ */
230
+ describe(_cx: DescribeContext): NativeNode {
231
+ const tip = this.tip;
232
+ if (this.#native && this.#native.tip === tip) return this.#native.node;
233
+ const line = (spans: readonly TspSpan[], role?: string, key?: string): NativeNode =>
234
+ keyed(text(spans, { wrap: "none", truncate: "end", role }), key ?? role ?? "");
235
+ // Centered brand lines are short and fixed; the logo is multi-line art that must never truncate.
236
+ const art = (spans: readonly TspSpan[], role: string): NativeNode =>
237
+ keyed(text(spans, { wrap: "none", role }), role);
238
+ const brand = keyed(
239
+ col(
240
+ [
241
+ art([span("Welcome back!", "strong")], "omp.welcome.greeting"),
242
+ node(
243
+ "image",
244
+ {
245
+ blob: welcomeLogoBlob(),
246
+ alt: APP_NAME,
247
+ w: 128,
248
+ role: "omp.welcome.logo",
249
+ },
250
+ undefined,
251
+ "logo",
252
+ ),
253
+ art([span(plainLine(this.modelName), "accent")], "omp.welcome.model"),
254
+ art([span(plainLine(this.providerName), "muted")], "omp.welcome.provider"),
255
+ ],
256
+ { align: "center", role: "omp.welcome.brand" },
257
+ ),
258
+ "brand",
259
+ );
260
+ const section = (key: string, label: string, rows: readonly NativeChild[]): NativeNode =>
261
+ keyed(
262
+ col([line([span(label, "dim")], "omp.welcome.heading"), ...rows], {
263
+ gap: "xs",
264
+ role: `omp.welcome.${key}`,
265
+ }),
266
+ key,
267
+ );
268
+ const shortcut = (key: string, label: string): NativeNode =>
269
+ keyed(row([kbd(key), line([span(label, "muted")])], { gap: "sm" }), label);
270
+ const info: NativeChild[] = [
271
+ line([span(this.version, "dim mono")], "omp.welcome.version"),
272
+ section("tips", "Tips", [
273
+ shortcut("#", "prompt actions"),
274
+ shortcut("/", "commands"),
275
+ shortcut("!", "run bash"),
276
+ shortcut("$", "run python"),
277
+ ]),
278
+ ];
279
+ if (this.lspServers !== null) {
280
+ const lsp: NativeChild[] = [];
281
+ if (this.lspServers.length === 0) lsp.push(line([span("No LSP servers", "dim")], undefined, "none"));
282
+ for (const server of this.lspServers.slice(0, WELCOME_LSP_SLOTS)) {
283
+ const [symbol, token] =
284
+ server.status === "ready"
285
+ ? (["status.enabled", "success"] as const)
286
+ : server.status === "available"
287
+ ? (["status.enabled", "dim"] as const)
288
+ : server.status === "connecting"
289
+ ? (["status.pending", "muted"] as const)
290
+ : (["status.error", "error"] as const);
291
+ lsp.push(
292
+ keyed(
293
+ row(
294
+ [
295
+ text([span("●", token)], { role: "omp.welcome.lsp-dot", title: server.status, aria: symbol }),
296
+ line([span(server.name)]),
297
+ ...server.fileTypes
298
+ .slice(0, 3)
299
+ .map(type => node("badge", { text: type, role: "omp.welcome.lsp-type" }, undefined, type)),
300
+ ],
301
+ { gap: "sm", role: "omp.welcome.lsp-row" },
302
+ ),
303
+ server.name,
304
+ ),
305
+ );
306
+ }
307
+ info.push(section("lsp", "LSP servers", lsp));
308
+ }
309
+ const recents: NativeChild[] = [];
310
+ if (this.recentSessions.length === 0) recents.push(line([span("No recent sessions", "dim")], undefined, "none"));
311
+ for (const [index, session] of this.recentSessions.slice(0, WELCOME_SESSION_SLOTS).entries()) {
312
+ recents.push(
313
+ keyed(
314
+ row(
315
+ [
316
+ line([span(plainLine(session.name))], "omp.welcome.session"),
317
+ line([span(session.timeAgo, "dim")], "omp.welcome.age"),
318
+ ],
319
+ {
320
+ gap: "md",
321
+ justify: "between",
322
+ role: "omp.welcome.recent",
323
+ actions: session.path ? { click: "resume" } : undefined,
324
+ title: session.path ? `Resume ${plainLine(session.name)}` : undefined,
325
+ },
326
+ ),
327
+ `s${index}`,
328
+ ),
329
+ );
330
+ }
331
+ info.push(section("recents", "Recent sessions", recents));
332
+ const body: NativeChild[] = [
333
+ keyed(
334
+ row([brand, keyed(col(info, { gap: "md", role: "omp.welcome.info" }), "info")], {
335
+ align: "start",
336
+ wrap: true,
337
+ role: "omp.welcome.grid",
338
+ }),
339
+ "grid",
340
+ ),
341
+ ];
342
+ if (tip) {
343
+ const isNew = NEW_TIP_MARKER.test(tip);
344
+ const tipText = plainLine(expandTipKeys(isNew ? tip.replace(NEW_TIP_MARKER, "") : tip));
345
+ const tipRow: NativeChild[] = [
346
+ node("icon", { name: "lightbulb", role: "omp.welcome.tip-icon" }),
347
+ text(tipText, { wrap: "word", role: "omp.welcome.tip-text" }),
348
+ ];
349
+ if (isNew) tipRow.push(node("shimmer", { text: "New", role: "omp.welcome.new" }));
350
+ body.push(node("row", { gap: "sm", align: "start", role: "omp.welcome.tip" }, tipRow, "tip"));
351
+ }
352
+ // No head row or chevron: the card is the hero; the version sits in the info column.
353
+ const described = card({ role: "omp.welcome" }, body);
354
+ this.#native = { tip, node: described };
355
+ return described;
356
+ }
357
+ /** A click on a recent session resumes it. */
358
+ handleNativeEvent(event: NativeUiEvent): void {
359
+ if (event.type !== "action" || event.act !== "resume") return;
360
+ const index = Number(/\/s(\d+)$/.exec(event.key)?.[1]);
361
+ const path = this.recentSessions[index]?.path;
362
+ if (path) runTranscriptAction({ act: "resume", path });
363
+ }
364
+
205
365
  /** The intro keeps the welcome block mutable; settling lets it retire to history. */
206
366
  isTranscriptBlockFinalized(): boolean {
207
367
  return this.#animTimer == null;
@@ -214,6 +374,12 @@ export class WelcomeComponent implements Component {
214
374
  */
215
375
  playIntro(requestRender: () => void): void {
216
376
  this.#stopAnimation();
377
+ // The intro is a repaint-only gradient sweep; a TSP terminal shows the
378
+ // settled card right away.
379
+ if (isNativeRendering()) {
380
+ requestRender();
381
+ return;
382
+ }
217
383
  this.#requestRender = requestRender;
218
384
  this.#animStart = performance.now();
219
385
  this.#requestRender();
@@ -516,9 +682,47 @@ export class WelcomeComponent implements Component {
516
682
  }
517
683
  }
518
684
 
685
+ /**
686
+ * {@link PI_LOGO} as SVG for the native welcome, on the terminal's grid: a
687
+ * cell is 3×6 units, so the 12×5-cell art spans 36×30 from (14,16). The left
688
+ * leg's `▒▒` tail is a half-opacity cell; the gradient spans the whole art in
689
+ * user space (per-axis normalized, like {@link gradientLogo}) so the tail
690
+ * keeps its colour. Tern mounts SVG blobs as live DOM, so the classes are
691
+ * animation hooks: `trace` (the outline, `pathLength=1` for a draw-on), `mark`
692
+ * (the fills) and the gradient stops `s0`–`s2`.
693
+ */
694
+ const WELCOME_LOGO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="10 12 44 38">
695
+ <defs><linearGradient id="g" gradientUnits="userSpaceOnUse" gradientTransform="matrix(36 0 0 30 14 16)" x1="0" y1="0" x2="1" y2="1">
696
+ <stop class="s0" offset="0" stop-color="#ed4abf"/><stop class="s1" offset=".5" stop-color="#9b4dff"/><stop class="s2" offset="1" stop-color="#5ad8e6"/>
697
+ </linearGradient></defs>
698
+ <path class="mark" fill="url(#g)" d="M14 16h36v6h-9v24h-6V22h-6v12h-6V22h-9z"/>
699
+ <rect class="mark" fill="url(#g)" opacity=".5" x="23" y="34" width="6" height="6"/>
700
+ <path class="trace" fill="none" stroke="url(#g)" stroke-width="1" stroke-linejoin="round" pathLength="1" d="M14 16h36v6h-9v24h-6V22h-6v18h-6V22h-9z"/>
701
+ </svg>`;
702
+
703
+ let welcomeLogoId: string | undefined;
704
+
705
+ /** The registered blob id of {@link WELCOME_LOGO_SVG}. */
706
+ function welcomeLogoBlob(): string {
707
+ welcomeLogoId ??= registerNativeBlob(new TextEncoder().encode(WELCOME_LOGO_SVG), "image/svg+xml");
708
+ return welcomeLogoId;
709
+ }
710
+
519
711
  /** Block-grid brand mark shared by the welcome and setup surfaces. */
520
712
  export const PI_LOGO = ["████████████", " ██ ██ ", " ██ ██ ", " ▒▒ ██ ", " ██ "];
521
713
 
714
+ /** The block-grid brand mark as accent lines; `shimmer` declares the terminal-clocked shine sweep. */
715
+ export function logoNode(lines: readonly string[], shimmer: boolean): NativeNode {
716
+ return col(
717
+ lines.map(line =>
718
+ text([span(line, "accent", shimmer ? { fx: "shimmer" } : undefined)], {
719
+ wrap: "none",
720
+ }),
721
+ ),
722
+ { align: "center", role: "omp.setup.logo" },
723
+ );
724
+ }
725
+
522
726
  /** Multi-stop palette for the diagonal gradient. */
523
727
  const GRADIENT_STOPS: ReadonlyArray<readonly [number, number, number]> = [
524
728
  [248, 79, 204], // oklch(0.7 0.24 340)
@@ -637,7 +841,10 @@ function introLogoFrame(progress: number): string[] {
637
841
  const phase = ((((1 - eased) * INTRO_SWEEPS) % 1) + 1) % 1;
638
842
  const shinePos = (((progress * INTRO_SHINE_TRAVERSALS) % 1) + 1) % 1;
639
843
  const shineStrength = (1 - eased) ** 1.5;
640
- return gradientLogo(PI_LOGO, phase, { strength: shineStrength, pos: shinePos });
844
+ return gradientLogo(PI_LOGO, phase, {
845
+ strength: shineStrength,
846
+ pos: shinePos,
847
+ });
641
848
  }
642
849
 
643
850
  /** Resting gradient frame, cached for re-renders outside of the intro. */
@@ -1,11 +1,25 @@
1
1
  /**
2
2
  * Render a code or markdown cell with optional output section.
3
3
  */
4
+ import type { TspSpan } from "@oh-my-pi/pi-wire";
4
5
  import { Markdown } from "../components/markdown";
6
+ import { styledSpans } from "../native/spans";
7
+ import { code, md, span } from "../native/describe";
8
+ import type { NativeNode } from "../native/node";
5
9
  import { getMarkdownTheme, highlightCode, type Theme } from "../theme/theme";
6
10
  import { formatDuration, formatExpandHint, formatMoreItems, formatStatusIcon, replaceTabs } from "./render-utils";
7
- import { outputBlockContentWidth, renderOutputBlock } from "./output-block";
8
- import { formatOutputPaneLines, splitTerminalOutputLines, styleToolOutputLine } from "./output-pane";
11
+ import {
12
+ describeOutputBlock,
13
+ type NativeOutputBlockSection,
14
+ outputBlockContentWidth,
15
+ renderOutputBlock,
16
+ } from "./output-block";
17
+ import {
18
+ describeOutputLines,
19
+ formatOutputPaneLines,
20
+ splitTerminalOutputLines,
21
+ styleToolOutputLine,
22
+ } from "./output-pane";
9
23
  import type { State } from "./types";
10
24
 
11
25
  /** Content and display limits for a code preview with optional output. */
@@ -188,6 +202,93 @@ export function renderCodeCell(options: CodeCellOptions, theme: Theme): string[]
188
202
  return renderOutputBlock({ header: title, headerMeta: meta, state, sections, width }, theme);
189
203
  }
190
204
 
205
+ type CellHeaderOptions = Pick<CodeCellOptions, "index" | "total" | "title" | "duration" | "language" | "showLanguage">;
206
+
207
+ /** Header spans for a native cell: language icon, `[i/n]`, title. Status is the card's chip. */
208
+ function describeHeader(options: CellHeaderOptions, theme: Theme): { head: TspSpan[]; meta?: TspSpan[] } {
209
+ const head: TspSpan[] = [];
210
+ const push = (part: readonly TspSpan[]): void => {
211
+ if (head.length > 0) head.push(span(" "));
212
+ head.push(...part);
213
+ };
214
+ if (options.showLanguage && options.language) {
215
+ const icon = theme.getLangIconStyled(options.language);
216
+ if (icon) push(styledSpans(icon));
217
+ }
218
+ if (options.index !== undefined && options.total !== undefined && options.total > 1) {
219
+ push([span(`[${options.index + 1}/${options.total}]`, "accent")]);
220
+ }
221
+ if (options.title) push([span(options.title, "toolTitle")]);
222
+ if (head.length === 0) head.push(span("Code", "toolTitle"));
223
+ return {
224
+ head,
225
+ meta: options.duration === undefined ? undefined : [span(formatDuration(options.duration), "dim")],
226
+ };
227
+ }
228
+
229
+ function describeCellOutput(
230
+ output: string | undefined,
231
+ expanded: boolean,
232
+ outputMaxLines: number,
233
+ ): NativeOutputBlockSection | undefined {
234
+ if (!output?.trim()) return undefined;
235
+ return {
236
+ label: [span("Output", "toolTitle")],
237
+ key: "output",
238
+ body: [describeOutputLines(splitTerminalOutputLines(output), { expanded, collapsedMaxLines: outputMaxLines })],
239
+ };
240
+ }
241
+
242
+ /**
243
+ * The native form of {@link renderCodeCell}: a collapsible `card` holding a
244
+ * `code` node (numbered from `codeStartLine`, or the first explicit line
245
+ * number) and an `ansi` output section. The collapsed code clamp is the
246
+ * card preview; highlighting and gutters are the terminal's.
247
+ */
248
+ export function describeCodeCell(options: Omit<CodeCellOptions, "width">, theme: Theme): NativeNode {
249
+ const { expanded = false, outputMaxLines = 6, codeMaxLines = 12 } = options;
250
+ const { head, meta } = describeHeader(options, theme);
251
+ const start = options.codeStartLine ?? options.codeLineNumbers?.find((line): line is number => line != null);
252
+ const sections: NativeOutputBlockSection[] = [
253
+ {
254
+ key: "code",
255
+ body: [code(options.code ?? "", { lang: options.language, start, numbers: start !== undefined || undefined })],
256
+ },
257
+ ];
258
+ const output = describeCellOutput(options.output, expanded, outputMaxLines);
259
+ if (output) sections.push(output);
260
+ return describeOutputBlock({
261
+ head,
262
+ meta,
263
+ state: getState(options.status),
264
+ role: "omp.cell.code",
265
+ sections,
266
+ collapsible: true,
267
+ collapsed: !expanded,
268
+ preview: { lines: codeMaxLines },
269
+ });
270
+ }
271
+
272
+ /** The native form of {@link renderMarkdownCell}: a collapsible `card` holding `md` source and optional output. */
273
+ export function describeMarkdownCell(options: Omit<MarkdownCellOptions, "width">, theme: Theme): NativeNode {
274
+ const { expanded = false, outputMaxLines = 6, contentMaxLines = 12 } = options;
275
+ const { head, meta } = describeHeader(options, theme);
276
+ const sections: NativeOutputBlockSection[] = [];
277
+ if (options.content.trim()) sections.push({ key: "content", body: [md(options.content)] });
278
+ const output = describeCellOutput(options.output, expanded, outputMaxLines);
279
+ if (output) sections.push(output);
280
+ return describeOutputBlock({
281
+ head,
282
+ meta,
283
+ state: getState(options.status),
284
+ role: "omp.cell.markdown",
285
+ sections,
286
+ collapsible: true,
287
+ collapsed: !expanded,
288
+ preview: { lines: contentMaxLines },
289
+ });
290
+ }
291
+
191
292
  /** Content and display limits for a Markdown preview with optional output. */
192
293
  export interface MarkdownCellOptions {
193
294
  content: string;
@@ -2,7 +2,10 @@
2
2
  * Render file listings with optional icons and metadata.
3
3
  */
4
4
  import { getLanguageFromPath } from "../lang-from-path";
5
+ import { node, span } from "../native/describe";
6
+ import type { NativeNode } from "../native/node";
5
7
  import type { Theme } from "../theme/theme";
8
+ import { fileLinkSpan } from "./hyperlink";
6
9
  import { renderTreeList } from "./tree-list";
7
10
 
8
11
  /** A file-list item with optional display metadata. */
@@ -26,6 +29,32 @@ export interface FileListOptions {
26
29
  hyperlinkFn?: (absPath: string, displayText: string) => string;
27
30
  }
28
31
 
32
+ /**
33
+ * The native form of {@link renderFileList}: a `list` of path `item`s keyed
34
+ * by path, linked to their absolute path, with language/folder icons and the
35
+ * meta as detail. Collapsed, the list is clamped to `maxCollapsed` lines and
36
+ * the terminal scrolls the rest.
37
+ */
38
+ export function describeFileList(options: Omit<FileListOptions, "hyperlinkFn">): NativeNode {
39
+ const { files, expanded = false, maxCollapsed = 8, showIcons = true } = options;
40
+ const items = files.map(entry => {
41
+ const isDirectory = entry.isDirectory ?? entry.path.endsWith("/");
42
+ const s = isDirectory ? "path accent" : "path";
43
+ const label = entry.absPath ? fileLinkSpan(entry.absPath, entry.path, s) : span(entry.path, s);
44
+ return node(
45
+ "item",
46
+ {
47
+ label: [label],
48
+ icon: showIcons ? (isDirectory ? "folder" : (getLanguageFromPath(entry.path) ?? "file")) : undefined,
49
+ detail: entry.meta ? [span(entry.meta, "dim")] : undefined,
50
+ },
51
+ undefined,
52
+ entry.path,
53
+ );
54
+ });
55
+ return node("list", { max: expanded ? undefined : { lines: maxCollapsed } }, items);
56
+ }
57
+
29
58
  /** Render file entries as a themed tree listing. */
30
59
  export function renderFileList(options: FileListOptions, theme: Theme): string[] {
31
60
  const { files, expanded = false, maxCollapsed = 8, showIcons = true, hyperlinkFn } = options;
@@ -6,6 +6,8 @@
6
6
  * permits it. Falls back to plain text when disabled.
7
7
  */
8
8
  import * as url from "node:url";
9
+ import type { TspSpan } from "@oh-my-pi/pi-wire";
10
+ import { span } from "../native/describe";
9
11
  import { setTerminalHyperlinks, TERMINAL, type TerminalId } from "../terminal-capabilities";
10
12
 
11
13
  const OSC = "\x1b]";
@@ -175,6 +177,36 @@ export function urlHyperlinkAlways(url: string, displayText: string): string {
175
177
  }
176
178
  }
177
179
 
180
+ /**
181
+ * A native link span to an HTTP(S) URL (`www.` inputs become `https://`).
182
+ * Unlike the OSC 8 wrappers this ignores terminal capability detection — a
183
+ * TSP terminal always handles `href` — but honours an explicit `off` policy.
184
+ * Non-HTTP(S) or unparsable URLs yield a plain span.
185
+ */
186
+ export function urlLinkSpan(target: string, displayText: string, s = "link"): TspSpan {
187
+ if (hyperlinkMode === "off") return span(displayText, s);
188
+ const normalized = target.match(/^www\./i) ? `https://${target}` : target;
189
+ try {
190
+ const parsed = new URL(normalized);
191
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return span(displayText, s);
192
+ const href = safeHyperlinkUri(parsed.href);
193
+ return href ? span(displayText, s, { href }) : span(displayText, s);
194
+ } catch {
195
+ return span(displayText, s);
196
+ }
197
+ }
198
+
199
+ /**
200
+ * A native link span to a filesystem path as a plain `file://` URI (the
201
+ * terminal opens it through the system; the location stays in the visible
202
+ * text). Honours an explicit `off` policy.
203
+ */
204
+ export function fileLinkSpan(filePath: string, displayText: string, s = "path"): TspSpan {
205
+ if (hyperlinkMode === "off") return span(displayText, s);
206
+ const href = safeHyperlinkUri(url.pathToFileURL(filePath).href);
207
+ return href ? span(displayText, s, { href }) : span(displayText, s);
208
+ }
209
+
178
210
  /**
179
211
  * Wrap `displayText` in an OSC 8 hyperlink pointing at a filesystem path.
180
212
  *
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * Bordered output container with optional header and sections.
3
3
  */
4
+ import type { TspCardStatus, TspPreview, TspSpan, TspText, TspTone } from "@oh-my-pi/pi-wire";
5
+ import { node, span } from "../native/describe";
6
+ import type { NativeChild, NativeNode } from "../native/node";
4
7
  import { ImageProtocol, TERMINAL } from "../terminal-capabilities";
5
8
  import type { Theme, ThemeColor } from "../theme/theme";
6
9
  import type { Component } from "../tui";
@@ -206,6 +209,113 @@ export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): st
206
209
  return lines;
207
210
  }
208
211
 
212
+ /** Card tone for an output state. */
213
+ export function outputStateTone(state: State | undefined): TspTone {
214
+ switch (state) {
215
+ case "pending":
216
+ case "running":
217
+ return "pending";
218
+ case "success":
219
+ return "success";
220
+ case "error":
221
+ return "error";
222
+ case "warning":
223
+ return "warning";
224
+ default:
225
+ return "neutral";
226
+ }
227
+ }
228
+
229
+ /** Card status chip for an output state. */
230
+ export function outputStateStatus(state: State | undefined): TspCardStatus | undefined {
231
+ switch (state) {
232
+ case "pending":
233
+ return "pending";
234
+ case "running":
235
+ return "running";
236
+ case "success":
237
+ case "warning":
238
+ return "done";
239
+ case "error":
240
+ return "error";
241
+ default:
242
+ return undefined;
243
+ }
244
+ }
245
+
246
+ /** One body section of a native output block. */
247
+ export interface NativeOutputBlockSection {
248
+ /** Titled sub-section (the ANSI path's labelled separator bar). */
249
+ label?: TspText;
250
+ body: readonly NativeChild[];
251
+ /** Divide from the previous section with a rule. */
252
+ separator?: boolean;
253
+ /** Stable identity when sections come and go. */
254
+ key?: string;
255
+ }
256
+
257
+ /** Semantic inputs for {@link describeOutputBlock}. */
258
+ export interface NativeOutputBlockOptions {
259
+ head?: TspText;
260
+ meta?: TspText;
261
+ state?: State;
262
+ /** Card role (`omp.tool.bash`, `omp.eval.cell`, …). Defaults to `omp.output`. */
263
+ role?: string;
264
+ /** Override the state-derived tone (the ANSI path's `borderColor`). */
265
+ tone?: TspTone;
266
+ sections?: readonly NativeOutputBlockSection[];
267
+ collapsible?: boolean;
268
+ collapsed?: boolean;
269
+ preview?: TspPreview;
270
+ /** Flat card without a ring (inline/plain variants). */
271
+ inset?: boolean;
272
+ key?: string;
273
+ }
274
+
275
+ function asSpans(content: TspText): readonly TspSpan[] {
276
+ return typeof content === "string" ? [span(content)] : content;
277
+ }
278
+
279
+ /**
280
+ * The native form of {@link renderOutputBlock}: a `card` whose tone and
281
+ * status chip come from the state, head from the header plus meta, and body
282
+ * from the sections (labelled ones as `section`s, separators as `rule`s).
283
+ * Borders, background fills and wrapping are the terminal's.
284
+ */
285
+ export function describeOutputBlock(options: NativeOutputBlockOptions): NativeNode {
286
+ let head: TspText | undefined = options.head;
287
+ if (options.meta !== undefined && options.meta !== "") {
288
+ head = head === undefined ? options.meta : [...asSpans(head), span(" · ", "dim"), ...asSpans(options.meta)];
289
+ }
290
+ const children: NativeChild[] = [];
291
+ const sections = options.sections ?? [];
292
+ for (let index = 0; index < sections.length; index++) {
293
+ const section = sections[index]!;
294
+ const key = section.key ?? String(index);
295
+ if (section.label !== undefined) {
296
+ children.push(node("section", { head: section.label }, section.body, key));
297
+ continue;
298
+ }
299
+ if (section.separator && index > 0) children.push(node("rule", undefined, undefined, `${key}:rule`));
300
+ for (const child of section.body) children.push(child);
301
+ }
302
+ return node(
303
+ "card",
304
+ {
305
+ role: options.role ?? "omp.output",
306
+ tone: options.tone ?? outputStateTone(options.state),
307
+ status: outputStateStatus(options.state),
308
+ head,
309
+ collapsible: options.collapsible,
310
+ collapsed: options.collapsed,
311
+ preview: options.preview,
312
+ inset: options.inset,
313
+ },
314
+ children,
315
+ options.key,
316
+ );
317
+ }
318
+
209
319
  /**
210
320
  * Cached wrapper around `renderOutputBlock`.
211
321
  *
@@ -1,4 +1,6 @@
1
1
  import { Text } from "../components/text";
2
+ import { ansi } from "../native/describe";
3
+ import type { DescribeContext, NativeNode } from "../native/node";
2
4
  import { ImageProtocol, TERMINAL } from "../terminal-capabilities";
3
5
  import type { Theme } from "../theme/theme";
4
6
  import type { Component } from "../tui";
@@ -114,6 +116,28 @@ export function formatOutputPaneLines(options: OutputPaneFormatOptions, theme: T
114
116
  return { lines, hiddenCount, hasSixel };
115
117
  }
116
118
 
119
+ /** Display policy for {@link describeOutputLines}. */
120
+ export interface NativeOutputOptions {
121
+ expanded: boolean;
122
+ collapsedMaxLines: number;
123
+ expandedMaxLines?: number;
124
+ edge?: OutputPaneEdge;
125
+ key?: string;
126
+ }
127
+
128
+ /**
129
+ * Raw output rows as a native `ansi` mini-terminal: the terminal wraps and
130
+ * styles them. The row cap becomes a `preview` clamp (with its own "N more"
131
+ * affordance); a tail edge follows the stream.
132
+ */
133
+ export function describeOutputLines(lines: readonly string[], options: NativeOutputOptions): NativeNode {
134
+ const limit = options.expanded ? options.expandedMaxLines : options.collapsedMaxLines;
135
+ const preview =
136
+ limit !== undefined && Number.isFinite(limit) ? { lines: Math.max(0, Math.floor(limit)) } : undefined;
137
+ const described = ansi(lines.join("\n"), { follow: options.edge === "tail" ? true : undefined, preview });
138
+ return options.key === undefined ? described : { ...described, key: options.key };
139
+ }
140
+
117
141
  /** Mutable options for a live {@link OutputPane}. */
118
142
  export interface OutputPaneOptions extends Omit<OutputPaneFormatOptions, "lines"> {
119
143
  paddingX?: number;
@@ -135,6 +159,7 @@ export class OutputPane implements Component {
135
159
  #pendingCarriageReturn = false;
136
160
  #text: Text;
137
161
  #renderKey = "";
162
+ #native: NativeNode | undefined;
138
163
 
139
164
  constructor(theme: Theme, options: OutputPaneOptions, text = "") {
140
165
  this.#theme = theme;
@@ -240,6 +265,17 @@ export class OutputPane implements Component {
240
265
  return this.#lines.join("\n");
241
266
  }
242
267
 
268
+ /** The retained rows as an `ansi` node; streamed appends grow its text, so the reconciler sends `text append`. */
269
+ describe(_cx: DescribeContext): NativeNode {
270
+ this.#native ??= describeOutputLines(this.#lines, {
271
+ expanded: this.#options.expanded,
272
+ collapsedMaxLines: this.#options.collapsedMaxLines,
273
+ expandedMaxLines: this.#options.expandedMaxLines,
274
+ edge: this.#options.edge,
275
+ });
276
+ return this.#native;
277
+ }
278
+
243
279
  render(width: number): readonly string[] {
244
280
  const paddingX = getPaddingX(this.#options.paddingX ?? 0);
245
281
  const contentWidth = Math.max(1, width - paddingX * 2);
@@ -262,6 +298,7 @@ export class OutputPane implements Component {
262
298
 
263
299
  invalidate(): void {
264
300
  this.#renderKey = "";
301
+ this.#native = undefined;
265
302
  this.#text.invalidate();
266
303
  }
267
304