@oh-my-pi/pi-tui 18.2.4 → 18.2.6

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 (748) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +43 -0
  3. package/dist/types/app-keybindings.d.ts +395 -0
  4. package/dist/types/apps/autoresearch-dashboard.d.ts +43 -0
  5. package/dist/types/apps/autoresearch-data.d.ts +15 -0
  6. package/dist/types/apps/cleanse-board.d.ts +66 -0
  7. package/dist/types/apps/cleanse-picker.d.ts +23 -0
  8. package/dist/types/apps/debug/log-formatting.d.ts +6 -0
  9. package/dist/types/apps/debug/log-viewer.d.ts +81 -0
  10. package/dist/types/apps/debug/protocol-probe.d.ts +42 -0
  11. package/dist/types/apps/debug/raw-sse-buffer.d.ts +58 -0
  12. package/dist/types/apps/debug/raw-sse.d.ts +26 -0
  13. package/dist/types/apps/debug/terminal-info.d.ts +34 -0
  14. package/dist/types/apps/debug/viewer-frame.d.ts +52 -0
  15. package/dist/types/apps/git/avatar.d.ts +9 -0
  16. package/dist/types/apps/git/colors.d.ts +49 -0
  17. package/dist/types/apps/git/diff-pane.d.ts +188 -0
  18. package/dist/types/apps/git/git-tui.d.ts +66 -0
  19. package/dist/types/apps/git/sidebar.d.ts +149 -0
  20. package/dist/types/apps/git/state.d.ts +117 -0
  21. package/dist/types/apps/if-bench-board.d.ts +75 -0
  22. package/dist/types/apps/live-visualizer.d.ts +33 -0
  23. package/dist/types/apps/ps-data.d.ts +51 -0
  24. package/dist/types/apps/ps-top.d.ts +33 -0
  25. package/dist/types/apps/session-picker.d.ts +26 -0
  26. package/dist/types/apps/setup-model-picker.d.ts +13 -0
  27. package/dist/types/apps/standalone-picker.d.ts +42 -0
  28. package/dist/types/autocomplete.d.ts +4 -0
  29. package/dist/types/chat/advisor-message.d.ts +11 -0
  30. package/dist/types/chat/assistant-message.d.ts +106 -0
  31. package/dist/types/chat/background-tan-message.d.ts +9 -0
  32. package/dist/types/chat/bash-execution.d.ts +47 -0
  33. package/dist/types/chat/cache-invalidation-marker.d.ts +50 -0
  34. package/dist/types/chat/chat-transcript-builder.d.ts +50 -0
  35. package/dist/types/chat/collab-prompt-message.d.ts +10 -0
  36. package/dist/types/chat/compaction-summary-message.d.ts +54 -0
  37. package/dist/types/chat/custom-message.d.ts +10 -0
  38. package/dist/types/chat/display-preferences.d.ts +13 -0
  39. package/dist/types/chat/eval-execution.d.ts +29 -0
  40. package/dist/types/chat/execution-shared.d.ts +51 -0
  41. package/dist/types/chat/extension-types.d.ts +28 -0
  42. package/dist/types/chat/hook-message.d.ts +10 -0
  43. package/dist/types/chat/image-loading.d.ts +46 -0
  44. package/dist/types/chat/late-diagnostics-message.d.ts +21 -0
  45. package/dist/types/chat/messages.d.ts +189 -0
  46. package/dist/types/chat/reaction.d.ts +30 -0
  47. package/dist/types/chat/read-target.d.ts +4 -0
  48. package/dist/types/chat/read-tool-group.d.ts +67 -0
  49. package/dist/types/chat/served-model-marker.d.ts +47 -0
  50. package/dist/types/chat/skill-message.d.ts +33 -0
  51. package/dist/types/chat/skill-title-input.d.ts +14 -0
  52. package/dist/types/chat/stripped-tool-calls-placeholder.d.ts +12 -0
  53. package/dist/types/chat/thinking-display.d.ts +12 -0
  54. package/dist/types/chat/todo-reminder.d.ts +13 -0
  55. package/dist/types/chat/tool-execution.d.ts +138 -0
  56. package/dist/types/chat/transcript-browser.d.ts +93 -0
  57. package/dist/types/chat/transcript-entry.d.ts +45 -0
  58. package/dist/types/chat/transcript-outline.d.ts +86 -0
  59. package/dist/types/chat/transcript-render-helpers.d.ts +92 -0
  60. package/dist/types/chat/ttsr-notification.d.ts +23 -0
  61. package/dist/types/chat/user-message.d.ts +52 -0
  62. package/dist/types/chrome/chat-block.d.ts +64 -0
  63. package/dist/types/chrome/collab-qrcode.d.ts +28 -0
  64. package/dist/types/chrome/context-thresholds.d.ts +10 -0
  65. package/dist/types/chrome/countdown-timer.d.ts +14 -0
  66. package/dist/types/chrome/diff.d.ts +14 -0
  67. package/dist/types/chrome/dynamic-border.d.ts +16 -0
  68. package/dist/types/chrome/error-block.d.ts +17 -0
  69. package/dist/types/chrome/form-theme.d.ts +3 -0
  70. package/dist/types/chrome/format.d.ts +12 -0
  71. package/dist/types/chrome/index.d.ts +20 -0
  72. package/dist/types/chrome/keybinding-hints.d.ts +40 -0
  73. package/dist/types/chrome/live-board.d.ts +23 -0
  74. package/dist/types/chrome/local-date.d.ts +4 -0
  75. package/dist/types/chrome/message-divider.d.ts +22 -0
  76. package/dist/types/chrome/message-frame.d.ts +52 -0
  77. package/dist/types/chrome/message-notice.d.ts +35 -0
  78. package/dist/types/chrome/overlay-box.d.ts +74 -0
  79. package/dist/types/chrome/qrcode.d.ts +48 -0
  80. package/dist/types/chrome/segment-track.d.ts +27 -0
  81. package/dist/types/chrome/select-list-mouse-routing.d.ts +4 -0
  82. package/dist/types/chrome/selector-helpers.d.ts +52 -0
  83. package/dist/types/chrome/shared.d.ts +5 -0
  84. package/dist/types/chrome/streaming-panel.d.ts +19 -0
  85. package/dist/types/chrome/tool-activity.d.ts +17 -0
  86. package/dist/types/chrome/transcript-container.d.ts +129 -0
  87. package/dist/types/chrome/transcript-status.d.ts +12 -0
  88. package/dist/types/chrome/visual-truncate.d.ts +19 -0
  89. package/dist/types/components/disclosure.d.ts +42 -0
  90. package/dist/types/components/form.d.ts +130 -0
  91. package/dist/types/components/key-value-list.d.ts +24 -0
  92. package/dist/types/components/layout/geometry.d.ts +73 -0
  93. package/dist/types/components/layout/row.d.ts +55 -0
  94. package/dist/types/components/layout/split-pane.d.ts +80 -0
  95. package/dist/types/components/layout/stack.d.ts +50 -0
  96. package/dist/types/components/menu-selection.d.ts +71 -0
  97. package/dist/types/components/metric.d.ts +44 -0
  98. package/dist/types/components/progress-bar.d.ts +36 -0
  99. package/dist/types/components/scroll-view.d.ts +53 -19
  100. package/dist/types/components/scroll-viewport.d.ts +46 -0
  101. package/dist/types/components/section.d.ts +19 -0
  102. package/dist/types/components/select-list.d.ts +46 -2
  103. package/dist/types/components/settings-list.d.ts +20 -0
  104. package/dist/types/components/table.d.ts +32 -0
  105. package/dist/types/components/tree-view.d.ts +130 -0
  106. package/dist/types/components/wizard-step.d.ts +60 -0
  107. package/dist/types/hotkeys-markdown.d.ts +7 -0
  108. package/dist/types/index.d.ts +17 -0
  109. package/dist/types/keybinding-matchers.d.ts +35 -0
  110. package/dist/types/keys.d.ts +2 -2
  111. package/dist/types/lang-from-path.d.ts +9 -0
  112. package/dist/types/overlays/advisor-config.d.ts +114 -0
  113. package/dist/types/overlays/agent-activity.d.ts +41 -0
  114. package/dist/types/overlays/agent-hub-projection.d.ts +33 -0
  115. package/dist/types/overlays/agent-hub-renderer.d.ts +53 -0
  116. package/dist/types/overlays/agent-hub-types.d.ts +99 -0
  117. package/dist/types/overlays/agent-hub.d.ts +126 -0
  118. package/dist/types/overlays/agent-transcript-viewer.d.ts +71 -0
  119. package/dist/types/overlays/agents-hub.d.ts +72 -0
  120. package/dist/types/overlays/ask-dialog.d.ts +88 -0
  121. package/dist/types/overlays/bordered-loader.d.ts +11 -0
  122. package/dist/types/overlays/btw-history-panel.d.ts +29 -0
  123. package/dist/types/overlays/btw-history.d.ts +17 -0
  124. package/dist/types/overlays/btw-panel.d.ts +26 -0
  125. package/dist/types/overlays/cleanse-panel.d.ts +36 -0
  126. package/dist/types/overlays/codex-reset-fireworks.d.ts +52 -0
  127. package/dist/types/overlays/composer-shape-preview.d.ts +47 -0
  128. package/dist/types/overlays/composer-shape-registry.d.ts +50 -0
  129. package/dist/types/overlays/copy-selector.d.ts +48 -0
  130. package/dist/types/overlays/copy-targets.d.ts +63 -0
  131. package/dist/types/overlays/error-banner.d.ts +13 -0
  132. package/dist/types/overlays/extensions/display-text.d.ts +10 -0
  133. package/dist/types/overlays/extensions/extension-dashboard.d.ts +63 -0
  134. package/dist/types/overlays/extensions/extension-list.d.ts +54 -0
  135. package/dist/types/overlays/extensions/inspector-model.d.ts +109 -0
  136. package/dist/types/overlays/extensions/inspector-panel.d.ts +17 -0
  137. package/dist/types/overlays/extensions/live-tool-session.d.ts +28 -0
  138. package/dist/types/overlays/extensions/mcp-runtime.d.ts +107 -0
  139. package/dist/types/overlays/extensions/state-manager.d.ts +42 -0
  140. package/dist/types/overlays/extensions/types.d.ts +165 -0
  141. package/dist/types/overlays/history-search.d.ts +16 -0
  142. package/dist/types/overlays/hook-editor.d.ts +44 -0
  143. package/dist/types/overlays/hook-input.d.ts +20 -0
  144. package/dist/types/overlays/hook-selector.d.ts +71 -0
  145. package/dist/types/overlays/hub-frame.d.ts +77 -0
  146. package/dist/types/overlays/login-dialog.d.ts +43 -0
  147. package/dist/types/overlays/logout-account-selector.d.ts +15 -0
  148. package/dist/types/overlays/mcp-add-wizard.d.ts +87 -0
  149. package/dist/types/overlays/model-browser.d.ts +213 -0
  150. package/dist/types/overlays/model-hub.d.ts +72 -0
  151. package/dist/types/overlays/model-picker.d.ts +74 -0
  152. package/dist/types/overlays/model-selector.d.ts +52 -0
  153. package/dist/types/overlays/move-overlay.d.ts +39 -0
  154. package/dist/types/overlays/oauth-selector.d.ts +41 -0
  155. package/dist/types/overlays/omfg-panel.d.ts +20 -0
  156. package/dist/types/overlays/pause-screen.d.ts +43 -0
  157. package/dist/types/overlays/plan-review-overlay.d.ts +89 -0
  158. package/dist/types/overlays/plan-save-overlay.d.ts +19 -0
  159. package/dist/types/overlays/plan-toc.d.ts +41 -0
  160. package/dist/types/overlays/plugin-selector.d.ts +28 -0
  161. package/dist/types/overlays/plugin-settings.d.ts +180 -0
  162. package/dist/types/overlays/queue-mode-selector.d.ts +11 -0
  163. package/dist/types/overlays/reset-usage-selector.d.ts +23 -0
  164. package/dist/types/overlays/rewind-selector.d.ts +61 -0
  165. package/dist/types/overlays/running-subagent-badge.d.ts +6 -0
  166. package/dist/types/overlays/session-account-selector.d.ts +24 -0
  167. package/dist/types/overlays/session-info-overlay.d.ts +17 -0
  168. package/dist/types/overlays/session-observer-registry.d.ts +77 -0
  169. package/dist/types/overlays/session-selector.d.ts +131 -0
  170. package/dist/types/overlays/settings-defs.d.ts +119 -0
  171. package/dist/types/overlays/settings-selector.d.ts +73 -0
  172. package/dist/types/overlays/show-images-selector.d.ts +11 -0
  173. package/dist/types/overlays/snapcompact-shape-preview.d.ts +31 -0
  174. package/dist/types/overlays/theme-selector.d.ts +12 -0
  175. package/dist/types/overlays/thinking-selector.d.ts +12 -0
  176. package/dist/types/overlays/tiny-title-download-progress.d.ts +21 -0
  177. package/dist/types/overlays/tree-selector.d.ts +92 -0
  178. package/dist/types/overlays/usage-dashboard.d.ts +94 -0
  179. package/dist/types/overlays/usage-display.d.ts +5 -0
  180. package/dist/types/overlays/usage-row.d.ts +17 -0
  181. package/dist/types/prompt/attachment-chips.d.ts +19 -0
  182. package/dist/types/prompt/composer-attachments.d.ts +71 -0
  183. package/dist/types/prompt/composer-cache.d.ts +37 -0
  184. package/dist/types/prompt/composer.d.ts +159 -0
  185. package/dist/types/prompt/custom-editor.d.ts +261 -0
  186. package/dist/types/prompt/editor-top-gap.d.ts +18 -0
  187. package/dist/types/prompt/emoji-autocomplete.d.ts +16 -0
  188. package/dist/types/prompt/github-ref-autocomplete.d.ts +35 -0
  189. package/dist/types/prompt/gradient-highlight.d.ts +32 -0
  190. package/dist/types/prompt/image-format.d.ts +4 -0
  191. package/dist/types/prompt/image-references.d.ts +26 -0
  192. package/dist/types/prompt/interactive-context-helpers.d.ts +43 -0
  193. package/dist/types/prompt/internal-url-autocomplete.d.ts +56 -0
  194. package/dist/types/prompt/macos-spelling.d.ts +44 -0
  195. package/dist/types/prompt/magic-keyword-boundary.d.ts +9 -0
  196. package/dist/types/prompt/magic-keywords.d.ts +26 -0
  197. package/dist/types/prompt/markdown-prose.d.ts +15 -0
  198. package/dist/types/prompt/model-mention-autocomplete.d.ts +25 -0
  199. package/dist/types/prompt/model-mention-syntax.d.ts +24 -0
  200. package/dist/types/prompt/orchestrate.d.ts +13 -0
  201. package/dist/types/prompt/prompt-action-autocomplete.d.ts +56 -0
  202. package/dist/types/prompt/queue-input.d.ts +8 -0
  203. package/dist/types/prompt/skill-tokens.d.ts +13 -0
  204. package/dist/types/prompt/tools-markdown.d.ts +12 -0
  205. package/dist/types/prompt/ultrathink.d.ts +13 -0
  206. package/dist/types/prompt/usage-amounts.d.ts +26 -0
  207. package/dist/types/prompt/video.d.ts +18 -0
  208. package/dist/types/prompt/welcome.d.ts +83 -0
  209. package/dist/types/prompt/workflow.d.ts +13 -0
  210. package/dist/types/render/code-cell.d.ts +51 -0
  211. package/dist/types/render/file-list.d.ts +22 -0
  212. package/dist/types/render/hyperlink.d.ts +80 -0
  213. package/dist/types/render/index.d.ts +16 -0
  214. package/dist/types/render/output-block.d.ts +54 -0
  215. package/dist/types/render/output-pane.d.ts +80 -0
  216. package/dist/types/render/render-utils.d.ts +312 -0
  217. package/dist/types/render/sixel.d.ts +21 -0
  218. package/dist/types/render/status-line.d.ts +23 -0
  219. package/dist/types/render/tool-card.d.ts +71 -0
  220. package/dist/types/render/tree-list.d.ts +29 -0
  221. package/dist/types/render/types.d.ts +17 -0
  222. package/dist/types/render/utils.d.ts +43 -0
  223. package/dist/types/render/width-aware-text.d.ts +23 -0
  224. package/dist/types/setup/lazy.d.ts +3 -0
  225. package/dist/types/setup/scenes/composer.d.ts +3 -0
  226. package/dist/types/setup/scenes/glyph.d.ts +3 -0
  227. package/dist/types/setup/scenes/model.d.ts +3 -0
  228. package/dist/types/setup/scenes/outro.d.ts +2 -0
  229. package/dist/types/setup/scenes/providers.d.ts +3 -0
  230. package/dist/types/setup/scenes/sign-in.d.ts +21 -0
  231. package/dist/types/setup/scenes/splash.d.ts +11 -0
  232. package/dist/types/setup/scenes/theme.d.ts +3 -0
  233. package/dist/types/setup/scenes/types.d.ts +110 -0
  234. package/dist/types/setup/scenes/web-search.d.ts +22 -0
  235. package/dist/types/setup/setup-version.d.ts +11 -0
  236. package/dist/types/setup/startup-splash.d.ts +9 -0
  237. package/dist/types/setup/wizard-overlay.d.ts +16 -0
  238. package/dist/types/setup/wizard.d.ts +25 -0
  239. package/dist/types/status-line/component.d.ts +182 -0
  240. package/dist/types/status-line/context-usage.d.ts +156 -0
  241. package/dist/types/status-line/footer.d.ts +30 -0
  242. package/dist/types/status-line/git-utils.d.ts +22 -0
  243. package/dist/types/status-line/host.d.ts +129 -0
  244. package/dist/types/status-line/index.d.ts +6 -0
  245. package/dist/types/status-line/loop.d.ts +18 -0
  246. package/dist/types/status-line/metrics.d.ts +21 -0
  247. package/dist/types/status-line/presets.d.ts +3 -0
  248. package/dist/types/status-line/schema.d.ts +15 -0
  249. package/dist/types/status-line/segments.d.ts +5 -0
  250. package/dist/types/status-line/separators.d.ts +3 -0
  251. package/dist/types/status-line/types.d.ts +236 -0
  252. package/dist/types/stdin-buffer.d.ts +4 -0
  253. package/dist/types/theme/color.d.ts +24 -0
  254. package/dist/types/theme/defaults/index.d.ts +9489 -0
  255. package/dist/types/theme/index.d.ts +4 -0
  256. package/dist/types/theme/loader.d.ts +23 -0
  257. package/dist/types/theme/mermaid-cache.d.ts +26 -0
  258. package/dist/types/theme/schema-validation.d.ts +3 -0
  259. package/dist/types/theme/schema.d.ts +25 -0
  260. package/dist/types/theme/session-color.d.ts +43 -0
  261. package/dist/types/theme/shimmer.d.ts +44 -0
  262. package/dist/types/theme/symbols.d.ts +34 -0
  263. package/dist/types/theme/theme-class.d.ts +299 -0
  264. package/dist/types/theme/theme.d.ts +111 -0
  265. package/dist/types/theme/tui-adapters.d.ts +30 -0
  266. package/dist/types/thinking.d.ts +165 -0
  267. package/dist/types/tools/agent-tree.d.ts +36 -0
  268. package/dist/types/tools/ask.d.ts +67 -0
  269. package/dist/types/tools/ast-edit.d.ts +53 -0
  270. package/dist/types/tools/ast-grep.d.ts +52 -0
  271. package/dist/types/tools/autoresearch.d.ts +156 -0
  272. package/dist/types/tools/bash-interactive.d.ts +28 -0
  273. package/dist/types/tools/bash.d.ts +103 -0
  274. package/dist/types/tools/conflict-detect.d.ts +43 -0
  275. package/dist/types/tools/debug.d.ts +60 -0
  276. package/dist/types/tools/default-renderer.d.ts +24 -0
  277. package/dist/types/tools/edit.d.ts +158 -0
  278. package/dist/types/tools/eval-format/code-mode-declarations.d.ts +5 -0
  279. package/dist/types/tools/eval-format/index.d.ts +5 -0
  280. package/dist/types/tools/eval-format/javascript.d.ts +2 -0
  281. package/dist/types/tools/eval-format/python.d.ts +2 -0
  282. package/dist/types/tools/eval.d.ts +94 -0
  283. package/dist/types/tools/fetch.d.ts +42 -0
  284. package/dist/types/tools/gh-format.d.ts +8 -0
  285. package/dist/types/tools/github.d.ts +144 -0
  286. package/dist/types/tools/glob.d.ts +44 -0
  287. package/dist/types/tools/goal.d.ts +42 -0
  288. package/dist/types/tools/grep.d.ts +64 -0
  289. package/dist/types/tools/grouped-file-output.d.ts +71 -0
  290. package/dist/types/tools/hashline-format.d.ts +28 -0
  291. package/dist/types/tools/hub.d.ts +340 -0
  292. package/dist/types/tools/index.d.ts +4 -0
  293. package/dist/types/tools/json-tree.d.ts +59 -0
  294. package/dist/types/tools/line-ranges.d.ts +29 -0
  295. package/dist/types/tools/list-limit.d.ts +15 -0
  296. package/dist/types/tools/lsp.d.ts +72 -0
  297. package/dist/types/tools/match-line-format.d.ts +11 -0
  298. package/dist/types/tools/mcp.d.ts +81 -0
  299. package/dist/types/tools/memory.d.ts +67 -0
  300. package/dist/types/tools/output-meta.d.ts +151 -0
  301. package/dist/types/tools/read.d.ts +139 -0
  302. package/dist/types/tools/renderer.d.ts +98 -0
  303. package/dist/types/tools/report-tool-issue.d.ts +8 -0
  304. package/dist/types/tools/resolve.d.ts +47 -0
  305. package/dist/types/tools/streaming-output.d.ts +282 -0
  306. package/dist/types/tools/subprocess.d.ts +24 -0
  307. package/dist/types/tools/task-repair-args.d.ts +53 -0
  308. package/dist/types/tools/task-yield-assembly.d.ts +20 -0
  309. package/dist/types/tools/task.d.ts +425 -0
  310. package/dist/types/tools/terminal-output.d.ts +8 -0
  311. package/dist/types/tools/think.d.ts +13 -0
  312. package/dist/types/tools/todo.d.ts +118 -0
  313. package/dist/types/tools/tool-errors.d.ts +7 -0
  314. package/dist/types/tools/vibe.d.ts +120 -0
  315. package/dist/types/tools/web-search.d.ts +195 -0
  316. package/dist/types/tools/write.d.ts +76 -0
  317. package/dist/types/tools/xd-url.d.ts +13 -0
  318. package/dist/types/tools/xdev.d.ts +52 -0
  319. package/dist/types/tui.d.ts +18 -0
  320. package/dist/types/utils.d.ts +2 -0
  321. package/package.json +37 -3
  322. package/src/app-keybindings.ts +760 -0
  323. package/src/apps/autoresearch-dashboard.ts +500 -0
  324. package/src/apps/autoresearch-data.ts +64 -0
  325. package/src/apps/cleanse-board.ts +341 -0
  326. package/src/apps/cleanse-picker.ts +57 -0
  327. package/src/apps/debug/log-formatting.ts +53 -0
  328. package/src/apps/debug/log-viewer.ts +868 -0
  329. package/src/apps/debug/protocol-probe.ts +267 -0
  330. package/src/apps/debug/raw-sse-buffer.ts +449 -0
  331. package/src/apps/debug/raw-sse.ts +282 -0
  332. package/src/apps/debug/terminal-info.ts +115 -0
  333. package/src/apps/debug/viewer-frame.ts +174 -0
  334. package/src/apps/git/avatar.ts +52 -0
  335. package/src/apps/git/colors.ts +109 -0
  336. package/src/apps/git/diff-pane.ts +1512 -0
  337. package/src/apps/git/git-tui.ts +889 -0
  338. package/src/apps/git/sidebar.ts +1204 -0
  339. package/src/apps/git/state.ts +113 -0
  340. package/src/apps/if-bench-board.ts +324 -0
  341. package/src/apps/live-visualizer.ts +238 -0
  342. package/src/apps/ps-data.ts +116 -0
  343. package/src/apps/ps-top.ts +422 -0
  344. package/src/apps/session-picker.ts +95 -0
  345. package/src/apps/setup-model-picker.ts +21 -0
  346. package/src/apps/standalone-picker.ts +111 -0
  347. package/src/autocomplete.ts +9 -13
  348. package/src/chat/advisor-message.ts +175 -0
  349. package/src/chat/assistant-message.ts +1214 -0
  350. package/src/chat/background-tan-message.ts +35 -0
  351. package/src/chat/bash-execution.ts +394 -0
  352. package/src/chat/cache-invalidation-marker.ts +94 -0
  353. package/src/chat/chat-transcript-builder.ts +593 -0
  354. package/src/chat/collab-prompt-message.ts +34 -0
  355. package/src/chat/compaction-summary-message.ts +261 -0
  356. package/src/chat/custom-message.ts +23 -0
  357. package/src/chat/display-preferences.ts +24 -0
  358. package/src/chat/eval-execution.ts +172 -0
  359. package/src/chat/execution-shared.ts +113 -0
  360. package/src/chat/extension-types.ts +46 -0
  361. package/src/chat/hook-message.ts +20 -0
  362. package/src/chat/image-loading.ts +122 -0
  363. package/src/chat/late-diagnostics-message.ts +92 -0
  364. package/src/chat/messages.ts +305 -0
  365. package/src/chat/reaction.ts +65 -0
  366. package/src/chat/read-target.ts +7 -0
  367. package/src/chat/read-tool-group.ts +873 -0
  368. package/src/chat/served-model-marker.ts +91 -0
  369. package/src/chat/skill-message.ts +220 -0
  370. package/src/chat/skill-title-input.ts +41 -0
  371. package/src/chat/stripped-tool-calls-placeholder.ts +35 -0
  372. package/src/chat/thinking-display.ts +312 -0
  373. package/src/chat/todo-reminder.ts +33 -0
  374. package/src/chat/tool-execution.ts +1395 -0
  375. package/src/chat/transcript-browser.ts +268 -0
  376. package/src/chat/transcript-entry.ts +96 -0
  377. package/src/chat/transcript-outline.ts +260 -0
  378. package/src/chat/transcript-render-helpers.ts +315 -0
  379. package/src/chat/ttsr-notification.ts +123 -0
  380. package/src/chat/user-message.ts +287 -0
  381. package/src/chrome/chat-block.ts +110 -0
  382. package/src/chrome/collab-qrcode.ts +74 -0
  383. package/src/chrome/context-thresholds.ts +85 -0
  384. package/src/chrome/countdown-timer.ts +74 -0
  385. package/src/chrome/diff.ts +266 -0
  386. package/src/chrome/dynamic-border.ts +36 -0
  387. package/src/chrome/error-block.ts +63 -0
  388. package/src/chrome/form-theme.ts +10 -0
  389. package/src/chrome/format.ts +66 -0
  390. package/src/chrome/index.ts +21 -0
  391. package/src/chrome/keybinding-hints.ts +55 -0
  392. package/src/chrome/live-board.ts +123 -0
  393. package/src/chrome/local-date.ts +20 -0
  394. package/src/chrome/message-divider.ts +51 -0
  395. package/src/chrome/message-frame.ts +164 -0
  396. package/src/chrome/message-notice.ts +103 -0
  397. package/src/chrome/overlay-box.ts +301 -0
  398. package/src/chrome/qrcode.ts +539 -0
  399. package/src/chrome/segment-track.ts +86 -0
  400. package/src/chrome/select-list-mouse-routing.ts +11 -0
  401. package/src/chrome/selector-helpers.ts +119 -0
  402. package/src/chrome/shared.ts +27 -0
  403. package/src/chrome/streaming-panel.ts +72 -0
  404. package/src/chrome/tool-activity.ts +44 -0
  405. package/src/chrome/transcript-container.ts +902 -0
  406. package/src/chrome/transcript-status.ts +27 -0
  407. package/src/chrome/visual-truncate.ts +70 -0
  408. package/src/components/disclosure.ts +235 -0
  409. package/src/components/editor.ts +10 -12
  410. package/src/components/form.ts +566 -0
  411. package/src/components/input.ts +6 -27
  412. package/src/components/key-value-list.ts +88 -0
  413. package/src/components/layout/geometry.ts +202 -0
  414. package/src/components/layout/row.ts +283 -0
  415. package/src/components/layout/split-pane.ts +349 -0
  416. package/src/components/layout/stack.ts +261 -0
  417. package/src/components/markdown.ts +16 -12
  418. package/src/components/menu-selection.ts +248 -0
  419. package/src/components/metric.ts +132 -0
  420. package/src/components/progress-bar.ts +140 -0
  421. package/src/components/scroll-view.ts +372 -70
  422. package/src/components/scroll-viewport.ts +154 -0
  423. package/src/components/section.ts +77 -0
  424. package/src/components/select-list.ts +238 -159
  425. package/src/components/settings-list.ts +103 -80
  426. package/src/components/table.ts +127 -0
  427. package/src/components/tree-view.ts +481 -0
  428. package/src/components/wizard-step.ts +229 -0
  429. package/src/deccara.ts +1 -3
  430. package/src/hotkeys-markdown.ts +100 -0
  431. package/src/index.ts +18 -0
  432. package/src/keybinding-matchers.ts +99 -0
  433. package/src/keys.ts +2 -2
  434. package/src/lang-from-path.ts +252 -0
  435. package/src/overlays/advisor-config.ts +761 -0
  436. package/src/overlays/agent-activity.ts +113 -0
  437. package/src/overlays/agent-hub-projection.ts +250 -0
  438. package/src/overlays/agent-hub-renderer.ts +281 -0
  439. package/src/overlays/agent-hub-types.ts +74 -0
  440. package/src/overlays/agent-hub.ts +1562 -0
  441. package/src/overlays/agent-transcript-viewer.ts +669 -0
  442. package/src/overlays/agents-hub.ts +1203 -0
  443. package/src/overlays/ask-dialog.ts +1202 -0
  444. package/src/overlays/bordered-loader.ts +41 -0
  445. package/src/overlays/btw-history-panel.ts +591 -0
  446. package/src/overlays/btw-history.ts +33 -0
  447. package/src/overlays/btw-panel.ts +167 -0
  448. package/src/overlays/cleanse-panel.ts +167 -0
  449. package/src/overlays/codex-reset-fireworks.ts +375 -0
  450. package/src/overlays/composer-shape-preview.ts +137 -0
  451. package/src/overlays/composer-shape-registry.ts +82 -0
  452. package/src/overlays/copy-selector.ts +618 -0
  453. package/src/overlays/copy-targets.ts +210 -0
  454. package/src/overlays/error-banner.ts +39 -0
  455. package/src/overlays/extensions/display-text.ts +39 -0
  456. package/src/overlays/extensions/extension-dashboard.ts +645 -0
  457. package/src/overlays/extensions/extension-list.ts +667 -0
  458. package/src/overlays/extensions/inspector-model.ts +484 -0
  459. package/src/overlays/extensions/inspector-panel.ts +669 -0
  460. package/src/overlays/extensions/live-tool-session.ts +67 -0
  461. package/src/overlays/extensions/mcp-runtime.ts +289 -0
  462. package/src/overlays/extensions/state-manager.ts +337 -0
  463. package/src/overlays/extensions/types.ts +208 -0
  464. package/src/overlays/history-search.ts +268 -0
  465. package/src/overlays/hook-editor.ts +272 -0
  466. package/src/overlays/hook-input.ts +84 -0
  467. package/src/overlays/hook-selector.ts +635 -0
  468. package/src/overlays/hub-frame.ts +262 -0
  469. package/src/overlays/login-dialog.ts +231 -0
  470. package/src/overlays/logout-account-selector.ts +115 -0
  471. package/src/overlays/mcp-add-wizard.ts +1436 -0
  472. package/src/overlays/model-browser.ts +1176 -0
  473. package/src/overlays/model-hub.ts +2279 -0
  474. package/src/overlays/model-picker.ts +285 -0
  475. package/src/overlays/model-selector.ts +107 -0
  476. package/src/overlays/move-overlay.ts +197 -0
  477. package/src/overlays/oauth-selector.ts +446 -0
  478. package/src/overlays/omfg-panel.ts +136 -0
  479. package/src/overlays/pause-screen.ts +198 -0
  480. package/src/overlays/plan-review-overlay.ts +1227 -0
  481. package/src/overlays/plan-save-overlay.ts +74 -0
  482. package/src/overlays/plan-toc.ts +139 -0
  483. package/src/overlays/plugin-selector.ts +97 -0
  484. package/src/overlays/plugin-settings.ts +839 -0
  485. package/src/overlays/queue-mode-selector.ts +55 -0
  486. package/src/overlays/reset-usage-selector.ts +170 -0
  487. package/src/overlays/rewind-selector.ts +499 -0
  488. package/src/overlays/running-subagent-badge.ts +19 -0
  489. package/src/overlays/session-account-selector.ts +68 -0
  490. package/src/overlays/session-info-overlay.ts +96 -0
  491. package/src/overlays/session-observer-registry.ts +289 -0
  492. package/src/overlays/session-selector.ts +1137 -0
  493. package/src/overlays/settings-defs.ts +315 -0
  494. package/src/overlays/settings-selector.ts +1415 -0
  495. package/src/overlays/show-images-selector.ts +44 -0
  496. package/src/overlays/snapcompact-shape-preview-doc.md +14 -0
  497. package/src/overlays/snapcompact-shape-preview.ts +192 -0
  498. package/src/overlays/theme-selector.ts +62 -0
  499. package/src/overlays/thinking-selector.ts +51 -0
  500. package/src/overlays/tiny-title-download-progress.ts +102 -0
  501. package/src/overlays/tree-selector.ts +1121 -0
  502. package/src/overlays/usage-dashboard.ts +629 -0
  503. package/src/overlays/usage-display.ts +45 -0
  504. package/src/overlays/usage-row.ts +118 -0
  505. package/src/prompt/attachment-chips.ts +201 -0
  506. package/src/prompt/composer-attachments.ts +280 -0
  507. package/src/prompt/composer-cache.ts +304 -0
  508. package/src/prompt/composer.ts +934 -0
  509. package/src/prompt/custom-editor.ts +1392 -0
  510. package/src/prompt/data/emojis.json +1 -0
  511. package/src/prompt/editor-top-gap.ts +28 -0
  512. package/src/prompt/emoji-autocomplete.ts +285 -0
  513. package/src/prompt/github-ref-autocomplete.ts +75 -0
  514. package/src/prompt/gradient-highlight.ts +101 -0
  515. package/src/prompt/image-format.ts +28 -0
  516. package/src/prompt/image-references.ts +102 -0
  517. package/src/prompt/interactive-context-helpers.ts +126 -0
  518. package/src/prompt/internal-url-autocomplete.ts +155 -0
  519. package/src/prompt/macos-spelling.ts +456 -0
  520. package/src/prompt/magic-keyword-boundary.ts +23 -0
  521. package/src/prompt/magic-keywords.ts +42 -0
  522. package/src/prompt/markdown-prose.ts +245 -0
  523. package/src/prompt/model-mention-autocomplete.ts +94 -0
  524. package/src/prompt/model-mention-syntax.ts +41 -0
  525. package/src/prompt/orchestrate.ts +26 -0
  526. package/src/prompt/prompt-action-autocomplete.ts +337 -0
  527. package/src/prompt/queue-input.ts +132 -0
  528. package/src/prompt/skill-tokens.ts +36 -0
  529. package/src/prompt/tips.txt +27 -0
  530. package/src/prompt/tools-markdown.ts +29 -0
  531. package/src/prompt/ultrathink.ts +26 -0
  532. package/src/prompt/usage-amounts.ts +99 -0
  533. package/src/prompt/video.ts +47 -0
  534. package/src/prompt/welcome.ts +605 -0
  535. package/src/prompt/workflow.ts +26 -0
  536. package/src/render/code-cell.ts +244 -0
  537. package/src/render/file-list.ts +58 -0
  538. package/src/render/hyperlink.ts +192 -0
  539. package/src/render/index.ts +17 -0
  540. package/src/render/output-block.ts +267 -0
  541. package/src/render/output-pane.ts +299 -0
  542. package/src/render/render-utils.ts +1182 -0
  543. package/src/render/sixel.ts +69 -0
  544. package/src/render/status-line.ts +55 -0
  545. package/src/render/tool-card.ts +272 -0
  546. package/src/render/tree-list.ts +188 -0
  547. package/src/render/types.ts +19 -0
  548. package/src/render/utils.ts +109 -0
  549. package/src/render/width-aware-text.ts +60 -0
  550. package/src/setup/lazy.ts +17 -0
  551. package/src/setup/scenes/composer.ts +127 -0
  552. package/src/setup/scenes/glyph.ts +120 -0
  553. package/src/setup/scenes/model.ts +138 -0
  554. package/src/setup/scenes/outro.ts +24 -0
  555. package/src/setup/scenes/providers.ts +107 -0
  556. package/src/setup/scenes/sign-in.ts +373 -0
  557. package/src/setup/scenes/splash.ts +192 -0
  558. package/src/setup/scenes/theme.ts +343 -0
  559. package/src/setup/scenes/types.ts +111 -0
  560. package/src/setup/scenes/web-search.ts +165 -0
  561. package/src/setup/setup-version.ts +11 -0
  562. package/src/setup/startup-splash.ts +107 -0
  563. package/src/setup/wizard-overlay.ts +319 -0
  564. package/src/setup/wizard.ts +101 -0
  565. package/src/status-line/component.ts +3003 -0
  566. package/src/status-line/context-usage.ts +688 -0
  567. package/src/status-line/footer.ts +323 -0
  568. package/src/status-line/git-utils.ts +42 -0
  569. package/src/status-line/host.ts +97 -0
  570. package/src/status-line/index.ts +6 -0
  571. package/src/status-line/loop.ts +28 -0
  572. package/src/status-line/metrics.ts +94 -0
  573. package/src/status-line/presets.ts +107 -0
  574. package/src/status-line/schema.ts +57 -0
  575. package/src/status-line/segments.ts +934 -0
  576. package/src/status-line/separators.ts +55 -0
  577. package/src/status-line/types.ts +227 -0
  578. package/src/stdin-buffer.ts +4 -2
  579. package/src/theme/color.ts +95 -0
  580. package/src/theme/dark.json +95 -0
  581. package/src/theme/defaults/alabaster.json +93 -0
  582. package/src/theme/defaults/amethyst.json +96 -0
  583. package/src/theme/defaults/anthracite.json +93 -0
  584. package/src/theme/defaults/basalt.json +91 -0
  585. package/src/theme/defaults/birch.json +95 -0
  586. package/src/theme/defaults/dark-abyss.json +91 -0
  587. package/src/theme/defaults/dark-arctic.json +104 -0
  588. package/src/theme/defaults/dark-aurora.json +95 -0
  589. package/src/theme/defaults/dark-catppuccin.json +107 -0
  590. package/src/theme/defaults/dark-cavern.json +91 -0
  591. package/src/theme/defaults/dark-celestial.json +106 -0
  592. package/src/theme/defaults/dark-copper.json +95 -0
  593. package/src/theme/defaults/dark-cosmos.json +90 -0
  594. package/src/theme/defaults/dark-cyberpunk.json +102 -0
  595. package/src/theme/defaults/dark-dracula.json +98 -0
  596. package/src/theme/defaults/dark-eclipse.json +91 -0
  597. package/src/theme/defaults/dark-ember.json +95 -0
  598. package/src/theme/defaults/dark-equinox.json +90 -0
  599. package/src/theme/defaults/dark-forest.json +96 -0
  600. package/src/theme/defaults/dark-github.json +105 -0
  601. package/src/theme/defaults/dark-gruvbox.json +112 -0
  602. package/src/theme/defaults/dark-lavender.json +95 -0
  603. package/src/theme/defaults/dark-lunar.json +89 -0
  604. package/src/theme/defaults/dark-midnight.json +95 -0
  605. package/src/theme/defaults/dark-monochrome.json +94 -0
  606. package/src/theme/defaults/dark-monokai.json +98 -0
  607. package/src/theme/defaults/dark-nebula.json +90 -0
  608. package/src/theme/defaults/dark-nord.json +98 -0
  609. package/src/theme/defaults/dark-ocean.json +101 -0
  610. package/src/theme/defaults/dark-one.json +100 -0
  611. package/src/theme/defaults/dark-poimandres.json +115 -0
  612. package/src/theme/defaults/dark-rainforest.json +91 -0
  613. package/src/theme/defaults/dark-reef.json +91 -0
  614. package/src/theme/defaults/dark-retro.json +92 -0
  615. package/src/theme/defaults/dark-rose-pine.json +96 -0
  616. package/src/theme/defaults/dark-sakura.json +95 -0
  617. package/src/theme/defaults/dark-slate.json +95 -0
  618. package/src/theme/defaults/dark-solarized.json +97 -0
  619. package/src/theme/defaults/dark-solstice.json +90 -0
  620. package/src/theme/defaults/dark-starfall.json +91 -0
  621. package/src/theme/defaults/dark-sunset.json +99 -0
  622. package/src/theme/defaults/dark-swamp.json +90 -0
  623. package/src/theme/defaults/dark-synthwave.json +103 -0
  624. package/src/theme/defaults/dark-taiga.json +91 -0
  625. package/src/theme/defaults/dark-terminal.json +95 -0
  626. package/src/theme/defaults/dark-tokyo-night.json +101 -0
  627. package/src/theme/defaults/dark-tundra.json +91 -0
  628. package/src/theme/defaults/dark-twilight.json +91 -0
  629. package/src/theme/defaults/dark-volcanic.json +91 -0
  630. package/src/theme/defaults/graphite.json +92 -0
  631. package/src/theme/defaults/index.ts +201 -0
  632. package/src/theme/defaults/light-arctic.json +107 -0
  633. package/src/theme/defaults/light-aurora-day.json +91 -0
  634. package/src/theme/defaults/light-canyon.json +91 -0
  635. package/src/theme/defaults/light-catppuccin.json +106 -0
  636. package/src/theme/defaults/light-cirrus.json +90 -0
  637. package/src/theme/defaults/light-coral.json +95 -0
  638. package/src/theme/defaults/light-cyberpunk.json +96 -0
  639. package/src/theme/defaults/light-dawn.json +90 -0
  640. package/src/theme/defaults/light-dunes.json +91 -0
  641. package/src/theme/defaults/light-eucalyptus.json +95 -0
  642. package/src/theme/defaults/light-forest.json +100 -0
  643. package/src/theme/defaults/light-frost.json +95 -0
  644. package/src/theme/defaults/light-github.json +115 -0
  645. package/src/theme/defaults/light-glacier.json +91 -0
  646. package/src/theme/defaults/light-gruvbox.json +108 -0
  647. package/src/theme/defaults/light-haze.json +90 -0
  648. package/src/theme/defaults/light-honeycomb.json +95 -0
  649. package/src/theme/defaults/light-lagoon.json +91 -0
  650. package/src/theme/defaults/light-lavender.json +95 -0
  651. package/src/theme/defaults/light-meadow.json +91 -0
  652. package/src/theme/defaults/light-mint.json +95 -0
  653. package/src/theme/defaults/light-monochrome.json +101 -0
  654. package/src/theme/defaults/light-ocean.json +99 -0
  655. package/src/theme/defaults/light-one.json +99 -0
  656. package/src/theme/defaults/light-opal.json +91 -0
  657. package/src/theme/defaults/light-orchard.json +91 -0
  658. package/src/theme/defaults/light-paper.json +95 -0
  659. package/src/theme/defaults/light-poimandres.json +115 -0
  660. package/src/theme/defaults/light-prism.json +90 -0
  661. package/src/theme/defaults/light-retro.json +98 -0
  662. package/src/theme/defaults/light-sand.json +95 -0
  663. package/src/theme/defaults/light-savanna.json +91 -0
  664. package/src/theme/defaults/light-solarized.json +102 -0
  665. package/src/theme/defaults/light-soleil.json +90 -0
  666. package/src/theme/defaults/light-sunset.json +99 -0
  667. package/src/theme/defaults/light-synthwave.json +98 -0
  668. package/src/theme/defaults/light-tokyo-night.json +111 -0
  669. package/src/theme/defaults/light-wetland.json +91 -0
  670. package/src/theme/defaults/light-zenith.json +89 -0
  671. package/src/theme/defaults/limestone.json +94 -0
  672. package/src/theme/defaults/mahogany.json +97 -0
  673. package/src/theme/defaults/marble.json +93 -0
  674. package/src/theme/defaults/obsidian.json +91 -0
  675. package/src/theme/defaults/onyx.json +91 -0
  676. package/src/theme/defaults/pearl.json +93 -0
  677. package/src/theme/defaults/porcelain.json +91 -0
  678. package/src/theme/defaults/quartz.json +96 -0
  679. package/src/theme/defaults/sandstone.json +95 -0
  680. package/src/theme/defaults/titanium.json +90 -0
  681. package/src/theme/index.ts +5 -0
  682. package/src/theme/light.json +93 -0
  683. package/src/theme/loader.ts +200 -0
  684. package/src/theme/mermaid-cache.ts +92 -0
  685. package/src/theme/schema-validation.ts +119 -0
  686. package/src/theme/schema.ts +168 -0
  687. package/src/theme/session-color.ts +253 -0
  688. package/src/theme/shimmer.ts +307 -0
  689. package/src/theme/symbols.ts +1433 -0
  690. package/src/theme/theme-class.ts +787 -0
  691. package/src/theme/theme-schema.json +463 -0
  692. package/src/theme/theme.ts +810 -0
  693. package/src/theme/tui-adapters.ts +339 -0
  694. package/src/thinking.ts +380 -0
  695. package/src/tools/agent-tree.ts +128 -0
  696. package/src/tools/ask.ts +482 -0
  697. package/src/tools/ast-edit.ts +210 -0
  698. package/src/tools/ast-grep.ts +171 -0
  699. package/src/tools/autoresearch.ts +287 -0
  700. package/src/tools/bash-interactive.ts +295 -0
  701. package/src/tools/bash.ts +468 -0
  702. package/src/tools/conflict-detect.ts +77 -0
  703. package/src/tools/debug.ts +167 -0
  704. package/src/tools/default-renderer.ts +172 -0
  705. package/src/tools/edit.ts +1258 -0
  706. package/src/tools/eval-format/code-mode-declarations.ts +61 -0
  707. package/src/tools/eval-format/index.ts +16 -0
  708. package/src/tools/eval-format/javascript.ts +952 -0
  709. package/src/tools/eval-format/python.ts +544 -0
  710. package/src/tools/eval.ts +835 -0
  711. package/src/tools/fetch.ts +226 -0
  712. package/src/tools/gh-format.ts +18 -0
  713. package/src/tools/github.ts +686 -0
  714. package/src/tools/glob.ts +213 -0
  715. package/src/tools/goal.ts +153 -0
  716. package/src/tools/grep.ts +385 -0
  717. package/src/tools/grouped-file-output.ts +211 -0
  718. package/src/tools/hashline-format.ts +59 -0
  719. package/src/tools/hub.ts +1488 -0
  720. package/src/tools/index.ts +71 -0
  721. package/src/tools/json-tree.ts +388 -0
  722. package/src/tools/line-ranges.ts +98 -0
  723. package/src/tools/list-limit.ts +43 -0
  724. package/src/tools/lsp.ts +702 -0
  725. package/src/tools/match-line-format.ts +20 -0
  726. package/src/tools/mcp.ts +309 -0
  727. package/src/tools/memory.ts +220 -0
  728. package/src/tools/output-meta.ts +367 -0
  729. package/src/tools/read.ts +628 -0
  730. package/src/tools/renderer.ts +107 -0
  731. package/src/tools/report-tool-issue.ts +13 -0
  732. package/src/tools/resolve.ts +139 -0
  733. package/src/tools/streaming-output.ts +1576 -0
  734. package/src/tools/subprocess.ts +39 -0
  735. package/src/tools/task-repair-args.ts +118 -0
  736. package/src/tools/task-yield-assembly.ts +147 -0
  737. package/src/tools/task.ts +2110 -0
  738. package/src/tools/terminal-output.ts +153 -0
  739. package/src/tools/think.ts +28 -0
  740. package/src/tools/todo.ts +580 -0
  741. package/src/tools/tool-errors.ts +15 -0
  742. package/src/tools/vibe.ts +420 -0
  743. package/src/tools/web-search.ts +409 -0
  744. package/src/tools/write.ts +511 -0
  745. package/src/tools/xd-url.ts +28 -0
  746. package/src/tools/xdev.ts +201 -0
  747. package/src/tui.ts +57 -4
  748. package/src/utils.ts +8 -0
