@linxin666/dsh-client-ui-skin-center 0.1.19 → 0.2.0

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.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # node scripts/verify-docs.mjs --write <dir>
5
- README.md: 0f2055eff6d26f61407584e4e18f70e716a815c2
6
- README.zh.md: 4747255cf51b02f43009eb8723d230f8e75c4990
5
+ README.md: e4117e5e0bc059733867e05273b7fa1c1c0011aa
6
+ README.zh.md: 14c36654ae4d264b8277bd205b8255677183a84c
package/README.md CHANGED
@@ -4,13 +4,15 @@ English | [中文](README.zh.md)
4
4
 
5
5
  `@linxin666/dsh-client-ui-skin-center` (cordis plugin id `ui-skin-center`) puts the skin list / try-on / apply into the real dsh Web GUI as a first-level settings section (settings → 皮肤中心 / Skin Center), a sibling nav item of General / Models / Plugins / Agent presets and of the Web UI Plugins group and Pet sections. The card carries its own enable switch (off disables try-on, apply and the background controls).
6
6
 
7
- - List: shows "官方默认" (official default) plus every skin in the repo (qq98 / ths / xp / blue-fantasy / dragon-heir / minecraft) with its name, tagline, and accent color; the currently active target carries the Active marker.
7
+ - List: shows "官方默认" (official default) plus every skin in the repo (xp / blue-fantasy / dragon-heir / minecraft / miku / matrix / harbor / trading / whale-mom / whale-song) with its name, tagline, and accent color; the currently active target carries the Active marker.
8
8
  - Try-on: clicking "Try on" loads that skin's client bundle on demand — the host route `/api/skin-center/bundle/<id>` serves `lib/client.js` as a same-origin script (the same mechanism the core uses to load plugins), the factory registers with the page's own `window.__ModuleLoader__`, and `window.__DSH_MODULES__.import` materializes it (a real loader, not a simulator and no eval); the chrome takes effect immediately; light/dark switching rides the official theme service; "Exit try-on" restores everything — the current skin's styles, DOM, favicon, title, and body inline styles are all restored. "官方默认" (official default) can also be tried on: one click immediately withdraws the skin and returns to the official look preview.
9
9
  - Mutual exclusion: during try-on, the active skin's visual writes (body attribute, background inline styles, chrome child nodes, xp's footer taskbar) are temporarily withdrawn per the prescription, and restored verbatim on exit; only one skin is on the page at a time.
10
- - Apply: the host half (`src/index.ts` + `src/routes.ts`) exposes `/api/skin-center/apply` and `/api/skin-center/bundle/<id>` (serves skin bundles on demand); clicking "Apply / 恢复默认" (Apply / Restore default) runs the embedded in-process `dsh-skin use` port (`src/skin-switch.ts`) server-side, writes `<harness-home>/cordis.patch.yml`, and the DSH config watcher hot-loads it within seconds and the page auto-refreshes — **no dsh web restart, no copying a command, no `dsh-skin` binary on PATH**. On failure the error message includes a terminal fallback command. Harness home follows the dsh launcher: an injected HOME maps to `<home>/.dsh`, else a trimmed non-empty `$DSH_HOME` is used directly, else `~/.dsh`. The target profile resolves as: explicit option, then `$DSH_SKIN_PROFILE`, then `$DSH_PROFILE`, then `process.cwd()` when it is a directory directly under `<harness-home>/profiles/<name>`, then `web`. Windows compatibility: the same resolution rules apply with no `$HOME` or fixed paths, and profile links fall back to directory junctions when symlink privileges are missing.
10
+ - Apply: the host half (`src/index.ts` + `src/routes.ts`) exposes `/api/skin-center/apply` and `/api/skin-center/bundle/<id>` (serves skin bundles on demand); clicking "Apply / 恢复默认" (Apply / Restore default) runs the embedded in-process `dsh-skin use` port (`src/skin-switch.ts`) server-side, writes `<harness-home>/profiles/<profile>/cordis.patch.yml`, and the DSH config watcher hot-loads it within seconds and the page auto-refreshes — **no dsh web restart, no copying a command, no `dsh-skin` binary on PATH**. On failure the error message includes a terminal fallback command. Harness home follows the dsh launcher: an injected HOME maps to `<home>/.dsh`, else a trimmed non-empty `$DSH_HOME` is used directly, else `~/.dsh`. The target profile resolves as: explicit option, then `$DSH_SKIN_PROFILE`, then `$DSH_PROFILE`, then `process.cwd()` when it is a directory directly under `<harness-home>/profiles/<name>`, then `web`. Windows compatibility: the same resolution rules apply with no `$HOME` or fixed paths, and profile links fall back to directory junctions when symlink privileges are missing.
11
11
 
