feat(cli): OSC 10 foreground query and inherit-fg auto theme mode#276
Conversation
Extends terminal_query.rs with a single OSC 10 + OSC 11 + DA1 batch so dark/light detection and the optional foreground inherit share one round-trip. Adds [ui].inherit_fg (default false) — when the user's configured theme is auto and inherit_fg is enabled, the resolved theme's text slot is replaced with the OSC 10 foreground RGB. Detection is silent when stdin/stdout are not a TTY. - terminal_query: parse_osc_color(input, code) shared parser; new query_terminal_colors_from_io and prime_terminal_colors helpers; detect_terminal_foreground reads from a OnceLock cache populated by the unified batch. - theme_runtime: init_with_options(theme_name, configured_name, inherit_fg) records the auto + inherit-fg state; current() applies the override when both flags are on and the cache hit succeeded. - schema: UiConfig.inherit_fg with default false; toml round-trip test. - repl + /theme command thread the new flag through. - docs: auto-detection paragraph + inherit_fg subsection in configuration/settings. ROADMAP 8.15.5 closed; onboarding picker exposure left as a TODO so the patch stays scoped — users opt in via config today.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b95f1171a4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if let Some(theme) = colorfgbg_theme() { | ||
| let _ = FOREGROUND_RGB.set(None); | ||
| let _ = BACKGROUND_RGB.set(None); | ||
| return theme; |
There was a problem hiding this comment.
Populate foreground cache before COLORFGBG early return
When COLORFGBG is set, detect_system_theme_uncached returns immediately and explicitly stores None in FOREGROUND_RGB, so [ui].inherit_fg = true can never apply even though the user selected theme = "auto". This affects terminals/shells that export COLORFGBG: the background theme resolves, but foreground inheritance is silently disabled for the whole process because the OnceLock is initialized with None on this path.
Useful? React with 👍 / 👎.
detect_system_theme_uncached short-circuited on SYSTEM_THEME_ENV, COLORFGBG, and TERM_PROGRAM=Apple_Terminal — explicitly storing None into FOREGROUND_RGB and BACKGROUND_RGB on each early-return path. The dark/light classification worked, but the OSC 10/11 round-trip that populates the actual RGB caches never ran when any of those env vars was set. Result: on the most common terminal/shell combination (any setup that exports COLORFGBG), the user could set theme = "auto" and inherit_fg = true, get a correctly-classified background theme, and still see the default text slot — because the foreground cache was forcibly initialised to None for the whole process. Restructure so dark/light classification is computed from env vars into an Option, the OSC batch always runs and populates both RGB caches, and the final return prefers the env-derived theme when available, falling back to luminance-derived from the OSC bg, and finally to Dark. Env-derived classification still wins (it's what the user explicitly told us); the OSC query is now strictly additive — it populates the inherit_fg payload regardless of whether classification needed it.
Summary
[ui].inherit_fgconfig key (defaultfalse). When the configured theme isautoandinherit_fg = true, the resolved theme'stextslot is replaced with the foreground RGB the terminal reported via OSC 10. Falls back cleanly to the theme default when detection failed or wasn't applicable. Explicit themes are taken at face value.prime_terminal_colors()anddetect_terminal_foreground()exposed onterminal_query; the OSC parser/sentinel/is_tty()gate from feat(cli): detect terminal theme via OSC 11 #268 are reused via a generalisedparse_osc_color(input, code).Detection is silent when stdin/stdout aren't a TTY (
agent --serve, CI, piped input) — theis_tty()gate is shared with the OSC 11 path.Test plan
cargo check --all-targetscargo test --all-targets(unit + integration; pre-existing bwrap sandbox tests fail in this environment due to user-namespace permissions and are unrelated)cargo clippy --all-targets -- -D warnings(clean)cargo fmt --all -- --check(clean)New tests:
parser_distinguishes_osc_10_from_osc_11— same byte stream carries both replies; the OSC code selects the payload.parses_osc_10_foreground_payload— direct OSC 10 reply parses; OSC 10 reply does not leak into an OSC 11 query.simulated_query_writes_batch_and_stops_at_da1(extended) — single batch (OSC 10,OSC 11,DA1), reader stops at the sentinel.back_compat_query_system_theme_from_io_still_returns_theme— the legacy OSC 11 helper still works on top of the unified parser.missing_osc_10_reply_returns_none_foreground_only— terminals that reply to OSC 11 but not OSC 10 yield a populated background andNoneforeground rather than failing both.is_tty_is_false_under_cargo_test— sentinel for the TTY gate that prevents escape sequences in non-interactive contexts.theme_runtime: detection succeeded / detection failed / inherit_fg disabled / configured theme not auto.UiConfigdefaults + TOML round-trip forinherit_fg.Notes
~/.config/agent-code/config.tomlfor now, documented indocs/configuration/settings.mdx.inherit_fgis opt-in and contrast against the theme background is the user's call.Closes ROADMAP 8.15.5. Builds on #268.