DSH Plugins Marketplace

DSH Plugins

Plugins

/

dsh-undo

r

dsh-undo

Manifest valid

Turn-level file undo for DeepSeek Harness: every write and edit is snapshotted before it lands, and the model can call the undo tool to roll back all files a conversation turn changed.

UI (client)hasBundlePatch

dsh-undo — 按轮次回退 agent 对文件的修改

给 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 waterfallDSH 的官方扩展点,能拿到 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 的话钩子永远轮不到执行 —— 实测跑完整个 agent 会话,零事件到达。
  2. 服务包装是必需的冗余。 真实链路是 SandboxedFileSystem → LocalFileSystem → FileSystem,而 ctx.fs 每次访问都返回 新的 traceable Proxy,所以包装 ctx.fs 上的方法没有意义,必须包装方法所属的原型。
  3. 两条路径会同时命中同一次写入,因此有跨机制去重:同一路径 + 同一事件 + 250 ms 内、 且来自不同机制时只记一条。同一机制内的连续两次写入不会被误合并。

轮次是怎么分出来的

工具执行上下文里只有 callId / rootCallId / agent,没有轮次号,所以轮次边界取自 会话日志中最近一条 user/message 事件的 seq(只扫描尾部 sessionScanEvents 条, 并按 (session, seq) 缓存,代价有界)。读不到会话的写入(例如 fs 服务兜底路径)会归入 「当前正在进行的轮次」,而不是自成一派。

提供的工具

模型可调用 undo:

参数说明
actionlist = 按轮次列出快照;restore = 回滚
id回滚单个快照(单文件精细回退);给出时优先于 turn
turn回滚哪一轮:last(默认)、从新到旧计数 1/2/…,或 list 显示的 turn 键
limitlist 时返回多少轮,默认 10
dryRunrestore 时只报告每个文件会变成什么,不写盘

人工入口:/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 里该条目可配:

键默认说明
maxSnapshots300保留快照条数上限,超出淘汰最旧的
maxFileBytes4194304超过此大小的文件不快照
onlyToolWritesfalsetrue 时只快照带工具 actor 的写入
sessionScanEvents400为定位轮次边界而扫描的会话日志尾部条数
listFilesPerTurn10action: "list" 每轮最多列出多少条文件,其余用一行省略汇总(list 带上 turn 则打印该轮全量清单)
debugfalsetrue 时把每个事件写入 $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

Comments

Loading…

Similar plugins

dsh-undo

by LingLambda

Context undo/redo plugin for DeepSeek Harness (dsh): roll the model context back to the last completed step and restore it again.

Manifest valid

★ 4

↓ 133/wk

MIT

TypeScript

Aug 15, 2026

dsh plugin --profile web add dsh-undo

by zoyluoblue

dsh plugin: snapshot your workspace every turn and restore the files to any earlier point. A rewind/undo for DeepSeek Harness coding sessions — your own git repo is never touched.

Manifest valid

★ 0

MIT

TypeScript

Aug 19, 2026

dsh plugin --profile web add @zoytown/dsh-rewind

by DDDMUC

Edit any user turn in DeepSeek Harness and re-run it: an inline editor rolls the conversation back through the official surface-replace contract, then re-prompts the agent with the revised text. The append-only session log is never rewritten.

Development & InfrastructureTerminal & ClientsManifest valid

★ 4

↓ 904/wk

MIT

JavaScript

Oct 9, 2026

dsh plugin --profile web add dsh-edit-turn

by hu669293657

Adds deliverable-file buttons to the end of each agent turn (opens files with the OS default app) and a floating dot rail for jumping between conversation turns.

UI & ExperienceDevelopment & InfrastructureManifest valid

★ 0

MIT

JavaScript

Aug 29, 2026

dsh plugin --profile web add dsh-turn-tools

by sharedcare

Codex-style conversation rollback and edit-and-resend plugin for DeepSeek Harness (DSH) Web UI

Sessions & MessagesManifest valid

★ 0

MIT

JavaScript

Sep 11, 2026

dsh plugin --profile web add conversation-rollback

by XSJUSTC

DSH (DeepSeek Harness) conversation rewind plugin - rewind to any user message, interrupt a running turn, hide the tail from chat view and model context, cancel freely before sending.

UI & ExperienceManifest valid

★ 11

MIT

JavaScript

Sep 22, 2026

dsh plugin --profile web add @xsj/dsh-rewind