@oh-my-pi/pi-tui 18.4.3 → 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 (447) hide show
  1. package/CHANGELOG.md +36 -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/todo-reminder.d.ts +4 -1
  22. package/dist/types/chat/tool-execution.d.ts +25 -1
  23. package/dist/types/chat/transcript-actions.d.ts +37 -0
  24. package/dist/types/chat/transcript-entry.d.ts +3 -1
  25. package/dist/types/chat/user-message.d.ts +25 -0
  26. package/dist/types/chrome/collab-qrcode.d.ts +7 -0
  27. package/dist/types/chrome/context-thresholds.d.ts +11 -0
  28. package/dist/types/chrome/countdown-timer.d.ts +9 -3
  29. package/dist/types/chrome/diff.d.ts +12 -0
  30. package/dist/types/chrome/dynamic-border.d.ts +3 -0
  31. package/dist/types/chrome/format.d.ts +6 -0
  32. package/dist/types/chrome/message-divider.d.ts +13 -0
  33. package/dist/types/chrome/message-frame.d.ts +10 -0
  34. package/dist/types/chrome/message-notice.d.ts +23 -0
  35. package/dist/types/chrome/overlay-box.d.ts +11 -2
  36. package/dist/types/chrome/qrcode.d.ts +7 -0
  37. package/dist/types/chrome/segment-track.d.ts +7 -0
  38. package/dist/types/chrome/selector-helpers.d.ts +0 -6
  39. package/dist/types/chrome/status-notice.d.ts +14 -0
  40. package/dist/types/chrome/streaming-panel.d.ts +3 -0
  41. package/dist/types/chrome/tool-activity.d.ts +3 -0
  42. package/dist/types/chrome/transcript-container.d.ts +13 -0
  43. package/dist/types/chrome/transcript-status.d.ts +15 -3
  44. package/dist/types/components/box.d.ts +7 -0
  45. package/dist/types/components/disclosure.d.ts +9 -0
  46. package/dist/types/components/editor.d.ts +37 -0
  47. package/dist/types/components/form.d.ts +14 -0
  48. package/dist/types/components/image.d.ts +7 -0
  49. package/dist/types/components/input.d.ts +20 -1
  50. package/dist/types/components/key-value-list.d.ts +3 -0
  51. package/dist/types/components/layout/geometry.d.ts +16 -0
  52. package/dist/types/components/layout/row.d.ts +7 -0
  53. package/dist/types/components/layout/split-pane.d.ts +8 -0
  54. package/dist/types/components/layout/stack.d.ts +6 -0
  55. package/dist/types/components/loader.d.ts +48 -0
  56. package/dist/types/components/markdown.d.ts +8 -0
  57. package/dist/types/components/metric.d.ts +7 -0
  58. package/dist/types/components/progress-bar.d.ts +3 -0
  59. package/dist/types/components/scroll-view.d.ts +6 -0
  60. package/dist/types/components/section.d.ts +3 -0
  61. package/dist/types/components/select-list.d.ts +33 -0
  62. package/dist/types/components/settings-list.d.ts +68 -0
  63. package/dist/types/components/spacer.d.ts +4 -0
  64. package/dist/types/components/tab-bar.d.ts +9 -0
  65. package/dist/types/components/table.d.ts +7 -0
  66. package/dist/types/components/text.d.ts +6 -0
  67. package/dist/types/components/tree-view.d.ts +9 -0
  68. package/dist/types/components/truncated-text.d.ts +3 -0
  69. package/dist/types/components/wizard-step.d.ts +6 -0
  70. package/dist/types/hotkeys-markdown.d.ts +24 -0
  71. package/dist/types/index.d.ts +5 -0
  72. package/dist/types/latex-block.d.ts +7 -0
  73. package/dist/types/native/apply.d.ts +39 -0
  74. package/dist/types/native/backend.d.ts +94 -0
  75. package/dist/types/native/blobs.d.ts +29 -0
  76. package/dist/types/native/describe.d.ts +56 -0
  77. package/dist/types/native/encode.d.ts +50 -0
  78. package/dist/types/native/icons.d.ts +18 -0
  79. package/dist/types/native/memo.d.ts +27 -0
  80. package/dist/types/native/node.d.ts +107 -0
  81. package/dist/types/native/overlay.d.ts +64 -0
  82. package/dist/types/native/picker.d.ts +124 -0
  83. package/dist/types/native/reconcile.d.ts +41 -0
  84. package/dist/types/native/settle.d.ts +11 -0
  85. package/dist/types/native/spans.d.ts +21 -0
  86. package/dist/types/native/state.d.ts +6 -0
  87. package/dist/types/native/tone.d.ts +24 -0
  88. package/dist/types/overlays/advisor-config.d.ts +20 -0
  89. package/dist/types/overlays/agent-hub-renderer.d.ts +27 -11
  90. package/dist/types/overlays/agent-hub.d.ts +10 -0
  91. package/dist/types/overlays/agent-transcript-viewer.d.ts +7 -0
  92. package/dist/types/overlays/agents-hub.d.ts +8 -0
  93. package/dist/types/overlays/annotation-overlay.d.ts +3 -0
  94. package/dist/types/overlays/ask-dialog.d.ts +23 -0
  95. package/dist/types/overlays/bordered-loader.d.ts +3 -0
  96. package/dist/types/overlays/btw-history-panel.d.ts +9 -0
  97. package/dist/types/overlays/btw-panel.d.ts +3 -0
  98. package/dist/types/overlays/cleanse-panel.d.ts +5 -2
  99. package/dist/types/overlays/composer-shape-preview.d.ts +7 -1
  100. package/dist/types/overlays/copy-selector.d.ts +38 -0
  101. package/dist/types/overlays/error-banner.d.ts +9 -0
  102. package/dist/types/overlays/extensions/extension-list.d.ts +1 -0
  103. package/dist/types/overlays/history-search.d.ts +18 -0
  104. package/dist/types/overlays/hook-editor.d.ts +28 -1
  105. package/dist/types/overlays/hook-input.d.ts +3 -0
  106. package/dist/types/overlays/hook-selector.d.ts +10 -0
  107. package/dist/types/overlays/hub-frame.d.ts +18 -0
  108. package/dist/types/overlays/jobs-panel.d.ts +24 -0
  109. package/dist/types/overlays/login-dialog.d.ts +10 -0
  110. package/dist/types/overlays/logout-account-selector.d.ts +4 -0
  111. package/dist/types/overlays/mcp-add-wizard.d.ts +4 -0
  112. package/dist/types/overlays/model-browser.d.ts +69 -0
  113. package/dist/types/overlays/model-hub.d.ts +7 -0
  114. package/dist/types/overlays/model-picker.d.ts +7 -0
  115. package/dist/types/overlays/move-overlay.d.ts +3 -0
  116. package/dist/types/overlays/oauth-selector.d.ts +4 -0
  117. package/dist/types/overlays/omfg-panel.d.ts +3 -0
  118. package/dist/types/overlays/pause-screen.d.ts +12 -0
  119. package/dist/types/overlays/plan-review-overlay.d.ts +5 -0
  120. package/dist/types/overlays/plan-save-overlay.d.ts +10 -0
  121. package/dist/types/overlays/plugin-selector.d.ts +4 -0
  122. package/dist/types/overlays/plugin-settings.d.ts +30 -0
  123. package/dist/types/overlays/queue-mode-selector.d.ts +4 -0
  124. package/dist/types/overlays/reset-usage-selector.d.ts +8 -0
  125. package/dist/types/overlays/rewind-selector.d.ts +5 -0
  126. package/dist/types/overlays/session-info-overlay.d.ts +19 -1
  127. package/dist/types/overlays/session-selector.d.ts +64 -1
  128. package/dist/types/overlays/settings-defs.d.ts +14 -0
  129. package/dist/types/overlays/settings-selector.d.ts +21 -0
  130. package/dist/types/overlays/show-images-selector.d.ts +4 -0
  131. package/dist/types/overlays/snapcompact-shape-preview.d.ts +2 -0
  132. package/dist/types/overlays/stats-notice.d.ts +8 -0
  133. package/dist/types/overlays/theme-selector.d.ts +11 -0
  134. package/dist/types/overlays/thinking-selector.d.ts +4 -0
  135. package/dist/types/overlays/tree-selector.d.ts +60 -2
  136. package/dist/types/overlays/usage-dashboard.d.ts +26 -3
  137. package/dist/types/overlays/usage-row.d.ts +36 -2
  138. package/dist/types/prompt/attachment-chips.d.ts +8 -0
  139. package/dist/types/prompt/composer-attachments.d.ts +15 -3
  140. package/dist/types/prompt/composer.d.ts +18 -1
  141. package/dist/types/prompt/custom-editor.d.ts +48 -2
  142. package/dist/types/prompt/editor-top-gap.d.ts +2 -0
  143. package/dist/types/prompt/macos-spelling.d.ts +6 -0
  144. package/dist/types/prompt/magic-keywords.d.ts +9 -0
  145. package/dist/types/prompt/queued-messages.d.ts +23 -0
  146. package/dist/types/prompt/skill-tokens.d.ts +4 -2
  147. package/dist/types/prompt/welcome.d.ts +16 -0
  148. package/dist/types/render/code-cell.d.ts +10 -0
  149. package/dist/types/render/file-list.d.ts +8 -0
  150. package/dist/types/render/hyperlink.d.ts +14 -0
  151. package/dist/types/render/output-block.d.ts +43 -0
  152. package/dist/types/render/output-pane.d.ts +17 -0
  153. package/dist/types/render/tool-card.d.ts +8 -0
  154. package/dist/types/render/tree-list.d.ts +8 -0
  155. package/dist/types/render/width-aware-text.d.ts +7 -0
  156. package/dist/types/setup/scenes/outro.d.ts +7 -0
  157. package/dist/types/setup/scenes/sign-in.d.ts +7 -0
  158. package/dist/types/setup/scenes/splash.d.ts +8 -0
  159. package/dist/types/setup/scenes/types.d.ts +6 -1
  160. package/dist/types/setup/wizard-overlay.d.ts +9 -0
  161. package/dist/types/status-line/component.d.ts +49 -5
  162. package/dist/types/status-line/context-usage.d.ts +20 -0
  163. package/dist/types/status-line/footer.d.ts +8 -0
  164. package/dist/types/status-line/metrics.d.ts +1 -2
  165. package/dist/types/status-line/segments.d.ts +10 -1
  166. package/dist/types/status-line/types.d.ts +40 -1
  167. package/dist/types/terminal-capabilities.d.ts +1 -1
  168. package/dist/types/terminal.d.ts +27 -0
  169. package/dist/types/theme/defaults/index.d.ts +100 -0
  170. package/dist/types/theme/schema.d.ts +2 -0
  171. package/dist/types/theme/shimmer.d.ts +8 -0
  172. package/dist/types/theme/theme-class.d.ts +2 -0
  173. package/dist/types/theme/theme.d.ts +33 -1
  174. package/dist/types/tools/ask.d.ts +3 -0
  175. package/dist/types/tools/ast-edit.d.ts +10 -1
  176. package/dist/types/tools/ast-grep.d.ts +10 -1
  177. package/dist/types/tools/autoresearch.d.ts +21 -4
  178. package/dist/types/tools/bash.d.ts +30 -1
  179. package/dist/types/tools/cfg-render.d.ts +5 -1
  180. package/dist/types/tools/debug.d.ts +3 -1
  181. package/dist/types/tools/default-renderer.d.ts +6 -1
  182. package/dist/types/tools/edit.d.ts +14 -1
  183. package/dist/types/tools/eval.d.ts +12 -1
  184. package/dist/types/tools/fetch.d.ts +16 -1
  185. package/dist/types/tools/find.d.ts +15 -1
  186. package/dist/types/tools/github.d.ts +3 -0
  187. package/dist/types/tools/glob.d.ts +14 -1
  188. package/dist/types/tools/goal.d.ts +3 -1
  189. package/dist/types/tools/grep.d.ts +14 -1
  190. package/dist/types/tools/grouped-file-output.d.ts +58 -0
  191. package/dist/types/tools/json-tree.d.ts +20 -0
  192. package/dist/types/tools/lsp.d.ts +3 -10
  193. package/dist/types/tools/mcp.d.ts +16 -1
  194. package/dist/types/tools/memory.d.ts +26 -0
  195. package/dist/types/tools/native-view.d.ts +90 -0
  196. package/dist/types/tools/proc-render.d.ts +7 -1
  197. package/dist/types/tools/read.d.ts +23 -1
  198. package/dist/types/tools/renderer.d.ts +57 -0
  199. package/dist/types/tools/report-tool-issue.d.ts +3 -0
  200. package/dist/types/tools/resolve.d.ts +14 -1
  201. package/dist/types/tools/task.d.ts +3 -0
  202. package/dist/types/tools/think.d.ts +3 -0
  203. package/dist/types/tools/todo.d.ts +12 -0
  204. package/dist/types/tools/vibe.d.ts +3 -1
  205. package/dist/types/tools/wait.d.ts +3 -0
  206. package/dist/types/tools/web-search.d.ts +8 -0
  207. package/dist/types/tools/write.d.ts +14 -1
  208. package/dist/types/tools/xdev.d.ts +13 -0
  209. package/dist/types/tui.d.ts +49 -0
  210. package/package.json +9 -9
  211. package/src/apps/autoresearch-dashboard.ts +362 -4
  212. package/src/apps/cleanse-board.ts +219 -1
  213. package/src/apps/cleanse-picker.ts +9 -1
  214. package/src/apps/debug/log-viewer.ts +15 -15
  215. package/src/apps/debug/protocol-probe.ts +2 -20
  216. package/src/apps/git/avatar.ts +2 -22
  217. package/src/apps/git/git-tui.ts +406 -59
  218. package/src/apps/git/help.ts +130 -0
  219. package/src/apps/git/sidebar.ts +491 -0
  220. package/src/apps/live-visualizer.ts +65 -0
  221. package/src/apps/ps-top.ts +448 -17
  222. package/src/apps/session-picker.ts +1 -0
  223. package/src/apps/setup-model-picker.ts +5 -1
  224. package/src/apps/standalone-picker.ts +55 -1
  225. package/src/autocomplete.ts +44 -1
  226. package/src/chat/advisor-message.ts +72 -3
  227. package/src/chat/assistant-message.ts +346 -11
  228. package/src/chat/background-tan-message.ts +4 -4
  229. package/src/chat/bash-execution.ts +81 -0
  230. package/src/chat/cache-invalidation-marker.ts +8 -0
  231. package/src/chat/chat-transcript-builder.ts +37 -6
  232. package/src/chat/collab-prompt-message.ts +15 -3
  233. package/src/chat/compaction-summary-message.ts +74 -1
  234. package/src/chat/custom-message.ts +3 -1
  235. package/src/chat/eval-execution.ts +57 -0
  236. package/src/chat/execution-shared.ts +153 -1
  237. package/src/chat/hook-message.ts +1 -0
  238. package/src/chat/late-diagnostics-message.ts +85 -2
  239. package/src/chat/read-tool-group.ts +341 -1
  240. package/src/chat/served-model-marker.ts +8 -0
  241. package/src/chat/skill-message.ts +63 -0
  242. package/src/chat/stripped-tool-calls-placeholder.ts +18 -10
  243. package/src/chat/todo-reminder.ts +34 -4
  244. package/src/chat/tool-execution.ts +385 -10
  245. package/src/chat/transcript-actions.ts +38 -0
  246. package/src/chat/transcript-browser.ts +2 -9
  247. package/src/chat/transcript-entry.ts +10 -1
  248. package/src/chat/transcript-render-helpers.ts +16 -15
  249. package/src/chat/ttsr-notification.ts +38 -1
  250. package/src/chat/user-message.ts +167 -4
  251. package/src/chrome/collab-qrcode.ts +27 -2
  252. package/src/chrome/context-thresholds.ts +34 -0
  253. package/src/chrome/countdown-timer.ts +24 -1
  254. package/src/chrome/diff.ts +60 -1
  255. package/src/chrome/dynamic-border.ts +7 -0
  256. package/src/chrome/format.ts +12 -0
  257. package/src/chrome/message-divider.ts +33 -1
  258. package/src/chrome/message-frame.ts +53 -10
  259. package/src/chrome/message-notice.ts +71 -0
  260. package/src/chrome/overlay-box.ts +45 -2
  261. package/src/chrome/qrcode.ts +28 -0
  262. package/src/chrome/segment-track.ts +26 -0
  263. package/src/chrome/selector-helpers.ts +1 -17
  264. package/src/chrome/status-notice.ts +46 -0
  265. package/src/chrome/streaming-panel.ts +25 -1
  266. package/src/chrome/tool-activity.ts +20 -0
  267. package/src/chrome/transcript-container.ts +37 -0
  268. package/src/chrome/transcript-status.ts +40 -11
  269. package/src/components/box.ts +51 -0
  270. package/src/components/disclosure.ts +33 -0
  271. package/src/components/editor.ts +216 -27
  272. package/src/components/form.ts +93 -9
  273. package/src/components/image.ts +30 -0
  274. package/src/components/input.ts +77 -26
  275. package/src/components/key-value-list.ts +18 -0
  276. package/src/components/layout/geometry.ts +44 -0
  277. package/src/components/layout/row.ts +30 -0
  278. package/src/components/layout/split-pane.ts +65 -0
  279. package/src/components/layout/stack.ts +27 -0
  280. package/src/components/loader.ts +183 -1
  281. package/src/components/markdown.ts +21 -0
  282. package/src/components/metric.ts +39 -0
  283. package/src/components/progress-bar.ts +28 -0
  284. package/src/components/scroll-view.ts +23 -0
  285. package/src/components/section.ts +16 -0
  286. package/src/components/select-list.ts +174 -25
  287. package/src/components/settings-list.ts +264 -7
  288. package/src/components/spacer.ts +17 -0
  289. package/src/components/tab-bar.ts +42 -0
  290. package/src/components/table.ts +34 -0
  291. package/src/components/text.ts +23 -0
  292. package/src/components/tree-view.ts +65 -0
  293. package/src/components/truncated-text.ts +14 -0
  294. package/src/components/wizard-step.ts +18 -9
  295. package/src/debug-server.ts +14 -7
  296. package/src/hotkeys-markdown.ts +251 -69
  297. package/src/index.ts +6 -0
  298. package/src/latex-block.ts +11 -0
  299. package/src/native/apply.ts +275 -0
  300. package/src/native/backend.ts +682 -0
  301. package/src/native/blobs.ts +70 -0
  302. package/src/native/describe.ts +124 -0
  303. package/src/native/encode.ts +233 -0
  304. package/src/native/icons.ts +184 -0
  305. package/src/native/memo.ts +64 -0
  306. package/src/native/node.ts +112 -0
  307. package/src/native/overlay.ts +131 -0
  308. package/src/native/picker.ts +333 -0
  309. package/src/native/reconcile.ts +1063 -0
  310. package/src/native/settle.ts +23 -0
  311. package/src/native/spans.ts +308 -0
  312. package/src/native/state.ts +28 -0
  313. package/src/native/tone.ts +79 -0
  314. package/src/overlays/advisor-config.ts +420 -0
  315. package/src/overlays/agent-hub-renderer.ts +155 -18
  316. package/src/overlays/agent-hub.ts +1037 -44
  317. package/src/overlays/agent-transcript-viewer.ts +129 -0
  318. package/src/overlays/agents-hub.ts +688 -53
  319. package/src/overlays/annotation-overlay.ts +391 -52
  320. package/src/overlays/ask-dialog.ts +435 -24
  321. package/src/overlays/bordered-loader.ts +17 -0
  322. package/src/overlays/btw-history-panel.ts +182 -0
  323. package/src/overlays/btw-panel.ts +68 -2
  324. package/src/overlays/cleanse-panel.ts +105 -15
  325. package/src/overlays/codex-reset-fireworks.ts +65 -5
  326. package/src/overlays/composer-shape-preview.ts +26 -1
  327. package/src/overlays/copy-selector.ts +545 -23
  328. package/src/overlays/error-banner.ts +44 -0
  329. package/src/overlays/extensions/extension-list.ts +23 -17
  330. package/src/overlays/history-search.ts +175 -33
  331. package/src/overlays/hook-editor.ts +113 -6
  332. package/src/overlays/hook-input.ts +22 -1
  333. package/src/overlays/hook-selector.ts +311 -22
  334. package/src/overlays/hub-frame.ts +80 -0
  335. package/src/overlays/jobs-panel.ts +112 -0
  336. package/src/overlays/login-dialog.ts +183 -1
  337. package/src/overlays/logout-account-selector.ts +102 -4
  338. package/src/overlays/mcp-add-wizard.ts +232 -53
  339. package/src/overlays/model-browser.ts +681 -22
  340. package/src/overlays/model-hub.ts +1402 -78
  341. package/src/overlays/model-picker.ts +175 -1
  342. package/src/overlays/move-overlay.ts +45 -0
  343. package/src/overlays/oauth-selector.ts +227 -23
  344. package/src/overlays/omfg-panel.ts +86 -2
  345. package/src/overlays/pause-screen.ts +55 -4
  346. package/src/overlays/plan-review-overlay.ts +352 -0
  347. package/src/overlays/plan-save-overlay.ts +45 -0
  348. package/src/overlays/plugin-selector.ts +21 -1
  349. package/src/overlays/plugin-settings.ts +195 -5
  350. package/src/overlays/queue-mode-selector.ts +19 -1
  351. package/src/overlays/reset-usage-selector.ts +110 -40
  352. package/src/overlays/rewind-selector.ts +458 -44
  353. package/src/overlays/session-account-selector.ts +1 -1
  354. package/src/overlays/session-info-overlay.ts +137 -1
  355. package/src/overlays/session-selector.ts +807 -46
  356. package/src/overlays/settings-defs.ts +41 -0
  357. package/src/overlays/settings-selector.ts +583 -23
  358. package/src/overlays/show-images-selector.ts +18 -1
  359. package/src/overlays/snapcompact-shape-preview.ts +48 -3
  360. package/src/overlays/stats-notice.ts +31 -0
  361. package/src/overlays/theme-selector.ts +31 -1
  362. package/src/overlays/thinking-selector.ts +22 -1
  363. package/src/overlays/tree-selector.ts +570 -110
  364. package/src/overlays/usage-dashboard.ts +587 -12
  365. package/src/overlays/usage-row.ts +161 -25
  366. package/src/prompt/attachment-chips.ts +60 -0
  367. package/src/prompt/composer-attachments.ts +31 -9
  368. package/src/prompt/composer.ts +55 -2
  369. package/src/prompt/custom-editor.ts +302 -4
  370. package/src/prompt/editor-top-gap.ts +8 -0
  371. package/src/prompt/macos-spelling.ts +24 -9
  372. package/src/prompt/magic-keywords.ts +22 -1
  373. package/src/prompt/model-mention-autocomplete.ts +1 -0
  374. package/src/prompt/queued-messages.ts +101 -0
  375. package/src/prompt/skill-tokens.ts +5 -3
  376. package/src/prompt/welcome.ts +213 -6
  377. package/src/render/code-cell.ts +103 -2
  378. package/src/render/file-list.ts +29 -0
  379. package/src/render/hyperlink.ts +32 -0
  380. package/src/render/output-block.ts +110 -0
  381. package/src/render/output-pane.ts +37 -0
  382. package/src/render/tool-card.ts +137 -0
  383. package/src/render/tree-list.ts +39 -0
  384. package/src/render/width-aware-text.ts +20 -0
  385. package/src/setup/scenes/composer.ts +29 -0
  386. package/src/setup/scenes/glyph.ts +15 -0
  387. package/src/setup/scenes/model.ts +36 -8
  388. package/src/setup/scenes/outro.ts +28 -1
  389. package/src/setup/scenes/sign-in.ts +122 -13
  390. package/src/setup/scenes/splash.ts +28 -1
  391. package/src/setup/scenes/theme.ts +88 -3
  392. package/src/setup/scenes/types.ts +7 -1
  393. package/src/setup/startup-splash.ts +46 -9
  394. package/src/setup/wizard-overlay.ts +140 -23
  395. package/src/status-line/component.ts +398 -16
  396. package/src/status-line/context-usage.ts +279 -50
  397. package/src/status-line/footer.ts +94 -1
  398. package/src/status-line/metrics.ts +3 -6
  399. package/src/status-line/segments.ts +463 -97
  400. package/src/status-line/separators.ts +3 -16
  401. package/src/status-line/types.ts +43 -1
  402. package/src/terminal-capabilities.ts +7 -0
  403. package/src/terminal.ts +130 -2
  404. package/src/theme/defaults/dark-neon-noir.json +100 -0
  405. package/src/theme/defaults/index.ts +2 -0
  406. package/src/theme/defaults/light-prism.json +5 -5
  407. package/src/theme/defaults/onyx.json +62 -62
  408. package/src/theme/schema.ts +15 -0
  409. package/src/theme/shimmer.ts +33 -0
  410. package/src/theme/theme-class.ts +24 -19
  411. package/src/theme/theme.ts +111 -9
  412. package/src/tools/ask.ts +157 -1
  413. package/src/tools/ast-edit.ts +174 -1
  414. package/src/tools/ast-grep.ts +82 -2
  415. package/src/tools/autoresearch.ts +149 -1
  416. package/src/tools/bash.ts +180 -49
  417. package/src/tools/cfg-render.ts +66 -1
  418. package/src/tools/debug.ts +78 -1
  419. package/src/tools/default-renderer.ts +35 -1
  420. package/src/tools/edit.ts +247 -2
  421. package/src/tools/eval.ts +257 -1
  422. package/src/tools/fetch.ts +102 -3
  423. package/src/tools/find.ts +127 -1
  424. package/src/tools/github.ts +119 -10
  425. package/src/tools/glob.ts +116 -1
  426. package/src/tools/goal.ts +56 -1
  427. package/src/tools/grep.ts +83 -2
  428. package/src/tools/grouped-file-output.ts +205 -0
  429. package/src/tools/json-tree.ts +116 -1
  430. package/src/tools/lsp.ts +318 -1
  431. package/src/tools/mcp.ts +80 -1
  432. package/src/tools/memory.ts +93 -11
  433. package/src/tools/native-view.ts +292 -0
  434. package/src/tools/proc-render.ts +221 -1
  435. package/src/tools/read.ts +199 -4
  436. package/src/tools/renderer.ts +61 -0
  437. package/src/tools/report-tool-issue.ts +7 -1
  438. package/src/tools/resolve.ts +63 -1
  439. package/src/tools/task.ts +406 -4
  440. package/src/tools/think.ts +19 -1
  441. package/src/tools/todo.ts +89 -0
  442. package/src/tools/vibe.ts +230 -2
  443. package/src/tools/wait.ts +181 -1
  444. package/src/tools/web-search.ts +113 -1
  445. package/src/tools/write.ts +144 -5
  446. package/src/tools/xdev.ts +64 -1
  447. package/src/tui.ts +294 -3
