Skip to content

fix(cli): preserve terminal contrast across light and dark themes - #729

Open
loveRhythm1990 wants to merge 7 commits into
matrixorigin:mainfrom
loveRhythm1990:investigate/issue-728-light-terminal
Open

fix(cli): preserve terminal contrast across light and dark themes#729
loveRhythm1990 wants to merge 7 commits into
matrixorigin:mainfrom
loveRhythm1990:investigate/issue-728-light-terminal

Conversation

@loveRhythm1990

@loveRhythm1990 loveRhythm1990 commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

Several CLI/TUI surfaces force light foregrounds or choose a dark panel background while inheriting the terminal's foreground. On a light terminal, this makes Markdown labels, welcome text, login input, and user messages difficult to read.

Use terminal-default foregrounds for ordinary text and emphasis, reuse the existing TUI palette for welcome accents and syntax highlighting, and pair conversation-panel foregrounds with their backgrounds. Auto mode now preserves terminal defaults when background information is unavailable instead of assuming dark. Keep explicit light/dark profiles and make plain/NO_COLOR paths consistent in the affected renderers.

Related issue

Closes #728

Change type

  • Feature
  • Bug fix
  • Documentation
  • Refactor or performance improvement
  • Test
  • Build, CI, or maintenance

User and compatibility impact

  • Markdown emphasis, welcome-panel body text, login fields, /agent and /messaging labels, and turn-summary values no longer force white or selection-only foregrounds on the terminal background.
  • Message, composer, and queued-message surfaces pair foreground/background colours. Plain mode ignores background hints, and explicit profile selection wins over conflicting background hints.
  • Welcome accents and code highlighting use the existing selected profile. Highlighting no longer independently assumes a dark theme or emits RGB colours for plain/ANSI palettes. Light-theme secondary text and accent contrast are improved.
  • Auto mode without background hints uses terminal-default colours; users wanting a coloured preset can select ASTRA_TUI_THEME=light or dark. This intentionally changes the former dark fallback.
  • astra chat --no-color / NO_COLOR disable Markdown styling, including code/table styling. Streaming cursor control remains available.
  • No new dependencies, settings, runtime semantics, or migrations. This fixes readability; it does not introduce a theme picker or redesign the entire UI.

Architecture and complexity delta

  • Canonical owner changed or extended: the existing tui/theme.rs palette and tui/style.rs conversation surfaces; streaming_md.rs remains the CLI Markdown owner. The welcome renderer reuses the TUI palette and existing crossterm colour conversion through crate-local exports.
  • Existing implementations and callers searched: welcome/login rendering, slash commands, user/composer/queued-message rendering, summaries, highlighting, terminal palette environment hints, CLI Markdown/SSE/final-text callers, and existing theme tests.
  • Superseded code, states, tables, shims, or self-only tests removed: forced-white display styles, duplicate syntax-highlighting palettes, duplicate background-lightness fallback, and unpaired panel-style helpers. Replaced an environment-mutating theme test with deterministic cases and isolated child-process coverage.
  • If parallel implementations remain, their boundary and retirement condition: no new theme state introduced. Existing CLI status helpers outside these affected surfaces remain unchanged; a wholesale migration of every coloured command is outside this fix.

Verification

  • Commands and results:
    • rtk proxy make format-check — passed.
    • cargo nextest run -p astra-cli --lib --offline -E 'test(tui::history_cell::user::tests)' — all 9 tests passed. The full-width user-message rendering test covers auto without background hints, light, dark, plain, and NO_COLOR in isolated processes, including foreground, full-row background, and breathing rows.
    • rtk git diff --check github/main...HEAD — passed.
    • cargo check -p astra-cli --tests --offline — passed before the dependency-only main merge.
    • cargo clippy -p astra-cli --tests -- -D warnings — could not complete after the main merge: the local build volume ran out of space (ENOSPC). An earlier type-complexity finding was corrected with a type alias; the CI static-check job passed at 6cef21c7d.
    • Focused temporary rustc --test harness — 72 tests passed using actual Markdown, terminal-region, palette, theme, surface, and highlighting modules. Extended UI harness — 89 tests passed, including actual login-rendering tests through a minimal bottom-pane interface stub and extracted welcome styling/tests. These are focused render tests, not a full Cargo test-suite run.
  • Public entrypoint exercised: traced astra, /login, /agent, /messaging, and astra chat --no-color into their render owners; exercised theme selection through isolated process environments, actual render functions, ratatui buffers, and vt100 cells. No live model session or manual Ghostty/other-terminal visual test was run.
  • Unhappy paths exercised: light/dark/unknown background; conflicting hints and explicit profiles; plain/NO_COLOR with background hints present; truecolor/256/16-colour theme selection; uncoloured Markdown code/tables; paired conversation surfaces; login focus and ordinary bold text. Light text roles are checked against a 4.5:1 contrast target on white.
  • Database verification: N/A; no database changes.

