dsh-dracula-theme 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lib/client.js +54 -47
  2. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -799,51 +799,59 @@ window.__ModuleLoader__.load({
799
799
  style.remove();
800
800
  }, "dsh-dracula-theme: surface tint lifecycle");
801
801
 
802
- // Restore the saved skin against the boot adoption storm. The
803
- // ThemeService adopts its durable built-in preference
804
- // ("light"/"dark"/"system") from the Host settings scope
805
- // asynchronously after boot; every adoption emits theme/change
806
- // with a built-in preference that overwrites a third-party one.
807
- // In slower boot paths the desktop client's RPC bridge emits
808
- // more, later sync events a fixed retry budget (a handful of
809
- // tries within a few seconds) can be exhausted and the theme
810
- // silently reverts to default. So instead of a time-boxed guard
811
- // we stay armed while the storm is active: re-assert the saved
812
- // skin on every built-in revert, and only yield to user actions
813
- // once the preference has rested on the saved skin for a quiet
814
- // period with no further adoption events.
802
+ // Restore the saved skin and hold it against the theme runtime's
803
+ // built-in preference. The ThemeService adopts its durable
804
+ // built-in preference ("light"/"dark"/"system") from the Host
805
+ // settings scope; every adoption emits theme/change with a
806
+ // built-in preference that overwrites a third-party one. That can
807
+ // happen not only in a boot storm, but ANY time the settings
808
+ // document is re-synced mid-session (another client touching the
809
+ // shared settings.yaml is enough) which silently reverts the
810
+ // UI to the built-in appearance without any user action.
811
+ //
812
+ // Strategy: track the last observed durable value. A built-in
813
+ // preference equal to it is an adoption echo of an unchanged
814
+ // document re-assert the saved skin. A different value is a
815
+ // real user change of the Appearance row (or the first boot
816
+ // adoption, within a short boot window) — the first sighting
817
+ // within the boot window re-asserts, any later one is respected
818
+ // and drops our stored choice, so the user's explicit
819
+ // appearance choice always wins afterwards.
815
820
  const saved = readSavedSkin();
816
- const savedValid = typeof saved === "string" && saved !== DEFAULT_SKIN && SKINS.some((skinDefinition) => skinDefinition.id === saved);
817
- let armed = savedValid;
818
- let quietTimer;
819
- const disarm = () => {
820
- armed = false;
821
- };
822
- const scheduleDisarm = () => {
823
- clearTimeout(quietTimer);
824
- quietTimer = setTimeout(disarm, 4000);
821
+ let savedValid = typeof saved === "string" && saved !== DEFAULT_SKIN && SKINS.some((skinDefinition) => skinDefinition.id === saved);
822
+ let lastSeenDurable = null;
823
+ const bootUntil = Date.now() + 15000;
824
+
825
+ /** Re-assert the saved skin from a fresh task (see the dispatch note below). */
826
+ const reassertSaved = () => {
827
+ if (!savedValid) return;
828
+ setTimeout(() => {
829
+ const pref = ctx.theme.getTheme().preference;
830
+ if (pref !== saved) ctx.theme.setTheme(saved);
831
+ }, 0);
825
832
  };
826
- const reassertAgainstAdoption = () => {
827
- if (!armed) return;
828
- const pref = ctx.theme.getTheme().preference;
829
- if (pref === saved) {
830
- scheduleDisarm();
833
+ /** Handle a built-in preference (light/dark/system) sighting. */
834
+ const considerBuiltin = (pref) => {
835
+ if (pref === lastSeenDurable) {
836
+ // Adoption echo: the document was re-synced with the same
837
+ // durable value. Hold the skin.
838
+ reassertSaved();
831
839
  return;
832
840
  }
833
- if (pref === "light" || pref === "dark" || pref === DEFAULT_SKIN) {
834
- // A built-in won — during boot this can only be a scope
835
- // adoption (nobody reaches the Appearance row that fast).
836
- // Re-assert, then require another quiet period.
837
- ctx.theme.setTheme(saved);
838
- scheduleDisarm();
841
+ lastSeenDurable = pref;
842
+ if (Date.now() <= bootUntil) {
843
+ // First sighting inside the boot window the boot
844
+ // adoption arriving. Restore the saved skin.
845
+ reassertSaved();
846
+ return;
839
847
  }
840
- // Another third-party theme the drop-foreign convention
841
- // below clears our stored choice instead of fighting.
848
+ // A durable change after boot is a real user action on the
849
+ // Appearance row: respect it and drop our stored choice so
850
+ // later echoes of the same value cannot resurrect the skin.
851
+ writeSavedSkin(DEFAULT_SKIN);
852
+ savedValid = false;
842
853
  };
843
- reassertAgainstAdoption();
844
- ctx.effect(() => () => {
845
- clearTimeout(quietTimer);
846
- }, "dsh-dracula-theme: boot restore lifecycle");
854
+ considerBuiltin(ctx.theme.getTheme().preference);
847
855
 
848
856
  const skinStore = createSkinStore();
849
857
  let skinBound;
@@ -852,19 +860,18 @@ window.__ModuleLoader__.load({
852
860
  };
853
861
  ctx.on("theme/change", (snapshot) => {
854
862
  syncSkin(snapshot);
863
+ const pref = snapshot.preference;
864
+ if (pref === DEFAULT_SKIN || pref === "light" || pref === "dark") {
865
+ considerBuiltin(pref);
866
+ return;
867
+ }
855
868
  // If the preference moved to another plugin's third-party theme,
856
869
  // drop our stored choice so only the last-picked plugin restores
857
870
  // at boot (both plugins must implement this convention).
858
- const pref = snapshot.preference;
859
- if (pref !== DEFAULT_SKIN && pref !== "light" && pref !== "dark" && !SKINS.some((skinDefinition) => skinDefinition.id === pref)) {
871
+ if (!SKINS.some((skinDefinition) => skinDefinition.id === pref)) {
860
872
  writeSavedSkin(DEFAULT_SKIN);
873
+ savedValid = false;
861
874
  }
862
- // Re-assert from a fresh task: a re-entrant setTheme inside the
863
- // dispatch is missed by other subscribers (ui-layout's
864
- // ThemePresenter), so the restored skin would never reach the DOM.
865
- setTimeout(() => {
866
- reassertAgainstAdoption();
867
- }, 0);
868
875
  });
869
876
 
870
877
  ctx.effect(() => ctx.locale.register(SETTINGS_NS, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-dracula-theme",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "🧛 Dracula theme for DeepSeek Harness: the classic dark palette (plus the Soft variant) registered into the built-in theme runtime",
5
5
  "license": "MIT",
6
6
  "author": "ossFrankFrank",