dsh-plugin-sync: Keep plugin lists consistent across multiple devices

前言

DSH 的运行方式是「一切皆插件」,插件装得越多,环境越贴近自己的工作流,但维护成本也越高:在办公室的桌面端装了一批插件,回家打开另一台设备却只有基础集合,要么手工重新装一遍,要么靠记忆核对哪些插件是开着的。手工复制插件目录的做法有几个问题:目录结构、cordis.patch.yml、依赖和 profile 的差异很难对齐,而且容易遗漏「某台设备上停用了某个插件」这种状态差异。

下面介绍的 wystan68/dsh-plugin-sync 解决的正是这个问题:它同步的不是插件源码,而是一份「插件清单」——包名、版本、启用/停用状态,在登录了 DSH 的设备之间保持一致。

这是什么

dsh-plugin-sync 由 Wystan68 维护(package.json 中 author 为 Wystan),分类为 admin-security,当前星标为 0。它定位为一个 DSH Host 插件 + Client 插件,通过同步码或加密中转在设备间搬运插件清单。

它明确不在同步范围内的内容:cordis.patch.yml 里的 config 配置项、插件源码,以及任何密钥或会话数据。也就是说,它解决的是「装上哪些、哪些开着」的问题,不是「配置成什么样」的问题。

安装与启用

在 DSH 里装(推荐):打开 设置 → 插件 → 安装插件,粘贴:

github:Wystan68/dsh-plugin-sync

或在终端装(需要 dsh 命令可用):

dsh plugin --profile desktop add github:Wystan68/dsh-plugin-sync

desktop 换成当前正在使用的 profile 名,不填 profile 时默认是 web。桌面版可以用完整路径调用:

"/Applications/DeepSeek Harness.app/Contents/Resources/runtime/cli/bin/dsh" plugin --profile desktop add github:Wystan68/dsh-plugin-sync

装完重启 DSH,左侧栏会出现「插件同步」图标(第 6 个)。卸载时在 设置 → 插件 里停用或移除,或执行:

dsh plugin --profile desktop remove dsh-plugin-sync

使用:同步码或加密中转

使用时的固定顺序是:先在每台设备设好同步密钥,再选一种传输方式,最后在差异预览里确认应用。

1、设同步密钥。打开面板,输入一把至少 8 位的密钥(例如 correct horse battery staple),点「设置」。密钥只在本机派生,明文不上传、不写入同步数据。

2、确认设备处在同一组。两台设备使用同一把密钥后,面板上会显示相同的同步组码(如 qvi2a-jwfkq)。

3、选择传输方式:

  • 同步码:A 设备点「生成同步码」复制,B 设备点「导入同步码」粘贴 → 预览差异 → 应用。不依赖任何服务器。
  • 加密中转:在「加密中转」里部署或填写地址 → A 点「推送」,B 点「拉取」→ 预览差异 → 应用。也可勾选「自动拉取并应用」。

4、确认差异。差异预览会列出:要安装的插件、要切换的启用状态、跳过项(本地链接插件、无安装来源)、版本差异提示。确认后再点「应用变更」。

同步语义

几点需要知道的语义,避免误操作:

  • 谁推送,以谁为准。同一同步组的远端只有一份最新快照,后推送的会覆盖先前的;应用后本机也变成这份清单的副本。
  • 最小改动。只安装缺失的插件、只切换与远端不同的启用状态;未列出的插件不会被卸载。版本不同只提示,不自动升降级。
  • 不会同步自己。插件同步自己的停用状态会被忽略,避免应用后界面消失。
  • 安装来源。npm 包按 name@version 安装;link: / file: 本地插件在其它设备上没有源码目录,会列入「跳过」并提示手动安装。
  • 账号通道。已登录 DeepSeek 账号时面板会显示账号信息;账号云同步接口尚未开放,当前同步仍由同步密钥驱动。

加密中转

一键部署:在「加密中转」里填一个 Cloudflare API Token,点「自动部署」。Token 需要 Account Settings: Read、Workers Scripts: Edit、Workers KV Storage: Edit 三项权限。插件会创建 dsh-plugin-sync KV 命名空间、上传 Worker(绑定 SYNC)、尝试开启 *.workers.dev 子域,最后把地址填回面板,每一步的结果都会显示。

手动部署:在面板里打开「手动部署」复制 Worker 脚本,或在仓库取 worker.mjs:

1、Cloudflare 控制台 → Workers & Pages → 创建 Worker,粘贴脚本。
2、绑定 KV 命名空间,变量名必须是 SYNC。
3、部署后把 https://<worker>.<子域>.workers.dev 填回面板。

中转协议:

GET    /health
GET    /v1/snapshots/{group}    → 密文信封 JSON,或 404
PUT    /v1/snapshots/{group}    → 写入信封
DELETE /v1/snapshots/{group}
Authorization: Bearer <由密钥派生的令牌>

载荷是端到端加密的 AES-256-GCM 密文,中转无法解密。同一同步组第一次写入时,中转会把令牌的 SHA-256 钉在 KV 里;换成另一把密钥既读不到也覆盖不了这个组。单次请求体上限 200 KB。

安全模型

同步码和中转共用同一套加密载荷,派生链路如下:

  • 密钥 → PBKDF2-SHA256(210,000 次)→ 32 字节主密钥;同步组码、中转令牌、加密密钥都由主密钥 HMAC 派生。
  • 本机只保存派生后的主密钥(DSH 凭据库 plugin-sync/settings),明文口令不会落盘。
  • 载荷在加密前先 gzip,使用随机 12 字节 IV 与 AAD(绑定同步组),防止跨组重放。
  • 中转只存密文;删除同步组会同时删除令牌哈希。

适用场景与注意

适合需要在多台 DSH 设备间保持插件集合一致、又不想手工核对的场景,尤其是明文同步码不方便传递时,可以用自建的 Cloudflare Worker 中转。

需要注意几点:插件以当前 DSH 进程的权限运行,安装前应先阅读源码与许可证(MIT),并确认 github:Wystan68/dsh-plugin-sync 这个来源可信。它只同步插件清单,不同步 config 与源码,配置差异仍需单独管理。中转自建的情况下,*.workers.dev 子域可用性依赖 Cloudflare;如果将来要正式使用账号云同步,需要等待接口开放。

结尾

dsh-plugin-sync 做的事情比较单薄但具体:把「设备之间插件集合是否一致」这个问题,收敛成一次同步码导入或一次中转拉取。项目当前版本 0.1.0,纯 ESM、无运行时依赖、要求 Node.js ≥ 20,测试覆盖密钥派生、加解密、同步码、差异计划、Worker 与端到端流程。目录页见 https://www.skillhub.cn/plugins/Wystan68/dsh-plugin-sync ,源码见 https://github.com/Wystan68/dsh-plugin-sync 。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye