官方主题插件

Official theme plugin

别名:@deepseek-ai/dsh-client-ui-theme、主题服务、Appearance 设置行、ThemeRuntime

DSH 自带的主题插件(`@deepseek-ai/dsh-client-ui-theme`):管亮 / 暗 / 跟随系统三态、宿主在插件加载前注入的调色板引导,以及 `--dsw-*` 设计令牌(静态尺度 + 语义别名)——第三方皮肤最终大多落在它这套令牌上。

一句话

官方主题插件不是一个「皮肤」,而是主题这件事的机制本身:它定义有哪几种主题、把偏好持久化到哪、以及在界面脚本跑起来之前怎么先把颜色定下来。第三方皮肤(插件的、或直接改 patch 层的)最后都是在覆盖它这套令牌。

三态与它存在哪

实现里写得很直接(@deepseek-ai/dsh-client-ui-theme/lib/index.js,实测 0.1.0-rc.6):

常量值
THEME_PREFERENCES["light", "dark", "system"]
DEFAULT_PREFERENCE"system"
THEME_SETTINGS_NAMESPACE"ui-theme"
THEME_PREFERENCE_FIELD"preference"

所以偏好落在 $DSH_HOME/settings.yaml 的 ui-theme.preference(宿主 settings,不是 profile 的 cordis.patch.yml)。三个词汇要分清:light / dark 是内置主题 id;system 是偏好、不是主题 id——实现里显式抛错 "system" is a preference, not a registrable theme id,它靠 matchMedia('(prefers-color-scheme: dark)') 解析成实际主题;第三方主题是运行期注册的(进程内扩展),注册 = 覆盖同名别名变量,而 README 承认目前不验证一组覆盖是否完整。

最后一条是排错关键:皮肤只覆盖一半令牌不会报错,表现出来就是「有些地方没变」。看到「换了主题但某个面板还是旧颜色」,先怀疑覆盖不全,而不是缓存。

启动前的调色板引导

宿主侧在 HTTP 服务器存在时,会往每个 index 响应里紧接 <body> 起标签注入一段同步脚本(injectBootTheme → bootThemeScript),核心是 document.documentElement.style.colorScheme = dark ? 'dark' : 'light' 与 document.body.toggleAttribute('data-ds-dark-theme', dark)。

三点推论:它是同步的、在界面模块脚本之前执行,所以不会先白屏闪一下再变黑;没有 settings provider 时嵌的是 system,所以「设置没生效」和「设置文件没被读到」在这里表现一样;data-ds-dark-theme 是明暗判定位,排查颜色问题时先看 <body> 上有没有它,比看 CSS 快。

令牌:两段式命名

lib/styles/design-platform.css 是令牌的唯一权威来源,命名分两层(本轮实际读到的例子):

层前缀实测例子
静态尺度--dsw-static-*--dsw-static-blue-500、--dsw-static-deepseek-500、--dsw-static-neutral-bluish-950
语义别名--dsw-alias-*--dsw-alias-bg-base、--dsw-alias-label-primary、--dsw-alias-border-l2、--dsw-alias-scrollbar-bg-l1
局部特例--dsw-specific-*--dsw-specific-sidebar-fill、--dsw-specific-input-major

README 里写着设计规则:新增颜色不许直接在别名层造值,必须同时给一个静态尺度层级与一个语义别名。所以市面皮肤(如「丝滑的DSH」里 dsh-myskin 的 patch 块)写的是 --dsw-alias-* / --dsw-specific-* 这类别名——改静态层等于改原料,改别名层才是改意图。patch 层可以带令牌覆盖,这就是「不装插件也能换配色」的路子(机制见 concept/1)。

界面入口

主题在设置界面里有一行:客户端侧注册进 settings.general.item 槽(实现注释称 Appearance row,三个色块对应 Light / Dark / System)。所以位置是「设置 → 通用」里的外观行,不是单独的主题页。

与其它东西的关系

关系对象说明
落在client/1 官方 Web UI它改的就是这个界面的样子
同层邻居asset/1 官方中文界面词条一个管配色、一个管词条,都挂在同一个设置界面里
层序依据concept/1 patch 层与层序「改令牌」这条路的覆盖顺序在这一层
装在同层的插件dsh-loader(npm)主题类改动同样受升级断裂影响

分区里另外几条(dsh-myskin、dsh-wallpaper-engine、图标包占位)还没有词条,只存在于 data/zones/themes.yml 的卡片上。

未核实 / 未声明

  • targets 只写了 [shell, colors]:图标(icons)与壁纸(wallpaper)不在其中——分区文件写了「独立图标包尚未成规模」,壁纸由 dsh-wallpaper-engine 这类第三方插件承担。editor 也未声明:包内确有 lib/styles/shiki.css(代码块着色),但我没有核实「换主题会连带改编辑器配色」这条因果。
  • 没有 dsh plugin add 形式的安装命令:它随 bundle 层出厂;install 字段写的是落点与偏好位置。
  • 第三方主题注册的稳定性:README 说是「进程内扩展、不跨越内置 settings schema」,且移除任一第三方主题都不会覆盖最后一个持久化的内置偏好。上游自述,本轮未复现。
  • repo / 许可证:取自该包 package.json 的 repository.url(directory: packages/client/ui-theme)与 license: MIT;仓库根 LICENSE 未读取。
  • 哪些界面:实现是客户端(platform: web)插件;headless / TUI 形态下有没有主题概念本轮未核实,compat.runtime 因此只写 web。
  • 令牌总数:本轮只列举实际读到的若干条,没有统计完整清单,所以不给「一共多少个令牌」这类数字。

谁引用了这一条

信息表

category
appearance.theme
install
内置:随 @deepseek-ai/dsh-web-app 的 bundle 层出厂,没有单独的安装命令;偏好写在 $DSH_HOME/settings.yaml 的 ui-theme.preference
licenseRefs
[object Object]
repo
deepseek-ai/deepseek-harness
targets
shell、colors
titleEn
Official theme plugin
updatedAt
2026-10-02

标签:令牌、设置、外观、主题