# dsh-undo-plugin

> Provides undo/rollback system for DSH: automatic snapshots of configuration and plugin code; one-click undo via WebUI, chat interface, and offline tool; safe mode and GUI fallback when DSH fails to start.

## Metadata

- Author: [@lire1131](https://github.com/lire1131)
- Repo: <https://github.com/lire1131/dsh-undo-plugin.git>
- GitHub: [lire1131/dsh-undo-savepoint](https://github.com/lire1131/dsh-undo-savepoint)
- Stars: 103
- Language: JavaScript
- License: [MIT](https://spdx.org/licenses/MIT.html)
- Topics: `backup`, `crash-recovery`, `deepseek-harness`, `dsh`, `dsh-plugin`, `powershell`, `rollback`, `snapshot`, `undo`, `windows`
- Forks: 4
- Open Issues: 3
- Last push: 2026-08-20T19:14:27.000Z
- Added: 2026-08-14T00:00:00.000Z

## Install

```bash
dsh plugin --profile web add github:lire1131/dsh-undo-plugin
```

## Wiki

## 一句话定位
这是 DSH 的撤销/回退系统，会在配置或插件代码改动时自动存档，覆盖后能一键还原——包括「改错了某个配置」「插件代码改坏」「DSH 起不来」三种典型事故。

## 核心能力
- 自动存档配置与插件代码：受监控的配置文件或插件代码变更后经防抖自动生成快照，无需手动操作
- 三入口一键撤销/恢复/回退：WebUI 头部按钮、全局快捷键（Ctrl+Alt+Z / Ctrl+Alt+Y）、对 AI 说「撤销上一步」、CLI/离线工具全部可用
- 插件代码也能回滚：连改坏插件源码的事故（如某插件抛出 `yield* is not async iterable`）都能一键还原，无需重装
- 密钥脱敏与本机还原：`.env` / `.credentials.yaml` 进快照自动替换值为占位符，真实值存本机 vault；导出 ZIP 不会泄露密钥；本机回滚时仍能完整还原
- 一键安全模式：DSH 起不来时关闭所有用户插件只留撤销插件，重启保证能起来；面板和 CLI 都能切
- 崩溃归因：上次异常退出会在 WebUI / GUI 横幅里直接给出「最后正常快照」id 与一键回退按钮，不用自己猜回退到哪
- 跨机迁移：快照可导出/导入 ZIP；恢复前自动预检缺失插件并明确提示「可能起不来」
- 局外急救工具：插件目录里的 PowerShell CLI + GUI 窗口，DSH 完全挂了也能用

## 技术实现
- **语言**: JavaScript (ESM, Node 20+) + 客户端 React (打包进 client.js) + 离线 PowerShell
- **关键依赖**: `@deepseek-ai/dsh-tools`（提供 `defineTool`，通过 `createRequire` 多锚点解析）、`node:fs`（快照与监听）、`node:child_process`（pnpm 依赖同步、PowerShell 文件选择器、ZIP 导出）、`react`/`react/jsx-runtime`（WebUI 头部按钮 + 面板）
- **架构模式**: Cordis 双面插件 — host 端注册 8 个 `defineTool` 与 `/api/undo/*` REST 路由并启动 fs.watch 防抖存档；client 端注入会话头部按钮槽、设置项槽与全局键盘事件；离线 PowerShell 工具与 Node 共享 `lib/spec.json` 与同一快照仓库
- **入口文件**: `lib/index.js`（host apply / 工具注册 / REST）、`lib/client.js`（React 组件与槽注入）、`cordis.patch.yml`（插件挂载声明）

## 适用场景
- 用户改了插件代码或配置后担心改坏想有后悔药 — 默认开自动存档，撤销就是一句话的事
- 安装/更新/卸载插件后 DSH 启动报错或行为异常 — 用快照回退到改动前即可，不必手工找配置文件回滚
- 装了某个插件导致 DSH 完全起不来 — 用 GUI/CLI 工具进安全模式保证能启动，再决定恢复或排查

## 前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DSH | 未明确声明下限（package.json `engines.dsh: >=0.0.1`） | 运行时需可解析 `@deepseek-ai/dsh-tools` |
| Node.js | >=20.0.0 | host 与 client 端均依赖 ESM、Node 内置模块与 PowerShell 5.1/7 |
| 平台 | Windows / macOS / Linux | 核心快照逻辑跨平台；离线 CLI/GUI 工具与一键桌面快捷方式主要面向 Windows（`runPnpm` 走 `cmd.exe`、`.ps1/.bat` 工具） |
| 原生模块 | 无 | 仅依赖 Node 内置模块与 `pnpm`（用于依赖同步） |

## 安装方式
```bash
dsh plugin --profile web add github:lire1131/dsh-undo-plugin
```

## 配置项
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| 自动保存开关 | 布尔 | 关闭后插件改动不再触发自动快照；手动保存与撤销仍可用 | 开启 |
| 防抖窗口 | 毫秒 | 改动发生后等多久才落盘一次快照；过小会频繁存档，过大会丢粒度 | 1500 |
| 自动档保留数 | 整数 | 自动存档最多保留多少份；超过自动清理 | 20 |
| 后悔档保留数 | 整数 | 撤销前自动存的「当前状态」快照保留多少份 | 10 |
| 自动清理 | 布尔 | 超量时是否自动删除旧自动档/后悔档；关闭则全部保留 | 开启 |
| 手动快照目录 | 路径 | 手动保存的快照存放位置；脱离默认路径便于放外置盘 | `$DSH_HOME/undo-snapshots/manual` |
| 自动快照目录 | 路径 | 自动存档与后悔档存放位置 | `$DSH_HOME/undo-snapshots/auto` |
| 敏感模式 | redacted / 明文 | `redacted`（默认）下 `.env` / `.credentials.yaml` 进快照时值替换为占位符；`明文` 模式与旧版本行为一致 | redacted |
| 插件目录白名单 | 列表 | 留空则自动发现 node_modules 下的 junction；显式填写则只快照指定目录 | 空 |

配置在 WebUI 设置页「快照」分区修改，或直接编辑 `$DSH_HOME/undo/settings.json`；也支持在 `cordis.patch.yml` 的 config 块里以编程方式注入。

## 常见问题

**Q: 装完插件没看到头部按钮？**

A: 装完需要重启 DSH 才进入稳态。默认装到 web profile，请确认命令行带的是 `dsh plugin --profile web add ...`。多 profile 机器上若用其他 profile，需要把 `--profile` 改成对应名字，否则插件会写到 web profile 的快照库。

**Q: 撤销会把当前改动丢了吗？**

A: 不会。每次撤销/回退前都会先把当前状态保存成「后悔档」（pre-restore），所以即便撤销错了还可以用 redo 恢复回去；只有 redo 被新的真实改动消化后才会被自动清理。

**Q: 快照会包含密钥吗？导出 ZIP 安全吗？**

A: 默认敏感模式是「脱敏」：`.env` / `.credentials.yaml` 进快照时值被替换成占位符，真实值存本机 vault（仅本机回滚时还原）。导出 ZIP 在脱敏模式下不含真实密钥；如果切到「明文」模式或导的是旧快照，导出文件会带真值并打显眼的告警。

**Q: DSH 完全起不来了还能用吗？**

A: 能。安装目录的 `tools\` 下有离线 CLI（`dsh-undo-savepoint.ps1`）和 GUI 窗口（`dsh-undo-savepoint-gui.ps1`），即便 DSH 进程不在也能用。最极端情况下可先开「安全模式」只保留撤销插件，再重启 DSH 一定起得来。

**Q: 跨机迁移快照要做什么？**

A: 在 A 机的快照面板点「导出」拿到 ZIP；先在 B 机装齐 A 用过的插件，再导入 ZIP。恢复时插件会做跨机预检，缺插件会明告，未安装的插件目录不会被写入。

**Q: 撤销涉及插件代码改动要不要重启？**

A: 需要。撤销/回退触及 `cordis.patch.yml`、profile/package.json 或插件代码时，报告里会出现「重启 DSH 后生效」的提示；纯 `.env` 或配置值变更一般不需要重启。

**Q: 自动快照会不会无限堆积？**

A: 不会。设置里可配自动档保留数量（默认 20 份）和后悔档保留数量（默认 10 份），超过上限会自动清理；手动保存的快照永不自动清除。

**Q: 安装命令的 `#master` 要不要带？**

A: 仓库当前安装命令是 `dsh plugin --profile web add github:lire1131/dsh-undo-plugin`，DSH 会拉默认分支。若你想锁版本，可显式加 `#master` 或 tag。

## 上手难度
入门 — 装上即用，默认配置已覆盖常见场景；遇到 DSH 起不来或想精调保留数量时再进设置页或离线工具即可。

## 已知问题与限制
- 单个快照引用体积上限 5MB；超出时插件代码树只记录清单 + 打 `truncated` 标记，不丢任何数据（手动快照/导出仍可兜底）— `lib/index.js:170 / lib/index.js:392-394`
- 撤销/回退涉及 `package.json` / `pnpm-lock.yaml` 时默认只报告 `node_modules` 不同步，不会自动跑 `pnpm install`；需显式传 `sync_deps: true`（CLI 用 `-SyncDeps`），且依赖同步失败不会回滚已还原的配置文件 — `lib/index.js:932-959 / CHANGELOG.md:33`
- 离线 CLI/GUI 工具主要面向 Windows PowerShell 5.1/7；macOS/Linux 上 host 部分可用，但一键桌面快捷方式与 GUI 窗口需手动改用本地终端 — `.github/workflows/ci.yml:7-9 / CHANGELOG.md:45`
- 跨机恢复时若目标快照引用了本机未装的插件，会出现 MODULE_NOT_FOUND 启动报错；插件会做预检提示但不会自动跳过缺失挂载 — `docs/migration.md:23-49 / lib/index.js:560-589`
- Windows 上 `fs.watch` 在被监听目录被删除/重命名时会异步抛 EPERM；插件已挂 error 处理器避免炸进程，但该 watcher 会被静默移除 — `lib/index.js:2093-2101`
- DSH 服务 API 调用逐项包 try/catch 降级（rc8 兼容盖子）：单个服务失败不会中断 apply，但对应能力会缺失 — `lib/index.js:1700-1714`

---

This document is auto-generated by [deepseek-plugin.org](https://deepseek-plugin.org). HTML page: [dsh-undo-plugin](https://deepseek-plugin.org/plugins/lire1131/dsh-undo-plugin)
Wiki generated by AI (model: `MiniMax-M3`)
