@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
@@ -12,9 +12,13 @@ import {
12
12
  PREVIEW_LIMITS,
13
13
  toPathList,
14
14
  } from "../render/render-utils";
15
- import { classifyGroupedLines, groupLineIndicesByBlank } from "./grouped-file-output";
15
+ import { classifyGroupedLines, describeGroupedOutput, groupLineIndicesByBlank } from "./grouped-file-output";
16
+ import { getLanguageFromPath } from "../lang-from-path";
17
+ import { code, compact, node, span } from "../native/describe";
18
+ import type { NativeChild } from "../native/node";
19
+ import { errorText, noteText, resultText, toolHead } from "./native-view";
16
20
  import type { OutputMeta } from "./output-meta";
17
- import type { RenderResultOptions, ToolRenderer } from "./renderer";
21
+ import type { NativeToolView, RenderResultOptions, ToolRenderer } from "./renderer";
18
22
 
19
23
  /** Display metadata returned by ast-grep. */
20
24
  export interface AstGrepToolDetails {
@@ -167,5 +171,81 @@ export const astGrepToolRenderer = {
167
171
  },
168
172
  );
169
173
  },
174
+ describeCall(args: AstGrepRenderArgs): NativeToolView {
175
+ const meta: string[] = [];
176
+ const scopePaths = toPathList(args.path ?? args.paths);
177
+ if (scopePaths.length) meta.push(`in ${scopePaths.join(", ")}`);
178
+ if (args.skip !== undefined && args.skip > 0) meta.push(`skip:${args.skip}`);
179
+ return { head: toolHead("AST Grep", span(args.pat ?? "?", "code"), ...meta) };
180
+ },
181
+
182
+ describeResult(
183
+ result: { content: Array<{ type: string; text?: string }>; details?: AstGrepToolDetails; isError?: boolean },
184
+ _options: RenderResultOptions,
185
+ args?: AstGrepRenderArgs,
186
+ ): NativeToolView {
187
+ const details = result.details;
188
+ const pattern = span(args?.pat ?? "?", "code");
189
+ if (result.isError) {
190
+ return {
191
+ head: toolHead("AST Grep", pattern),
192
+ tone: "error",
193
+ body: [errorText(resultText(result) || "Unknown error")],
194
+ };
195
+ }
196
+ const matchCount = details?.matchCount ?? 0;
197
+ const filesSearched = details?.filesSearched ?? 0;
198
+ const limitReached = details?.limitReached ?? false;
199
+ const parseErrors = details?.parseErrors ?? [];
200
+ const parseNote =
201
+ parseErrors.length > 0
202
+ ? node(
203
+ "section",
204
+ {
205
+ head: [span(formatParseErrorsCountLabel(parseErrors, details?.parseErrorsTotal), "warning")],
206
+ collapsible: true,
207
+ collapsed: true,
208
+ },
209
+ [code(parseErrors.join("\n"))],
210
+ "parse-errors",
211
+ )
212
+ : undefined;
213
+ if (matchCount === 0) {
214
+ const meta = ["0 matches"];
215
+ if (details?.scopePath) meta.push(`in ${details.scopePath}`);
216
+ if (filesSearched > 0) meta.push(`searched ${filesSearched}`);
217
+ return {
218
+ head: toolHead("AST Grep", pattern, ...meta),
219
+ tone: "warning",
220
+ body: compact<NativeChild>([
221
+ noteText("No matches found"),
222
+ parseErrors.length > 0 &&
223
+ noteText("Query may be mis-scoped; narrow `path` before concluding absence", "warning"),
224
+ parseNote,
225
+ ]),
226
+ };
227
+ }
228
+ const meta = [formatCount("match", matchCount), formatCount("file", details?.fileCount ?? 0)];
229
+ if (details?.scopePath) meta.push(`in ${details.scopePath}`);
230
+ meta.push(`searched ${filesSearched}`);
231
+ const head = toolHead("AST Grep", pattern, ...meta);
232
+ if (limitReached) head.push(span(" limit reached", "warning"));
233
+ const allLines = (details?.displayContent ?? resultText(result)).split("\n");
234
+ const kept = groupLineIndicesByBlank(allLines)
235
+ .filter(indices => {
236
+ const first = allLines[indices[0]!]!;
237
+ return !first.startsWith("Result limit reached") && !first.startsWith("Parse issues:");
238
+ })
239
+ .flatMap(indices => [...indices.map(index => allLines[index]!), ""]);
240
+ return {
241
+ head,
242
+ body: compact<NativeChild>([
243
+ ...describeGroupedOutput(kept, { lang: getLanguageFromPath }),
244
+ limitReached && noteText("limit reached; narrow path or increase limit", "warning"),
245
+ parseNote,
246
+ ]),
247
+ preview: { lines: COLLAPSED_MATCH_LIMIT },
248
+ };
249
+ },
170
250
  mergeCallAndResult: true,
