fix(ui-tui): a skin owns the terminal's DEFAULT foreground (OSC-10) — kills the invisible-text class - #69632
Merged
Merged
Conversation
…ide the OSC-11 background The input fix's sibling, hit immediately after: the composer was themed but AGENT text went black-on-black the same way. Root cause is the class, not the call site — markdown body, borders, and every token rendered without an explicit color falls back to the terminal's DEFAULT foreground, which belongs to the HOST profile's polarity, not the skin's. A dark skin on a light terminal repaints the backdrop via OSC-11 while thousands of default-fg cells stay near-black. Chasing every <Text> is unwinnable. Instead own the default itself: when a skin authors a background (the existing opt-in), paint the default foreground from the resolved theme's text color via OSC-10. Every unthemed token — present and future — re-bases onto the skin atomically, exactly like the background. terminalModes: the OSC-11 slot generalizes to defaultColorSlot(10|11) — same paint/clear/exit-restore contract, tracked per slot, so a skinless session still never touches the terminal. reapplyTheme repaints the fg too: polarity flips swap paired palettes, moving the text tone while the background stays. Tests: slot contract runs table-driven over both OSC codes; handler test pins the invariant (default fg == theme text; dropping the background releases both defaults). Suite 1344✓, typecheck/lint/prettier clean.
Contributor
૮ >ﻌ< ა ci reviewrunning on 1f65221 CI timingsCI timings · View jobWall time 7m28s vs 8m10s (-8.6%). 3 job(s) slower, 3 faster, 1 unchanged.
|
OutThisLife
enabled auto-merge
July 22, 2026 21:33
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
…nal-default-fg fix(ui-tui): a skin owns the terminal's DEFAULT foreground (OSC-10) — kills the invisible-text class
33hodl
pushed a commit
to 33hodl/hermes-agent
that referenced
this pull request
Aug 12, 2026
…nal-default-fg fix(ui-tui): a skin owns the terminal's DEFAULT foreground (OSC-10) — kills the invisible-text class
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.
Follow-up to #69616, hit one demo later: composer themed, but the agent's response body went black-on-black the same way. Same class, different call site — and the class is the thing to kill.
The class
The skin repaints the terminal background via OSC-11, but every token rendered without an explicit color — markdown body, borders, anything default-fg — falls back to the terminal's default foreground, which belongs to the HOST profile's polarity, not the skin's. Dark skin + light terminal ⇒ near-black text on pure black. Everything the theming engine explicitly paints (headers, accents, status colors, the placeholder) flips perfectly; the hole is precisely the tokens it doesn't paint. Chasing every
<Text>(what #69616 did for the input) is unwinnable one call site at a time.Fix — own the default itself
When a skin authors a
background(the existing opt-in),applySkinnow paints the terminal's default foreground from the resolved theme's text color via OSC-10, beside the OSC-11 background it already painted. Every default-fg token — present and future — re-bases onto the skin atomically, exactly like the background. No skin background ⇒ both defaults restore to the terminal's own; a skinless session never touches the terminal.terminalModes: the OSC-11 background slot generalizes todefaultColorSlot(10 | 11)— one paint/clear/exit-restore contract, painted-state tracked per slot, exit reset appends only what was actually painted.reapplyThemerepaints the fg too: polarity flips swap paired palettes, moving the text tone while the skin's background stays put.#69616's explicit input theming stays on top — the composer is first-class themed, not merely default-correct.Tests
terminalModes— the slot contract runs table-driven over both OSC codes: paint from hex, ignore junk/non-TTY, exit-reset restores only-if-painted, dropping the color releases the defaultcreateGatewayEventHandler— the invariant: a skin owning the background paints both defaults,fg == theme.color.text; dropping the background releases both (OSC-110 + OSC-111)