tamashi486/dsh-plugins-hub ↗★ 0
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.
安装
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:tamashi486/dsh-plugins-hub说明文档
阅读完整 README ↗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-openspec(link: 到开发目录)是第三方,@deepseek-ai/dsh-tool-fs 是官方,cordis:include 这种 loader 内建归官方。
每种来源支持什么
| 来源 | 检查更新 | 更新 | 卸载 | 启停 |
|---|---|---|---|---|
npm(^1.2.3) | 对比 registry 的 latest,只在严格更新时才报「可更新」 | pnpm add @latest | ✅ | ✅ |
git(github:owner/repo) | git ls-remote 的远端 HEAD 对比 pnpm-lock.yaml 里记录的 commit | pnpm 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-manager:
settings.section版本的管理页、卸载失败降级、中间态提示。 - dsh-market/dshmarket:pnpm 兼容层、更新检测(npm dist-tag / git HEAD)、失败分类、重启语义。
- 官方包本身就是契约:
dsh-client-ui-settings-plugins(settings.plugins.tab插槽)、dsh-host-plugin-inventory、dsh-client-connection、dsh-app-boot(profile/bundle)、dsh pluginCLI。
License
MIT