@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,810 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { detectMacOSAppearance, MacAppearanceObserver } from "@oh-my-pi/pi-natives";
4
+ import type { Terminal, TerminalAppearance } from "../terminal";
5
+ import { colorLuma } from "@oh-my-pi/pi-utils/color";
6
+ import { getCustomThemesDir } from "@oh-my-pi/pi-utils/dirs";
7
+ import * as logger from "@oh-my-pi/pi-utils/logger";
8
+ import { ansi256ToHex, resolveThemeColors, resolveVarRefs } from "./color";
9
+ import { type CreateThemeOptions, getBuiltinThemes, loadTheme, loadThemeJson, loadThemeSync } from "./loader";
10
+ import type { ThemeColor, ThemeJson } from "./schema";
11
+ import type { SymbolPreset } from "./symbols";
12
+ import type { Theme } from "./theme-class";
13
+
14
+ export { getAvailableThemes, getAvailableThemesWithPaths, getThemeByName, type ThemeInfo } from "./loader";
15
+ export { isValidThemeColor, type ThemeBg, type ThemeColor } from "./schema";
16
+ export {
17
+ getAvailableSymbolPresets,
18
+ isValidSymbolPreset,
19
+ type SpinnerType,
20
+ type SymbolKey,
21
+ type SymbolPreset,
22
+ } from "./symbols";
23
+ export { Theme } from "./theme-class";
24
+ export {
25
+ createHighlightStream,
26
+ getEditorTheme,
27
+ getMarkdownTheme,
28
+ getSelectListTheme,
29
+ getSettingsListTheme,
30
+ getSymbolTheme,
31
+ highlightCode,
32
+ setMarkdownMermaidRendering,
33
+ warmHighlighter,
34
+ } from "./tui-adapters";
35
+
36
+ /** Appearance detected via OSC 11 background color query, or undefined if not yet available. */
37
+ var terminalReportedAppearance: "dark" | "light" | undefined;
38
+
39
+ /** Appearance reported by the macOS fallback observer, or undefined if not yet available. */
40
+ var macOSReportedAppearance: "dark" | "light" | undefined;
41
+
42
+ function shouldUseMacOSAppearanceFallback(): boolean {
43
+ // Zellij currently breaks OSC 11 passthrough on macOS, so terminal-derived
44
+ // appearance cannot be trusted there. Fall back to host macOS appearance
45
+ // without letting it override valid terminal signals elsewhere.
46
+ return process.platform === "darwin" && !!Bun.env.ZELLIJ;
47
+ }
48
+
49
+ function detectTerminalBackground(): "dark" | "light" {
50
+ // Tier 1: terminal-reported appearance from OSC 11 luminance.
51
+ if (!shouldUseMacOSAppearanceFallback() && terminalReportedAppearance) {
52
+ return terminalReportedAppearance;
53
+ }
54
+
55
+ // Tier 2: COLORFGBG env var (static at process start, but still terminal-derived).
56
+ const colorfgbg = Bun.env.COLORFGBG || "";
57
+ if (colorfgbg) {
58
+ const parts = colorfgbg.split(";");
59
+ if (parts.length >= 2) {
60
+ const bg = parseInt(parts[1], 10);
61
+ if (!Number.isNaN(bg)) return bg < 8 ? "dark" : "light";
62
+ }
63
+ }
64
+
65
+ // Tier 3: host macOS appearance for known-broken terminal paths only.
66
+ if (shouldUseMacOSAppearanceFallback()) {
67
+ const macAppearance = macOSReportedAppearance ?? detectMacOSAppearance();
68
+ if (macAppearance) return macAppearance;
69
+ }
70
+
71
+ return "dark";
72
+ }
73
+
74
+ function getDefaultTheme(): string {
75
+ const bg = detectTerminalBackground();
76
+ return bg === "light" ? autoLightTheme : autoDarkTheme;
77
+ }
78
+
79
+ // ============================================================================
80
+ // Global Theme Instance
81
+ // ============================================================================
82
+
83
+ /** Active theme; imports remain live across initialization, previews, and theme switches. */
84
+ export var theme: Theme;
85
+ var currentThemeName: string | undefined;
86
+
87
+ type ThemeBinding = (value: Theme) => void;
88
+ var themeBindings: Set<ThemeBinding> | undefined;
89
+
90
+ /** @internal Mirror assignments into bundled module bindings without replacing the UI change listener. */
91
+ export function bindTheme(binding: ThemeBinding): () => void {
92
+ const bindings = (themeBindings ??= new Set<ThemeBinding>());
93
+ bindings.add(binding);
94
+ binding(theme);
95
+ return () => {
96
+ bindings.delete(binding);
97
+ };
98
+ }
99
+
100
+ function assignTheme(value: Theme): void {
101
+ theme = value;
102
+ if (themeBindings) {
103
+ for (const binding of themeBindings) binding(value);
104
+ }
105
+ }
106
+
107
+ /** Get the name of the currently active theme. */
108
+ export function getCurrentThemeName(): string | undefined {
109
+ return currentThemeName;
110
+ }
111
+
112
+ /** Returns unstyled `text` before `initTheme()` assigns the global theme; use only for early-render paths. */
113
+ export function fgOrPlain(color: ThemeColor, text: string, styledText: string = text): string {
114
+ return typeof theme === "undefined" ? text : theme.fg(color, styledText);
115
+ }
116
+ export interface ThemeChangeEvent {
117
+ /** Preview/presentation-only changes should repaint live UI without replacing native scrollback. */
118
+ ephemeral?: boolean;
119
+ }
120
+
121
+ var currentSymbolPresetOverride: SymbolPreset | undefined;
122
+ var currentColorBlindMode: boolean = false;
123
+ var themeWatcher: fs.FSWatcher | undefined;
124
+ var themeReloadTimer: NodeJS.Timeout | undefined;
125
+ var sigwinchHandler: (() => void) | undefined;
126
+ var autoDetectedTheme: boolean = false;
127
+ var autoDarkTheme: string = "dark";
128
+ var autoLightTheme: string = "light";
129
+ var onThemeChangeCallback: ((event: ThemeChangeEvent) => void) | undefined;
130
+ var themeLoadRequestId: number = 0;
131
+ let themeEpoch = 0;
132
+
133
+ function getCurrentThemeOptions(): CreateThemeOptions {
134
+ return {
135
+ symbolPresetOverride: currentSymbolPresetOverride,
136
+ colorBlindMode: currentColorBlindMode,
137
+ };
138
+ }
139
+ function configureTheme(
140
+ symbolPreset?: SymbolPreset,
141
+ colorBlindMode?: boolean,
142
+ darkTheme?: string,
143
+ lightTheme?: string,
144
+ ): string {
145
+ autoDetectedTheme = true;
146
+ autoDarkTheme = darkTheme ?? "dark";
147
+ autoLightTheme = lightTheme ?? "light";
148
+ currentSymbolPresetOverride = symbolPreset;
149
+ currentColorBlindMode = colorBlindMode ?? false;
150
+ const name = getDefaultTheme();
151
+ currentThemeName = name;
152
+ return name;
153
+ }
154
+
155
+ /** Initialize the active theme synchronously before the first terminal paint. */
156
+ export function initThemeSync(
157
+ symbolPreset?: SymbolPreset,
158
+ colorBlindMode?: boolean,
159
+ darkTheme?: string,
160
+ lightTheme?: string,
161
+ ): void {
162
+ const name = configureTheme(symbolPreset, colorBlindMode, darkTheme, lightTheme);
163
+ const options: CreateThemeOptions = {
164
+ symbolPresetOverride: currentSymbolPresetOverride,
165
+ colorBlindMode: currentColorBlindMode,
166
+ };
167
+ try {
168
+ assignTheme(loadThemeSync(name, options));
169
+ } catch (error) {
170
+ logger.debug("Theme loading failed, falling back to dark theme", { error: String(error) });
171
+ currentThemeName = "dark";
172
+ assignTheme(loadThemeSync("dark", options));
173
+ }
174
+ }
175
+
176
+ /** Ensure the module-local theme is initialized before synchronous component work. */
177
+ export function ensureThemeSync(): void {
178
+ if (typeof theme === "undefined") initThemeSync();
179
+ }
180
+
181
+ /** Initialize the default theme only when no earlier prepaint initialized one. */
182
+ export async function ensureTheme(): Promise<void> {
183
+ if (typeof theme !== "undefined") return;
184
+ await initTheme();
185
+ }
186
+
187
+ export async function initTheme(
188
+ enableWatcher: boolean = false,
189
+ symbolPreset?: SymbolPreset,
190
+ colorBlindMode?: boolean,
191
+ darkTheme?: string,
192
+ lightTheme?: string,
193
+ ): Promise<void> {
194
+ const name = configureTheme(symbolPreset, colorBlindMode, darkTheme, lightTheme);
195
+ try {
196
+ assignTheme(await loadTheme(name, getCurrentThemeOptions()));
197
+ if (enableWatcher) {
198
+ await startThemeWatcher();
199
+ startSigwinchListener();
200
+ }
201
+ } catch (err) {
202
+ logger.debug("Theme loading failed, falling back to dark theme", { error: String(err) });
203
+ currentThemeName = "dark";
204
+ assignTheme(await loadTheme("dark", getCurrentThemeOptions()));
205
+ // Don't start watcher for fallback theme
206
+ }
207
+ }
208
+
209
+ export async function setTheme(
210
+ name: string,
211
+ enableWatcher: boolean = false,
212
+ ): Promise<{ success: boolean; error?: string }> {
213
+ autoDetectedTheme = false;
214
+ currentThemeName = name;
215
+ const requestId = ++themeLoadRequestId;
216
+ try {
217
+ const loadedTheme = await loadTheme(name, getCurrentThemeOptions());
218
+ if (requestId !== themeLoadRequestId) {
219
+ return { success: false, error: "Theme change superseded by a newer request" };
220
+ }
221
+ assignTheme(loadedTheme);
222
+ if (enableWatcher) {
223
+ await startThemeWatcher();
224
+ }
225
+ notifyThemeChange();
226
+ return { success: true };
227
+ } catch (error) {
228
+ if (requestId !== themeLoadRequestId) {
229
+ return { success: false, error: "Theme change superseded by a newer request" };
230
+ }
231
+ // Theme is invalid - fall back to dark theme
232
+ currentThemeName = "dark";
233
+ assignTheme(await loadTheme("dark", getCurrentThemeOptions()));
234
+ // The active theme just changed to the fallback — bump the epoch so memoized
235
+ // renderers (e.g. ToolExecutionComponent) re-shape with the fallback colors
236
+ // instead of holding the failed theme's stale styling.
237
+ notifyThemeChange();
238
+ // Don't start watcher for fallback theme
239
+ return {
240
+ success: false,
241
+ error: error instanceof Error ? error.message : String(error),
242
+ };
243
+ }
244
+ }
245
+
246
+ export async function previewTheme(
247
+ name: string,
248
+ event: ThemeChangeEvent = { ephemeral: true },
249
+ ): Promise<{ success: boolean; error?: string }> {
250
+ const requestId = ++themeLoadRequestId;
251
+ try {
252
+ const loadedTheme = await loadTheme(name, getCurrentThemeOptions());
253
+ if (requestId !== themeLoadRequestId) {
254
+ return { success: false, error: "Theme preview superseded by a newer request" };
255
+ }
256
+ assignTheme(loadedTheme);
257
+ notifyThemeChange(event);
258
+ return { success: true };
259
+ } catch (error) {
260
+ if (requestId !== themeLoadRequestId) {
261
+ return { success: false, error: "Theme preview superseded by a newer request" };
262
+ }
263
+ return {
264
+ success: false,
265
+ error: error instanceof Error ? error.message : String(error),
266
+ };
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Enable auto-detection mode, switching to the appropriate dark/light theme.
272
+ */
273
+ export function enableAutoTheme(event: ThemeChangeEvent = {}): void {
274
+ autoDetectedTheme = true;
275
+ reevaluateAutoTheme("enableAutoTheme", event);
276
+ }
277
+
278
+ /**
279
+ * Update the theme mappings for auto-detection mode.
280
+ * When a dark/light mapping changes and auto-detection is active, re-evaluate the theme.
281
+ */
282
+ export function setAutoThemeMapping(mode: "dark" | "light", themeName: string): void {
283
+ if (mode === "dark") autoDarkTheme = themeName;
284
+ else autoLightTheme = themeName;
285
+ reevaluateAutoTheme("setAutoThemeMapping");
286
+ }
287
+
288
+ /**
289
+ * Called when the terminal detects a dark/light appearance change.
290
+ * The terminal layer queries OSC 11 (background color) and computes luminance;
291
+ * Mode 2031 notifications trigger re-queries rather than providing the value directly.
292
+ */
293
+ export function onTerminalAppearanceChange(
294
+ mode: "dark" | "light",
295
+ event: ThemeChangeEvent = { ephemeral: true },
296
+ ): void {
297
+ if (terminalReportedAppearance === mode) return;
298
+ terminalReportedAppearance = mode;
299
+ reevaluateAutoTheme("terminal appearance", event);
300
+ }
301
+
302
+ export function setThemeInstance(themeInstance: Theme): void {
303
+ autoDetectedTheme = false;
304
+ assignTheme(themeInstance);
305
+ currentThemeName = "<in-memory>";
306
+ stopThemeWatcher();
307
+ notifyThemeChange({ ephemeral: true });
308
+ }
309
+
310
+ /**
311
+ * Set the symbol preset override, recreating the theme with the new preset.
312
+ */
313
+ export async function setSymbolPreset(preset: SymbolPreset): Promise<void> {
314
+ currentSymbolPresetOverride = preset;
315
+ if (!currentThemeName) return;
316
+
317
+ const requestId = ++themeLoadRequestId;
318
+ try {
319
+ const loadedTheme = await loadTheme(currentThemeName, getCurrentThemeOptions());
320
+ if (requestId !== themeLoadRequestId) return;
321
+ assignTheme(loadedTheme);
322
+ } catch {
323
+ if (requestId !== themeLoadRequestId) return;
324
+ // Fall back to dark theme with new preset
325
+ assignTheme(await loadTheme("dark", getCurrentThemeOptions()));
326
+ if (requestId !== themeLoadRequestId) return;
327
+ }
328
+ notifyThemeChange({ ephemeral: true });
329
+ }
330
+
331
+ /**
332
+ * Get the current symbol preset override.
333
+ */
334
+ export function getSymbolPresetOverride(): SymbolPreset | undefined {
335
+ return currentSymbolPresetOverride;
336
+ }
337
+
338
+ /**
339
+ * Set color blind mode, recreating the theme with the new setting.
340
+ * When enabled, uses blue instead of green for diff additions.
341
+ */
342
+ export async function setColorBlindMode(enabled: boolean): Promise<void> {
343
+ currentColorBlindMode = enabled;
344
+ if (!currentThemeName) return;
345
+
346
+ const requestId = ++themeLoadRequestId;
347
+ try {
348
+ const loadedTheme = await loadTheme(currentThemeName, getCurrentThemeOptions());
349
+ if (requestId !== themeLoadRequestId) return;
350
+ assignTheme(loadedTheme);
351
+ } catch {
352
+ if (requestId !== themeLoadRequestId) return;
353
+ // Fall back to dark theme
354
+ assignTheme(await loadTheme("dark", getCurrentThemeOptions()));
355
+ if (requestId !== themeLoadRequestId) return;
356
+ }
357
+ notifyThemeChange({ ephemeral: true });
358
+ }
359
+
360
+ /**
361
+ * Get the current color blind mode setting.
362
+ */
363
+ export function getColorBlindMode(): boolean {
364
+ return currentColorBlindMode;
365
+ }
366
+
367
+ export function onThemeChange(callback: (event: ThemeChangeEvent) => void): () => void {
368
+ onThemeChangeCallback = callback;
369
+ return () => {
370
+ if (onThemeChangeCallback === callback) {
371
+ onThemeChangeCallback = undefined;
372
+ }
373
+ };
374
+ }
375
+
376
+ /**
377
+ * Monotonic counter bumped on any theme-affecting change that should invalidate
378
+ * cached renders: theme swaps and reloads (including the invalid-theme dark
379
+ * fallback), theme previews, symbol-preset changes, and color-blind-mode
380
+ * changes — everything that routes through {@link notifyThemeChange}. Consumers
381
+ * key cached renders on it so the next render re-shapes their output.
382
+ */
383
+ export function getThemeEpoch(): number {
384
+ return themeEpoch;
385
+ }
386
+
387
+ /** Bump the theme epoch and notify the registered theme-change listener. */
388
+ function notifyThemeChange(event: ThemeChangeEvent = {}): void {
389
+ themeEpoch++;
390
+ onThemeChangeCallback?.(event);
391
+ }
392
+
393
+ async function startThemeWatcher(): Promise<void> {
394
+ stopThemeWatcher();
395
+
396
+ // Only watch if it's a custom theme (not built-in)
397
+ if (!currentThemeName || currentThemeName === "dark" || currentThemeName === "light") {
398
+ return;
399
+ }
400
+
401
+ const customThemesDir = getCustomThemesDir();
402
+ const watchedThemeName = currentThemeName;
403
+ const watchedFileName = `${watchedThemeName}.json`;
404
+ const themeFile = path.join(customThemesDir, watchedFileName);
405
+
406
+ // Only watch if the file exists
407
+ if (!fs.existsSync(themeFile)) {
408
+ return;
409
+ }
410
+
411
+ const scheduleReload = () => {
412
+ if (themeReloadTimer) {
413
+ clearTimeout(themeReloadTimer);
414
+ }
415
+ themeReloadTimer = setTimeout(() => {
416
+ themeReloadTimer = undefined;
417
+
418
+ // Ignore stale timers after switching themes or stopping the watcher
419
+ if (currentThemeName !== watchedThemeName) {
420
+ return;
421
+ }
422
+
423
+ // Keep the last successfully loaded theme active if the file is temporarily missing
424
+ if (!fs.existsSync(themeFile)) {
425
+ return;
426
+ }
427
+
428
+ loadTheme(watchedThemeName, getCurrentThemeOptions())
429
+ .then(loadedTheme => {
430
+ assignTheme(loadedTheme);
431
+ notifyThemeChange({ ephemeral: true });
432
+ })
433
+ .catch(() => {
434
+ // Ignore errors (file might be in invalid state while being edited)
435
+ });
436
+ }, 100);
437
+ };
438
+
439
+ try {
440
+ themeWatcher = fs.watch(customThemesDir, (_eventType, filename) => {
441
+ if (currentThemeName !== watchedThemeName) {
442
+ return;
443
+ }
444
+ if (!filename) {
445
+ scheduleReload();
446
+ return;
447
+ }
448
+ const changedFile = String(filename);
449
+ if (changedFile !== watchedFileName) {
450
+ return;
451
+ }
452
+ scheduleReload();
453
+ });
454
+ } catch {
455
+ // Ignore errors starting watcher
456
+ }
457
+ }
458
+
459
+ /**
460
+ * Load and apply an already-resolved auto-theme name.
461
+ */
462
+ function applyResolvedAutoTheme(resolved: string, debugLabel: string, event: ThemeChangeEvent): void {
463
+ if (resolved === currentThemeName) return;
464
+ currentThemeName = resolved;
465
+ const requestId = ++themeLoadRequestId;
466
+ loadTheme(resolved, getCurrentThemeOptions())
467
+ .then(loadedTheme => {
468
+ if (requestId !== themeLoadRequestId) return;
469
+ assignTheme(loadedTheme);
470
+ notifyThemeChange(event);
471
+ })
472
+ .catch(err => {
473
+ if (requestId !== themeLoadRequestId) return;
474
+ logger.debug(`Theme switch on ${debugLabel} failed`, { error: String(err) });
475
+ });
476
+ }
477
+
478
+ /**
479
+ * Shared logic for re-evaluating the auto-detected theme.
480
+ * An explicit appearance is provisional input and does not alter terminal-reported state.
481
+ */
482
+ function reevaluateAutoTheme(debugLabel: string, event: ThemeChangeEvent = {}, appearance?: "dark" | "light"): void {
483
+ if (!autoDetectedTheme) return;
484
+ const resolved =
485
+ appearance === undefined ? getDefaultTheme() : appearance === "dark" ? autoDarkTheme : autoLightTheme;
486
+ applyResolvedAutoTheme(resolved, debugLabel, event);
487
+ }
488
+
489
+ function reevaluateAutoThemeForAppearance(debugLabel: string, appearance?: "dark" | "light"): void {
490
+ reevaluateAutoTheme(debugLabel, { ephemeral: true }, appearance);
491
+ }
492
+
493
+ // ============================================================================
494
+ // macOS Appearance Fallback Observer
495
+ // ============================================================================
496
+
497
+ type MacOSAppearanceReprobeTerminal = Pick<
498
+ Terminal,
499
+ "appearance" | "onAppearanceChange" | "onAppearanceReport" | "onPrivateModeReport" | "refreshAppearance"
500
+ >;
501
+
502
+ const MACOS_APPEARANCE_REPROBE_DELAYS_MS = [25, 50, 100, 250, 500, 1000] as const;
503
+ const MACOS_APPEARANCE_RECONCILE_DELAY_MS = 1100;
504
+
505
+ /**
506
+ * Fall back to native macOS appearance notifications when the terminal
507
+ * explicitly confirms that Mode 2031 notifications are unsupported.
508
+ *
509
+ * Native notifications provisionally repaint from the host appearance and
510
+ * synchronously trigger an OSC 11 probe, followed by a bounded burst of six
511
+ * retries. A changed terminal classification cancels the sequence; otherwise
512
+ * a confirmed terminal classification is restored at the validation deadline.
513
+ */
514
+ export function startMacOSAppearanceReprobeFallback(terminal: MacOSAppearanceReprobeTerminal): () => void {
515
+ let disposed = false;
516
+ let observerStartAttempted = false;
517
+ let observer: MacAppearanceObserver | undefined;
518
+ let probeGeneration = 0;
519
+ let probeSequenceActive = false;
520
+ let probeBaseline: TerminalAppearance | undefined;
521
+ let probeResponseConfirmed = false;
522
+ const probeTimers = new Set<Timer>();
523
+ let reconciliationTimer: Timer | undefined;
524
+
525
+ const cancelProbeSequence = (): void => {
526
+ probeGeneration++;
527
+ probeSequenceActive = false;
528
+ probeBaseline = undefined;
529
+ probeResponseConfirmed = false;
530
+ if (reconciliationTimer) {
531
+ clearTimeout(reconciliationTimer);
532
+ reconciliationTimer = undefined;
533
+ }
534
+ for (const timer of probeTimers) {
535
+ clearTimeout(timer);
536
+ }
537
+ probeTimers.clear();
538
+ };
539
+
540
+ const scheduleProbeSequence = (): void => {
541
+ cancelProbeSequence();
542
+ if (disposed || !autoDetectedTheme) return;
543
+
544
+ probeSequenceActive = true;
545
+ probeBaseline = terminal.appearance;
546
+ probeResponseConfirmed = false;
547
+ const generation = probeGeneration;
548
+ terminal.refreshAppearance?.();
549
+ if (disposed || generation !== probeGeneration || !autoDetectedTheme) return;
550
+ for (const delay of MACOS_APPEARANCE_REPROBE_DELAYS_MS) {
551
+ const timer = setTimeout(() => {
552
+ probeTimers.delete(timer);
553
+ if (disposed || generation !== probeGeneration) return;
554
+ if (!autoDetectedTheme) {
555
+ cancelProbeSequence();
556
+ return;
557
+ }
558
+ terminal.refreshAppearance?.();
559
+ }, delay);
560
+ timer.unref?.();
561
+ probeTimers.add(timer);
562
+ }
563
+ reconciliationTimer = setTimeout(() => {
564
+ reconciliationTimer = undefined;
565
+ if (disposed || generation !== probeGeneration) return;
566
+ const appearance = probeResponseConfirmed ? terminal.appearance : undefined;
567
+ cancelProbeSequence();
568
+ if (!autoDetectedTheme || !appearance) return;
569
+ reevaluateAutoThemeForAppearance("macOS appearance reconciliation", appearance);
570
+ }, MACOS_APPEARANCE_RECONCILE_DELAY_MS);
571
+ reconciliationTimer.unref?.();
572
+ };
573
+
574
+ const unsubscribeAppearanceReport = terminal.onAppearanceReport?.(() => {
575
+ if (disposed || !probeSequenceActive) return;
576
+ probeResponseConfirmed = true;
577
+ });
578
+
579
+ terminal.onAppearanceChange(appearance => {
580
+ if (disposed || !probeSequenceActive || appearance === probeBaseline) return;
581
+ cancelProbeSequence();
582
+ });
583
+
584
+ terminal.onPrivateModeReport?.((mode, supported, confirmed) => {
585
+ if (disposed || observerStartAttempted || mode !== 2031 || supported || confirmed !== true) {
586
+ return;
587
+ }
588
+
589
+ observerStartAttempted = true;
590
+ try {
591
+ observer = MacAppearanceObserver.start((err, appearance) => {
592
+ if (disposed) return;
593
+ if (err) {
594
+ cancelProbeSequence();
595
+ return;
596
+ }
597
+ if (appearance === "dark" || appearance === "light") {
598
+ reevaluateAutoThemeForAppearance("macOS provisional appearance", appearance);
599
+ }
600
+ scheduleProbeSequence();
601
+ });
602
+ } catch (err) {
603
+ logger.warn("Failed to start macOS appearance reprobe observer", { err });
604
+ }
605
+ });
606
+
607
+ return () => {
608
+ if (disposed) return;
609
+ disposed = true;
610
+ cancelProbeSequence();
611
+ if (unsubscribeAppearanceReport) unsubscribeAppearanceReport();
612
+ const activeObserver = observer;
613
+ observer = undefined;
614
+ if (!activeObserver) return;
615
+ try {
616
+ activeObserver.stop();
617
+ } catch (err) {
618
+ logger.debug("Failed to stop macOS appearance reprobe observer", { err });
619
+ }
620
+ };
621
+ }
622
+
623
+ var macObserver: { stop(): void } | undefined;
624
+
625
+ function startMacAppearanceObserver(): void {
626
+ stopMacAppearanceObserver();
627
+ if (!shouldUseMacOSAppearanceFallback()) return;
628
+ try {
629
+ macOSReportedAppearance = detectMacOSAppearance() ?? undefined;
630
+ macObserver = MacAppearanceObserver.start((err, appearance) => {
631
+ if (!err && (appearance === "dark" || appearance === "light")) {
632
+ macOSReportedAppearance = appearance;
633
+ reevaluateAutoThemeForAppearance("macOS fallback");
634
+ }
635
+ });
636
+ } catch (err) {
637
+ logger.warn("Failed to start macOS appearance observer", { err });
638
+ }
639
+ }
640
+
641
+ function stopMacAppearanceObserver(): void {
642
+ if (macObserver) {
643
+ macObserver.stop();
644
+ macObserver = undefined;
645
+ }
646
+ macOSReportedAppearance = undefined;
647
+ }
648
+
649
+ // ============================================================================
650
+ // SIGWINCH Listener
651
+ // ============================================================================
652
+
653
+ /** Re-check appearance on SIGWINCH and switch dark/light when using auto-detected theme. */
654
+ function startSigwinchListener(): void {
655
+ stopSigwinchListener();
656
+ sigwinchHandler = () => {
657
+ reevaluateAutoThemeForAppearance("SIGWINCH");
658
+ };
659
+ process.on("SIGWINCH", sigwinchHandler);
660
+ startMacAppearanceObserver();
661
+ }
662
+
663
+ function stopSigwinchListener(): void {
664
+ if (sigwinchHandler) {
665
+ process.removeListener("SIGWINCH", sigwinchHandler);
666
+ sigwinchHandler = undefined;
667
+ }
668
+ stopMacAppearanceObserver();
669
+ }
670
+
671
+ export function stopThemeWatcher(): void {
672
+ if (themeReloadTimer) {
673
+ clearTimeout(themeReloadTimer);
674
+ themeReloadTimer = undefined;
675
+ }
676
+ if (themeWatcher) {
677
+ themeWatcher.close();
678
+ themeWatcher = undefined;
679
+ }
680
+ stopSigwinchListener();
681
+ terminalReportedAppearance = undefined;
682
+ }
683
+
684
+ // ============================================================================
685
+ // HTML Export Helpers
686
+ // ============================================================================
687
+
688
+ /**
689
+ * Classify a parsed theme JSON as light/dark by the perceived luminance of its
690
+ * status-line background. Mirrors {@link Theme.isLight} so the synchronous
691
+ * helpers below stay in lockstep with the runtime classifier — see the comment
692
+ * on `Theme.statusLineLuminance` for why `statusLineBg` is the source of truth
693
+ * (themes like `porcelain` style a dark chat bubble on an otherwise-light
694
+ * theme, so `userMessageBg` is unreliable).
695
+ */
696
+ function isLightThemeJson(themeJson: ThemeJson): boolean {
697
+ try {
698
+ const resolved = resolveVarRefs(themeJson.colors.statusLineBg, themeJson.vars ?? {});
699
+ const luminance = colorLuma(resolved);
700
+ return luminance !== undefined && luminance > 0.5;
701
+ } catch {
702
+ return false;
703
+ }
704
+ }
705
+
706
+ function getHtmlDefaultTextForSurface(surface: string | number | undefined): string {
707
+ const luminance = surface === undefined ? undefined : colorLuma(surface);
708
+ return luminance !== undefined && luminance > 0.5 ? "#000000" : "#e5e5e7";
709
+ }
710
+
711
+ function resolveThemeExportColors(themeJson: ThemeJson): {
712
+ pageBg?: string;
713
+ cardBg?: string;
714
+ infoBg?: string;
715
+ } {
716
+ const exportSection = themeJson.export;
717
+ if (!exportSection) return {};
718
+
719
+ const vars = themeJson.vars ?? {};
720
+ const resolve = (value: string | number | undefined): string | undefined => {
721
+ if (value === undefined) return undefined;
722
+ if (typeof value === "number") return ansi256ToHex(value);
723
+ if (value === "" || value.startsWith("#")) return value;
724
+ const varName = value.startsWith("$") ? value.slice(1) : value;
725
+ if (varName in vars) {
726
+ const resolved = resolveVarRefs(varName, vars);
727
+ return typeof resolved === "number" ? ansi256ToHex(resolved) : resolved;
728
+ }
729
+ return value;
730
+ };
731
+
732
+ return {
733
+ pageBg: resolve(exportSection.pageBg),
734
+ cardBg: resolve(exportSection.cardBg),
735
+ infoBg: resolve(exportSection.infoBg),
736
+ };
737
+ }
738
+
739
+ /**
740
+ * Get resolved theme colors as CSS-compatible hex strings.
741
+ * Used by HTML export to generate CSS custom properties.
742
+ */
743
+ export async function getResolvedThemeColors(themeName?: string): Promise<Record<string, string>> {
744
+ const name = themeName ?? getDefaultTheme();
745
+ const themeJson = await loadThemeJson(name);
746
+ const exportColors = resolveThemeExportColors(themeJson);
747
+ const resolved = resolveThemeColors(themeJson.colors, themeJson.vars);
748
+
749
+ // Empty foreground tokens use the terminal default color. In HTML export,
750
+ // that default must contrast the export surface, not the TUI status line:
751
+ // custom light themes can still export dark transcript cards when they omit
752
+ // `export`, because generateThemeVars derives those cards from userMessageBg.
753
+ const defaultText = getHtmlDefaultTextForSurface(
754
+ exportColors.cardBg ?? exportColors.pageBg ?? resolved.userMessageBg,
755
+ );
756
+
757
+ const cssColors: Record<string, string> = {};
758
+ for (const [key, value] of Object.entries(resolved)) {
759
+ if (typeof value === "number") {
760
+ cssColors[key] = ansi256ToHex(value);
761
+ } else if (value === "") {
762
+ // Empty means default terminal color - use sensible fallback for HTML
763
+ cssColors[key] = defaultText;
764
+ } else {
765
+ cssColors[key] = value;
766
+ }
767
+ }
768
+ return cssColors;
769
+ }
770
+
771
+ /**
772
+ * Check if a theme is a "light" theme by analyzing its status-line background
773
+ * luminance. Loads theme JSON synchronously (built-in or custom file on disk)
774
+ * for callers in synchronous flows (settings migration, setup wizard).
775
+ */
776
+ export function isLightTheme(themeName?: string): boolean {
777
+ const name = themeName ?? "dark";
778
+ const builtinThemes = getBuiltinThemes();
779
+ let themeJson: ThemeJson | undefined;
780
+ if (name in builtinThemes) {
781
+ themeJson = builtinThemes[name];
782
+ } else {
783
+ try {
784
+ const customPath = path.join(getCustomThemesDir(), `${name}.json`);
785
+ const content = fs.readFileSync(customPath, "utf-8");
786
+ themeJson = JSON.parse(content) as ThemeJson;
787
+ } catch {
788
+ return false;
789
+ }
790
+ }
791
+ return isLightThemeJson(themeJson);
792
+ }
793
+
794
+ /**
795
+ * Get explicit export colors from theme JSON, if specified.
796
+ * Returns undefined for each color that isn't explicitly set.
797
+ */
798
+ export async function getThemeExportColors(themeName?: string): Promise<{
799
+ pageBg?: string;
800
+ cardBg?: string;
801
+ infoBg?: string;
802
+ }> {
803
+ const name = themeName ?? getDefaultTheme();
804
+ try {
805
+ const themeJson = await loadThemeJson(name);
806
+ return resolveThemeExportColors(themeJson);
807
+ } catch {
808
+ return {};
809
+ }
810
+ }