@@ -1,8 +1,16 @@
1
- import { Container } from "../tui";
1
+ import { type Component, Container } from "../tui";
2
+ import { isNativeRendering } from "../native/state";
2
3
  import { Disclosure } from "../components/disclosure";
3
4
  import { Text } from "../components/text";
4
5
  import { formatDiagnostics } from "../render/render-utils";
5
- import { getLanguageFromPath, theme } from "../theme";
6
+ import { getLanguageFromPath, getThemeEpoch, theme } from "../theme";
7
+ import { card, span, text, withHidden } from "../native/describe";
8
+ import { type NativeNode, type NativeUiEvent, rootToggleExpanded } from "../native/node";
9
+ import { plainText } from "../native/spans";
10
+ import { Memo } from "../native/memo";
11
+
12
+ /** Diagnostics shown by the collapsed native card, matching the ANSI tree's collapsed count. */
13
+ const COLLAPSED_DIAGNOSTICS = 5;
6
14
 
7
15
  const EMPTY_ROWS: readonly string[] = [];
8
16
 
@@ -14,6 +22,45 @@ export interface LateDiagnosticsFile {
14
22
  messages?: string[];
15
23
  }
16
24
 
25
+ /** A tool frame (edit/write) that takes late diagnostics for its own paths. */
26
+ interface LateDiagnosticsTarget {
27
+ attachLateDiagnostics(
28
+ files: readonly { path: string; summary: string; errored: boolean; messages: string[] }[],
29
+ ): boolean;
30
+ }
31
+
32
+ /**
33
+ * Native terminals append late diagnostics into the edit/write frame they
34
+ * belong to: each file goes to the most recent tool component in `blocks`
35
+ * that accepts it. Returns the files no frame took (all of them on the ANSI
36
+ * path), for the standalone {@link LateDiagnosticsMessageComponent}.
37
+ */
38
+ export function routeLateDiagnostics(
39
+ blocks: readonly Component[],
40
+ files: readonly LateDiagnosticsFile[],
41
+ ): LateDiagnosticsFile[] {
42
+ if (!isNativeRendering()) return [...files];
43
+ const targets = blocks.filter(
44
+ (block): block is Component & LateDiagnosticsTarget =>
45
+ typeof (block as Partial<LateDiagnosticsTarget>).attachLateDiagnostics === "function",
46
+ );
47
+ const unrouted: LateDiagnosticsFile[] = [];
48
+ for (const file of files) {
49
+ const entry = file.path
50
+ ? {
51
+ path: file.path,
52
+ summary: file.summary ?? "",
53
+ errored: file.errored === true,
54
+ messages: file.messages ?? [],
55
+ }
56
+ : undefined;
57
+ const routed =
58
+ entry !== undefined && targets.findLast(target => target.attachLateDiagnostics([entry])) !== undefined;
59
+ if (!routed) unrouted.push(file);
60
+ }
61
+ return unrouted;
62
+ }
63
+
17
64
  /**
18
65
  * Renders late LSP diagnostics (arrived after edit/write returned) in the
19
66
  * transcript, reusing the same tree renderer the edit/write tools use so the
@@ -26,6 +73,8 @@ export class LateDiagnosticsMessageComponent extends Container {
26
73
  // lazily on its first render. Only the tool-visibility gate stays here.
27
74
  #disclosure: Disclosure | undefined;
28
75
  readonly #files: LateDiagnosticsFile[];
76
+ #expanded = false;
77
+ readonly #native = new Memo();
29
78
 
30
79
  constructor(files: LateDiagnosticsFile[]) {
31
80
  super();
@@ -35,6 +84,7 @@ export class LateDiagnosticsMessageComponent extends Container {
35
84
  }
36
85
 
37
86
  setExpanded(expanded: boolean): void {
87
+ this.#expanded = expanded;
38
88
  this.#disclosure?.setExpanded(expanded);
39
89
  }
40
90
 
@@ -47,6 +97,39 @@ export class LateDiagnosticsMessageComponent extends Container {
47
97
  return super.render(width);
48
98
  }
49
99
 
100
+ handleNativeEvent(event: NativeUiEvent): void {
101
+ const expanded = rootToggleExpanded(event);
102
+ if (expanded !== undefined) this.setExpanded(expanded);
103
+ }
104
+
105
+ /**
106
+ * A severity-toned card (role `omp.diagnostics.late`) with one wrapped line
107
+ * per diagnostic, clamped by the terminal while collapsed.
108
+ */
109
+ override describe(): NativeNode {
110
+ const key = [this.#expanded, this.#toolActivityVisible, getThemeEpoch()];
111
+ return this.#native.get(key, () => {
112
+ const input = this.#diagnosticInput();
113
+ const icon = input?.errored ? theme.status.error : theme.status.warning;
114
+ const head = [span(`${icon} `, input?.errored ? "error" : "warning"), span("Late diagnostics", "toolTitle")];
115
+ if (input?.summary) head.push(span(` (${plainText(input.summary)})`, "dim"));
116
+ const diagnostics = card(
117
+ {
118
+ role: "omp.diagnostics.late",
119
+ tone: input?.errored ? "error" : "warning",
120
+ head,
121
+ collapsible: true,
122
+ collapsed: !this.#expanded,
123
+ preview: { lines: COLLAPSED_DIAGNOSTICS },
124
+ },
125
+ (input?.messages ?? []).map((message, index) =>
126
+ text([span(plainText(message), "mono")], { wrap: "word", key: `d${index}` }),
127
+ ),
128
+ );
129
+ return withHidden(diagnostics, !this.#toolActivityVisible);
130
+ });
131
+ }
132
+
50
133
  override invalidate(): void {
51
134
  this.#rebuild();
52
135
  }