171
251
  } satisfies ToolRenderer<AstGrepRenderArgs, AstGrepToolDetails>;
@@ -1,7 +1,13 @@
1
1
  import { Text } from "../components/text";
2
2
  import type { Theme } from "../theme/theme";
3
3
  import { replaceTabs, truncateToWidth, shortenPath } from "../render/render-utils";
4
- import type { ToolRenderer } from "./renderer";
4
+ import type { TspTone } from "@oh-my-pi/pi-wire";
5
+ import { ansi, compact, kv, node, row, span, text } from "../native/describe";
6
+ import type { NativeNode } from "../native/node";
7
+ import { OwnerMemo } from "../native/memo";
8
+ import { plainText } from "../native/spans";
9
+ import { errorView, resultText, toolHead } from "./native-view";
10
+ import type { NativeToolView, ToolRenderer, ToolRenderResult } from "./renderer";
5
11
  import type { TruncationResult } from "./streaming-output";
6
12
 
7
13
  /** Whether a lower or higher metric is better. */
@@ -155,6 +161,35 @@ export interface InitExperimentDetails {
155
161
  baselineCommit: string | null;
156
162
  }
157
163
 
164
+ /** Tone of an experiment disposition: kept succeeds, discarded warns, the rest fail. */
165
+ function experimentTone(status: ExperimentStatus): TspTone {
166
+ return status === "keep" ? "success" : status === "discard" ? "warning" : "error";
167
+ }
168
+
169
+ /** Plain first line of a free-form argument, for single-line heads. */
170
+ function firstLine(value: string | undefined): string {
171
+ return (
172
+ plainText(value ?? "")
173
+ .trim()
174
+ .split("\n")[0] ?? ""
175
+ );
176
+ }
177
+
178
+ /** Result text as a wrapped body, or an error card. */
179
+ function describeTextResult(
180
+ title: string,
181
+ result: ToolRenderResult<unknown>,
182
+ style?: string,
183
+ ): NativeToolView | undefined {
184
+ const output = resultText(result);
185
+ if (result.isError) return errorView(title, output);
186
+ const body = plainText(output).trimEnd();
187
+ return body ? { body: [text(style ? [span(body, style)] : body, { wrap: "word" })] } : undefined;
188
+ }
189
+
190
+ const logResultMemo = new OwnerMemo<NativeToolView | undefined>();
191
+ const runResultMemo = new OwnerMemo<NativeToolView | undefined>();
192
+
158
193
  function renderInitCall(name: string, theme: Theme): string {
159
194
  return `${theme.fg("toolTitle", theme.bold("init_experiment"))} ${theme.fg("accent", truncateToWidth(replaceTabs(name), 100))}`;
160
195
  }
@@ -168,8 +203,42 @@ export const initExperimentToolRenderer = {
168
203
  const text = replaceTabs(result.content.find(part => part.type === "text")?.text ?? "");
169
204
  return new Text(text, 0, 0);
170
205
  },
206
+ describeCall(args): NativeToolView {
207
+ return { head: toolHead("init_experiment", span(firstLine(args.name), "accent")) };
208
+ },
209
+ describeResult(result): NativeToolView | undefined {
210
+ return describeTextResult("init_experiment", result);
211
+ },
171
212
  } satisfies ToolRenderer<{ name: string }, InitExperimentDetails>;
