DSH 版本守卫:记录插件版本与配置快照,插件冲突导致 DSH 崩坏后可脱离 DSH 进程回退到上一个可用版本 ·…
30.2/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/25 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查有告警:未发布到 npm registry,仅可从源码安装。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add skyjjgw/dsh-version-guard该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · other
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 14 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意未发布到 npm registry,仅可从源码安装
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✗npm 包dsh-version-guard(未发布到 npm,仅可源码安装)
✓Node 引擎要求 >=22.19.0 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/14 00:33:14
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 52 处,展示前 46 条)
- 发起网络请求lib/host/index.js:48
const response = await fetch(`http://${host}:${target.port}/`, { - 读取本地文件lib/host/index.js:97
if (!existsSync(join(profileDir, 'package.json'))) { - 发起网络请求lib/client/client.js:81
fetch(guardUrl('/healthz'), { cache: 'no-store' }) - 读取本地文件lib/bin/version-guard.js:40
const pkg = JSON.parse(readFileSync(join(PACKAGE_ROOT, 'package.json'), 'utf8')) - 读取本地文件lib/bin/version-guard.js:79
if (!existsSync(profileDir) && active.source !== 'recent' && active.source !== 'single' && active.source !== 'default') { - 读取本地文件lib/bin/version-guard.js:92
if (!active.confident && existsSync(profileDir) && profileDir === active.dir) { - 读取本地文件lib/bin/version-guard.js:99
if (profileDir === null || !existsSync(profileDir)) { - 读取本地文件lib/bin/version-guard.js:146
return existsSync(join(profileDir, 'package.json')) ? makeService(profileDir) : null - 读取本地文件lib/bin/version-guard.js:151
if (dir === null || !existsSync(join(dir, 'package.json'))) return null - 执行外部命令来自配置/变量lib/bin/version-guard.js:177
const child = spawn(command.file, command.args, { detached: true, stdio: 'ignore', windowsHide: true }) - 读取本地文件lib/core/store.js:378
compositionFiles: COMPOSITION_FILES.filter((relative) => existsSync(join(profile.dir, relative))), - 读取本地文件lib/recovery/detect.js:41
if (existsSync(join(home, 'profiles'))) return { home, candidates } - 读取本地文件lib/recovery/detect.js:45
if (existsSync(home)) return { home, candidates } - 读取本地文件lib/recovery/detect.js:85
entries = readdirSync(root, { withFileTypes: true }) - 读取本地文件lib/recovery/detect.js:94
const hasPackage = existsSync(packageJson) - 读取本地文件lib/recovery/detect.js:97
mtimeMs = statSync(hasPackage ? packageJson : dir).mtimeMs - 读取本地文件lib/recovery/detect.js:233
const entries = readdirSync(root, { withFileTypes: true }) - 读取本地文件lib/core/describe.js:143
hasMain: main !== null && existsSync(join(base, main)), - 读取本地文件lib/core/describe.js:144
hasPatch: typeof bundle.patch === 'string' && existsSync(join(base, bundle.patch)), - 读取本地文件lib/core/describe.js:457
names = readdirSync(root, { withFileTypes: true }) - 读取本地文件lib/core/describe.js:470
mtimeMs = statSync(dir).mtimeMs - 读取本地文件lib/core/describe.js:472
out.push({ name, dir, mtimeMs, hasPackage: existsSync(join(dir, 'package.json')) }) - 读取本地文件lib/core/fsx.js:31
statSync(path) - 读取本地文件lib/core/fsx.js:47
return readFileSync(path, 'utf8') - 写入本地文件lib/core/fsx.js:99
renameSync(from, to) - 写入本地文件lib/core/fsx.js:119
mkdirSync(dirname(path), { recursive: true }) - 写入本地文件lib/core/fsx.js:122
writeFileSync(temp, content) - 删除本地文件lib/core/fsx.js:126
rmSync(temp, { force: true }) - 写入本地文件lib/core/fsx.js:133
writeFileSync(path, content) - 读取本地文件lib/core/fsx.js:161
return readdirSync(dir).filter((name) => name.endsWith('.json')).map((name) => name.slice(0, -5)) - 写入本地文件lib/core/fsx.js:179
mkdirSync(dirname(lockPath), { recursive: true }) - 读取本地文件lib/core/fsx.js:196
age = Date.now() - statSync(lockPath).mtimeMs - 删除本地文件lib/core/fsx.js:202
rmSync(lockPath, { force: true }) - 删除本地文件lib/core/fsx.js:215
rmSync(lockPath, { force: true }) - 读取本地文件lib/core/fsx.js:222
return existsSync(dir) - 读取本地文件lib/core/pnpm.js:30
if (existsSync(local)) candidates.push({ command: process.execPath, args: [local], source: 'profile node_modules/pnpm' }) - 读取本地文件lib/core/pnpm.js:34
if (existsSync(runtime)) candidates.push({ command: process.execPath, args: [runtime], source: 'DSH runtime payload' }) - 执行外部命令来自配置/变量lib/core/pnpm.js:68
const child = spawn(pnpm.command, args, { - 读取本地文件lib/core/snapshot.js:57
names = readdirSync(snapshotsDir) - 写入本地文件lib/core/snapshot.js:157
mkdirSync(paths.snapshotsDir, { recursive: true }) - 读取本地文件lib/core/snapshot.js:236
names = readdirSync(snapshotsDir).filter((name) => name.endsWith('.json')) - 读取本地文件lib/core/snapshot.js:304
if (!existsSync(file)) return false - 删除本地文件lib/core/snapshot.js:306
rmSync(file) - 读取本地文件lib/core/snapshot.js:412
if (previous !== null && !statSync(target).isFile()) { - 删除本地文件lib/core/snapshot.js:440
rmSync(write.target, { force: true }) - 删除本地文件lib/core/snapshot.js:450
if (write.previous === null) rmSync(write.target, { force: true })
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
展开完整介绍(83 字)↓
DSH 版本守卫:记录插件版本与配置快照,插件冲突导致 DSH 崩坏后可脱离 DSH 进程回退到上一个可用版本 · DeepSeek Harness 插件的进程外回退
README
由 DeepSeek 最新模型翻译生成DSH 版本守卫 · dsh-version-guard
插件冲突导致 DSH 打不开时,用它退回上一个可用版本。
不少用户装了一个冲突插件,就把 DSH 装坏了:窗口打不开,或者打开后立刻退出。dsh-version-guard 会记录插件版本和配置快照,让坏掉的安装能回退——回退入口是一个脱离 DSH 运行的页面,所以 DSH 自己起不来时它照样能用。
为什么需要它(问题本身)
DSH 的插件装在 profile 目录里,由 package.json 的 dsh.profile.bundles 决定启动时加载哪些。装了一个有问题的插件之后:
* DSH 启动过程中抛错 → 窗口打不开,或者闪一下就退出;
* 而这个插件是在 DSH 里装的,所以你现在没有办法在 DSH 里把它卸掉 ——界面本身就是坏的。这是一个死锁。
dsh-version-guard 的做法是把这个死锁拆开:
1. 在 DSH 还健康的时候,每次成功启动后自动记录一个「回退点」,里面存着插件清单、每个插件的版本、以及决定加载哪些插件的配置文件。
2. 在 DSH 坏掉之后,用一个独立进程(只需要 Node,不加载任何 DSH 代码)打开恢复页,把配置退回上一个成功启动的版本。
展开完整文档(README 剩余 1 节)
DSH 版本守卫 · dsh-version-guard
插件冲突导致 DSH 打不开时,用它退回上一个可用版本。
不少用户装了一个冲突插件,就把 DSH 装坏了:窗口打不开,或者打开后立刻退出。dsh-version-guard 会记录插件版本和配置快照,让坏掉的安装能回退——回退入口是一个脱离 DSH 运行的页面,所以 DSH 自己起不来时它照样能用。
为什么需要它(问题本身)
DSH 的插件装在 profile 目录里,由 package.json 的 dsh.profile.bundles 决定启动时加载哪些。装了一个有问题的插件之后:
* DSH 启动过程中抛错 → 窗口打不开,或者闪一下就退出;
* 而这个插件是在 DSH 里装的,所以你现在没有办法在 DSH 里把它卸掉 ——界面本身就是坏的。这是一个死锁。
dsh-version-guard 的做法是把这个死锁拆开:
1. 在 DSH 还健康的时候,每次成功启动后自动记录一个「回退点」,里面存着插件清单、每个插件的版本、以及决定加载哪些插件的配置文件。
2. 在 DSH 坏掉之后,用一个独立进程(只需要 Node,不加载任何 DSH 代码)打开恢复页,把配置退回上一个成功启动的版本。
组成
| 部分 | 位置 | 作用 |
| 宿主插件 | lib/host/index.js | 写启动记录、成功启动后自动打回退点、把恢复页的 HTTP 接口挂到 DSH 上 |
| 设置页 | lib/client/client.js | 在 DSH 设置里加一页「版本守卫」,内嵌上面那个恢复页 |
| 离线恢复页 | lib/recovery/ + lib/bin/version-guard.js | 脱离 DSH 进程运行的恢复服务,DSH 起不来时唯一的入口 |
| 共享核心 | lib/core/ | 快照、恢复、版本识别、插件启停、pnpm 调用;两个前端共用同一套逻辑 |
设计上最要紧的一点:恢复能力不放在恢复对象里面。离线恢复页不 import 任何 @deepseek-ai/ 代码,只依赖 Node 与 profile 目录,因此插件把 DSH 搞坏时它照样能用。
安装
从 GitHub 安装
在 DSH 可用时,使用官方插件命令安装到实际使用的 profile(下面以 web 为例):
dsh plugin --profile web add github:skyjjgw/dsh-version-guard
安装后重启 DSH。仓库已包含可直接运行的 lib/,无需额外构建,也未发布到 npm。
请在发生故障前保存本仓库副本,方便直接运行其中的 dsh-version-guard.cmd 或 node lib/bin/version-guard.js;离线入口的使用不依赖 DSH 成功启动。
从本地目录安装
1. 放到插件目录
把整个 dsh-version-guard 目录放到 DSH 的插件目录,例如:
E:\dsh\plugins\dsh-version-guard
2. 让 profile 加载它
以 E:\dsh\data\profiles\web-enhanced 为例,编辑该目录下的 package.json:
{
"dependencies": {
// 新增这一行;用 link: 指向上面的目录,源码改动会立刻生效 "dsh-version-guard": "link:E:/dsh/plugins/dsh-version-guard" },
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
// 新增这一行;这一行才是真正决定启动时加载它的地方 "dsh-version-guard" ] } } }
然后在 profile 目录里同步依赖:
cd /d E:\dsh\data\profiles\web-enhanced
pnpm install --ignore-scripts
重启 DSH。设置里会出现「版本守卫」一页。
用 link: 而不是复制,是为了避免「插件目录里的源码」和「profile 里实际加载的那份」两份代码不一致 —— 那正是这类工具最容易出的问题。
3. 放好恢复入口
把 dsh-version-guard.cmd 放到顺手的位置(桌面即可)。它自己会去找 DSH 自带的 Node 运行时,所以不要求用户装 Node。
崩了以后怎么办
方式一:双击 dsh-version-guard.cmd(推荐)
打开浏览器里的离线恢复页,点「一键救援」。它会:
1. 找到最近一次成功启动时记录的回退点;
2. 先把当前状态记录成一个新的回退点(所以这一步本身也能撤销);
3. 把 package.json、cordis.patch.yml、pnpm-lock.yaml 等配置文件写回去;
4. 如果插件版本有变化,提示你点「立即同步依赖」跑一次 pnpm install。
然后关闭页面,重新启动 DSH。
方式二:命令行
dsh-version-guard.cmd --rescue --dry-run :: 先看看会退回哪一版,不改任何东西
dsh-version-guard.cmd --rescue :: 直接回退
dsh-version-guard.cmd --status :: 查看各插件版本与启动健康状况
dsh-version-guard.cmd --list :: 列出所有 profile
方式三:手动定位问题插件
如果不想整体回退,在恢复页的「当前插件版本」里找到可疑的那个,点「停用」。
停用会像官方插件管理器一样,在 profile 的 cordis.patch.yml 中写入对应入口的 disabled: true。它不会删除依赖、修改 bundles 或删除任何文件,随时可以「恢复启用」,官方管理器与版本守卫看到的是同一份状态。
恢复页能做什么
当前插件版本:每个插件的「要求版本 / 实际安装版本 / lockfile 锁定版本」、启用状态、以及为什么是这个状态(例如「不在加载列表里」「node_modules 里缺失」「所有 Cordis 行都被停用」)。
* 版本回退点:时间、类型(成功启动 / 手动记录 / 改动前 / 回退前)、当时的插件数量与 DSH 版本,可对比、回退、删除。
* 一键救援 / 预演:预演只计算会退回哪一版,不做任何修改。
* 单插件停用 / 恢复启用 / 锁定版本。
* 同步依赖:显式点击才跑 pnpm install --ignore-scripts。
它到底改了什么
回退点的内容是决定 profile 是什么的那些文件:
| 文件 | 说明 |
| package.json | 依赖版本 + dsh.profile.bundles 加载列表 |
| cordis.patch.yml | 用户补丁层(插件的启停与配置覆盖) |
| pnpm-lock.yaml | 实际解析到的版本 |
.dsh-market/state.json 由插件市场拥有,不属于 profile 组合真源,版本守卫不会快照或回写它。版本守卫也不再维护私有停用列表;插件启停唯一以 cordis.patch.yml 为准。
不复制 node_modules。 它可以从 package.json + pnpm-lock.yaml 用 pnpm 重新装出来,复制它只会让快照大到无法管理。所以「配置回退」和「依赖同步」是两步,恢复页会在需要时明确提示第二步。
不碰会话、密钥、设置。 回退点只覆盖上面这几个文件。
安全设计
* 恢复能力与被恢复对象隔离:离线恢复页不加载任何 DSH 代码。
* 写入原子性:所有文件写入都是「同目录临时文件 + rename」,中途崩溃不会留下半截的 package.json。Windows 上 rename 被占用时会重试,最后才退回原地写。
* 回退是事务性的:先把每个目标文件的当前内容读出来,中途失败会把已完成的改动逐个还原。
* 回退前先记录:所以「回退」这个动作本身也可以被回退。
* 路径校验:profile 名称在拼接前就校验,快照 id 也必须符合固定格式,拒绝 .. 与绝对路径,防止越出 profile 目录。
* 请求令牌:恢复页所有写操作都要带上本进程生成的令牌,其它页面的脚本拿不到它。
* 不改系统:不装东西、不动 PATH。依赖同步用 --ignore-scripts,避免在救援这个最不该出意外的时刻执行第三方安装脚本。
数据文件
都在 profile 目录下的 .dsh-version-guard/:
.dsh-version-guard/
├── boot.json 启动记录:上次是否走完、连续失败次数 ├── guard.lock 并发写锁 └── snapshots/ 回退点,默认保留最近 30 个 └── snap-<时间>-<类型>.json
删掉整个 .dsh-version-guard/ 目录不会影响 DSH 启动,只是会丢掉回退点。
工作原理:崩坏是怎么被发现的
「DSH 打不开」这件事本身没法在坏掉的进程里报告,所以用的是启动记录:
1. 宿主插件在启动早期写一条「启动中」记录;
2. 只有当 HTTP 服务真的能应答(对自身发一次请求并拿到响应)之后,才把这条记录标记为成功,并打一个回退点;
3. 下一次启动时如果发现上一条记录还停在「启动中」,就说明上一次启动没走完 —— 这就是崩溃信号;连续 2 次就判定为崩溃循环,并在控制台打印救援指引。
关键点是第 2 步不只判断端口是否被监听:端口通了不等于界面能用。
已知限制
* 不做应用版本回退。这里回退的是插件与配置,不是 DeepSeek Harness 应用本身(那需要保存安装包,是另一套机制)。
* 依赖同步需要网络。回退点里的版本范围如果指向一个本地已经没有的版本,必须联网才能装回来。恢复页会在此时明确提示。
* 社区插件自带的前端入口依赖 dsh.client 约定。本插件的客户端是按
window.__ModuleLoader__.load({ id, factory }) 这个 classic script 约定写的,
顶层不能用 import/export(那会让插件页整体加载失败)。
* 客户端远程调用走的是自己的 HTTP 路由(/dsh-version-guard/),而不是 typert/remote。这样不需要维护一份严格的类型描述文件,代价是它没有网关的计量与取消能力。
单插件启停与官方插件管理器共用 cordis.patch.yml。版本守卫写入对应入口的 disabled 覆盖,不删除 dependencies 或 dsh.profile.bundles,因此不会出现一个界面显示启用、实际宿主仍未加载的双真源状态。
关于 profile 识别
宿主插件必须知道「当前这个 DSH 进程用的是哪个 profile」,因为它要把启动记录和回退点写进那个 profile。判断顺序是:
1. 命令行上的 --profile <名称>;
2. 环境变量 DSH_PROFILE;
3. 插件配置里的 profile;
4. 最近修改过的那个 profile(这种情况下会打印警告)。
第 1 项排在第 2 项前面是有原因的:实测中 DSH 启动 --profile web-enhanced 时,环境里仍带着 DSH_PROFILE=desktop。若先信环境变量,在多 profile 的机器上就会把回退点写进另一个 profile —— 用户以为被保护了,实际用的那个 profile 一直没被记录。这个顺序有专门的回归测试(test/profile-detect.test.js)。
排障
恢复页打不开
dsh-version-guard.cmd --status
它只依赖 Node。如果连它都报「找不到 Node 运行时」,用 --NodePath 指定:
.\dsh-version-guard.ps1 -NodePath "D:\node\node.exe" -Status
回退之后 DSH 还是打不开
说明问题不在配置层。在恢复页里逐个「停用」社区插件(从最近装的那个开始),每次停用后重启 DSH 试一次。全停用之后仍然打不开,那就是 DSH 应用本身或环境问题,与插件无关。
回退后提示「还需要同步依赖」
点恢复页里的「立即同步依赖」,或者命令行:
dsh-version-guard.cmd --install
设置里没有「版本守卫」
宿主插件没有加载。检查 profile 的 dsh.profile.bundles 里是否有 dsh-version-guard,以及 node_modules 里能不能找到它。注意:即使这一页不出现, 离线恢复页依然可用。
自检
npm test
npm run verify
测试覆盖 profile 识别优先级、官方格式的插件启停、市场状态不进入快照以及回退隔离;包约定检查覆盖 exports、dsh.bundle、dsh.client、classic script、相对 import、 Cordis 补丁与路由挂载。GitHub Actions 会在 Node 22 和 24 上运行两组检查。
许可
MIT预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
skyjjgw/dsh-version-guard
DSH 版本守卫:记录插件版本与配置快照,插件冲突导致 DSH 崩坏后可脱离 DSH 进程回退到上一个可用版本 ·…
相关插件 · 其他
模型破甲清洗HunYiSage/dsh-purge
⚔️ DeepSeek Harness 网络安全红队工具dsh-purge
★ 16,993已汉化DeepSeek 客户端
73
女娲蒸馏alchaincyf/nuwa-skill
输入名人名字,提炼其思维模型与决策方式供你调用
★ 37,308已汉化DSH
72
逆向分析桥接Fanqi89/dsh-rea
REA(Reverse Engineer Anything)MCP 桥接,用来把 REA 逆向工具接入 DSH 插件
★ 51已汉化DSH
72
语音女友beiyege-01/dsh-voice-ai-girlfriend
语音 AI 女友Voice AI girlfriend for DeepSeek Harness:Whisper…
★ 888已汉化DSH
71.6
红队越狱测试套件Minglink/dsh-infinite-gen-5
DeepSeek v4.1 flash 逆向工具无限五代 求 Star 收藏 ⭐欢迎大家提交项目的改进
★ 3,759已汉化DSH
71.4
协同办公空间dream-num/univer-workspace
一个让人类与 AI Agent 共同创作、协作和审阅的开源 Office 工作空间。
★ 2,269已汉化DSH
70.8
这是你的仓库?认领条目