@@ -1,17 +1,38 @@
1
1
  import * as path from "node:path";
2
+ import { pathToFileURL } from "node:url";
2
3
  import type { AssistantMessage, Usage } from "@oh-my-pi/pi-ai";
3
4
  import { type Component } from "../tui";
4
5
  import { Container } from "../tui";
5
6
  import { Text } from "../components/text";
6
7
  import { getLanguageFromPath, theme } from "../theme";
7
8
  import { parseLineRanges, selectorLineRanges } from "../tools/line-ranges";
8
- import { type ReadRenderArgs, type ReadToolDetails, readSourceFsPath, splitPathAndSel } from "../tools/read";
9
+ import {
10
+ type ReadRenderArgs,
11
+ type ReadToolDetails,
12
+ readContentCode,
13
+ readSourceFsPath,
14
+ splitPathAndSel,
15
+ } from "../tools/read";
9
16
  import { PREVIEW_LIMITS, shortenPath } from "../render/render-utils";
10
17
  import { fileHyperlink, renderCodeCell } from "../render";
11
18
  import { canonicalizeMessage } from "./thinking-display";
12
19
  import { internalUrlSchemeSpec, splitUrlScheme } from "../tools/url-scheme-host";
13
20
  import type { ToolExecutionHandle } from "./tool-execution";
