Bundle
dsh-veneer
Veneer — a lightweight visual editor to reskin the DeepSeek Harness UI: edit background surfaces (color/image/opacity) with theme persistence.
- Source
- swordordead
- stars
- 2 stars
- License
- MIT
- Updated
- Updated 4 days ago
Readme
# ✨ Veneer:给 DeepSeek Harness 换一套你喜欢的界面
Veneer 是 DeepSeek Harness(DSH)的**可视化换肤插件**。无需修改 CSS 或配置文件:在侧栏打开「编辑」,就能调整**背景、图片、字体、颜色和细节样式**;保存后,下次打开仍会保留。

## 🎨 用法一眼看懂
1. 在 DSH 左下角点击 **「编辑」**。
2. 选择**背景、字体、AI 主题或样式**,边改边预览。
3. 点击 **「保存主题」**,设置会自动保留。

## 🚀 安装
```bash
dsh plugin --profile web add github:swordordead/dsh-Veneer
```
安装完成后**重启一次 `dsh web`**,刷新网页,即可在侧栏底部找到 **「编辑」**。
也可以使用 npm 包安装(发布后):
```bash
dsh plugin --profile web add dsh-veneer
```
> 💡 **这是一个 DSH 社区插件。** 欢迎在 [GitHub Issues](https://github.com/swordordead/dsh-Veneer/issues) 提交问题与建议。
---
## 🪄 能做什么
| 能力 | 说明 |
|------|------|
| 🎨 背景换肤 | 12 个背景面:侧边栏背景 / 主背景(消息气泡、输入框、各浮层) / Veneer 面板自身 |
| 🖼 背景图 | 每个背景可上传或拖放图片(自动识别真实格式)、设「变淡」透明度;可在预览中拖拽裁切焦点、用横纵滑块精调,或一键居中;轻点预览可收缩/展开 |
| 💾 保存/复制/重置 | 持久化到 DSH Host Settings(浏览器 `localStorage` 兼容快照兜底,Harness 更新不丢);可复制 CSS;每张字体卡片可单独「重置」,底部「重置全部设置」恢复背景、字体和文字颜色 |
| 🔤 字体与文字颜色 | 分别调整全局、侧边栏、主内容、输入区和 Veneer 面板的字体与文字颜色;每个位置都支持「✎ 自定义字体名」直接输入本机字体 |
| 📦 导出/导入主题 | 一键导出全部设置(含背景图 URL)为 JSON,可复制或下载;导入可完整恢复(同机),跨机器时图片引用可能失效 |
| 🤖 AI 生成主题 | 「AI 主题」标签页选模型(与对话共用 Harness 模型目录与凭据,零配置)+ 一句话描述(或选风格),复用对话同一模型运行时生成整套背景+字体主题,预览确认后再应用/放弃 |
| ✨ 样式精调 | 「样式」标签页微调圆角 / 边框 / 阴影 / 强调色(真实存在的 CSS 变量才开放),改完自动保存,支持单组恢复默认 |
| 🗂 模板库 | 「样式」标签页顶部内置 8 套主题模板(莫兰迪/赛博/暖棕/极简/深空/森林/海洋/复古纸),点选即预览,应用一键切换整套主题 |
## 🧩 架构
- **host 半区**(`lib/index.js`):图片上传 API + 图片静态服务(嗅探真实图片格式,不信任扩展名) + AI 生成代理(`POST /api/dsh-veneer/ai/generate`,优先走 Harness 的 `ctx.llm` 统一运行时复用对话模型目录与凭据;仅当请求方显式携带 `apiKey` 时才直连 DeepSeek,且只允许 `api.deepseek.com` 上游) + 模型目录接口(`GET /api/dsh-veneer/ai/models`)
- **client 半区**(`lib/client.js`):侧栏按钮 + 浮动面板 + 背景/字体/样式编辑逻辑
- **主题存储**(`lib/theme-storage.js`):Host Settings 命名空间 `dsh-veneer`(唯一字段 `theme`)+ `localStorage` 兼容快照的双写协调、读取优先级与迁移决策(Host 合法 → Host 优先并刷新快照;Host 空 → boot 时迁移旧本地主题一次;Host 不可用/非法 → 本地兜底且不覆盖 Host)
- **设置契约**:host 端用 `@deepseek-ai/dsh-settings` 的 `settingsNamespace()` 注册 Schema;settings 服务未挂载时 client 退回 `localStorage`,但 Harness 仍须提供静态模块 `@deepseek-ai/dsh-settings` / `@deepseek-ai/schemastery`(zip 安装器会预检);client 端经动态可选 `settingsScope` 读写订阅,重置使用 `unset` 清空字段而非写 `null`
- 入口:`package.json` 的 `dsh.client` 声明 + `ctx.slots.inject("sidebar.footer.action", …)` 把按钮挂进侧栏底栏
## 📁 项目结构
```
dsh-veneer/
├── lib/
│ ├── index.js # host 半区:图片上传/静态服务 + AI 生成代理
│ ├── client.js # client 半区:侧栏按钮 + 换肤面板 + 默认皮肤预设
│ ├── theme-storage.js # 主题解析/规范化/读写协调/Host 迁移决策(纯逻辑,可单测)
│ ├── llm-errors.js # AI 错误码 → 友好中文文案映射
│ └── assets/ # 内置默认皮肤底图(随 npm 包分发,host 启动时复制到用户存储)
├── cordis.patch.yml # bundle 注册层(随包发布,`dsh plugin add` 自动应用)
├── package.json # 插件声明(dsh.client / dsh.bundle)+ npm 发布清单
├── install.bat # zip 离线安装入口(双击运行)
├── install.ps1 # zip 离线安装脚本(幂等 + SHA256 校验 + 与 dsh plugin 互斥)
├── sync.ps1 # 开发期同步到本地 DSH profile
├── tools/
│ ├── pack-release.ps1 # 打 zip 离线发布包
│ └── validate_templates.cjs # 模板 / AI 契约校验
├── test/ # Playwright(Python)回归脚本
└── docs/ # 架构 / 变更记录 / 计划
```
## 🌟 默认皮肤预设(装上即用)
首次安装打开 DSH 即为作者常用皮肤:白底 + 三张底图(侧栏 / 主背景 / 输入框)+ 深蓝文字,
无需任何配置。实现方式:
- 底图随 npm 包分发(`lib/assets/`),host 启动时把缺失的图复制到用户 DSH 存储目录
(`~/.dsh/storages/dsh-veneer/images/`),幂等且**绝不覆盖**用户自己上传的同名图片;
- client 端在浏览器 `localStorage` 无已保存主题时自动套用预设;用户一旦保存自己的主题,
即以用户数据为准,预设不再干扰;「重置全部设置」后回到预设。
- 底图来源为作者自用皮肤图片,随包分发仅供个人换肤使用(MIT)。
## 🤖 AI 生成主题(模型与凭据说明)
- 在面板「AI 主题」标签页选择模型(提供方 + 模型两级下拉),与对话共用 Harness 模型目录与凭据,**零 API Key 配置**,也不会把 Key 存到 `localStorage`。
- 生成请求走 Harness 的 `ctx.llm` 统一运行时(不带 `sessionId` 的一次性 completion),不进对话历史、不阻塞主对话。
- 模型服务不可用、凭据缺失/无效、限流(429)、无额度(402)或网络失败时,面板内显示友好中文错误,不影响已保存的主题。
- 生成结果先进入「预览」态,确认「应用」才会持久化;「放弃」恢复生成前状态。
## 🚀 安装部署
### 方式一:官方插件命令(推荐)
DSH 的插件机制支持「bundle」:只要包的 `package.json` 声明了
`"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }`,`dsh plugin add`
就会自动装包并注册,接收者**零手动配置**:
```bash
# 从 npm 安装
dsh plugin --profile web add dsh-veneer
# 或直接从 GitHub 仓库安装(会自动跑构建脚本,首次可能提示允许 build)
dsh plugin --profile web add github:swordordead/dsh-Veneer
# 或从本地目录/zip 解压目录安装
dsh plugin --profile web add /path/to/dsh-veneer
```
首次安装或含 Host 端改动的升级完成后重启一次 `dsh web`,再刷新浏览器;无需手动
改配置文件。仅前端 client 更新时强制刷新即可。卸载同样一条命令:
`dsh plugin --profile web remove dsh-veneer`。
> 前置条件:`dsh` CLI 与 `pnpm` 都在 PATH 中(`dsh plugin` 底层转发给 pnpm)。
### 方式二:zip + 双击安装(离线 / 无 node / pnpm 环境)
针对无法使用命令行或没有 Node 环境的接收者,提供了 zip 包 + 一键安装脚本:
1. 打包(发布前先按版本号策略递增 `package.json` 的 `version`):
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\pack-release.ps1
```
生成 `release\dsh-veneer-vX.Y.Z.zip`(只含运行期必需文件:`package.json`、
`cordis.patch.yml`、`lib/`、`install.bat`、`install.ps1`、`使用说明.txt`),
可上传 GitHub Releases 或直接发文件。
2. 接收者:解压 → 双击 `install.bat`。脚本自动完成复制 + 注册,幂等(重复执行不会
重复注册)、带 SHA256 校验,无需 node/pnpm。首次安装或版本包含 Host 端改动时,
需重启一次 `dsh web`;仅 `lib/client.js` 变化时强制刷新浏览器即可。
**与方式一互斥**:若接收者已用 `dsh plugin --profile web add dsh-veneer` 安装过,
`install.ps1` 会在复制前检测到并安全退出,不会覆盖 pnpm 管理的目录;此时应使用
`dsh plugin --profile web update dsh-veneer` 更新。
3. 接收者升级:重新下载新包再次双击并按上条规则重启/刷新即可。主题存于 Harness
Settings(`settings.yaml`),不随插件目录覆盖,已有设置会保留。
> 自定义 DSH 数据目录(设置了 `DSH_HOME`)的接收者:先 `set DSH_HOME=...` 再运行,或
> `powershell -NoProfile -ExecutionPolicy Bypass -File .\install.ps1 -DshHome "目录"`。
### 手动方式(了解原理)
```powershell
$dst = "$env:USERPROFILE\.dsh\profiles\web\node_modules\dsh-veneer"
New-Item -ItemType Directory -Path "$dst" -Force | Out-Null
Copy-Item -Recurse -Force .\* "$dst"
```
再在 `profiles/web/cordis.patch.yml` 注册 `dsh-veneer`,重启 `dsh web`。
(zip 里的 `install.bat` 就是把这两步自动化的脚本。)
### 日常同步(改完代码后)
```powershell
powershell -ExecutionPolicy Bypass -File .\sync.ps1 -AllowManagedOverwrite
```
`sync.ps1` 默认拒绝覆盖由 `dsh plugin` 管理的目录;上述开关只用于维护者明确进行本地开发部署。
脚本会先对 `lib/client.js`、`lib/index.js`、`lib/theme-storage.js`、`lib/llm-errors.js`
做 `node --check`,仅复制运行期白名单(`package.json`、`cordis.patch.yml`、`lib/`)到
`$env:USERPROFILE\.dsh\profiles\web\node_modules\dsh-veneer`,最后比对 SHA256。
仅前端 client 改动时刷新浏览器即可;`lib/index.js`、依赖或插件注册变化后需重启 `dsh web`。
### 发布到 npm(维护者)
```bash
npm login # 首次需登录 npm 账号
npm publish # 发布 dsh-veneer,接收者即可 `dsh plugin --profile web add dsh-veneer`
```
`package.json` 的 `files` 白名单只发布 `lib/` + `cordis.patch.yml`(npm 会自动附带
package.json / README / LICENSE),docs、test、install 脚本不会进 npm 包。
## ✅ 测试
Node 单元测试(无需 DSH / 浏览器,随时可跑):
```powershell
npm test
# 等价于: node --experimental-test-module-mocks --test
#(Node 24 起 module mocking 需要该 flag;host-settings.test.mjs 依赖 mock.module)
# - test/ai-colors.test.mjs AI 颜色容错单测(22 用例,mock canvas)
# - test/ai-colors.browser.test.mjs 真实浏览器引擎验证 CSS Color 4(oklch/hwb/lab/color()),
# 依赖 playwright(devDependency,缺失时自动跳过)
# - test/llm-errors.test.mjs LLM 错误码映射单测
# - test/theme-storage.test.mjs 主题解析/规范化/Host 迁移决策单测
# - test/client-storage-integration.test.mjs client 工厂有/无 settingsScope 双写集成单测
# - test/host-settings.test.mjs Host 设置命名空间 + Schema 注册(可选依赖)单测
# - test/install-script-check.ps1 zip 安装器 BOM/依赖/官方管理互斥/离线复制校验
```
Playwright 回归脚本(需 DSH 跑在 `127.0.0.1:3080`):
```powershell
python test\veneer-skin-check.py # 面板结构 / 导出导入 / 字体选择器 / 无 pageerror
python test\system-fonts-check.py # 系统字体扫描 + 字体/文字颜色精调 + 重置语义
python test\background-image-position-check.py # 背景图位置滑块 / 预览拖拽裁切 / 变淡蒙层 / 移除图
python test\import-security-check.py # 导入安全:CSS 注入 / 非法 token / 恶意 URL / 合法 rgb 色
python test\ai-theme-check.py # AI 生成(mock)/ 预览应用放弃 / 样式维度 / 模板库 / 无 pageerror
```
模板与 AI 契约校验工具(开发期使用):
```powershell
node tools\validate_templates.cjs
```
## 📄 License
MIT
Install
dsh plugin --profile web add github:swordordead/dsh-Veneer
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-veneer from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.