dsh-dream-skin 0.2.0 → 0.2.2

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.
package/README.en.md CHANGED
@@ -24,6 +24,11 @@ Native skinning + wallpaper + theme packs — a romance-engineered project built
24
24
 
25
25
  </div>
26
26
 
27
+ > 🚀 **Now on npm!** With DSH installed, add it in one command — no cloning needed:
28
+ > ```sh
29
+ > dsh plugin --profile web add dsh-dream-skin
30
+ > ```
31
+
27
32
  > **Homage to [Codex-Dream-Skin](https://github.com/Fei-Away/Codex-Dream-Skin).** But the approach is different:
28
33
  > Codex injects CSS into the desktop client's renderer via CDP, whereas DSH is a **token-driven Web GUI** that ships
29
34
  > first-class "third-party plugins registering themes". So this plugin is **purely native** — no injection, no binary
@@ -74,13 +79,13 @@ Differentiation inspired by existing DSH skin projects plus Codex's skin UX:
74
79
 
75
80
  ```sh
76
81
  # 1. install
77
- dsh plugin --profile web add -w dsh-dream-skin
82
+ dsh plugin --profile web add dsh-dream-skin
78
83
  # 2. restart
79
84
  dsh web
80
85
  # 3. open Settings → General → Skins and pick one → done.
81
86
  ```
82
87
 
83
- > `-w` (workspace) is required because every profile ships a `pnpm-workspace.yaml`.
88
+ > Installs the published npm package no cloning. If `dsh plugin add` reports a workspace error, append `-w`.
84
89
 
85
90
  ## 🧩 What kind of plugin is this
86
91
 
@@ -139,16 +144,12 @@ system.
139
144
 
140
145
  ## 📦 Install
141
146
 
142
-
143
- ### Option A: From source / a local directory
147
+ ### Option A: From npm (published, **recommended**)
144
148
 
145
149
  ```sh
146
- dsh plugin --profile web add -w /path/to/dsh-dream-skin
150
+ dsh plugin --profile web add dsh-dream-skin
147
151
  ```
148
152
 
149
- > The `-w` flag is **required**: every profile ships a `pnpm-workspace.yaml`, so pnpm treats the profile directory
150
- > as a workspace root and a bare `add` fails with `ERR_PNPM_ADDING_TO_ROOT`.
151
-
152
153
  Then **restart** the web server:
153
154
 
154
155
  ```sh
@@ -158,10 +159,14 @@ dsh web
158
159
 
159
160
  Open **Settings → General** to see the **Skins**, **Accent**, **Wallpaper** / **Advanced Wallpaper**, and **Theme Packs** rows.
160
161
 
161
- ### Option B: From npm (after publishing)
162
+ > The `-w` (workspace) flag is needed on a bare `add` because every profile ships a `pnpm-workspace.yaml`; pnpm treats
163
+ > the profile directory as a workspace root, so a bare add fails with `ERR_PNPM_ADDING_TO_ROOT`. If your profile already
164
+ > uses the workspace, you won't need to repeat it.
165
+
166
+ ### Option B: From source / a local directory (developers)
162
167
 
163
168
  ```sh
164
- dsh plugin --profile web add -w dsh-dream-skin
169
+ dsh plugin --profile web add -w /path/to/dsh-dream-skin
165
170
  ```
166
171
 
167
172
  ## 🧩 Compatibility
package/README.md CHANGED
@@ -24,6 +24,11 @@
24
24
 
25
25
  </div>
26
26
 
27
+ > 🚀 **现已发布到 npm!** 装好 DSH 后,一条命令即可安装,无需 clone:
28
+ > ```sh
29
+ > dsh plugin --profile web add dsh-dream-skin
30
+ > ```
31
+
27
32
  > **致敬 [Codex-Dream-Skin](https://github.com/Fei-Away/Codex-Dream-Skin)。** 但实现路径不同:Codex 是往桌面客户端渲染进程
28
33
  > 注入 CSS(CDP),而 DSH 本身是 **token 驱动的 Web GUI**,官方就提供了「第三方插件注册主题」的能力——所以本插件是
29
34
  > **纯原生接入**,无注入、不改二进制、不因客户端更新失效。
@@ -126,25 +131,22 @@ DeepSeek Harness 的口号是「一切皆插件」:模型、工具、沙箱、
126
131
 
127
132
  ```sh
128
133
  # 1. 安装
129
- dsh plugin --profile web add -w dsh-dream-skin
134
+ dsh plugin --profile web add dsh-dream-skin
130
135
  # 2. 重启
131
136
  dsh web
132
137
  # 3. 打开 设置 → 常规 → 皮肤,挑一套 → 完。
133
138
  ```
134
139
 
135
- > 传入 `-w`(workspace)是因为每个 profile 自带 `pnpm-workspace.yaml`,pnpm 需要知道这是 workspace 安装。
140
+ > 装的是 npm 已完成发布的正式包,无需 clone。若 `dsh plugin add` 报 workspace 相关错误,补一个 `-w` 即可。
136
141
 
137
142
  ## 📦 安装
138
143
 
139
- ### 方式一:从源码 / 本地目录
144
+ ### 方式一:npm(已发布,**推荐**)
140
145
 
141
146
  ```sh
142
- dsh plugin --profile web add -w /path/to/dsh-dream-skin
147
+ dsh plugin --profile web add dsh-dream-skin
143
148
  ```
144
149
 
145
- > `-w` 标志**必需**:每个 profile 自带 `pnpm-workspace.yaml`,pnpm 会把它当作 workspace 根,裸 `add` 会报
146
- > `ERR_PNPM_ADDING_TO_ROOT`。
147
-
148
150
  然后**重启** web 服务:
149
151
 
150
152
  ```sh
@@ -154,10 +156,13 @@ dsh web
154
156
 
155
157
  打开 **设置 → 常规**,即可看到「皮肤」「强调色」「背景图片 / 高级壁纸」与「主题包」等行。
156
158
 
157
- ### 方式二:npm 安装(发布后)
159
+ > `-w` 标志在裸 `add` 时必需:每个 profile 自带 `pnpm-workspace.yaml`,pnpm 会把它当作 workspace 根,裸加报错
160
+ > `ERR_PNPM_ADDING_TO_ROOT`。若已加过 `-w`,后续用现有 workspace 即无需重复。
161
+
162
+ ### 方式二:从源码 / 本地目录(开发者)
158
163
 
159
164
  ```sh
160
- dsh plugin --profile web add -w dsh-dream-skin
165
+ dsh plugin --profile web add -w /path/to/dsh-dream-skin
161
166
  ```
162
167
 
163
168
  ## 🧩 兼容性
package/lib/client.js CHANGED
@@ -328,7 +328,7 @@ window.__ModuleLoader__.load({
328
328
 
329
329
  /** Simplified Chinese dictionary (the key-set source of truth). */
330
330
  const zh = {
331
- "skin.title": "皮肤(Mirage 幻梦)",
331
+ "skin.title": "皮肤",
332
332
  "skin.default": "默认",
333
333
  "skin.abyss": "深海渊",
334
334
  "skin.aurora": "极光",
@@ -365,7 +365,7 @@ window.__ModuleLoader__.load({
365
365
 
366
366
  /** English dictionary, checked complete against the zh key set. */
367
367
  const en = {
368
- "skin.title": "Skins (Mirage)",
368
+ "skin.title": "Skins",
369
369
  "skin.default": "Default",
370
370
  "skin.abyss": "Abyss",
371
371
  "skin.aurora": "Aurora",
@@ -1098,6 +1098,7 @@ window.__ModuleLoader__.load({
1098
1098
  "aria-pressed": gradient === g,
1099
1099
  style: {
1100
1100
  ...styles.presetswatches,
1101
+ background: g,
1101
1102
  ...(gradient === g ? { outline: "2px solid var(--dsw-alias-brand-primary)" } : {})
1102
1103
  },
1103
1104
  onClick: () => setGradient(g),
@@ -1629,26 +1630,39 @@ window.__ModuleLoader__.load({
1629
1630
  return data ? `url("${data}")` : null;
1630
1631
  }
1631
1632
 
1633
+ /** Guards against re-entrant wallp-paper re-shading (overrideTokens emits theme/change). */
1634
+ let _applyingWallpaper = false;
1635
+
1632
1636
  /** Re-render the wallpaper backdrop from the current config. */
1633
1637
  function applyWallpaper2(ctx) {
1634
- const bg = wallpaperBackgroundCss();
1635
- const urlIsSet = bg !== null;
1636
- if (!urlIsSet) {
1637
- teardownWallpaper();
1638
- return;
1639
- }
1640
- if (wallpaperEl === null || !document.body.contains(wallpaperEl)) {
1641
- wallpaperEl = document.createElement("div");
1642
- wallpaperEl.style.cssText = "position:fixed;inset:0;z-index:-1;pointer-events:none;background-size:cover;background-position:center;background-repeat:no-repeat;";
1643
- document.body.prepend(wallpaperEl);
1638
+ // Re-entrancy guard: overrideTokens() below emits `theme/change`, which our
1639
+ // syncSkin listener would answer by calling applyWallpaper2 again — that
1640
+ // recursion would overflow the stack. Applying while already applying is a
1641
+ // no-op; the first (outermost) call performs the shading.
1642
+ if (_applyingWallpaper) return;
1643
+ _applyingWallpaper = true;
1644
+ try {
1645
+ const bg = wallpaperBackgroundCss();
1646
+ const urlIsSet = bg !== null;
1647
+ if (!urlIsSet) {
1648
+ teardownWallpaper();
1649
+ return;
1650
+ }
1651
+ if (wallpaperEl === null || !document.body.contains(wallpaperEl)) {
1652
+ wallpaperEl = document.createElement("div");
1653
+ wallpaperEl.style.cssText = "position:fixed;inset:0;z-index:-1;pointer-events:none;background-size:cover;background-position:center;background-repeat:no-repeat;";
1654
+ document.body.prepend(wallpaperEl);
1655
+ }
1656
+ const blur = readWallpaperBlur();
1657
+ wallpaperEl.style.backgroundImage = bg;
1658
+ wallpaperEl.style.filter = blur > 0 ? `blur(${blur}px)` : "none";
1659
+ // Auto-dim lowers the wash opacity when enabled.
1660
+ const baseFill = readWallpaperOpacity();
1661
+ const wash = readWallpaperAutodim() ? Math.min(baseFill, 0.45) : baseFill;
1662
+ shadeTokens2(ctx, wash, wash);
1663
+ } finally {
1664
+ _applyingWallpaper = false;
1644
1665
  }
1645
- const blur = readWallpaperBlur();
1646
- wallpaperEl.style.backgroundImage = bg;
1647
- wallpaperEl.style.filter = blur > 0 ? `blur(${blur}px)` : "none";
1648
- // Auto-dim lowers the wash opacity when enabled.
1649
- const baseFill = readWallpaperOpacity();
1650
- const wash = readWallpaperAutodim() ? Math.min(baseFill, 0.45) : baseFill;
1651
- shadeTokens2(ctx, wash, wash);
1652
1666
  }
1653
1667
 
1654
1668
  /** Like the original shadeTokens but with configurable alphas for the wash. */
@@ -1730,6 +1744,7 @@ window.__ModuleLoader__.load({
1730
1744
  const accent = useStore((s) => s.accent);
1731
1745
  const base = useStore((s) => s.base);
1732
1746
  const activeValue = accent !== DEFAULT_ACCENT ? accent : base;
1747
+ const inputValue = normalizeHex(activeValue) || "#4f83f2";
1733
1748
  return (0, react_jsx_runtime.jsxs)("div", {
1734
1749
  style: styles.group,
1735
1750
  children: [
@@ -1742,7 +1757,7 @@ window.__ModuleLoader__.load({
1742
1757
  children: [
1743
1758
  (0, react_jsx_runtime.jsx)("input", {
1744
1759
  type: "color",
1745
- value: (0, _react.useMemo)(() => normalizeHex(activeValue) || "#4f83f2", [activeValue]),
1760
+ value: inputValue,
1746
1761
  style: { ...styles.swatch, width: "40px", height: "32px", padding: 0, border: "none", borderRadius: "8px", cursor: "pointer" },
1747
1762
  onChange: (event) => setAccent(event.target.value)
1748
1763
  }),
@@ -1951,7 +1966,9 @@ window.__ModuleLoader__.load({
1951
1966
  let wallpaperBound;
1952
1967
  const syncWallpaper = () => {
1953
1968
  wallpaperRevision += 1;
1954
- wallpaperBound?.sync(wallpaperBackgroundCss(), readWallpaperOpacity(), readWallpaperBlur(), wallpaperRevision);
1969
+ // Store the raw data URL (not the CSS url(...) wrapper) so the
1970
+ // Wallpaper row can render an <img> preview and test `url !== null`.
1971
+ wallpaperBound?.sync(readWallpaper(), readWallpaperOpacity(), readWallpaperBlur(), wallpaperRevision);
1955
1972
  };
1956
1973
  applyWallpaper2(ctx);
1957
1974
  syncWallpaper();
@@ -2094,6 +2111,7 @@ window.__ModuleLoader__.load({
2094
2111
  // P0: per-user accent override row.
2095
2112
  const accentStore = createAccentStore();
2096
2113
  let accentBound;
2114
+ let accentRevision = 0;
2097
2115
  const accentInjected = (actions) => {
2098
2116
  accentBound = actions;
2099
2117
  const base = resolveAccent(ctx.theme.getTheme()) || DEFAULT_ACCENT;
@@ -2101,12 +2119,19 @@ window.__ModuleLoader__.load({
2101
2119
  return {
2102
2120
  setAccent: (value) => {
2103
2121
  const applied = setAccent(ctx, value === DEFAULT_ACCENT ? null : value);
2104
- accentBound?.sync(applied || DEFAULT_ACCENT, resolveAccent(ctx.theme.getTheme()) || DEFAULT_ACCENT, 0);
2122
+ accentBound?.sync(
2123
+ applied || DEFAULT_ACCENT,
2124
+ resolveAccent(ctx.theme.getTheme()) || DEFAULT_ACCENT,
2125
+ ++accentRevision
2126
+ );
2105
2127
  },
2106
2128
  clearAccent: () => {
2107
2129
  setAccent(ctx, null);
2108
- accentBound?.sync(DEFAULT_ACCENT, resolveAccent(ctx.theme.getTheme()) || DEFAULT_ACCENT, 0);
2109
- syncSkin(ctx.theme.getTheme());
2130
+ accentBound?.sync(
2131
+ DEFAULT_ACCENT,
2132
+ resolveAccent(ctx.theme.getTheme()) || DEFAULT_ACCENT,
2133
+ ++accentRevision
2134
+ );
2110
2135
  }
2111
2136
  };
2112
2137
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-dream-skin",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "DeepSeek Harness 换肤插件 (Dream Skin for DeepSeek Harness): curated --dsw-alias-* theme presets, a custom translucent wallpaper with opacity/blur controls, theme-pack import/export + share links, per-user accent, favorites & surprise-me, and durable per-browser persistence — in the spirit of the Codex Dream Skin project.",
5
5
  "license": "MIT",
6
6
  "type": "module",