Final checklist

  • I added or updated tests at the layer that owns the behavior, or
    explained why no test is needed.
  • I updated public or design documentation for contract changes, or the
    change needs no documentation update.
  • I checked the diff for credentials, private URLs, customer data,
    generated files, and other sensitive information.
  • The PR title follows the repository's Conventional Commit format.

@XuPeng-SH XuPeng-SH left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep review of 9653874. No blocking correctness or regression findings.

The fix addresses the cause described in #728 at the shared rendering boundary. Removing the forced foreground colors lets the terminal choose readable text colors while retaining bold, italic, and heading emphasis. I inspected the locked termimad 0.23.2 implementation: its default skin provides those attributes without foreground overrides for these elements, and no_style removes the code/table styling as well. I also verified the separate crossterm versions: the renderer's 0.23.2 dependency does not implement the NO_COLOR handling present in the CLI's 0.29 dependency, so handling this explicitly in the renderer is justified.

I traced chat --no-color through process-environment initialization and checked both incremental rendering and the server-admission final-text caller. The presence-based NO_COLOR behavior, including an empty value, is consistent with the existing CLI theme/rendering checks. The change stays in the canonical renderer and does not introduce a terminal-specific theme detector or another rendering path.

The tests exercise useful observable behavior: vt100 cell foreground/background and emphasis for ordinary text, list labels, and headings; content preservation and absence of style escapes across code, quotes, lists, and tables; and subprocess-isolated environment cases that verify the selected test actually ran. Streaming cursor control remains outside the documented no-style contract.

Independent validation:

  • Compiled the actual streaming_md, terminal_region, and output_sink modules in an isolated Cargo test harness, using the repository's test stdout macro and pinned direct dependencies: all 47 tests passed.
  • git diff --check against the PR base passed.
  • Reviewed both changed files and the relevant callers/dependency implementation.

Limits: this was focused module validation, not a full Astra Cargo/workspace build or a live CLI/model session. I did not visually validate Ghostty or other native terminal applications. The combined-status API returned no status entries, so this review does not claim that all CI checks are green.

@mergify mergify Bot added the queued label Sep 7, 2026
@mergify

mergify Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-09-07 09:48 UTC · Rule: main · triggered by rule Automatic queue on approval for main
  • 🟠 Checks running · in-place
  • 🚫 Left the queue2026-09-07 10:06 UTC · at c0222dd8bbcb2853fd7e695737d96f0ac2a8016d

This pull request spent 18 minutes 4 seconds in the queue, with no time running CI.

Waiting for
  • any of: [🛡 GitHub branch protection]
    • check-neutral = Test: astra-cli (edge-fs-tools)
    • check-skipped = Test: astra-cli (edge-fs-tools)
    • check-success = Test: astra-cli (edge-fs-tools)
  • any of: [🛡 GitHub branch protection]
    • check-neutral = Test: astra-cli (edge-git-gix)
    • check-skipped = Test: astra-cli (edge-git-gix)
    • check-success = Test: astra-cli (edge-git-gix)
  • any of: [🛡 GitHub branch protection]
    • check-neutral = Test: astra-cli (non-edge)
    • check-skipped = Test: astra-cli (non-edge)
    • check-success = Test: astra-cli (non-edge)
