把智能体本轮改过的文件一键还原到改动前
29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/9 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add ruaibeite/dsh-undo该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
是什么
dsh 原生插件 · chat
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 24 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件
查看扫描证据(共 8 处,展示前 8 条)
- 读取本地文件lib/index.js:112
const parsed = JSON.parse(readFileSync(join(root, 'index.json'), 'utf8')); - 写入本地文件lib/index.js:122
writeFileSync(join(root, 'index.json'), JSON.stringify(entries, null, 2)); - 写入本地文件lib/index.js:131
appendFileSync(join(root, 'debug.log'), `${new Date().toISOString()} ${line}\n`); - 写入本地文件lib/index.js:302
mkdirSync(filesDir, { recursive: true }); - 写入本地文件lib/index.js:394
writeFileSync(file, existed ? content : ''); - 删除本地文件lib/index.js:427
unlinkSync(dropped.file); - 读取本地文件lib/index.js:732
content = readFileSync(entry.file, 'utf8'); - 删除本地文件lib/index.js:779
unlinkSync(entry.path);
扫描于 2026/10/31(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-fs@deepseek-ai/dsh-tools@deepseek-ai/schemastery给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 一键还原本轮改动文件
- 写入编辑前自动快照
- 模型调用工具回滚
DeepSeek Harness 的回合级文件撤销:每次写入和编辑落地前都会快照,模型可调用撤销工具回滚某一轮对话改动的所有文件。
README
由 DeepSeek 最新模型翻译生成dsh-undo — 按轮次回退智能体对文件的修改
给 DeepSeek Harness 加一个文件回滚能力:每次写入或编辑落盘之前先把原内容快照下来,模型可以调用 undo 工具把一整轮对话改动过的所有文件一次退回 —— 不是只能退单个文件。
定位:它和「对话回退」类插件不是一回事
| | 本插件 | 对话回退类(如 dsh-rewind-plugin、dsh-recall-plugin) |
| 回滚对象 | 文件(本轮改动过的全部文件) | 对话上下文 + 文件 |
| 谁来触发 | 模型自己调 undo 工具,人也可以直接敲 /undo | 人在界面上点按钮 / 敲命令 |
| 运行环境 | host 侧插件,headless、无 Web UI 的 profile 同样可用 | 主要在 Web GUI 里用 |
| 依赖 | 无(不依赖 git) | 多数依赖 git 或会话 fork 机制 |
| 沙箱 | 不 fork shell:快照在进程内写,workspace-write 会话下无需额外放宽权限 | 取决于实现:经 shell 往工作区之外的存储写入时,会被会话沙箱拒掉 |
需要「把对话切回某条消息之前」请用上面那两个插件;本插件只做文件层,且刻意保持轻量。
展开完整文档(README 剩余 1 节)
dsh-undo — 按轮次回退智能体对文件的修改
给 DeepSeek Harness 加一个文件回滚能力:每次写入或编辑落盘之前先把原内容快照下来,模型可以调用 undo 工具把一整轮对话改动过的所有文件一次退回 —— 不是只能退单个文件。
定位:它和「对话回退」类插件不是一回事
| | 本插件 | 对话回退类(如 dsh-rewind-plugin、dsh-recall-plugin) |
| 回滚对象 | 文件(本轮改动过的全部文件) | 对话上下文 + 文件 |
| 谁来触发 | 模型自己调 undo 工具,人也可以直接敲 /undo | 人在界面上点按钮 / 敲命令 |
| 运行环境 | host 侧插件,headless、无 Web UI 的 profile 同样可用 | 主要在 Web GUI 里用 |
| 依赖 | 无(不依赖 git) | 多数依赖 git 或会话 fork 机制 |
| 沙箱 | 不 fork shell:快照在进程内写,workspace-write 会话下无需额外放宽权限 | 取决于实现:经 shell 往工作区之外的存储写入时,会被会话沙箱拒掉 |
需要「把对话切回某条消息之前」请用上面那两个插件;本插件只做文件层,且刻意保持轻量。
沙箱表现:为什么它在受限会话里照样能记录
它的快照与索引是用 Node 的 fs 在进程内写的,不 fork shell、不调用 ctx.shell ——所以在 workspace-write 这类受限会话里不需要任何权限放宽就能持续记录。这一点在真实环境里验证过:同一台机器上,靠 shell 调 git、把仓库放在工作区之外的实现,其 git add 在 workspace-write 下会因写工作区之外而失败(影子仓库对象数为 0);本插件在同样的会话里正常产出快照并带回轮次标记。
边界(便于评审核对,逐条对应代码):
- 快照与索引($DSH_HOME/undo/):fs.writeFileSync,进程内写入,不经过命令沙箱。
- 回滚既有文件:走 harness 的 ctx.fs.writeText,受文件策略约束(只读会话里会被拒 —— 这是期望行为)。
- 删除本轮新建的文件:harness 的文件系统服务没有删除接口,这一步用 fs.unlinkSync,因此不受沙箱策略约束(只读会话里同样会执行)。这是本插件唯一不经策略的写操作,回滚语义需要它:把「本轮新建」还原成「不存在」。
- 不读凭据、不发网络请求、不碰你的 git 仓库。
它怎么工作
两条互补的捕获路径,都只做旁路记录、不改变任何写入语义:
| 路径 | 位置 | 说明 |
| ① intent 钩子(主) | fs/write-intent / fs/edit-intent waterfall | DSH 的官方扩展点,能拿到 actor(callId、agent)等工具执行信息 |
| ② fs 服务包装(兜底) | writeText / editText 的实现原型 | 若 ① 因任何原因收不到事件,② 保证仍然有快照 |
三条经验性的结论,都已落在代码里(细节见 lib/index.js 注释):
1. intent 钩子必须 prepend: true。 cordis 的 waterfall 语义是「不调用 next() 的监听器会否决其后的整条链」,而 @deepseek-ai/dsh-fs-observation-policy 正是这样一个监听器(它直接决定 intent 并返回)。profile 补丁里的插件加载晚于内置插件,所以不 prepend 的话钩子永远轮不到执行 —— 实测跑完整个智能体会话,零事件到达。
2. 服务包装是必需的冗余。 真实链路是 SandboxedFileSystem → LocalFileSystem → FileSystem,而 ctx.fs 每次访问都返回 新的 traceable Proxy,所以包装 ctx.fs 上的方法没有意义,必须包装方法所属的原型。
3. 两条路径会同时命中同一次写入,因此有跨机制去重:同一路径 + 同一事件 + 250 ms 内、且来自不同机制时只记一条。同一机制内的连续两次写入不会被误合并。
轮次是怎么分出来的
工具执行上下文里只有 callId / rootCallId / agent,没有轮次号,所以轮次边界取自 会话日志中最近一条 user/message 事件的 seq(只扫描尾部 sessionScanEvents 条,并按 (session, seq) 缓存,代价有界)。读不到会话的写入(例如 fs 服务兜底路径)会归入「当前正在进行的轮次」,而不是自成一派。
提供的工具
模型可调用 undo:
| 参数 | 说明 |
| action | list = 按轮次列出快照;restore = 回滚 |
| id | 回滚单个快照(单文件精细回退);给出时优先于 turn |
| turn | 回滚哪一轮:last(默认)、从新到旧计数 1/2/…,或 list 显示的 turn 键 |
| limit | list 时返回多少轮,默认 10 |
| dryRun | restore 时只报告每个文件会变成什么,不写盘 |
人工入口:/undo 命令
模型不是唯一的使用者 —— 你也可以在输入框直接敲:
| 命令 | 作用 |
| /undo 或 /undo list | 列出最近的轮次(每轮最多 listFilesPerTurn 条,其余省略汇总) |
| /undo restore [轮次] | 回滚该轮;省略轮次 = 最近一轮,轮次用 list 里的序号(1 = 最新) |
| /undo dry [轮次] | 只预演:报告每个文件会变成什么,不写盘 |
| /undo id <快照id> | 只回滚单个快照(单文件精细回退) |
命令与工具共用同一套执行逻辑(命令只负责把输入解析成工具参数),所以两边行为不会漂移。
命令注册是机会式的:profile 里没有命令注册表时照常加载(只少一个人工入口), /undo 已被别的插件占用时自动改注册为 /undo-turn,而不会加载失败。
界面按钮:助手消息动作行里的 ↶
Web GUI 里还有一个按钮:已定稿助手消息的动作行(复制、分支旁边)会出现 ↶ 回退本轮。
点击即回退最近一轮;因为回退本身也会被快照,再点一次就能撤销这次回退(等效 redo)。
只想预览时用 /undo dry。
按钮不直接碰文件,而是执行宿主命令 /undo 1 —— 所以三条路径(模型工具、/undo 命令、界面按钮)共用同一套执行逻辑与同一份结果呈现,不存在「按钮和命令行为不一致」的可能。
实现要点(便于评审核对):
- 客户端半边是 client/client.js,由 package.json 的 dsh.client + exports["./client"] 声明;
它是手写的预构建入口(window.__ModuleLoader__.load({ id, factory }),React 与官方客户端包由宿主 require 提供),不需要打包步骤。
- 注册进 conversation.chat.assistant-actions(官方反馈条目用的同一插槽),order: 20 排在它之后。
- 通过插槽的按会话 inject 拿到绑定了 sessionId 的 runUndo,组件不需要自己解析会话。
回滚语义
- 一轮里同一文件被多次快照(改了两遍)→ 取最早那条,即该文件在本轮开始前的状态。
- 本轮期间新建的文件 → 回滚 = 删除它。
- 回滚动作本身也会被快照 → 回滚可以再撤销(等效 redo)。
- 单个文件失败不会中止整轮:报告里逐条列出成功/失败。
安装
从 GitHub 安装(推荐;package.json 里的 dsh.bundle 让 dsh 自动挂载)
dsh plugin --profile web add github:ruaibeite/dsh-undo
或本地克隆后用脚本(自动改用桌面版自带的 CLI) ./install.sh
PROFILE_NAME=headless ./install.sh
安装后重启 dsh 生效。
存储与配置
$DSH_HOME/undo/
├── index.json # 快照索引,每条含 id/time/path/existed/bytes/turn/sessionId └── files/<快照id> # 快照内容(逐字节)
$DSH_HOME 内部的写入会被排除(那是 harness 自身状态,不是工作区文件)。
cordis.patch.yml 里该条目可配:
| 键 | 默认 | 说明 |
| maxSnapshots | 300 | 保留快照条数上限,超出淘汰最旧的 |
| maxFileBytes | 4194304 | 超过此大小的文件不快照 |
| onlyToolWrites | false | true 时只快照带工具 actor 的写入 |
| sessionScanEvents | 400 | 为定位轮次边界而扫描的会话日志尾部条数 |
| listFilesPerTurn | 10 | action: "list" 每轮最多列出多少条文件,其余用一行省略汇总(list 带上 turn 则打印该轮全量清单) |
| debug | false | true 时把每个事件写入 $DSH_HOME/undo/debug.log |
限制(如实说明)
- 只回滚文件,不回滚对话。 对话层回退请用专门的插件。
- 只看得见经 ctx.fs 的写入。 通过 shell 等绕过 fs 直接落盘的改动不会产生快照;不过这些文件在被工具再次写入时,会以「当时已存在」的形态被快照。
- 超过 maxFileBytes 的单个文件不快照。
- 轮次分组依赖会话日志里存在 user/message 事件;取不到时退化为按工具调用分组。
- 快照只写 $DSH_HOME,不改工作区、不碰你的 git 仓库、无网络请求。
测试
npm install # 官方包从 npm 安装(devDependencies,0.2.0-rc.2 线)
npm test # 业务逻辑:mock fs/tools/agent,36 项断言
npm run test:integration # 真实 cordis 容器 + 真实 waterfall 分发 + 真实 Config 校验,15 项断言
两套测试都用隔离的 DSH_HOME(仓库内 .test-home / .cordis-test-home),跑完自动清理。
许可
MIT预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
ruaibeite/dsh-undo
把智能体本轮改过的文件一键还原到改动前
相关插件 · 对话 / 记忆
上下文中枢oceanbase/powercontext
上下文跟着工作走 —— 跨会话、跨智能体、跨人。
★ 1,462已汉化DSH
73
智能体记忆库plastic-labs/honcho
Honcho 是记忆基础设施,用来构建有状态的智能体。这些智能体能理解不断变化的人、智能体、群组、项目和想法。
★ 7,848已汉化DSH
71.7
长程智能体控制面loopx-project/loopx
给 Agent 一个目标,让工作持续向前。
★ 6,358已汉化DSH
71.3
智能体上下文数据库volcengine/OpenViking
给 AI 智能体用的上下文数据库
★ 41,246已汉化DSH
71.3
长效机器人团队Fei2411/DS-Bot
DS Bot 是一个基于 DeepSeek Harness简称 dsh的 bot 插件,插件将 dsh 改造为 bot…
★ 4,717已汉化DSH
71.1
可携带记忆层EverMind-AI/EverOS
为什么选择 EverOS
★ 13,711已汉化DSH
71.1