tamashi486/dsh-plugins-hub0

dsh-plugins-hub

Third-party plugin hub for DeepSeek Harness — an official/community grouped plugin list inside Settings → Plugins, with update checks, one-click update, uninstall, and live enable/disable.

包名
dsh-plugins-hub
版本
0.1.0
许可证
MIT
最近更新
2026年9月12日

安装

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:tamashi486/dsh-plugins-hub

dsh-plugins-hub

设置 → 插件 里把「官方插件」和「第三方插件」分开,并管理第三方插件:检查更新、更新、卸载、启用/停用。

设置 → 插件
├── 插件配置   (官方,order 0)
├── 插件列表   (官方只读清单,order 10)
└── 第三方插件 (本插件,order 20)   ← 新增

它长什么样

Tab 顶部是 profile 概览(profile 名、第三方数、官方数、pnpm 是否可用),下面是两组可折叠的插件卡片:

  • 第三方插件(默认展开):每张卡片显示名称、版本、第三方/官方、安装方式(npm / git / 本地链接 / 本地目录 / 内置)、bundle 层、运行状态(运行中 / 已停用 / 补丁停用 / 加载失败 / 未挂载)、更新状态(可更新 1.2.3 / 已是最新 / 本地来源 / 未检查),以及描述、安装 spec、包目录、git 状态(分支 / 是否脏 / 落后多少提交)。 每行的操作:更新拉取源码启用 / 停用目录(在文件管理器里打开)、卸载(二次确认)。
  • 官方插件(默认折叠):随发行版安装的那 150+ 行,只读,用来对照「哪些是自己装的」。

底部是「最近一次操作」面板,可以展开看 pnpm / git 的原始输出。

判定规则:谁算第三方

不看包名猜,而是看包实际落在哪里

解析结果判定
落在 profile 自己的 node_modules(含 link: / file: 依赖,它们的软链就在那里)第三方
只经安装闭包 ~/.dsh/profiles/node_modules 解析到官方
解析不到,回退 @deepseek-ai/ 前缀启发式展示用兜底

所以 dsh-openspeclink: 到开发目录)是第三方,@deepseek-ai/dsh-tool-fs 是官方,cordis:include 这种 loader 内建归官方。

每种来源支持什么

来源检查更新更新卸载启停
npm^1.2.3对比 registry 的 latest,只在严格更新时才报「可更新」pnpm add @latest
gitgithub:owner/repogit ls-remote 的远端 HEAD 对比 pnpm-lock.yaml 里记录的 commitpnpm add
link: / file:不查线上版本,读取该目录的 git 状态若目录是 git 仓库且工作区干净:git pull --ff-only;否则不可更新
官方内置✅(改动写入补丁层)

「可更新」永远只代表“有更新的版本”,不会把降级说成更新(预发布版 vs 稳定版的比较走完整 semver 优先级)。

生效时机

  • 启用 / 停用:改写 profile 的 cordis.patch.yml(只动目标行,注释、!!js 表达式、insert: 块里其它行都原样保留),DSH 的配置热重载会在 1~3 秒内重组插件树,不用重启
  • 更新 / 卸载:等价于 dsh plugin --profile web add|remove,会同步 dsh.profile.bundles需要重启 dsh web 才会彻底生效,Tab 里会出现提示条和「复制重启命令」。

卸载一个非 bundle 插件时,会把用户补丁层里指向它的 insert 行改成 disabled: true,避免它下次启动因为找不到包而报错。

安全边界

  • 所有宿主路由仅接受本机回环请求,且校验 Host / Origin;写操作还要求自定义头 x-dsh-plugins-hub(跨站请求会先触发预检,而本服务从不批准预检)。
  • 包名、entry id 都过白名单正则;不拼 shell,全部走 execFile 参数数组。
  • 受保护行不能停用或卸载:热重载链(cordis-plugin-timer / cordis-plugin-hmr)、Web 服务链(dsh-host-webserver / dsh-web-app / dsh-client-modules / dsh-client-connection / dsh-api-remotes)、设置面板本身,以及本插件自己。
  • 官方内置插件不能被卸载,只能停用。

安装

# 装进 web profile(会同时登记到 dsh.profile.bundles)
dsh plugin --profile web add link:/path/to/dsh-plugins-hub
# 或者已发布到 npm 时:
dsh plugin --profile web add dsh-plugins-hub

# 重启 dsh web,然后:设置 → 插件 → 第三方插件
dsh web

从源码构建:

npm install
npm run build      # 宿主半边 tsc → lib/,浏览器半边 esbuild → lib/client.js
npm run typecheck
npm run check      # typecheck + node --check 产物

结构

src/index.ts         宿主插件:路由、清单组装、更新检查、pnpm/git 变更、补丁启停
src/profile.ts       profile 定位、原子写、pnpm 运行器、bundle 列表 reconcile
src/classify.ts      官方/第三方判定与包解析
src/updates.ts       registry / git 更新检测、semver 比较、checkout 的 git 事实
src/patch.ts         cordis.patch.yml 行级改写
src/validate.ts      出参白名单校验
src/contract.ts      宿主 ↔ 浏览器 的线上类型
src/client/          浏览器半边:settings.plugins.tab 注册、Tab UI、中英字典、样式
cordis.patch.yml     bundle 补丁层:插入宿主行并声明 inject

宿主半边不 import 任何 @deepseek-ai/* 包,全部按鸭子类型消费(loader.entries()webServer.register),因此不需要 peer 依赖闭包,也能跨 DSH 版本继续加载。

参考

实现前读过这些同类插件,设计上大量借鉴(也踩过它们踩过的坑):

  • fazhu4/dsh-plugin-studio:在 settings.plugins.tab 里做官方/社区分组、补丁层启停、受保护行名单。
  • HTUP1/dsh-plugin-managersettings.section 版本的管理页、卸载失败降级、中间态提示。
  • dsh-market/dshmarket:pnpm 兼容层、更新检测(npm dist-tag / git HEAD)、失败分类、重启语义。
  • 官方包本身就是契约:dsh-client-ui-settings-pluginssettings.plugins.tab 插槽)、dsh-host-plugin-inventorydsh-client-connectiondsh-app-boot(profile/bundle)、dsh plugin CLI。

License

MIT