前言¶
在 DeepSeek Harness(DSH)里用 Web UI 让模型改代码时,常见情况是:某一轮改错了,你希望只撤回这一轮,或者把工作区恢复到更早某一轮结束时的样子,并且先看 diff 再决定是否写回磁盘。
DSH 自带的 @deepseek-ai/dsh-workspace-changes 会记录一轮里改了哪些文件并展示 diff,但快照放在 Session 的临时目录里,Session 或 Host 结束就没了,也没有回滚能力。dsh-checkpoints 在此基础上增加影子 git 仓库(重启后仍在)和可按文件勾选、带预览的回滚,行为上接近 Cursor 的检查点体验。
下面介绍这个由 tower666 维护、归类为工作流的 bundle 插件如何安装、能做什么,以及使用时需要注意的安全边界。
这是什么¶
dsh-checkpoints(npm 包名同名,当前资料中的版本为 1.1.0,MIT 许可证)是面向 DSH Web 平台的 bundle:安装后会写入 profile,Host 重启后加载。
它在 Harness 主目录下维护与真实工作区隔离的 shadow git 仓库,在每一轮对话的 turn/start 与 turn/end 各拍一次快照,并把该轮变更文件列表记入目录旁的 catalog;Web 页在每个已完成轮次下展示一行操作入口,同时暴露 /api/checkpoints.* 接口,并把同等能力以 workspace_checkpoint 工具交给模型(写盘前走 DSH 审批)。
与 workspace-changes 的差别¶
| 能力 | dsh-workspace-changes(官方插件) | dsh-checkpoints |
|---|---|---|
| 记录每轮 diff | 有 | 有(并持久化) |
| 快照存放 | Session 临时目录 | $DSH_HOME/workspace-checkpoints |
| 重启后保留 | 否 | 是 |
| 回滚 / 撤销 | 无 | 有,支持预览与按文件勾选 |
升级 bundle 时 README 写明尚无自动升级路径:需先移除再安装新版本;但 $DSH_HOME/workspace-checkpoints 下的检查点在移除与重装后仍会保留,对话侧历史可继续用。
核心功能¶
快照与目录¶
- 在
turn/start、turn/end把工作区快照写入 shadow 仓库,并把该轮变更文件列表写入 catalog。 - 默认存储目录为
$DSH_HOME/workspace-checkpoints(可通过 mount 配置storeDir覆盖)。
Web UI 上每个轮次一行¶
最新一轮与更早轮次提供的动作不同:
最新一轮 ⟲ N files changed in this turn [Undo this turn's changes…]
更早轮次 ⟲ N files changed in this turn [Revert to this turn…]
| 轮次位置 | 动作 | 基线 | 文件列表 |
|---|---|---|---|
| 最新 | Undo this turn’s changes | 本轮开始时的内容 | 仅本轮改过的文件 |
| 更早 | Revert to this turn | 该轮结束时的工作区 | 该轮结束与当前之间所有有差异的路径 |
说明:历史轮次行不提供「只撤销某一轮、却保留其后各轮改动」;在历史位置上的语义是「回到这里」。最新轮没有「之后的轮次」,因此只提供撤销本轮。
对话框会列出文件与行数、按需加载 unified diff 预览、支持全选/全不选,只写勾选中的文件。基线中不存在的路径会标为将删除;超过大小限制的快照标为不可回滚(not revertable)。应用后还可撤销本次回滚本身。
两类回滚语义¶
- Undo this turn’s changes:把本轮动过的文件恢复为本轮开始时的内容;本轮未碰的文件不动。
- Revert to this turn:让整个工作区等同该轮结束时的状态;保留该轮及之前的改动,丢弃之后所有轮的改动。最新轮不显示此项。
执行写盘前,当前将被覆盖的状态会先被快照,因此上述操作本身也可以再 undo。
HTTP API¶
路由挂在 ctx.connection.fetch 下、位于 /api 内,受 Connection 鉴权,返回 no-cache JSON:
| 路由 | 方法 | 用途 |
|---|---|---|
/api/checkpoints.turns?sessionId= |
GET | 某 Session 的全部已记录轮次 |
/api/checkpoints.plan |
POST | 生成回滚预览(body:{sessionId, turn, side?, paths?};side: 'start' 默认表示撤销该轮自身改动,side: 'end' 表示回到该轮结束态) |
/api/checkpoints.diff?planId=&path= |
GET | 某预览 plan 下单文件的 unified diff |
/api/checkpoints.restore |
POST | 应用预览({planId}) |
/api/checkpoints.undo |
POST | 撤销已应用的回滚({undoId}) |
回滚分两阶段:plan 只读;返回的 planId 一次性有效,并在 planTtlMs(默认 600000 ms)后过期。若在预览打开期间任一计划内文件被改动,restore 会拒绝。路径相对录制的工作区根解析,绝对路径或越界路径会被拒绝。
模型工具¶
对外暴露 workspace_checkpoint 工具,写操作经 ctx.approval.request(),由 Session 审批策略决定;'unavailable' 时失败关闭。审批服务要求处于 open turn,Web 侧则由对话框完成预览与确认。
安装与启用¶
该包是 bundle:安装即选中 profile,正在运行的 Host 需重启一次后才会加载。
从 npm(推荐)¶
dsh plugin --profile web add dsh-checkpoints
也可在 Web UI 的 Plugins → Add 填入包名,或通过 Creator 预设里 plugin_manager 的 install_bundle,target 填 dsh-checkpoints。npm 包页:https://www.npmjs.com/package/dsh-checkpoints。
从 git 指定版本¶
dsh plugin --profile web add git+https://github.com/tower666/dsh-checkpoints.git#v1.1.0
将上述 spec 作为 install_bundle 的 target 亦可;需要不可变来源时可用 commit SHA 替代 tag。
从本地目录¶
install_bundle 的 target 指向本仓库绝对路径。
运行环境¶
package.json 要求 dsh 引擎 ^0.2.1-rc.3、node >=20。
配置(Mount)¶
在 profile 中挂载示例:
- name: 'dsh-checkpoints'
config:
maxFileBytes: 2097152
| 字段 | 默认值 | 含义 |
|---|---|---|
storeDir |
$DSH_HOME/workspace-checkpoints |
shadow 仓库与 catalog 目录 |
timeoutMs |
30000 |
单次 git 命令超时(毫秒) |
outputMaxBytes |
8388608 |
单次 git 输出保留上限(字节) |
maxFileBytes |
2097152 |
回滚写盘与 diff 的单文件快照上限;更大则 unsupported: oversized |
maxDiffBytes |
524288 |
单次预览 unified diff 文本上限 |
maxTurnsPerSession |
300 |
每 Session catalog 保留轮次上限,超出则丢弃最旧 |
planTtlMs |
600000 |
未应用的预览 plan 有效时长 |
bundle 刻意未声明 Config schema:从工作区目录安装时无法依赖 Host 自带的 schema 库,非法配置会回落到上表默认值而非阻止激活。
安全模型(使用前宜知晓)¶
- 不写入用户仓库:快照命令的
GIT_DIR指向 shadow 仓库;用户.git仅通过只读GIT_ALTERNATE_OBJECT_DIRECTORIES挂接对象库。集成测试对宿主.git树做前后哈希比对。 - 使用空的
GIT_CONFIG_GLOBAL,并设置core.autocrlf=false、core.safecrlf=false,避免全局 git 配置改变字节级一致性。 - 工作目录即使不在任何 git 仓库内,仍可建检查点;shadow 仓库自包含。
- 大于
maxFileBytes的 blob 会列出但不参与写回。
插件以当前 DSH 进程权限运行;安装前请自行审阅源码与许可证(MIT),并在生产工作区先小范围试用回滚流程。
存储布局(简要)¶
$DSH_HOME/workspace-checkpoints/
catalog.json # session → turn → {beforeTree, afterTree, files}
empty-gitconfig
repos/<sha1(workspace)>/ # 每个工作区一个 shadow 仓库
.git/
index
...
适用场景¶
- 在 DSH Web 上长对话改代码,需要跨 Host 重启仍能查看历史轮次变更并回滚。
- 希望先预览 diff、再按文件勾选写盘,而不是整目录盲目还原。
- 需要把检查点能力以 API 或
workspace_checkpoint工具纳入自动化,并接受 DSH 审批门禁。
不宜期待:在不回到某一历史结束态的前提下,单独「摘掉」中间某一旧轮而保留其后改动——当前 UI 行动作不支持这种语义。
结尾¶
dsh-checkpoints 用持久 shadow git 与 catalog,补上了 DSH 原生 workspace-changes 在生命周期与回滚上的缺口;配合预览、plan/restore 两阶段与对用户仓库的只读隔离,适合把 Web 对话当成可撤销的多轮编辑会话来用。