172
213
 
214
+ /** Native log summary: disposition badge, description, and metric/baseline grid. */
215
+ function describeSummary(details: LogDetails): NativeToolView {
216
+ const { experiment, state } = details;
217
+ const tone = experimentTone(experiment.status);
218
+ const deviations = details.scopeDeviations.length;
219
+ return {
220
+ tone,
221
+ body: compact([
222
+ row(
223
+ [
224
+ node("badge", { text: experiment.status.toUpperCase(), tone }),
225
+ text([span(plainText(experiment.description), "muted")], { wrap: "word", grow: 1 }),
226
+ ],
227
+ { gap: "sm" },
228
+ ),
229
+ kv([
230
+ [plainText(state.metricName), [span(formatNum(experiment.metric, state.metricUnit), "accent num")]],
231
+ [
232
+ "baseline",
233
+ state.bestMetric !== null ? [span(formatNum(state.bestMetric, state.metricUnit), "num")] : undefined,
234
+ ],
235
+ ["confidence", state.confidence !== null ? [span(`${state.confidence.toFixed(1)}x`, "num")] : undefined],
236
+ ["deviations", deviations > 0 ? [span(String(deviations), "warning")] : undefined],
237
+ ]),
238
+ ]),
239
+ };
240
+ }
241
+
173
242
  function renderSummary(details: LogDetails, theme: Theme): string {
174
243
  const { experiment, state } = details;
175
244
  const color = experiment.status === "keep" ? "success" : experiment.status === "discard" ? "warning" : "error";
@@ -205,8 +274,46 @@ export const logExperimentToolRenderer = {
205
274
  }
206
275
  return new Text(renderSummary(details, theme), 0, 0);
207
276
  },
277
+ describeCall(args): NativeToolView {
278
+ return {
279
+ head: toolHead(
280
+ "log_experiment",
281
+ args.status ? span(args.status, experimentTone(args.status)) : undefined,
282
+ span(firstLine(args.description), "muted"),
283
+ ),
284
+ };
285
+ },
286
+ describeResult(result): NativeToolView | undefined {
287
+ return logResultMemo.get(result, [], () => {
288
+ const details = result.details;
289
+ if (result.isError || !details) return describeTextResult("log_experiment", result);
290
+ return describeSummary(details);
291
+ });
292
+ },
208
293
  } satisfies ToolRenderer<{ status: ExperimentStatus; description: string }, LogDetails>;
209
294
 