14
21
  import { formatUsageRow } from "../overlays/usage-row";
22
+ import { formatCount } from "@oh-my-pi/pi-utils";
23
+ import type { TspCardStatus, TspSpan, TspText } from "@oh-my-pi/pi-wire";
24
+ import type { NativeToolHead } from "../tools/renderer";
25
+ import { card, code, keyed, node, span, text, withHidden } from "../native/describe";
26
+ import {
27
+ type DescribeContext,
28
+ type NativeChild,
29
+ type NativeNode,
30
+ type NativeUiEvent,
31
+ rootToggleExpanded,
32
+ } from "../native/node";
33
+ import { plainText } from "../native/spans";
34
+ import { Memo } from "../native/memo";
35
+ import { fileHref, fileRow, inlineErrorView } from "../tools/native-view";
15
36
 
16
37
  /**
17
38
  * Extract the read call's target path. `path` is the canonical arg; `file_path`
@@ -117,6 +138,21 @@ type ReadUsageRow = {
117
138
  /** Number of code lines to show in collapsed preview mode */
118
139
  const COLLAPSED_PREVIEW_LINES = PREVIEW_LIMITS.OUTPUT_COLLAPSED;
119
140
 
141
+ /**
142
+ * Collapsed clamp for a data-first group whose previews are already trimmed
143
+ * to {@link COLLAPSED_PREVIEW_LINES}: large enough never to cut the trimmed
144
+ * body, so collapsed shows every file and the head of each preview.
145
+ */
146
+ const TRIMMED_BODY_PREVIEW = { lines: 1000 } as const;
147
+
148
+ /** Native item tone per read status; successful reads stay neutral. */
149
+ const READ_STATUS_TONE: Record<ReadEntry["status"], "pending" | "warning" | "error" | undefined> = {
150
+ success: undefined,
151
+ pending: "pending",
152
+ warning: "warning",
153
+ error: "error",
154
+ };
155
+
120
156
  type ReadDisplayTarget = {
121
157
  entry: ReadEntry;
122
158
  targetPath: string;
@@ -329,6 +365,10 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
329
365
  // run broke, seal(), or an expansion toggle — and the transcript's
330
366
  // width-epoch resolution and committed-render bypass must observe it.
331
367
  #blockVersion = 0;
368
+ #displayVersion = 0;
369
+ readonly #native = new Memo();
370
+ /** Content previews toggled in the terminal, by tool call id. */
371
+ #previewCollapsed = new Map<string, boolean>();
332
372
 
333
373
  constructor(options: ReadToolGroupOptions = {}) {
334
374
  super();
@@ -503,6 +543,7 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
503
543
  setExpanded(expanded: boolean): void {
504
544
  if (this.#expanded !== expanded) this.#blockVersion++;
505
545
  this.#expanded = expanded;
546
+ this.#previewCollapsed.clear();
506
547
  this.#updateDisplay();
507
548
  }
508
549
 
@@ -515,7 +556,306 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
515
556
  return this;
516
557
  }
517
558
 
559
+ /**
560
+ * Mirrors the terminal's toggles: the `tool` head (the group's root) is
561
+ * `Ctrl+O`'s expansion; a fallback preview card collapses on its own
562
+ * (`setExpanded` resets those).
563
+ */
564
+ handleNativeEvent(event: NativeUiEvent): void {
565
+ const expanded = rootToggleExpanded(event);
566
+ if (expanded !== undefined) {
567
+ this.setExpanded(expanded);
568
+ return;
569
+ }
570
+ if (event.type !== "toggle" || !event.key.startsWith("p")) return;
571
+ const toolCallId = event.key.slice(1);
572
+ if (!this.#entries.has(toolCallId)) return;
573
+ this.#previewCollapsed.set(toolCallId, event.collapsed);
574
+ this.#displayVersion++;
575
+ }
576
+
577
+ /**
578
+ * The read run as one inline `tool` on terminals that list the kind, else
579
+ * the fallback: a bare `card` (role `omp.tool.read`) with `Read <path>` or
580
+ * `Read (N)` in the head, a `list` of path items (status tone, link,
581
+ * correction and conflict detail, nested usage) and, with content previews
582
+ * on, a `code` block per read clamped by the card's preview while collapsed.
583
+ */
584
+ override describe(cx?: DescribeContext): NativeNode {
585
+ const dataFirst = cx?.supports("tool") === true;
586
+ const key = [dataFirst, this.#displayVersion, this.#toolActivityVisible, this.#sealed];
587
+ return this.#native.get(key, () =>
588
+ withHidden(dataFirst ? this.#describeTool() : this.#describeGroup(), !this.#toolActivityVisible),
589
+ );
590
+ }
591
+
592
+ /**
593
+ * The data-first read (§7.3 read, read group, read error): one inline
594
+ * `tool` (role `omp.tool.read`). One file: `Read path:13-36`, a failure's
595
+ * message in the head. Several: `Read 3 files` over one 22px row per file
596
+ * (glyph, dim dir, strong name, range). Content previews are numbered
597
+ * `code` (a section per file in a group), trimmed while collapsed.
598
+ */
599
+ #describeTool(): NativeNode {
600
+ const entries = [...this.#entries.values()];
601
+ const rows = this.#buildSummaryRows(this.#displayTargetsForEntries(entries));
602
+ const status = this.#groupStatus(entries);
603
+ const previews = entries.filter(entry => entry.status !== "error" && this.#shouldRenderPreview(entry));
604
+ const body: NativeChild[] = [];
605
+ let head: NativeToolHead;
606
+ // Previews (and a long error message) are what a collapse hides; plain rows always show.
607
+ let collapsible = previews.length > 0;
608
+ if (rows.length <= 1) {
609
+ const row = rows[0];
610
+ const error = row && this.#statusForTargets(row.targets) === "error" ? this.#errorFor(row) : undefined;
611
+ const rowHead: NativeToolHead = row ? this.#nativeRowHead(row) : { target: "…", targetKind: "path" };
612
+ if (error !== undefined) {
613
+ const view = inlineErrorView(rowHead, error);
614
+ head = view.tool ?? rowHead;
615
+ if (view.body) {
616
+ body.push(...view.body);
617
+ collapsible = true;
618
+ }
619
+ } else {
620
+ head = rowHead;
621
+ }
622
+ for (const entry of previews) body.push(...this.#nativePreview(entry));
623
+ for (const [i, usage] of (this.#usageRowsBySummaryRow(rows).get(0) ?? []).entries()) {
624
+ body.push(this.#nativeUsage(usage, `u${i}`));
625
+ }
626
+ } else {
627
+ head = { target: formatCount("file", rows.length), targetKind: "text" };
628
+ const summaryRows = this.#buildSummaryRows(
629
+ this.#displayTargetsForEntries(entries.filter(entry => !previews.includes(entry))),
630
+ );
631
+ const usageByRow = this.#usageRowsBySummaryRow(summaryRows);
632
+ for (const [index, row] of summaryRows.entries()) {
633
+ body.push(this.#nativeFileRow(row));
634
+ for (const [i, usage] of (usageByRow.get(index) ?? []).entries()) {
635
+ body.push(this.#nativeUsage(usage, `u${index}.${i}`));
636
+ }
637
+ }
638
+ for (const entry of previews) {
639
+ const split = splitPathAndSel(entry.path);
640
+ const name = shortenPath(split.path);
641
+ const sectionHead: TspSpan[] = [span(name || "…", "path")];
642
+ if (split.sel) sectionHead.push(span(`:${split.sel}`, "muted"));
643
+ body.push(node("section", { head: sectionHead }, this.#nativePreview(entry), `p${entry.toolCallId}`));
644
+ const usage = this.#usageRows.get(entry.toolCallId);
645
+ if (usage) body.push(this.#nativeUsage(usage, `u${entry.toolCallId}`));
646
+ }
647
+ }
648
+ return node(
649
+ "tool",
650
+ {
651
+ ...head,
652
+ role: "omp.tool.read",
653
+ name: "read",
654
+ title: "Read",
655
+ status,
656
+ tone: status === "error" ? "error" : undefined,
657
+ frame: "inline",
658
+ collapsible,
659
+ collapsed: collapsible ? !this.#expanded : undefined,
660
+ preview: collapsible ? TRIMMED_BODY_PREVIEW : undefined,
661
+ },
662
+ body,
663
+ );
664
+ }
665
+
666
+ /** Head data for one summary row: the path (+ selector) target, its link, correction and conflicts. */
667
+ #nativeRowHead(row: ReadSummaryRow): NativeToolHead {
668
+ const split = splitPathAndSel(row.targetPath);
669
+ const filePath = shortenPath(split.sel ? split.path : row.targetPath);
670
+ const correctedFrom = this.#correctedFromForTargets(row.targets);
671
+ const conflicts = this.#conflictCountForTargets(row.targets);
672
+ return {
673
+ target: filePath ? `${filePath}${split.sel ? `:${split.sel}` : ""}` : "…",
674
+ targetKind: "path",
675
+ href: fileHref(linkPathForTargets(row.targets)),
676
+ meta: correctedFrom ? [`corrected from ${shortenPath(correctedFrom)}`] : undefined,
677
+ badges: conflicts
678
+ ? [{ text: `${conflicts} conflict${conflicts === 1 ? "" : "s"}`, tone: "warning" }]
679
+ : undefined,
680
+ };
681
+ }
682
+
683
+ /** One 22px group row: status glyph, path and range, conflicts chip, then the correction or error message. */
684
+ #nativeFileRow(row: ReadSummaryRow): NativeNode {
685
+ const split = splitPathAndSel(row.targetPath);
686
+ const status = this.#statusForTargets(row.targets);
687
+ const correctedFrom = this.#correctedFromForTargets(row.targets);
688
+ const conflicts = this.#conflictCountForTargets(row.targets);
689
+ const error = status === "error" ? this.#errorFor(row) : undefined;
690
+ const detail: TspText | undefined =
691
+ error !== undefined
692
+ ? [span(`— ${error.split("\n", 1)[0]}`, "error")]
693
+ : correctedFrom
694
+ ? `corrected from ${shortenPath(correctedFrom)}`
695
+ : undefined;
696
+ return fileRow(shortenPath(split.sel ? split.path : row.targetPath), {
697
+ range: split.sel ? `:${split.sel}` : undefined,
698
+ href: fileHref(linkPathForTargets(row.targets)),
699
+ icon: status === "error" ? "x-circle" : undefined,
700
+ tone: READ_STATUS_TONE[status],
701
+ chip: conflicts ? { text: `${conflicts} conflict${conflicts === 1 ? "" : "s"}` } : undefined,
702
+ detail,
703
+ title: error,
704
+ key: row.targetPath,
705
+ });
706
+ }
707
+
708
+ /** The failure message of a row's failed read (its result text, `Error:` prefix dropped). */
709
+ #errorFor(row: ReadSummaryRow): string {
710
+ const failed = row.targets.find(target => target.entry.status === "error")?.entry;
711
+ return (
712
+ plainText(failed?.contentText ?? "")
713
+ .replace(/^Error:\s*/, "")
714
+ .trim() || "Read failed"
715
+ );
716
+ }
717
+
718
+ /** One read's content as numbered `code`, trimmed to its first lines (plus a count) while collapsed. */
719
+ #nativePreview(entry: ReadEntry): NativeChild[] {
720
+ const split = splitPathAndSel(entry.path);
721
+ const lines = (entry.contentText ?? "").split("\n");
722
+ const shown = this.#expanded ? lines.length : Math.min(lines.length, COLLAPSED_PREVIEW_LINES);
723
+ const blocks: NativeChild[] = readContentCode(
724
+ lines.slice(0, shown).join("\n"),
725
+ entry.codeStartLine ?? firstSelectorLine(split.sel) ?? 1,
726
+ entry.codeLineNumbers?.slice(0, shown),
727
+ getLanguageFromPath(split.path),
728
+ );
729
+ const hidden = lines.length - shown;
730
+ if (hidden > 0) {
731
+ blocks.push(
732
+ keyed(text([span(formatCount("more line", hidden), "muted")], { role: "omp.tool.stats" }), "more"),
733
+ );
734
+ }
735
+ return blocks;
736
+ }
737
+
738
+ #describeGroup(): NativeNode {
739
+ const entries = [...this.#entries.values()];
740
+ const rows = this.#buildSummaryRows(this.#displayTargetsForEntries(entries));
741
+ const usageByRow = this.#usageRowsBySummaryRow(rows);
742
+ const previews = entries.filter(entry => this.#shouldRenderPreview(entry));
743
+ const status = this.#groupStatus(entries);
744
+ const title = span("Read", "toolTitle");
745
+ const children: NativeChild[] = [];
746
+ let head: TspSpan[] = [title];
747
+ if (rows.length === 1) {
748
+ head = [title, span(" "), ...this.#nativePathSpans(rows[0]!)];
749
+ if (previews.length === 0) {
750
+ for (const usage of usageByRow.get(0) ?? []) children.push(this.#nativeUsage(usage, "u0"));
751
+ }
752
+ } else if (rows.length > 1) {
753
+ head = [title, span(` (${rows.length})`, "dim")];
754
+ const summaryTargets = this.#displayTargetsForEntries(
755
+ entries.filter(entry => !this.#shouldRenderPreview(entry)),
756
+ );
757
+ const summaryRows = this.#buildSummaryRows(summaryTargets);
758
+ const summaryUsage = this.#usageRowsBySummaryRow(summaryRows);
759
+ const items = summaryRows.map((row, index) => {
760
+ const usage = (summaryUsage.get(index) ?? []).map(usageRow =>
761
+ plainText(
762
+ formatUsageRow(
763
+ usageRow.usage,
764
+ usageRow.durationMs,
765
+ usageRow.ttftMs,
766
+ usageRow.timestamp,
767
+ usageRow.turnElapsedMs,
768
+ ),
769
+ ),
770
+ );
771
+ return node(
772
+ "item",
773
+ {
774
+ label: this.#nativePathSpans(row),
775
+ tone: READ_STATUS_TONE[this.#statusForTargets(row.targets)],
776
+ detail: usage.length > 0 ? [span(usage.join(" · "), "dim")] : undefined,
777
+ },
778
+ [],
779
+ row.targetPath,
780
+ );
781
+ });
782
+ if (items.length > 0) children.push(node("list", {}, items));
783
+ }
784
+ for (const entry of previews) {
785
+ const split = splitPathAndSel(entry.path);
786
+ const pathValue = shortenPath(entry.path);
787
+ children.push(
788
+ node(
789
+ "card",
790
+ {
791
+ role: "omp.tool.read.preview",
792
+ tone: READ_STATUS_TONE[entry.status],
793
+ head: pathValue ? [title, span(" "), span(pathValue, "path")] : [title],
794
+ collapsible: true,
795
+ collapsed: this.#previewCollapsed.get(entry.toolCallId) ?? !this.#expanded,
796
+ preview: { lines: COLLAPSED_PREVIEW_LINES },
797
+ },
798
+ [
799
+ code(entry.contentText ?? "", {
800
+ lang: getLanguageFromPath(split.path),
801
+ start: entry.codeStartLine,
802
+ numbers: true,
803
+ }),
804
+ ],
805
+ `p${entry.toolCallId}`,
806
+ ),
807
+ );
808
+ const usage = this.#usageRows.get(entry.toolCallId);
809
+ if (usage) children.push(this.#nativeUsage(usage, `u${entry.toolCallId}`));
810
+ }
811
+ return card(
812
+ {
813
+ role: "omp.tool.read",
814
+ // A group is plain rows: the per-file previews are the only frames.
815
+ variant: "bare",
816
+ status,
817
+ tone: status === "error" ? "error" : status === "running" ? "pending" : undefined,
818
+ head,
819
+ },
820
+ children,
821
+ );
822
+ }
823
+
824
+ #groupStatus(entries: readonly ReadEntry[]): TspCardStatus {
825
+ let rank = 0;
826
+ for (const entry of entries) rank = Math.max(rank, READ_STATUS_RANK[entry.status]);
827
+ if (rank === READ_STATUS_RANK.error) return "error";
828
+ if (rank === READ_STATUS_RANK.pending) return this.#sealed ? "cancelled" : "running";
829
+ return "done";
830
+ }
831
+
832
+ /** Path spans for a summary row: linked path, selector, correction note and conflict badge. */
833
+ #nativePathSpans(row: ReadSummaryRow): TspSpan[] {
834
+ const split = splitPathAndSel(row.targetPath);
835
+ const filePath = shortenPath(split.sel ? split.path : row.targetPath);
836
+ const linkPath = linkPathForTargets(row.targets);
837
+ const spans: TspSpan[] = [];
838
+ if (filePath) {
839
+ const href = linkPath && path.isAbsolute(linkPath) ? pathToFileURL(linkPath).href : undefined;
840
+ spans.push(span(filePath, "path", href ? { href } : undefined));
841
+ } else {
842
+ spans.push(span("…", "toolOutput"));
843
+ }
844
+ if (split.sel) spans.push(span(`:${split.sel}`, "accent"));
845
+ const correctedFrom = this.#correctedFromForTargets(row.targets);
846
+ if (correctedFrom) spans.push(span(` (corrected from ${shortenPath(correctedFrom)})`, "dim"));
847
+ const conflicts = this.#conflictCountForTargets(row.targets);
848
+ if (conflicts) spans.push(span(` (⚠ ${conflicts} conflict${conflicts === 1 ? "" : "s"})`, "warning"));
849
+ return spans;
850
+ }
851
+
852
+ #nativeUsage(usage: ReadUsageRow, key: string): NativeNode {
853
+ const line = formatUsageRow(usage.usage, usage.durationMs, usage.ttftMs, usage.timestamp, usage.turnElapsedMs);
854
+ return text([span(plainText(line), "dim")], { wrap: "word", key, role: "omp.usage" });
855
+ }
856
+
518
857
  #updateDisplay(): void {
858
+ this.#displayVersion++;
519
859
  const entries = [...this.#entries.values()];
520
860
  const displayTargets = this.#displayTargetsForEntries(entries);
521
861
  const displayRows = this.#buildSummaryRows(displayTargets);
@@ -86,6 +86,14 @@ export class ServedModelMarkerComponent extends MessageDividerComponent {
86
86
  labelColor: "warning",
87
87
  ruleColor: "dim",
88
88
  ruleWidth: 10,
89
+ role: "omp.marker.served-model",
90
+ native: {
91
+ icon: "warn",
92
+ label: () => {
93
+ const via = info.upstreamProvider ? `${info.provider}/${info.upstreamProvider}` : info.provider;
94
+ return `Served ${info.served} · requested ${info.requested} · via ${via}`;
95
+ },
96
+ },
89
97
  });
90
98
  }
91
99
  }
@@ -1,3 +1,4 @@
1
+ import { pathToFileURL } from "node:url";
1
2
  import type { TextContent } from "@oh-my-pi/pi-ai";
2
3
  import { type Component } from "../tui";
3
4
  import { Box } from "../components/box";
@@ -11,6 +12,10 @@ import type { CustomMessage, SkillPromptDetails } from "./messages";
11
12
  import { fileHyperlink } from "../render";
12
13
  import { collapseSkillTokens, skillChipLabel, skillChipStyle, skillToken } from "../prompt/composer-attachments";
13
14
  import { type UserBubbleOptions, UserMessageComponent, userBubbleColor } from "./user-message";
15
+ import type { TspSpan } from "@oh-my-pi/pi-wire";
16
+ import { card, md, node, span, text } from "../native/describe";
17
+ import { type NativeChild, type NativeNode, type NativeUiEvent, rootToggleExpanded } from "../native/node";
18
+ import { Memo } from "../native/memo";
14
19
 
15
20
  /**
16
21
  * Transcript row for a user-invoked skill. Two layouts, chosen by where the
@@ -41,6 +46,8 @@ export class SkillMessageComponent extends Container {
41
46
 
42
47
  readonly #message: CustomMessage<SkillPromptDetails>;
43
48
  readonly #imageLinks?: readonly (string | undefined)[];
49
+ #expanded = false;
50
+ readonly #native = new Memo();
44
51
 
45
52
  constructor(message: CustomMessage<SkillPromptDetails>, imageLinks?: readonly (string | undefined)[]) {
46
53
  super();
@@ -51,9 +58,65 @@ export class SkillMessageComponent extends Container {
51
58
  }
52
59
 
53
60
  setExpanded(expanded: boolean): void {
61
+ this.#expanded = expanded;
54
62
  this.#disclosure?.setExpanded(expanded);
55
63
  }
56
64
 
65
+ handleNativeEvent(event: NativeUiEvent): void {
66
+ const expanded = rootToggleExpanded(event);
67
+ if (expanded !== undefined) this.setExpanded(expanded);
68
+ }
69
+
70
+ /**
71
+ * A user-toned card (role `omp.skill`): the skill chip (linked to its
72
+ * SKILL.md) and prompt size in the head, the user's draft as markdown, and
73
+ * the loaded skill prompt, described only while expanded because it can
74
+ * be large.
75
+ */
76
+ override describe(): NativeNode {
77
+ return this.#native.get([this.#expanded], () => {
78
+ const details = this.#message.details;
79
+ const name = details?.name?.trim() || "unknown";
80
+ const token = skillToken(name);
81
+ const prompt = details?.prompt ?? (details?.args ? `${token} ${details.args}` : token);
82
+ const display = collapseSkillTokens(
83
+ prompt,
84
+ candidate => candidate === name,
85
+ () => {},
86
+ );
87
+ const label = skillChipLabel(name);
88
+ const leading = display.startsWith(label) && /^\s*$/.test(display.charAt(label.length));
89
+ const draft = leading ? display.slice(label.length).trim() : display;
90
+ const head: TspSpan[] = [
91
+ span(
92
+ label,
93
+ "customMessageLabel strong",
94
+ details?.path ? { href: pathToFileURL(details.path).href } : undefined,
95
+ ),
96
+ ];
97
+ if (typeof details?.lineCount === "number") {
98
+ head.push(span(` ${details.lineCount} ${details.lineCount === 1 ? "line" : "lines"}`, "muted"));
99
+ }
100
+ const children: NativeChild[] = [];
101
+ if (draft) children.push(md(draft));
102
+ const promptText = this.#expanded ? this.#extractText() : "";
103
+ if (promptText) {
104
+ children.push(
105
+ node(
106
+ "section",
107
+ { head: [span("prompt", "muted")], role: "omp.skill.prompt" },
108
+ [md(promptText)],
109
+ "prompt",
110
+ ),
111
+ );
112
+ }
113
+ return card(
114
+ { role: "omp.skill", tone: "user", head, collapsible: true, collapsed: !this.#expanded },
115
+ children.length > 0 ? children : [text([span(label, "muted")])],
116
+ );
117
+ });
118
+ }
119
+
57
120
  /**
58
121
  * Transcript finalization contract (see `FinalizableBlock`): an optimistic
59
122
  * `/skill:` row reports `false` so the container keeps it live and removable
@@ -1,5 +1,7 @@
1
1
  import { Text } from "../components/text";
2
2
  import { theme } from "../theme";
3
+ import { span, text } from "../native/describe";
4
+ import type { NativeNode } from "../native/node";
3
5
 
4
6
  /**
5
7
  * Dim transcript marker for tool calls stripped from the resolved branch
@@ -8,26 +10,32 @@ import { theme } from "../theme";
8
10
  */
9
11
  export class StrippedToolCallsPlaceholder extends Text {
10
12
  #toolActivityVisible: boolean;
13
+ readonly #label: string;
14
+ #native: NativeNode | undefined;
11
15
 
12
16
  constructor(strippedToolCalls: number, toolActivityVisible: boolean) {
13
- super(
14
- theme.fg(
15
- "dim",
16
- theme.italic(
17
- `${strippedToolCalls} tool call${strippedToolCalls === 1 ? "" : "s"} elided — no result on this branch`,
18
- ),
19
- ),
20
- 1,
21
- 0,
22
- );
17
+ const label = `${strippedToolCalls} tool call${strippedToolCalls === 1 ? "" : "s"} elided — no result on this branch`;
18
+ super(theme.fg("dim", theme.italic(label)), 1, 0);
19
+ this.#label = label;
23
20
  this.#toolActivityVisible = toolActivityVisible;
24
21
  }
25
22
 
26
23
  setToolActivityVisible(visible: boolean): void {
27
24
  this.#toolActivityVisible = visible;
25
+ this.#native = undefined;
28
26
  this.invalidate();
29
27
  }
30
28
 
29
+ /** A dim italic note, mounted but hidden while tool activity is hidden. */
30
+ override describe(): NativeNode {
31
+ this.#native ??= text([span(this.#label, "dim em")], {
32
+ wrap: "word",
33
+ role: "omp.tool.elided",
34
+ hidden: this.#toolActivityVisible ? undefined : true,
35
+ });
36
+ return this.#native;
37
+ }
38
+
31
39
  override render(width: number): readonly string[] {
32
40
  if (!this.#toolActivityVisible) return [];
33
41
  return super.render(width);