DSH 的主题插件不改一行宿主代码,凭的是三层令牌机制
在 DSH 生态里给界面换肤,直觉做法是「想办法改样式」。RevolutionLA/dsh-dream-skin(幻梦换肤主题包,185 Star、周下载 9,994)走的是另一条路:一行注入都没有,既不改二进制,也不往渲染进程里塞 CSS——因为 DSH 本身就把「第三方插件注册主题」做成了官方能力。
宿主的主题是一层令牌,不是一张样式表
DSH 的 web 外壳内置了一套 --dsw- 设计令牌;ThemeRuntime 允许第三方插件注册主题去覆盖其中的别名层,即 --dsw-alias- 那一层。皮肤切换就是换一组变量取值:每套皮肤携带 colorScheme(light / dark)驱动 body[data-ds-dark-theme],别名 token 覆盖由 ui-layout 的 ThemePresenter 以内联自定义属性应用。
这件事一旦成立,「换肤」就从「跟宿主的样式表打架」变成「在宿主允许的位置写一组变量」。Codex-Dream-Skin 要在桌面客户端的渲染进程里用 CDP 注入 CSS,是因为它要改的东西没有官方入口;DSH 有入口,所以本插件走纯原生接入。
双面插件:host 半边几乎什么都不做
它是标准的双面插件(dsh-plugin)。dsh.bundle 一侧通过 cordis.patch.yml 插入 dream-skin loader 入口,对应 host 半边的 lib/index.js,apply 是空操作,与官方 ui- 包同构;dsh.client 一侧指向 lib/client.js,即浏览器半边,直接以 __ModuleLoader__ 格式编写,免构建。
真正干活的是浏览器半边:用 ctx.theme.register(...) 注册 8 套皮肤;恢复上次保存的皮肤并 ctx.theme.setTheme(...) 应用;把壁纸渲染成 z-index:-1 的固定背景层,再用 ctx.theme.overrideTokens(...) 让主画布 --dsw-alias-bg-base 与侧边栏 --dsw-specific-sidebar-fill 半透明;监听 theme/change,切皮肤或切深浅色时重新着色。界面则通过 ctx.slots 挂进 settings.section 独立分节。
运行时能力探测:找不到依赖时安静降级
它没有声明 engines.dsh:semver 只在与自身 major.minor.patch 三元组相同的轨道上放行预发布版本,单一范围无法同时覆盖 0.1.1-rc.x 与 0.1.2-rc.x,反而会把明确支持的版本判成「不兼容」;宿主目前也不读取这个字段。于是兼容性从「声明式」改成了「运行时探测」。
v9.10.0 起,客户端 bundle 把全部平台 seed 放在受控 try 内按候选顺序探测:先是 react / react/jsx-runtime,然后是设置 store 的 master 名 @deepseek-ai/dsh-client-store,再退到稳定版名 @deepseek-ai/dsh-client-runtime/client;判定依据是「require 成功返回」,而不是匹配宿主的内部错误文案。这样同一份构建能同时覆盖两代宿主:稳定版 0.1.0-rc.6 / 0.1.1-rc.x(peer 以 ^0.1.0-rc.6 对齐)与 DSH master(dsh-client-runtime 拆分后的新模块表)。
如果某天宿主把全部 seed 都换了代,插件会降级成一个不注册任何 UI 的哑模块,并打一条 console.warn,而不是抛错。这直接对应 issue #43:宿主对 loader-entry 工厂不做隔离,一个工厂抛错就能让整个 DSH Web 全屏 Failed to load plugins。
坑一:宿主换代后外观悄悄回到内置样式,却没有任何报错
现象。 宿主大版本升级之后,界面自己变回了内置外观,插件像是没装过。
原因。 运行时能力探测一个候选 seed 都没命中,插件按设计降级成哑模块——它会打印一条 console.warn,但不抛错,所以浏览器里看不出「坏了」。
怎么处理。 先确认宿主是不是改了模块表名称,再等插件跟进;这是设计行为而非故障,报障前先看控制台那条 warn。
坑二:DSH Desktop 上侧边栏透明度滑杆没反应
现象。 原生 Web 里侧边栏透明度滑杆正常,换成 DSH Desktop 桌面壳就推不动;右侧文件面板不受影响,于是左右不一致。
原因。 桌面壳在自己的子树上就近声明了 --dsw-specific-sidebar-fill,就近声明遮蔽了主题的覆盖值(issue #55)。
怎么处理。 升级到 v9.16.0 及以后:该版本让这片子树重新继承(inherit !important,原生 Web 里不匹配任何元素)。
坑三:安全扫描标「中风险」,是不是在乱写盘
现象。 源码静态扫描命中 8 处证据:写本地文件 4 处、读本地文件 1 处、写剪贴板 1 处、网络请求 2 处,结论是 🟡 中风险。
原因。 逐条看是两类正常实现——lib/index.js 里的 statePath 读取与 writeFileSync(..., { mode: 0o600 }) 是状态持久化,lib/client.js 里的 fetch(HOST_API) 是壁纸拉取、navigator.clipboard.writeText(url) 是「复制分享链接」。
怎么处理。 按预期行为理解即可,但要点在于详情页明确标注尚无人工评估——静态扫描只反映源码中出现的调用,不构成安全背书。装任何插件前先备份 ~/.dsh。
总结
这套插件的技术含量不在皮肤数量,而在于它把换肤建立在宿主已开放的 token 与扩展点之上——不注入、不改二进制,用运行时能力探测替代声明式版本约束;想对照同类插件的中文清单与安装形态见 DeepSeek Harness Hub 插件清单。
适合与不适合
适合:正在用 DSH 做开发、希望界面能按个人偏好定制的人;需要浅色/深色各一套、又不想自己写 CSS 的人;想把配色打包成 .dsh-theme.json 分享给同事的人。
不适合:期待跨设备、跨浏览器自动同步外观的人——皮肤与壁纸只存 localStorage,换个浏览器就是重来;想靠插件解决功能问题的人——它只是外观插件;对安全评估要求严格的人——静态扫描结论是中风险且尚无人工评估,Roadmap 里的首帧无闪烁与宿主哈希类名全量去依赖也仍未完成。
标签:dsh-dream-skin、DeepSeek Harness、双面插件、token 主题系统、运行时能力探测
本文由 DeepSeek Harness Hub 自动整理,数据来源于插件详情页。