@hmkk/dsh-appearance
A lightweight font and theme plugin for the DSH client: Latin/Chinese/code font pickers that list only installed families, and five official palettes (One Dark Pro, Dracula, Nord, GitHub, Catppuccin) applied through the official theme tokens, including code-block syntax colors. No bundled fonts, no
Install
dsh plugin --profile web add @hmkk/dsh-appearance
Sandbox test
This plugin has not been tested yet. Submit a test →
README
@hmkk/dsh-appearance
轻量的字体与主题插件 —— 给 DSH(DeepSeek Harness)桌面端 / Web 端加字体、配色预设、强调色与正文字号。不花哨:只改字体栈和颜色 token,没有动效、背景图或贴图皮肤。
亮点
轻 · 不打包字体文件、零运行时依赖、零构建步骤;仓库根就是插件包,两个 JS 文件 + 一份 42 个 token 的覆盖层,不改 DSH 源码
字体 · 中英文分两个框选,候选只列本机已安装的字体(Chromium Local Font Access);代码字体单列
主题 · One Dark Pro(Darker 档)/ Dracula / Nord / GitHub / Catppuccin 五套官方色板;浅色一侧是 One Light / Alucard / Nord Light / GitHub Light / Latte
覆盖 · 每个预设 42 个 token:底色、两级表面、四级文字、四档边框、状态色、卡片填充、代码块与 shiki 语法高亮——侧栏 / 菜单 / 卡片 / 代码块一起换
把关 · npm run check 逐个核对 token 名是否真的存在,并对 5 套预设 × 明暗两态 × 17 组做 WCAG 对比度检查,另有 54 项冒烟断言
配色预设
预设 · 深色底色 · 浅色底色 · 强调色 · 关键字 · 字符串
One Dark Pro · #1B1D23 · #FAFAFA · #61AFEF · #C678DD · #98C379
Dracula · #191A21 · #FFFBEB · #BD93F9 · #FF79C6 · #F1FA8C
Nord · #2E3440 · #ECEFF4 · #88C0D0 · #81A1C1 · #A3BE8C
GitHub · #0D1117 · #FFFFFF · #58A6FF · #FF7B72 · #A5D6FF
Catppuccin · #1E1E2E · #EFF1F5 · #89B4FA · #CBA6F7 · #A6E3A1
<details>
<summary>色板来源与两处最小偏离</summary>
取各主题官方色值,不做主观发挥——One Dark Pro 深色用 Darker 档(对话底取 peekViewEditor.background #1B1D23、面板/代码块取编辑器色 #23272E、再往上 #2C313A/#323842 是官方悬浮/选中色,正文 #ABB2BF,语法色取自扩展自带的 OneDark-Pro-darker.json),Dracula / Nord / GitHub Primer / Catppuccin 同理。
层级按各主题自己的关系排:最暗的一档给对话底,面板/代码块取编辑器色,越往前的表面越亮。这样既有面板感(对话底与内容差 8~11 级),整窗观感又和 VS Code 一致——早先两次偏差都出在这一层:一次把悬浮色当表面色(整窗偏亮),一次底色不够深(代码块和卡片跟背景糊在一起)。
只有两处偏离,都写在代码注释里:① 主题没公布的第四级灰阶按它自己的灰阶插值;② 浅色档里对比度不达标的原版彩色会压暗(例如 Latte 的粉彩)。
代码块底色取主题的面板/控件表面(VS Code 里 markdown 代码块就是这一层),所以代码块和对话底色一定分得开。另外四个 --dsw-static-neutral-* 填充(卡片头 / 悬停)也一并接管:deliverables / plan / schedule 这类卡片把它们写在元素级,不接管的话标题栏会停在 DSH 的固定近黑色(#212123)上,和卡片其它部分对不上。
仍未覆盖:菜单/浮层的模糊背板、终端 ANSI 色。明暗由「设置 → 通用」的外观切换决定,插件不另设开关。
</details>
装到 DSH
插件是一个组合包(bundle):带 dsh.bundle.patch 的 npm 包,已发布到 npm —— @hmkk/dsh-appearance。
要求 DSH 0.2.0-rc.2 或更新(package.json 的 engines.dsh)。这个字段是声明式的:宿主不会据此拒绝加载,它的用途是说明兼容范围。token 名会随宿主版本变化,换 DSH 版本后跑一次 npm run verify 即可核对。
A. 从 npm 装(推荐,一条命令)
npx -y --package @deepseek-ai/dsh dsh plugin --profile desktop add @hmkk/dsh-appearance
预构建包,走 npm 安装不会触发构建授权(allowBuilds)。
B. 界面安装(免命令行) —— DSH 左侧「Plugins」→「添加插件」,填本仓库的绝对路径(仓库根就是插件包):
D:\path\to\DSH-appearance
C. 从仓库源码安装
npx -y --package @deepseek-ai/dsh dsh plugin --profile desktop add https://github.com/LX-HMKK/DSH-appearance # 或本地目录 npx -y --package @deepseek-ai/dsh dsh plugin --profile desktop add D:\path\to\DSH-appearance
装完会把这行追加进 profile 的 dsh.profile.bundles,重启一次 DSH,然后在「设置 → 外观」里用。
<details>
<summary>没有 dsh CLI 时的手动 link 安装(已实测)</summary>
在 $DSH_HOME/profiles/<profile>/ 下做三件事:
1. package.json:dependencies 加 "@hmkk/dsh-appearance": "link:<本仓库绝对路径>",dsh.profile.bundles 数组追加 "@hmkk/dsh-appearance";
2. node_modules/@hmkk/dsh-appearance 建目录联接(junction / symlink)指向本仓库根(scoped 名要先建 @hmkk/ 目录);
3. 在仓库根补一个 peer 链接:node_modules/@deepseek-ai/schemastery → <profile>/node_modules/@deepseek-ai/schemastery。
少了第 3 步会踩坑:目录联接会让 Node 按真实路径(本仓库)向上找依赖,而 DSH 的运行时包在 profile 里,宿主半侧的 import '@deepseek-ai/schemastery' 会直接 ERR_MODULE_NOT_FOUND。
校验(在 profile 目录里跑,解析链与真实 loader 一致):
node -e "import('@hmkk/dsh-appearance').then(m => console.log(m.name, typeof m.apply, Object.keys(m.Config({}))))"
回滚:删掉依赖与 bundles 条目、删掉两个链接即可(安装前请备份 package.json)。
</details>
设置页里有三块
- 字体:界面与正文字体(西文 / 中文两个框分开选)、代码字体、正文字号(10–22 px,与「设置 → 通用」同一个值)。
- 配色:默认 / One Dark Pro / Dracula / Nord / GitHub / Catppuccin + 强调色、背景色、文字色,浅色与深色各一套。
- 高级(默认折叠):手动编辑字体栈、导入 / 导出整套设置(
dsh-appearance-v1:{...})、重置全部。
Config 字段
字段 · 默认 · 含义
preset · default · 配色预设 id(onedark / dracula / nord / github / catppuccin)
uiFont · '' · 界面与正文字体栈;空 = 跟随 DSH 默认
codeFont · '' · 代码字体栈;空 = 跟随 DSH 默认
accentLight / accentDark · '' · 强调色,按明暗档分别覆盖
surfaceLight / surfaceDark · '' · 背景色
inkLight / inkDark · '' · 文字色
手填值逐档合并:只填了深色档时,浅色档保留预设的值。认不出的预设 id(例如旧版本删掉的那几套)一律按 default 处理。
开发
无构建步骤:改 index.js / client.js 直接生效。link 安装的 checkout 由 HMR 重载;替换版本号才需要重启。
npm test # 冒烟测试(54 项断言) npm run verify # token 名 + 配色对比度 npm run check # 两个都跑(提交前必跑)
<details>
<summary>仓库结构</summary>
仓库根 = 插件包本体(awesome-dsh-plugin 的 CI 只从根 / packages / plugins / apps 读 package.json)
├─ package.json dsh.bundle.patch + dsh.client 两半侧的声明,以及开发用 scripts
├─ cordis.patch.yml 组合包层:插入插件行(行 id = 设置命名空间)
├─ index.js 宿主半侧:Config schema + 首屏字体注入
├─ client.js 浏览器半侧:设置页 + token 覆盖层(无构建)
├─ locale/{zh,en}.json 插件卡片的显示名与描述
├─ screenshots.json 插件市场详情页的截图清单
├─ assets/ 截图与配色预览图
└─ tools/ 开发工具(零依赖纯 Node)
├─ smoke-test.mjs 假 React + 假 ctx,把插件真跑一遍
├─ verify.mjs token 名校验 + 配色对比度校验
├─ gen-presets.cjs 色板 → 42 个 token 字面量的生成器
└─ asar.mjs 直接读取 DSH 的 app.asar(排查内部实现用)
</details>
<details>
<summary>设计说明:为什么必须有宿主半侧</summary>
两件事只有宿主(Node)能做:
1. 设置命名空间。DSH 的设置命名空间就是 Loader 行的 id,客户端插件无法自建。所以持久化必须由宿主半侧导出 Config(volatile 字段),浏览器半侧才能用 ctx.configForms.get('dsh-appearance') 读写。
2. 首屏注入。webserver/index-inject 是宿主侧的扩展点;客户端 CSS 要等 JS 模块图加载完才到。没有这一步,每次刷新都会先看到默认字体、再跳成用户选的字体。
数据流:
用户改动
└─> ctx.configForms.get('dsh-appearance').set/unset
└─> Host 校验 + 写入 profile 的 cordis.patch.yml(volatile 字段,带 revision)
└─> 快照回流(subscribe)
├─> 宿主:下次渲染 index 时把字体写进 <head>(首屏即正确)
└─> 客户端:c
…(truncated)Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::1,最后更新 2026-10-05