feat(tui): add Dune Dark theme and keep light Dune - #713
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
WalkthroughThe PR updates the Dune palette, adds and registers the Dune Dark theme, expands ANSI contrast validation, and updates theme documentation and release notes. ChangesDune theme
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 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 |
Vasanthdev2004
left a comment
There was a problem hiding this comment.
Small, clean change: Dune is reassigned from the warm light-sand palette to a dark, daltonized palette with IsDark correctly flipped to true, and the wiring test is updated to match. The full tui suite passes, including the truecolor and xterm-256-quantized WCAG-AA contrast guards covering Dune's selected-row, diff-band, and status-color pairs, so the new colors hold up on 256-color terminals too. No objections — approving.
4631efa to
da6cb17
Compare
Status
Ready for human review/approval. |
2389075
jatmn
left a comment
There was a problem hiding this comment.
I found issues that need to be addressed before this is ready.
Findings
-
[P2] Preserve Dune's diff identity on ANSI-256 terminals
internal/tui/theme_palettes.go:455
In a 256-color terminal, the repository's ownxterm256Hexalgorithm maps bothaddBg(#0a1f14) anddelBg(#240a0e) to#121212; it likewise maps both word-span backgrounds to#303030. Added and removed diff bands therefore become identical (and the base bands blend into the panel) for Dune users, contrary to the claimed colorblind/xterm behavior. Choose backgrounds that quantize to distinct green/red entries and add Dune equivalents of the existing Neon ANSI-256 diff assertions. -
[P2] Update the public Dune description
docs/THEMES.md:12
The guide still says Dune is a warm sand-and-cream palette with charcoal ink and a soft amber accent. This change makes the same user-selectable theme near-black with white/orange and daltonized blue/red signals, and registers it as dark. Update the documentation with the new appearance so--theme dune,ZERO_THEME=dune, and the picker are described consistently.
|
Pushed a fixup addressing both open findings:
Verified go build ./..., go vet ./..., and internal/tui tests (theme-specific tests all pass; there's one unrelated pre-existing failure, TestAltScreenTranscriptScrollKeepsFooterFixed, that also fails on the unmodified branch since it needs a TTY). Checked gofmt cleanliness with git diff --check against upstream/main on the changed files, no issues. |
Dune was rendering as a light/sandy theme with a 55/55/55 grey surface, which did not match Claude Code's dark colorblind mode. Rebase the palette on a near-black surface (#0e0e10) with the brand-orange accent from openclaude's dark-daltonized theme, and move the warm grey to the user-prompt bubble only. Brighten the muted/faint/faintest gray ramp and darken selBg/addBg/delBg so all WCAG-AA and xterm-256 contrast invariants hold. Updates the stale test that still marked Dune as light. Refs Gitlawb#709
Empty commit to re-run CI. Prior Windows smoke failed on TestRunExecOptimizedSessionUnderGate (0 prewarm HEAD probes), which is unrelated to the Dune palette change.
waitFor polled QueueDepth(), which flips as soon as a slot is leased, before the worker is registered in p.active by track(). Drain() only sees stragglers in p.active, so a wide enough scheduling window let it observe an empty active set and return without killing anything. Windows CI's coarser goroutine scheduling was wide enough to hit this reliably; wait on WorkerStats() instead, which reflects p.active.
Dune's addBg/delBg (#0a1f14/#240a0e) and addBgWord/delBgWord (#1f4d33/#4d1620) each quantized to the same xterm-256 gray (#121212 and #303030), making added and removed diff lines indistinguishable on terminals without truecolor support. Rebase the four diff band colors on stronger green/red channel separation so they quantize to distinct xterm cube colors, following the pattern Neon already uses. Adds the Dune equivalent of Neon's ANSI-256 diff-band assertions in TestExtendedThemeANSI256Contrast. Also updates the Dune entry in docs/THEMES.md, which still described the old warm sand/cream/amber palette instead of the dark colorblind-safe one this PR introduced.
4efe601 to
c8ee46c
Compare
|
Rebased onto current upstream main (was 17 commits behind). Clean replay, no conflicts. Local: theme/palette-focused |
jatmn
left a comment
There was a problem hiding this comment.
I found issues that need to be addressed before this is ready.
Findings
- [P2] Preserve readable added diffs on ANSI-256 terminals
internal/tui/theme_palettes.go:459
buildThemerenders the changed palette as actual add-diff foreground/background pairs, but ANSI-256 quantization makes them unreadable:greenonaddBgbecomes#5f87ffon#005f00(2.43:1) for the add sign,faintestonaddBgbecomes#9e9e9eon#005f00(2.97:1) for the line-number gutter, andaddInkonaddBgWordbecomes#afffd7on#008700(4.06:1) for changed-word text. Thus--theme dunefails AA/readability for core added-diff content on 256-color terminals. The new Dune assertions check only green/red band identity, whereas the existing Neon section tests these rendered text pairs. Please choose quantization-safe Dune colors and add the equivalent Dune assertions.
The prior fix made Dune's add and del diff bands quantize to distinct xterm-256 colors, but the foreground/background pairs rendered on top of them were not checked and fail AA once quantized: green on addBg drops to 2.43:1, faintest on addBg to 2.97:1, and addInk on addBgWord to 4.06:1. Brighten green, faintest, and addInk so each pairing clears 4.5:1 after xterm-256 quantization, matching the bar Neon already holds. Add the equivalent Dune assertions to TestExtendedThemeANSI256Contrast, mirroring the existing Neon checks for these rendered text pairs.
|
Addressed the latest finding: the add-diff bands were distinct after xterm-256 quantization, but the text rendered on top of them wasn't checked and failed AA. Changed in Dune:
faintest and green both needed a hue shift, not just a brightness bump: at the same brightness a neutral gray/blue can't clear 4.5:1 against xterm's quantized green background (the math works out the same way Neon's own faintest is tinted green rather than staying pure gray). Del-side pairs (red/faintest/delInk on delBg) were already fine and are untouched. Added the equivalent Dune assertions to
|
There was a problem hiding this comment.
I found issues that need to be addressed before this is ready.
Findings
-
[P2] Keep the selected row visibly distinct after ANSI-256 quantization
internal/tui/theme_palettes.go:464
On an ANSI-256 terminal, the repository'sxterm256Hexmapping turns the new Dune panel (#0e0e10) into#121212andselBg(#191c1f) into#1c1c1c. Their contrast is only 1.099:1, just below the 1.10 selected-row visibility threshold enforced byTestSelectedRowBandIsVisibleAndReadable.onSeluses this background for the selected permission choice and every selectable list, so the active row remains effectively indistinguishable in the terminal mode this PR explicitly claims to support. Choose a selection color that quantizes farther from the panel and add the panel-vs-selection ANSI-256 assertion. -
[P2] Split the unrelated daemon test repair out of this palette PR
internal/daemon/pool_test.go:227
This is a separate current scope-policy blocker, not a claim that the test repair is incorrect: it repairs a Windows scheduling race inTestPoolDrainKillsStraggler, but the PR description, its Dune-theme claim, and its cited reference contain no approved daemon scope. The repository policy requires each community PR to stay focused on its approved issue. Move this change to its own approved daemon issue/PR (with its race validation) so the Dune palette review remains auditable.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/tui/theme_select_test.go (1)
449-455: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winCheck hue identity after quantization.
greenishandreddishinspect the original hex values, while the test claims to validate xterm-256 output. A future palette could quantize to a neutral or wrong-hue color and still pass these assertions.Proposed fix
- if q(dune.addBg) == q(dune.delBg) || !greenish(q(dune.addBg)) || !reddish(q(dune.delBg)) { + if q(dune.addBg) == q(dune.delBg) || !greenish(q(dune.addBg)) || !reddish(q(dune.delBg)) { ... - if q(dune.addBgWord) == q(dune.delBgWord) || !greenish(q(dune.addBgWord)) || !reddish(q(dune.delBgWord)) { + if q(dune.addBgWord) == q(dune.delBgWord) || !greenish(q(dune.addBgWord)) || !reddish(q(dune.delBgWord)) {🤖 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 `@internal/tui/theme_select_test.go` around lines 449 - 455, Update the quantized palette assertions in the dune checks to evaluate hue identity on the quantized xterm-256 values, not the original hex colors. Ensure both add/del row bands and word-span bands remain distinct and green/red respectively after quantization, using the existing q, greenish, and reddish helpers.
🤖 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.
Outside diff comments:
In `@internal/tui/theme_select_test.go`:
- Around line 449-455: Update the quantized palette assertions in the dune
checks to evaluate hue identity on the quantized xterm-256 values, not the
original hex colors. Ensure both add/del row bands and word-span bands remain
distinct and green/red respectively after quantization, using the existing q,
greenish, and reddish helpers.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 917ede12-fa90-44e0-ae81-b4fd02cec874
📒 Files selected for processing (2)
internal/tui/theme_palettes.gointernal/tui/theme_select_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
- internal/tui/theme_palettes.go
jatmn
left a comment
There was a problem hiding this comment.
I found issues that need to be addressed before this is ready.
Findings
-
[P2] Complete the Dune Dark status-border audit across every supported color profile
internal/tui/theme_palettes.go:516
Dune Dark setscardRunto#3399ff. Through the same production conversion path used by the new test—colorprofile.ANSI.Convert(lipgloss.Color(...))—that becomes ANSI bright blue (#0000ff), whilepanel(#0e0e10) becomes ANSI black (#000000). The rendered pair is therefore only 2.44:1. This is below the repository's established 3:1 requirement for non-text card borders (the NeoncardErrassertions inTestExtendedThemeANSI256Contrastalready document and enforce that threshold).This is a status-token-family gap rather than an isolated literal.
cardRunis used for in-flight tool-call borders (internal/tui/rendering.go:1429) and running-specialist left rules (internal/tui/specialist_card.go:362). Its sibling tokens are also production state indicators:cardErrborders failed tool cards, error note boxes, and failed specialist cards (internal/tui/rendering.go:994,internal/tui/rendering.go:1446, andinternal/tui/specialist_card.go:364), whilecardPermbecomespermBorderand frames both filled and unfilled permission surfaces (internal/tui/rendering.go:1152andinternal/tui/rendering.go:1192). The PR claims truecolor, xterm-256, and real ANSI-16 auditing, but the current tests exercise none of these Dune Dark border/surface pairings; they only contain a one-off NeoncardErrcheck in truecolor and xterm-256. That omission is why the current suite stays green.Please treat the following as the acceptance contract for one complete fix; changing only the
cardRunhex or adding only one ANSI-16 assertion would leave the same blind spot in place:- Choose a Dune Dark
cardRunvalue whose converted output remains at least 3.0:1 against the converted panel in truecolor, xterm-256, and ANSI-16. One known-safe direction is#cceeff, already used by this palette'sbluetoken and documented here as mapping to ANSI bright cyan; a different cool running color is fine if the real conversions prove it passes. - Audit the complete semantic status-border family—
cardRun,cardErr, andcardPerm—rather than assuming the untouched siblings are safe. Assert all three againstpanel; becausecardPermalso borders the filled permission card, assert it againstpermBgas well. - Exercise every advertised profile using the repository's existing helpers: raw hex pairs in
TestExtendedThemeContrastInvariants,xterm256Hexpairs inTestExtendedThemeANSI256Contrast, and the actualansi16Hex/colorprofile.ANSI.Convertpath inTestDuneDarkANSI16Contrast. Every status-border pairing above must use the 3.0 non-text threshold; do not lower the threshold to make a palette value pass. - Preserve the intended state identities after conversion: running, error, and permission borders should not collapse to the same converted ANSI color. The current cool/red/yellow roles should remain distinguishable in both xterm-256 and ANSI-16 even when their exact source hex values change.
- Keep the change scoped to Dune Dark's semantic status borders and their regression coverage. This finding does not require retuning decorative rules, prompt fills, unrelated themes, or weakening the PR's accessibility claims.
A focused verification command is
go test ./internal/tui/ -run 'TestExtendedThemeContrastInvariants|TestExtendedThemeANSI256Contrast|TestDuneDarkANSI16Contrast' -count=1, followed bygofmt/make fmt-checkand the existing repository CI gates. The review should be considered addressed only when the full matrix passes, not merely when the original 2.44:1cardRunpair changes. - Choose a Dune Dark
Swap cardRun to #cceeff (was 2.44:1 on panel under ANSI-16 conversion, below the 3:1 WCAG 1.4.11 non-text threshold) and cardPerm to #fff200 (was collapsing to the same ANSI red as cardErr, losing the permission-state identity under 16-color). Add regression coverage for cardRun/cardErr/cardPerm against panel (and cardPerm against permBg) in truecolor, xterm-256, and real ANSI-16 conversion, plus collapse checks so running/error/permission stay three distinct states after quantization.
|
Pushed a fix for jatmn's latest finding: cardRun swapped to #cceeff (was 2.44:1 against panel under ANSI-16 conversion, below the 3:1 WCAG 1.4.11 non-text threshold) and cardPerm to #fff200 (was collapsing to the same ANSI red as cardErr under 16-color). Added coverage for cardRun/cardErr/cardPerm against panel and permBg across truecolor, xterm-256, and real ANSI-16 conversion, plus collapse checks. Verified with Note: gnanam1990's earlier process/scope finding (no approved issue for changing Dune's identity from light to dark, and the daemon test fix riding along in an earlier revision) is not addressed by this push — that's a product decision for a maintainer, not something I'm resolving here. |
|
@coderabbitai full review |
✅ Action performedFull review finished. Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 28 minutes. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
internal/tui/theme_select_test.go (2)
584-596: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUse
lookupThemeinstead of re-scanning the registry.
TestNewThemePresetsWiredalready useslookupThemeat line 283. The manual loop here duplicates that lookup and adds afoundflag for no gain.♻️ Proposed simplification
- var pal palette - found := false - for _, entry := range themeRegistry { - if entry.Name == "dune-dark" { - pal = entry.Palette - found = true - break - } - } - if !found { - t.Fatal("theme 'dune-dark' is not registered") - } + entry, ok := lookupTheme("dune-dark") + if !ok { + t.Fatal("theme 'dune-dark' is not registered") + } + pal := entry.Palette🤖 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 `@internal/tui/theme_select_test.go` around lines 584 - 596, Update TestDuneDarkANSI16Contrast to retrieve the “dune-dark” palette through the existing lookupTheme helper, removing the manual themeRegistry loop and found flag while preserving the test’s failure behavior for an unregistered theme.
599-605: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDrop the stale first half of this comment.
Lines 599-601 and lines 602-605 describe the same table. The second paragraph supersedes the first and also covers the gutter pairs. Keep one.
🧹 Proposed cleanup
- // Diff sign text and changed-word text: the pairs users actually read on - // add/del rows under 16-color. Prior values were bright-blue-on-green - // (1.67:1) and bright-red-on-maroon (2.74:1). // Diff sign text, changed-word text, and gutter line numbers (faintest on🤖 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 `@internal/tui/theme_select_test.go` around lines 599 - 605, Remove the stale first paragraph in the comment near the theme selection test, keeping only the second paragraph that documents diff signs, changed words, gutter line numbers, and their WCAG AA contrast requirements.
🤖 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 `@docs/THEMES.md`:
- Around line 19-20: In the Dune Dark description in THEMES.md, replace the
unsupported “colorblind-safe” and “matching Claude Code’s daltonized dark mode”
claims with narrower wording that describes the palette as colorblind-friendly
and inspired by Claude Code’s palette, without implying simulation validation or
exact equivalence.
---
Nitpick comments:
In `@internal/tui/theme_select_test.go`:
- Around line 584-596: Update TestDuneDarkANSI16Contrast to retrieve the
“dune-dark” palette through the existing lookupTheme helper, removing the manual
themeRegistry loop and found flag while preserving the test’s failure behavior
for an unregistered theme.
- Around line 599-605: Remove the stale first paragraph in the comment near the
theme selection test, keeping only the second paragraph that documents diff
signs, changed words, gutter line numbers, and their WCAG AA contrast
requirements.
🪄 Autofix
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: CHILL
Plan: Pro Plus
Run ID: cb4312e5-f351-4cea-b1a7-af630c448f7c
📒 Files selected for processing (6)
CHANGELOG.mdREADME.mdREADME_ZH.mddocs/THEMES.mdinternal/tui/theme_palettes.gointernal/tui/theme_select_test.go
Describe the palette as colorblind-friendly and inspired by Claude Code's daltonized dark palette, rather than claiming colorblind-safe parity with Claude Code dark mode. Align the theme_palettes comment the same way.
|
Addressed CodeRabbit accessibility wording finding (discussion_r3737946449). Change (f7fd778):
No equivalent overclaim in README / CHANGELOG. |
|
@coderabbitai full review |
✅ Action performedFull review finished. Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 13 minutes. |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/tui/theme_select_test.go (1)
436-568: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winUse the production ANSI-256 converter in these assertions.
xterm256Hexuses squared RGB distance, butcolorprofile.ANSI256.Convertdelegates toansi.Convert256, which uses HSLuv distance when choosing between cube and gray candidates. Replace the helper body with thecolorprofile.ANSI256.Convert(lipgloss.Color(hexColor))andRGBA()implementation used byansi16Hex.🤖 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 `@internal/tui/theme_select_test.go` around lines 436 - 568, Update the xterm256Hex helper used by TestExtendedThemeANSI256Contrast to convert colors through colorprofile.ANSI256.Convert(lipgloss.Color(hexColor)) and derive the returned hex value via RGBA(), matching ansi16Hex’s implementation. Keep the existing assertions unchanged.Source: Coding guidelines
🤖 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.
Outside diff comments:
In `@internal/tui/theme_select_test.go`:
- Around line 436-568: Update the xterm256Hex helper used by
TestExtendedThemeANSI256Contrast to convert colors through
colorprofile.ANSI256.Convert(lipgloss.Color(hexColor)) and derive the returned
hex value via RGBA(), matching ansi16Hex’s implementation. Keep the existing
assertions unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 58c6e6b6-0b9f-4399-9994-391512f03eef
📒 Files selected for processing (6)
CHANGELOG.mdREADME.mdREADME_ZH.mddocs/THEMES.mdinternal/tui/theme_palettes.gointernal/tui/theme_select_test.go
|
Thank you. Two points worth addressing:
I'll also update the docs and tests to add explicit docstrings for any functions that are missing them to satisfy the coverage threshold. |
|
@gnaman1990 the process and scope concern in your CHANGES_REQUESTED is settled: maintainer jatmn approved the current head on 2026-08-09 (review, submittedAt 2026-08-09T20:20:29Z, state APPROVED), confirming the dark re-theme direction. CodeRabbit also approved the same head on 2026-08-07 (submittedAt 2026-08-07T18:35:56Z, state APPROVED). CI is green on head f7fd778: Smoke (ubuntu, macos, windows), Performance Smoke, Security & code health, and Zero Review all pass. Could you re-review the current head, or dismiss your outstanding CHANGES_REQUESTED so the PR can merge? No engineering changes are pending. |
Co-Authored-By: cairn-code <282421612+cairn-code@users.noreply.github.com>
1fc71c2
|
Updated |
The production colorprofile.ANSI256 conversion (HSLuv distance) maps the previous accent to xterm #5f5f00, which drops accent-on-selBg contrast to 4.47:1. Darken the accent so it quantizes to #444444 instead, restoring 6.47:1 on the quantized selBg. The test helper now exercises the real production conversion path. Co-Authored-By: cairn-code <282421612+cairn-code@users.noreply.github.com>
|
Fixed the macOS smoke failure: with the test helper now exercising the production |
|
@coderabbitai full review |
✅ Action performedFull review finished. |
Summary
Adds
dune-darkas a separate near-black, colorblind-friendly theme inspired by Claude Code's daltonized dark palette, while keeping lightduneas the warm sand-and-cream theme. Users who want the dark canvas use/theme dune-dark(orZERO_THEME=dune-dark/--theme dune-dark);/theme dunestays light.Diff and selection colors are audited for WCAG AA in truecolor, after xterm-256 downsampling, and (for Dune Dark) after the real 16-color ANSI conversion path used on
TERM=xterm.Changes
internal/tui/theme_palettes.godune(sand/cream) and registersdune-darkas its own dark preset.colorprofile.ANSIconversion.internal/tui/theme_select_test.goduneanddune-dark.TestDuneDarkANSI16Contrastasserts diff and selected-row pairs viacolorprofile.ANSI.Convert.docs/THEMES.mdREADME.md,README_ZH.md,CHANGELOG.mddune-dark(thirteen color themes alongsidedark/light).Test plan
go test ./internal/tui/ -run 'Theme|Palette|Dune|Contrast|ANSI|Diff|Hierarchy|Wired' -count=1git diff HEAD --check/theme duneis warm light sand;/theme dune-darkis near-black with orange accent and cool/warm diffsTERM=xtermsmoke for readable add/del signs on Dune DarkRefs #841
Summary by CodeRabbit
New Features
Documentation