295
+ /** Native run status: TIMEOUT/FAIL/PASS badge with duration and primary metric. */
296
+ function describeStatus(details: RunDetails): { tone: TspTone; node: NativeNode } {
297
+ const duration = `${details.durationSeconds.toFixed(1)}s`;
298
+ let tone: TspTone = "success";
299
+ let label = "PASS";
300
+ let meta = duration;
301
+ if (details.timedOut) {
302
+ tone = "error";
303
+ label = "TIMEOUT";
304
+ } else if (details.exitCode !== 0) {
305
+ tone = "error";
306
+ label = "FAIL";
307
+ meta = `exit=${details.exitCode} ${duration}`;
308
+ } else if (details.parsedPrimary !== null) {
309
+ meta = `${duration} ${plainText(details.metricName)}=${formatNum(details.parsedPrimary, details.metricUnit)}`;
310
+ }
311
+ return {
312
+ tone,
313
+ node: row([node("badge", { text: label, tone }), text([span(meta, tone)], { truncate: "end" })], { gap: "sm" }),
314
+ };
315
+ }
316
+
210
317
  function renderStatus(details: RunDetails, theme: Theme): string {
211
318
  if (details.timedOut) {
212
319
  return theme.fg("error", `TIMEOUT ${details.durationSeconds.toFixed(1)}s`);
@@ -263,6 +370,40 @@ export const runExperimentToolRenderer = {
263
370
  : "";
264
371
  return new Text(preview ? `${statusText}\n${theme.fg("dim", preview)}${suffix}` : statusText, 0, 0);
265
372
  },
373
+ describeCall(): NativeToolView {
374
+ return { head: toolHead("run_experiment", span(DEFAULT_HARNESS_COMMAND, "muted")) };
375
+ },
376
+ describeResult(result): NativeToolView | undefined {
377
+ return runResultMemo.get(result, [], () => {
378
+ const details = result.details;
379
+ if (isProgressDetails(details)) {
380
+ const output = resultText(result);
381
+ return {
382
+ tone: "warning",
383
+ preview: { lines: 6 },
384
+ body: compact([
385
+ node("spinner", { label: [span(`Running ${plainText(details.elapsed)}…`, "warning")] }),
386
+ output.trim() ? ansi(output, { follow: true }) : undefined,
387
+ ]),
388
+ };
389
+ }
390
+ if (result.isError || !details || !isRunDetails(details)) return describeTextResult("run_experiment", result);
391
+ const status = describeStatus(details);
392
+ return {
393
+ tone: status.tone,
394
+ preview: { lines: 6 },
395
+ body: compact([
396
+ status.node,
397
+ details.tailOutput.trim() ? ansi(details.tailOutput, { follow: true }) : undefined,
398
+ details.truncation && details.fullOutputPath
399
+ ? text([span("Full output: ", "warning"), span(shortenPath(details.fullOutputPath), "path")], {
400
+ truncate: "middle",
401
+ })
402
+ : undefined,
403
+ ]),
404
+ };
405
+ });
406
+ },
266
407
  } satisfies ToolRenderer<unknown, RunDetails | RunExperimentProgressDetails>;
267
408
 
268
409
  /** Persisted experiment notes after an update. */
@@ -284,4 +425,11 @@ export const updateNotesToolRenderer = {
284
425
  const text = replaceTabs(result.content.find(part => part.type === "text")?.text ?? "");
285
426
  return new Text(theme.fg("muted", text), 0, 0);
286
427
  },
428
+ describeCall(args): NativeToolView {
429
+ const preview = args.append_idea ?? args.body?.slice(0, 100);
430
+ return { head: toolHead("update_notes", span(firstLine(preview), "muted")) };
431
+ },
432
+ describeResult(result): NativeToolView | undefined {
433
+ return describeTextResult("update_notes", result, "muted");
434
+ },
287
435
  } satisfies ToolRenderer<{ body: string; append_idea?: string }, UpdateNotesDetails>;
package/src/tools/bash.ts CHANGED
@@ -18,7 +18,16 @@ import {
18
18
  stripRawOutputArtifactNotice,
19
19
  stripTrailingNotice,
20
20
  } from "./output-meta";
21
- import type { RenderResultOptions, ToolRenderer } from "./renderer";
21
+ import type {
22
+ NativeToolHead,
23
+ NativeToolView,
24
+ RenderResultContextOptions,
25
+ RenderResultOptions,
26
+ ToolRenderer,
27
+ } from "./renderer";
28
+ import { ansi, compact, keyed } from "../native/describe";
29
+ import type { NativeChild } from "../native/node";
30
+ import { footnoteText, resultText } from "./native-view";
22
31
 
23
32
  /** Default collapsed shell output preview height. */
24
33
  export const BASH_DEFAULT_PREVIEW_LINES = DEFAULT_TERMINAL_PREVIEW_LINES;
@@ -261,6 +270,122 @@ export function formatBashCommandLines(args: BashRenderArgs, uiTheme: Theme): st
261
270
  return highlightedLines.map((line, i) => (i === 0 ? `${prefix}${line}` : line));
262
271
  }
263
272
 
