Light themes for dark-painted TUIs, and color-scheme reporting - #65
Merged
Merged
Conversation
Programs with an automatic theme (Claude Code's Auto, Neovim) can detect light or dark through the color-scheme query and mode 2031, but the shim never installed the color-scheme callback: CSI ? 996 n went unanswered, and DECRQM reported mode 2031 as supported while no change report was ever sent. A theme switch left those programs on the old scheme. The shim now derives the scheme from the default background (light when dark text out-contrasts light text), answers CSI ? 996 n with it, and queues CSI ? 997 ; 1|2 n on the PTY response path when a theme change flips the scheme and the program enabled mode 2031. New sessions also get COLORFGBG unless the caller set one, for programs that read it at startup. Verified against a live daemon: Claude Code's Auto preview now follows a mid-session theme reload; with the previous binary it stayed dark. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Applications that paint every cell with their own background ignore the terminal theme; Grok's default theme fills the screen with #141414, so a light theme never shows. Under a light theme, the WebGPU renderer now remaps a pane when at least 60% of its cells carry an explicit dark background (released below 35% to avoid flicker), so programs that follow the theme are never touched. The remap runs per style in resolveStyle, before blending, leaving glyph coverage, color glyphs, and the shader stack alone. Surfaces mirror their toe-corrected OKLab lightness around the theme background, neutral ink keeps its distance from its cell background, and accents land in an APCA mid-tone band with their hue kept. Block elements use the surface mapping so art seams line up. Against each app's own light design this measured mean ink ΔE 3.1 (Grok), 3.3 (Codex), 3.7 (OpenCode), versus 5.0, 10.1, and 5.5 for a full-screen invert. Configuration defaults TerminalTheme.lightAdaptation to "auto"; embedders can pass "off" through the workspace theme override. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rust 1.99.0 (2026-09-28) added clippy::double_must_use, which fires on the code async-trait 0.1.89 generates for the mesh traits, so the required verify and windows gates fail under `-D warnings` on any branch. 0.1.92 no longer emits the redundant attribute. It and its new syn 3 dependency need Rust 1.71, inside the workspace's 1.88 minimum. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…entory async-trait is not in the aarch64-apple-ios graph, so the reviewed components are unchanged; only the Cargo.lock digest and the BOM and resource hashes derived from it move. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
With a light ghosttea theme, several agent TUIs stay dark or half-broken:
#141414on every cell, so the terminal background never shows. Itsautotheme follows the macOS appearance, not the terminal.A probe showed
CSI ? 996 ngoing unanswered and DECRQM claiming mode 2031 support while noCSI ? 997 nwas ever sent.What changes
feat(terminal): report the color schemeCSI ? 996 n, and queuesCSI ? 997 ; 1|2 nwhen a theme change flips the scheme and the program enabled mode 2031.COLORFGBG(0;15/15;0) unless the caller set one.feat(react): adapt dark-painted panes to light themesrenderers/light-adaptation.ts, applied per style inresolveStylebefore blending. Glyph coverage, color glyphs and the shader stack are untouched.TerminalTheme.lightAdaptationdefaults to"auto"from configuration; embedders can pass"off"through the workspacethemeoverride.The rules come from capturing each app's dark and own-light screens through a private
ghostteadand scoring candidate remaps against them. Mean ink ΔE against each app's own light design (lower is better):A full-screen invert also flips hue: Grok's amber accent turns blue and Claude's red diff rows turn cyan.
Verification
ghosttea-vt(996 reply, 2031 reports only on a scheme flip),ghosttea-core(theme change emits the report asWriteToTransport),ghosttea(COLORFGBGhint yields to the caller),light-adaptation.test.ts(parity with the measured colors, engagement thresholds, hysteresis, opt-out).ghosttea-react: tsc, eslint, prettier, and 275 vitest tests pass. Theghosttea-vt,ghosttea-coreandghostteasuites pass.WebGpuTerminalRendererrender light with the card border, gray hierarchy and amber accent intact.service::protocol_tests::closing_a_session_records_why_it_endedis flaky here. It failed 1 of 4 runs on unmodifiedmaintoo.CI notes
chore(deps)commit: Rust 1.99.0 (2026-09-28) addedclippy::double_must_use, which fires on code generated byasync-trait0.1.89 inmesh.rs. That broke the requiredverifyandwindowsgates for every branch.async-trait0.1.92 fixes it; it andsyn3 need Rust 1.71, inside our 1.88 minimum.audit-published: expected to fail. This PR changes native sources, so the pinned Apple native artifact predates them until the next release rebuilds and pins it.dependency-audit: new npm advisories (vitest, electron, undici, brace-expansion). This is unrelated and fails onmaintoo.Not in this PR
lightAdaptation.minimum-contrast.🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.