12
12
  - Background controls: a background-occlusion slider (0–100%) veils the backdrop behind the panels for skins that paint one (blue-fantasy / whale-song), plus two per-state Gaussian-blur sliders (0–20 px) — 空对话 (blur when the conversation is empty) and 有对话 (blur once it has content). The active blur is applied through a fixed `backdrop-filter` element behind the shell; 0 disables it entirely (no element, no GPU cost). These apply only to skins that paint a backdrop; the official default has none.
13
13
 
14
+ - Wallpaper Engine bridge: the card can use the machine's local Wallpaper Engine library as the GUI backdrop. The host half (`src/we-library.ts` + `src/we-routes.ts`) locates the WE install (Steam app 431960: registry + `libraryfolders.vdf` + probe paths on Windows), scans its projects and workshop content plus optional manual folders, and serves the inventory, media (Range-streamed), previews, web-wallpaper project files (with the WE API shim injected), and scene main-texture PNGs (decoded in-process from PKG/TEX by `src/pkg-extract.ts`, cached on disk) through same-origin `/api/skin-center/we/*` routes. Video wallpapers render in a `<video>`, web wallpapers in a sandboxed `<iframe>`, scene wallpapers as a static frame; a "static frame" render mode pins a zero-animation-cost image for any type. Per-wallpaper Import copies the project into `<harness-home>/skin-center/wallpapers/` so it survives Steam library changes, with update detection against the workshop original. Wallpapers are the user's own local files and are never uploaded or redistributed — Workshop content belongs to its authors. No Wallpaper Engine install (e.g. macOS)? The panel's Manual folders row adds any folder of `.mp4`/`.webm` files, a single wallpaper project folder, or a folder of projects as the library ('~' expands to the home directory).
15
+
14
16
  ## Install (official plugin bundle)
15
17
 
16
18
  Install the family skin aggregate package `@linxin666/dsh-skins` first (all skins plus the skin center in one); for this package alone use the `link:` commands below.
@@ -31,7 +33,7 @@ A local `link:` install needs built artifacts first — `lib/` is git-ignored an
31
33
 
32
34
  pnpm ≥10 requires authorizing `allowBuilds` before installing a git dependency (the `prepare` script builds in place); a local `link:` install has no such requirement.
33
35
 
34
- The skin plugins (qq98 / ths / xp / blue-fantasy) must resolve in the host for skin-center to list / try on the full set; skin-center itself has no mutual-exclusion requirement.
36
+ The skin plugins (xp / blue-fantasy / miku etc.) must resolve in the host for skin-center to list / try on the full set; skin-center itself has no mutual-exclusion requirement.
35
37
 
36
38
  ## Directory structure
37
39
 
@@ -46,6 +48,12 @@ skins/skin-center/
46
48
  src/client/try-on.ts # try-on engine (real loader + mutual-exclusion restore, incl. official try-on)
47
49
  src/client/locales.ts # en/zh copy
48
50
  src/client/skin-center.module.css # panel styles (--dsw-* tokens, adapting to the skin)