273
+ /**
274
+ * Plain (unstyled) command line for native views: `cd <dir> && NAME="…" <command>`,
275
+ * built from the same decoded display args (incl. streamed `__partialJson` env) as the ANSI path.
276
+ */
277
+ export function formatBashCommandText(args: BashRenderArgs): string {
278
+ const displayWorkdir = formatToolWorkingDirectory(args.cwd, getProjectDir());
279
+ const envAssignments = formatBashEnvAssignments(getBashEnvForDisplay(args));
280
+ const parts: string[] = [];
281
+ if (displayWorkdir) parts.push(`cd ${displayWorkdir} &&`);
282
+ if (envAssignments) parts.push(envAssignments);
283
+ parts.push(args.command || "…");
284
+ return parts.join(" ");
285
+ }
286
+
287
+ /** Bash output with the LLM-facing notices (background, exit, wall time, artifact, truncation) removed. */
288
+ function stripBashNotices(
289
+ rawOutput: string,
290
+ details: BashToolDetails | undefined,
291
+ ): { text: string; artifactId?: string } {
292
+ const withoutBackground =
293
+ details?.async?.state === "running"
294
+ ? stripTrailingNotice(rawOutput, formatBackgroundNotice(details.async.jobId))
295
+ : rawOutput;
296
+ const strippedOutput = stripOutputNotice(withoutBackground, details?.meta);
297
+ const withoutExit =
298
+ details?.exitCode === undefined
299
+ ? strippedOutput
300
+ : stripTrailingNotice(strippedOutput, formatExitCodeNotice(details.exitCode));
301
+ const withoutWall =
302
+ details?.wallTimeMs === undefined
303
+ ? withoutExit
304
+ : stripTrailingNotice(withoutExit, formatWallTimeNotice(details.wallTimeMs));
305
+ return stripRawOutputArtifactNotice(withoutWall);
306
+ }
307
+ /** `Wall: 1.20s`, `Timeout: 30s`, … metadata parts shown under bash output. */
308
+ function bashStatsParts(
309
+ details: BashToolDetails | undefined,
310
+ contextTimeout: number | undefined,
311
+ artifactId: string | undefined,
312
+ isError: boolean,
313
+ ): string[] {
314
+ const timeoutDisabled = details?.timeoutDisabled === true || contextTimeout === 0;
315
+ const timeoutSeconds = timeoutDisabled ? undefined : (details?.timeoutSeconds ?? contextTimeout);
316
+ const requestedTimeoutSeconds = details?.requestedTimeoutSeconds;
317
+ const wallTimeMs = details?.wallTimeMs;
318
+ const statsParts: string[] = [];
319
+ if (details?.async?.state === "running") {
320
+ statsParts.push(`Backgrounded: ${details.async.jobId}`);
321
+ }
322
+ if (details?.service) {
323
+ const service = details.service;
324
+ statsParts.push(`Service: ${service.name}`, `State: ${service.state}`);
325
+ statsParts.push(`Ready: ${service.ready ? "yes" : service.timedOut ? "timed out" : "no"}`);
326
+ if (service.pid !== undefined) statsParts.push(`PID: ${service.pid}`);
327
+ }
328
+ if (wallTimeMs !== undefined) {
329
+ statsParts.push(`Wall: ${formatWallTimeSeconds(wallTimeMs)}s`);
330
+ }
331
+ if (timeoutDisabled) {
332
+ statsParts.push("Timeout: disabled");
333
+ }
334
+ if (typeof timeoutSeconds === "number") {
335
+ statsParts.push(
336
+ requestedTimeoutSeconds !== undefined && requestedTimeoutSeconds !== timeoutSeconds
337
+ ? `Timeout: ${timeoutSeconds}s (requested ${requestedTimeoutSeconds}s clamped)`
338
+ : `Timeout: ${timeoutSeconds}s`,
339
+ );
340
+ }
341
+ if (artifactId) {
342
+ statsParts.push(`Artifact: ${artifactId}`);
343
+ }
344
+ if (isError && typeof details?.exitCode === "number") {
345
+ statsParts.push(`Exit: ${details.exitCode}`);
346
+ }
347
+ return statsParts;
348
+ }
349
+
350
+ /**
351
+ * Native head facts of a shell call: title, the command once (`cd`/env
352
+ * prefix included), a `background` badge for a backgrounded job, the
353
+ * `exit N` chip and a `timed out` note only when the deadline hit.
354
+ */
355
+ function shellToolHead(
356
+ title: string,
357
+ command: string,
358
+ details: BashToolDetails | undefined,
359
+ settled: boolean,
360
+ ): NativeToolHead {
361
+ const exit = settled && details?.exitCode !== undefined && details.exitCode !== 0 ? details.exitCode : undefined;
362
+ return {
363
+ title,
364
+ target: command,
365
+ targetKind: "command",
366
+ lang: "bash",
367
+ badges:
368
+ details?.async?.state === "running"
369
+ ? [{ text: "background", title: `Backgrounded as job ${details.async.jobId}` }]
370
+ : undefined,
371
+ exit,
372
+ note: settled && details?.timedOut === true ? "timed out" : undefined,
373
+ };
374
+ }
375
+
376
+ /** The quiet final line's facts under shell output: service state and the full-output artifact. */
377
+ function shellFootParts(details: BashToolDetails | undefined, artifactId: string | undefined): string[] {
378
+ const parts: string[] = [];
379
+ const service = details?.service;
380
+ if (service) {
381
+ parts.push(`Service ${service.name}`, service.state);
382
+ parts.push(service.ready ? "ready" : service.timedOut ? "ready timed out" : "not ready");
383
+ if (service.pid !== undefined) parts.push(`PID ${service.pid}`);
384
+ }
385
+ if (artifactId) parts.push(`Artifact ${artifactId}`);
386
+ return parts;
387
+ }
388
+
264
389
  function toBashRenderArgs<TArgs>(args: TArgs | undefined, config: ShellRendererConfig<TArgs>): BashRenderArgs {
265
390
  return {
266
391
  command: config.resolveCommand?.(args),
@@ -378,58 +503,17 @@ export function createShellRenderer<TArgs>(config: ShellRendererConfig<TArgs>) {
378
503
  ) {
379
504
  return cachedSnapshot;
380
505
  }
381
- const withoutBackground =
382
- details?.async?.state === "running"
383
- ? stripTrailingNotice(rawOutput, formatBackgroundNotice(details.async.jobId))
384
- : rawOutput;
385
- const strippedOutput = stripOutputNotice(withoutBackground, details?.meta);
386
- const withoutExit =
387
- details?.exitCode === undefined
388
- ? strippedOutput
389
- : stripTrailingNotice(strippedOutput, formatExitCodeNotice(details.exitCode));
390
- const withoutWall =
391
- details?.wallTimeMs === undefined
392
- ? withoutExit
393
- : stripTrailingNotice(withoutExit, formatWallTimeNotice(details.wallTimeMs));
394
- const rawOutputArtifact = stripRawOutputArtifactNotice(withoutWall);
506
+ const rawOutputArtifact = stripBashNotices(rawOutput, details);
395
507
  const output = rawOutputArtifact.text;
396
508
  const displayOutput = output.trimEnd();
397
509
  const showingFullOutput = expanded && renderContext?.isFullOutput === true;
398
510
 
399
- // Build truncation warning
400
- const timeoutDisabled = details?.timeoutDisabled === true || renderContext?.timeout === 0;
401
- const timeoutSeconds = timeoutDisabled ? undefined : (details?.timeoutSeconds ?? renderContext?.timeout);
402
- const requestedTimeoutSeconds = details?.requestedTimeoutSeconds;
403
- const wallTimeMs = details?.wallTimeMs;
404
- const statsParts: string[] = [];
405
- if (details?.async?.state === "running") {
406
- statsParts.push(`Backgrounded: ${details.async.jobId}`);
407
- }
408
- if (details?.service) {
409
- const service = details.service;
410
- statsParts.push(`Service: ${service.name}`, `State: ${service.state}`);
411
- statsParts.push(`Ready: ${service.ready ? "yes" : service.timedOut ? "timed out" : "no"}`);
412
- if (service.pid !== undefined) statsParts.push(`PID: ${service.pid}`);
413
- }
414
- if (wallTimeMs !== undefined) {
415
- statsParts.push(`Wall: ${formatWallTimeSeconds(wallTimeMs)}s`);
416
- }
417
- if (timeoutDisabled) {
418
- statsParts.push("Timeout: disabled");
419
- }
420
- if (typeof timeoutSeconds === "number") {
421
- statsParts.push(
422
- requestedTimeoutSeconds !== undefined && requestedTimeoutSeconds !== timeoutSeconds
423
- ? `Timeout: ${timeoutSeconds}s (requested ${requestedTimeoutSeconds}s clamped)`
424
- : `Timeout: ${timeoutSeconds}s`,
425
- );
426
- }
427
- if (rawOutputArtifact.artifactId) {
428
- statsParts.push(`Artifact: ${rawOutputArtifact.artifactId}`);
429
- }
430
- if (isError && typeof details?.exitCode === "number") {
431
- statsParts.push(`Exit: ${details.exitCode}`);
432
- }
511
+ const statsParts = bashStatsParts(
512
+ details,
513
+ renderContext?.timeout,
514
+ rawOutputArtifact.artifactId,
515
+ isError,
516
+ );
433
517
  const timeoutLine =
434
518
  statsParts.length > 0
435
519
  ? uiTheme.fg(
@@ -506,6 +590,53 @@ export function createShellRenderer<TArgs>(config: ShellRendererConfig<TArgs>) {
506
590
  },
507
591
  );
508
592
  },
593
+ describeCall(args: TArgs, options: RenderResultOptions): NativeToolView {
594
+ const command = formatBashCommandText(toBashRenderArgs(args, config));
595
+ // The command shows once, in the head; the body is only the output.
596
+ return {
597
+ tool: shellToolHead(config.resolveTitle(args, options), command, undefined, false),
598
+ preview: { tail: BASH_DEFAULT_PREVIEW_LINES },
599
+ };
600
+ },
601
+
602
+ describeResult(
603
+ result: {
604
+ content: Array<{ type: string; text?: string }>;
605
+ details?: BashToolDetails;
606
+ isError?: boolean;
607
+ },
608
+ options: RenderResultContextOptions & { renderContext?: BashRenderContext },
609
+ args?: TArgs,
610
+ ): NativeToolView {
611
+ const details = result.details;
612
+ const renderContext = options.renderContext;
613
+ const isError = result.isError === true;
614
+ const isPartial = options.isPartial === true;
615
+ const rawOutput = renderContext?.output ?? resultText(result);
616
+ const stripped = stripBashNotices(rawOutput, details);
617
+ const output = stripped.text.trimEnd();
618
+ const expanded = renderContext?.expanded ?? options.expanded;
619
+ const showingFullOutput = expanded && renderContext?.isFullOutput === true;
620
+ const command = formatBashCommandText(toBashRenderArgs(args, config));
621
+ const previewLines = renderContext?.previewLines ?? BASH_DEFAULT_PREVIEW_LINES;
622
+ // Wall time is the head timer, the timeout a note only when hit, the exit a head chip:
623
+ // what is left (service state, artifact, truncation) is one quiet final line.
624
+ const meta = details?.meta;
625
+ const body: NativeChild[] = compact([
626
+ output.trim().length > 0 &&
627
+ keyed(ansi(output, { follow: isPartial, role: "omp.tool.bash.output" }), "output"),
628
+ footnoteText(shellFootParts(details, stripped.artifactId), {
629
+ ...meta,
630
+ truncation: showingFullOutput ? undefined : meta?.truncation,
631
+ }),
632
+ ]);
633
+ return {
634
+ tool: shellToolHead(config.resolveTitle(args, options), command, details, !isPartial),
635
+ body,
636
+ tone: !isPartial && isError && details?.timedOut === true ? "warning" : undefined,
637
+ preview: { tail: previewLines },
638
+ };
639
+ },
509
640
  mergeCallAndResult: true,
510
641
  inline: true,
511
642
  } satisfies ToolRenderer<TArgs, BashToolDetails>;
