From 41add74a0846af5ef0cef209d0fe4c92db4f96b0 Mon Sep 17 00:00:00 2001 From: Robert V Hudson <42922131+zhangqinzhong@users.noreply.github.com> Date: Tue, 23 Jun 2026 05:53:34 +0800 Subject: [PATCH] fix: improve terminal contrast in light themes (Tango Light + xterm minimumContrastRatio) (#5986) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: darken Builtin Tango Light ANSI colors for readability Nine ANSI colors had contrast ratios below 3:1 against the white background, making CLI output unreadable in light mode. Darkened to readable Tango shades while keeping the warm palette identity. Co-Authored-By: Claude * fix: enable xterm minimumContrastRatio and add light theme tests xterm.js minimumContrastRatio (4.5) auto-adjusts low-contrast ANSI foreground colors at render time — a safety net for all themes, including custom imports. Added test coverage for this option and for the Tango Light ANSI color contrast assertions. Co-Authored-By: Claude * chore: trigger CI re-run --------- Co-authored-by: zhangqinzhong Co-authored-by: Claude --- .../lib/pane-manager/pane-lifecycle.test.ts | 4 ++++ .../lib/pane-manager/pane-terminal-options.ts | 3 +++ src/renderer/src/lib/terminal-theme.test.ts | 20 +++++++++++++++++++ .../src/lib/terminal-themes/defaults.ts | 18 +++++++++-------- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/renderer/src/lib/pane-manager/pane-lifecycle.test.ts b/src/renderer/src/lib/pane-manager/pane-lifecycle.test.ts index c1347f16ce8..25174f917bf 100644 --- a/src/renderer/src/lib/pane-manager/pane-lifecycle.test.ts +++ b/src/renderer/src/lib/pane-manager/pane-lifecycle.test.ts @@ -83,6 +83,10 @@ describe('buildDefaultTerminalOptions', () => { expect(buildDefaultTerminalOptions().scrollbar?.width).toBe(7) }) + it('enables xterm contrast correction for low-contrast CLI colors', () => { + expect(buildDefaultTerminalOptions().minimumContrastRatio).toBe(4.5) + }) + it('only uses inactive outline for block cursors', () => { expect(resolveTerminalCursorInactiveStyle('block')).toBe('outline') expect(resolveTerminalCursorInactiveStyle('bar')).toBe('bar') diff --git a/src/renderer/src/lib/pane-manager/pane-terminal-options.ts b/src/renderer/src/lib/pane-manager/pane-terminal-options.ts index 2be964e07b1..82418eaff4a 100644 --- a/src/renderer/src/lib/pane-manager/pane-terminal-options.ts +++ b/src/renderer/src/lib/pane-manager/pane-terminal-options.ts @@ -27,6 +27,9 @@ export function buildDefaultTerminalOptions(): ITerminalOptions { fontWeightBold: '500', scrollback: 10000, allowTransparency: false, + // Why: agent CLIs sometimes render body text with ANSI white/bright-white + // on light themes; xterm can keep those cells readable across renderers. + minimumContrastRatio: 4.5, // Why: on macOS, non-US layouts rely on Option to compose characters like @ and €. macOptionIsMeta: false, macOptionClickForcesSelection: true, diff --git a/src/renderer/src/lib/terminal-theme.test.ts b/src/renderer/src/lib/terminal-theme.test.ts index 2c09bb36825..f0211797bd6 100644 --- a/src/renderer/src/lib/terminal-theme.test.ts +++ b/src/renderer/src/lib/terminal-theme.test.ts @@ -261,6 +261,26 @@ describe('default dark terminal theme selection contrast', () => { }) }) +describe('default light terminal theme ANSI contrast', () => { + it('keeps CLI body/header ANSI colors readable on the terminal background', () => { + const theme = getBuiltinTheme(DEFAULT_TERMINAL_THEME_LIGHT) + + expect(theme, `${DEFAULT_TERMINAL_THEME_LIGHT} should exist`).not.toBeNull() + if (!theme?.background) { + throw new Error(`${DEFAULT_TERMINAL_THEME_LIGHT} is missing a background color`) + } + + for (const key of ['cyan', 'white', 'brightCyan', 'brightWhite'] as const) { + const color = theme[key] + expect(color, `${DEFAULT_TERMINAL_THEME_LIGHT}.${key} should be defined`).toBeDefined() + if (!color) { + throw new Error(`${DEFAULT_TERMINAL_THEME_LIGHT}.${key} is missing`) + } + expect(contrastRatio(color, theme.background)).toBeGreaterThanOrEqual(4.5) + } + }) +}) + describe('isTerminalBackgroundLight', () => { it('classifies common terminal background color formats by luminance', () => { const split = vi.spyOn(String.prototype, 'split') diff --git a/src/renderer/src/lib/terminal-themes/defaults.ts b/src/renderer/src/lib/terminal-themes/defaults.ts index 003d4732b19..fa0a8ef4c28 100644 --- a/src/renderer/src/lib/terminal-themes/defaults.ts +++ b/src/renderer/src/lib/terminal-themes/defaults.ts @@ -38,18 +38,20 @@ export const DEFAULT_TERMINAL_THEMES: TerminalThemeMap = { black: '#2e3436', red: '#cc0000', green: '#4e9a06', - yellow: '#c4a000', + // Why: Claude-style previews use ANSI accent colors for readable text, + // so the light theme cannot keep Tango's near-white legacy values. + yellow: '#8e7700', blue: '#3465a4', magenta: '#75507b', - cyan: '#06989a', - white: '#d3d7cf', + cyan: '#05727e', + white: '#6a6a6a', brightBlack: '#555753', brightRed: '#ef2929', - brightGreen: '#8ae234', - brightYellow: '#fce94f', - brightBlue: '#729fcf', + brightGreen: '#1b7a1b', + brightYellow: '#6d5a00', + brightBlue: '#204a87', brightMagenta: '#ad7fa8', - brightCyan: '#34e2e2', - brightWhite: '#eeeeec' + brightCyan: '#034b50', + brightWhite: '#3d3d3d' } }