DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Deepworks Theme — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins

dsh-deepworks-theme

Deepworks Theme

DeepWorks 主题层:把 dsh Web UI 里的 DeepSeek Harness 品牌换成 DeepWorks 的

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add dsh-deepworks-theme@0.2.0
READMECompatibilityVersions

Compatibility and provenance

Deepworks Theme is published as dsh-deepworks-theme and currently resolves to version 0.2.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
npm
Registry updated
9/20/2026

Versions

0.2.0stable
9/15/2026
0.1.0stable
8/18/2026

Related plugins

Loading related plugins…

Latest
0.2.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
123.2 kB
Files
11
Surface
web
License
MIT
Source
npm
GitHub
★ 0
Weekly downloads
52
View source ↗Project homepage ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in ui-customization.

Better Sidebardsh-better-sidebarDSH web plugin: a VSCode-like right sidebar (explorer / editor / terminal / git / browser), isolated per conversation session. Exposes a service for other plugins to register sidebar tabs and file viewers.Codex Ui@michengai/dsh-codex-uiDSH Codex UI — 为 DeepSeek Harness Web 提供 Codex 风格侧栏、工作区会话树、全局搜索和轮次导航 · A Codex-style sidebar, workspace session tree, global search, and turn navigation for DSH WebDafeiyudsh-dafeiyuA desktop-native BigFish companion driven by DeepSeek Harness session events.Web App@deepseek-ai/dsh-web-appThe dsh browser-surface bundle: the web patch layer over dsh-base plus the runtime glue plugin (frontend dist serving, web-surface prompt, bash runtime variables, URL line)

README

dsh-deepworks-theme

DeepWorks 适配层里的主题包:把 Web UI 里露出的 DeepSeek Harness 标识换成 DeepWorks 的。这是一个可安装的组合包(bundle),装上就生效,不需要 --patch,也不需要改 harness 源码。

dsh plugin --profile web add dsh-deepworks-theme
dsh web

本包只管品牌这一件事。模型配置、记忆、技能中心等是同一个仓库里各自独立的包,各装各的、各发各的版本;家族全貌、命名约定与路线图见仓库根 README。

现在换掉了什么

位置换成
侧边栏展开态的品牌行:方形标记 + 产品名assets/deepworks-logo.png + assets/deepworks-wordmark.png
侧边栏收起态的方形标记assets/deepworks-logo.png
空会话首屏的 hero 图形同上那张方形标记
首屏标语「探索未至之境」/「Into the Unknown」与旁边的「预览版」徽章「让每一次构建更快一步」/「Build faster, together」,徽章摘掉
界面企业色(--dsw-alias-brand-primary)取自 logo 的蓝色,明暗两套
浏览器标签页图标与 PWA 图标那张方形标记
浏览器标签页标题DeepWorks,且在会话切换后仍守得住
PWA manifest本包提供,名称、描述、主题色都是 DeepWorks 的

上游默认是鲸鱼方标 + harness 字标 + 动画鲸鱼 hero + DeepSeek 蓝;企业色换成 #2f6fed(深色模式 #5b9bff)。

两张图取自 fastagi-web-obs.deepexi.com 的 deepworks-wordmark@2x.png 与 deepworks-logo.png,已落盘进包内。

字标是透明底深色文字,深色模式下由浏览器半侧用 invert 翻成浅色,所以只需维护这一张图。

不碰 harness 源码,卸载即完整还原。

安装

三种交付方式,效果一样,代价不同:

方式命令说明
npmdsh plugin --profile web add dsh-deepworks-theme发布时已构建好 lib/,安装零摩擦
tarballdsh plugin --profile web add ./dsh-deepworks-theme-0.2.0.tgzpnpm pack 产出,同样是预构建产物
GitHubdsh plugin --profile web add "github:Dbraum/dsh-deepworks#<sha>&path:/packages/theme"拉的是源码,靠 prepare 脚本现场构建,见下

本仓库是个 monorepo,所以 git 规格要带子目录:#<sha> 是 committish,&path:/packages/theme 指到本包所在的目录(pnpm 的 git 解析器按 & 拆参数,path: 是其中一个)。整串含 &,在 shell 里要加引号。

从 git 安装时 pnpm 拉到的是源码不是构建产物,本包的 prepare 脚本会在安装后跑 tsdown 补上 lib/。但 pnpm 10+ 在得到显式允许前拒绝执行 git 依赖的 prepare,所以首次 add 会失败;把 pnpm 打印的包键写进该 profile 的 pnpm-workspace.yaml 再重试:

allowBuilds:
  dsh-deepworks-theme: true

请如实看待这项授权:它允许本包的代码在安装时于你的机器上执行,且不在 agent 的任何沙箱之内。锁定 commit(#<sha>)能让后续推送无法悄悄改变实际运行的内容。不想让使用者做这项授权,就用 npm 或 tarball 分发。

卸载:dsh plugin --profile web remove dsh-deepworks-theme,依赖和对应的层一起消失。

使用

两种用法,取决于你有没有 dsh:当组合包用是本包的本职,装上即生效、不写代码;当普通 npm 包用是给自建 cordis 应用的,需要自己挂载。

一、当 dsh 组合包用(主路径)

从零到看见效果,三条命令:

dsh plugin --profile web add dsh-deepworks-theme   # 装包,patch 层自动并入 profile
dsh web                                            # 起 Web UI
# 浏览器打开输出的地址,侧边栏 logo、标签页图标和标题都已是 DeepWorks

生效不需要额外配置——图和标题都内置在包里。装上之后 $DSH_HOME/profiles/web/ 下会多出这一层,位置在 harness 自带两层之后、你自己那层之前(见原理的第二张图)。

想确认到底装没装上:dsh plugin 是把参数透传给 pnpm 的(dsh plugin --profile <name> <pnpm args>),所以 pnpm 的命令都能用:

dsh plugin --profile web list     # 透传成 pnpm list,应能看到 dsh-deepworks-theme

要换成自己的图和标题,不改本包,在自己 profile 的 cordis.patch.yml 里按 id 覆盖,详见换成自己的图和标题。改完不用重启,刷新浏览器即可。

二、当普通 npm 包用(编程式)

如果你不是在 dsh 里,而是自己搭的 cordis 应用,可以直接装:

npm install dsh-deepworks-theme    # 或 pnpm add / yarn add

前提两条:Node ^22.19.0 || >=24,以及本包是 纯 ESM("type": "module"),CommonJS 里只能用动态 import()。宿主还必须提供 webServer 服务——品牌层的 inject = ['webServer'] 声明了这个依赖,没有它插件不会启动。

包有三个导出,各管一摊:

导出内容
dsh-deepworks-theme品牌层插件本体(Host 半侧):apply、inject、name、Config,外加几个纯函数
dsh-deepworks-theme/brand品牌事实常量:PRODUCT_NAME、SHORT_NAME、DESCRIPTION、ASSETS、CHROME
dsh-deepworks-theme/client浏览器半侧,由 dsh 的客户端模块表加载;不要在 Node 里 import

挂载插件(只得到 Host 半侧——界面里的 logo 需要浏览器半侧,那要由 dsh 的客户端模块表加载):

import { Context } from '@deepseek-ai/cordis'
import WebServer from '@deepseek-ai/dsh-host-webserver'
import * as branding from 'dsh-deepworks-theme'

const ctx = new Context()
await ctx.plugin(WebServer, { host: '127.0.0.1', port: 5140 })  // 必须先有 webServer
await ctx.plugin(branding, {})                                   // 用内置的 DeepWorks 图和标题

await 一个 fiber 表示等它加载完成。品牌层的 inject 会让它自己等 webServer 就绪,所以两句的先后不影响正确性,但 await 能让配置校验的报错当场抛出来,而不是变成一个没人接的 rejection。

传配置就是第二个参数,字段与默认值见配置项:

await ctx.plugin(branding, {
  images: {
    logo: '/absolute/path/to/my-logo.png',
    wordmark: '/absolute/path/to/my-wordmark.png',
  },
  title: '我的产品',
})

注意 images 只吃本地绝对路径或远程地址(https:// / // / data:),相对路径不行。配置在加载期校验:文件不存在、routePath 形状不合法、地址里有会越出 HTML 引号的字符,都会当场让插件启动失败并指名字段,不会拖到浏览器请求时才 404。

只用内置的品牌常量,不挂插件也行——比如你想在自己的页面里引用同一张图:

import { PRODUCT_NAME, ASSETS } from 'dsh-deepworks-theme/brand'

console.log(PRODUCT_NAME)      // 'DeepWorks'
console.log(ASSETS.wordmark)   // …/node_modules/dsh-deepworks-theme/assets/deepworks-wordmark.png
console.log(ASSETS.logo)       // …/node_modules/dsh-deepworks-theme/assets/deepworks-logo.png

ASSETS 给的是文件系统绝对路径(靠 import.meta.url 算出来的),不是 URL——可以直接 readFile,但要在浏览器里显示得你自己挂路由或复制到静态目录。

卸载:插件的每处注册都走 ctx.effect(),所以停掉 fiber 就全部回卷,路由变 404、index.html 的注入撤干净:

const fiber = await ctx.plugin(branding, {})
await fiber.dispose()

三、离线 / 内网安装

拿不到 npm registry 时用 tarball,产物完全一样:

pnpm pack                                                          # 在 packages/theme 里产出 dsh-deepworks-theme-0.2.0.tgz
dsh plugin --profile web add ./dsh-deepworks-theme-0.2.0.tgz       # 或 npm install ./dsh-deepworks-theme-0.2.0.tgz

tarball 里是预构建产物,装的时候不跑构建、不需要联网,也不需要 allowBuilds 授权——这点和 git 安装相反(git 装的是源码,见安装)。

包的形状

一个包、一个 patch 层、一个版本,两个半侧:

packages/theme/            # 发布名 dsh-deepworks-theme
  cordis.patch.yml         # 本包的 patch 层,一行,写裸包名
  assets/                  # 品牌资产
  client.js                # 浏览器半侧 → "./client",手写,不进构建
  src/
    index.ts               # 品牌层插件(Host 半侧)→ 包的 "." 导出
    brand.ts               # 品牌事实(产品名、两张图的路径、企业色)→ "./brand"

patch 行必须写裸包名,插件因此必须是包的 . 导出。 浏览器半侧的扫描以 loader 条目解析到的包为准,带斜杠的说明符会被 harness 的 exactPackageSpecifier 判为子路径直接跳过(packages/client/modules/src/client/manifest.ts)——写成 dsh-deepworks-theme/branding 的后果是 Host 半侧照常生效、界面里的 logo 却一点没变,且没有任何报错。0.1.0 的 ./branding 子路径布局因此在 0.2.0 被收回。

这条约束也意味着本包放不下第二个层:一个包只有一个 . 导出。真要再加层,那是 packages/ 下的另一个包。

src/brand.ts 必须保持独立构建入口而不是被打进 lib/index.js——品牌资产的路径靠 import.meta.url 算,它得稳定落在 lib/ 下一层深。

功能上不属于「主题」的东西不要加进本包,在 packages/ 下另开一个包:使用者才能只装想要的那部分,版本也各走各的。这条边界和目录约定见仓库根 README。

本包每份构建配置都必须自包含(tsdown.config.ts、tsconfig.json 不引用仓库根):从 git 安装时 pnpm 只取 packages/theme 这一个子目录出来跑 prepare,那时身边没有 monorepo。

换成自己的图和标题

不要改本包,在自己 profile 的 cordis.patch.yml 里按 id 覆盖即可($DSH_HOME/profiles/<name>/cordis.patch.yml)。本包这一行的 id 是 deepworks-theme-branding,deepworks-<包>-<层> 是家族的命名约定——patch 的 id 是所有 bundle 共享的全局命名空间,重名会让 loader 启动即报 duplicate loader entry id:

- id: deepworks-theme-branding
  config:
    images:
      logo: '/absolute/path/to/my-logo.png'
      wordmark: '/absolute/path/to/my-wordmark.png'
    title: '我的产品'

换界面里的图,只能换本地文件。 images 也吃 https:// / // / data: 地址,但那只对 favicon 与 PWA 图标生效:界面里的两处图由浏览器半侧按固定路由请求,而远程地址恰恰是「不挂路由」的那种。要把图放在 OBS/CDN 上,得改 client.js 里的两个 URL 常量,那就是改本包了。

patch 是整块替换 config,不是按键深合并,所以要把想保留的字段一并重述——images 这一层同样是整块替换,只写 logo 时 wordmark 会退回包内自带的图。改完不用重启:patch 层被监听,进程会重新组合,刷新浏览器即可。换图片文件本身更简单——插件每次请求重新读盘,直接覆盖文件再刷新就行。

配置项

字段默认说明
images.logo包内 assets/deepworks-logo.png方形标记:侧边栏、首屏 hero、标签页图标与 PWA 图标
images.wordmark包内 assets/deepworks-wordmark.png横向字标:侧边栏展开态的品牌行
routePath/deepworks/logo本地图片挂载的路由前缀,每张落在 <前缀>/<目标>;需与站内已有路由错开
replaceFavicontrue是否连浏览器标签页图标一起换
title'DeepWorks'浏览器标签页标题;给空串表示不动上游的
manifesttrue是否提供 /manifest.webmanifest

images 的值是本地绝对路径或远程地址二选一。本地路径指向不存在的文件、routePath 形状不合法、地址里含引号括号一类会越出 HTML 引号的字符,都在加载期直接让插件启动失败并指名是哪个字段——不留到浏览器请求时才 404。标题走的是另一条路:它是正常会出现 & 的用户文本,所以转义而不是拒绝。

支持 png / jpg / gif / webp / svg / ico,按扩展名给 Content-Type。两处图都以 object-fit: contain 渲染,等比缩放不裁切,所以任何比例的图都不会变形。

改了 routePath 要同步改 client.js 里的 LOGO_URL 与 WORDMARK_URL:浏览器半侧写死这两个常量,两边不一致时界面里的图会 404,退回槽位的内置 fallback,而 favicon 照常是新的。这是两个半侧之间没有配置通道的直接后果。

原理

品牌层是 dual-face:Host 半侧跑在 Node 里,浏览器半侧跑在浏览器里,各干各的一摊,谁也替代不了谁——侧边栏 logo 是 React 槽位的占位组件,favicon 是 HTTP 路由上的字节流。

半侧文件负责
Hostsrc/index.ts图片路由、PWA manifest、index.html 的首屏标题与图标元数据
浏览器client.js三个品牌槽位占位、企业色板、深色模式字标反色、标题守卫、首屏标语
flowchart LR
  PKG["package.json<br/>dsh.bundle.patch + dsh.client"] --> PATCH["cordis.patch.yml<br/>insert dsh-deepworks-theme(裸包名)"]
  PATCH --> APPLY["Host: apply(ctx, config)<br/>inject: ['webServer']"]
  APPLY -->|"ctx.effect + register()"| ROUTE["图片与 manifest 的 HTTP 路由<br/>/deepworks/logo/logo、…/wordmark<br/>每次请求重新读盘"]
  APPLY -->|"ctx.effect + tapIndex()"| TAP["index.html 改写<br/>换 title、换 favicon、加 manifest 链接"]
  PKG --> CLIENT["client.js<br/>浏览器模块表加载"]
  CLIENT -->|"ctx.slots.register"| SLOT["占三个官方品牌槽位<br/>渲染 &lt;img&gt;"]
  CLIENT -->|"ctx.theme.overrideTokens"| TOKEN["企业色板"]
  SLOT --> IMG["浏览器按固定路由加载图片"]
  ROUTE --> IMG

用到的官方扩展点一共四个:

  • ctx.slots.register — 占三个品牌槽位。配合 ctx.slots.inject(name, ...) 等待声明方,与激活顺序无关;槽位消失时贡献自动撤回。三个槽位由两个不同的包声明,所以拆成两条等待链,任一方迟到都不会拖住另一方。
  • ctx.theme.overrideTokens(source, tokens) — 叠一层别名 token。每个 token 必须同时给 light 与 dark,运行时校验,传裸字符串会抛出教学式错误。
  • ctx.webServer.register — 每张品牌图与 manifest 各挂一条精确路由,每次请求重新读盘。
  • ctx.webServer.tapIndex — 改写 index.html:换 <title>、换 favicon、加 manifest 链接。tap 在每个 index 响应上都会跑,所以它是幂等的。

每处注册都走 ctx.effect(),插件卸载时自动撤销。

装上以后,本包这一层落在 profile 组合里 harness 自带的两层之后、使用者自己那层之前:

flowchart TB
  ROOT["空的 profile 根"] --> B1["@deepseek-ai/dsh-base"]
  B1 --> B2["@deepseek-ai/dsh-web-app"]
  B2 --> B3["dsh-deepworks-theme<br/>本包的 cordis.patch.yml"]
  B3 --> P["profile 的 cordis.patch.yml<br/>← 使用者在这里覆盖 images / title"]
  P --> H["$DSH_HOME/cordis.patch.yml"]
  H --> O["--patch overlay"]

关键取舍:占用官方槽位,而不是用 CSS 盖 svg。0.1.0 用的是后者,因为当时上游的插槽表里没有品牌位;上游补上 sidebar.brand.mark、sidebar.brand.name、conversation.hero.brand.mark 之后,官方已经把这几处做成了受支持的扩展点(@deepseek-ai/dsh-client-ui-brand-official 就是上游自己的占用者),按 viewBox 猜 svg 不再是耦合最小的做法。取舍与后果见 ADR-0002。

两处没有槽位可用,只能退回 DOM 操作,各自选了明确的失败方式:

  • 标签页标题:ui-layout 的 DocumentTitle 在每次会话与面板切换时按构建期的 DSH_CLIENT_TITLE 重写标题,已安装的插件改不了那个构建值,所以 Host 注入的 <title> 只活到外壳挂载为止。浏览器半侧挂一个 MutationObserver 在外壳每次写入后把产品名补回去,并保留它拼在前面的会话名。
  • 首屏标语:上游用 t() 直接渲染进一个 span,外面没有槽位,而 ctx.locale.register 对已有 owner 的 (namespace, locale) 是抛错不是覆盖,拿不到字典这条路。于是按原文精确匹配文本节点——上游改了文案就不再命中、退回显示原文,好过按位置匹配而误伤无关文本。

开发

依赖装在仓库根(pnpm workspace,一次装全仓库的包);其余命令在 packages/theme 里跑,或从根上用 --filter 指名:

pnpm install                              # 在仓库根:装全仓库依赖,并通过 prepare 跑一次构建
pnpm --filter dsh-deepworks-theme build   # 也可以 cd packages/theme 后 pnpm run build
pnpm --filter dsh-deepworks-theme typecheck
pnpm --filter dsh-deepworks-theme test    # 冒烟 + 集成,都不需要浏览器和 API key
cd packages/theme && pnpm pack            # 产出可 dsh plugin add 的 tarball

在仓库根跑不带 --filter 的 pnpm run build / typecheck / test,是 pnpm -r——全仓库每个包都跑一遍。

tests/smoke.ts 用一个假的 ctx(只提供 webServer、logger、effect)直接跑 apply,快且不起进程,覆盖两张图各走各的路由、远程地址不挂路由、manifest 的内容与开关、标题替换与转义、以及加载期校验;tests/integration.ts 则 new Context() 挂上真的 @deepseek-ai/dsh-host-webserver 和品牌层,用 fetch 打真实端口逐条比对字节,并在卸载 fiber 后确认三条路由都变成 404、index taps 也撤干净了。这份可测性来自「插件只依赖 ctx 上的服务」。

两份测试都只覆盖 Host 半侧。 浏览器半侧(client.js)要一个真的浏览器与客户端模块表才能跑,目前没有自动化覆盖——集成测试守住的是两个半侧的接合点:浏览器半侧写死的那两条路由确实存在且吐出正确的字节。改 client.js 要手动验:dsh web 起来,看侧边栏展开/收起两态、空会话首屏、明暗两种主题、以及切换会话后的标签页标题。

client.js 不进构建也不过 TypeScript 检查,这是「装完即用、不需要浏览器打包步骤」的代价。

浏览器半侧验过的行为

浏览器半侧的这份清单是在真实 dsh web 上用 Playwright 逐条核过的(浅色与深色两种配色、中英两种界面语言),可作为改 client.js 后的手动回归清单:

  • 标签页标题为 DeepWorks,切换会话后仍然守得住
  • 三处 img[src^="/deepworks/"] 均可见,尺寸分别是 24×24(侧边栏标记)、85×24(侧边栏字标)、34×34(首屏 hero)
  • --dsw-alias-brand-primary 浅色 #2f6fed、深色 #5b9bff
  • 深色模式下字标 filter: invert(1) brightness(1.8),浅色模式下为 none
  • 官方鱼标与字标的 SVG 渲染数为 0
  • 首屏无「探索未至之境」/「Into the Unknown」,显示品牌标语;「预览版」徽章已摘掉
  • 无 console 报错与 pageerror,启动无插件警告

依赖只有三样,各有各的角色:@deepseek-ai/schemastery 是唯一的运行时依赖(配置 schema 真的会执行);@deepseek-ai/cordis 和 @deepseek-ai/dsh-host-webserver 都只被 import type,运行期不产生 import,所以是 devDependency——运行期的依赖声明是插件导出的 inject = ['webServer'],由宿主满足。

本包由 dsh-logo-swap 0.2.0 改名重组而来:那个包是通用的「换掉 logo」,这个包是「DeepWorks 的主题层」,图与标题都已内置,版本号因此重新从 0.1.0 起算。它一度以 dsh-deepworks 之名占据仓库根,家族要放进第二个包时拆到了 packages/theme——dsh-deepworks 这个名字留给以后的全家桶(见仓库根 README),patch 行的 id 也在那次拆分里带上了包名前缀(deepworks-branding → deepworks-theme-branding)。

从 0.1.0 升级

0.2.0 换掉了实现(CSS 覆盖 → 占用官方槽位,见 ADR-0002),配置与导出都有破坏性变更。patch 行的 id 没变,所以按 id 写的覆盖仍然落在正确的层上,但里面的字段要改:

0.1.00.2.0
images.brand(横幅那处)images.wordmark
images.mark(方形那处)images.logo
targets: ['brand', 'mark']删掉——两处总是一起换
faviconSource: 'mark'删掉——图标总是取 logo
—新增 manifest(默认 true)
import … from 'dsh-deepworks-theme'(品牌常量)'dsh-deepworks-theme/brand'
import … from 'dsh-deepworks-theme/branding'(插件)'dsh-deepworks-theme'
patch 行 name: 'dsh-deepworks-theme/branding'name: dsh-deepworks-theme(必须是裸包名)

profile 里的 patch 行由本包自己的 cordis.patch.yml 提供,升级即生效,不用手改。要手改的只有你自己 profile 那层里写过的 config。

发布到 npm

包名不带 scope,就叫 dsh-deepworks-theme。发布在包目录里做,不在仓库根(根是 private,发不出去)。

cd packages/theme
pnpm run typecheck && pnpm run test   # 发布是不可撤销的,先让两道闸都绿
npm version patch                     # 或 minor / major:改 package.json 并打一个 git tag
npm login                             # 一次即可,凭据存在 ~/.npmrc
pnpm publish --access public          # prepare 会在打包前自动跑一次 tsdown

npm version 打的 tag 只写版本号,仓库里有多个包时会撞车;家族第二个包出现后要改成带包名的 tag(npm version patch --tag-version-prefix=dsh-deepworks-theme-v,或交给 changesets)。

pnpm publish 打包前会跑 prepare,所以发出去的一定是当次源码构建的产物,不会是本地残留的旧 lib/。tarball 里只有 files 列的 lib/、assets/、client.js、cordis.patch.yml,加上 npm 总会带上的 package.json、README.md、LICENSE——src/、tests/ 和构建配置都不在内。client.js 必须在 files 里:它是手写的、不进构建,漏了它 client-modules 会在启动时抛「exports no "./client" bundle」。想先确认,用 pnpm publish --dry-run --no-git-checks,或 pnpm pack 出 tarball 后装到一个空目录里 import 一遍。

npm 上的版本不能覆盖,发错了只能再发一个版本号(npm unpublish 有 72 小时窗口且会留下墓碑)。

已知限制

  • 和 harness 的版本是硬耦合的。 @deepseek-ai/dsh-host-webserver 的 latest dist-tag 停在 0.0.1-rc.1,那一版提供的服务叫 httpServer;当前 harness 提供的是 webServer,只在 alpha / next 线上发布。所以本包按确切版本依赖 0.1.6-alpha.1,并在仓库根的 pnpm-workspace.yaml 里放行它的发布年龄门槛。harness 处于 pre-release,明确不承诺兼容旧格式,分发本包时要说明它对应哪个 dsh 版本。
  • 槽位名是与上游的耦合点。 上游若给三个品牌槽位改名,client.js 里对应的 ctx.slots.inject 会永远等不到,界面静默退回上游的 fallback 图——插件照常加载,只是什么都没换掉。
  • 两个半侧之间没有配置通道。 images 改成远程地址只对 favicon 与 PWA 图标生效;改 routePath 必须同步改 client.js 里的两个 URL 常量。这两处不一致时没有报错,只是界面里的图 404。
  • 首屏标语按原文匹配。 上游改了那句文案(或新增一种界面语言),替换就不再命中,页面显示上游原文。这是刻意选的失败方式,但它确实会随上游版本悄悄失效。
  • 字标靠 CSS 反色适配深色模式。 包内字标是透明底深色文字(实测 240×68 里 3008 个 alpha>0 的像素亮度全部低于 110,最高仅 32),深色模式下用 invert(1) brightness(1.8) 翻成浅色,省掉第二份资源。换成浅色或彩色字标时要改掉 client.js 里的 WORDMARK_DARK_CSS,否则深色模式下会被反成一片糊。
  • client.js 没有自动化测试,也不过类型检查。 它是手写的加载器工厂,改动只能手动验,见开发。
  • 界面里的产品名文案仍是上游的。 槽位换的是图形,散落在界面各处提到 DeepSeek Harness 的文案不在本包覆盖范围内——那要走 locale 字典,而上游对已有 owner 的 (namespace, locale) 是抛错不是覆盖。