All conditions
  • any of [🛡 GitHub branch protection]:
    • check-neutral = Test: astra-cli (edge-fs-tools)
    • check-skipped = Test: astra-cli (edge-fs-tools)
    • check-success = Test: astra-cli (edge-fs-tools)
  • any of [🛡 GitHub branch protection]:
    • check-neutral = Test: astra-cli (edge-git-gix)
    • check-skipped = Test: astra-cli (edge-git-gix)
    • check-success = Test: astra-cli (edge-git-gix)
  • any of [🛡 GitHub branch protection]:
    • check-neutral = Test: astra-cli (non-edge)
    • check-skipped = Test: astra-cli (non-edge)
    • check-success = Test: astra-cli (non-edge)
  • #review-threads-unresolved = 0 [🛡 GitHub branch protection]
  • github-review-approved [🛡 GitHub branch protection]
  • any of [🛡 GitHub branch protection]:
    • check-success = Check PR title
    • check-neutral = Check PR title
    • check-skipped = Check PR title
  • any of [🛡 GitHub branch protection]:
    • check-success = check
    • check-neutral = check
    • check-skipped = check
  • any of [🛡 GitHub branch protection]:
    • check-skipped = Test: core crates + bridge hooks
    • check-neutral = Test: core crates + bridge hooks
    • check-success = Test: core crates + bridge hooks
  • any of [🛡 GitHub branch protection]:
    • check-skipped = Test: astra-runtime
    • check-neutral = Test: astra-runtime
    • check-success = Test: astra-runtime
  • any of [🛡 GitHub branch protection]:
    • check-success = Test: astra-cli (edge-rest)
    • check-neutral = Test: astra-cli (edge-rest)
    • check-skipped = Test: astra-cli (edge-rest)
  • any of [🛡 GitHub branch protection]:
    • check-success = Test: astra-cli (edge-shell)
    • check-neutral = Test: astra-cli (edge-shell)
    • check-skipped = Test: astra-cli (edge-shell)
  • any of [🛡 GitHub branch protection]:
    • check-success = Test: online (core)
    • check-neutral = Test: online (core)
    • check-skipped = Test: online (core)
  • any of [🛡 GitHub branch protection]:
    • check-success = Test: online (integration)
    • check-neutral = Test: online (integration)
    • check-skipped = Test: online (integration)
  • any of [🛡 GitHub branch protection]:
    • check-skipped = Test: turn-core + services + plan
    • check-neutral = Test: turn-core + services + plan
    • check-success = Test: turn-core + services + plan
  • any of [🛡 GitHub branch protection]:
    • check-skipped = web (typecheck, test, build)
    • check-neutral = web (typecheck, test, build)
    • check-success = web (typecheck, test, build)
  • any of [🛡 GitHub branch protection]:
    • check-skipped = Astra SDK (typecheck, test+coverage, build)
    • check-neutral = Astra SDK (typecheck, test+coverage, build)
    • check-success = Astra SDK (typecheck, test+coverage, build)

Reason

Pull request #729 has been dequeued

Queue conditions are not satisfied:

  • -draft [📌 queue requirement]
  • any of: [🔀 queue conditions]
    • all of: [📌 queue conditions of queue rule main]
      • any of: [🛡 GitHub branch protection]
        • check-neutral = Test: astra-cli (edge-fs-tools)
        • check-skipped = Test: astra-cli (edge-fs-tools)
        • check-success = Test: astra-cli (edge-fs-tools)
      • any of: [🛡 GitHub branch protection]
        • check-neutral = Test: astra-cli (edge-git-gix)
        • check-skipped = Test: astra-cli (edge-git-gix)
        • check-success = Test: astra-cli (edge-git-gix)
      • any of: [🛡 GitHub branch protection]
        • check-neutral = Test: astra-cli (non-edge)
        • check-skipped = Test: astra-cli (non-edge)
        • check-success = Test: astra-cli (non-edge)

Failing checks:

Hint

You should look at the reason for the failure and decide if the pull request needs to be fixed or if you want to requeue it.
If you do update this pull request, it will automatically be requeued once the queue conditions match again.
If you think this was a flaky issue instead, you can requeue the pull request, without updating it, by posting a @mergifyio queue comment.

Requeued — the merge queue status continues in this comment ↓.

@loveRhythm1990
loveRhythm1990 marked this pull request as draft September 7, 2026 10:06
@mergify mergify Bot added dequeued and removed queued labels Sep 7, 2026
@loveRhythm1990 loveRhythm1990 changed the title fix(cli): preserve terminal foreground in markdown output fix(cli): preserve terminal contrast across light and dark themes Sep 7, 2026
@mergify mergify Bot removed the dequeued label Sep 7, 2026
@loveRhythm1990
loveRhythm1990 marked this pull request as ready for review September 7, 2026 10:52
@mergify mergify Bot added the queued label Sep 7, 2026
@mergify

mergify Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-09-07 11:00 UTC · Rule: main · triggered by rule Automatic queue on approval for main
  • 🚫 Left the queue2026-09-07 11:03 UTC · at aad3ab680151bfe4297b71e2efcf8f074fad1bd4

This pull request spent 2 minutes 46 seconds in the queue, with no time running CI.

Reason

The pull request can't be updated

For security reasons, Mergify can't update this pull request. Try updating locally.
GitHub response: refusing to allow a GitHub App to create or update workflow .github/workflows/build_push_to_idc.yml without workflows permission

Hint

You should update or rebase your pull request manually. If you do, this pull request will automatically be requeued once the queue conditions match again.
If you think this was a flaky issue, you can requeue the pull request, without updating it, by posting a @mergifyio queue comment.

Tick the box to put this pull request back in the merge queue (same as @mergifyio queue).

  • Requeue this pull request

@mergify mergify Bot added dequeued and removed queued labels Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: CLI Markdown bold text is nearly invisible on light terminal backgrounds

2 participants