fix(themes): desktop repaints when the ACTIVE skin is edited in place - #69581
Merged
Conversation
Live theme authoring's core loop — Hermes recolors the skin file it just activated — repainted the TUI but not the GUI. The event path was fine (post-#69533 the WS broadcast lands and ingestBackendSkin refreshes the $backendThemes registry); the same-name apply guard also no-ops correctly (it's what protects a manual desktop theme pick). The repaint was supposed to come from the registry: the active theme IS that skin, its palette just changed. But ThemeProvider memoized deriveTheme on [themeName, resolvedMode] only, while deriveTheme reads the registry non-reactively via resolveTheme — so the store update re-rendered the provider and handed back the stale palette. Name switches repainted (themeName moves); recolors never did. Add the theme stores (user/backend/registry) to the memo's deps — they are deriveTheme's actual reactivity, same as the availableThemes memo directly above. applyTheme is idempotent, and $backendThemes only publishes on a real palette change, so no spurious repaints. Tests: render ThemeProvider for real — activation applies; a same-name recolor repaints (fails without the fix); an inactive-skin seed doesn't touch the painted theme.
OutThisLife
enabled auto-merge
July 22, 2026 20:09
Contributor
૮ >ﻌ< ა ci reviewrunning on afd0270 CI timingsCI timings · View jobWall time 8m33s vs 8m15s (+3.6%). 3 job(s) slower, 3 faster, 1 unchanged.
|
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
…edit-repaint fix(themes): desktop repaints when the ACTIVE skin is edited in place
33hodl
pushed a commit
to 33hodl/hermes-agent
that referenced
this pull request
Aug 12, 2026
…edit-repaint fix(themes): desktop repaints when the ACTIVE skin is edited in place
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Third and final leg of the live-theme loop (#68857, #69533). Repro from dogfooding session
20260722_145956_5ebda8: Hermes activates a new skin — every surface paints (that's #69533 working). Then "make it hot pink" — Hermes rewrites the same skin file. TUI repaints; desktop doesn't.Why
Everything upstream was already correct:
ingestBackendSkinrefreshes the$backendThemesregistry with the new palette,The repaint on a recolor is supposed to come from the registry: the active theme IS that skin, and its palette just changed.
ThemeProvidereven subscribes to$backendThemes… but memoized the derived active theme on[themeName, resolvedMode]only, whilederiveThemereads the registry non-reactively (resolveTheme→$backendThemes.get()). The store update re-rendered the provider and the memo handed back the stale palette — soapplyThemenever re-ran. A name switch busts the memo (that's why activation worked); an in-place edit never did.Fix
One memo: add the theme stores (
userThemes,backendThemes,registryVersion) to theactiveThemedeps — they'rederiveTheme's actual reactivity, exactly mirroring theavailableThemesmemo ten lines above. No new events, no guard changes.applyThemeis idempotent and$backendThemesonly publishes on a real palette diff, so there are no spurious repaints.Also covers the sibling paths for free: an in-place edit of an active user-installed theme and a registry-contributed theme update now repaint too.
Tests
context.test.tsxrenders the realThemeProvider(jsdom, CSS vars on:root):mainwithout the fix ✓Themes suite 66✓ (8 files), typecheck + lint clean.