51
+ src/we-library.ts # WE library discovery (Steam/workshop/manual folders/import store)
52
+ src/we-routes.ts # /api/skin-center/we/* routes (inventory/media/web/scene-frame/import)
53
+ src/we-shim-source.ts # WE Web API shim served to web wallpapers
54
+ src/pkg-extract.ts # in-process PKG/TEX decoder for scene static frames
55
+ src/client/wallpaper.ts # wallpaper layer controller (media/scrim layers, static frame, pause-on-hidden)
56
+ src/client/WallpaperPanel.tsx # wallpaper grid + render controls in the card
49
57
  src/client/generated/skins.ts # generated: skin registry (metadata only, do not hand-edit)
50
58
  ```
51
59
 
@@ -56,7 +64,7 @@ skins/skin-center/
56
64
  - Failure semantics: when the bundle route 404s (skin not installed / `lib/client.js` not built) or the network fails, the script's error event fires, try-on reports a generic error and fully restores the active skin; no half skin is left between loading and restoring (the tryOn catch branch handles recovery).
57
65
  - Exit restore: first run the skin's disposer (withdraws attribute/chrome/favicon/title/background entirely), then `invalidate(package)` + remove the style tag, then restore the active skin's visual snapshot verbatim. Official-default try-on = the same withdrawal prescription but without mounting any skin; exit restores identically.
58
66
  - Active-skin detection: `window.__DSH_BOOT__.entries` only contains enabled entries, compared against the registry packages; no match means official default.
59
- - One-click apply: host `/api/skin-center/apply` runs the embedded port of `dsh-skin use <name>` / `use official` (the port is the sole authority for the managed section and the symlink). Paths are `<harness-home>/cordis.patch.yml` and `<harness-home>/profiles/<profile>/node_modules` with the home/profile resolution described above. When the active skin is itself installed as a bundle — listed in the profile manifest's `dsh.profile.bundles` or `dependencies` (the two channels the loader reconciles), or a registry `bundleWired` skin — the home layer writes only the mutual-exclusion `disabled: true` rows and leaves the insert to the bundle patch; anything else, including the skin-center's own resolvability symlinks, keeps the home insert row. The structural dir-probe fallback applies only when the profile manifest is missing/unreadable. The DSH daemon surface ships its own config watcher (`watchUserPatches` + config-only HMR); after the patch is written it hot-loads in seconds without a restart; a browser refresh picks up the new boot graph (client plugin-graph row changes are not within `dsh-client-hmr` semantics).
67
+ - One-click apply: host `/api/skin-center/apply` runs the embedded port of `dsh-skin use <name>` / `use official` (the port is the sole authority for the managed section and the symlink). Paths are `<harness-home>/profiles/<profile>/cordis.patch.yml` and `<harness-home>/profiles/<profile>/node_modules` with the home/profile resolution described above; legacy global managed rows are removed on the first switch so other profiles never load Web-only skins. When the active skin is itself installed as a bundle — listed in the profile manifest's `dsh.profile.bundles` or `dependencies` (the two channels the loader reconciles), or a registry `bundleWired` skin — the profile layer writes only the mutual-exclusion `disabled: true` rows and leaves the insert to the bundle patch; anything else, including the skin-center's own resolvability symlinks, keeps the profile insert row. The structural dir-probe fallback applies only when the profile manifest is missing/unreadable. Before appending the managed rows, the writer removes the DSH default `[]` root while preserving comments; an incompatible non-empty flow root fails before the atomic replacement. The DSH daemon surface ships its own config watcher (`watchUserPatches` + config-only HMR); after the patch is written it hot-loads in seconds without a restart; a browser refresh picks up the new boot graph (client plugin-graph row changes are not within `dsh-client-hmr` semantics).
60
68
 
61
69
  ## Build (in-repo tsdown, no DSH checkout)
62
70
 
@@ -75,11 +83,11 @@ pnpm --filter @linxin666/dsh-client-ui-skin-center run bundle
75
83
  ## Install (personal environment wiring, not committed to the checkout)
76
84
 
77
85
  ```sh
78
- # 1. profile symlink (same as qq98/blue-fantasy)
86
+ # 1. profile symlink (same as xp/blue-fantasy)
79
87
  ln -sfn ~/code/dsh-web-ui/packages/skins/skin-center \