@@ -16,8 +16,11 @@ import {
16
16
  } from "../render/render-utils";
17
17
  import { highlightCode, type Theme } from "../theme/theme";
18
18
  import { parseCfgUrl } from "./cfg-url";
19
- import type { RenderResultOptions } from "./renderer";
19
+ import type { NativeToolView, RenderResultOptions } from "./renderer";
20
20
  import { card, type CardToolResult, firstText, safe } from "./result-card";
21
+ import { code, compact, span, text } from "../native/describe";
22
+ import { plainText } from "../native/spans";
23
+ import { errorView, toolHead } from "./native-view";
21
24
 
22
25
  /** Summary of a `cfg://` read, attached to read tool details. */
23
26
  export interface CfgReadDetails {
@@ -77,6 +80,68 @@ export function renderCfgRead(
77
80
  }, options);
78
81
  }
79
82
 
83
+ /** TSP view of `read cfg://…`: path and counts in the head, the listing as YAML. */
84
+ export function describeCfgRead(
85
+ url: string,
86
+ result: CardToolResult | undefined,
87
+ details: CfgReadDetails | undefined,
88
+ ): NativeToolView {
89
+ const description = (details?.path ?? parseCfgUrl(url)?.segments.join(".")) || "all settings";
90
+ const meta: string[] = [];
91
+ if (details) {
92
+ meta.push(details.count === 1 ? "1 setting" : `${details.count} settings`);
93
+ if (details.modified) meta.push(`${details.modified} modified`);
94
+ }
95
+ if (result?.isError) return errorView("Config", firstText(result) || "Settings read failed.", description, ...meta);
96
+ const head = toolHead("Config", description, ...meta);
97
+ if (!result) return { head };
98
+ const listing = plainText(safe(firstText(result).trimEnd()));
99
+ return {
100
+ head,
101
+ body: listing ? [code(listing, { lang: "yaml" })] : undefined,
102
+ preview: { lines: PREVIEW_LIMITS.COLLAPSED_ITEMS },
103
+ };
104
+ }
105
+
106
+ /** TSP view of `write cfg://…[/save]`: scope/outcome in the head, then `previous → value`. */
107
+ export function describeCfgWrite(
108
+ url: string,
109
+ content: string | undefined,
110
+ result: CardToolResult | undefined,
111
+ details: CfgWriteDetails | undefined,
112
+ ): NativeToolView {
113
+ const target = parseCfgUrl(url);
114
+ const path = details?.path ?? target?.segments.join(".");
115
+ const save = details?.save ?? target?.save ?? false;
116
+ if (result?.isError) return errorView("Config", firstText(result) || "Settings write failed.", path);
117
+ const head = toolHead("Config", path);
118
+ head.push(span(" "), span(save ? "persist" : "session", save ? "accent strong" : "muted"));
119
+ if (details?.outcome === "declined") head.push(span(" "), span("declined", "warning strong"));
120
+ if (details?.outcome === "unchanged") head.push(span(" "), span("unchanged", "muted"));
121
+ const next = span(plainText(details?.value ?? content?.trim() ?? "…"), "toolOutput");
122
+ const change = details
123
+ ? [span(plainText(details.previous), "dim"), span(" → ", "dim"), next]
124
+ : [span("→ ", "dim"), next];
125
+ return {
126
+ head,
127
+ tone: details?.outcome === "declined" ? "warning" : undefined,
128
+ body: compact([
129
+ text(change, { wrap: "word" }),
130
+ details?.effective !== undefined
131
+ ? text(
132
+ [
133
+ span(
134
+ `still ${plainText(details.effective)}: a higher-precedence layer overrides the saved value`,
135
+ "warning",
136
+ ),
137
+ ],
138
+ { wrap: "word" },
139
+ )
140
+ : undefined,
141
+ ]),
142
+ };
143
+ }
144
+
80
145
  /** Render `write cfg://…[/save]`: the proposed value while pending, then the approved/declined change. */
81
146
  export function renderCfgWrite(
82
147
  url: string,