dsh-session-deleter:在 Web UI 中删除 Session 与单条消息

前言

在 DeepSeek Harness(DSH)里,Session 持久化插件 @deepseek-ai/dsh-session-persistence-jsonl 只提供 create、open、flush、stat、list,没有删除接口。界面可以归档 Session,却无法从侧边栏真正移除一条记录;Workspace 写入时才会顺带 prune id,subagent/catalog 又是只追加的,客户端也没有暴露 delete 的服务。磁盘上的 Session 目录和日志会长期堆积,而 Harness 本体并未提供对应的 Web 操作。

社区插件 dsh-session-deleter(维护者 ghgjkbf,分类:记忆)在不改 Harness 核心的前提下,补上「整 Session 删除」以及「单条消息级」的处理:默认进私有回收站,永久删除需二次确认;消息侧支持 shadow(line A)与 truncate(line B),均可撤销。下面介绍它的定位、能力与用法。

这是什么

dsh-session-deleter 是一个 DSH bundle 插件(npm 包名 dsh-session-deleter,当前版本 0.2.0,MIT 许可证,要求 Node >= 20)。它在 Harness 自带的 Web 服务器上挂载 /session-deleter 路由,并在 Web UI 的多个 slot 注册入口,让你从浏览器完成 Session 与消息的删除类操作,而不依赖 Harness 尚未提供的删除 API。

SkillHub 目录页:ghgjkbf/dsh-session-deleter。源码与说明:GitHub 仓库。SkillHub 是社区插件目录,与 DeepSeek / 幻方无官方从属关系;DSH 生态遵循「一切皆插件」,安装前请自行审阅源码与许可证。

核心功能

整 Session:回收站、恢复、永久删除

插件提供三种可从 UI 触达的操作(README 原文归纳):

  1. Delete a whole Session — 将整个 Session 目录(含各代日志)移动到回收站,可恢复。
  2. Restore — 把回收站中的目录移回原路径;若目标路径已被占用则拒绝覆盖。
  3. Delete permanently — 唯一不可撤销的步骤,也是唯一真正释放磁盘空间的步骤;需要第二次明确点击(或 API 传 confirm: true)。

设计原则:默认可逆。第一次删除请求不会直接删字节,在同一文件系统上通过 rename 进回收站,原子完成「破坏性工作」的实质步骤。

单条消息:Shadow 与 Truncate

除整 Session 外,插件还通过 HTTP 暴露消息级接口(见下文路由表):

  • Shadow(line A):只追加、完全可逆。用 developer/message tombstone 替换模型可见 fold 中的一个 surface 节点,机制与官方 compaction 类似。转录界面仍可能显示原行(按 surface 约定),但 tombstone 不会对 LLM 派生消息——即从模型上下文里去掉该条,不从屏幕上去掉。
  • Truncate(line B):通过重建「保留的 frame 对齐前缀」从 artifact 中移除事件,转录行一并消失;会保留 .bak- 备份以便字节级恢复。这是唯一会改写已有字节的消息操作。

安全与拒绝策略

插件会拒绝它无法安全完成的请求,例如:

  • 正在运行的 Session 日志仍被写入,不在其 writer 下删除。
  • 发起请求的 Session 不能删除自身。
  • Session id 作为路径段,形如路径遍历的 id 会在触盘前被拒绝。
  • 目录可同时存在 v3、v4 等多代日志,实现不硬编码文件名。

重写日志时,每个 durable batch 重发一个带校验的 Zstandard frame,.jsonl.zstd 是可独立解码 frame 的拼接,而非单一流,以保证后续 append 仍能被后端结构扫描识别。

界面入口

表面 Slot 位置说明
侧边栏底部(Settings 旁) sidebar.footer.action order: 20,始终可见,无需 hover
Session 选择对话框 shell.overlay 由底部入口打开
Session「…」菜单 sidebar.workspaces.session.menu.item order: 500,在 pin/rename/fork/archive 之后
确认对话框 shell.overlay 全框浮层
管理页 settings.section Settings 内 order: 50
管理页(同一内容) shell.overlay order: 5,插件内管理浮层

侧边栏底部入口是主入口:DSH 只在指针悬停于非当前 Session 行时才绘制「…」,从不 hover 的用户可能看不到菜单项里的插件能力。选择器会列出所有可删 Session;运行中或当前 Session 会显示但不可删。

删除与管理相关对话框先做 dry run:展示目录、大小、日志代数、影响范围与残留,再执行移动。

管理页同一组件渲染两处。Shell 的 Settings 面板没有可从客户端直接打开的 service;选择器里的「管理回收站」与对话框里的「打开管理页」会打开管理浮层(与 Settings 段相同内容)。仍会 best-effort 尝试 selectPanel("settings"),以便在注册了该 key 的构建上跳转到 Settings。

Host 路由

插件在 Harness Web 服务器路径前缀 /session-deleter 下提供服务:

