中文EN

dsh-tauri-turnrewind

gitnpmMIT

Git worktree 的 turn 级工作区撤销:每个 turn 建私有快照,/undo 先出红绿 diff 预览卡、卡内确认;turn 之后被改过的文件拒绝用冲突 diff 覆盖,只有显式 --force 或 --skip-conflicts 才继续;不写用户仓库的 HEAD、index、stash 与提交历史。

下载量 / Downloads
712

安装

dsh plugin --profile web add dsh-tauri-turnrewind

沙箱测试

这个插件还没测过。提交测试 →

README

dsh-tauri-turnrewind

本地开发中的 DSH turn 回滚插件(TypeScript 重写版,位于 packages/,遵循 workspace 插件规范;旧 JS 版已移除)。

分发(2026-09-06 起):插件已随桌面构建打包——列入 dsh-tauri-bundle 依赖(构建期部署进 src-tauri/resources/node_modules/)与 src-tauri/resources/internal-plugins.json 预装清单,下载桌面版即装即用,无需任何手动配置。定位仍是实验功能:恢复路径直接使用 Node/Git,尚未接入受控的宿主 sandbox/Tauri bridge,请在可丢弃的工作区先行试用。
Git 目录模式(当前形态):工作区必须位于 Git worktree(OpenCode 风格)。非 Git 目录显式禁用——turn 记为 skipped(TURNREWIND_GIT_REQUIRED),/undo 说明原因,不再为普通目录建快照。ignore 规则(.gitignore / .git/info/exclude / global excludes / .gitattributes)委托给源仓库;私有 snapshot repo 通过 alternates 借用源对象。设计与进度见 docs/TURN_REWIND_GIT_DIR_PROGRESS.md。

当前状态

这是 Host MVP 原型,当前实现:

  • 为已领取的 Agent turn 建立私有 Git 快照;
  • 将快照映射记录到 $DSH_HOME/ledger.sqlite;
  • git 子进程模型:快照、diff、恢复走异步 spawn,不阻塞 Host 事件循环;同一会话的捕获/结算按 FIFO 串行;收到 turn 输入后,before snapshot 通过 agent/pre-step barrier 完成后才允许模型和工具执行;同一 workspace 被其他 session 占用时,新 turn 会正常运行但记为 skipped,避免共享 snapshot 链互相污染。同步开销已收敛:工作区解析合并为单次 rev-parse 子进程并带 60s 缓存(过期后先回缓存值、后台异步刷新),冲突检测的文件读取(上限 64MB)已改异步;
  • git 可用性探测:系统没有 git 时,turn 显式记为 skipped(原因 TURNREWIND_GIT_UNAVAILABLE),而不是静默失败;
  • 快照链自愈:私有快照仓库被删/损坏后,下一次捕获自动降级重建基线(日志有一条 warning),后续 turn 照常可撤销;被清空前留下来的旧 turn 会在 /undo 选目标时自动识别为死快照并标记跳过(snapshot ref missing),不会甩出 git 原始报错;
  • alternates 失效自愈:私有 repo 通过 alternates 借用源仓库对象,而源仓库 git gc --prune=now(amend/rebase 的日常残留)可能删掉被借用且不可达的对象;每次 capture 后做连通性检查(git rev-list --objects --missing=print),发现缺对象即降级为自包含存储(不再借用、不再复制源 index)并重建基线,旧 turn 走死快照跳过路径;
  • 工作区资格守卫(Git 目录模式):会话 cwd 必须位于 Git worktree(子目录自动归并到 worktree 根,共享同一快照域);家目录、家目录祖先、盘根等系统目录直接拒绝;非 Git 目录记为 TURNREWIND_GIT_REQUIRED,不再做全目录预算扫描(见「工作区资格」);
  • 不可用弹窗:客户端半(src/client/)通过 turnrewind 会话投影检测到不可用提示时,在 Web UI 内弹出模态对话框(中英双语、跟随应用主题)。单会话只报一次:提示以会话内消息形式永久留档可查,弹窗只对页面存活期间新到达的提示触发,历史提示(重启后重新进入会话)不会重复弹窗;
  • 两阶段 /undo:先出预览卡(红绿 diff + +x -y 徽标 + 文件清单),卡内 ✓/✗ 按钮确认执行或取消——不看预览就不会误执行;计划 5 分钟过期。过期与取消都只锁执行、不抹账本记录:过期的 plan 卡片保留文件清单与 diff 供随时回看(归档视图);取消的 plan 是用户主动放弃,卡片塌缩为一行「已取消」留痕。确认时二次校验磁盘与预览绑定;
  • 恢复前比较当前文件与 turn 完成时的快照,发现变化则拒绝覆盖,并给出「turn 产物 → 当前磁盘」的冲突 diff;
  • 冲突可用 --skip-conflicts(只恢复无冲突文件)或 --force(强制覆盖)直接执行;
  • /undo --redo(重做最近一次已应用的 undo)已禁用:入口在解析层直接拒绝,底层恢复路径加固代码保留但未开放(见「已禁用:redo」);
  • 注册人类命令 /undo;
  • /undo 默认处理当前会话最新的单个可恢复 turn,也可指定完整 turn ID;
  • 同一 workspace 的活动 turn 或 undo 操作互斥;
  • 插件重启时将未完成 turn 标记为 abandoned;未完成的 Undo 与 Redo operation 会标记为 needs-recovery,对应 workspace 在清理前拒绝新的 rewind 操作,避免未知磁盘状态被继续覆盖。恢复面板:不可用弹窗在 reason 命中恢复围栏时提供「打开恢复面板」入口,可查看被围 workspace 的中断操作明细,并选择「已检查,保留历史并解锁」(operation 转 recovery-acknowledged 终态)或「清除 rewind 数据并解锁」(等价 purge);
  • /undo --doctor:只读诊断——git 可用性、工作区资格、账本规模与围栏、快照仓库健康(refs / alternates)、最近 turn 状态、备份新旧;
  • 账本打开时执行 PRAGMA quick_check(损坏显式拒绝加载,TURNREWIND_LEDGER_CORRUPT),并每日滚动备份到 ledger.sqlite.bak(VACUUM INTO 一致性快照),损坏时可按「还原 .bak → 重启」恢复;
  • 每次 Undo 的回退提示独立持久化;下一次模型 step 一次性注入全部 pending notice;
  • 不修改用户项目的 HEAD、分支、index、stash 或提交历史。

使用方法

在已加载本插件的 DSH 会话中:

/undo

默认进入两阶段流程:先输出预览卡(每个文件的红绿 diff 与 +x -y 徽标),

卡内附两个按钮——✓ 执行撤销 与 ✕ 取消。点 ✓ 才会真正恢复文件;

不点击的话计划 5 分钟后自动过期,不会误执行。确认时还会二次校验磁盘,

预览之后文件又被改动过(冲突)会拒绝执行并提示重新预览。

也可以指定完整 turn ID、或只看计划不动手:

/undo <session-id>:<turn-number>
/undo --dry-run      # 仅输出文件清单与分类,不含 diff
/undo --preview      # 输出内容与 /undo 的预览卡一致

磁盘在预览后又被改动(冲突)时,可以选择处理策略:

/undo --skip-conflicts   # 只恢复无冲突文件,跳过的文件会列出
/undo --force            # 强制覆盖冲突文件(执行前仍有回滚点保护)

其他:

/undo --cancel <plan-id>    # 取消一个待确认的预览计划
/undo --doctor              # 只读诊断报告(不能与其他选项组合)

当前不支持 / 已禁用:

/undo --redo     # 已禁用(功能冻结),入口直接拒绝
/undo --subtree  # 未实现

父对话递归撤销、消息旁 Undo 按钮和设置页模式切换尚未实现。

工作区资格(Git-only)

曾有用户在 QQ 机器人会话(默认工作目录是家目录、约 250 GB 内容)上触发 git add --all 级别的灾难,早期版本因此引入了全目录预算扫描。当前实现以源仓库的 Git worktree 为快照边界:非 Git 目录禁用(不再做预算扫描,也不再为普通目录建快照)。turn 开始前的资格检查:

1. 系统目录直接拒绝:家目录本身、家目录的祖先目录(如 C:\Users、C:\)、以及任何盘符根目录。这类目录无论多小都不做快照。

2. 必须是 Git worktree:会话 cwd 不在 Git worktree 内的 turn 记为 skipped(原因 TURNREWIND_GIT_REQUIRED)。子目录会话自动归并到 worktree 根(git rev-parse --show-toplevel),共享同一快照域;同一仓库的 linked worktree 各自成域。

3. 快照范围委托给源仓库 ignore 规则:.gitignore、.git/info/exclude(每次 capture 重同步)、global excludes 与 .gitattributes 语义与源仓库一致;插件自身只额外排除 .git 元数据与 turnrewind 临时文件。不再有自定义敏感文件名单——未写进 ignore 的文件(含 .env、密钥类文件)会被快照;这是有意的取舍:token.ts、credentials.module.ts 等合法源码曾被旧规则静默排除,导致 undo 永远无法恢复它们。若不希望某些文件进入快照,请把它们加进源仓库的 ignore 规则。

被拒绝的 turn 仍正常执行,只是不提供 undo。同时该会话会收到一条一次性提示([Turn rewind unavailable]),说明工作区被拒绝的原因;每个会话只提示一次,后续 turn 不再重复打扰。提示会以两种形态呈现:

1. 会话内消息:插件来源的上下文注入消息,模型和用户都可见、可审计;

2. Web UI 弹窗:宿主端 turnrewind 会话投影(src/host/service/dialog-projection.ts)把提示折叠进会话列表快照,客户端半(src/client/register/dialog.ts)从 sessions.list 的 projectionValues.turnrewind 读到后弹出模态对话框。去重不在浏览器存储里做(localStorage 会因换端口/清存储丢「已读」):按「单会话一次」种子逻辑,进入会话时已存在的提示视为历史留档(会话内消息永久可见)不弹,只有页面存活期间新到达的提示弹一次。

  • 敏感文件提醒:会话首次追踪一个工作区时做一次浅层启发式扫描(根 + 两层、上限 500 文件、跳过 node_modules),命中 .env/密钥类且未被 ignore 的文件时发一条一次性 [Turn rewind privacy notice](每会话+工作区一条),列出会被快照的具体文件与退出方式(加 ignore)。扫描失败静默跳过——这是提醒,不是门禁。

大工作区的取舍:不再做预算预扫描,快照耗时与磁盘占用随仓库规模增长(Git ignore 能排除 node_modules 等,但容量/性能风险仍由使用者自行承担);单文件快照/恢复上限为 64 MB——超限文件仍会被捕获进快照,/undo 预览会以 [too large] 标注并在执行后单文件报告为「未恢复」,不会导致整次 undo 失败,其余文件照常恢复。若项目里有此类大文件且不希望被追踪,请把它们加进源仓库的 ignore 规则。

清理已膨胀的快照数据

如果某个工作区在旧版本下已经生成过巨大快照,先停止 DSH Host 进程,再执行:

node packages\dsh-tauri-turnrewind-ts\purge-workspace.mjs "C:\Users\<user>\Desktop\test"          # release 数据目录 ~/.dsh
node packages\dsh-tauri-turnrewind-ts\purge-workspace.mjs "C:\Users\<user>\Desktop\test" --home "$env:USERPROFILE\.dsh.dev"  # debug

(需先 pnpm --filter dsh-tauri-turnrewind build 产出 dist/——CLI 从构建产物导入引擎。)

该命令删除该工作区对应的私有快照仓库($DSH_HOME/snapshots/<hash>.git)及其全部账本记录(turns / operations / notices / plans / workspaces),其他工作区的数据不受影响。workspace 被运行中的 Host 占用时命令会拒绝执行(workspace lock),请先停止对应 Host 进程。

注意:这个 CLI 只在两种场景需要——①账本损坏前的彻

…(truncated)

以上内容来自 npm 上的 README,我们只做格式化,不改内容。

版本

npm 上共发布:2,最后更新 2026-09-08

链接

GitHub · Homepage · npm

同类插件