@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,47 @@
1
+ import * as path from "node:path";
2
+ import type { ImageContent } from "@oh-my-pi/pi-ai";
3
+
4
+ /** Container extensions treated as video. Mirrors the video subset of the local-protocol binary list. */
5
+ const VIDEO_EXTENSION_LOOKUP: Record<string, true> = {
6
+ ".mp4": true,
7
+ ".mov": true,
8
+ ".mkv": true,
9
+ ".webm": true,
10
+ ".m4v": true,
11
+ ".avi": true,
12
+ ".wmv": true,
13
+ };
14
+
15
+ /** True when the path names a video container we handle through ffmpeg. */
16
+ export function isVideoPath(filePath: string): boolean {
17
+ return VIDEO_EXTENSION_LOOKUP[path.extname(filePath).toLowerCase()] === true;
18
+ }
19
+
20
+ /**
21
+ * Original local source path stored on a generated contact-sheet image. Symbol
22
+ * metadata stays out of serialized/model-bound image data while traveling with
23
+ * the draft object until AgentSession creates its hidden companion message.
24
+ */
25
+ const kVideoPreviewSource = Symbol("video.previewSource");
26
+
27
+ /** A contact-sheet image tagged with the original local video path. */
28
+ export type VideoPreviewImage = ImageContent & {
29
+ readonly [kVideoPreviewSource]: string;
30
+ };
31
+
32
+ /** Create a model-ready contact-sheet image tagged with its original video path. */
33
+ export function createVideoPreviewImage(preview: ImageContent, sourcePath: string): VideoPreviewImage {
34
+ return {
35
+ type: "image",
36
+ data: preview.data,
37
+ mimeType: preview.mimeType,
38
+ [kVideoPreviewSource]: sourcePath,
39
+ };
40
+ }
41
+
42
+ /** Return the original video path associated with a generated contact-sheet image. */
43
+ export function videoPreviewSource(preview: ImageContent): string | undefined {
44
+ if (!(kVideoPreviewSource in preview)) return undefined;
45
+ const sourcePath = preview[kVideoPreviewSource];
46
+ return typeof sourcePath === "string" ? sourcePath : undefined;
47
+ }
@@ -0,0 +1,605 @@
1
+ import { TERMINAL } from "../terminal-capabilities";
2
+ import type { Component } from "../tui";
3
+ import { padding, replaceTabs, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "../utils";
4
+ import { APP_NAME } from "@oh-my-pi/pi-utils/dirs";
5
+ import { theme } from "../theme/theme";
6
+ import tipsText from "./tips.txt" with { type: "text" };
7
+
8
+ /** Tips embedded at build time, one per line; blanks dropped. */
9
+ const TIPS: readonly string[] = tipsText
10
+ .split("\n")
11
+ .map(line => line.trim())
12
+ .filter(line => line.length > 0);
13
+
14
+ /**
15
+ * Fixed number of session rows in the welcome box so its height stays stable
16
+ * across recent-session updates.
17
+ */
18
+ export const WELCOME_SESSION_SLOTS = 4;
19
+
20
+ /**
21
+ * Fixed number of LSP-server rows, for the same reason. Overflow is sliced so
22
+ * the box height is constant regardless of how many servers a project has.
23
+ */
24
+ export const WELCOME_LSP_SLOTS = 4;
25
+
26
+ /** Trailing marker that flags a tip as a "what's new" callout. Stripped before
27
+ * wrapping (with any preceding whitespace) and replaced by {@link NEW_TAG_TEXT}
28
+ * painted as a shimmering rainbow. Non-global so `.test` stays stateless. */
29
+ const NEW_TIP_MARKER = /\s*\[NEW\]\s*$/;
30
+
31
+ /** Visible text rendered in place of {@link NEW_TIP_MARKER}. */
32
+ const NEW_TAG_TEXT = "NEW!";
33
+
34
+ /** Milliseconds for one full hue rotation of the rainbow "NEW!" tag. */
35
+ const NEW_GLOW_PERIOD_MS = 1500;
36
+
37
+ /** Selection weight for "[NEW]" tips; ordinary tips weigh 1, so a freshly added
38
+ * affordance surfaces this many times as often. */
39
+ const NEW_TIP_WEIGHT = 4;
40
+
41
+ /** Pick a tip from `tips`, biased toward "[NEW]" tips by {@link NEW_TIP_WEIGHT};
42
+ * `r` is a uniform sample in [0, 1). Returns "" when `tips` is empty.
43
+ * Exported for tests. */
44
+ export function pickWeightedTip(tips: readonly string[], r: number): string {
45
+ if (tips.length === 0) return "";
46
+ const weights = tips.map(tip => (NEW_TIP_MARKER.test(tip) ? NEW_TIP_WEIGHT : 1));
47
+ const total = weights.reduce((sum, weight) => sum + weight, 0);
48
+ let acc = r * total;
49
+ for (let i = 0; i < tips.length; i++) {
50
+ acc -= weights[i] ?? 1;
51
+ if (acc < 0) return tips[i] ?? "";
52
+ }
53
+ return tips[tips.length - 1] ?? "";
54
+ }
55
+
56
+ type ColorEncoding = "ansi-16m" | "ansi-256";
57
+
58
+ /** Paint each glyph of {@link NEW_TAG_TEXT} on a moving HSL rainbow. `phase`
59
+ * rotates the hue offset cyclically; successive renders with increasing phase
60
+ * shimmer, while a fixed phase yields a still rainbow. */
61
+ function renderNewTag(phase: number, encoding: ColorEncoding): string {
62
+ const bold = "\x1b[1m";
63
+ const reset = "\x1b[0m";
64
+ const wrapped = ((phase % 1) + 1) % 1;
65
+ const chars = [...NEW_TAG_TEXT];
66
+ let out = bold;
67
+ let prev = "";
68
+ for (let i = 0; i < chars.length; i++) {
69
+ const hue = Math.round(((i / chars.length + wrapped) % 1) * 360);
70
+ const color = Bun.color(`hsl(${hue}, 95%, 60%)`, encoding) ?? "";
71
+ if (color !== prev) {
72
+ out += color;
73
+ prev = color;
74
+ }
75
+ out += chars[i];
76
+ }
77
+ return out + reset;
78
+ }
79
+ export function renderWelcomeTip(tip: string, boxWidth: number, phase = 0): string[] {
80
+ const label = "Tip: ";
81
+ const labelWidth = visibleWidth(label);
82
+ const bodyBudget = boxWidth - 1 - labelWidth; // 1 = leading indent
83
+ if (bodyBudget < 8) return [];
84
+
85
+ const isNew = NEW_TIP_MARKER.test(tip);
86
+ const body = isNew ? tip.replace(NEW_TIP_MARKER, "") : tip;
87
+
88
+ const wrappedBody = wrapTextWithAnsi(replaceTabs(body), bodyBudget);
89
+ if (wrappedBody.length === 0) return [];
90
+
91
+ // Pull both colors from the active theme so the line stays readable on light
92
+ // themes; the previous hardcoded `#b48cff` / `#9ccfff` pastels (plus a manual
93
+ // `\x1b[2m` dim on the body) dropped to ~1.5:1 contrast on a white background.
94
+ const continuationIndent = padding(labelWidth);
95
+ const styledLabel = theme.fg("customMessageLabel", label);
96
+
97
+ const lines = wrappedBody.map((line, index) => {
98
+ const styledBody = theme.fg("muted", line);
99
+ const content = index === 0 ? `${styledLabel}${styledBody}` : `${continuationIndent}${styledBody}`;
100
+ return ` ${theme.italic(content)}`;
101
+ });
102
+
103
+ if (isNew) {
104
+ // Append the rainbow tag to the final body line when it fits within the
105
+ // box; otherwise drop it onto its own indented continuation line so the
106
+ // styled glyphs never overflow or reflow the wrapped body.
107
+ const encoding: ColorEncoding = TERMINAL.trueColor ? "ansi-16m" : "ansi-256";
108
+ const tag = renderNewTag(phase, encoding);
109
+ const tagWidth = 1 + visibleWidth(NEW_TAG_TEXT); // 1 = space separator
110
+ const lastLine = lines[lines.length - 1];
111
+ if (lastLine !== undefined && visibleWidth(lastLine) + tagWidth <= boxWidth) {
112
+ lines[lines.length - 1] = `${lastLine} ${tag}`;
113
+ } else {
114
+ lines.push(` ${continuationIndent}${tag}`);
115
+ }
116
+ }
117
+
118
+ return lines;
119
+ }
120
+
121
+ export interface RecentSession {
122
+ name: string;
123
+ timeAgo: string;
124
+ }
125
+
126
+ export interface LspServerInfo {
127
+ name: string;
128
+ status: "ready" | "error" | "connecting" | "available";
129
+ fileTypes: string[];
130
+ }
131
+
132
+ /**
133
+ * Premium welcome screen with block-based OMP logo and two-column layout.
134
+ */
135
+ export class WelcomeComponent implements Component {
136
+ #animStart: number | null = null;
137
+ #animTimer: Timer | null = null;
138
+ #requestRender: (() => void) | null = null;
139
+ // Tip randomness is latched once so the tip is stable across renders, but
140
+ // the nerdfont-nag gate re-reads the live preset: the startup prepaint can
141
+ // run under the default "unicode" preset before settings resolve the real
142
+ // one, and a memoized nag would survive the switch to "nerd".
143
+ #nagRoll: number | undefined;
144
+ #tipRoll: number | undefined;
145
+ // Render cache: the welcome box is the first transcript-area component, so
146
+ // returning a stable array reference keeps the whole frame prefix stable.
147
+ // Bypassed while the intro animation runs (every frame differs).
148
+ #cachedWidth = -1;
149
+ #cachedLines: string[] | undefined;
150
+
151
+ constructor(
152
+ private version: string,
153
+ private modelName: string,
154
+ private providerName: string,
155
+ private recentSessions: RecentSession[] = [],
156
+ private lspServers: LspServerInfo[] = [],
157
+ ) {}
158
+ get tip(): string | undefined {
159
+ this.#nagRoll ??= Math.random();
160
+ this.#tipRoll ??= Math.random();
161
+ if (theme.getSymbolPreset() === "unicode" && this.#nagRoll < 0.1) {
162
+ return "Please use nerdfont 😭.";
163
+ }
164
+ return pickWeightedTip(TIPS, this.#tipRoll) || undefined;
165
+ }
166
+
167
+ invalidate(): void {
168
+ this.#cachedWidth = -1;
169
+ this.#cachedLines = undefined;
170
+ }
171
+ /** The intro keeps the welcome block mutable; settling lets it retire to history. */
172
+ isTranscriptBlockFinalized(): boolean {
173
+ return this.#animTimer == null;
174
+ }
175
+
176
+ /**
177
+ * Play a one-shot intro that sweeps the gradient through every phase
178
+ * before settling on the resting frame. Safe to call multiple times —
179
+ * subsequent calls reset and replay.
180
+ */
181
+ playIntro(requestRender: () => void): void {
182
+ this.#stopAnimation();
183
+ this.#requestRender = requestRender;
184
+ this.#animStart = performance.now();
185
+ this.#requestRender();
186
+ this.#animTimer = setInterval(() => {
187
+ const elapsed = performance.now() - (this.#animStart ?? 0);
188
+ if (elapsed >= INTRO_MS) {
189
+ this.#stopAnimation();
190
+ }
191
+ this.#requestRender?.();
192
+ }, INTRO_TICK_MS);
193
+ }
194
+
195
+ #stopAnimation(): void {
196
+ if (this.#animTimer != null) {
197
+ clearInterval(this.#animTimer);
198
+ this.#animTimer = null;
199
+ }
200
+ this.#animStart = null;
201
+ this.#requestRender = null;
202
+ // The settled (resting) frame differs from the last intro frame.
203
+ this.invalidate();
204
+ }
205
+
206
+ /**
207
+ * Redirect a running intro's render callback to a new target when a host
208
+ * remounts this component mid-animation.
209
+ * Returns true while the intro is still animating; false = no-op (settled).
210
+ */
211
+ retargetIntro(requestRender: () => void): boolean {
212
+ if (this.#animTimer == null) return false;
213
+ this.#requestRender = requestRender;
214
+ return true;
215
+ }
216
+
217
+ /** Stop the intro immediately and settle on the resting frame. Safe when idle. */
218
+ stopIntro(): void {
219
+ this.#stopAnimation();
220
+ }
221
+
222
+ /** Update the version embedded in the welcome border title. */
223
+ setVersion(version: string): void {
224
+ this.version = version;
225
+ this.invalidate();
226
+ }
227
+
228
+ setModel(modelName: string, providerName: string): void {
229
+ this.modelName = modelName;
230
+ this.providerName = providerName;
231
+ this.invalidate();
232
+ }
233
+
234
+ setRecentSessions(sessions: RecentSession[]): void {
235
+ this.recentSessions = sessions;
236
+ this.invalidate();
237
+ }
238
+
239
+ setLspServers(servers: LspServerInfo[]): void {
240
+ this.lspServers = servers;
241
+ this.invalidate();
242
+ }
243
+
244
+ render(termWidth: number): readonly string[] {
245
+ const animating = this.#animStart != null;
246
+ if (!animating && this.#cachedLines && this.#cachedWidth === termWidth) {
247
+ return this.#cachedLines;
248
+ }
249
+ const lines = this.#renderLines(termWidth);
250
+ if (animating) {
251
+ this.#cachedLines = undefined;
252
+ this.#cachedWidth = -1;
253
+ } else {
254
+ this.#cachedLines = lines;
255
+ this.#cachedWidth = termWidth;
256
+ }
257
+ return lines;
258
+ }
259
+
260
+ #renderLines(termWidth: number): string[] {
261
+ // Box dimensions - responsive with max width and small-terminal support
262
+ const maxWidth = 100;
263
+ const boxWidth = Math.min(maxWidth, Math.max(0, termWidth - 2));
264
+ if (boxWidth < 4) {
265
+ return [];
266
+ }
267
+ const dualContentWidth = boxWidth - 3; // 3 = │ + │ + │
268
+ const preferredLeftCol = 26;
269
+ const minLeftCol = 12; // logo width
270
+ const minRightCol = 20;
271
+ // Dynamic model/provider labels are truncated inside the fixed column.
272
+ // Letting them influence the responsive breakpoint changes the box height
273
+ // when authoritative session data replaces the empty prepaint labels.
274
+ const leftMinContentWidth = Math.max(minLeftCol, visibleWidth("Welcome back!"));
275
+ const desiredLeftCol = Math.max(
276
+ Math.min(preferredLeftCol, Math.max(minLeftCol, Math.floor(dualContentWidth * 0.35))),
277
+ leftMinContentWidth,
278
+ );
279
+ const dualLeftCol =
280
+ dualContentWidth >= minRightCol + 1
281
+ ? Math.min(desiredLeftCol, dualContentWidth - minRightCol)
282
+ : Math.max(1, dualContentWidth - 1);
283
+ const dualRightCol = Math.max(1, dualContentWidth - dualLeftCol);
284
+ const showRightColumn = dualLeftCol >= leftMinContentWidth && dualRightCol >= minRightCol;
285
+ const leftCol = showRightColumn ? dualLeftCol : boxWidth - 2;
286
+ const rightCol = showRightColumn ? dualRightCol : 0;
287
+
288
+ // Logo: pick a frame from the intro animation if active, else the resting frame.
289
+ const logoColored = this.#currentLogoFrame();
290
+
291
+ // Left column - centered content
292
+ const leftLines = [
293
+ "",
294
+ this.#centerText(theme.bold("Welcome back!"), leftCol),
295
+ "",
296
+ ...logoColored.map(l => this.#centerText(l, leftCol)),
297
+ "",
298
+ this.#centerText(theme.fg("muted", this.modelName), leftCol),
299
+ this.#centerText(theme.fg("borderMuted", this.providerName), leftCol),
300
+ ];
301
+
302
+ // Right column separator
303
+ const separatorWidth = Math.max(0, rightCol - 2); // padding on each side
304
+ const separator = ` ${theme.fg("dim", theme.boxRound.horizontal.repeat(separatorWidth))}`;
305
+
306
+ // Recent sessions content
307
+ const sessionLines: string[] = [];
308
+ if (this.recentSessions.length === 0) {
309
+ sessionLines.push(` ${theme.fg("dim", "No recent sessions")}`);
310
+ } else {
311
+ // Reserve width for the bullet prefix (" • ") and the trailing " (timeAgo)"
312
+ // so the relative time is never the part that gets truncated. The name
313
+ // absorbs whatever space is left.
314
+ const bulletPrefix = ` ${theme.md.bullet} `;
315
+ const prefixWidth = visibleWidth(bulletPrefix);
316
+ for (const session of this.recentSessions.slice(0, WELCOME_SESSION_SLOTS)) {
317
+ const timeSuffixRaw = ` (${session.timeAgo})`;
318
+ const timeWidth = visibleWidth(timeSuffixRaw);
319
+ const nameBudget = Math.max(1, rightCol - prefixWidth - timeWidth);
320
+ const nameVis = visibleWidth(session.name);
321
+ const name = nameVis > nameBudget ? truncateToWidth(session.name, nameBudget) : session.name;
322
+ sessionLines.push(
323
+ `${theme.fg("dim", bulletPrefix)}${theme.fg("muted", name)}${theme.fg("dim", timeSuffixRaw)}`,
324
+ );
325
+ }
326
+ }
327
+ // Pad to the fixed slot count so the box height doesn't depend on session count.
328
+ while (sessionLines.length < WELCOME_SESSION_SLOTS) {
329
+ sessionLines.push("");
330
+ }
331
+
332
+ // LSP servers content
333
+ const lspLines: string[] = [];
334
+ if (this.lspServers.length === 0) {
335
+ lspLines.push(` ${theme.fg("dim", "No LSP servers")}`);
336
+ } else {
337
+ for (const server of this.lspServers.slice(0, WELCOME_LSP_SLOTS)) {
338
+ const icon =
339
+ server.status === "ready"
340
+ ? theme.styledSymbol("status.enabled", "success")
341
+ : server.status === "available"
342
+ ? theme.styledSymbol("status.enabled", "dim")
343
+ : server.status === "connecting"
344
+ ? theme.styledSymbol("status.pending", "muted")
345
+ : theme.styledSymbol("status.error", "error");
346
+ const exts = server.fileTypes.slice(0, 3).join(" ");
347
+ lspLines.push(` ${icon} ${theme.fg("muted", server.name)} ${theme.fg("dim", exts)}`);
348
+ }
349
+ }
350
+ // Pad to the fixed slot count so the box height doesn't depend on server count.
351
+ while (lspLines.length < WELCOME_LSP_SLOTS) {
352
+ lspLines.push("");
353
+ }
354
+
355
+ // Right column
356
+ const rightLines = [
357
+ ` ${theme.bold(theme.fg("accent", "Tips"))}`,
358
+ ` ${theme.fg("dim", "#")}${theme.fg("muted", " for prompt actions")}`,
359
+ ` ${theme.fg("dim", "/")}${theme.fg("muted", " for commands")}`,
360
+ ` ${theme.fg("dim", "!")}${theme.fg("muted", " to run bash")}`,
361
+ ` ${theme.fg("dim", "$")}${theme.fg("muted", " to run python")}`,
362
+ separator,
363
+ ` ${theme.bold(theme.fg("accent", "LSP Servers"))}`,
364
+ ...lspLines,
365
+ separator,
366
+ ` ${theme.bold(theme.fg("accent", "Recent sessions"))}`,
367
+ ...sessionLines,
368
+ "",
369
+ ];
370
+
371
+ // Border characters (dim)
372
+ const hChar = theme.boxRound.horizontal;
373
+ const h = theme.fg("dim", hChar);
374
+ const v = theme.fg("dim", theme.boxRound.vertical);
375
+ const tl = theme.fg("dim", theme.boxRound.topLeft);
376
+ const tr = theme.fg("dim", theme.boxRound.topRight);
377
+ const bl = theme.fg("dim", theme.boxRound.bottomLeft);
378
+ const br = theme.fg("dim", theme.boxRound.bottomRight);
379
+
380
+ const lines: string[] = [];
381
+
382
+ // Top border with embedded title
383
+ const title = ` ${APP_NAME} v${this.version} `;
384
+ const titlePrefixRaw = hChar.repeat(3);
385
+ const titleStyled = theme.fg("dim", titlePrefixRaw) + theme.fg("muted", title);
386
+ const titleVisLen = visibleWidth(titlePrefixRaw) + visibleWidth(title);
387
+ const titleSpace = boxWidth - 2;
388
+ if (titleVisLen >= titleSpace) {
389
+ lines.push(tl + truncateToWidth(titleStyled, titleSpace) + tr);
390
+ } else {
391
+ const afterTitle = titleSpace - titleVisLen;
392
+ lines.push(tl + titleStyled + theme.fg("dim", hChar.repeat(afterTitle)) + tr);
393
+ }
394
+
395
+ // Content rows
396
+ const maxRows = showRightColumn ? Math.max(leftLines.length, rightLines.length) : leftLines.length;
397
+ for (let i = 0; i < maxRows; i++) {
398
+ const left = this.#fitToWidth(leftLines[i] ?? "", leftCol);
399
+ if (showRightColumn) {
400
+ const right = this.#fitToWidth(rightLines[i] ?? "", rightCol);
401
+ lines.push(v + left + v + right + v);
402
+ } else {
403
+ lines.push(v + left + v);
404
+ }
405
+ }
406
+ // Bottom border
407
+ if (showRightColumn) {
408
+ lines.push(bl + h.repeat(leftCol) + theme.fg("dim", theme.boxRound.teeUp) + h.repeat(rightCol) + br);
409
+ } else {
410
+ lines.push(bl + h.repeat(leftCol) + br);
411
+ }
412
+
413
+ // Randomly picked tip, rendered directly beneath the box.
414
+ lines.push(...this.#renderTip(boxWidth));
415
+
416
+ return lines;
417
+ }
418
+
419
+ /**
420
+ * Render the per-instance tip line: the `customMessageLabel`-themed `Tip:`
421
+ * label followed by a `muted` body, the whole line italicized. Returns `[]`
422
+ * when no tip is available or the box is too narrow to be useful.
423
+ */
424
+ #renderTip(boxWidth: number): string[] {
425
+ const tip = this.tip;
426
+ if (!tip) return [];
427
+ // A trailing "[NEW]" marker paints an animated rainbow "NEW!" tag. Derive
428
+ // its hue phase from wall-clock time so it shimmers across the welcome
429
+ // intro's re-render frames, then settles into a still rainbow once the box
430
+ // caches its resting frame. Non-"[NEW]" tips ignore the phase entirely.
431
+ const phase = NEW_TIP_MARKER.test(tip) ? performance.now() / NEW_GLOW_PERIOD_MS : 0;
432
+ return renderWelcomeTip(tip, boxWidth, phase);
433
+ }
434
+
435
+ /** Center text within a given width */
436
+ #centerText(text: string, width: number): string {
437
+ const visLen = visibleWidth(text);
438
+ if (visLen >= width) {
439
+ return truncateToWidth(text, width);
440
+ }
441
+ const leftPad = Math.floor((width - visLen) / 2);
442
+ const rightPad = width - visLen - leftPad;
443
+ return padding(leftPad) + text + padding(rightPad);
444
+ }
445
+
446
+ /** Fit string to exact width with ANSI-aware truncation/padding */
447
+ #fitToWidth(str: string, width: number): string {
448
+ const visLen = visibleWidth(str);
449
+ if (visLen > width) {
450
+ const ellipsis = "…";
451
+ const ellipsisWidth = visibleWidth(ellipsis);
452
+ const maxWidth = Math.max(0, width - ellipsisWidth);
453
+ let truncated = "";
454
+ let currentWidth = 0;
455
+ let inEscape = false;
456
+ for (const char of str) {
457
+ if (char === "\x1b") inEscape = true;
458
+ if (inEscape) {
459
+ truncated += char;
460
+ if (char === "m") inEscape = false;
461
+ } else if (currentWidth < maxWidth) {
462
+ truncated += char;
463
+ currentWidth++;
464
+ }
465
+ }
466
+ return `${truncated}${ellipsis}`;
467
+ }
468
+ return str + padding(width - visLen);
469
+ }
470
+
471
+ /** Pick the logo frame for the current intro phase, or the resting frame. */
472
+ #currentLogoFrame(): readonly string[] {
473
+ if (this.#animStart == null) return REST_FRAME;
474
+ const elapsed = performance.now() - this.#animStart;
475
+ if (elapsed >= INTRO_MS) return REST_FRAME;
476
+ return introLogoFrame(elapsed / INTRO_MS);
477
+ }
478
+ }
479
+
480
+ /** Block-grid brand mark shared by the welcome and setup surfaces. */
481
+ export const PI_LOGO = ["████████████", " ██ ██ ", " ██ ██ ", " ▒▒ ██ ", " ██ "];
482
+
483
+ /** Multi-stop palette for the diagonal gradient. */
484
+ const GRADIENT_STOPS: ReadonlyArray<readonly [number, number, number]> = [
485
+ [248, 79, 204], // oklch(0.7 0.24 340)
486
+ [147, 98, 244], // oklch(0.62 0.21 295)
487
+ [0, 219, 228], // oklch(0.81 0.14 200)
488
+ ];
489
+
490
+ /** 256-color ramp fallback when truecolor isn't available. */
491
+ const GRADIENT_RAMP_256 = [206, 170, 134, 99, 69, 74, 44];
492
+
493
+ /** Half-width of the shine highlight band, expressed in gradient-t units. */
494
+ const SHINE_HALF_WIDTH = 0.18;
495
+
496
+ export interface ShineConfig {
497
+ /** Overall opacity of the shine overlay, in [0, 1]. */
498
+ strength: number;
499
+ /** Center of the shine band along the diagonal, in [0, 1]. */
500
+ pos: number;
501
+ }
502
+
503
+ /**
504
+ * Resolve the gradient SGR foreground escape for a normalized position `t`
505
+ * (0..1) along the diagonal, compositing the optional sliding shine highlight.
506
+ * Shared by {@link gradientLogo} and the setup splash so both stay
507
+ * color-identical (truecolor when available, 256-color ramp otherwise).
508
+ */
509
+ export function gradientEscape(t: number, shine?: ShineConfig): string {
510
+ const shineStrength = shine && shine.strength > 0 ? shine.strength : 0;
511
+ const shinePos = shine ? shine.pos : 0;
512
+ if (TERMINAL.trueColor) {
513
+ // 5-stop palette widens the visible color range and avoids the
514
+ // deep-blue valley a naive HSL lerp falls into.
515
+ const stops = GRADIENT_STOPS;
516
+ const seg = t * (stops.length - 1);
517
+ const i = Math.min(stops.length - 2, Math.floor(seg));
518
+ const f = seg - i;
519
+ const a = stops[i];
520
+ const b = stops[i + 1];
521
+ let r = a[0] + (b[0] - a[0]) * f;
522
+ let g = a[1] + (b[1] - a[1]) * f;
523
+ let bl = a[2] + (b[2] - a[2]) * f;
524
+ if (shineStrength > 0) {
525
+ const dist = Math.abs(t - shinePos);
526
+ const intensity = Math.max(0, 1 - dist / SHINE_HALF_WIDTH) * shineStrength;
527
+ if (intensity > 0) {
528
+ r += (255 - r) * intensity;
529
+ g += (255 - g) * intensity;
530
+ bl += (255 - bl) * intensity;
531
+ }
532
+ }
533
+ return `\x1b[38;2;${Math.round(r)};${Math.round(g)};${Math.round(bl)}m`;
534
+ }
535
+ const ramp = GRADIENT_RAMP_256;
536
+ let idx = Math.min(ramp.length - 1, Math.max(0, Math.floor(t * (ramp.length - 1) + 0.5)));
537
+ if (shineStrength > 0) {
538
+ const dist = Math.abs(t - shinePos);
539
+ const intensity = Math.max(0, 1 - dist / SHINE_HALF_WIDTH) * shineStrength;
540
+ // Promote to the brightest ramp slot when the shine band peaks here.
541
+ if (intensity > 0.5) idx = ramp.length - 1;
542
+ }
543
+ return `\x1b[38;5;${ramp[idx]}m`;
544
+ }
545
+
546
+ /**
547
+ * Apply a multi-stop diagonal gradient (top-left → bottom-right) plus an
548
+ * optional sliding shine band across multi-line art. `phase` (0..1) shifts the
549
+ * gradient along the diagonal, wrapping at 1. When `shine` is provided, a soft
550
+ * white highlight is composited on top, centered at `shine.pos`.
551
+ */
552
+ export function gradientLogo(lines: readonly string[], phase = 0, shine?: ShineConfig): string[] {
553
+ const reset = "\x1b[0m";
554
+ const rows = lines.length;
555
+ const cols = Math.max(...lines.map(l => l.length));
556
+ const xSpan = Math.max(1, cols - 1);
557
+ const ySpan = Math.max(1, rows - 1);
558
+ const normalizedPhase = ((phase % 1) + 1) % 1;
559
+ return lines.map((line, y) => {
560
+ let result = "";
561
+ for (let x = 0; x < line.length; x++) {
562
+ const char = line[x];
563
+ if (char === " ") {
564
+ result += char;
565
+ continue;
566
+ }
567
+ // SVG's (0,0) → (1,1) gradient projects both normalized axes
568
+ // equally: top-right and bottom-left land on the purple midpoint.
569
+ const base = (x / xSpan + y / ySpan) / 2;
570
+ const t = normalizedPhase === 0 ? base : (base + normalizedPhase) % 1;
571
+ result += gradientEscape(t, shine) + char + reset;
572
+ }
573
+ return result;
574
+ });
575
+ }
576
+
577
+ /** Total length of the intro animation. */
578
+ const INTRO_MS = 3000;
579
+ /** Render cadence during the intro (~30fps). */
580
+ const INTRO_TICK_MS = 33;
581
+ /** Number of full gradient rotations the sweep performs before settling. */
582
+ const INTRO_SWEEPS = 2.5;
583
+ /** Number of times the shine highlight crosses the diagonal across the intro. */
584
+ const INTRO_SHINE_TRAVERSALS = 3;
585
+
586
+ /**
587
+ * Logo frame for a normalized intro progress in [0, 1).
588
+ *
589
+ * Ease-out cubic so the spin decelerates into the resting state. The gradient
590
+ * sweeps backward through INTRO_SWEEPS full rotations (`eased == 1` → phase =
591
+ * 0 = resting frame) while the shine traverses the diagonal at a steady pace,
592
+ * decoupled from the gradient phase so the two layers parallax; its strength
593
+ * fades with the same ease-out curve so the highlight is gone by the resting
594
+ * frame.
595
+ */
596
+ function introLogoFrame(progress: number): string[] {
597
+ const eased = 1 - (1 - progress) ** 3;
598
+ const phase = ((((1 - eased) * INTRO_SWEEPS) % 1) + 1) % 1;
599
+ const shinePos = (((progress * INTRO_SHINE_TRAVERSALS) % 1) + 1) % 1;
600
+ const shineStrength = (1 - eased) ** 1.5;
601
+ return gradientLogo(PI_LOGO, phase, { strength: shineStrength, pos: shinePos });
602
+ }
603
+
604
+ /** Resting gradient frame, cached for re-renders outside of the intro. */
605
+ const REST_FRAME = gradientLogo(PI_LOGO, 0);
@@ -0,0 +1,26 @@
1
+ import { createGradientHighlighter, type KeywordHighlighter } from "./gradient-highlight";
2
+ import { magicKeywordRegex } from "./magic-keyword-boundary";
3
+ import { keywordInProse } from "./markdown-prose";
4
+
5
+ const WORKFLOW_WORD = magicKeywordRegex("workflowz");
6
+
7
+ /**
8
+ * Whether `text` contains the standalone keyword "workflowz"
9
+ * (lowercase, prose-delimited) in prose — never inside a code block, inline
10
+ * code span, or XML/HTML section.
11
+ */
12
+ export function containsWorkflow(text: string): boolean {
13
+ return keywordInProse(text, WORKFLOW_WORD);
14
+ }
15
+
16
+ /**
17
+ * Highlight every standalone "workflowz" in `text` for editor display
18
+ * with a warm amber→green gradient (hue 30..150), visually distinct from
19
+ * ultrathink's rainbow and orchestrate's teal→violet.
20
+ */
21
+ export const highlightWorkflow: KeywordHighlighter = createGradientHighlighter({
22
+ probe: /workflowz/,
23
+ highlight: magicKeywordRegex("workflowz", "g"),
24
+ stops: 14,
25
+ hue: t => 30 + t * 120,
26
+ });