Skip to content

Add: reactive theme switching (auto dark/light based on OS appearance)#652

Open
LeonFedotov wants to merge 7 commits intoPiebald-AI:mainfrom
LeonFedotov:feat/reactive-theme
Open

Add: reactive theme switching (auto dark/light based on OS appearance)#652
LeonFedotov wants to merge 7 commits intoPiebald-AI:mainfrom
LeonFedotov:feat/reactive-theme

Conversation

@LeonFedotov
Copy link
Copy Markdown

@LeonFedotov LeonFedotov commented Apr 1, 2026

Summary

Two patches for the theme system:

1. Fix theme detection (always-applied)

Replaces the broken COLORFGBG startup detection with cross-platform native detection. Benefits all users with theme: "auto", not just those enabling reactive switching.

  • macOS: defaults read -g AppleInterfaceStyle (instant)
  • Linux: gdbus call on freedesktop appearance portal
  • Windows: reg query for AppsUseLightTheme
  • Fallback: COLORFGBG (preserved for terminals that set it)

2. Reactive theme switching (opt-in feature)

Patches ThemeProvider's empty useEffect to load a platform-native theme watcher (tw.js in CONFIG_DIR). Auto-switches theme when OS appearance changes mid-session.

  • 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 native async OSC 11 (500ms poll)

Motivation

Claude Code's "auto" theme only detects dark/light mode once at startup via COLORFGBG, 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

File Change
src/patches/themeDetection.ts NEW — always-applied COLORFGBG fix (cross-platform detection)
src/patches/themeDetection.test.ts NEW — 5 tests for detection patching
src/patches/reactiveTheme.ts NEW — opt-in useEffect patch (loads tw.js)
src/patches/reactiveTheme.test.ts NEW — 6 tests against 3 CC version patterns
src/reactiveThemeWatcher.ts NEW — tw.js source (written to CONFIG_DIR at apply time)
src/types.ts 3 new MiscConfig fields
src/defaultSettings.ts Default values (opt-in, enableReactiveTheme: false)
src/patches/index.ts Both patches registered + tw.js install/cleanup
src/ui/components/MiscView.tsx MiscConfig defaults for TUI

Config

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_HOME overrides. tw.js is cleaned up when the feature is disabled.

Testing

  • 11 unit tests covering 3 CC version patterns (v2.1.86, v2.1.87, v2.1.89)
  • Idempotency tests (apply twice → no change)
  • Failure case tests (patterns not found → returns null)
  • Custom theme ID test
  • pnpm lint passes
  • pnpm run test passes (232 total, 0 failures)
  • pnpm prettier --check src passes
  • Manual test: macOS arm64, CC 2.1.89, dark/light toggle works reactively

Summary by CodeRabbit

  • New Features

    • Reactive theme switching that follows system appearance on macOS, Linux, and Windows.
    • UI settings to enable/disable reactive theming and to customize dark/light theme identifiers.
    • Automatic install/cleanup of a small runtime watcher when reactive theming is enabled.
    • Improved cross-platform theme detection fallback for environments lacking native signals.
  • Tests

    • Added tests covering reactive theme injection, theme-detection, idempotency, and error handling.

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
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 1, 2026

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

Adds 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

Cohort / File(s) Summary
Config & Types
src/defaultSettings.ts, src/types.ts, src/ui/components/MiscView.tsx
Added misc fields enableReactiveTheme: boolean, reactiveThemeDarkId: string, reactiveThemeLightId: string with defaults false, "dark", "light"; UI defaults updated.
Patch registry & wiring
src/patches/index.ts
Registered reactive-theme (guarded by enableReactiveTheme) and fix-theme-detection; wired writeReactiveTheme and writeThemeDetection; applyCustomization now writes or removes tw.js in CONFIG_DIR.
Patch implementations & tests
src/patches/reactiveTheme.ts, src/patches/reactiveTheme.test.ts, src/patches/themeDetection.ts, src/patches/themeDetection.test.ts
New writeReactiveTheme (exports ReactiveThemeConfig) injects guarded dynamic loader calling tw.js; new writeThemeDetection replaces COLORFGBG detect logic with cross-platform detection. Tests cover multiple bundle shapes, idempotency, and failure logging.
Runtime watcher
src/reactiveThemeWatcher.ts
Added REACTIVE_THEME_WATCHER_JS: CommonJS watcher script supporting macOS (file or defaults plist), Linux (gdbus + monitor), Windows (registry + PowerShell), and an OSC-based fallback; returns cleanup function for useEffect.

