diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx index 88b9616b0..ed77e04b4 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx @@ -169,6 +169,9 @@ function resolveTheme(theme: ThemeJson, mode: "dark" | "light") { throw new Error(`Color reference "${c}" not found in defs or theme`) } } + if (typeof c === "number") { + return ansiToRgba(c) + } return resolveColor(c[mode]) } @@ -203,6 +206,51 @@ function resolveTheme(theme: ThemeJson, mode: "dark" | "light") { } as Theme } +function ansiToRgba(code: number): RGBA { + // Standard ANSI colors (0-15) + if (code < 16) { + const ansiColors = [ + "#000000", // Black + "#800000", // Red + "#008000", // Green + "#808000", // Yellow + "#000080", // Blue + "#800080", // Magenta + "#008080", // Cyan + "#c0c0c0", // White + "#808080", // Bright Black + "#ff0000", // Bright Red + "#00ff00", // Bright Green + "#ffff00", // Bright Yellow + "#0000ff", // Bright Blue + "#ff00ff", // Bright Magenta + "#00ffff", // Bright Cyan + "#ffffff", // Bright White + ] + return RGBA.fromHex(ansiColors[code] ?? "#000000") + } + + // 6x6x6 Color Cube (16-231) + if (code < 232) { + const index = code - 16 + const b = index % 6 + const g = Math.floor(index / 6) % 6 + const r = Math.floor(index / 36) + + const val = (x: number) => (x === 0 ? 0 : x * 40 + 55) + return RGBA.fromInts(val(r), val(g), val(b)) + } + + // Grayscale Ramp (232-255) + if (code < 256) { + const gray = (code - 232) * 10 + 8 + return RGBA.fromInts(gray, gray, gray) + } + + // Fallback for invalid codes + return RGBA.fromInts(0, 0, 0) +} + export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ name: "Theme", init: (props: { mode: "dark" | "light" }) => {