Add: reactive theme switching (auto dark/light based on OS appearance)#652
Add: reactive theme switching (auto dark/light based on OS appearance)#652LeonFedotov wants to merge 7 commits intoPiebald-AI:mainfrom
Conversation
Patches the ThemeProvider's empty useEffect to load ~/.tweakcc/tw.js, which sets up platform-native theme watchers. Also replaces the COLORFGBG detect function with cross-platform detection for better startup accuracy. Platform support: - macOS: fs.watch on GlobalPreferences.plist (~100ms), optional Swift watcher (0ms) - Linux: gdbus monitor on freedesktop portal (event-driven, 0ms) - Windows: PowerShell RegNotifyChangeKeyValue (event-driven, 0ms) - SSH/tmux: TerminalQuerier OSC 11 native async (500ms poll) Config: misc.enableReactiveTheme, misc.reactiveThemeDarkId, misc.reactiveThemeLightId
|
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:
📝 WalkthroughWalkthroughAdds a reactive-theme feature: new misc settings and UI defaults, two new patchers (reactive-theme and theme-detection) with tests, a runtime watcher script emitted to CONFIG_DIR/tw.js, and install/remove logic for that watcher in applyCustomization. Changes
Sequence DiagramssequenceDiagram
participant App as applyCustomization
participant Patch as Patch System
participant Bundle as Target JS Bundle
participant FS as CONFIG_DIR (tw.js)
participant Watcher as Watcher Script (tw.js)
participant OS as Operating System
App->>Patch: apply "reactive-theme" / "fix-theme-detection"
activate Patch
Patch->>Bundle: run writeThemeDetection / writeReactiveTheme
Patch->>FS: write `tw.js` when enabled
Patch-->>App: patched bundle saved
deactivate Patch
Note over Watcher,OS: Runtime (when theme setting == "auto")
Watcher->>OS: query platform appearance (darwin/linux/win32 or OSC)
OS-->>Watcher: current theme (dark/light)
Watcher->>Bundle: call theme setter with darkId/lightId
sequenceDiagram
participant Darwin as macOS Watcher
participant Linux as Linux Watcher
participant Win as Windows Watcher
participant Fallback as OSC Fallback
participant AppState as App setState
rect rgba(100,150,200,0.5)
Darwin->>Darwin: read ~/.claude/.current-theme or `defaults read`
Darwin->>Darwin: fs.watch / plist watch -> debounce
Darwin-->>AppState: setState(dark/light)
end
rect rgba(100,200,150,0.5)
Linux->>Linux: gdbus Settings.Read + monitor process
Linux-->>AppState: setState(dark/light)
end
rect rgba(200,150,100,0.5)
Win->>Win: registry query + spawn PowerShell monitor
Win-->>AppState: setState(dark/light)
end
rect rgba(150,150,150,0.5)
Fallback->>Fallback: poll OSC 11, parse luminance -> map to dark/light
Fallback-->>AppState: setState(dark/light)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/patches/index.ts (1)
906-913: Consider cleanup oftw.jswhen feature is disabled.The
tw.jsfile is written toCONFIG_DIRwhenenableReactiveThemeis true, but it's never removed when the feature is subsequently disabled. While harmless (the file won't be loaded if the patch isn't applied), this could leave orphaned files.This is minor and can be addressed in a follow-up if desired.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/patches/index.ts` around lines 906 - 913, The code currently writes tw.js to CONFIG_DIR when config.settings.misc?.enableReactiveTheme is true (using twJsPath and REACTIVE_THEME_WATCHER_JS) but never removes it if the feature is later disabled; update the same block around enableReactiveTheme to remove the file when the flag is false by checking for the existing file (twJsPath) and deleting it (safe-check with fsSync.existsSync and fsSync.unlinkSync or a try/catch to ignore missing-file errors), so tw.js is cleaned up when enableReactiveTheme is turned off while preserving the current write behavior when enabled.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/patches/reactiveTheme.ts`:
- Around line 137-142: The generated require() in the patch for reactiveTheme.ts
hardcodes "~/.tweakcc/tw.js", so update the string literal inserted by the patch
generator to use the resolved CONFIG_DIR at apply-time instead of
".tweakcc","tw.js"; specifically, when building the replacement string for
${reactVar}.useEffect (the block using ${requireFunc} and returning
require(...)(
${setStateVar}${querierArg},"${config.darkThemeId}","${config.lightThemeId}" )),
replace the path construction arguments with the single resolved config
directory + "/tw.js" string (injected by the patcher) so the require call uses
the correct CONFIG_DIR (respecting TWEAKCC_CONFIG_DIR / XDG paths) rather than
the hardcoded segments.
In `@src/reactiveThemeWatcher.ts`:
- Around line 140-141: The watchWindows function currently builds psScript using
_path.join(HOME, '.tweakcc'), which can diverge from the actual CONFIG_DIR
(overridden by TWEAKCC_CONFIG_DIR); update watchWindows to accept or import the
canonical CONFIG_DIR from src/config.ts (or read process.env.TWEAKCC_CONFIG_DIR)
and use _path.join(CONFIG_DIR, 'theme-watcher.ps1') for psScript, and likewise
update the require path in reactiveTheme.ts (the require of ".tweakcc","tw.js")
to derive from the same CONFIG_DIR instead of hardcoding ".tweakcc"; ensure the
function signature or call sites pass CONFIG_DIR if making it a parameter so
both writing and requiring the script use the same resolved config directory.
---
Nitpick comments:
In `@src/patches/index.ts`:
- Around line 906-913: The code currently writes tw.js to CONFIG_DIR when
config.settings.misc?.enableReactiveTheme is true (using twJsPath and
REACTIVE_THEME_WATCHER_JS) but never removes it if the feature is later
disabled; update the same block around enableReactiveTheme to remove the file
when the flag is false by checking for the existing file (twJsPath) and deleting
it (safe-check with fsSync.existsSync and fsSync.unlinkSync or a try/catch to
ignore missing-file errors), so tw.js is cleaned up when enableReactiveTheme is
turned off while preserving the current write behavior when enabled.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f7164d34-2b88-4932-93dc-88e3e10db6fc
📒 Files selected for processing (7)
src/defaultSettings.tssrc/patches/index.tssrc/patches/reactiveTheme.test.tssrc/patches/reactiveTheme.tssrc/reactiveThemeWatcher.tssrc/types.tssrc/ui/components/MiscView.tsx
| var configDir = _path.join(HOME, '.tweakcc'); | ||
| var psScript = _path.join(configDir, 'theme-watcher.ps1'); |
There was a problem hiding this comment.
Hardcoded ~/.tweakcc path may diverge from CONFIG_DIR when TWEAKCC_CONFIG_DIR is set.
The watchWindows function hardcodes _path.join(HOME, '.tweakcc') for the PowerShell script location. However, CONFIG_DIR in src/config.ts can be overridden via the TWEAKCC_CONFIG_DIR environment variable, or may resolve to ~/.claude/tweakcc or $XDG_CONFIG_HOME/tweakcc. If users customize their config directory, the PowerShell script will be written to a different location than expected.
The same issue applies to the require() path in reactiveTheme.ts (line 140) which hardcodes ".tweakcc","tw.js".
Consider passing the config directory path as a parameter or reading it from an environment variable at runtime.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/reactiveThemeWatcher.ts` around lines 140 - 141, The watchWindows
function currently builds psScript using _path.join(HOME, '.tweakcc'), which can
diverge from the actual CONFIG_DIR (overridden by TWEAKCC_CONFIG_DIR); update
watchWindows to accept or import the canonical CONFIG_DIR from src/config.ts (or
read process.env.TWEAKCC_CONFIG_DIR) and use _path.join(CONFIG_DIR,
'theme-watcher.ps1') for psScript, and likewise update the require path in
reactiveTheme.ts (the require of ".tweakcc","tw.js") to derive from the same
CONFIG_DIR instead of hardcoding ".tweakcc"; ensure the function signature or
call sites pass CONFIG_DIR if making it a parameter so both writing and
requiring the script use the same resolved config directory.
Address CodeRabbit review: - Use resolved CONFIG_DIR at apply time instead of hardcoded ~/.tweakcc in both the useEffect require() path and tw.js Windows watcher - Pass configDir as 5th argument to tw.js entry point - Clean up tw.js when enableReactiveTheme is disabled
Extract patchDetectFunction from reactiveTheme.ts into its own themeDetection.ts as an always-applied patch (PatchGroup.ALWAYS_APPLIED). This benefits all users with theme "auto", not just those who enable reactive theme switching. The COLORFGBG env var doesn't work on most terminals (macOS terminals don't set it). The replacement uses platform-native detection: - macOS: defaults read -g AppleInterfaceStyle - Linux: gdbus call on freedesktop appearance portal - Windows: reg query AppsUseLightTheme - Fallback: COLORFGBG (preserved)
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/patches/themeDetection.test.ts (1)
46-59: RedundantclearCaches()call.Line 47 calls
clearCaches()butbeforeEachalready clears caches before each test. This is unnecessary.🧹 Remove redundant call
it('handles different function names (v2.1.87)', () => { - clearCaches(); const detect87 =🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/patches/themeDetection.test.ts` around lines 46 - 59, The test contains a redundant call to clearCaches() inside the 'handles different function names (v2.1.87)' test; remove the clearCaches() invocation from the test body (the test that builds detect87 and calls writeThemeDetection) since the test suite's beforeEach already clears caches. Locate the test by the it(...) description and the detect87 string / function MR4() and delete the clearCaches() line so the test still creates detect87, calls writeThemeDetection, and asserts the expected results.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/patches/reactiveTheme.ts`:
- Around line 136-143: The generated call to tw.js can shift arguments when dep2
(querier) is absent; change the querier fragment so the call always passes five
arguments by making querierArg equal to ',void 0' when dep2 is falsy (instead of
an empty string). Update the string assembly that builds the require call (the
replacement using reactVar.useEffect, twJsPath, setStateVar, config.darkThemeId,
config.lightThemeId, CONFIG_DIR and deps) so it injects this querierArg (',void
0' when dep2 is missing) ensuring tw.js is always invoked as (setState, querier,
darkId, lightId, configDir).
---
Nitpick comments:
In `@src/patches/themeDetection.test.ts`:
- Around line 46-59: The test contains a redundant call to clearCaches() inside
the 'handles different function names (v2.1.87)' test; remove the clearCaches()
invocation from the test body (the test that builds detect87 and calls
writeThemeDetection) since the test suite's beforeEach already clears caches.
Locate the test by the it(...) description and the detect87 string / function
MR4() and delete the clearCaches() line so the test still creates detect87,
calls writeThemeDetection, and asserts the expected results.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 80dbf553-ca01-4be3-a816-c86fcc19bd5f
📒 Files selected for processing (5)
src/patches/index.tssrc/patches/reactiveTheme.test.tssrc/patches/reactiveTheme.tssrc/patches/themeDetection.test.tssrc/patches/themeDetection.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/patches/reactiveTheme.test.ts
- Use void 0 as querier placeholder when dep2 is absent so configDir doesn't shift into the lightId position - Remove redundant clearCaches() calls in tests (beforeEach handles it)
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/patches/reactiveTheme.ts (1)
43-44: Anchor on the full ThemeProvider memo shape.
markerstops at the first{themeSetting:..., while the patch really depends on the specific{themeSetting:...,currentTheme:...}object inside ThemeProvider. That is a pretty loose hook for minified upstream code and makes the region search easier to misdirect if another object starts the same way.Based on learnings: in
src/patches/, patch regexes should be strict and match the minified upstream format exactly.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/patches/reactiveTheme.ts` around lines 43 - 44, The current loose marker regexp (the marker constant used with content.match in reactiveTheme.ts) only anchors on "{themeSetting:..." and can match unintended objects; update the marker to strictly match the full ThemeProvider memo shape including the adjacent "currentTheme" property and the same minified formatting (i.e., require "{themeSetting:<ident>,currentTheme:<ident>," with no optional whitespace) so the search targets the exact object; change the marker constant and ensure subsequent code that uses match still references the same match groups or indices.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/patches/reactiveTheme.ts`:
- Around line 137-143: The injected string literals (CONFIG_DIR,
config.darkThemeId, config.lightThemeId and the constructed twJsPath) are not
safely serialized and can break or enable code injection; update the code that
builds replacement (which references CONFIG_DIR, twJsPath, reactVar, dep1,
setStateVar and deps) to use JSON.stringify(...) for every runtime string
inserted into the emitted JS (serialize CONFIG_DIR before building twJsPath and
use JSON.stringify(config.darkThemeId) and JSON.stringify(config.lightThemeId)
and JSON.stringify(twJsPath) in the replacement) so all quotes/newlines are
escaped and no raw runtime values are embedded.
In `@src/patches/themeDetection.test.ts`:
- Line 6: Remove the inline explanatory comments from the test file
src/patches/themeDetection.test.ts (e.g., the "// Synthetic COLORFGBG detect
function from CC v2.1.89" and the other inline comment instances used inside the
test cases), leaving only the assertions and test code; locate the comments
around the theme detection tests (the top-of-file synthetic detect comment and
the two other single-line comments within the tests) and delete them so the
tests contain no inline explanatory comments per repo style.
---
Nitpick comments:
In `@src/patches/reactiveTheme.ts`:
- Around line 43-44: The current loose marker regexp (the marker constant used
with content.match in reactiveTheme.ts) only anchors on "{themeSetting:..." and
can match unintended objects; update the marker to strictly match the full
ThemeProvider memo shape including the adjacent "currentTheme" property and the
same minified formatting (i.e., require
"{themeSetting:<ident>,currentTheme:<ident>," with no optional whitespace) so
the search targets the exact object; change the marker constant and ensure
subsequent code that uses match still references the same match groups or
indices.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 8fac1fca-0278-4489-a151-2318d76670a4
📒 Files selected for processing (3)
src/patches/reactiveTheme.test.tssrc/patches/reactiveTheme.tssrc/patches/themeDetection.test.ts
✅ Files skipped from review due to trivial changes (1)
- src/patches/reactiveTheme.test.ts
Note: native bytecode buildsThe This is the same root cause as #628, #629, #635, #645 — most tweakcc patches fail on recent native builds because The native binary actually contains both modules — a bytecode version and a plaintext JS version at different offsets. The source JS is fully patchable (confirmed: my standalone binary patcher works by finding and patching the plaintext module directly). I'm working on a fix for the extraction layer — will submit as a separate PR. |
…, remove comments - Use JSON.stringify for config values injected into patched JS - Tighten ThemeProvider marker regex to include currentTheme - Remove inline comments from themeDetection.test.ts (repo style) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
🧹 Nitpick comments (3)
src/patches/reactiveTheme.ts (3)
43-44: Tighten the ThemeProvider marker regex to reduce false-positive matches.Line 43 uses a broad
[\s\S]*?span; in minified patch targets this can over-capture and make region detection brittle. Prefer a stricter minified-shape anchor.Based on learnings "In patches under src/patches/, assume code works with minified, original Claude Code installations. Patch regexes must be strict and match the minified format exactly (ignore formatting differences like whitespace/newlines)."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/patches/reactiveTheme.ts` around lines 43 - 44, The current marker regex (variable "marker" used with content.match) uses a broad [\s\S]*? which over-captures; replace that middle span with a stricter minified-shape anchor (e.g. a non-greedy character class that excludes the closing brace or only allows the expected minified tokens) so the pattern only matches within the single object expression for ThemeProvider; update the regex assigned to "marker" accordingly so content.match(marker) reliably finds the minified {themeSetting:...,currentTheme:...} fragment without spanning unrelated code.
1-24: Remove non-essential inline comments in this logic file.This file adds a large volume of descriptive comments that should be trimmed to keep patch code lean and consistent with repository standards.
As per coding guidelines "Do not add comments unless explicitly requested".
Also applies to: 35-38
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/patches/reactiveTheme.ts` around lines 1 - 24, Remove non-essential inline comments in src/patches/reactiveTheme.ts: trim the large descriptive header and verbose notes about "Reactive Theme Switching", the multi-line lists of useEffect variants (zA.useEffect, KG.useEffect, UG.useEffect) and COLORFGBG detect variants (_k5, MR4, uG4), and any other explanatory lines (including the lines referenced 35-38) so the file contains only the essential patch logic and minimal one-line clarifications per block; keep the loader replacement and COLORFGBG detection code intact and do not alter function names or implementation, only delete extraneous comment text to comply with the "Do not add comments unless explicitly requested" guideline.
88-90: Usedebug()for patch-failure logs instead ofconsole.error.The fallback behavior is good (
return null), but logging should use the project-standard debug logger for consistency and controllable verbosity.As per coding guidelines "Implement error handling with try-catch blocks, log errors with debug(), and return graceful fallbacks".
Also applies to: 106-108, 126-128
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/patches/reactiveTheme.ts` around lines 88 - 90, Replace the console.error calls in reactiveTheme (the fallback logs that say 'patch: reactiveTheme: failed to find ThemeProvider function' and the similar messages at the other occurrences) with the project debug logger: call debug(...) instead and include any available error/details in the message; ensure the debug function is imported / available in reactiveTheme.ts before using it; apply the same change for the other two occurrences referenced (around the ThemeProvider checks at the other ranges) so all patch-failure logs use debug() and keep the existing graceful return null behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/patches/reactiveTheme.ts`:
- Around line 43-44: The current marker regex (variable "marker" used with
content.match) uses a broad [\s\S]*? which over-captures; replace that middle
span with a stricter minified-shape anchor (e.g. a non-greedy character class
that excludes the closing brace or only allows the expected minified tokens) so
the pattern only matches within the single object expression for ThemeProvider;
update the regex assigned to "marker" accordingly so content.match(marker)
reliably finds the minified {themeSetting:...,currentTheme:...} fragment without
spanning unrelated code.
- Around line 1-24: Remove non-essential inline comments in
src/patches/reactiveTheme.ts: trim the large descriptive header and verbose
notes about "Reactive Theme Switching", the multi-line lists of useEffect
variants (zA.useEffect, KG.useEffect, UG.useEffect) and COLORFGBG detect
variants (_k5, MR4, uG4), and any other explanatory lines (including the lines
referenced 35-38) so the file contains only the essential patch logic and
minimal one-line clarifications per block; keep the loader replacement and
COLORFGBG detection code intact and do not alter function names or
implementation, only delete extraneous comment text to comply with the "Do not
add comments unless explicitly requested" guideline.
- Around line 88-90: Replace the console.error calls in reactiveTheme (the
fallback logs that say 'patch: reactiveTheme: failed to find ThemeProvider
function' and the similar messages at the other occurrences) with the project
debug logger: call debug(...) instead and include any available error/details in
the message; ensure the debug function is imported / available in
reactiveTheme.ts before using it; apply the same change for the other two
occurrences referenced (around the ThemeProvider checks at the other ranges) so
all patch-failure logs use debug() and keep the existing graceful return null
behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5b7e1790-9188-4266-a921-2a08d4086fb9
📒 Files selected for processing (2)
src/patches/reactiveTheme.tssrc/patches/themeDetection.test.ts
✅ Files skipped from review due to trivial changes (1)
- src/patches/themeDetection.test.ts
bl-ue
left a comment
There was a problem hiding this comment.
This is very cool, and I think it would be pretty popular! However, you've hardcoded a lot of variable names, which will completely break in the immediate next version.
# Conflicts: # src/defaultSettings.ts # src/patches/index.ts # src/types.ts # src/ui/components/MiscView.tsx
|
@bl-ue I understand what you mean, did you have a chance to look at my other pr? #654 |
|
basically: minified names change every version, so any static regex will eventually break. Instead of maintaining regex patterns manually, let an LLM read the actual code and find the right injection points dynamically. |
Summary
Two patches for the theme system:
1. Fix theme detection (always-applied)
Replaces the broken
COLORFGBGstartup detection with cross-platform native detection. Benefits all users withtheme: "auto", not just those enabling reactive switching.defaults read -g AppleInterfaceStyle(instant)gdbus callon freedesktop appearance portalreg queryforAppsUseLightThemeCOLORFGBG(preserved for terminals that set it)2. Reactive theme switching (opt-in feature)
Patches ThemeProvider's empty
useEffectto load a platform-native theme watcher (tw.jsin CONFIG_DIR). Auto-switches theme when OS appearance changes mid-session.fs.watchonGlobalPreferences.plist(~100ms), optional Swift watcher (0ms)gdbus monitoron freedesktop portal (event-driven, 0ms)RegNotifyChangeKeyValue(event-driven, 0ms)TerminalQueriernative async OSC 11 (500ms poll)Motivation
Claude Code's
"auto"theme only detects dark/light mode once at startup viaCOLORFGBG, which doesn't work on most terminals (especially macOS). Switching OS appearance mid-session leaves the UI on the wrong theme until restart.This has been the most-requested theme feature for 9+ months with no official resolution.
Related: anthropics/claude-code#2990 (213+ thumbs up, 38 comments), anthropics/claude-code#11813 (134+ thumbs up)
Supersedes: #260 (startup-only detection, self-closed)
Based on: antonioacg/claude-code-theme-patch#1 (standalone binary patcher by same author, adapted for tweakcc)
Files changed
src/patches/themeDetection.tssrc/patches/themeDetection.test.tssrc/patches/reactiveTheme.tssrc/patches/reactiveTheme.test.tssrc/reactiveThemeWatcher.tssrc/types.tsMiscConfigfieldssrc/defaultSettings.tsenableReactiveTheme: false)src/patches/index.tssrc/ui/components/MiscView.tsxConfig
The detection fix is always-applied (no config needed). Reactive switching is opt-in:
{ "settings": { "misc": { "enableReactiveTheme": true, "reactiveThemeDarkId": "dark", "reactiveThemeLightId": "light" } } }Theme IDs map to the user's configured themes array. All paths respect
TWEAKCC_CONFIG_DIR/XDG_CONFIG_HOMEoverrides. tw.js is cleaned up when the feature is disabled.Testing
pnpm lintpassespnpm run testpasses (232 total, 0 failures)pnpm prettier --check srcpassesSummary by CodeRabbit
New Features
Tests