SipengXie2024
dsh-rewind
Claude Code-style rewind for DeepSeek Harness (dsh): edit a past user message and re-run on a forked session, restore files to the turn boundary, or branch with a summary
- Stars
- 0
- Language
- TypeScript
- Created
- Aug 16, 2026
- Updated
- Aug 16, 2026
Introduction
dsh-rewind
把 Claude Code 的 rewind 能力移植到 DeepSeek Harness(dsh)的第三方插件:指着历史里任意一条用户消息,把对话、代码或两者一起回退到那个时刻,或从那里开一个摘要分支。
单包双半:host 半是一个薄 RPC 网关(rewind 命名空间)+ 一个 tools/execute 捕获中间件;client 半以键控槽覆盖(同 key user、priority -1)替换官方用户消息渲染器,加出回退菜单。fork、打开、重发全部复用官方 client sessions 服务,host 不新增会话操作。
菜单四项(对位 Claude Code 的 rewind 弹出菜单)
| 菜单项 | 行为 |
|---|---|
| 恢复对话(编辑重跑) | 气泡就地变编辑框,确认后 fork 到上一轮 turn/end 边界,打开子会话并重发改写后的消息 |
| 恢复对话与代码 | 同上,但 fork 前先展示文件回退卡片;确认时先把勾选文件写回边界前内容,再 fork 重跑 |
| 仅恢复代码 | 只做文件回退,不 fork 不发消息,留在当前会话 |
| 摘要至此,开新分支 | fork(含点击轮)→ 打开分支 → 自动执行 /compact 压缩头段历史 |
CC 菜单的第五项 "Summarize from here" 不做:dsh 的 compactNow 语义是压头段、保近尾,与「压点击处之后」方向相反;compactRegion 要求开轮空闲,菜单时点不可用。机制冲突,不硬凑。
菜单打开即探测文件变动数(0.3.2 起):打开菜单时并行调 previewRestore,两个代码恢复项的 label 实时显示「N 个文件有改动」;探测确认 0 变动时这两项置灰并注明「边界后无文件改动」。对位 CC 的设计——CC 在无 tracked file changes 时直接不显示两个代码恢复选项(官方 checkpointing 文档),不显示数量;这里改为显式计数 + 置灰,信息更多一层。Codex 无对位物:其 undo(ghost-commit)功能已移除(feature 表 Stage::Removed),看变动只有 /diff 现场跑 git diff。
文件快照与恢复(P1)
- 捕获:
tools/executewaterfall 中间件按工具名过滤write/edit/str_replace_editor(按名过滤天然覆盖 code preset 的 Code Mode 子调用,且恰好捕获一次)。write/edit 从结果 value 取 before/after;str_replace_editor 无结果 value,在派发前预读。 - 账本:storage-domain
rewind域(snapshots 表,key=callId)+$DSH_HOME/rewind/objects/内容寻址对象库(sha256 去重)。重启后从持久层 seed,内存降级模式下 GC 不跑(防误删)。 - 恢复:按边界后每个文件取最早改前快照写回(
ctx.fs.writeText,不经 tools waterfall,结构性不会自捕获)。当前磁盘指纹 ≠ 最后一次工具写入指纹的文件标「外部改动」,默认不勾。 - create 的文件只报告「需手动删除」,插件不删文件(
ctx.fs无删除动词;绕开它走 node:fs 会破坏远端 backend 抽象)。 - GC:
retentionDays(默认 14 天)过期行 + 孤儿对象,boot 后与每 24h 各扫一次。
配置(settings.yaml,热生效)
rewind:
captureEnabled: true # 关掉即停止捕获(已有快照不动)
retentionDays: 14 # 0 = 立即全部过期(下次扫描清空)
maxFileBytes: 10485760 # 超过此大小的改前内容不入库(标 lost)
边界声明(与 Claude Code 相同的边界)
- bash 及其他副作用工具不兜底:只捕获三个结构化写工具。模型经 bash 写的文件、跑掉的命令、外部系统副作用,rewind 一概不知情也不回退。
- 恢复写回不经审批门:
ctx.fs.writeText直写,不走 tools waterfall,因此不触发审批/沙箱升级弹窗。恢复是用户在确认卡片上显式发起的工作区全局操作,确认框即授权点。 - 带图消息重跑:读原附件转 base64 重发;读取失败降级为纯文本重发并提示。
- steering 消息不给回退按钮:fork 是轮粒度,轮中插话没有独立边界,不提供即最诚实的表达。
- 首条用户消息禁用回退(无上一轮边界可回)。
构建与安装
npm run check # tsc --noEmit + vitest(56 项)
npm run build # tsc + tsdown(client 半闭包工厂 CJS)
npm pack
dsh plugin --profile web add dsh-rewind-<version>.tgz # 每次安装必须 bump version(pnpm 同名同版本去重)
host 半迭代可用 dsh-hot-reload 的 /reload dsh-rewind 免重启;client 半刷新页面即新 bundle。
踩坑记录
- cordis 服务属性可见性:
ctx.fs这类服务属性只对inject声明过该服务的插件存在;ctx.get('fs')则绕过声明直查注册表。本插件 0.3.0 曾因漏声明inject: ['fs']导致捕获的 targetKey 全部走 fallback、恢复预览全报「无法读取」(0.3.1 修复)。