dsh-plugin-backpack
Verified@kxreas/dsh-plugin-backpack · v0.1.1 · MIT · Web UI
插件背包(Plugin Backpack):在「设置 → 插件背包」里记录并导出当前 DSH 插件(不含本插件)。导出四选一:完整插件包 zip、TGZ 混合包(npm 来源只写清单、非 npm 来源附带物理包)、带 SHA-256 校验的文本清单、压缩口令;清单/口令会提示非 npm 来源不能带源码。支持添加导入与全量替换导入,全量替换需输入「我确定」并自动备份,安装失败只记录一次、结束后弹窗汇总,失败自动回滚;仅非 npm 的部分包会被禁止用于全量替换。
Install
dsh plugin add @kxreas/dsh-plugin-backpack Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Published to npm without a public repository. Inspect the package contents before installing.
Tags
Creators
Readme
插件背包(@kxreas/dsh-plugin-backpack)
DSH WebUI 的插件备份、迁移与恢复工具。入口在 设置 → 插件背包,用于把当前 profile 中用户安装的插件导出为可搬运的插件包、TGZ 混合包、清单或口令,并在另一台设备上导入。
- 导出四选一:插件包 / TGZ 混合包 / 清单 / 口令
- 导入两种模式:添加导入 / 全量替换
- 只处理用户安装、可移除的 profile 插件,不会列出、导出或移除插件背包自身
- 清单带 SHA-256 与数量校验;安装失败不重试;全量替换自动备份并在失败时回滚
- 纯 JavaScript,无原生依赖;Node 版本要求见
package.json
当前版本:0.1.1 · 许可:MIT
功能概览
| 能力 | 说明 |
|---|---|
| 插件信息 | 列出插件名、版本、安装来源、启用状态与组件行数 |
| 插件包导出 | 生成单个 zip:export-info.json + 每个插件一份离线包 |
| TGZ 混合包 | 单个 .tgz:npm 来源只写清单,非 npm 来源附带物理包 |
| 仅非 npm 打包 | 只打包 git / link / file / 本地路径等非 npm 来源插件 |
| 清单导出 | 单个 .dsmp 文本文件,带正文 SHA-256 与插件数量校验 |
| 口令导出 | 生成 DSHP1. 压缩单行串,直接显示、可复制,不落盘 |
| 添加导入 | 只新增缺少的插件,同名插件忽略,不动已有包 |
| 全量替换 | 先备份,再移除全部用户插件,再安装导入源;需二次确认 |
| 失败处理 | 单次尝试,不自动重试;失败写入报告并在结束后弹窗汇总 |
| 回滚 | 全量替换任一安装失败时,恢复备份中的插件与启用状态 |
| 部分包保护 | 仅非 npm 的部分包只能添加导入,宿主端拒绝全量替换 |
环境要求
- DSH Desktop 或 DSH Web,profile 中已启用
pluginManager服务 - 插件设置页依赖
settings.section客户端插槽 - Node.js:
^22.19.0 || >=24.0.0(与package.json的engines一致) - 目标插件必须是通过 profile 安装、
removable: true的用户插件
开发与验证环境:DSH 0.2.1-rc.2,Node.js 24。更老的 DSH 版本可能缺少 pluginManager 或客户端插槽接口,安装后不会正常挂载。
安装
从 npm 安装
dsh plugin add @kxreas/dsh-plugin-backpack
也可以在 DSH 的插件管理界面选择“安装第三方插件”,输入 npm 包名。
仅执行
npm install不会启用 DSH bundle。必须通过dsh plugin add或 DSH 插件管理器安装,让 profile 选中该 bundle。
安装完成后:
- 重启 DSH(宿主端插件模块在进程启动时加载);
- 刷新 Web 页面;
- 打开 设置 → 插件背包。
本地开发安装
dsh plugin add link:E:/path/to/dsh-plugin-backpack
本地 link: 安装适合开发调试;发布 npm 包后,最终用户使用包名安装即可。
快速开始
备份当前设备
- 打开 设置 → 插件背包,确认“当前插件”列表。
- 选择导出方式:
- 插件包:适合完整迁移,包含全部插件源码文件;
- TGZ 混合包:npm 插件只记录清单,非 npm 插件带物理包,通常更省空间;
- 清单:只记录名称、版本、来源、启用状态;
- 口令:只生成一段可复制字符串。
- 插件包 / TGZ 混合包 / 清单会弹出目录选择器;每次导出都重新选择,不保存默认目录。
- 导出结果会显示文件路径,或直接显示口令与复制按钮。
迁移到另一台设备
- 在目标设备安装并启用本插件。
- 把插件包 zip 或混合包 tgz 拷到目标设备,或准备清单 / 口令。
- 打开 设置 → 插件背包 → 导入,选择来源并点击 校验并预览。
- 选择 添加导入(推荐先做增量迁移)或 全量替换。
- 导入结束后查看弹窗中的成功 / 失败 / 回滚摘要;刷新页面查看插件变化。
导出
导出面板有四个标签,一次只产出一种结果。
插件包
生成一个 zip 文件:
dsh-plugin-packages-20261017-184500.zip
├── export-info.json
├── README.txt
└── packages/
├── export-info.json
├── dsh-meme-0.1.43.zip
├── dsh-meme-0.1.43.zip.meta.json
└── ...
packages/*.zip是每个插件的包根目录,包含包内真实的node_modules文件(符号链接会被跳过)。packages/*.zip.meta.json记录来源、启用状态、SHA-256、字节数。- 完整包(
scope: "all")包含全部用户插件,可用于添加导入或全量替换。 - 部分包(
scope: "non-npm")只包含非 npm 来源插件,partial: true、fullReplaceAllowed: false,只能添加导入。 - 离线包只保存插件自身文件;pnpm 安装时仍会按
package.json解析依赖,可能需要本机 store、镜像或网络。
TGZ 混合包
生成一个 .tgz 文件,适合在“完整插件包太大、又需要带非 npm 插件源码”的场景下节省空间:
dsh-plugin-hybrid-20261017-184500.tgz
├── manifest.dsmp
├── export-info.json
├── README.txt
└── packages/
├── dsh-at-file-0.7.0.zip
├── dsh-at-file-0.7.0.zip.meta.json
└── ...
- 清单记录全部插件;npm 来源只写名称、版本、来源、启用状态,不带物理包。
- 只为非 npm 来源(git / link / file / 本地路径等)插件保存物理包。
export-info.json标记kind: "dsh-plugin-hybrid"、scope: "hybrid"、fullReplaceAllowed: true。- 可用于添加导入或全量替换;导入 npm 插件时需要 registry / 网络可用。
packages/单独拿出来仍是部分包:sidecar 带partial: true,直接选择packages/目录不能全量替换。- 外层是 tar.gz,支持
.tgz/.tar.gz上传,也可选择包含该文件的目录导入。
清单
生成一个 .dsmp 文本文件,只包含插件名、版本、安装来源与启用状态:
{"format":"dsh-plugin-manifest","version":1,"created":"2026-10-17T10:00:00.000Z","count":2,"sha256":"<正文 SHA-256>","tool":"@kxreas/dsh-plugin-backpack/0.1.1"}
{"name":"dsh-meme","version":"0.1.43","source":"dsh-meme@^0.1.43","enabled":true}
{"name":"dsh-at-file","version":"0.7.0","source":"git+https://github.com/omdsh-dev/dsh-at-file.git","enabled":false}
清单不包含插件源码。导入时按安装来源重装,因此非 npm 来源(git / link / file / 本地路径)在换机后可能无法安装。
口令
生成一段 DSHP1. 开头的压缩单行串,直接显示在面板下方,可复制,不写文件:
DSHP1.<base64url(zlib(compact-json))>
口令只包含插件名、版本、启用状态和无法从 name@version 推导的非 npm 来源。它不包含源码与离线包,导入时仍需按来源重装。
示例:18 个真实插件约 620 个字符。
非 npm 来源提示
清单和口令无法携带源码。导出前,面板会列出所有非 npm 来源插件,并提示改用“插件包”导出;插件包标签下也可以直接选择“仅打包非 npm 来源插件”。
非 npm 来源包括:
git+https://.../git+ssh://...等 Git 来源link:本地目录file:本地 tarballhttps://...直接 tarball- 本地绝对路径或相对路径
workspace:等非 registry 来源
导入
导入来源
- 插件包导出目录:目录中包含
export-info.json与packages/*.zip - 插件包 zip/tgz:完整插件包、混合 TGZ 包、仅非 npm 的部分包,或单个插件包
- 清单文本:粘贴
.dsmp内容,或从文件读取 - 口令:粘贴
DSHP1.字符串,或从文件读取
导入前必须点击 校验并预览。预览会显示插件数量、将安装数量、重复数量、将移除数量、校验错误和警告。
添加导入
- 不修改已安装的同名插件;
- 按包名判重:本机已安装同名插件(含停用的)直接跳过,不比较版本;
- 其余插件安装到 profile;
- 单个安装失败只记录,继续处理后续插件;
- 导入结束后弹窗列出失败项,不自动重试。
全量替换
全量替换会改变整个用户插件集合,必须满足以下条件:
- 输入确认词(面板默认显示为
我确定); - 在确认弹窗中再次确认;
- 导入源允许全量替换(部分包不允许)。
执行流程:
- 把当前全部用户安装、可移除的插件备份到
~/.dsh/plugin-backpack/rollback/<jobId>/; - 移除当前用户插件(保留插件背包自身与 DSH 内置插件);
- 安装导入源中的插件;
- 任一安装失败:移除本次新装插件,恢复备份中的插件与启用状态;
- 将失败项、回滚状态、备份目录和报告路径展示在结果弹窗中。
部分包限制
仅非 npm 的部分包(partial: true / fullReplaceAllowed: false)只能添加导入。导入预览会显示“部分包 · 不能全量替换”并禁用全量替换;直接调用接口也会被宿主端以 PARTIAL_PACKAGE 拒绝。
部分包标记同时存在于:
export-info.jsonpackages/export-info.json- 每个
*.zip.meta.json
因此解压后只选择 packages/ 目录,或只保留 zip + sidecar,仍然能识别部分包。
TGZ 混合包是一个例外:根目录 export-info.json 标记 fullReplaceAllowed: true,因为清单包含全部插件;但 packages/ 里的 sidecar 仍标记为部分包,单独选择 packages/ 目录不能全量替换。
失败与报告
- 安装 / 移除单次失败不会重试;
- 失败原因、pnpm 输出末尾、日志路径写入
~/.dsh/plugin-backpack/reports/import-<时间戳>-<jobId>.json; - 导入结束后的弹窗汇总成功、跳过、失败、回滚状态;
- 回滚失败项会单独列出;
- 旧报告不会自动删除。
导入或回滚过程中不要停用本插件、关闭 DSH 进程或强制断电。任务随进程中断, 已经移除的插件需要按备份目录手动恢复。
清单格式(开发者)
文件结构
第一行是 meta JSON,之后每行一个插件 JSON:
{"format":"dsh-plugin-manifest","version":1,"created":"2026-10-17T10:00:00.000Z","count":2,"sha256":"<正文 SHA-256>","tool":"@kxreas/dsh-plugin-backpack/0.1.1"}
{"name":"dsh-meme","version":"0.1.43","source":"dsh-meme@^0.1.43","enabled":true}
校验规则
任一规则不满足都会直接中止导入:
- 第一行必须是合法 meta JSON,且
format/version/count/sha256合法; - 正文(去掉 meta 行与末尾单个换行)的 SHA-256 必须等于
meta.sha256; - 正文行数必须等于
meta.count; - 每行必须是合法 JSON,包名、版本、来源、
enabled合法; - 插件名不能重复,也不能是本插件自身;
- 清单引用离线包时,包的 SHA-256、字节数、包内
package.json名称与版本必须一致; - 离线包必须带
dsh.bundle.patch或cordis.patch.yml。
清单来自粘贴文本、没有离线包时不会报“包缺失”,但会在预览中警告,导入时按来源重装。
TGZ 混合包格式(开发者)
- 外层:gzip 压缩的 tar,扩展名
.tgz/.tar.gz。 manifest.dsmp:全部插件;npm 来源条目没有package字段,非 npm 条目带package/sha256/bytes。export-info.json:{ "kind": "dsh-plugin-hybrid", "version": 1, "scope": "hybrid", "partial": false, "fullReplaceAllowed": true, "physicalScope": "non-npm", "count": 18, "physicalCount": 11, "npmOnly": ["dsh-meme", "..."], "packages": [ { "name": "dsh-at-file", "version": "0.7.0", "file": "packages/dsh-at-file-0.7.0.zip" } ] }packages/*.zip只包含非 npm 插件;sidecar 带partial: true/fullReplaceAllowed: false,单独选择packages/时阻止全量替换。- 根目录
export-info.json的fullReplaceAllowed: true优先,因此整个 tgz / 导出目录可用于全量替换。
口令格式(开发者)
DSHP1.<base64url(zlib(compact-json))>
compact JSON 仅保存:
- 插件名
- 版本
- 启用状态
- 无法从
name@version推导的非 npm 来源
zlib 自带 adler32 校验;解压失败、Base64 非法、版本不支持都会报错。口令不包含离线包与源码。
数据与安全
| 路径 | 用途 |
|---|---|
~/.dsh/plugin-backpack/store/ |
导入时生成的稳定 .tgz(离线包转 pnpm tarball) |
~/.dsh/plugin-backpack/rollback/<jobId>/ |
全量替换前的自动备份 |
~/.dsh/plugin-backpack/reports/ |
导入报告 |
~/.dsh/plugin-backpack/tmp/ |
上传包 / 导出包解压临时目录(24 小时后清理) |
~/.dsh/plugin-backpack/incoming/ |
浏览器上传的原始 zip(24 小时后清理) |
安全约束:
- HTTP 路由仅接受
127.0.0.1/::1回环请求; - 所有请求必须带
x-dsh-plugin-backpack: 1自定义头,避免网页跨站触发; - 浏览器上传限制 2GB;
- zip 解压有路径穿越、符号链接、条目数量与总大小限制;
- 安装、移除、启用统一调用
ctx.pluginManager,不手写 profile 的package.json、锁文件或cordis.patch.yml; - 插件包、TGZ 混合包、清单、口令只包含插件元数据与各插件安装目录文件;插件背包自身不额外收集 DSH 账号令牌或个人配置。
兼容性与边界
- 只管理用户安装、可移除的 profile 插件;不管理 DSH 内置插件、
availability !== "profile"的包; - 只记录 bundle 的启用状态,不导出每个插件自己的配置,也不导出 profile 覆盖层(
cordis.patch.yml条目); - 离线包包含插件自身文件,但 pnpm 仍会解析
package.json依赖;完全离线迁移需要目标机具备依赖缓存或镜像; - 从插件包 / TGZ 混合包 / 导出目录导入后,profile 依赖可能写成
file:~/.dsh/plugin-backpack/store/*.tgz,而不是原来的link:/ git 来源;想保留原始来源,请用清单或口令导入; - 导入完成后不会自动刷新页面,需要手动刷新以更新插件界面;
- 安装失败不会自动重试,也不会回退到旧版本;全量替换模式除外(会整体回滚)。
故障排查
设置里看不到“插件背包”
- 确认插件已通过
dsh plugin add或插件管理器安装并启用; - 重启 DSH 后刷新页面;
- 检查 DSH 是否包含
pluginManager与settings.section接口。
页面提示“宿主端需要重启”
客户端 client.js 已更新,但当前进程仍加载旧宿主端。关闭并重新打开 DSH,让 lib/*.js 重新求值。
部分包无法全量替换
这是预期行为。仅非 npm 的部分包只包含部分插件,全量替换会删除其余插件;宿主端会返回 PARTIAL_PACKAGE。请使用完整插件包、TGZ 混合包、清单或口令执行全量替换。
非 npm 插件从清单/口令安装失败
清单与口令不包含源码。改用插件包导出,并在导入预览中确认离线包可用。
安装失败
- 查看结果弹窗中的 pnpm 日志路径;
- 查看
~/.dsh/plugin-backpack/reports/下的导入报告; - 含安装脚本的包可能需要 DSH 单独授权;
- 失败不会自动重试,修正来源后可重新预览并导入。
导入后界面没变化
刷新 Web 页面。宿主端插件已安装,但客户端插槽与侧边栏需要重新加载。
开发
目录结构
dsh-plugin-backpack/
├── package.json
├── cordis.patch.yml # 宿主端 bundle 行
├── client.js # 浏览器端设置页(模块加载器格式)
├── lib/
│ ├── index.js # 宿主端路由、任务、导出/导入编排
│ ├── manifest.js # 清单与口令格式
│ ├── plugins.js # 插件包解析、打包、来源分类
│ └── zip.js # zip / tar.gz / 校验工具
└── tools/ # 开发自测,不随 npm 包发布
本地检查
node --check lib/index.js
node --check lib/manifest.js
node --check lib/plugins.js
node --check lib/zip.js
node --check client.js
node tools/smoke-archive.mjs # zip / tar / 清单 / 口令
node tools/smoke-host.mjs # 假 profile + 假 pluginManager 跑真实路由
node tools/smoke-client.mjs # 可选 React SSR 渲染检查
smoke-client.mjs 依次从 DSH_BACKPACK_REACT_DIR、用户全局 node_modules、当前目录 node_modules 解析 React;没有 react-dom 时只运行模块加载检查。推荐显式指定同时包含 react 与 react-dom 的目录:
$env:DSH_BACKPACK_REACT_DIR='E:\path\to\node_modules'
node tools/smoke-client.mjs
License
MIT