theme.ts 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. import chalk, { Chalk } from 'chalk'
  2. import { env } from './env.js'
  3. export type Theme = {
  4. autoAccept: string
  5. bashBorder: string
  6. claude: string
  7. claudeShimmer: string // Lighter version of claude color for shimmer effect
  8. claudeBlue_FOR_SYSTEM_SPINNER: string
  9. claudeBlueShimmer_FOR_SYSTEM_SPINNER: string
  10. permission: string
  11. permissionShimmer: string // Lighter version of permission color for shimmer effect
  12. planMode: string
  13. ide: string
  14. promptBorder: string
  15. promptBorderShimmer: string // Lighter version of promptBorder color for shimmer effect
  16. text: string
  17. inverseText: string
  18. inactive: string
  19. inactiveShimmer: string // Lighter version of inactive color for shimmer effect
  20. subtle: string
  21. suggestion: string
  22. remember: string
  23. background: string
  24. // Semantic colors
  25. success: string
  26. error: string
  27. warning: string
  28. merged: string
  29. warningShimmer: string // Lighter version of warning color for shimmer effect
  30. // Diff colors
  31. diffAdded: string
  32. diffRemoved: string
  33. diffAddedDimmed: string
  34. diffRemovedDimmed: string
  35. // Word-level diff highlighting
  36. diffAddedWord: string
  37. diffRemovedWord: string
  38. // Agent colors
  39. red_FOR_SUBAGENTS_ONLY: string
  40. blue_FOR_SUBAGENTS_ONLY: string
  41. green_FOR_SUBAGENTS_ONLY: string
  42. yellow_FOR_SUBAGENTS_ONLY: string
  43. purple_FOR_SUBAGENTS_ONLY: string
  44. orange_FOR_SUBAGENTS_ONLY: string
  45. pink_FOR_SUBAGENTS_ONLY: string
  46. cyan_FOR_SUBAGENTS_ONLY: string
  47. // Grove colors
  48. professionalBlue: string
  49. // Chrome colors
  50. chromeYellow: string
  51. // TUI V2 colors
  52. clawd_body: string
  53. clawd_background: string
  54. userMessageBackground: string
  55. userMessageBackgroundHover: string
  56. /** Message-actions selection. Cool shift toward `suggestion` blue; distinct from default AND userMessageBackground. */
  57. messageActionsBackground: string
  58. /** Text-selection highlight background (alt-screen mouse selection). Solid
  59. * bg that REPLACES the cell's bg while preserving its fg — matches native
  60. * terminal selection. Previously SGR-7 inverse (swapped fg/bg per cell),
  61. * which fragmented badly over syntax highlighting. */
  62. selectionBg: string
  63. bashMessageBackgroundColor: string
  64. memoryBackgroundColor: string
  65. rate_limit_fill: string
  66. rate_limit_empty: string
  67. fastMode: string
  68. fastModeShimmer: string
  69. // Brief/assistant mode label colors
  70. briefLabelYou: string
  71. briefLabelClaude: string
  72. // Rainbow colors for ultrathink keyword highlighting
  73. rainbow_red: string
  74. rainbow_orange: string
  75. rainbow_yellow: string
  76. rainbow_green: string
  77. rainbow_blue: string
  78. rainbow_indigo: string
  79. rainbow_violet: string
  80. rainbow_red_shimmer: string
  81. rainbow_orange_shimmer: string
  82. rainbow_yellow_shimmer: string
  83. rainbow_green_shimmer: string
  84. rainbow_blue_shimmer: string
  85. rainbow_indigo_shimmer: string
  86. rainbow_violet_shimmer: string
  87. }
  88. export const THEME_NAMES = [
  89. 'dark',
  90. 'light',
  91. 'light-daltonized',
  92. 'dark-daltonized',
  93. 'light-ansi',
  94. 'dark-ansi',
  95. ] as const
  96. /** A renderable theme. Always resolvable to a concrete color palette. */
  97. export type ThemeName = (typeof THEME_NAMES)[number]
  98. export const THEME_SETTINGS = ['auto', ...THEME_NAMES] as const
  99. /**
  100. * A theme preference as stored in user config. `'auto'` follows the system
  101. * dark/light mode and is resolved to a ThemeName at runtime.
  102. */
  103. export type ThemeSetting = (typeof THEME_SETTINGS)[number]
  104. /**
  105. * Light theme using explicit RGB values to avoid inconsistencies
  106. * from users' custom terminal ANSI color definitions
  107. */
  108. const lightTheme: Theme = {
  109. autoAccept: 'rgb(135,0,255)', // Electric violet
  110. bashBorder: 'rgb(255,0,135)', // Vibrant pink
  111. claude: 'rgb(215,119,87)', // Claude orange
  112. claudeShimmer: 'rgb(245,149,117)', // Lighter claude orange for shimmer effect
  113. claudeBlue_FOR_SYSTEM_SPINNER: 'rgb(87,105,247)', // Medium blue for system spinner
  114. claudeBlueShimmer_FOR_SYSTEM_SPINNER: 'rgb(117,135,255)', // Lighter blue for system spinner shimmer
  115. permission: 'rgb(87,105,247)', // Medium blue
  116. permissionShimmer: 'rgb(137,155,255)', // Lighter blue for shimmer effect
  117. planMode: 'rgb(0,102,102)', // Muted teal
  118. ide: 'rgb(71,130,200)', // Muted blue
  119. promptBorder: 'rgb(153,153,153)', // Medium gray
  120. promptBorderShimmer: 'rgb(183,183,183)', // Lighter gray for shimmer effect
  121. text: 'rgb(0,0,0)', // Black
  122. inverseText: 'rgb(255,255,255)', // White
  123. inactive: 'rgb(102,102,102)', // Dark gray
  124. inactiveShimmer: 'rgb(142,142,142)', // Lighter gray for shimmer effect
  125. subtle: 'rgb(175,175,175)', // Light gray
  126. suggestion: 'rgb(87,105,247)', // Medium blue
  127. remember: 'rgb(0,0,255)', // Blue
  128. background: 'rgb(0,153,153)', // Cyan
  129. success: 'rgb(44,122,57)', // Green
  130. error: 'rgb(171,43,63)', // Red
  131. warning: 'rgb(150,108,30)', // Amber
  132. merged: 'rgb(135,0,255)', // Electric violet (matches autoAccept)
  133. warningShimmer: 'rgb(200,158,80)', // Lighter amber for shimmer effect
  134. diffAdded: 'rgb(105,219,124)', // Light green
  135. diffRemoved: 'rgb(255,168,180)', // Light red
  136. diffAddedDimmed: 'rgb(199,225,203)', // Very light green
  137. diffRemovedDimmed: 'rgb(253,210,216)', // Very light red
  138. diffAddedWord: 'rgb(47,157,68)', // Medium green
  139. diffRemovedWord: 'rgb(209,69,75)', // Medium red
  140. // Agent colors
  141. red_FOR_SUBAGENTS_ONLY: 'rgb(220,38,38)', // Red 600
  142. blue_FOR_SUBAGENTS_ONLY: 'rgb(37,99,235)', // Blue 600
  143. green_FOR_SUBAGENTS_ONLY: 'rgb(22,163,74)', // Green 600
  144. yellow_FOR_SUBAGENTS_ONLY: 'rgb(202,138,4)', // Yellow 600
  145. purple_FOR_SUBAGENTS_ONLY: 'rgb(147,51,234)', // Purple 600
  146. orange_FOR_SUBAGENTS_ONLY: 'rgb(234,88,12)', // Orange 600
  147. pink_FOR_SUBAGENTS_ONLY: 'rgb(219,39,119)', // Pink 600
  148. cyan_FOR_SUBAGENTS_ONLY: 'rgb(8,145,178)', // Cyan 600
  149. // Grove colors
  150. professionalBlue: 'rgb(106,155,204)',
  151. // Chrome colors
  152. chromeYellow: 'rgb(251,188,4)', // Chrome yellow
  153. // TUI V2 colors
  154. clawd_body: 'rgb(215,119,87)',
  155. clawd_background: 'rgb(0,0,0)',
  156. userMessageBackground: 'rgb(240, 240, 240)', // Slightly darker grey for optimal contrast
  157. userMessageBackgroundHover: 'rgb(252, 252, 252)', // ≥250 to quantize distinct from base at 256-color level
  158. messageActionsBackground: 'rgb(232, 236, 244)', // cool gray — darker than userMsg 240 (visible on white), slight blue toward `suggestion`
  159. selectionBg: 'rgb(180, 213, 255)', // classic light-mode selection blue (macOS/VS Code-ish); dark fgs stay readable
  160. bashMessageBackgroundColor: 'rgb(250, 245, 250)',
  161. memoryBackgroundColor: 'rgb(230, 245, 250)',
  162. rate_limit_fill: 'rgb(87,105,247)', // Medium blue
  163. rate_limit_empty: 'rgb(39,47,111)', // Dark blue
  164. fastMode: 'rgb(255,106,0)', // Electric orange
  165. fastModeShimmer: 'rgb(255,150,50)', // Lighter orange for shimmer
  166. // Brief/assistant mode
  167. briefLabelYou: 'rgb(37,99,235)', // Blue
  168. briefLabelClaude: 'rgb(215,119,87)', // Brand orange
  169. rainbow_red: 'rgb(235,95,87)',
  170. rainbow_orange: 'rgb(245,139,87)',
  171. rainbow_yellow: 'rgb(250,195,95)',
  172. rainbow_green: 'rgb(145,200,130)',
  173. rainbow_blue: 'rgb(130,170,220)',
  174. rainbow_indigo: 'rgb(155,130,200)',
  175. rainbow_violet: 'rgb(200,130,180)',
  176. rainbow_red_shimmer: 'rgb(250,155,147)',
  177. rainbow_orange_shimmer: 'rgb(255,185,137)',
  178. rainbow_yellow_shimmer: 'rgb(255,225,155)',
  179. rainbow_green_shimmer: 'rgb(185,230,180)',
  180. rainbow_blue_shimmer: 'rgb(180,205,240)',
  181. rainbow_indigo_shimmer: 'rgb(195,180,230)',
  182. rainbow_violet_shimmer: 'rgb(230,180,210)',
  183. }
  184. /**
  185. * Light ANSI theme using only the 16 standard ANSI colors
  186. * for terminals without true color support
  187. */
  188. const lightAnsiTheme: Theme = {
  189. autoAccept: 'ansi:magenta',
  190. bashBorder: 'ansi:magenta',
  191. claude: 'ansi:redBright',
  192. claudeShimmer: 'ansi:yellowBright',
  193. claudeBlue_FOR_SYSTEM_SPINNER: 'ansi:blue',
  194. claudeBlueShimmer_FOR_SYSTEM_SPINNER: 'ansi:blueBright',
  195. permission: 'ansi:blue',
  196. permissionShimmer: 'ansi:blueBright',
  197. planMode: 'ansi:cyan',
  198. ide: 'ansi:blueBright',
  199. promptBorder: 'ansi:white',
  200. promptBorderShimmer: 'ansi:whiteBright',
  201. text: 'ansi:black',
  202. inverseText: 'ansi:white',
  203. inactive: 'ansi:blackBright',
  204. inactiveShimmer: 'ansi:white',
  205. subtle: 'ansi:blackBright',
  206. suggestion: 'ansi:blue',
  207. remember: 'ansi:blue',
  208. background: 'ansi:cyan',
  209. success: 'ansi:green',
  210. error: 'ansi:red',
  211. warning: 'ansi:yellow',
  212. merged: 'ansi:magenta',
  213. warningShimmer: 'ansi:yellowBright',
  214. diffAdded: 'ansi:green',
  215. diffRemoved: 'ansi:red',
  216. diffAddedDimmed: 'ansi:green',
  217. diffRemovedDimmed: 'ansi:red',
  218. diffAddedWord: 'ansi:greenBright',
  219. diffRemovedWord: 'ansi:redBright',
  220. // Agent colors
  221. red_FOR_SUBAGENTS_ONLY: 'ansi:red',
  222. blue_FOR_SUBAGENTS_ONLY: 'ansi:blue',
  223. green_FOR_SUBAGENTS_ONLY: 'ansi:green',
  224. yellow_FOR_SUBAGENTS_ONLY: 'ansi:yellow',
  225. purple_FOR_SUBAGENTS_ONLY: 'ansi:magenta',
  226. orange_FOR_SUBAGENTS_ONLY: 'ansi:redBright',
  227. pink_FOR_SUBAGENTS_ONLY: 'ansi:magentaBright',
  228. cyan_FOR_SUBAGENTS_ONLY: 'ansi:cyan',
  229. // Grove colors
  230. professionalBlue: 'ansi:blueBright',
  231. // Chrome colors
  232. chromeYellow: 'ansi:yellow', // Chrome yellow
  233. // TUI V2 colors
  234. clawd_body: 'ansi:redBright',
  235. clawd_background: 'ansi:black',
  236. userMessageBackground: 'ansi:white',
  237. userMessageBackgroundHover: 'ansi:whiteBright',
  238. messageActionsBackground: 'ansi:white',
  239. selectionBg: 'ansi:cyan', // lighter named bg for light-ansi; dark fgs stay readable
  240. bashMessageBackgroundColor: 'ansi:whiteBright',
  241. memoryBackgroundColor: 'ansi:white',
  242. rate_limit_fill: 'ansi:yellow',
  243. rate_limit_empty: 'ansi:black',
  244. fastMode: 'ansi:red',
  245. fastModeShimmer: 'ansi:redBright',
  246. briefLabelYou: 'ansi:blue',
  247. briefLabelClaude: 'ansi:redBright',
  248. rainbow_red: 'ansi:red',
  249. rainbow_orange: 'ansi:redBright',
  250. rainbow_yellow: 'ansi:yellow',
  251. rainbow_green: 'ansi:green',
  252. rainbow_blue: 'ansi:cyan',
  253. rainbow_indigo: 'ansi:blue',
  254. rainbow_violet: 'ansi:magenta',
  255. rainbow_red_shimmer: 'ansi:redBright',
  256. rainbow_orange_shimmer: 'ansi:yellow',
  257. rainbow_yellow_shimmer: 'ansi:yellowBright',
  258. rainbow_green_shimmer: 'ansi:greenBright',
  259. rainbow_blue_shimmer: 'ansi:cyanBright',
  260. rainbow_indigo_shimmer: 'ansi:blueBright',
  261. rainbow_violet_shimmer: 'ansi:magentaBright',
  262. }
  263. /**
  264. * Dark ANSI theme using only the 16 standard ANSI colors
  265. * for terminals without true color support
  266. */
  267. const darkAnsiTheme: Theme = {
  268. autoAccept: 'ansi:magentaBright',
  269. bashBorder: 'ansi:magentaBright',
  270. claude: 'ansi:redBright',
  271. claudeShimmer: 'ansi:yellowBright',
  272. claudeBlue_FOR_SYSTEM_SPINNER: 'ansi:blueBright',
  273. claudeBlueShimmer_FOR_SYSTEM_SPINNER: 'ansi:blueBright',
  274. permission: 'ansi:blueBright',
  275. permissionShimmer: 'ansi:blueBright',
  276. planMode: 'ansi:cyanBright',
  277. ide: 'ansi:blue',
  278. promptBorder: 'ansi:white',
  279. promptBorderShimmer: 'ansi:whiteBright',
  280. text: 'ansi:whiteBright',
  281. inverseText: 'ansi:black',
  282. inactive: 'ansi:white',
  283. inactiveShimmer: 'ansi:whiteBright',
  284. subtle: 'ansi:white',
  285. suggestion: 'ansi:blueBright',
  286. remember: 'ansi:blueBright',
  287. background: 'ansi:cyanBright',
  288. success: 'ansi:greenBright',
  289. error: 'ansi:redBright',
  290. warning: 'ansi:yellowBright',
  291. merged: 'ansi:magentaBright',
  292. warningShimmer: 'ansi:yellowBright',
  293. diffAdded: 'ansi:green',
  294. diffRemoved: 'ansi:red',
  295. diffAddedDimmed: 'ansi:green',
  296. diffRemovedDimmed: 'ansi:red',
  297. diffAddedWord: 'ansi:greenBright',
  298. diffRemovedWord: 'ansi:redBright',
  299. // Agent colors
  300. red_FOR_SUBAGENTS_ONLY: 'ansi:redBright',
  301. blue_FOR_SUBAGENTS_ONLY: 'ansi:blueBright',
  302. green_FOR_SUBAGENTS_ONLY: 'ansi:greenBright',
  303. yellow_FOR_SUBAGENTS_ONLY: 'ansi:yellowBright',
  304. purple_FOR_SUBAGENTS_ONLY: 'ansi:magentaBright',
  305. orange_FOR_SUBAGENTS_ONLY: 'ansi:redBright',
  306. pink_FOR_SUBAGENTS_ONLY: 'ansi:magentaBright',
  307. cyan_FOR_SUBAGENTS_ONLY: 'ansi:cyanBright',
  308. // Grove colors
  309. professionalBlue: 'rgb(106,155,204)',
  310. // Chrome colors
  311. chromeYellow: 'ansi:yellowBright', // Chrome yellow
  312. // TUI V2 colors
  313. clawd_body: 'ansi:redBright',
  314. clawd_background: 'ansi:black',
  315. userMessageBackground: 'ansi:blackBright',
  316. userMessageBackgroundHover: 'ansi:white',
  317. messageActionsBackground: 'ansi:blackBright',
  318. selectionBg: 'ansi:blue', // darker named bg for dark-ansi; bright fgs stay readable
  319. bashMessageBackgroundColor: 'ansi:black',
  320. memoryBackgroundColor: 'ansi:blackBright',
  321. rate_limit_fill: 'ansi:yellow',
  322. rate_limit_empty: 'ansi:white',
  323. fastMode: 'ansi:redBright',
  324. fastModeShimmer: 'ansi:redBright',
  325. briefLabelYou: 'ansi:blueBright',
  326. briefLabelClaude: 'ansi:redBright',
  327. rainbow_red: 'ansi:red',
  328. rainbow_orange: 'ansi:redBright',
  329. rainbow_yellow: 'ansi:yellow',
  330. rainbow_green: 'ansi:green',
  331. rainbow_blue: 'ansi:cyan',
  332. rainbow_indigo: 'ansi:blue',
  333. rainbow_violet: 'ansi:magenta',
  334. rainbow_red_shimmer: 'ansi:redBright',
  335. rainbow_orange_shimmer: 'ansi:yellow',
  336. rainbow_yellow_shimmer: 'ansi:yellowBright',
  337. rainbow_green_shimmer: 'ansi:greenBright',
  338. rainbow_blue_shimmer: 'ansi:cyanBright',
  339. rainbow_indigo_shimmer: 'ansi:blueBright',
  340. rainbow_violet_shimmer: 'ansi:magentaBright',
  341. }
  342. /**
  343. * Light daltonized theme (color-blind friendly) using explicit RGB values
  344. * to avoid inconsistencies from users' custom terminal ANSI color definitions
  345. */
  346. const lightDaltonizedTheme: Theme = {
  347. autoAccept: 'rgb(135,0,255)', // Electric violet
  348. bashBorder: 'rgb(0,102,204)', // Blue instead of pink
  349. claude: 'rgb(255,153,51)', // Orange adjusted for deuteranopia
  350. claudeShimmer: 'rgb(255,183,101)', // Lighter orange for shimmer effect
  351. claudeBlue_FOR_SYSTEM_SPINNER: 'rgb(51,102,255)', // Bright blue for system spinner
  352. claudeBlueShimmer_FOR_SYSTEM_SPINNER: 'rgb(101,152,255)', // Lighter bright blue for system spinner shimmer
  353. permission: 'rgb(51,102,255)', // Bright blue
  354. permissionShimmer: 'rgb(101,152,255)', // Lighter bright blue for shimmer
  355. planMode: 'rgb(51,102,102)', // Muted blue-gray (works for color-blind)
  356. ide: 'rgb(71,130,200)', // Muted blue
  357. promptBorder: 'rgb(153,153,153)', // Medium gray
  358. promptBorderShimmer: 'rgb(183,183,183)', // Lighter gray for shimmer
  359. text: 'rgb(0,0,0)', // Black
  360. inverseText: 'rgb(255,255,255)', // White
  361. inactive: 'rgb(102,102,102)', // Dark gray
  362. inactiveShimmer: 'rgb(142,142,142)', // Lighter gray for shimmer effect
  363. subtle: 'rgb(175,175,175)', // Light gray
  364. suggestion: 'rgb(51,102,255)', // Bright blue
  365. remember: 'rgb(51,102,255)', // Bright blue
  366. background: 'rgb(0,153,153)', // Cyan (color-blind friendly)
  367. success: 'rgb(0,102,153)', // Blue instead of green for deuteranopia
  368. error: 'rgb(204,0,0)', // Pure red for better distinction
  369. warning: 'rgb(255,153,0)', // Orange adjusted for deuteranopia
  370. merged: 'rgb(135,0,255)', // Electric violet (matches autoAccept)
  371. warningShimmer: 'rgb(255,183,50)', // Lighter orange for shimmer
  372. diffAdded: 'rgb(153,204,255)', // Light blue instead of green
  373. diffRemoved: 'rgb(255,204,204)', // Light red
  374. diffAddedDimmed: 'rgb(209,231,253)', // Very light blue
  375. diffRemovedDimmed: 'rgb(255,233,233)', // Very light red
  376. diffAddedWord: 'rgb(51,102,204)', // Medium blue (less intense than deep blue)
  377. diffRemovedWord: 'rgb(153,51,51)', // Softer red (less intense than deep red)
  378. // Agent colors (daltonism-friendly)
  379. red_FOR_SUBAGENTS_ONLY: 'rgb(204,0,0)', // Pure red
  380. blue_FOR_SUBAGENTS_ONLY: 'rgb(0,102,204)', // Pure blue
  381. green_FOR_SUBAGENTS_ONLY: 'rgb(0,204,0)', // Pure green
  382. yellow_FOR_SUBAGENTS_ONLY: 'rgb(255,204,0)', // Golden yellow
  383. purple_FOR_SUBAGENTS_ONLY: 'rgb(128,0,128)', // True purple
  384. orange_FOR_SUBAGENTS_ONLY: 'rgb(255,128,0)', // True orange
  385. pink_FOR_SUBAGENTS_ONLY: 'rgb(255,102,178)', // Adjusted pink
  386. cyan_FOR_SUBAGENTS_ONLY: 'rgb(0,178,178)', // Adjusted cyan
  387. // Grove colors
  388. professionalBlue: 'rgb(106,155,204)',
  389. // Chrome colors
  390. chromeYellow: 'rgb(251,188,4)', // Chrome yellow
  391. // TUI V2 colors
  392. clawd_body: 'rgb(215,119,87)',
  393. clawd_background: 'rgb(0,0,0)',
  394. userMessageBackground: 'rgb(220, 220, 220)', // Slightly darker grey for optimal contrast
  395. userMessageBackgroundHover: 'rgb(232, 232, 232)', // ≥230 to quantize distinct from base at 256-color level
  396. messageActionsBackground: 'rgb(210, 216, 226)', // cool gray — darker than userMsg 220, slight blue
  397. selectionBg: 'rgb(180, 213, 255)', // light selection blue; daltonized fgs are yellows/blues, both readable on light blue
  398. bashMessageBackgroundColor: 'rgb(250, 245, 250)',
  399. memoryBackgroundColor: 'rgb(230, 245, 250)',
  400. rate_limit_fill: 'rgb(51,102,255)', // Bright blue
  401. rate_limit_empty: 'rgb(23,46,114)', // Dark blue
  402. fastMode: 'rgb(255,106,0)', // Electric orange (color-blind safe)
  403. fastModeShimmer: 'rgb(255,150,50)', // Lighter orange for shimmer
  404. briefLabelYou: 'rgb(37,99,235)', // Blue
  405. briefLabelClaude: 'rgb(255,153,51)', // Orange adjusted for deuteranopia (matches claude)
  406. rainbow_red: 'rgb(235,95,87)',
  407. rainbow_orange: 'rgb(245,139,87)',
  408. rainbow_yellow: 'rgb(250,195,95)',
  409. rainbow_green: 'rgb(145,200,130)',
  410. rainbow_blue: 'rgb(130,170,220)',
  411. rainbow_indigo: 'rgb(155,130,200)',
  412. rainbow_violet: 'rgb(200,130,180)',
  413. rainbow_red_shimmer: 'rgb(250,155,147)',
  414. rainbow_orange_shimmer: 'rgb(255,185,137)',
  415. rainbow_yellow_shimmer: 'rgb(255,225,155)',
  416. rainbow_green_shimmer: 'rgb(185,230,180)',
  417. rainbow_blue_shimmer: 'rgb(180,205,240)',
  418. rainbow_indigo_shimmer: 'rgb(195,180,230)',
  419. rainbow_violet_shimmer: 'rgb(230,180,210)',
  420. }
  421. /**
  422. * Dark theme using explicit RGB values to avoid inconsistencies
  423. * from users' custom terminal ANSI color definitions
  424. */
  425. const darkTheme: Theme = {
  426. autoAccept: 'rgb(175,135,255)', // Electric violet
  427. bashBorder: 'rgb(253,93,177)', // Bright pink
  428. claude: 'rgb(215,119,87)', // Claude orange
  429. claudeShimmer: 'rgb(235,159,127)', // Lighter claude orange for shimmer effect
  430. claudeBlue_FOR_SYSTEM_SPINNER: 'rgb(147,165,255)', // Blue for system spinner
  431. claudeBlueShimmer_FOR_SYSTEM_SPINNER: 'rgb(177,195,255)', // Lighter blue for system spinner shimmer
  432. permission: 'rgb(177,185,249)', // Light blue-purple
  433. permissionShimmer: 'rgb(207,215,255)', // Lighter blue-purple for shimmer
  434. planMode: 'rgb(72,150,140)', // Muted sage green
  435. ide: 'rgb(71,130,200)', // Muted blue
  436. promptBorder: 'rgb(136,136,136)', // Medium gray
  437. promptBorderShimmer: 'rgb(166,166,166)', // Lighter gray for shimmer
  438. text: 'rgb(255,255,255)', // White
  439. inverseText: 'rgb(0,0,0)', // Black
  440. inactive: 'rgb(153,153,153)', // Light gray
  441. inactiveShimmer: 'rgb(193,193,193)', // Lighter gray for shimmer effect
  442. subtle: 'rgb(80,80,80)', // Dark gray
  443. suggestion: 'rgb(177,185,249)', // Light blue-purple
  444. remember: 'rgb(177,185,249)', // Light blue-purple
  445. background: 'rgb(0,204,204)', // Bright cyan
  446. success: 'rgb(78,186,101)', // Bright green
  447. error: 'rgb(255,107,128)', // Bright red
  448. warning: 'rgb(255,193,7)', // Bright amber
  449. merged: 'rgb(175,135,255)', // Electric violet (matches autoAccept)
  450. warningShimmer: 'rgb(255,223,57)', // Lighter amber for shimmer
  451. diffAdded: 'rgb(34,92,43)', // Dark green
  452. diffRemoved: 'rgb(122,41,54)', // Dark red
  453. diffAddedDimmed: 'rgb(71,88,74)', // Very dark green
  454. diffRemovedDimmed: 'rgb(105,72,77)', // Very dark red
  455. diffAddedWord: 'rgb(56,166,96)', // Medium green
  456. diffRemovedWord: 'rgb(179,89,107)', // Softer red (less intense than bright red)
  457. // Agent colors
  458. red_FOR_SUBAGENTS_ONLY: 'rgb(220,38,38)', // Red 600
  459. blue_FOR_SUBAGENTS_ONLY: 'rgb(37,99,235)', // Blue 600
  460. green_FOR_SUBAGENTS_ONLY: 'rgb(22,163,74)', // Green 600
  461. yellow_FOR_SUBAGENTS_ONLY: 'rgb(202,138,4)', // Yellow 600
  462. purple_FOR_SUBAGENTS_ONLY: 'rgb(147,51,234)', // Purple 600
  463. orange_FOR_SUBAGENTS_ONLY: 'rgb(234,88,12)', // Orange 600
  464. pink_FOR_SUBAGENTS_ONLY: 'rgb(219,39,119)', // Pink 600
  465. cyan_FOR_SUBAGENTS_ONLY: 'rgb(8,145,178)', // Cyan 600
  466. // Grove colors
  467. professionalBlue: 'rgb(106,155,204)',
  468. // Chrome colors
  469. chromeYellow: 'rgb(251,188,4)', // Chrome yellow
  470. // TUI V2 colors
  471. clawd_body: 'rgb(215,119,87)',
  472. clawd_background: 'rgb(0,0,0)',
  473. userMessageBackground: 'rgb(55, 55, 55)', // Lighter grey for better visual contrast
  474. userMessageBackgroundHover: 'rgb(70, 70, 70)',
  475. messageActionsBackground: 'rgb(44, 50, 62)', // cool gray, slight blue
  476. selectionBg: 'rgb(38, 79, 120)', // classic dark-mode selection blue (VS Code dark default); light fgs stay readable
  477. bashMessageBackgroundColor: 'rgb(65, 60, 65)',
  478. memoryBackgroundColor: 'rgb(55, 65, 70)',
  479. rate_limit_fill: 'rgb(177,185,249)', // Light blue-purple
  480. rate_limit_empty: 'rgb(80,83,112)', // Medium blue-purple
  481. fastMode: 'rgb(255,120,20)', // Electric orange for dark bg
  482. fastModeShimmer: 'rgb(255,165,70)', // Lighter orange for shimmer
  483. briefLabelYou: 'rgb(122,180,232)', // Light blue
  484. briefLabelClaude: 'rgb(215,119,87)', // Brand orange
  485. rainbow_red: 'rgb(235,95,87)',
  486. rainbow_orange: 'rgb(245,139,87)',
  487. rainbow_yellow: 'rgb(250,195,95)',
  488. rainbow_green: 'rgb(145,200,130)',
  489. rainbow_blue: 'rgb(130,170,220)',
  490. rainbow_indigo: 'rgb(155,130,200)',
  491. rainbow_violet: 'rgb(200,130,180)',
  492. rainbow_red_shimmer: 'rgb(250,155,147)',
  493. rainbow_orange_shimmer: 'rgb(255,185,137)',
  494. rainbow_yellow_shimmer: 'rgb(255,225,155)',
  495. rainbow_green_shimmer: 'rgb(185,230,180)',
  496. rainbow_blue_shimmer: 'rgb(180,205,240)',
  497. rainbow_indigo_shimmer: 'rgb(195,180,230)',
  498. rainbow_violet_shimmer: 'rgb(230,180,210)',
  499. }
  500. /**
  501. * Dark daltonized theme (color-blind friendly) using explicit RGB values
  502. * to avoid inconsistencies from users' custom terminal ANSI color definitions
  503. */
  504. const darkDaltonizedTheme: Theme = {
  505. autoAccept: 'rgb(175,135,255)', // Electric violet
  506. bashBorder: 'rgb(51,153,255)', // Bright blue
  507. claude: 'rgb(255,153,51)', // Orange adjusted for deuteranopia
  508. claudeShimmer: 'rgb(255,183,101)', // Lighter orange for shimmer effect
  509. claudeBlue_FOR_SYSTEM_SPINNER: 'rgb(153,204,255)', // Light blue for system spinner
  510. claudeBlueShimmer_FOR_SYSTEM_SPINNER: 'rgb(183,224,255)', // Lighter blue for system spinner shimmer
  511. permission: 'rgb(153,204,255)', // Light blue
  512. permissionShimmer: 'rgb(183,224,255)', // Lighter blue for shimmer
  513. planMode: 'rgb(102,153,153)', // Muted gray-teal (works for color-blind)
  514. ide: 'rgb(71,130,200)', // Muted blue
  515. promptBorder: 'rgb(136,136,136)', // Medium gray
  516. promptBorderShimmer: 'rgb(166,166,166)', // Lighter gray for shimmer
  517. text: 'rgb(255,255,255)', // White
  518. inverseText: 'rgb(0,0,0)', // Black
  519. inactive: 'rgb(153,153,153)', // Light gray
  520. inactiveShimmer: 'rgb(193,193,193)', // Lighter gray for shimmer effect
  521. subtle: 'rgb(80,80,80)', // Dark gray
  522. suggestion: 'rgb(153,204,255)', // Light blue
  523. remember: 'rgb(153,204,255)', // Light blue
  524. background: 'rgb(0,204,204)', // Bright cyan (color-blind friendly)
  525. success: 'rgb(51,153,255)', // Blue instead of green
  526. error: 'rgb(255,102,102)', // Bright red
  527. warning: 'rgb(255,204,0)', // Yellow-orange for deuteranopia
  528. merged: 'rgb(175,135,255)', // Electric violet (matches autoAccept)
  529. warningShimmer: 'rgb(255,234,50)', // Lighter yellow-orange for shimmer
  530. diffAdded: 'rgb(0,68,102)', // Dark blue
  531. diffRemoved: 'rgb(102,0,0)', // Dark red
  532. diffAddedDimmed: 'rgb(62,81,91)', // Dimmed blue
  533. diffRemovedDimmed: 'rgb(62,44,44)', // Dimmed red
  534. diffAddedWord: 'rgb(0,119,179)', // Medium blue
  535. diffRemovedWord: 'rgb(179,0,0)', // Medium red
  536. // Agent colors (daltonism-friendly, dark mode)
  537. red_FOR_SUBAGENTS_ONLY: 'rgb(255,102,102)', // Bright red
  538. blue_FOR_SUBAGENTS_ONLY: 'rgb(102,178,255)', // Bright blue
  539. green_FOR_SUBAGENTS_ONLY: 'rgb(102,255,102)', // Bright green
  540. yellow_FOR_SUBAGENTS_ONLY: 'rgb(255,255,102)', // Bright yellow
  541. purple_FOR_SUBAGENTS_ONLY: 'rgb(178,102,255)', // Bright purple
  542. orange_FOR_SUBAGENTS_ONLY: 'rgb(255,178,102)', // Bright orange
  543. pink_FOR_SUBAGENTS_ONLY: 'rgb(255,153,204)', // Bright pink
  544. cyan_FOR_SUBAGENTS_ONLY: 'rgb(102,204,204)', // Bright cyan
  545. // Grove colors
  546. professionalBlue: 'rgb(106,155,204)',
  547. // Chrome colors
  548. chromeYellow: 'rgb(251,188,4)', // Chrome yellow
  549. // TUI V2 colors
  550. clawd_body: 'rgb(215,119,87)',
  551. clawd_background: 'rgb(0,0,0)',
  552. userMessageBackground: 'rgb(55, 55, 55)', // Lighter grey for better visual contrast
  553. userMessageBackgroundHover: 'rgb(70, 70, 70)',
  554. messageActionsBackground: 'rgb(44, 50, 62)', // cool gray, slight blue
  555. selectionBg: 'rgb(38, 79, 120)', // classic dark-mode selection blue (VS Code dark default); light fgs stay readable
  556. bashMessageBackgroundColor: 'rgb(65, 60, 65)',
  557. memoryBackgroundColor: 'rgb(55, 65, 70)',
  558. rate_limit_fill: 'rgb(153,204,255)', // Light blue
  559. rate_limit_empty: 'rgb(69,92,115)', // Dark blue
  560. fastMode: 'rgb(255,120,20)', // Electric orange for dark bg (color-blind safe)
  561. fastModeShimmer: 'rgb(255,165,70)', // Lighter orange for shimmer
  562. briefLabelYou: 'rgb(122,180,232)', // Light blue
  563. briefLabelClaude: 'rgb(255,153,51)', // Orange adjusted for deuteranopia (matches claude)
  564. rainbow_red: 'rgb(235,95,87)',
  565. rainbow_orange: 'rgb(245,139,87)',
  566. rainbow_yellow: 'rgb(250,195,95)',
  567. rainbow_green: 'rgb(145,200,130)',
  568. rainbow_blue: 'rgb(130,170,220)',
  569. rainbow_indigo: 'rgb(155,130,200)',
  570. rainbow_violet: 'rgb(200,130,180)',
  571. rainbow_red_shimmer: 'rgb(250,155,147)',
  572. rainbow_orange_shimmer: 'rgb(255,185,137)',
  573. rainbow_yellow_shimmer: 'rgb(255,225,155)',
  574. rainbow_green_shimmer: 'rgb(185,230,180)',
  575. rainbow_blue_shimmer: 'rgb(180,205,240)',
  576. rainbow_indigo_shimmer: 'rgb(195,180,230)',
  577. rainbow_violet_shimmer: 'rgb(230,180,210)',
  578. }
  579. export function getTheme(themeName: ThemeName): Theme {
  580. switch (themeName) {
  581. case 'light':
  582. return lightTheme
  583. case 'light-ansi':
  584. return lightAnsiTheme
  585. case 'dark-ansi':
  586. return darkAnsiTheme
  587. case 'light-daltonized':
  588. return lightDaltonizedTheme
  589. case 'dark-daltonized':
  590. return darkDaltonizedTheme
  591. default:
  592. return darkTheme
  593. }
  594. }
  595. // Create a chalk instance with 256-color level for Apple Terminal
  596. // Apple Terminal doesn't handle 24-bit color escape sequences well
  597. const chalkForChart =
  598. env.terminal === 'Apple_Terminal'
  599. ? new Chalk({ level: 2 }) // 256 colors
  600. : chalk
  601. /**
  602. * Converts a theme color to an ANSI escape sequence for use with asciichart.
  603. * Uses chalk to generate the escape codes, with 256-color mode for Apple Terminal.
  604. */
  605. export function themeColorToAnsi(themeColor: string): string {
  606. const rgbMatch = themeColor.match(/rgb\(\s?(\d+),\s?(\d+),\s?(\d+)\s?\)/)
  607. if (rgbMatch) {
  608. const r = parseInt(rgbMatch[1]!, 10)
  609. const g = parseInt(rgbMatch[2]!, 10)
  610. const b = parseInt(rgbMatch[3]!, 10)
  611. // Use chalk.rgb which auto-converts to 256 colors when level is 2
  612. // Extract just the opening escape sequence by using a marker
  613. const colored = chalkForChart.rgb(r, g, b)('X')
  614. return colored.slice(0, colored.indexOf('X'))
  615. }
  616. // Fallback to magenta if parsing fails
  617. return '\x1b[35m'
  618. }