Skip to content

Fix repeated cmux themes set reloads - #4359

Merged
austinywang merged 45 commits into
mainfrom
issue-4355-cmux-themes-set-state-dependent
May 20, 2026
Merged

austinywang merged 45 commits into
mainfrom
issue-4355-cmux-themes-set-state-dependent

Conversation

@austinywang

@austinywang austinywang commented May 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Fixes cmux themes set: only the first invocation applies — subsequent calls silently no-op #4355
  • cmux themes set, cmux themes clear, and the bare interactive cmux themes picker now request a targeted cmux theme reload with phase=final after writing the managed Ghostty config.
  • The CLI no longer falls through generic socket.reload_config for theme writes, avoiding the extra dark/light load pass that caused 3024 Day to flicker.
  • Final theme reloads apply immediately and cancel any pending preview reload; preview/legacy reloads remain debounced.
  • Runtime color-scheme synchronization now only skips active reentrant calls, so repeated same-lightness theme changes still repaint live Ghostty surfaces.
  • For explicit same-theme light/dark values like 3024 Day, cmux preserves the resolved terminal color scheme during the reload load phase instead of briefly switching through app appearance.
  • Adds behavior-level regression coverage for repeated theme writes, final reload notifications, runtime scheme decisions, and the 3024 Day flicker path.

Root Cause

The previous reload path mixed two different mechanisms: cmux theme-specific distributed reloads and generic Ghostty reload_config socket reloads. For 3024 Day, the generic reload could make the load phase resolve against app appearance before the terminal theme scheme settled, so the surface pulsed between dark and light.

A later guard also skipped runtime color-scheme synchronization when the requested light/dark scheme matched the already-applied scheme. That avoided one reentrant crash path, but it also meant repeated theme changes could stop repainting after the first change. The guard now skips only active reentrant setter calls.

Verification

  • Built the tagged debug app with ./scripts/reload.sh --tag fix-day3024-flicker.
  • Dogfooded repeated changes with CMUX_TAG=fix-day3024-flicker scripts/cmux-debug-cli.sh --json themes set '3024 Night' and CMUX_TAG=fix-day3024-flicker scripts/cmux-debug-cli.sh --json themes set '3024 Day'.
  • Verified repeated 3024 Night / 3024 Day changes still apply after the first change.
  • Confirmed the targeted 3024 Day while already light path logs distributed.cmux.themes.final, uses load scheme=light, and does not emit socket.reload_config or already_applied.
  • Did not run tests locally per repository policy; CI is running on the pushed branch.

Note

Medium Risk
Touches theme reload plumbing across the CLI and app runtime color-scheme/config reload paths; mistakes could cause missed reloads, flicker, or incorrect appearance updates, but changes are localized and heavily covered by new regression tests.

Overview
Theme reload flow is reworked to stop repeated/flickering reloads. The CLI now posts a distributed reload notification after themes set/clear and after the interactive picker exits, including socketPath and phase=final, and chooses the target bundle id from the socket name (tagged debug/nightly/staging supported).

The app now interprets theme reload phases and stabilizes color-scheme updates. AppDelegate filters reload notifications by bundle id, debounces legacy/preview reloads but applies final immediately (cancelling pending previews), and refreshes surfaces by reapplying the surface color scheme plus passing a preferredColorScheme through config reload paths to avoid transient dark/light flips on single-theme values.

UI/appearance readability is improved. Adds contrast-based foreground color helpers and uses them for sidebar selected/workspace rows, titlebar controls, and panel foregrounds; WindowAppearanceSnapshot now derives a chrome/sidebars content scheme from the composited terminal background and can add a subtle sidebar contrast overlay when backdrops are unified.

Safety + coverage. Prevents socket-path overrides when an inherited CMUX_BUNDLE_ID conflicts with the current bundle, and adds extensive regression tests for theme reload notifications/phases, interactive picker behavior, runtime scheme decisions, contrast helpers, and process timeout handling.

