前言¶
DSH(DeepSeek Harness)网页版有几处界面元素是写在宿主构建产物里的:侧边栏左上角的品牌 Logo、空对话时的欢迎区、对话区域的底色。想在内部部署里换成自己的标识或背景图,常规做法是改宿主构建,但宿主一更新就得重做一遍。
dsh-customui-plugin 换了个思路:不改宿主构建,通过插件机制往浏览器端注入脚本,在 DOM 层做覆盖,同时在设置页里给这些改动一个正式入口。下面介绍它的功能、原理和安装步骤。
这是什么¶
dsh-customui-plugin 是一个 DSH web 平台插件,仓库地址为 https://github.com/nexsjournal/dsh-customui-plugin,许可证为 MIT。它只做一件事:在 DSH 网页版的设置页里新增一个「个性化」导航项,通过这个页面自定义三处界面元素——侧边栏左上角 Logo、空对话欢迎区(Logo + 文案)、对话区域背景图。所有修改实时生效,不需要重启 DSH。
插件没有任何构建步骤:lib/index.js(宿主侧,注册设置 + 打白名单补丁)与 lib/client.js(浏览器侧,设置页 + 实时应用引擎)都是纯 JS,安装前可以直接读完源码。
核心功能¶
| 设置项 | 说明 |
|---|---|
| 左上角 Logo | 替换侧边栏左上角的品牌标识(侧边栏展开状态生效)。建议横版 SVG,显示高度 24px。 |
| 欢迎区 Logo | 替换空对话欢迎区的小鱼图标,显示高度 34px。 |
| 欢迎区文案 | 留空保持原版欢迎语;填写后仅显示该文案(Logo 可同显)。 |
| 对话背景图 | 铺在对话区域(消息 + 输入框)后方,支持「铺满 / 完整显示」与 0–100% 透明度。建议 1600×900(16:9 横版)。 |
每个图片项都支持两种来源:
- 上传本地图片。客户端自动压缩:位图缩放到不超过 1920px、转 JPEG/PNG;SVG 原样保留。
- 粘贴 https 图片链接。
其他能力:
- 修改实时生效:纯浏览器端 DOM 覆盖 + MutationObserver 监听,React 重渲染、切换会话、侧边栏折叠后自动补回,应用逻辑幂等。
- 配置写入 DSH 设置命名空间 customui,随 profile 持久化,落在
~/.dsh/settings.yaml的 customui 段。 - 支持一键「恢复默认」,清掉已存配置。
实时生效的原理¶
插件不改宿主构建,靠两层机制。
第一层是锚点选择。客户端脚本不绑定会随构建变化的哈希 class 名,而是用三个稳定的设计常量做锚点:
品牌字标 svg[viewBox="0 0 182 24"]
欢迎区小鱼 svg[viewBox="0 0 23.16 17.04"]
对话区域 [data-conversation-scroll]
第二层是持续监听。MutationObserver 盯着 DOM,React 重渲染、切换会话、侧边栏折叠之后都会把自定义内容补回来;应用逻辑幂等,不会无限循环。配置存在 customui 命名空间里,命名空间一变更立即重新应用——所以在设置页里改,界面马上变。
背景图的具体落点:铺在 [data-conversation-scroll] 容器上,经 ::before 伪元素、z-index:-1、真 CSS opacity 控制。透明度低于 100% 时对话区底色会透出,浅色、深色背景都能融合。
安装与启用¶
前提:需要已有一个 DSH web 部署(dsh web 或桌面版);插件 engines 要求 Node >= 20。
执行安装脚本:
# 方式一:本仓库目录(开发期 link: 软链安装,改动即时生效)
bash scripts/install.sh
# 方式二:npm / GitHub
bash scripts/install.sh dsh-customui-plugin@1.0.0
bash scripts/install.sh git+https://github.com/<owner>/dsh-customui-plugin.git
两点说明:
- npm 示例里的版本号沿用插件 README 的写法(@1.0.0),与仓库 package.json 中的 0.1.0 不一致,安装时以实际发布的版本为准。
- GitHub 方式里的
<owner>是 README 中的占位符,需替换为实际仓库所有者;本插件的仓库地址见上文。
如果不用脚本,等价的手工步骤是:
dsh plugin --profile web add -w /path/to/dsh-customui-plugin
-w 必需,因为 profile 是 pnpm workspace 根。
安装后需要重启 DSH 一次。原因:插件启动时会把 customui 命名空间幂等地加入 Web 设置页的 api-proxy 白名单(dsh-host-apiproxy 的 WEB_SETTINGS_NAMESPACES),所以「个性化」导航项与设置写入在下一次启动后才出现。之后所有配置修改都是热生效的,不再需要重启。
另外,桌面版更新(覆盖安装)会重置 api-proxy 白名单文件,重启后插件会再次自动打补丁,不需要手工处理。
典型用法¶
经过上面的步骤,重启 DSH 后打开设置页,侧边导航里会出现「个性化」一项(与通用设置、模型、插件、Agent 预设等并列)。接下来的流程:
- 进入「个性化」设置页。
- 逐项设置左上角 Logo、欢迎区 Logo 与文案、对话背景图;图片可上传本地文件,也可粘贴 https 链接。
- 每一项改动立即反映到界面上,不需要刷新或重启。
想回到原版界面时,点「恢复默认」即可清掉已存配置。
卸载插件:
dsh plugin --profile web rm dsh-customui-plugin
执行后重启 DSH,再点一次「恢复默认」,把已经写入 profile 的配置也清掉。
开发者视角¶
对想研究 DSH 插件写法的开发者,这个插件的打包方式值得看一下。package.json 里声明了两块:
dsh.bundle.patch指向./cordis.patch.yml,负责宿主 bundle 树插入;dsh.client.inject注入@deepseek-ai/dsh-client-runtime、@deepseek-ai/dsh-client-locale、dsh-client-ui-slots、dsh-client-ui-settings四个客户端包,platform 为 web。
peerDependencies 里的 @deepseek-ai/dsh-settings 与 @deepseek-ai/schemastery 均为可选。
改完源码可以做语法检查:
node --check lib/index.js && node --check lib/client.js
文件结构如下:
├── package.json # dsh.bundle.patch + dsh.client.inject 声明
├── cordis.patch.yml # 宿主 bundle 树插入
├── dsh.plugin.json # 插件清单
├── lib/
│ ├── index.js # 服务端:customui 设置命名空间 + api-proxy 白名单自补丁
│ └── client.js # 浏览器端:个性化设置页 + 实时 DOM 应用引擎
├── scripts/install.sh
├── LICENSE
└── README.md
适用场景与注意¶
适合的场景:
- 团队内部部署 DSH,想换成自己的品牌 Logo、欢迎语或统一背景图;
- 个人想给对话区配一张背景图、替换默认欢迎语;
- 插件开发者想参考「设置命名空间 + 客户端注入 + api-proxy 白名单自补丁」这套做法。
已知边界,使用前先确认:
- 侧边栏折叠(rail)状态下只显示图标、不渲染字标,此时左上角 Logo 不生效,展开后恢复;
- 欢迎区仅在空对话时显示,有消息后该区域消失(背景图不受影响);
- 若某个版本的 DSH 消息气泡自带不透明底色,背景图会被挡住,可降低透明度或换图;
- 图片以 data URL 存进
~/.dsh/settings.yaml的 customui 段,上传时虽已自动压缩,仍建议用几十 KB~几百 KB 的图。
安全方面需要说明:DSH 插件以当前 dsh 进程的权限运行,安装任何第三方插件前都应检查源码与许可证。就这个插件而言,无构建步骤、lib 下两个文件均为纯 JS、许可证为 MIT,审阅成本比较低。
结语¶
dsh-customui-plugin 用插件机制给 DSH 网页版补上了界面个性化的能力:改动实时生效、随 profile 持久化、不动宿主构建。对想给内部部署换品牌的团队,或者想学习 DSH 插件写法的开发者,都可以先把源码过一遍。
DSH 的理念是「一切皆插件」,这类个性化插件正是这套机制的正常用法。
- 插件目录页:https://www.skillhub.cn/plugins/nexsjournal/dsh-customui-plugin
- GitHub 仓库:https://github.com/nexsjournal/dsh-customui-plugin
skillhub.cn 是独立的社区插件目录,与 DeepSeek、幻方没有官方从属关系。