DSH Web 自定义插件 · 官方 client-plugin 形态(v3.0.0)· 平台模块由宿主 module table 提供,随 DSH 版本兼容
dsh-thinking-levels-settings 给 DSH Web 的 设置 → 思考级别 新增一页,
用于为自定义 llm-pi-ai 提供商的每个模型配置 reasoningEfforts
(off / minimal / low / medium / high / xhigh / max),并通过官方 Settings wire 持久化到
~/.dsh/settings.yaml。
false)/ 显式声明档位(档位 → 协议值,留空表示不发参数)。input: [text, image];两项都不勾则省略该字段(继承目录)。viewBox 0 0 16 16 / currentColor);图标一律 aria-hidden 并始终伴随文字,不使用 emoji。package.json 注入),装机后一眼确认生效的是哪个版本。zh/en 词条,跟随平台的
设置 → 通用设置 → 语言,切换即时生效。它是 纯客户端插件:node 半(lib/index.js)的 apply 为空,
浏览器半(lib/client.js)以官方 window.__ModuleLoader__.load 闭包工厂注册
settings.section 槽位贡献。
它同时支持 官方 publish 文档(打包与安装插件)的两种形态:
package.json 声明 dsh.bundle(patch: ./cordis.patch.yml)。
dsh plugin --profile <name> add <tarball> 一步完成安装 —— pnpm 装包 →
reconcile 识别 dsh.bundle → 自动挂进 dsh.profile.bundles → loader 激活 →
client-modules 暴露浏览器 bundle。符合 deepseek-harness develop/basic/publish 文档。install.sh 在 profile 的 cordis.patch.yml 里追加一行挂载(与官方
client 插件如 dsh-client-ui-settings 的安装方式同构)。dsh-client-modules 会扫描 profile loader 条目,
对声明了 dsh.client(platform: web)且 exports["./client"] 指向构建产物的包,
把 lib/client.js 作为 /plugins/<id>/client.js 提供给浏览器。
无论哪种安装形态,最后一步都是 重启 dsh + 硬刷新浏览器。
按你的环境选一种方式。方式 A/B 需要 dsh CLI 和 pnpm
(dsh plugin 是一个 pnpm 转发器),这是 deepseek-harness 官方 publish 文档推荐的安装方式。
pnpm --version
优先使用 Node.js 自带的 Corepack:
corepack enable
corepack prepare pnpm@latest --activate
pnpm --version
如果系统没有 corepack,通过 npm 安装:
npm install --global pnpm
pnpm --version
command -v pnpm
该命令必须能输出 pnpm 路径,dsh plugin 才能调用它。
dsh plugin 能找到它。
无权限全局安装时优先使用 Corepack,或选择方式 C。dsh plugin --profile web add github:blackteaYES/dsh-thinking-levels-settings#master
前提:本机需要 dsh CLI 和 pnpm(dsh plugin 是
pnpm 转发器)。没有 pnpm 请看方式 C。
master 分支由 CI 自动维护为预构建产物分支——只含 lib/
与包元数据,不含源码、没有 prepare 脚本,安装即用,reconcile 自动加入
dsh.profile.bundles:无需本地构建,pnpm ≥10 也不再需要
allowBuilds 构建授权。合并到 main 后自动更新,之后
pnpm update 即升级。
ERR_PNPM_ADDING_TO_ROOT(workspace-root 保护),加 -w:
dsh plugin --profile web add -w github:blackteaYES/dsh-thinking-levels-settings#master。
直接 github:blackteaYES/dsh-thinking-levels-settings(不带 #master)
会克隆源码并在本机执行 git 依赖的 prepare 构建。pnpm ≥10 首次会报
ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED——官方预期的安全拦截。处理:
把错误中 allowBuilds: 下方打印的完整包键原样复制到
~/.dsh/profiles/web/pnpm-workspace.yaml 顶层:
allowBuilds:
"<粘贴 pnpm 错误中打印的完整包键>": true
然后锁定并重试错误中同一个 commit:
dsh plugin --profile web add "github:blackteaYES/dsh-thinking-levels-settings#<sha>"。
这项授权允许插件源码在本机执行;只对可信源码授权并锁定 commit。
从 release 页下载 dsh-thinking-levels-settings-<version>.tgz,
或直接使用直链一步安装(tarball 由 CI 在打 v* tag 时自动构建附加):
dsh plugin --profile web add https://github.com/blackteaYES/dsh-thinking-levels-settings/releases/download/v3.0.0/dsh-thinking-levels-settings-3.0.0.tgz
这条命令做了什么(官方机制):pnpm 把 tarball 装进 profile → 依赖解析到声明了
dsh.bundle 的包 → reconcilePlugins 把它自动加入
dsh.profile.bundles 层列表 → 下次启动时 loader 加载 cordis.patch.yml
的行(ui-thinking-levels-settings)→ client-modules 扫描并暴露浏览器 bundle。
无需手动编辑任何文件、无需构建授权。
重启 dsh(Ctrl+C 后重新 npx @deepseek-ai/dsh web),
浏览器 硬刷新(Ctrl+Shift+R)。
llm-pi-ai 配置,会按 provider/模型列出可编辑的档位;页面写入将持久化到 ~/.dsh/settings.yaml。tar -xzf dsh-thinking-levels-settings-3.0.0.tgz -C /tmp/rel
cd /tmp/rel/package
bash install.sh # 默认 profile: web
DSH_PROFILE=web bash install.sh # 显式指定
DSH_HOME=/path bash install.sh # 覆盖 DSH home
脚本会:检测到 dsh + pnpm 都可用时自动走官方路径(dsh plugin add,
失败自动 -w 重试),否则走手工路径。重复运行安全(旧版本备份为
.previous,依赖与 patch 行不重复添加)。
重启 dsh,浏览器硬刷新。
包目录就位 → profile package.json 加 "dsh-thinking-levels-settings": "file:./packages/dsh-thinking-levels-settings"
→ cordis.patch.yml 追加:
- insert:
- id: ui-thinking-levels-settings
name: dsh-thinking-levels-settings
@deepseek-ai/* 声明为普通 dependencies,
pnpm 安装时会往 profile 的 node_modules 里物化一套旧版本副本(约 30 个
@deepseek-ai/* 包 + zod/immer/zustand 等)。cordis 以 profile 目录为解析锚点,
这些近端旧副本会遮蔽 dsh 本体提供的模块,造成新旧混跑:所有对话报
history unavailable for session "...": TypeError: Cannot read properties of undefined (reading 'parse')、
设置页异常等。升级到 2.1+ 前请先清理一次。cd ~/.dsh/profiles/web
dsh plugin --profile web remove dsh-thinking-levels-settings # 等价 pnpm remove
dependencies 与 dsh.profile.bundles
数组里都不应再有 dsh-thinking-levels-settings(remove 不会动 bundles 字段,有则手工删)。
ls node_modules/@deepseek-ai 应报不存在或为空;
若还有真实目录(非符号链接),全是旧插件拖入的副本,整棵删除:
rm -rf node_modules/@deepseek-ai
ls node_modules | grep -E '^(zod|immer|zustand|fflate|use-sync-external-store|@standard-schema)$'
有则一并删除。宿主自己的依赖在上一级 ~/.dsh/profiles/node_modules(指向安装的符号链接),
不受影响;删的只是 profiles/web/node_modules 这一层被插件拖进来的旧副本。
重启 dsh web,确认历史会话恢复正常(不再报 history unavailable),再按方式 A / B 安装 2.1+。 2.1 起宿主包改为 optional peerDependencies,2.2 起不再声明任何 @deepseek-ai 包(dev/peer 全无),任何 pnpm 配置下都不会再物化副本。
适用:你拿到的是 源码包(含 src/、tsdown.config.ts、tsconfig.json),
想在这台机器上继续开发和重新构建。前两步与“方式 D 手工”相同(包目录就位 + file: 依赖),第 3 步改为在插件目录内构建:
cd ~/.dsh/profiles/web/packages/dsh-thinking-levels-settings
# 1) 安装构建工具链与官方 @deepseek-ai client 依赖(需要网络,写入项目 node_modules)
npm install --ignore-scripts
# 2) 构建(tsdown 产出 lib/index.js + lib/client.js + map,随后 tsc 产出 lib/types)
npm run bundle
# 3) 开发模式:改 src/ 后自动重建(client-modules 的 HMR 会检测到 client.js rev 变化并热更新)
npm run watch
构建完成后回到第 4 步(profile 级 npm install 建立链接 + 重启)。
npm install 需要能访问 npm registry(国内可用镜像加速)。构建产物 lib/ 不入 git,
任何时候 npm run bundle 都能复原。| 检查项 | 命令 / 位置 | 期望 |
|---|---|---|
| 包目录就位 | ls ~/.dsh/profiles/web/packages/dsh-thinking-levels-settings/lib/ |
看到 client.js、index.js、invariant.js、types/ |
| 符号链接建立 | ls -la ~/.dsh/profiles/web/node_modules/ | grep thinking |
dsh-thinking-levels-settings -> ../packages/dsh-thinking-levels-settings |
| patch 行存在 | grep -A1 "ui-thinking-levels-settings" ~/.dsh/profiles/web/cordis.patch.yml |
输出 id: ui-thinking-levels-settings 与 name: dsh-thinking-levels-settings |
| 包被 client-modules 暴露 | curl -s http://127.0.0.1:3080/ | grep -o '"id":"dsh-thinking-levels-settings"[^}]*}' |
出现 "url":"/plugins/dsh-thinking-levels-settings/client.js?rev=…" |
| bundle 可拉取 | curl -s http://127.0.0.1:3080/plugins/dsh-thinking-levels-settings/client.js | head -c 60 |
以 window.__ModuleLoader__.load({ 开头 |
| 页面可见 | 浏览器 → 设置 | 左侧出现“思考级别”入口 |
把插件迁移到另一台机器的 DSH 安装,本质就是 把包目录打包带走,在新机器上按“第 2 节方式 A/B/C/D”安装。
项目里已带 release.sh,一键产出官方形态的 .tgz 发布包
(npm pack,遵循 package.json 的 files 白名单):
bash release.sh # 产出 dsh-thinking-levels-settings-<version>.tgz
OUT_DIR=/path bash release.sh # 输出到指定目录
cd ~/.dsh/profiles/web/packages/dsh-thinking-levels-settings
npm run bundle # 确保 lib/ 是最新产物(含 invariant.js 与 types/)
release.sh 内部会自动跑这一步。发布包里只含 files 白名单的内容
(lib/ 构建产物 + 两个文档 + cordis.patch.yml + package.json),不含 src/ 与构建工具 ——
目标机不需要任何构建环境。
把 dsh-thinking-levels-settings-<version>.tgz(约 20KB)发给目标机(放到 GitHub
Release、邮件、网盘均可)。目标机有两种安装路径:
dsh plugin --profile web add ./dsh-thinking-levels-settings-<version>.tgzbash install.sh(脚本会自动检测,有 dsh+pnpm 就走官方路径,否则走手工路径)mkdir -p ~/.dsh/profiles/web/packages
cd ~/.dsh/profiles/web/packages
tar -xzf dsh-thinking-levels-settings-3.0.0.tgz # 解出 package/ 目录
mv package dsh-thinking-levels-settings
ls dsh-thinking-levels-settings/lib/ # 确认 client.js / index.js / invariant.js / types
~/.dsh/profiles/web/package.json 的 dependencies 加
"dsh-thinking-levels-settings": "file:./packages/dsh-thinking-levels-settings"~/.dsh/profiles/web/cordis.patch.yml 追加:
- insert:
- id: ui-thinking-levels-settings
name: dsh-thinking-levels-settingscd ~/.dsh/profiles/web && npm install --package-lock=false --ignore-scripts,重启 dsh web,硬刷新浏览器install.sh,解包后以
bash install.sh 运行即可——自动检测环境:有 dsh + pnpm 走官方
dsh plugin add 路径(失败自动 -w 重试),否则走手工路径(复制包目录 +
package.json 注入 file: 依赖 + cordis.patch.yml 追加挂载行)。
幂等,可重复运行。也可显式指定:DSH_PROFILE=web bash install.sh。新版本到手后,保持 profile 的依赖声明和 patch 行不变,只更新包目录内容:
# 备份旧版(可选)
mv ~/.dsh/profiles/web/packages/dsh-thinking-levels-settings \
~/.dsh/profiles/web/packages/dsh-thinking-levels-settings.old
# 放入新版
cp -r dsh-thinking-levels-settings ~/.dsh/profiles/web/packages/
# node_modules 里的符号链接仍指向 ../packages/dsh-thinking-levels-settings,无需重新 install
cd ~/.dsh/profiles/web
npm install --package-lock=false --ignore-scripts # 仅刷新 lockfile 引用(可选)
# 重启 dsh web + 硬刷新浏览器
如果新版本的 package.json 变了(比如依赖增加),才必须重新执行 profile 级 npm install。
cd ~/.dsh/profiles/web
# 1) 从 package.json 的 dependencies 删掉 dsh-thinking-levels-settings
# 2) 从 cordis.patch.yml 删掉 - insert: … ui-thinking-levels-settings 段
# 3) 删除包目录与链接:
rm -rf node_modules/dsh-thinking-levels-settings packages/dsh-thinking-levels-settings
# 4) 重启 dsh web,硬刷新浏览器
cordis.patch.yml 是顶层 YAML 数组(- insert: 顶格写)。这是 pnpm ≥10 对 git 依赖 prepare 脚本的首次安全授权,不是下载、代理或插件 manifest
故障。该路径现在仅属于开发者路径(从 main 源码安装);普通用户请改用
方式 A(#master 预构建产物,无 prepare、无需授权)或方式 B(Release tarball)。
仍要走源码安装时:把 pnpm 打印的完整包键原样加入当前 profile 的
pnpm-workspace.yaml 顶层 allowBuilds,然后锁定同一个 commit 重新执行
add。官方依据:
从 GitHub 安装:构建脚本这道坎。
这是 ≤2.0 旧版插件把宿主包物化进 profile 造成的新旧版本混跑症状,与 dsh 本体无关。 按「从 ≤2.0 旧版升级:先清理被污染的 profile」清理后重装 2.1+ 即可恢复。
说明当前 profile 没有注册 llm-pi-ai 命名空间(未配置 dsh-llm-pi-ai 提供方)。
这个插件只服务该命名空间;没有 llm-pi-ai 的 provider 配置时页面不会列出模型。
这是 Settings wire 的 SETTINGS_CONFLICT 冲突保护:另一个窗口/进程改了同一命名空间。
刷新页面后重试即可。
例如 Cannot find module 'xxx' —— 说明 client bundle 里出现了非平台模块依赖。
正式形态的 bundle 只允许 react 等平台模块走 require,其余必须内联;
如果你改了 src/client/index.ts 引入了新的 npm 包(非 inline-safe),需要把该包改为内联
或在 tsdown.config.ts 的 EXTERNAL_PLATFORM_MODULES 里声明。
先确认 Node 版本(node -v ≥ 22.19)。npm run bundle 需要能访问 npm registry
拉取 @deepseek-ai/* 依赖;国内网络可用 --registry=https://registry.npmmirror.com 加速。
| 路径 | 作用 | 来源 |
|---|---|---|
package.json | dsh.client 清单、exports(. / ./invariant / ./client / ./src/*)、files | 源码维护 |
src/index.ts | node 半入口(空 apply) | 源码维护 |
src/client/index.ts | 浏览器半:settings.section 槽注册 + 页面组件 | 源码维护 |
src/invariant.ts | invariant companion(包所有权注册) | 源码维护 |
tsdown.config.ts | 构建配置(官方 tsdown.client.ts 形态) | 源码维护 |
lib/index.js | 构建产物:node 半 | npm run bundle |
lib/client.js | 构建产物:ModuleLoader 闭包工厂 | npm run bundle |
lib/invariant.js | 构建产物:invariant | npm run bundle |
lib/types/**/*.d.ts | 类型声明 | npm run types(bundle 内联) |
cordis.patch.yml | 一行 patch 模板 | 源码维护 |
INSTALL.md | 文本版安装说明 | 源码维护 |
dsh.client 清单(platform: web)+
exports["./client"] → 构建产物 lib/client.js(window.__ModuleLoader__.load
闭包工厂,react 等平台模块走注入 require)+ exports["./invariant"] +
exports["./src/*"] + files 只含产物与文档。安装侧 = 包目录(file: 依赖)+
一行 patch。参考:deepseek-harness packages/client/AGENTS.md、
docs/architecture.zh.md、packages/client/tsdown.client.ts。