Sequence Diagrams

sequenceDiagram
    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
Loading
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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • bl-ue
  • georpar

Poem

🐰 I hopped into code with a twitch and a grin,

I taught dark and light how quietly to spin.
I drop a small watcher named "tw.js" to run,
It listens for moods and nudges themes when done.
Tiny paws, big tweaks — now let the skins have fun.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main feature addition: reactive theme switching with automatic dark/light detection based on OS appearance, which aligns with the PR's primary objective.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/patches/index.ts (1)

906-913: Consider cleanup of tw.js when feature is disabled.

The tw.js file is written to CONFIG_DIR when enableReactiveTheme is 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

📥 Commits

Reviewing files that changed from the base of the PR and between bc5cdbe and 37e91be.

📒 Files selected for processing (7)
  • src/defaultSettings.ts
  • src/patches/index.ts
  • src/patches/reactiveTheme.test.ts
  • src/patches/reactiveTheme.ts
  • src/reactiveThemeWatcher.ts
  • src/types.ts
  • src/ui/components/MiscView.tsx

Comment thread src/patches/reactiveTheme.ts
Comment thread src/reactiveThemeWatcher.ts Outdated
Comment on lines +140 to +141
var configDir = _path.join(HOME, '.tweakcc');
var psScript = _path.join(configDir, 'theme-watcher.ps1');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

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)
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/patches/themeDetection.test.ts (1)

46-59: Redundant clearCaches() call.

Line 47 calls clearCaches() but beforeEach already 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

📥 Commits

Reviewing files that changed from the base of the PR and between 1e1c58b and 09d9bb4.

📒 Files selected for processing (5)
  • src/patches/index.ts
  • src/patches/reactiveTheme.test.ts
  • src/patches/reactiveTheme.ts
  • src/patches/themeDetection.test.ts
  • src/patches/themeDetection.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/patches/reactiveTheme.test.ts

Comment thread src/patches/reactiveTheme.ts Outdated
- 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)
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/patches/reactiveTheme.ts (1)

43-44: Anchor on the full ThemeProvider memo shape.

marker stops 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

📥 Commits

Reviewing files that changed from the base of the PR and between 09d9bb4 and 9729e6f.

📒 Files selected for processing (3)
  • src/patches/reactiveTheme.test.ts
  • src/patches/reactiveTheme.ts
  • src/patches/themeDetection.test.ts
✅ Files skipped from review due to trivial changes (1)
  • src/patches/reactiveTheme.test.ts

Comment thread src/patches/reactiveTheme.ts Outdated
Comment thread src/patches/themeDetection.test.ts Outdated
@LeonFedotov
Copy link
Copy Markdown
Author

Note: native bytecode builds

The fix-theme-detection and reactive-theme patches work correctly on npm installs (readable cli.js), but fail on native binary installs where the extracted JS has a @bun @bytecode header — function bodies are compiled bytecode, not regex-searchable text.

This is the same root cause as #628, #629, #635, #645 — most tweakcc patches fail on recent native builds because extractClaudeJsFromNativeInstallation pulls the bytecode module instead of the source JS module.

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>
@LeonFedotov
Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 1, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 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: Use debug() for patch-failure logs instead of console.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

📥 Commits

Reviewing files that changed from the base of the PR and between 9729e6f and 4a5eb7d.

📒 Files selected for processing (2)
  • src/patches/reactiveTheme.ts
  • src/patches/themeDetection.test.ts
✅ Files skipped from review due to trivial changes (1)
  • src/patches/themeDetection.test.ts

Copy link
Copy Markdown
Member

@bl-ue bl-ue left a comment

Choose a reason for hiding this comment

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

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
@LeonFedotov
Copy link
Copy Markdown
Author

@bl-ue I understand what you mean, did you have a chance to look at my other pr? #654
do you have ideas how to manage this without hardcoding var names? my idea is to ask claude to do the actual injecting by looking at its own code in a hidden session, or like similar to what oh-my-zsh has where it asks you to confirm an update from time to time so in the same manner from time to time (when CC updates) it will launch with a message saying "post update claude agent session ok? i need to fix the injections and adjust varnames gimmie a sec"
or similarly setup a ci workflow that triggers every so often checks claude code version if its new then starts opus to find the right code positions and var names for that version and commits it back to this repo...
wdyt?

@LeonFedotov
Copy link
Copy Markdown
Author

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.

@LeonFedotov LeonFedotov requested a review from bl-ue April 2, 2026 10:22
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.

2 participants