Reviewed by Cursor Bugbot for commit aac8005. Bugbot is set up for automated code reviews on this repo. Configure here.

@vercel

vercel Bot commented May 19, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment May 20, 2026 2:29am
cmux-staging Building Building Preview, Comment May 20, 2026 2:29am

@coderabbitai

coderabbitai Bot commented May 19, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

CLI threads socketPath/explicitPassword through themes commands and attempts a socket "reload_config" RPC (with optional auth) before falling back to distributed notification. Appearance store accepts an injected apply hook and skips terminal-theme synchronization during the initial reload. Tests and socket-request instrumentation added.

Changes

Socket-based theme reload for successive theme changes

Layer / File(s) Summary
Socket-based reload mechanism
CLI/CMUXCLI+ThemeSupport.swift, Sources/AppDelegate.swift
Added requestThemeReloadOverSocket(socketPath:explicitPassword:), updated reloadThemesIfPossible(socketPath:explicitPassword:) to try a socket RPC and fall back to distributed notification; notification handler now ignores reloads targeted at other bundle identifiers.
Interactive helper runner refactor
CLI/CMUXCLI+Themes.swift
Replaced execve-based interactive helper with a Process-based runInteractiveHelper that launches, waits for termination, and throws CLIError on failures.
Thread socket parameters through theme command handlers
CLI/CMUXCLI+Themes.swift
Extended runThemes, runInteractiveThemes, runThemesSet, and runThemesClear to accept socketPath/explicitPassword and forward them into subcommands and reload calls.
Main CLI entry point call site update
CLI/cmux.swift
Top-level runThemes invocation updated to forward resolvedSocketPath and socketPasswordArg.
Regression tests & socket responder instrumentation
cmuxTests/CMUXCLIErrorOutputRegressionTests.swift
Added tests verifying reload_config requests for each themes set and for the interactive picker; added theme helpers; hardened runShell/runProcess timeout escalation; extended UnixSocketResponder to record and expose received requests thread-safely.

Appearance startup gating and injection

Layer / File(s) Summary
Inject applyAppearanceMode and gate initial sync
Sources/KeyboardShortcutSettingsFileStore.swift
Added applyAppearanceMode injection, hasCompletedInitialReload flag, initializer changes to accept injection and mark initial reload done, and use injected closure while preventing terminal-theme synchronization during the initial reload.
Startup test for appearance gating
cmuxTests/KeyboardShortcutSettingsFileStoreStartupTests.swift
Added test confirming initial managed appearance load does not synchronize terminal theme, while a subsequent reload does; captures apply parameters via injected closure.

Sequence Diagram

sequenceDiagram
  participant CLI as cmux CLI
  participant runThemesSet as runThemesSet
  participant reloadSupport as reloadThemesIfPossible
  participant socketHelper as requestThemeReloadOverSocket
  participant Socket as UnixSocket
  participant App as Running App
  CLI->>runThemesSet: themes set <name>
  runThemesSet->>runThemesSet: write theme to config
  runThemesSet->>reloadSupport: socketPath, explicitPassword
  reloadSupport->>socketHelper: socketPath, explicitPassword
  socketHelper->>Socket: connect
  alt socket authenticates
    Socket->>Socket: authenticate
  end
  Socket->>App: "reload_config"
  App-->>Socket: success
  Socket-->>socketHelper: success
  socketHelper-->>reloadSupport: true
  reloadSupport-->>runThemesSet: ThemeReloadStatus(requested: bundleId)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Poem

🐰 I poked a socket, soft and bright,

