/** * Letta Code Color System * * This file defines all colors used in the application. * No colors should be hardcoded in components - all should reference this file. */ import { getTerminalTheme } from "../helpers/terminalTheme"; /** * Parse a hex color (#RRGGBB) to RGB components. */ function parseHex(hex: string): { r: number; g: number; b: number } { const h = hex.replace("#", ""); return { r: parseInt(h.slice(0, 2), 16), g: parseInt(h.slice(2, 4), 16), b: parseInt(h.slice(4, 6), 16), }; } /** * Convert a hex color (#RRGGBB) to an ANSI 24-bit background escape sequence. */ export function hexToBgAnsi(hex: string): string { const { r, g, b } = parseHex(hex); return `\x1b[48;2;${r};${g};${b}m`; } /** * Convert a hex color (#RRGGBB) to an ANSI 24-bit foreground escape sequence. */ export function hexToFgAnsi(hex: string): string { const { r, g, b } = parseHex(hex); return `\x1b[38;2;${r};${g};${b}m`; } // Brand colors (dark mode) export const brandColors = { orange: "#FF5533", // dark orange blue: "#0707AC", // dark blue // text colors primaryAccent: "#8C8CF9", // lighter blue primaryAccentLight: "#BEBEEE", // even lighter blue textMain: "#DEE1E4", // white textSecondary: "#A5A8AB", // light grey textDisabled: "#46484A", // dark grey // status colors statusSuccess: "#64CF64", // green statusWarning: "#FEE19C", // yellow statusError: "#F1689F", // red } as const; // Brand colors (light mode) export const brandColorsLight = { orange: "#FF5533", // dark orange blue: "#0707AC", // dark blue // text colors primaryAccent: "#3939BD", // lighter blue primaryAccentLight: "#A9A9DE", // even lighter blue textMain: "#202020", // white textSecondary: "#797B7D", // light grey textDisabled: "#A5A8AB", // dark grey // status colors statusSuccess: "#28A428", // green statusWarning: "#B98813", // yellow statusError: "#BA024C", // red } as const; // Semantic color system const _colors = { // Welcome screen welcome: { border: brandColors.primaryAccent, accent: brandColors.primaryAccent, }, // Selector boxes (model, agent, generic select) selector: { border: brandColors.primaryAccentLight, title: brandColors.primaryAccentLight, itemHighlighted: brandColors.primaryAccent, itemCurrent: brandColors.statusSuccess, // for "(current)" label }, // Command autocomplete and command messages command: { selected: brandColors.primaryAccent, inactive: brandColors.textDisabled, // uses dimColor prop border: brandColors.textDisabled, running: brandColors.textSecondary, error: brandColors.statusError, }, // Approval/HITL screens approval: { border: brandColors.primaryAccentLight, header: brandColors.primaryAccent, }, // Code and markdown elements (use terminal theme colors) code: { inline: "green", }, link: { text: brandColors.primaryAccentLight, url: brandColors.primaryAccent, }, heading: { primary: "cyan", secondary: brandColors.primaryAccent, }, // Status indicators status: { error: brandColors.statusError, success: brandColors.statusSuccess, interrupt: brandColors.statusError, processing: brandColors.primaryAccent, // base text color processingShimmer: brandColors.primaryAccentLight, // shimmer highlight }, // Tool calls tool: { pending: brandColors.textSecondary, // blinking dot (ready/waiting for approval) completed: brandColors.statusSuccess, // solid green dot (finished successfully) streaming: brandColors.textSecondary, // solid gray dot (streaming/in progress) running: brandColors.textSecondary, // blinking gray dot (executing) error: brandColors.statusError, // solid red dot (failed) memoryName: brandColors.primaryAccent, // memory tool name highlight (matches thinking spinner) }, // Input box input: { border: brandColors.textDisabled, prompt: brandColors.textMain, }, // Bash mode bash: { prompt: brandColors.statusError, // Red ! prompt border: brandColors.statusError, // Red horizontal bars dot: brandColors.statusError, // Red dot in output }, // Shell command syntax highlighting shellSyntaxDark: { prompt: "#cba6f7", text: "#cdd6f4", comment: "#6c7086", keyword: "#89b4fa", string: "#a6e3a1", number: "#fab387", literal: "#fab387", builtIn: "#f9e2af", variable: "#f5c2e7", title: "#94e2d5", attr: "#74c7ec", operator: "#bac2de", punctuation: "#bac2de", meta: "#f38ba8", substitution: "#f5c2e7", }, shellSyntaxLight: { prompt: "#8839ef", text: "#4c4f69", comment: "#9ca0b0", keyword: "#1e66f5", string: "#40a02b", number: "#fe640b", literal: "#fe640b", builtIn: "#df8e1d", variable: "#ea76cb", title: "#179299", attr: "#209fb5", operator: "#5c5f77", punctuation: "#5c5f77", meta: "#d20f39", substitution: "#e64553", }, // Todo list todo: { completed: brandColors.primaryAccent, // Same blue as in-progress, with strikethrough inProgress: brandColors.primaryAccent, }, // Subagent display subagent: { header: brandColors.primaryAccent, running: brandColors.statusWarning, completed: brandColors.statusSuccess, error: brandColors.statusError, treeChar: brandColors.textSecondary, hint: "#808080", // Grey to match Ink's dimColor }, // Background subagent bgSubagent: { label: "#87af87", spinner: "#5faf5f", }, // Info/modal views info: { border: brandColors.primaryAccent, prompt: brandColors.primaryAccent, }, // Diff rendering (line bg palette matches Codex CLI dark theme, see // ~/dev/codex/codex-rs/tui/src/diff_render.rs lines 60-61) diff: { addedLineBg: "#213A2B", removedLineBg: "#4A221D", contextLineBg: undefined, // Word-level highlight colors (used by MemoryDiffRenderer) addedWordBg: "#2d7a2d", removedWordBg: "#7a2d2d", textOnDark: "white", textOnHighlight: "white", symbolAdd: "green", symbolRemove: "red", symbolContext: undefined, }, // Error display error: { border: "red", text: "red", }, // Generic text colors (used with dimColor prop or general text) text: { normal: "white", dim: "gray", bold: "white", }, // Footer bar footer: { agentName: brandColors.primaryAccent, }, // Context window breakdown categories contextBreakdown: { system: "#E07050", // coral-red coreMemory: "#E0A040", // amber tools: "#20B2AA", // turquoise messages: "#8C8CF9", // brand purple summaryMemory: "#D0B060", // gold other: "#A0A0A0", // light grey }, } as const; // Combine static colors with theme-aware dynamic properties export const colors = { ..._colors, get shellSyntax() { return getTerminalTheme() === "light" ? _colors.shellSyntaxLight : _colors.shellSyntaxDark; }, // User messages (past prompts) - theme-aware background // Uses getter to read theme at render time (after async init) get userMessage() { const theme = getTerminalTheme(); return { background: theme === "light" ? "#dcddf2" : "#2d2d2d", // light purple for light, subtle gray for dark text: undefined, // use default terminal text color }; }, };