DeepSeek Harness 会话整理插件:可恢复删除与分叉编辑

前言

DeepSeek Harness(DSH)目前对会话的操作只有「归档」:归档只是把会话 id 记进 archivedSessionIds,日志目录原封不动。这就带来两个问题:一是真正的删除能力缺失,二是已经发出的请求无法修改。

tazewell/dsh-session-tidy 插件补上了这两点:把会话移入可恢复的 7 天回收站,以及通过 fork 分支的方式修改已经发送的请求。

插件简介

tazewell/dsh-session-tidy 是一个 DSH 工作流插件,提供两个核心能力:

  • 可恢复删除:删除会话时,文件移动到 ~/.dsh/session-trash/entries/<时间戳>-<会话 id>/,7 天内可恢复,过期后惰性清理。
  • 分叉编辑:在任意一条用户消息上点击铅笔图标,修改后 fork 一个分支会话,原会话根据选项移入回收站或保留。

安装

插件包名为 dsh-session-tidy,版本 1.0.0。

插件管理器(推荐):使用插件管理器的 install_bundle 指向包目录(或解压后的目录),或在插件市场里按包名安装。管理器会负责 profile 的 package.json、cordis.patch.yml 与依赖。

手动登记:在 ~/.dsh/profiles/<profile>/package.json 里添加:

"dependencies": { "dsh-session-tidy": "^1.0.0" },
"dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-session-tidy"] } }

然后在 profile 目录安装依赖并重启 DSH。

会话删除与恢复

侧边栏每个会话的悬浮操作区和「…」菜单各有一个删除入口。

  1. 点击删除 → 确认对话框显示会话标题。
  2. 确认后 Host 先停止该会话正在跑的任务(子代理、后台命令、定时提醒),再把它移入回收站,并清掉投影缓存。
  3. 侧边栏底部的垃圾桶按钮打开回收站,可以:
    - 恢复:文件回到原来的会话目录、重新挂回原工作区、解除归档;
    - 彻底删除:立即删掉回收站里的目录,不可恢复;
    - 清空回收站:删除全部记录(会二次确认)。

当前正在主视图打开的会话不能删除:对话框会提示先切换到其他会话。

存储位置与保留期

~/.dsh/session-trash/entries/<时间戳>-<会话 id>/
  meta.json      # id、标题、原工作区、删除时间、字节数
  session/       # 原来的会话目录

回收站保留 7 天,过期条目在下次打开回收站时惰性清理。

安全机制

  • 删除只发生在 ~/.dsh 内,路径会做目录逃逸校验。
  • 接口只接受本机回环调用、同源请求并带 x-dsh-plugin: session-tidy 头,杜绝任意网页或局域网客户端调用。

修改已经发送的请求

每条用户消息下面(时间、复制按钮那一行)都多了一个铅笔图标:鼠标移到那条消息上才会显现,点它就改这条请求——不必是最后一条。

  1. 点击某条消息的铅笔 → 对话框「修改这条请求」里就显示这条请求的原文,可以直接改。
  2. 确认后插件在该请求之前 fork 出一个分支会话,把改好的内容写进新会话的输入框草稿,并自动切过去。分支的历史正好停在「这条请求之前」,所以这条提问和它后面(以及它自己的半截回答)都不会带过去。
  3. 在分支里看过没问题就回车发送。

切点规则

切点取的是上一条已完成 turn 的结尾(turn/end 的 seq),不是「消息 seq − 1」:用户消息前面还有它自己那条 turn 的 turn/start、step/start,按 seq − 1 切会让宿主给这个空 turn 补一个「forked」结束,界面上就会多出一行没有内容的「已完成,用时 1 秒」。规则还会跳过这种空 turn(两条 turn-tail 相邻),所以之前编辑留下的空壳会在下一次编辑时一起丢掉。

原会话处理

对话框里有一个默认勾选的选项「把原会话移入回收站(7 天内可恢复)」:

  • 勾选(默认):分支沿用原会话的标题,原会话进回收站,侧边栏里看起来就是「同一个会话被改掉了」;想找回来随时去回收站恢复。
  • 取消勾选:原会话保留,分支标题加 (1) 后缀,两个会话并存,可以对照。

如果原会话移入回收站失败(比如文件一时被占用),分支照常保留并提示原因,不会因为回收失败把已建好的分支丢掉。

为什么 fork

DSH 目前没有「原地截断会话日志」的能力(只能归档、不能回退),fork 是唯一能「替换掉这条请求」又不丢历史的方式。

限制

  • 只能取回文本:附件、@ 引用的 chip 不会跟着过去(正文会保留)。
  • 会话正在跑的时候铅笔置灰(先停止,再编辑);没有可编辑文本(比如只发了图片)的消息不显示。
  • 改的是较早的消息时,那条消息之后的对话只存在于原会话里——所以默认把原会话放进回收站,取消勾选就能两边都留着。
  • 草稿是写给分支会话的,取消编辑不会污染当前会话的草稿。
  • 分支和原会话共享同一条前缀历史,所以上下文是连续的。

结构说明

  • index.js — Host 入口:解析 DSH home、注册 /plugin/session-tidy 前缀路由,删除前调用 workspaceRegistry.archiveSession(id, { stopActivity: true }),恢复后重新 attachSession 并 unarchiveSession。
  • lib/trash.js — 回收站存储:移动(跨盘回退到复制+删除)、meta、恢复、清理、过期。
  • lib/routes.js — HTTP 层:GET trash、POST delete|restore|purge|empty,含同源与请求头校验。
  • client.js — 浏览器侧:会话行删除按钮、菜单项、侧边栏底部回收站入口、每条用户消息的悬停铅笔(注入到官方气泡操作行)、确认框 / 回收站对话框 / Toast(全部使用 --dsw-alias-* 主题变量,跟随明暗主题)。
  • cordis.patch.yml — bundle patch,插入 session-tidy 这一行。

测试与验证

运行测试:

node --test "test/*.test.mjs"

38 个用例覆盖回收站存储、HTTP 路由(回环/同源校验、回滚、错误码)、Host 注册,Client 的插槽注册与词典完整性,以及消息铅笔的注入 / 禁用 / 取值、弹窗内直接编辑、空内容禁用确认、fork 切点(上一条 turn/end、跳过空 turn)、草稿写入(写入的是改后文本)、原会话入回收站与失败提示。

已安装到 desktop profile 并现场确认 /plugin/session-tidy/trash 返回 {"ok":true,"entries":[]},说明 Host 半已生效;浏览器内的最终视觉呈现需要在实际页面里确认。

适用场景

适合需要频繁清理会话、或者需要修改已发送请求的 DSH 用户。插件以当前 dsh 进程权限运行,安装前应检查源码与许可证(MIT)。

后续计划

  • 空会话 / 空分支批量清理
  • 分支血缘标记与「回到原会话」
  • 编辑时带上附件与 @ 引用
  • 批量清理面板(按工作区筛选、按大小排序、批量删除)
  • 导出会话、存储占用统计

目录

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye