DeepSeek Harness Hub
← 返回列表

会话回退插件JJXjustin/dsh-session-rewind

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
未验证

把会话与文件回退到任意版本点,失败自动回滚

尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/5 · 已提供中文文档

DSH 会话与文件回退插件(影子 git 仓库)

综合分
29.6
GitHub 分
29.6
用户评分
★ Stars
1
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add JJXjustin/dsh-session-rewind
该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/16(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

dsh-session-rewind

DSH 会话回退插件:给会话事件日志打「版本点」,可把会话回退到任意版本点(归档原日志 → 重建日志文件 → 刷新投影缓存),并可选 git 锚点实现文件级回退。

- 纯 host + client 插件,不改动 DSH 官方源码文件
- 版本点不写入会话日志本身(不污染 append-only 日志),存于 /.dsh-rewind// 独立目录
- 回退前强制确认(两阶段工具),回退失败自动全量回滚,绝不留下半截状态
- 文件快照采用影子仓库:.git 放在 .dsh-rewind/shadow-repos/,绝不侵入用户项目目录(不 git init、不写 .gitignore);快照范围受 pathspec 白名单约束(默认排除 .git/node_modules/.dsh-rewind/.agent-teams/_rollback/日志等,可配置)

前置要求

- DeepSeek Harness(DSH)≥ 0.1.2-rc.1(插件在 0.1.2-rc.1 开发与验证;兼容依赖新版 Session API,旧版 DSH
- Git for macOS:
- 官方镜像:(国内更快)
- 安装时确保 git 在 PATH 中(git --version 能输出即成功)

安装

1. 获取插件

从 GitHub 克隆本仓库到你的机器(任选其一):

HTTPS(推荐,需要先配置 git)
git clone https://github.com/JJXjustin/dsh-session-rewind.git

或 SSH(配置了 SSH key 后)
git clone git@github.com:JJXjustin/dsh-session-rewind.git

克隆后进入目录:cd dsh-session-rewind

2. 装配到 DSH

插件通过 DSH 的 profile 装配(link 目录方式,免 build)。在你的 DSH profile 目录(~/.dsh/profiles/web):

macOS / Linux
cd ~/.dsh/profiles/web
pnpm add -w link:/你克隆到的绝对路径/dsh-session-rewind

Windows
cd C:\Users\\.dsh\profiles\web
pnpm add -w link:C:/你克隆到的绝对路径/dsh-session-rewind

确认 package.json 的 dsh.profile.bundles 数组包含 dsh-session-rewind。

说明:dsh-session-rewind 是纯 JS 插件(lib/.js 手写、无 build 步骤),无需 npm install/build,link 装配后刷新页面即可生效。若改了 package.json 的 dsh.client 声明、或 client bundle 生效异常,重启 DSH 让 client-modules 重新扫描。

3. 卸载

删掉 package.json 里的 dependencies + bundles 两处引用 + node_modules\dsh-session-rewind junction 即可。

配置(可选)

~/.dsh/dsh-session-rewind.json:

{
"autoCheckpoint": false,
"autoCheckpointPerTurn": true,
"checkpointOnTool": false,
"autoEveryNTurns": 0,
"gitAnchor": true,
"shadowDir": null,
"rewindPaths": null,
"rewindExclude": null
}

| 字段 | 默认 | 说明 |
|---|---|---|
| autoCheckpoint | false | agent/pre-step(每步/模型请求前)打点,默认关——打点统一为「每轮一次」 |
| autoCheckpointPerTurn | true | 每轮对话结束打 1 个版本点(唯一的默认打点来源;autoEveryNTurns>0 时改按 N 轮取模) |
| checkpointOnTool | false | 每个顶层工具调用前打一版(标签「工具:」),显式开启才生效(旧名 checkpointOnTools: true 仍兼容) |
| autoEveryNTurns | 0 | 每 N 轮打点(0 = 用 autoCheckpointPerTurn 的每轮语义) |
| gitAnchor | true | 文件快照默认开:每个检查点同时在影子仓库建 git 提交(commit message = dsh-rewind::),还原时把工作区受管范围完整恢复到该快照 |
| shadowDir | null | 影子仓库根目录(显式指定则不用 rewindDir/shadow-repos);默认 /.dsh-rewind/shadow-repos/ |
| rewindPaths | null | 快照白名单(数组),默认整个工作区;配置后只快照这些路径 |
| rewindExclude | null | 额外排除路径(追加到内置排除 .git/node_modules/.dsh-rewind/.agent-teams/_rollback/日志等之后) |

聊天 UI(client 端)

输入卡片上方有一个常驻的 「🕐 还原检查点」 入口(注册在 conversation.input.dock 插槽,与待办/队列/goal 行并存):

1. 点击展开版本点列表(时间 / 标签 / seq / 轮数 / git 快照标志)——只显示当前轮次以前的轮次(当前轮内的检查点在轮次结束后才会出现);面板打开期间每 4 秒自动轮询刷新,新版本点无需刷新页面即可看到
2. 点某一版本点 → 预览将丢弃什么(N 条事件 / M 轮 / K 个工具调用 + 文件恢复提示「文件将完整恢复到检查点快照(git xxx):已跟踪文件回退、未提交改动丢弃、未跟踪的新文件移入归档备份」)
3. 确认还原 → 会话日志 + 工作区文件一起回退:clean -fd + checkout -f  -- (影子仓库,reset 不支持 pathspec,故用组合拳)把受管范围恢复到检查点快照;快照后新增的已跟踪文件也一并移除(移到影子仓库 restore-backups/ 备份,不是硬删);成功显示摘要后页面自动重载;失败显示错误(归档保留可恢复)

撤销:回退后未发新消息时,面板顶部显示 「↩ 撤销回退」(两次点击确认)——会话日志从归档恢复 + 文件恢复到回退前状态(git reset --hard gitBefore + 未跟踪文件从备份移回),均无需重启。

⚠ 无文件快照的检查点:列表里标红「⚠ 无文件快照」的检查点是 git 快照机制启用之前打的旧点(或打点时 git 快照失败)——还原它们只回退会话、不会回退文件(当时没有拍过快照,技术上限无法补)。git 快照启用后打的所有检查点默认带 git xxx 绿色标记,还原即可同步回退文件。

数据经 host 侧 /api/rewind/{list,preview,confirm,undo,undoable,status}(loopback-only)流转,client 不直接读文件。UI 全部包在 React error boundary 内,崩溃只降级该入口,不影响对话面板。

关于「回退后继续对话」:回退 live 会话时会就地热重置内存副本(磁盘+内存+文件三者一致),无需重启即可继续;热重置失败才回落到冻结兜底。

位点说明:最初按 Cline 对齐选用 conversation.chat.turnTail(每轮末尾),但该 chain 已被 dsh-client-ui-deliverables/dsh-better-sidebar 的产出文件行占用(chain 只渲染一个 entry,有文件时必赢)——改为 conversation.input.dock(list 型,多 ID 共存,输入卡上方独立行)。

注意:client bundle 改动只需刷新页面即生效(bundle 从 /plugins/ 实时服务);若改 package.json 的 dsh.client 声明则需要重启 DSH 让 client-modules 重新扫描(包声明缓存不热更新)。

工具

| 工具 | 作用 |
|---|---|
| rewind_checkpoint { label?, withFiles? } | 手动打版本点;文件快照(影子仓库 git)默认随打点创建,需工作区有 git(影子仓库自动 init,不侵入项目) |
| rewind_list { sessionId? } | 列版本点与回退记录(时间/标签/seq/轮数/工具数/git 锚点) |
| session_rewind { sessionId?, checkpointId?, seq? } | 预览回退:展示将丢弃的事件/轮数/工具数统计并挂起待确认请求(不执行任何修改) |
| session_rewind_confirm | 确认并执行挂起的回退(磁盘截断 + live 会话热重置,可直接继续对话) |
| rewind_undo { sessionId? } | 撤销最近一次回退(仅当回退后未发新消息);从归档恢复 + 热重置 |
| rewind_restore { checkpointId?, commit? } | P1 文件级回退:clean -fd + checkout -f  --  到影子仓库锚点 |
| rewind_status | 插件状态:配置 / 冻结会话 / 挂起请求 |

回退流程(模型侧标准操作):

1. 调用 rewind_list 查看版本点 → 选定目标
2. 调用 session_rewind 获取预览(丢弃 N 条事件 / M 轮 / K 个工具调用)
3. 用 ask_user_question 向用户展示预览并请求确认;用户明确同意后才调用 session_rewind_confirm;拒绝则放弃(pending 10 分钟过期)

回退语义

- seq 是独占边界:回退到 seq V = 保留 events[0..V),V 及之后的事件被截断
- 只允许切在轮边界(不能截断在 turn 中间,与 DSH fork 同规则)
- 执行顺序:先归档原日志(~/.dsh/dsh-session-rewind/archive/-.jsonl,人读)→ 两步原子替换日志文件(zstd 保持 header 独立帧)→ 刷新投影缓存(coldSnapshot)→ 记录回退摘要
- 投影刷新失败 → 自动从归档全量回滚,日志恢复原状,不抛半截
- 归档文件与 checkpoints.json 里的 rewinds 记录构成可审计副本,原日志绝不静默删除

live 会话:热截断(无需重启)

回退正在运行的会话时,磁盘截断后同步热重置其内存副本(日志数组、surface 折叠、派生消息缓存、header/context 折叠、持久化写游标、投影单元)——与磁盘状态一致后直接继续对话,新事件 seq 从版本点连续追加,无需重启 DSH:

- 回退未在运行的会话 → 立即完全生效(UI/历史读取走磁盘)
- 回退正在运行的会话 → 磁盘截断 + 内存热重置,当场可继续对话
- 热重置任一步失败 → 自动回落旧的 frozen 兜底(agent/pre-step 拦截防 seq 冲突,重启后从磁盘恢复)——日志安全始终优先

撤销回退(rewind undo)

回退后只要还没发出新消息,可以一键撤销、完整恢复到回退前状态:

- 面板顶部出现 「↩ 撤销回退」(两次点击确认);或模型工具 rewind_undo
- 从归档恢复完整日志到磁盘 + 热重置内存(同样无需重启),并刷新投影缓存
- 回退后已产生新消息则拒绝撤销(会话已从回退点走出新轨迹,旧轨迹仍在归档永久保留)

数据目录

默认写入「会话自己的工作区」 /.dsh-rewind/(cwd = 会话 header.cwd;例如本机工作区为 D:\AI_WORK\DeepSeek Work):

/.dsh-rewind/
├── archive/                                  # 回退归档(原始 JSONL 文本)+ untracked/restore-backups 备份
│   ├── -.jsonl
│   └── untracked-/                 # 还原时移除的未跟踪文件(撤销可移回)
├── shadow-repos//               # 影子 git 仓库(文件快照,.git 不侵入项目)
│   ├── .git/                                  # 快照对象库 + commit(message=dsh-rewind::)
│   ├── exclude                                # 影子仓库自己的排除规则(core.excludesFile)
│   └── restore-backups//                  # 还原时移除的快照后新增跟踪文件(撤销可移回)
├── /                             # 每会话版本点簿
│   └── .json                     # { checkpoints: [...], rewinds: [...] }

- 不用 ~/.dsh(用户明确要求不落 C 盘);~/.dsh/dsh-session-rewind.json 的 rewindDir 可显式覆盖
- 无 cwd 的会话兜底 /.dsh-rewind(rewind_status 的 fallbackRootDir 展示)
- 工作区零侵入:用户在项目里看不到任何 .git/.gitignore,快照全部落在 .dsh-rewind/shadow-repos/ 下
- 历史遗留数据(早期版本写入 ~/.dsh-rewind / ~/.dsh/dsh-session-rewind)可用
node tools/migrate-data.mjs 合并进工作区(按 id/seq 去重、保留最新 200 点,幂等可重跑)

设计要点

- 工具注册走「永不 throw」双兜底(harness.defineTool/registerTool → ctx.tools.register → 降级不注册),任何失败不影响 DSH 启动
- 插件 inject: ['tools', 'webServer'];sessions / sessionPersistence / sessionProjectionCache 全部 ctx.get 可选获取,缺哪个功能降级到哪
- client bundle 为 window.__ModuleLoader__.load 格式(DSH client-modules 标准),不依赖 __DSH_MODULES__;package.json 的 dsh.client.inject 使用 better-sidebar 0.14.0 验证过的注入组合
- 日志重建不依赖 @deepseek-ai/ 运行时包(chunk-rows 展开/打包为自实现最小版本,写回采用不打包布局,官方读取路径布局无关),无 peer 依赖安装坑
- zstd 写回与官方一致:header 单独一帧 + 事件帧,checksum 开启

单元测试

cd C:\Users\asus\.dsh\plugin-src\dsh-session-rewind
node --test test/core.test.mjs

覆盖:chunk-rows 展开、seq 连续性校验、编码往返、轮边界校验、统计/标签、bookkeeping 去重、回退事务(截断+归档+记录)、边界失败零写入、投影失败全量回滚、zstd 分帧、恶意 session id 路径转义。

明确不做(Out of Scope)

- 前进/redo(回退即截断)
- 跨会话回退
- 修改 DSH 官方源码(dsh-* npm 包)
- UI 主题/皮肤

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群