方法 路径 用途
GET /health 生效中的根路径与当前 Session id
GET /inventory 所有已存 Session(字节、代数、标题)
GET /plan?sessionId=… 预演:后果、残留、阻塞因素
POST /delete {sessionId, force?} → 移入回收站
GET /trash 回收站条目、孤儿检测、大小
POST /restore {id} → 移回
POST /purge {id, confirm: true} → 删除字节
GET /ledger?limit= 只追加的操作日志
GET /messages?sessionId=… 消息列表及 live/shadowed 状态
POST /messages/shadow {sessionId, seq} → tombstone 单条(line A)
POST /messages/unshadow {sessionId, tombstoneSeq} → 撤销 shadow
POST /messages/truncate {sessionId, throughSeq} → 截断尾部(line B)
POST /messages/untruncate {sessionId, backupPath} → 从备份恢复

安装与启用

已抓取资料中的 README 未给出单独的 dsh plugin add … 一类 CLI 安装行;SkillHub 页面标注「可安装」,具体安装方式以你当前 DSH 版本的 bundle / 市场流程为准,并在安装前阅读仓库源码。

启用后,可选配置通过 bundle 行的 config 传入(摘自 README):

- insert:
    - id: session-deleter
      name: 'dsh-session-deleter'
      config:
        sessionRoot: 'D:/somewhere/sessions'
        trashRoot: 'D:/somewhere/trash'
        protectCurrentSession: true
        refuseLiveSessions: true

默认值:

  • sessionRoot:<DSH_HOME|~/.dsh>/sessions
  • trashRoot:<home>/session-trash/sessions

卸载时:移除 bundle 行与 npm 包即可;回收站中已持有的目录仍保留,可手工恢复——manifest.json 记录每条目的原路径。

磁盘状态

  • <home>/session-trash/sessions/ — 每次删除对应一个 held 目录,另有 manifest.json。
  • <home>/session-trash/ledger.jsonl — 每个操作阶段一行,只追加;读时若末尾行因崩溃 torn 则丢弃,不当作损坏。

典型用法

从 Web UI 删除 Session

  1. 在侧边栏底部(Settings 旁)打开 Session 选择器,或对非当前 Session 使用「…」菜单中的删除项。
  2. 在确认对话框中查看 dry run 计划(目录、大小、代数、影响与残留)。
  3. 确认后 Session 目录移入回收站;需要时在管理页或浮层中 Restore,或二次确认 永久删除 以释放空间。

运行中或当前 Session 不可删;若配置 protectCurrentSession / refuseLiveSessions 为 true(默认语义见上),与 README 中的保护策略一致。

通过 HTTP 预演与删除(示例)

在 Harness Web 服务已挂载插件的前提下,可先查清单再预演(路径相对于站点根下的 /session-deleter):

GET /session-deleter/inventory
GET /session-deleter/plan?sessionId=<你的 session id>
POST /session-deleter/delete
Content-Type: application/json

{"sessionId": "<你的 session id>"}

永久清除回收站中某条(不可恢复):

POST /session-deleter/purge
Content-Type: application/json

{"id": "<回收站条目 id>", "confirm": true}

消息级操作需先 GET /messages?sessionId=… 取得 seq,再按需调用 /messages/shadow 或 /messages/truncate;撤销分别用 /messages/unshadow 与 /messages/untruncate(truncate 需 backupPath)。

维护者验证脚本

仓库提供针对真实 Session 树副本的验证命令(非 mock 插件逻辑),例如:

node tools/verify-host.mjs "$DSH_HOME/sessions"
node tools/verify-http.mjs
node tools/verify-client.mjs

完整列表与环境变量说明见 GitHub README 的 Verification 一节。

适用场景与注意

适合谁:长期在本地或自托管 DSH 上积累大量 Session、需要像桌面应用一样「删掉并偶尔找回」的开发者;需要在不改 Harness 的前提下清理磁盘、或精细裁剪某 Session 内消息(模型上下文 vs 界面展示)的场景。

务必注意:

  • 插件以当前 DSH 进程权限读写 sessionRoot、trashRoot 与回收站;安装前检查源码与 MIT 许可证,确认路径与备份策略可接受。
  • 只有 purge(及 truncate 对 artifact 的改写)会不可逆地改变或删除字节;其余 Session 删除默认可从回收站恢复。
  • Shadow 不删屏幕上的行,Truncate 会;选型前先理解 README 中 Shadow vs truncate 一节。
  • 社区目录与 GitHub 星标(截至资料抓取为 0)不代表官方背书;版本与行为以仓库 CHANGELOG 与 tag 0.2.0 为准。

结尾

dsh-session-deleter 补上了 DSH Web UI 与 Session 持久化层之间缺失的删除能力:整 Session 默认进回收站,永久删除需明确确认;消息支持可逆 shadow 与带备份的 truncate。若你正在维护本地 Session 目录或需要可控的消息裁剪,可在审阅源码后通过 bundle 接入。

  • 目录页:https://www.skillhub.cn/plugins/ghgjkbf/dsh-session-deleter
  • GitHub:https://github.com/ghgjkbf/dsh-session-deleter
羽毛球分组比赛记分
小程序二维码

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

小夜