Sent reload_config into the night,
Themes hopped out, no longer stuck,
Colors changed with a joyful pluck,
Terminals cheered — a hopping luck!


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (4 errors, 1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Cmux Swift Logging ❌ Error Line 134 in CLI/CMUXCLI+Themes.swift uses error.localizedDescription instead of String(describing: error), violating project logging conventions per .github/review-bot-rules/swift-logging.md Replace error.localizedDescription with String(describing: error) at line 134: throw CLIError(message: "Failed to launch interactive theme picker: \(String(describing: error))")
Cmux User-Facing Error Privacy ❌ Error Line 134 in CLI/CMUXCLI+Themes.swift violates user-facing error privacy by exposing raw upstream Process API errors via error.localizedDescription. Replace error.localizedDescription with String(describing: error) per the review comment to prevent exposing upstream framework implementation details.
Cmux Full Internationalization ❌ Error 11 unlocalized error messages in CLI/CMUXCLI+Themes.swift violate internationalization policy. Errors need String(localized:) with xcstrings entries for all supported locales. Add localization keys for all CLIError messages. Add entries to Resources/Localizable.xcstrings with translations for all supported locales using cli.error.* pattern.
Cmux Architecture Rethink ❌ Error PR violates established CLI error-formatting convention. Line 134 in CLI/CMUXCLI+Themes.swift uses error.localizedDescription instead of String(describing:). Replace error.localizedDescription with String(describing: error) on line 134 to match project convention for CLI error diagnostics.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Cmux Swift Actor Isolation ❓ Inconclusive No result was produced after verification. Marking as INCONCLUSIVE. Re-run the check or adjust instructions to produce a final result.
✅ Passed checks (11 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix repeated cmux themes set reloads' clearly and specifically describes the main change: resolving the issue where repeated theme set commands were not reloading.
Linked Issues check ✅ Passed The PR directly addresses issue #4355 by routing theme commands through the authenticated socket reload_config path, implementing fallback to distributed notifications, and adding regression tests verifying reloads after consecutive theme writes.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the repeated theme set reload issue: socket-based reload routing, notification filtering by bundle ID, and deferring terminal theme sync to prevent re-entrant reloads.
Cmux Swift Blocking Runtime ✅ Passed No new blocking/timing patterns in production code. CLI code appropriately uses process.waitUntilExit() replacing execve. Test-only semaphores already existed.
Cmux No Hacky Sleeps ✅ Passed PR modifies Swift theme reload code. Custom check scope is non-Swift production (TypeScript, JavaScript, shell). No violations found. Test Thread.sleep is appropriate scaffolding.
Cmux Swift Concurrency ✅ Passed Test-only DispatchQueue with proper lifecycle and AppKit boundary DispatchQueue.main.async are allowed per rules. No legacy patterns for ordinary async work detected.
Cmux Swift @Concurrent ✅ Passed No @concurrent violations found. New functions perform synchronous I/O in CLI layer without violating concurrency rules.
Cmux Swift File And Package Boundaries ✅ Passed No new oversized files. Max +35 lines to files under 500 lines; +16 lines to 1595-line file, far below 250-line threshold. Focused bug fix with clear extraction path.
Cmux Swiftui State Layout ✅ Passed PR contains no SwiftUI view changes. Changes are in CLI code, model classes, and existing AppKit bridge touched incidentally. No new state patterns introduced.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed No NSWindow, NSPanel, NSWindowController, or SwiftUI Window/WindowGroup code added or modified. Changes are CLI theme, settings store, and notification handler code only.
Description check ✅ Passed The pull request description is comprehensive and addresses all required sections from the template with clear details about changes, testing, and verification steps.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-4355-cmux-themes-set-state-dependent

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…s-set-state-dependent

# Conflicts:
#	cmuxTests/CMUXCLIErrorOutputRegressionTests.swift
@greptile-apps

greptile-apps Bot commented May 19, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes repeated and flickery cmux theme-change behavior by routing cmux themes set, cmux themes clear, and the interactive picker through a targeted distributed-notification reload (phase=final) instead of the generic Ghostty socket.reload_config path. On the app side it adds debouncing for legacy/preview reloads, cancellable final reloads, and reentrancy guards in GhosttyApp to prevent the double dark/light config-load pass that caused 3024 Day to flicker.

  • CLI side: CMUXCLI+Themes.swift replaces execve with Process+waitUntilExit, treats SIGINT/SIGTERM as a silent cancel, and posts a phase=final distributed notification after every successful theme write; CMUXCLI+ThemeSupport.swift derives the target bundle ID from the resolved socket filename so stale CMUX_BUNDLE_ID environment values are bypassed.
  • App side: AppDelegate gains a DispatchWorkItem+asyncAfter debounce for preview/legacy reloads; GhosttyApp tracks effectiveTerminalColorSchemePreference from the resolved terminal background and guards reloadConfiguration and synchronizeGhosttyRuntimeColorScheme with depth counters to suppress reentrant calls.
  • Chrome/sidebar: New WCAG-linearized luminance/contrast helpers drive sidebarContrastOverlayColor, titlebar foreground, and selected-workspace foreground colors so they remain legible on both light and semi-transparent dark terminal backgrounds.

Confidence Score: 5/5

Safe to merge; the theme reload pipeline is well-covered by new behavior-level regression tests and the changed paths are all guarded by the new reentrancy checks.

All issues found are style and architecture observations — the debounce using asyncAfter, dead parameters in the synchronization decision helper, and the depth-counter approach to reentrancy. None introduce incorrect behavior on the changed paths, and the regression test suite directly exercises the flicker path, repeated theme writes, signal-cancel handling, and stale-bundle-ID targeting.

Sources/AppDelegate.swift and Sources/GhosttyTerminalView.swift contain the new debounce and reentrancy-guard logic; a follow-on task to migrate these to structured Swift concurrency would reduce the maintenance surface.

Important Files Changed

Filename Overview
CLI/CMUXCLI+ThemeSupport.swift Adds socket-filename-to-bundle-ID mapping so the distributed reload notification targets the correct cmux variant even when CMUX_BUNDLE_ID is stale; also threads socketPath into the notification payload and through to reloadThemesIfPossible.
CLI/CMUXCLI+Themes.swift Replaces execve-based interactive picker with a Process+waitUntilExit loop; treats SIGINT/SIGTERM and conventional exit codes 130/143 as silent cancels; posts final theme reload notification only on a completed (exit 0) picker run.
Sources/AppDelegate.swift Adds DispatchWorkItem+asyncAfter debounce for legacy/preview theme reloads; final reloads cancel any pending work item and fire immediately. The asyncAfter pattern is flagged by the swift-blocking-runtime rule.
Sources/GhosttyTerminalView.swift Adds effectiveTerminalColorSchemePreference, reloadConfigurationDepth, and runtimeColorSchemeSynchronizationDepth to GhosttyApp; reentrancy guards suppress double-reloads but leave the reachable-bad-state representable (flagged as a structural concern).
Sources/App/GhosttySurfaceConfigurationRefresh.swift Introduces reload source constants (legacy/preview/final), debounce predicate, and applySurfaceColorScheme callback into applyAfterAppConfigReload; clean addition.
Sources/Sidebar/SidebarAppearanceSupport.swift Adds WCAG-linearized relative luminance and contrast helpers and new titlebarControlForegroundNSColor; all math is straightforward.
Sources/Windowing/WindowAppearanceSnapshot.swift compositedTerminalBackgroundColor now produces an opaque composited color; chromeColorScheme and sidebarContrastOverlayColor added; WindowBackdropController opacity check correctly migrated to terminalBackgroundOpacity.
Sources/SocketControlSettings.swift inheritedBundleIdentifierConflicts check blocks CMUX_SOCKET_PATH override when the inherited CMUX_BUNDLE_ID mismatches the running bundle, preventing stale environment leaks.

Sequence Diagram

sequenceDiagram
    participant CLI as cmux CLI
    participant DN as DistributedNotificationCenter
    participant AD as AppDelegate
    participant GA as GhosttyApp
    participant S as GhosttySurface

    CLI->>CLI: writeManagedThemeOverride()
    CLI->>DN: "post(cmuxThemesReload, phase=final, bundleId, socketPath)"

    alt legacy / preview reload
        DN-->>AD: "handleThemesReloadNotification(phase=preview)"
        AD->>AD: debounce 180ms asyncAfter + DispatchWorkItem
        AD->>GA: "reloadConfiguration(source=preview)"
    else final reload
        DN-->>AD: "handleThemesReloadNotification(phase=final)"
        AD->>AD: cancel pending workItem immediately
        AD->>GA: "reloadConfiguration(source=final)"
    end

    GA->>GA: "guard reloadConfigurationDepth == 0"
    GA->>GA: runtimeColorSchemeForConfigLoad() stable scheme for single-theme
    GA->>GA: synchronizeGhosttyRuntimeColorScheme(loadScheme)
    GA->>GA: updateDefaultBackground effectiveTerminalColorSchemePreference
    GA->>GA: synchronizeGhosttyRuntimeColorScheme(resolvedScheme)
    GA->>GA: ghostty_app_update_config()
    GA->>AD: scheduleSurfaceRefreshAfterConfigurationReload(preferredColorScheme)
    AD->>S: reapplySurfaceColorSchemeAfterGhosttyConfigReload(preferred)
    AD->>S: reloadSurfaceConfiguration(soft, source)
    AD->>S: refreshHostBackgroundAfterGhosttyConfigReload()
Loading

Reviews (22): Last reviewed commit: "fix: preserve right sidebar remembered m..." | Re-trigger Greptile

Comment thread CLI/CMUXCLI+ThemeSupport.swift Outdated
coderabbitai[bot]
coderabbitai Bot previously requested changes May 19, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 `@CLI/CMUXCLI`+ThemeSupport.swift:
- Around line 331-343: The code currently calls client.close() both via the
defer { client.close() } placed immediately after try client.connect() and again
inside the catch block, risking a double-close; remove the explicit
client.close() from the catch branch and rely on the defer to always close the
client after connect; keep the defer where it is and leave error handling in the
catch (return false) as-is, referencing client.connect(), defer { client.close()
}, authenticateClientIfNeeded(...), client.send(command:), and the catch block
to locate the change.
🪄 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: 04622fd3-c05f-4f79-b3d0-5a8253950f71

📥 Commits

Reviewing files that changed from the base of the PR and between 3d8e798 and 1be9d26.

📒 Files selected for processing (4)
  • CLI/CMUXCLI+ThemeSupport.swift
  • CLI/CMUXCLI+Themes.swift
  • CLI/cmux.swift
  • cmuxTests/CMUXCLIErrorOutputRegressionTests.swift

Comment thread CLI/CMUXCLI+ThemeSupport.swift Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 4 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread cmuxTests/CMUXCLIErrorOutputRegressionTests.swift
@lawrencecchen
lawrencecchen dismissed coderabbitai[bot]’s stale review May 19, 2026 08:43

Stale CodeRabbit changes-requested review from 1be9d26. The double-close finding was fixed in a270a92, the inline thread is resolved, and the latest CodeRabbit status is successful on head 43ce3c9.

@austinywang
austinywang force-pushed the issue-4355-cmux-themes-set-state-dependent branch from 44c2c5f to 935c7c9 Compare May 19, 2026 09:10
Comment thread cmuxTests/CMUXCLIErrorOutputRegressionTests.swift Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread CLI/CMUXCLI+Themes.swift
coderabbitai[bot]
coderabbitai Bot previously requested changes May 19, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 `@CLI/CMUXCLI`+Themes.swift:
- Line 134: Replace error.localizedDescription with String(describing: error)
when constructing the CLIError in the interactive theme picker throw site;
update the throw CLIError(message: "Failed to launch interactive theme picker:
\(error.localizedDescription)") to use String(describing: error) so the CLIError
includes the full diagnostic for non-LocalizedError types (reference the throw
site that constructs CLIError in CMUXCLI+Themes.swift).
🪄 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: eb815632-5f46-437e-b667-6f92bbaebeaf

📥 Commits

Reviewing files that changed from the base of the PR and between b4cba6c and 8a4e57c.

📒 Files selected for processing (3)
  • CLI/CMUXCLI+Themes.swift
  • Sources/AppDelegate.swift
  • cmuxTests/CMUXCLIErrorOutputRegressionTests.swift

Comment thread CLI/CMUXCLI+Themes.swift Outdated
…s-set-state-dependent

# Conflicts:
#	Sources/KeyboardShortcutSettingsFileStore.swift
#	cmuxTests/KeyboardShortcutSettingsFileStoreStartupTests.swift
@lawrencecchen
lawrencecchen dismissed coderabbitai[bot]’s stale review May 19, 2026 09:59

Addressed in 415c1a0 by switching the CLI error formatting to String(describing: error). CodeRabbit's latest status for the head commit is passing.

Comment thread Sources/GhosttyTerminalView.swift
@austinywang

Copy link
Copy Markdown
Contributor Author

Updated with the working fix in two commits:

  • 15709e439 test: cover cmux theme reload notifications
  • 59fc0abd4 fix: keep cmux theme reloads stateful

What changed:

  • cmux themes set now posts the cmux theme reload notification with phase=final instead of falling through the generic socket.reload_config path.
  • Removed the already_applied runtime color-scheme skip so same-lightness theme changes can still reapply Ghostty's runtime color-scheme signal.
  • During cmux same-theme reloads, the load phase preserves the resolved terminal scheme, so applying 3024 Day while already light stays light instead of pulsing through dark.
  • Preview reloads remain debounced; final reloads cancel any pending preview and apply immediately.

Dogfood:

  • Built the tagged debug app with ./scripts/reload.sh --tag fix-day3024-flicker.
  • Reproduced repeated changes through CMUX_TAG=fix-day3024-flicker scripts/cmux-debug-cli.sh --json themes set ....
  • Verified repeated 3024 Night / 3024 Day changes continue to apply after the first change.
  • Confirmed the targeted 3024 Day while already light path logs distributed.cmux.themes.final, uses load scheme=light, and does not emit socket.reload_config or already_applied.

Tests:

  • Added behavior-level regression coverage for repeated theme writes posting final reload notifications and avoiding generic socket reloads.
  • Added runtime scheme decision/load-scheme coverage for the flicker path.
  • Did not run tests locally per repo policy; CI is running on the pushed branch.

Comment thread CLI/CMUXCLI+ThemeSupport.swift
Comment thread Sources/Windowing/WindowAppearanceSnapshot.swift
Comment thread Sources/Windowing/WindowAppearanceSnapshot.swift Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 452745b. Configure here.

Comment thread Sources/Windowing/WindowAppearanceSnapshot.swift
@wowpotato

Copy link
Copy Markdown
Contributor

▎ Thanks for the flicker fix and the regression tests — solid work.
▎
▎ Flagging an unintended UX regression for users with custom dark themes:
▎
▎ Repro
▎ - cmux 0.64.8, macOS dark mode
▎ - theme = dark:Nord (background #2e3440)
▎ - Sidebar / titlebar / panel foreground colors are now derived from the composited terminal background via the new contrast helpers.
▎
▎ Observed
▎ The chrome reads noticeably different from 0.64.7 — even though my theme didn't change, the surrounding UI did. For users who tuned palettes against a fixed chrome, this feels like
▎ the app silently restyled itself.
▎
▎ Suggestion
▎ Could the adaptive contrast derivation be gated behind a setting (e.g. sidebarAppearance.adaptiveContrast defaulting to true to preserve the new behavior, but allowing false for users
▎ who want the pre-0.64.8 fixed chrome)? That keeps the flicker fix intact while giving users an escape hatch.

This branch was successfully deployed

1 active deployment
Preview – cmux — aac80054 Deployed May 20, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cmux themes set: only the first invocation applies — subsequent calls silently no-op

2 participants