前言¶
在 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 原文归纳):
- Delete a whole Session — 将整个 Session 目录(含各代日志)移动到回收站,可恢复。
- Restore — 把回收站中的目录移回原路径;若目标路径已被占用则拒绝覆盖。
- Delete permanently — 唯一不可撤销的步骤,也是唯一真正释放磁盘空间的步骤;需要第二次明确点击(或 API 传
confirm: true)。
设计原则:默认可逆。第一次删除请求不会直接删字节,在同一文件系统上通过 rename 进回收站,原子完成「破坏性工作」的实质步骤。
单条消息:Shadow 与 Truncate¶
除整 Session 外,插件还通过 HTTP 暴露消息级接口(见下文路由表):
- Shadow(line A):只追加、完全可逆。用
developer/messagetombstone 替换模型可见 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>/sessionstrashRoot:<home>/session-trash/sessions
卸载时:移除 bundle 行与 npm 包即可;回收站中已持有的目录仍保留,可手工恢复——manifest.json 记录每条目的原路径。
磁盘状态¶
<home>/session-trash/sessions/— 每次删除对应一个 held 目录,另有manifest.json。<home>/session-trash/ledger.jsonl— 每个操作阶段一行,只追加;读时若末尾行因崩溃 torn 则丢弃,不当作损坏。
典型用法¶
从 Web UI 删除 Session¶
- 在侧边栏底部(Settings 旁)打开 Session 选择器,或对非当前 Session 使用「…」菜单中的删除项。
- 在确认对话框中查看 dry run 计划(目录、大小、代数、影响与残留)。
- 确认后 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