@@ -0,0 +1,511 @@
1
+ import type { HighlightStream } from "@oh-my-pi/pi-natives";
2
+ import type { Component } from "../tui";
3
+ import { Text } from "../components/text";
4
+ import { getLanguageFromPath } from "../lang-from-path";
5
+ import { createHighlightStream, highlightCode, type Theme } from "../theme/theme";
6
+ import { fileHyperlink, renderStatusLine } from "../render";
7
+ import { framedToolCard } from "../render/tool-card";
8
+ import {
9
+ cachedRenderedString,
10
+ createRenderedStringCache,
11
+ Ellipsis,
12
+ formatDiagnostics,
13
+ formatErrorDetail,
14
+ formatExpandHint,
15
+ formatMoreItems,
16
+ formatStatusIcon,
17
+ PREVIEW_LIMITS,
18
+ type RenderedStringCache,
19
+ replaceTabs,
20
+ shortenPath,
21
+ TRUNCATE_LENGTHS,
22
+ truncateToWidth,
23
+ } from "../render/render-utils";
24
+ import type { FileDiagnosticsResult } from "./lsp";
25
+ import type { OutputMeta } from "./output-meta";
26
+ import type { RenderResultOptions, ToolActivityContext, ToolActivitySummary, ToolRenderer } from "./renderer";
27
+ import { couldBecomeXdUrl, parseXdUrl } from "./xd-url";
28
+ import {
29
+ renderXdevCall,
30
+ renderXdevResult,
31
+ xdevActivitySummary,
32
+ type XdevRenderDispatch,
33
+ type XdevMountedRenderer,
34
+ } from "./xdev";
35
+ import { isResolutionDeviceName, renderResolutionDeviceCall } from "./resolve";
36
+ import { REPORT_ISSUE_DEVICE_NAME, renderReportIssueDeviceCall } from "./report-tool-issue";
37
+
38
+ /** Details returned by the write tool for transcript rendering. */
39
+ export interface WriteToolDetails {
40
+ diagnostics?: FileDiagnosticsResult;
41
+ meta?: OutputMeta;
42
+ /** Set when the file was auto-chmod'd because content begins with a `#!` shebang. */
43
+ madeExecutable?: boolean;
44
+ /** Absolute filesystem path the write resolved to. Used by the renderer to wrap
45
+ * the (possibly cwd-relative) header path in an OSC 8 `file://` hyperlink. */
46
+ resolvedPath?: string;
47
+ /** Set when the write dispatched an `xd://` tool device; drives renderer delegation. */
48
+ xdev?: XdevRenderDispatch;
49
+ }
50
+
51
+ interface WriteRenderArgs {
52
+ path?: unknown;
53
+ file_path?: unknown;
54
+ content?: unknown;
55
+ }
56
+
57
+ const WRITE_PREVIEW_LINES = 6;
58
+
59
+ function countLines(text: string): number {
60
+ if (!text) return 0;
61
+ return text.split("\n").length;
62
+ }
63
+
64
+ /** Bounded newline scan: whether `text` spans more than `maxLines` lines.
65
+ * Runs on every live compose (the repaint predicate below), so it must not
66
+ * materialize the split the way `countLines` does. */
67
+ function exceedsLineCount(text: string, maxLines: number): boolean {
68
+ if (!text) return false;
69
+ let lines = 1;
70
+ for (let index = text.indexOf("\n"); index !== -1; index = text.indexOf("\n", index + 1)) {
71
+ if (++lines > maxLines) return true;
72
+ }
73
+ return false;
74
+ }
75
+
76
+ function writeContentOf(args: unknown): string {
77
+ if (args == null || typeof args !== "object" || !("content" in args)) return "";
78
+ const content = args.content;
79
+ return typeof content === "string" ? content : "";
80
+ }
81
+
82
+ function formatLineCountSuffix(lineCount: number, uiTheme: Theme): string {
83
+ if (lineCount <= 0) return "";
84
+ return uiTheme.fg("dim", ` · ${lineCount} line${lineCount === 1 ? "" : "s"}`);
85
+ }
86
+
87
+ function normalizeDisplayText(text: unknown): string {
88
+ let displayText = "";
89
+ if (typeof text === "string") {
90
+ displayText = text;
91
+ } else if (text !== undefined && text !== null) {
92
+ displayText = String(text);
93
+ }
94
+ return displayText.replace(/\r/g, "");
95
+ }
96
+
97
+ /**
98
+ * Minimum line-number gutter width for write previews. The streaming preview's
99
+ * gutter must stay byte-stable as the line count grows: a width derived purely
100
+ * from `String(totalLines).length` widens at the 10/100/1000-line crossings,
101
+ * causing the live preview to jitter. Reserving 3 digits keeps the gutter
102
+ * constant through 999 lines and keeps the streamed rows aligned with the
103
+ * final result render.
104
+ */
105
+ const WRITE_GUTTER_MIN_WIDTH = 3;
106
+
107
+ const writeStreamingPreviewStateKey = Symbol("writeStreamingPreviewState");
108
+
109
+ /**
110
+ * Per-component state for incrementally rendering a streamed write.
111
+ * The ToolExecutionComponent's persistent render options carry the state, so
112
+ * it lives exactly as long as the component and cannot leak across tool calls.
113
+ */
114
+ interface WriteStreamingPreviewState {
115
+ /** Prior full content; append-only growth is validated with an exact prefix check. */
116
+ previous: string;
117
+ /** `1 + count("\n")` over the scanned content. */
118
+ lineCount: number;
119
+ /** Raw offset immediately after the last newline consumed by `highlighter`. */
120
+ completeLength: number;
121
+ /** Highlighted, complete logical lines; the unfinished trailing line is rendered plain. */
122
+ highlightedLines: string[];
123
+ /** Stateful parser carrying syntax scopes across appended complete lines. */
124
+ highlighter: HighlightStream | null;
125
+ language: string | undefined;
126
+ uiTheme: Theme;
127
+ /** Content length for which the trailing line was flushed as final (`argsComplete`); -1 when none. */
128
+ finalFlushedLength: number;
129
+ /** Highlighted trailing line from the final flush; rendered in place of the plain tail. */
130
+ finalTrailing: string;
131
+ }
132
+
133
+ interface WriteStreamingPreviewStateCarrier {
134
+ [writeStreamingPreviewStateKey]?: WriteStreamingPreviewState;
135
+ }
136
+
137
+ function createWriteStreamingPreviewState(language: string | undefined, uiTheme: Theme): WriteStreamingPreviewState {
138
+ return {
139
+ previous: "",
140
+ lineCount: 1,
141
+ completeLength: 0,
142
+ highlightedLines: [],
143
+ highlighter: createHighlightStream(language, uiTheme),
144
+ language,
145
+ uiTheme,
146
+ finalFlushedLength: -1,
147
+ finalTrailing: "",
148
+ };
149
+ }
150
+
151
+ /**
152
+ * Advance line counting and syntax highlighting only across newly appended
153
+ * content. Complete lines are retained because Ctrl+O can expand the preview;
154
+ * the current partial line stays plain until its terminating newline arrives.
155
+ * Once args are final, the trailing line is flushed through the highlighter
156
+ * (its only push without a trailing newline) so a settled-but-queued preview
157
+ * keeps syntax colors, including for one-line files.
158
+ */
159
+ function updateStreamingPreview(
160
+ streamKey: WriteStreamingPreviewStateCarrier | undefined,
161
+ content: string,
162
+ language: string | undefined,
163
+ uiTheme: Theme,
164
+ argsComplete = false,
165
+ ): WriteStreamingPreviewState | undefined {
166
+ if (streamKey === undefined) return undefined;
167
+
168
+ let state = streamKey[writeStreamingPreviewStateKey];
169
+ if (
170
+ state === undefined ||
171
+ state.language !== language ||
172
+ state.uiTheme !== uiTheme ||
173
+ content.length < state.previous.length ||
174
+ !content.startsWith(state.previous) ||
175
+ // A final flush consumed the trailing partial line; later growth would
176
+ // re-feed it, so restart the parser instead of corrupting its state.
177
+ (state.finalFlushedLength !== -1 && content.length !== state.finalFlushedLength)
178
+ ) {
179
+ state = createWriteStreamingPreviewState(language, uiTheme);
180
+ streamKey[writeStreamingPreviewStateKey] = state;
181
+ }
182
+
183
+ let completeLength = state.completeLength;
184
+ for (let i = state.previous.length; i < content.length; i++) {
185
+ if (content.charCodeAt(i) === 10) {
186
+ state.lineCount++;
187
+ completeLength = i + 1;
188
+ }
189
+ }
190
+ if (completeLength > state.completeLength) {
191
+ const chunk = content.slice(state.completeLength, completeLength).replace(/\r/g, "");
192
+ let chunkHighlighted = chunk;
193
+ if (state.highlighter) {
194
+ try {
195
+ chunkHighlighted = state.highlighter.push(chunk);
196
+ } catch {
197
+ state.highlighter = null;
198
+ }
199
+ }
200
+ const lines = chunkHighlighted.split("\n");
201
+ lines.pop();
202
+ state.highlightedLines.push(...lines);
203
+ state.completeLength = completeLength;
204
+ }
205
+ if (argsComplete && state.finalFlushedLength !== content.length && !content.endsWith("\n")) {
206
+ const trailing = content.slice(state.completeLength).replace(/\r/g, "");
207
+ if (trailing.length > 0) {
208
+ let trailingHighlighted = trailing;
209
+ if (state.highlighter) {
210
+ try {
211
+ trailingHighlighted = state.highlighter.push(trailing);
212
+ } catch {
213
+ state.highlighter = null;
214
+ }
215
+ }
216
+ state.finalTrailing = trailingHighlighted;
217
+ state.finalFlushedLength = content.length;
218
+ }
219
+ }
220
+ state.previous = content;
221
+ return state;
222
+ }
223
+
224
+ function formatStreamingContent(
225
+ content: string,
226
+ expanded: boolean,
227
+ language: string | undefined,
228
+ uiTheme: Theme,
229
+ spinnerFrame?: number,
230
+ cache?: RenderedStringCache,
231
+ streamKey?: WriteStreamingPreviewStateCarrier,
232
+ argsComplete?: boolean,
233
+ ): string {
234
+ if (!content) return "";
235
+ const bodyText = cachedRenderedString(cache, uiTheme, expanded, language ?? "", content, () => {
236
+ const state = updateStreamingPreview(streamKey, content, language, uiTheme, argsComplete === true);
237
+ let totalLines: number;
238
+ let startIndex: number;
239
+ let visibleLines: string[];
240
+ if (state) {
241
+ totalLines = state.lineCount;
242
+ startIndex = expanded ? 0 : Math.max(0, totalLines - PREVIEW_LIMITS.EXPANDED_LINES);
243
+ const flushed = argsComplete === true && state.finalFlushedLength === content.length;
244
+ const trailingLine = flushed ? state.finalTrailing : content.slice(state.completeLength).replace(/\r/g, "");
245
+ if (totalLines === 1 && trailingLine.length === 0) return "";
246
+ visibleLines = [...state.highlightedLines.slice(startIndex), trailingLine];
247
+ } else {
248
+ const normalized = normalizeDisplayText(content);
249
+ if (normalized.length === 0) return "";
250
+ const lines = normalized.split("\n");
251
+ totalLines = lines.length;
252
+ startIndex = expanded ? 0 : Math.max(0, totalLines - PREVIEW_LIMITS.EXPANDED_LINES);
253
+ visibleLines = highlightCode(lines.slice(startIndex).join("\n"), language);
254
+ }
255
+ const hidden = startIndex;
256
+ const lineNumberWidth = Math.max(WRITE_GUTTER_MIN_WIDTH, String(totalLines).length);
257
+
258
+ let text = "\n\n";
259
+ if (hidden > 0) {
260
+ text += `${uiTheme.fg("dim", `… (${hidden} earlier line${hidden === 1 ? "" : "s"})`)}\n`;
261
+ }
262
+ for (let i = 0; i < visibleLines.length; i++) {
263
+ const lineNum = startIndex + i + 1;
264
+ const gutter = uiTheme.fg("dim", `${String(lineNum).padStart(lineNumberWidth, " ")} `);
265
+ const body = replaceTabs(visibleLines[i] ?? "");
266
+ text += `${gutter}${body}\n`;
267
+ }
268
+ return text;
269
+ });
270
+ if (bodyText.length === 0) return "";
271
+ // The animated glyph lives on this trailing line — inside the transcript's
272
+ // volatile-tail holdback — never in the header: an animating head row pins
273
+ // the native-scrollback commit boundary at the top of the block, so a long
274
+ // expanded preview could never scroll-append mid-stream.
275
+ const spinner = spinnerFrame !== undefined ? `${formatStatusIcon("running", uiTheme, spinnerFrame)} ` : "";
276
+ return `${bodyText}${spinner}${uiTheme.fg("dim", `… (streaming)`)}`;
277
+ }
278
+
279
+ function renderContentPreview(
280
+ content: string,
281
+ expanded: boolean,
282
+ language: string | undefined,
283
+ uiTheme: Theme,
284
+ cache?: RenderedStringCache,
285
+ ): string {
286
+ if (!content) return "";
287
+ return cachedRenderedString(cache, uiTheme, expanded, language ?? "", content, () => {
288
+ const rawLines = normalizeDisplayText(content).split("\n");
289
+ const totalLines = rawLines.length;
290
+ const maxLines = expanded ? totalLines : Math.min(totalLines, WRITE_PREVIEW_LINES);
291
+ const visibleLines = rawLines.slice(0, maxLines);
292
+ const highlighted = highlightCode(visibleLines.join("\n"), language);
293
+ const lineNumberWidth = Math.max(WRITE_GUTTER_MIN_WIDTH, String(totalLines).length);
294
+ const hidden = totalLines - maxLines;
295
+
296
+ let text = "\n\n";
297
+ for (let i = 0; i < highlighted.length; i++) {
298
+ const lineNum = i + 1;
299
+ const gutter = uiTheme.fg("dim", `${String(lineNum).padStart(lineNumberWidth, " ")} `);
300
+ const body = replaceTabs(highlighted[i] ?? "");
301
+ text += `${gutter}${body}\n`;
302
+ }
303
+ if (!expanded && hidden > 0) {
304
+ const hint = formatExpandHint(uiTheme, expanded, hidden > 0);
305
+ const moreLine = `${formatMoreItems(hidden, "line")}${hint ? ` ${hint}` : ""}`;
306
+ text += uiTheme.fg("dim", moreLine);
307
+ }
308
+ return text.trimEnd();
309
+ });
310
+ }
311
+
312
+ /** Render context for the write tool: resolves an `xd://`-mounted tool so its live renderer drives device dispatch previews. */
313
+ export interface WriteRenderContext {
314
+ resolveXdevMounted?: (name: string) => XdevMountedRenderer | undefined;
315
+ }
316
+
317
+ /** Render file writes and delegated tool-device calls. */
318
+ export const writeToolRenderer = {
319
+ /** Compact one-line activity: device writes read as the mounted tool (`LSP · references foo`), file writes as `Write · <path>`. */
320
+ activitySummary(args: unknown, context: ToolActivityContext): ToolActivitySummary {
321
+ const writeArgs = (args ?? {}) as WriteRenderArgs;
322
+ const rawPath =
323
+ typeof writeArgs.file_path === "string"
324
+ ? writeArgs.file_path
325
+ : typeof writeArgs.path === "string"
326
+ ? writeArgs.path
327
+ : "";
328
+ if (!rawPath) return { label: "Write" };
329
+ const xdev = parseXdUrl(rawPath);
330
+ if (xdev?.name) {
331
+ const resolveMounted = (context.renderContext as WriteRenderContext | undefined)?.resolveXdevMounted;
332
+ return xdevActivitySummary(xdev.name, writeArgs.content, resolveMounted);
333
+ }
334
+ return { label: "Write", detail: shortenPath(rawPath) };
335
+ },
336
+
337
+ renderCall(
338
+ args: WriteRenderArgs,
339
+ options: RenderResultOptions & WriteStreamingPreviewStateCarrier & { renderContext?: WriteRenderContext },
340
+ uiTheme: Theme,
341
+ ): Component | undefined {
342
+ const rawPath =
343
+ typeof args.file_path === "string" ? args.file_path : typeof args.path === "string" ? args.path : "";
344
+ // Render NOTHING until the streamed path arrives and provably is not an
345
+ // xd:// device. Device writes then render as queued until execution starts,
346
+ // after which they delegate to the mounted tool's renderer.
347
+ // A present-but-malformed path (array/object from a bad provider parse)
348
+ // is definitively not xd:// — fall through to the legacy frame.
349
+ if (args.path === undefined && args.file_path === undefined) return undefined;
350
+ if (rawPath && couldBecomeXdUrl(rawPath)) {
351
+ const xdev = parseXdUrl(rawPath);
352
+ // The path string is settled once the content field started streaming.
353
+ const pathSettled = args.content !== undefined;
354
+ if (!xdev?.name || !pathSettled) return undefined;
355
+ if (isResolutionDeviceName(xdev.name)) return renderResolutionDeviceCall(xdev.name, args.content, uiTheme);
356
+ if (xdev.name === REPORT_ISSUE_DEVICE_NAME) return renderReportIssueDeviceCall(args.content, uiTheme);
357
+ return renderXdevCall(xdev.name, args.content, options, uiTheme, options.renderContext?.resolveXdevMounted);
358
+ }
359
+ const filePath = shortenPath(rawPath);
360
+ const lang = rawPath ? (getLanguageFromPath(rawPath) ?? "text") : "text";
361
+ const langIcon = uiTheme.fg("muted", uiTheme.getLangIcon(lang));
362
+ const pathDisplay = filePath ? uiTheme.fg("accent", filePath) : uiTheme.fg("toolOutput", "…");
363
+ // No status icon on the head row: it's the head of the framed block, and
364
+ // native-scrollback commits are prefix-only — an animated glyph would pin
365
+ // the commit boundary at the top, and the pending hourglass just adds
366
+ // noise. The liveness cue rides the trailing "(streaming)" line instead.
367
+ const header = renderStatusLine(
368
+ {
369
+ title: "Write",
370
+ description: `${langIcon} ${pathDisplay}`,
371
+ },
372
+ uiTheme,
373
+ );
374
+ // Raw content, not normalizeDisplayText(args.content): the collapsed
375
+ // streaming path normalizes only its tail window, so a full-payload
376
+ // normalize on every reveal tick would re-introduce the O(n²) streaming
377
+ // cost formatStreamingContent avoids. Non-string content still falls
378
+ // back to the normalizing stringify.
379
+ const content = typeof args.content === "string" ? args.content : normalizeDisplayText(args.content);
380
+ const streamingCache = createRenderedStringCache();
381
+ return framedToolCard(uiTheme, () => {
382
+ const body = content
383
+ ? formatStreamingContent(
384
+ content,
385
+ Boolean(options?.expanded),
386
+ lang,
387
+ uiTheme,
388
+ options?.spinnerFrame,
389
+ streamingCache,
390
+ // `options` is the ToolExecutionComponent's persistent
391
+ // render-state object — a stable identity across reveal ticks
392
+ // that keys the incremental preview state. `argsComplete`
393
+ // flushes the trailing line through the highlighter once.
394
+ options,
395
+ options?.argsComplete,
396
+ )
397
+ : "";
398
+ const bodyLines = body ? body.split("\n") : [];
399
+ while (bodyLines.length > 0 && bodyLines[0].trim() === "") bodyLines.shift();
400
+ return {
401
+ header,
402
+ sections: bodyLines.length > 0 ? [{ content: bodyLines }] : [],
403
+ phase: "pending",
404
+ borderColor: "borderMuted",
405
+ };
406
+ });
407
+ },
408
+
409
+ renderResult(
410
+ result: { content: Array<{ type: string; text?: string }>; details?: WriteToolDetails; isError?: boolean },
411
+ options: RenderResultOptions & { renderContext?: WriteRenderContext },
412
+ uiTheme: Theme,
413
+ args?: WriteRenderArgs,
414
+ ): Component {
415
+ // xd:// dispatch results render as the mounted tool's own result.
416
+ const xdev = result.details?.xdev;
417
+ if (xdev) {
418
+ const delegated = renderXdevResult(xdev, result, options, uiTheme, options.renderContext?.resolveXdevMounted);
419
+ if (delegated) return delegated;
420
+ const text = result.content?.find(c => c.type === "text")?.text ?? "";
421
+ return new Text(uiTheme.fg("toolOutput", replaceTabs(text)), 0, 0);
422
+ }
423
+ const rawPath =
424
+ typeof args?.file_path === "string" ? args.file_path : typeof args?.path === "string" ? args.path : "";
425
+ const filePath = shortenPath(rawPath);
426
+ const fileContent = normalizeDisplayText(args?.content);
427
+ const lang = rawPath ? getLanguageFromPath(rawPath) : undefined;
428
+ const langIcon = uiTheme.fg("muted", uiTheme.getLangIcon(lang));
429
+ // The header shows the cwd-relative path but links to the absolute path the
430
+ // write resolved to (args.path may be relative, which would yield a broken
431
+ // `file://` URI). Falls back to plain text when the result lacks a path.
432
+ const linkTarget = result.details?.resolvedPath;
433
+ const styledPath = filePath ? uiTheme.fg("accent", filePath) : uiTheme.fg("toolOutput", "…");
434
+ const pathDisplay = filePath && linkTarget ? fileHyperlink(linkTarget, styledPath) : styledPath;
435
+
436
+ if (result.isError) {
437
+ const errorText = result.content?.find(c => c.type === "text")?.text ?? "";
438
+ const header = renderStatusLine(
439
+ { icon: "error", title: "Write", description: `${langIcon} ${pathDisplay}` },
440
+ uiTheme,
441
+ );
442
+ return framedToolCard(uiTheme, () => ({
443
+ header,
444
+ sections: [{ content: formatErrorDetail(errorText, uiTheme).split("\n") }],
445
+ phase: "error",
446
+ borderColor: "error",
447
+ }));
448
+ }
449
+
450
+ const isPartial = options.isPartial === true;
451
+ const progressText = result.content?.find(c => c.type === "text")?.text ?? "";
452
+ const lineCount = countLines(fileContent);
453
+ const lineSuffix = formatLineCountSuffix(lineCount, uiTheme);
454
+ const execSuffix =
455
+ !isPartial && result.details?.madeExecutable
456
+ ? `${uiTheme.fg("dim", " · ")}${uiTheme.fg("success", "made executable!")}`
457
+ : "";
458
+ const header = renderStatusLine(
459
+ {
460
+ icon: isPartial ? "running" : undefined,
461
+ iconOverride: isPartial ? undefined : uiTheme.styledSymbol("tool.write", "accent"),
462
+ spinnerFrame: options.spinnerFrame,
463
+ title: "Write",
464
+ description: `${langIcon} ${pathDisplay}${lineSuffix}${execSuffix}`,
465
+ },
466
+ uiTheme,
467
+ );
468
+ const diagnostics = result.details?.diagnostics;
469
+
470
+ const previewCache = createRenderedStringCache();
471
+ return framedToolCard(uiTheme, () => {
472
+ const { expanded } = options;
473
+ let body = renderContentPreview(fileContent, expanded, lang, uiTheme, previewCache);
474
+ if (isPartial && progressText) {
475
+ const safeProgressText = truncateToWidth(
476
+ replaceTabs(progressText),
477
+ TRUNCATE_LENGTHS.LINE,
478
+ Ellipsis.Unicode,
479
+ );
480
+ body = `${uiTheme.fg("muted", safeProgressText)}${body ? `\n${body}` : ""}`;
481
+ }
482
+ if (!isPartial && diagnostics) {
483
+ const diagText = formatDiagnostics(diagnostics, expanded, uiTheme, fp =>
484
+ uiTheme.getLangIcon(getLanguageFromPath(fp)),
485
+ );
486
+ if (diagText.trim()) {
487
+ const diagLines = diagText.split("\n");
488
+ const firstNonEmpty = diagLines.findIndex(line => line.trim());
489
+ if (firstNonEmpty >= 0) body += `\n${diagLines.slice(firstNonEmpty).join("\n")}`;
490
+ }
491
+ }
492
+ const bodyLines = body.split("\n");
493
+ while (bodyLines.length > 0 && bodyLines[0].trim() === "") bodyLines.shift();
494
+ return {
495
+ header,
496
+ sections: bodyLines.length > 0 ? [{ content: bodyLines }] : [],
497
+ phase: isPartial ? "partial" : "success",
498
+ borderColor: "borderMuted",
499
+ };
500
+ });
501
+ },
502
+ mergeCallAndResult: true,
503
+ // The collapsed pending preview follows the streaming edge with a tail
504
+ // window once the content outgrows it (`… (N earlier lines)` + last rows);
505
+ // the first partial result re-anchors the frame to the top of the file, so
506
+ // tail rows already committed to viewport/native scrollback would survive
507
+ // as stale content above the new frame without a full replay. Expanded and
508
+ // short previews stay top-anchored and skip the (scrollback-wiping) reset.
509
+ forceFirstResultViewportRepaint: (args: unknown, options: RenderResultOptions) =>
510
+ !options.expanded && exceedsLineCount(writeContentOf(args), PREVIEW_LIMITS.EXPANDED_LINES),
511
+ } satisfies ToolRenderer<WriteRenderArgs, WriteToolDetails>;
@@ -0,0 +1,28 @@
1
+ /** Canonical prefix for virtual tool-device URLs. */
2
+ export const XD_URL_PREFIX = "xd://";
3
+
4
+ /** Returns the canonical tool name from a bare or `xd://`-prefixed spelling. */
5
+ export function stripXdUrlPrefix(name: string): string {
6
+ return name.toLowerCase().startsWith(XD_URL_PREFIX) ? name.slice(XD_URL_PREFIX.length) : name;
7
+ }
8
+
9
+ /**
10
+ * Parse an `xd://` URL into its device target.
11
+ * Returns `null` for other or malformed URLs and `name: null` for the root.
12
+ */
13
+ export function parseXdUrl(input: string): { name: string | null } | null {
14
+ const trimmed = input.trim();
15
+ if (!trimmed.toLowerCase().startsWith(XD_URL_PREFIX)) return null;
16
+ const name = trimmed.slice(XD_URL_PREFIX.length);
17
+ if (name.length === 0) return { name: null };
18
+ if (/[/?#]/.test(name)) return null;
19
+ return { name };
20
+ }
21
+
22
+ /** Whether a streaming path prefix could still become an `xd://` URL. */
23
+ export function couldBecomeXdUrl(partialPath: string): boolean {
24
+ if (partialPath.length <= XD_URL_PREFIX.length) {
25
+ return XD_URL_PREFIX.startsWith(partialPath.toLowerCase());
26
+ }
27
+ return partialPath.toLowerCase().startsWith(XD_URL_PREFIX);
28
+ }