80
88
  ~/.dsh/profiles/node_modules/@linxin666/dsh-client-ui-skin-center
81
89
 
82
- # 2. add to ~/.dsh/cordis.patch.yml (outside the dsh-skin managed section, do not touch that section):
90
+ # 2. add to ~/.dsh/profiles/web/cordis.patch.yml (outside the dsh-skin managed section, do not touch that section):
83
91
  # - insert:
84
92
  # - id: ui-skin-center
85
93
  # name: '@linxin666/dsh-client-ui-skin-center'
@@ -102,7 +110,7 @@ Exit try-on = try-on skin disposer (real code path) → module invalidate + styl
102
110
  - [x] The list contains the official default plus all skins; the currently active one is marked
103
111
  - [x] Try-on really takes effect (chrome/background/title/favicon); light/dark correct; the official default can be tried on
104
112
  - [x] Exit fully restores; mutual exclusion (no two title bars)
105
- - [x] One-click apply: the host API runs `dsh-skin use`, the watcher hot-loads, the page auto-refreshes (no restart); failure carries a command fallback
113
+ - [x] One-click apply: the host API runs `dsh-skin use`, the watcher hot-loads, and the new skin is hot-mounted in place through the real module system (no reload, no restart — instant switch in packaged installs too; a page reload remains the fallback when the hot mount fails); failure carries a command fallback
106
114
  - [x] Regression: the dsh-skin CLI (incl. `use official`), the web gallery, and the official GUI are unaffected
107
115
  - [x] On-demand loading: cold start does not parse the ~700KB embedded base64 (`generated/skins.ts` is only ~5KB of metadata); try-on fetches the bundle on demand; no eval (CSP needs no `unsafe-eval`)
108
116
  - [x] e2e screenshots live in `docs/e2e/skin-center/`
package/README.zh.md CHANGED
@@ -4,13 +4,15 @@
4
4
 
5
5
  `@linxin666/dsh-client-ui-skin-center`(cordis 插件 id `ui-skin-center`)把皮肤列表/试穿/应用放进真实 dsh Web GUI 的设置页,作为一级菜单项(设置 → 皮肤中心),与通用设置 / 模式 / 插件 / Agent 预设以及 Web UI 插件组、宠物同级。卡片自带启用开关(关闭后停用试穿、应用与背景控件)。
6
6
 
7
- - 列表:展示「官方默认」+ 仓库里全部皮肤(qq98 / ths / xp / blue-fantasy / dragon-heir / minecraft)的名称、tagline、强调色;当前激活的目标带 Active 标记。
7
+ - 列表:展示「官方默认」+ 仓库里全部皮肤(xp / blue-fantasy / dragon-heir / minecraft / miku / matrix / harbor / trading / whale-mom / whale-song)的名称、tagline、强调色;当前激活的目标带 Active 标记。
8
8
  - 试穿:点击「Try on」后按需加载该皮肤的 client bundle——host 路由 `/api/skin-center/bundle/<id>` 以同源 script 提供 `lib/client.js`(内核加载插件的同一机制),factory 注册到页面自己的 `window.__ModuleLoader__`,`window.__DSH_MODULES__.import` 物化(不是模拟器、不用 eval),chrome 立即生效;亮/暗切换走官方 theme 服务;「Exit try-on」完全还原——当前皮肤的样式、DOM、favicon、标题、body 内联样式全部恢复。「官方默认」也可试穿:点一下皮肤立即收回、回到官方外观预览。
9
9
  - 互斥:试穿期间会按配方暂时收回当前激活皮肤的视觉写面(body 属性、背景内联样式、chrome 子节点、xp 的 footer taskbar),退出后原样恢复;同一时刻页面上只有一套皮肤。
10
- - 应用:host 半区(`src/index.ts` + `src/routes.ts`)暴露 `/api/skin-center/apply` 与 `/api/skin-center/bundle/<id>`(按需提供皮肤 bundle),点击「Apply / 恢复默认」即在服务端执行内嵌的 `dsh-skin use` 进程内移植版(`src/skin-switch.ts`),写入 `<harness-home>/cordis.patch.yml` 后由 DSH 配置 watcher 秒级热载入,页面自动刷新生效——**无需重启 dsh web,无需复制命令,也不要求 PATH 上有 `dsh-skin` 二进制**。应用失败时错误提示里附带终端兜底命令。harness home 与 dsh 启动器一致:注入的 HOME 映射为 `<home>/.dsh`,否则优先使用去除首尾空白后非空的 `$DSH_HOME`(直接使用,不再追加后缀),最后回退到 `~/.dsh`。目标 profile 依次取:显式选项、`$DSH_SKIN_PROFILE`、`$DSH_PROFILE`、`process.cwd()` 直接位于 `<harness-home>/profiles/<name>` 下时的 `<name>`,最后 `web`。Windows 兼容性:同一套解析规则不依赖 `$HOME` 与固定路径,符号链接权限不足时 profile 链接回退为目录 junction。
10
+ - 应用:host 半区(`src/index.ts` + `src/routes.ts`)暴露 `/api/skin-center/apply` 与 `/api/skin-center/bundle/<id>`(按需提供皮肤 bundle),点击「Apply / 恢复默认」即在服务端执行内嵌的 `dsh-skin use` 进程内移植版(`src/skin-switch.ts`),写入 `<harness-home>/profiles/<profile>/cordis.patch.yml` 后由 DSH 配置 watcher 秒级热载入,页面自动刷新生效——**无需重启 dsh web,无需复制命令,也不要求 PATH 上有 `dsh-skin` 二进制**。应用失败时错误提示里附带终端兜底命令。harness home 与 dsh 启动器一致:注入的 HOME 映射为 `<home>/.dsh`,否则优先使用去除首尾空白后非空的 `$DSH_HOME`(直接使用,不再追加后缀),最后回退到 `~/.dsh`。目标 profile 依次取:显式选项、`$DSH_SKIN_PROFILE`、`$DSH_PROFILE`、`process.cwd()` 直接位于 `<harness-home>/profiles/<name>` 下时的 `<name>`,最后 `web`。Windows 兼容性:同一套解析规则不依赖 `$HOME` 与固定路径,符号链接权限不足时 profile 链接回退为目录 junction。
11
11
 
12
12
  - 背景控制:背景遮挡滑块(0–100%)为带背景插画的皮肤(blue-fantasy / whale-song)背后的背景加遮罩;另有两条按对话状态区分的背景高斯模糊滑块(0–20 px)——「空对话」在对话为空时生效、「有对话」在出现内容后生效。生效的模糊通过 shell 背后的一个固定 `backdrop-filter` 元素施加;设为 0 即完全关闭(无元素、无 GPU 开销)。这些控件仅对带背景插画的皮肤可见有效;官方默认无背景图。
13
13
 
14
+ - Wallpaper Engine 桥接:卡片可以把本机 Wallpaper Engine 壁纸库用作 GUI 背景。host 半区(`src/we-library.ts` + `src/we-routes.ts`)定位 WE 安装(Steam 应用 431960:Windows 下走注册表 + `libraryfolders.vdf` + 探针路径),扫描其 projects 与创意工坊内容及可选的手动目录,经同源 `/api/skin-center/we/*` 路由提供清单、媒体流(支持 Range)、预览图、web 壁纸项目文件(注入 WE API shim)以及场景壁纸主纹理 PNG(由 `src/pkg-extract.ts` 进程内解码 PKG/TEX,落盘缓存)。视频壁纸用 `<video>` 渲染,网页壁纸用沙箱 `<iframe>`,场景壁纸以静态帧呈现;「静态帧」渲染模式可为任意类型钉一张零动画开销的图片。每张壁纸的「导入」把项目复制进 `<harness-home>/skin-center/wallpapers/`,Steam 库迁移后仍可使用,并对照工坊原件做更新检测。壁纸均为用户本机已有文件,绝不上传或再分发——创意工坊内容版权归其作者所有。没有 Wallpaper Engine(如 macOS)?面板的「手动目录」行可把任意 `.mp4`/`.webm` 文件夹、单个壁纸项目文件夹或项目合集文件夹加为壁纸库('~' 会展开为用户主目录)。
15
+
14
16
  ## 安装(官方 plugin bundle 方式)
