Repository navigation
mux-tui: light-theme-aware chrome adapts to host background - #7648
Conversation
In light-background terminals the TUI chrome (context menu, status bar, tab bar, sidebar selection, prompt, omnibar) rendered hardcoded dark ANSI indices and clashed badly. The terminal already probes host fg/bg via OSC 10/11; the chrome now uses it. ChromeTheme::dark() reproduces the previous hardcoded indices exactly (dark terminals render byte-identically); ChromeTheme::light() is a curated light palette. Selection is by host-bg luminance at startup, overridable via theme.chrome: auto|light|dark (default auto; probe failure keeps dark). Explicit config colors (tab_bg, tab_active_bg, sidebar_active_bg, borders) still win. Terminal content rendering and resolve_palette_color are untouched.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughAdds chrome theme resolution and override tracking in ChangesChrome theme system
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (4 errors, 1 warning)
✅ Passed checks (20 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR introduces a
Confidence Score: 5/5Safe to merge — purely presentational chrome theming with no changes to terminal content rendering, auth, or data paths; dark terminals render byte-identically to the previous code. Every hardcoded color index substitution is mechanical and independently testable. The override priority logic (explicit Ghostty/mux.json colors win over chrome defaults) is consistently applied across all call sites and covered by the new tests. The chrome is computed once at startup from an already-probed value and stored on App, so there is no concurrency concern. The intentional limitation — chrome mode changes in mux.json require a restart — is documented in the PR and doesn't introduce incorrect behavior. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[main::run_tui] -->|probe OSC 10/11| B[DefaultColors]
B --> C[app::run]
C --> D[config::load]
D --> E[Config\nchrome: ChromeMode\ntheme_overrides: ThemeOverrides]
C --> F{ChromeTheme::for_defaults\nconfig.chrome + DefaultColors.bg}
F -->|Auto + luminance > 128| G[ChromeTheme::light]
F -->|Auto + luminance ≤ 128 or bg=None| H[ChromeTheme::dark]
F -->|Light override| G
F -->|Dark override| H
G --> I[config.apply_chrome_defaults\nfills selection_bg/fg\nif !theme_overrides.selection]
H --> I
I --> J[App\nchrome: ChromeTheme\nconfig: Config]
J -->|render| K[UI modules\nread app.chrome.*\nchecking theme_overrides at call site]
J -->|reload_config| L[new Config loaded\napply_chrome_defaults with same chrome\nself.chrome unchanged]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[main::run_tui] -->|probe OSC 10/11| B[DefaultColors]
B --> C[app::run]
C --> D[config::load]
D --> E[Config\nchrome: ChromeMode\ntheme_overrides: ThemeOverrides]
C --> F{ChromeTheme::for_defaults\nconfig.chrome + DefaultColors.bg}
F -->|Auto + luminance > 128| G[ChromeTheme::light]
F -->|Auto + luminance ≤ 128 or bg=None| H[ChromeTheme::dark]
F -->|Light override| G
F -->|Dark override| H
G --> I[config.apply_chrome_defaults\nfills selection_bg/fg\nif !theme_overrides.selection]
H --> I
I --> J[App\nchrome: ChromeTheme\nconfig: Config]
J -->|render| K[UI modules\nread app.chrome.*\nchecking theme_overrides at call site]
J -->|reload_config| L[new Config loaded\napply_chrome_defaults with same chrome\nself.chrome unchanged]
Reviews (3): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile |
| } | ||
| } | ||
|
|
||
| pub fn is_light_background(bg: Rgb) -> bool { |
There was a problem hiding this comment.
is_light_background is pub but is only used within this file — in for_defaults and the in-file test module. Rust test modules with use super::* can access non-pub items in the parent module, so no external visibility is needed. Exposing it as pub widens the crate's API surface unnecessarily; pub(crate) scopes it to the crate if other modules ever need it, or it can remain private.
| pub fn is_light_background(bg: Rgb) -> bool { | |
| pub(crate) fn is_light_background(bg: Rgb) -> bool { |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| menu_bg: Color::Indexed(254), | ||
| menu_fg: Color::Indexed(236), | ||
| menu_border: Color::Indexed(246), | ||
| menu_selected_bg: Color::Indexed(252), |
There was a problem hiding this comment.
sidebar_dim_fg identical across both palettes
sidebar_dim_fg is Color::Indexed(242) (≈ #6c6c6c) in both dark() and light(). On a dark background this reads as a subtle dim, but on the light sidebar background (sidebar_selected_bg: Indexed(253) ≈ #dadada base), index 242 against a surrounding background of ~254 yields a contrast ratio below 3:1, making dim labels hard to read. A lighter index in the 238–240 range would improve legibility on light backgrounds without clashing on the dark side.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@mux/crates/mux-tui/src/config.rs`:
- Around line 1047-1062: The regression test in
dark_chrome_matches_legacy_indices only validates a small subset of
ChromeTheme::dark() and can miss legacy-color drift. Expand the assertions in
that test to cover the remaining important fields on ChromeTheme, especially
border_active_fg plus the omitted menu_*, prompt_*, tab_plain_*, and omnibar_*
foreground/background values, so any future change to dark() breaks the legacy
parity lock.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: d3736b75-5dae-4391-b99e-f9d55f396738
📒 Files selected for processing (8)
mux/crates/mux-tui/src/app.rsmux/crates/mux-tui/src/config.rsmux/crates/mux-tui/src/main.rsmux/crates/mux-tui/src/ui/mod.rsmux/crates/mux-tui/src/ui/omnibar.rsmux/crates/mux-tui/src/ui/overlay.rsmux/crates/mux-tui/src/ui/pane.rsmux/crates/mux-tui/src/ui/sidebar.rs
| #[test] | ||
| fn dark_chrome_matches_legacy_indices() { | ||
| let chrome = ChromeTheme::dark(); | ||
| assert_eq!(chrome.menu_bg, Color::Indexed(237)); | ||
| assert_eq!(chrome.menu_selected_bg, Color::Indexed(242)); | ||
| assert_eq!(chrome.prompt_bg, Color::Indexed(236)); | ||
| assert_eq!(chrome.status_bg, Color::Indexed(236)); | ||
| assert_eq!(chrome.status_active_bg, Color::Indexed(240)); | ||
| assert_eq!(chrome.tab_bar_bg, Color::Indexed(236)); | ||
| assert_eq!(chrome.tab_active_bg, Color::Indexed(240)); | ||
| assert_eq!(chrome.tab_active_unfocused_bg, Color::Indexed(238)); | ||
| assert_eq!(chrome.sidebar_selected_bg, Color::Indexed(236)); | ||
| assert_eq!(chrome.omnibar_edit_bg, Color::Indexed(236)); | ||
| assert_eq!(chrome.border_fg, Color::Indexed(238)); | ||
| assert_eq!(chrome.scrollbar_thumb_active_fg, Color::Indexed(252)); | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Regression-lock test only covers a quarter of ChromeTheme::dark() fields.
dark_chrome_matches_legacy_indices is meant to lock in legacy indexed-color parity, but it only asserts 12 of the struct's 44 color fields. Notably border_active_fg (Indexed(110), the focused-pane border — one of the most visually prominent colors) isn't checked, along with most menu_*, prompt_*, tab_plain_*, and omnibar_* foregrounds. A future edit to dark() could silently change legacy appearance without failing this test.
♻️ Suggested additional assertions
#[test]
fn dark_chrome_matches_legacy_indices() {
let chrome = ChromeTheme::dark();
assert_eq!(chrome.menu_bg, Color::Indexed(237));
assert_eq!(chrome.menu_selected_bg, Color::Indexed(242));
assert_eq!(chrome.prompt_bg, Color::Indexed(236));
+ assert_eq!(chrome.border_active_fg, Color::Indexed(110));
+ assert_eq!(chrome.omnibar_edit_fg, Color::Indexed(252));
+ assert_eq!(chrome.sidebar_border, Color::Indexed(237));
assert_eq!(chrome.status_bg, Color::Indexed(236));
assert_eq!(chrome.status_active_bg, Color::Indexed(240));
assert_eq!(chrome.tab_bar_bg, Color::Indexed(236));📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #[test] | |
| fn dark_chrome_matches_legacy_indices() { | |
| let chrome = ChromeTheme::dark(); | |
| assert_eq!(chrome.menu_bg, Color::Indexed(237)); | |
| assert_eq!(chrome.menu_selected_bg, Color::Indexed(242)); | |
| assert_eq!(chrome.prompt_bg, Color::Indexed(236)); | |
| assert_eq!(chrome.status_bg, Color::Indexed(236)); | |
| assert_eq!(chrome.status_active_bg, Color::Indexed(240)); | |
| assert_eq!(chrome.tab_bar_bg, Color::Indexed(236)); | |
| assert_eq!(chrome.tab_active_bg, Color::Indexed(240)); | |
| assert_eq!(chrome.tab_active_unfocused_bg, Color::Indexed(238)); | |
| assert_eq!(chrome.sidebar_selected_bg, Color::Indexed(236)); | |
| assert_eq!(chrome.omnibar_edit_bg, Color::Indexed(236)); | |
| assert_eq!(chrome.border_fg, Color::Indexed(238)); | |
| assert_eq!(chrome.scrollbar_thumb_active_fg, Color::Indexed(252)); | |
| } | |
| #[test] | |
| fn dark_chrome_matches_legacy_indices() { | |
| let chrome = ChromeTheme::dark(); | |
| assert_eq!(chrome.menu_bg, Color::Indexed(237)); | |
| assert_eq!(chrome.menu_selected_bg, Color::Indexed(242)); | |
| assert_eq!(chrome.prompt_bg, Color::Indexed(236)); | |
| assert_eq!(chrome.border_active_fg, Color::Indexed(110)); | |
| assert_eq!(chrome.omnibar_edit_fg, Color::Indexed(252)); | |
| assert_eq!(chrome.sidebar_border, Color::Indexed(237)); | |
| assert_eq!(chrome.status_bg, Color::Indexed(236)); | |
| assert_eq!(chrome.status_active_bg, Color::Indexed(240)); | |
| assert_eq!(chrome.tab_bar_bg, Color::Indexed(236)); | |
| assert_eq!(chrome.tab_active_bg, Color::Indexed(240)); | |
| assert_eq!(chrome.tab_active_unfocused_bg, Color::Indexed(238)); | |
| assert_eq!(chrome.sidebar_selected_bg, Color::Indexed(236)); | |
| assert_eq!(chrome.omnibar_edit_bg, Color::Indexed(236)); | |
| assert_eq!(chrome.border_fg, Color::Indexed(238)); | |
| assert_eq!(chrome.scrollbar_thumb_active_fg, Color::Indexed(252)); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@mux/crates/mux-tui/src/config.rs` around lines 1047 - 1062, The regression
test in dark_chrome_matches_legacy_indices only validates a small subset of
ChromeTheme::dark() and can miss legacy-color drift. Expand the assertions in
that test to cover the remaining important fields on ChromeTheme, especially
border_active_fg plus the omitted menu_*, prompt_*, tab_plain_*, and omnibar_*
foreground/background values, so any future change to dark() breaks the legacy
parity lock.
Selection joins ChromeTheme: dark keeps the existing 0x3a3a3a default, light substitutes a macOS-style light blue (#ccddf5). Explicit mux.json selection colors and Ghostty-seeded selection colors still win via a theme_overrides.selection origin flag; the substitution applies at startup and on config reload.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@mux/crates/mux-tui/src/app.rs`:
- Around line 851-856: The reload_config flow currently reapplies the new config
but keeps using the startup chrome value, so changes to theme.chrome are ignored
until restart. Update App to retain the probed DefaultColors and, inside
reload_config, rebuild self.chrome with ChromeTheme::for_defaults before calling
apply_chrome_defaults and session.apply_config. Use the existing reload_config
and ChromeTheme::for_defaults symbols to locate the change, and ensure
self.chrome is refreshed from the reloaded config rather than reused from
startup.
In `@mux/crates/mux-tui/src/config.rs`:
- Around line 816-823: The method name is too broad for what it actually does:
Config::apply_chrome_defaults only updates selection_bg and selection_fg. Rename
it to something more specific like apply_chrome_selection_defaults, and update
any call sites or references so the narrow contract is clear to future readers.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 2776eeae-adf2-45dd-a47b-5734971a2196
📒 Files selected for processing (2)
mux/crates/mux-tui/src/app.rsmux/crates/mux-tui/src/config.rs
| fn reload_config(&mut self) { | ||
| let config = crate::config::load(); | ||
| let mut config = crate::config::load(); | ||
| config.apply_chrome_defaults(self.chrome); | ||
| self.session.apply_config(&config); | ||
| self.config = config; | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map relevant Rust files and inspect the app/state/theme flow.
git ls-files 'mux/crates/mux-tui/src/*.rs' | sed -n '1,120p'
printf '\n--- app.rs outline ---\n'
ast-grep outline mux/crates/mux-tui/src/app.rs --view expanded || true
printf '\n--- search for chrome/default colors/app state ---\n'
rg -n "default_colors|ChromeTheme::for_defaults|apply_chrome_defaults|reload_config|theme\\.chrome|chrome" mux/crates/mux-tui/src -SRepository: manaflow-ai/cmux
Length of output: 24411
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '540,665p' mux/crates/mux-tui/src/app.rs
printf '\n--- reload_config and nearby ---\n'
sed -n '843,865p' mux/crates/mux-tui/src/app.rs
printf '\n--- ChromeTheme / apply_chrome_defaults / for_defaults ---\n'
sed -n '780,840p' mux/crates/mux-tui/src/config.rsRepository: manaflow-ai/cmux
Length of output: 7059
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect ChromeTheme definitions and any runtime source of default colors.
rg -n "struct ChromeTheme|enum ChromeMode|impl ChromeTheme|for_defaults|DefaultColors|probe_default_colors|set_default_colors" mux/crates/mux-tui/src -S
printf '\n--- host_colors.rs ---\n'
sed -n '1,140p' mux/crates/mux-tui/src/host_colors.rs
printf '\n--- relevant config.rs section ---\n'
sed -n '1,220p' mux/crates/mux-tui/src/config.rsRepository: manaflow-ai/cmux
Length of output: 15093
Recompute chrome on config reload reload_config reloads config, but self.chrome stays at the startup value, so changing theme.chrome in mux.json has no effect until restart. Store the probed DefaultColors on App and rebuild self.chrome with ChromeTheme::for_defaults(config.chrome, default_colors) before apply_chrome_defaults.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@mux/crates/mux-tui/src/app.rs` around lines 851 - 856, The reload_config flow
currently reapplies the new config but keeps using the startup chrome value, so
changes to theme.chrome are ignored until restart. Update App to retain the
probed DefaultColors and, inside reload_config, rebuild self.chrome with
ChromeTheme::for_defaults before calling apply_chrome_defaults and
session.apply_config. Use the existing reload_config and
ChromeTheme::for_defaults symbols to locate the change, and ensure self.chrome
is refreshed from the reloaded config rather than reused from startup.
| impl Config { | ||
| pub fn apply_chrome_defaults(&mut self, chrome: ChromeTheme) { | ||
| if !self.theme_overrides.selection { | ||
| self.theme.selection_bg = chrome.selection_bg; | ||
| self.theme.selection_fg = chrome.selection_fg; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
apply_chrome_defaults is narrowly scoped to selection only — consider a more specific name.
The method name suggests it applies all chrome-derived defaults, but it only ever touches selection_bg/selection_fg. Given the rest of the chrome palette is consumed directly from app.chrome at render time (not config.theme), this is likely intentional, but a name like apply_chrome_selection_defaults would make the narrow contract obvious to future readers touching this method.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@mux/crates/mux-tui/src/config.rs` around lines 816 - 823, The method name is
too broad for what it actually does: Config::apply_chrome_defaults only updates
selection_bg and selection_fg. Rename it to something more specific like
apply_chrome_selection_defaults, and update any call sites or references so the
narrow contract is clear to future readers.
# Conflicts: # mux/crates/mux-tui/src/config.rs # mux/crates/mux-tui/src/ui/omnibar.rs # mux/crates/mux-tui/src/ui/overlay.rs
# Conflicts: # cmux-tui/crates/cmux-tui/src/config.rs
|
Too many files changed for review. ( |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 793a8e1. Configure here.
| @@ -0,0 +1 @@ | |||
| {"rustc_fingerprint":7916351246056945259,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.94.0 (4a4ef493e 2026-03-02)\nbinary: rustc\ncommit-hash: 4a4ef493e3a1488c6e321570238084b38948f6db\ncommit-date: 2026-03-02\nhost: aarch64-apple-darwin\nrelease: 1.94.0\nLLVM version: 21.1.8\n","stderr":""},"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n/Users/lawrence/.rustup/toolchains/stable-aarch64-apple-darwin\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"aarch64\"\ntarget_endian=\"little\"\ntarget_env=\"\"\ntarget_family=\"unix\"\ntarget_feature=\"aes\"\ntarget_feature=\"crc\"\ntarget_feature=\"dit\"\ntarget_feature=\"dotprod\"\ntarget_feature=\"dpb\"\ntarget_feature=\"dpb2\"\ntarget_feature=\"fcma\"\ntarget_feature=\"fhm\"\ntarget_feature=\"flagm\"\ntarget_feature=\"fp16\"\ntarget_feature=\"frintts\"\ntarget_feature=\"jsconv\"\ntarget_feature=\"lor\"\ntarget_feature=\"lse\"\ntarget_feature=\"neon\"\ntarget_feature=\"paca\"\ntarget_feature=\"pacg\"\ntarget_feature=\"pan\"\ntarget_feature=\"pmuv3\"\ntarget_feature=\"ras\"\ntarget_feature=\"rcpc\"\ntarget_feature=\"rcpc2\"\ntarget_feature=\"rdm\"\ntarget_feature=\"sb\"\ntarget_feature=\"sha2\"\ntarget_feature=\"sha3\"\ntarget_feature=\"ssbs\"\ntarget_feature=\"vh\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"macos\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"apple\"\nunix\n","stderr":""}},"successes":{}} No newline at end of file | |||
There was a problem hiding this comment.
Committed Cargo build artifacts
Medium Severity
The diff adds the entire mux/target/ tree (fingerprints, debug/deps .d files, CACHEDIR.TAG, and local machine paths). That is generated Cargo output, not source for the chrome theme work, and it bloats the repo and can confuse other builds.
Reviewed by Cursor Bugbot for commit 793a8e1. Configure here.


In light-background terminals the mux TUI chrome (context menu, status bar, tab bar, sidebar selection, prompt, omnibar) rendered hardcoded dark ANSI indices and clashed badly — dark boxes and strips on a light terminal. The terminal content already adapts (host palette); the chrome did not.
The TUI already probes host fg/bg via OSC 10/11. The chrome now derives from it:
ChromeTheme::dark()reproduces the previous hardcoded indices exactly (dark terminals render byte-identically — verified index-by-index at every converted site),ChromeTheme::light()is a curated light palette (light-gray surfaces, dark text, readable accents). Selection happens once at startup from background luminance (rec.709, >128), overridable viatheme.chrome: auto|light|dark(default auto; probe failure keeps dark). Explicit config colors (tab_bg,tab_active_bg,sidebar_active_bg, borders) still take priority. Terminal content rendering andresolve_palette_colorare untouched.Tests: luminance edges, a dark-palette regression lock on known indices, auto/override selection, and config parse rejection of unknown variants.
Verified on the AWS M4 Pro builder (this Mac's macOS 26 SDK can't link ghostty-vt-sys): fmt, clippy
-D warnings,cargo test --workspace(17 suites), smoke-tui all green.🤖 Generated with Claude Code
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.Note
Low Risk
Presentation-layer theming and config precedence only; terminal pane rendering and palette resolution are unchanged, with dark mode kept index-identical via tests.
Overview
Adds host-aware TUI chrome so menus, status/tab bars, sidebar, omnibar, prompts, toasts, borders, and scrollbars no longer use fixed dark ANSI indices on light terminals.
Startup now passes probed
DefaultColorsintoapp::run, builds aChromeTheme(darkmatches prior indices;lightis a new palette), and stores it onApp.chrome. UI draw paths readapp.chromeinstead of hardcoded colors.theme.chrome(auto|light|dark, defaultauto) picks the palette from background luminance when not forced.ThemeOverridestracks explicit theme keys (selection, tab/sidebar/border colors);apply_chrome_defaultsonly fills selection when not overridden, including after config reload (chrome is not recomputed from the host on reload). Ghostty/mux.json selection colors still win over light chrome defaults.Config docs and tests cover luminance, dark regression, override persistence, and invalid
chromevalues.Reviewed by Cursor Bugbot for commit 793a8e1. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by cubic
Make
mux-tuichrome adapt to the terminal’s light or dark background, including text selection, so menus, bars, and prompts fit light terminals. Dark terminals render exactly as before; terminal content is unchanged.theme.chromewithauto|light|dark(defaultauto);autochooses by host background luminance at startup and falls back to dark. The result is stored asApp.chrome.ChromeThemepalettes:dark()matches legacy indices;light()is curated (selection#ccddf5, dark stays#3a3a3a). Applied to menu, prompt, toast, omnibar, status/tab bars, sidebar, borders, and scrollbars; terminal panes are unchanged.selection,tab_bg,tab_active_bg,sidebar_active_bg,border_active, andborder_inactive. Ghostty/mux.jsonselection colors take priority;Config::apply_chrome_defaultsfills only when not overridden, and reload reapplies these defaults without recomputing the host theme.Written for commit 793a8e1. Summary will update on new commits.
Summary by CodeRabbit
New Features
Bug Fixes
Tests