15
17
 
16
18
  推荐先装皮肤全家桶聚合包 `@linxin666/dsh-skins` 一次到位(含全部皮肤与皮肤中心);只装本包时用下列 link 命令。
@@ -31,7 +33,7 @@ skin-center 是符合 DSH 官方插件标准的自包含 bundle(`dsh.bundle.pa
31
33
 
32
34
  pnpm ≥10 安装 git 依赖前需先授权 `allowBuilds`(`prepare` 会原地构建),本地 link 安装则无此要求。
33
35
 
34
- 需要皮肤插件们(qq98 / ths / xp / blue-fantasy)在宿主里也可解析时,skin-center 才能完整列出 / 试穿全部皮肤;skin-center 本身无互斥要求。
36
+ 需要皮肤插件们(xp / blue-fantasy / miku 等)在宿主里也可解析时,skin-center 才能完整列出 / 试穿全部皮肤;skin-center 本身无互斥要求。
35
37
 
36
38
  ## 目录结构
37
39
 
@@ -46,6 +48,12 @@ skins/skin-center/
46
48
  src/client/try-on.ts # 试穿引擎(真实 loader + 互斥还原,含官方试穿)
47
49
  src/client/locales.ts # en/zh 文案
48
50
  src/client/skin-center.module.css # 面板样式(--dsw-* token,随皮肤自适应)
51
+ src/we-library.ts # WE 库发现(Steam/工坊/手动目录/导入存储)
52
+ src/we-routes.ts # /api/skin-center/we/* 路由(清单/媒体/web/scene-frame/导入)
53
+ src/we-shim-source.ts # 供 web 壁纸的 WE API shim
54
+ src/pkg-extract.ts # 进程内 PKG/TEX 解码器(场景静态帧)
55
+ src/client/wallpaper.ts # 壁纸层控制器(media/scrim 层、静态帧、后台暂停)
56
+ src/client/WallpaperPanel.tsx # 卡片内的壁纸网格与渲染控件
49
57
  src/client/generated/skins.ts # 生成:皮肤注册表(仅元数据,勿手改)
50
58
  ```
51
59
 
@@ -56,7 +64,7 @@ skins/skin-center/
56
64
  - 失败语义:bundle 路由 404(皮肤未安装 / `lib/client.js` 未构建)或网络失败时,script 的 error 事件触发,试穿报通用错误并完整还原激活皮肤;加载与还原之间不会留下半套皮肤(tryOn 的 catch 分支负责恢复)。
57
65
  - 退出还原:先跑皮肤的 disposer(属性/chrome/favicon/标题/背景全撤回),再 `invalidate(package)` + 删 style 标签,最后把激活皮肤的视觉快照原样恢复。官方默认试穿 = 同一套收回配方但不挂载任何皮肤,退出同样原样恢复。
58
66
  - 激活皮肤检测:`window.__DSH_BOOT__.entries` 只含启用条目,与注册表 package 比对;无匹配即官方默认。
59
- - 一键应用:host `/api/skin-center/apply` 执行内嵌的 `dsh-skin use <name>` / `use official` 移植版(该移植版是 managed 区段与 symlink 的唯一权威)。路径为 `<harness-home>/cordis.patch.yml` 与 `<harness-home>/profiles/<profile>/node_modules`,home/profile 按上文规则解析。当激活皮肤自身已作为 bundle 安装——出现在 profile manifest 的 `dsh.profile.bundles` 或 `dependencies` 中(loader 仅对这两条通道做 patch 行归并),或注册表标记 `bundleWired`——home 层只写互斥的 `disabled: true` 行,insert 留给 bundle patch;其余情况(包括 skin-center 自建的可解析 symlink)都保留 home 层 insert 行。结构目录探测仅在 profile manifest 缺失/不可读时兜底。DSH 长驻表面自带配置 watcher(`watchUserPatches` + config-only HMR),patch 写入后数秒热载入、无需重启;浏览器刷新页面取新 boot 图即生效(client 插件图行增删不在 `dsh-client-hmr` 语义内)。
67
+ - 一键应用:host `/api/skin-center/apply` 执行内嵌的 `dsh-skin use <name>` / `use official` 移植版(该移植版是 managed 区段与 symlink 的唯一权威)。路径为 `<harness-home>/profiles/<profile>/cordis.patch.yml` 与 `<harness-home>/profiles/<profile>/node_modules`,home/profile 按上文规则解析;首次切换会清理旧的全局 managed 行,避免其他 profile 加载 Web 专用皮肤。当激活皮肤自身已作为 bundle 安装——出现在 profile manifest 的 `dsh.profile.bundles` 或 `dependencies` 中(loader 仅对这两条通道做 patch 行归并),或注册表标记 `bundleWired`——profile 层只写互斥的 `disabled: true` 行,insert 留给 bundle patch;其余情况(包括 skin-center 自建的可解析 symlink)都保留 profile 层 insert 行。结构目录探测仅在 profile manifest 缺失/不可读时兜底。追加 managed 行前会在保留注释的同时移除 DSH 默认 `[]` 根;不兼容的非空 flow 根会在原子替换前失败。DSH 长驻表面自带配置 watcher(`watchUserPatches` + config-only HMR),patch 写入后数秒热载入、无需重启;浏览器刷新页面取新 boot 图即生效(client 插件图行增删不在 `dsh-client-hmr` 语义内)。
60
68
 
61
69
  ## 构建(仓库内 tsdown,无需 DSH checkout)
62
70
 
@@ -75,11 +83,11 @@ pnpm --filter @linxin666/dsh-client-ui-skin-center run bundle
75
83
  ## 安装(个人环境接线,不在 checkout 提交)
76
84
 
77
85
  ```sh
78
- # 1. profile symlink(与 qq98/blue-fantasy 同款)
86
+ # 1. profile symlink(与 xp/blue-fantasy 同款)
79
87
  ln -sfn ~/code/dsh-web-ui/packages/skins/skin-center \
80
88
  ~/.dsh/profiles/node_modules/@linxin666/dsh-client-ui-skin-center
81
89
 
82
- # 2. ~/.dsh/cordis.patch.yml 增加(放在 dsh-skin managed 段之外,勿动该段):
90
+ # 2. ~/.dsh/profiles/web/cordis.patch.yml 增加(放在 dsh-skin managed 段之外,勿动该段):
83
91
  # - insert:
84
92
  # - id: ui-skin-center
85
93
  # name: '@linxin666/dsh-client-ui-skin-center'
@@ -102,7 +110,7 @@ ln -sfn ~/code/dsh-web-ui/packages/skins/skin-center \
102
110
  - [x] 列表含官方默认 + 全部皮肤,当前激活有标记
103
111
  - [x] 试穿真实生效(chrome/背景/标题/favicon),亮/暗正确;官方默认可试穿
104
112
  - [x] 退出完全还原;互斥(不出现两套标题栏)
105
- - [x] 一键应用:host API 执行 `dsh-skin use`,watcher 热载入,页面自动刷新生效(无重启);失败附命令兜底
113
+ - [x] 一键应用:host API 执行 `dsh-skin use`,watcher 热载入,新皮肤经真实模块系统原地热挂载生效(无刷新、无重启,打包版同样秒切;热挂载失败时回退到刷新页面路径),失败附命令兜底
106
114
  - [x] 回归:dsh-skin CLI(含 `use official`)、网页 Gallery、官方 GUI 不受影响
107
115
  - [x] 按需加载:冷启动不解析 ~700KB 内嵌 base64(`generated/skins.ts` 仅 5KB 元数据),试穿按需取 bundle;无 eval(CSP 无需 `unsafe-eval`)
108
116
  - [x] e2e 截图见 `docs/e2e/skin-center/`