DSH 对话回收站(dsh-session-trash)
给 DeepSeek Harness 的插件:把对话真正删掉(不是归档),进回收站保留 3 天,期间可恢复,到期自动永久删除。
- 仓库:https://github.com/xwhking/dsh-session-trash
- 当前版本:v1.5.2
一、先说清楚 DSH 的现状
DSH 只有归档 ,没有删除。归档的三个问题:
- 内容还在磁盘上,只是加了一个隐藏 flag;
- 切到「显示已归档」,它又出现在侧栏;
- 归档提示上有「撤销」,一点就回来。
更麻烦的是:如果删的是刚用完的对话,它根本不会消失 ------DSH 在内存里保留 Agent 对象,会话列表是「磁盘 + 内存」叠加出来的。
二、功能
| 功能 | 说明 |
|---|---|
| 删除对话 | 会话行 ⋯ 菜单里的红色「删除对话」,点击后立刻从侧栏消失 |
| 回收站 | 侧栏底部垃圾桶图标,列出标题、删除时间、剩余时间、状态 |
| 恢复 | 3 天内把对话原样搬回原工作区(字节一致) |
| 彻底删除 | 立即永久删除,不可恢复 |
| 清空回收站 | 一次清掉所有条目 |
| 自动过期 | 后台每 5 分钟扫一次,启动时补扫 |
| 失败可见 | 弹红字 + 写 last-error.json(含调用栈) |
回收站面板每条会显示当前状态:
日志已移走,任何列表都看不到------ 正常纯移动你仍开着它,关闭后会彻底隐藏------ 走了临时归档兜底没有落盘内容,重启后彻底消失------ 从未落盘的空壳
三、怎么做的
3.1 核心结论:日志移走 = 删除
侧栏的渲染逻辑是:
每个工作区行 = 工作区成员 sessionIds ∩ 平台会话列表 summaries
而平台会话列表来自磁盘日志 ~/.dsh/sessions/<工作区>/<ID>/session.v4.jsonl.zstd。
所以把日志目录挪出 sessions 根,这篇对话就从任何列表里消失,不需要归档。
3.2 但活着的对话绕不过去
如果这篇对话你还开着,DSH 内存里还留着 Agent,那么日志挪走了,平台仍然会列出它。
我查过两个接口,都没有删除能力:
| 接口 | 可用方法 |
|---|---|
sessionPersistence |
create / open / flush / stat / list ------ 无 delete |
| 活会话的 Agent 对象 | loopCtx / session / inbox / phase / ctx / send / cancel ------ 无 dispose/close/destroy/stop |
唯一能压住它的开关就是归档。
3.3 完整删除流程(代码里的真实顺序)
- archiveSession(id, { stopActivity: true }) └─ 唯一用途:停掉还在往这篇日志里写的任务
- 日志目录 rename 到 ~/.dsh/dsh-session-trash/files// └─ rename 失败会重试 3 次,再退化为「复制 + 删除」
- detachSession(id) ------ 从工作区成员里摘除
- 判断 hasLiveAgent(id): ├─ false(绝大多数)→ unarchiveSession(id) 立刻取消归档 │ → 归档列表里不留任何痕迹 └─ true(你还开着) → 保留归档,写 archiveFallback = true
- 写入 state.json(sessionId / title / group / deletedAt / expiresAt)
3.4 兜底会自动撤销
每 2 秒检查带 archiveFallback 的条目:
| 平台还持有 Agent | 归档标记 | 动作 |
|---|---|---|
| 是 | 已设置 | 不动(唯一手段) |
| 是 | 被清掉了(平台撤销) | 重新归档 |
| 否(放手了) | 已设置 | 取消归档,靠日志不在隐藏 |
| 否 | 已清掉 | 清标记,收工 |
判定用 ctx.get('agents')?.get(id) !== undefined。
注意:这只回答「内存里还有没有它」,不是 「它是否在运行」------后者用 agent/status 事件。
3.5 最后一层:让浏览器不画它
Host 层保证了「文件没了、列表不返回」,但「那一行还在」是浏览器决定的。两个绕不过的现实:
- 活会话即使日志移走,宿主仍会返回它;
- 归档筛选有「显示已归档」档,会把归档行当正常行渲染。
所以客户端加了第 4 层:
已删 id → localStorage(key: dsh-session-trash.hidden.v1) ↓ 侧栏渲染 data-row-key="session:" ↓ id 在集合里 → 加 data-st-hidden → CSS display:none ↓ MutationObserver 监听,刷新/切档/宿主重推列表都照样隐藏
恢复时把 id 移出集合,行立刻回来。
3.6 顺带修掉的空「未分组」组头
DSH 把未分组渲染成 data-row-key="workspace:"(空 key)。组里只要还有一篇平台仍列着的会话,组头就画出来------哪怕下面的行已被隐藏。
修法:applyHidden() 额外检查组头,往后遍历兄弟节点(是兄弟,不是子节点),若所有会话行都被隐藏,就把组头也隐藏。
3.7 四层职责
| 层 | 负责 |
|---|---|
| 归档 | 让行当场消失 |
| CSS 隐藏 | 让行永远不出现 |
| 移日志 | 让内容真删 |
| 守卫 | 不留归档垃圾 |
四、几个要注意的点
| 注意 | 说明 |
|---|---|
| 别删/别移插件目录 | 本地安装记的是 link:<目录>,动了就失效 |
| 正在跑的对话不会被硬删 | 会先停掉它再删 |
| 彻底删除不可逆 | 3 天内可恢复,过期或彻底删除就没了 |
| 没发过消息的新对话 | 磁盘无日志可挪,只能归档隐藏,重启后消失 |
| 活会话的 Agent 仍占内存 | DSH 无驱逐接口,只能重启释放;但侧栏已不显示,不影响使用 |
| 保留天数 | profile 的 cordis.patch.yml 里改 retentionDays |
五、怎么下载安装
方式一:Release 包(推荐)
- 打开 Releases,下载
dsh-session-trash-1.5.2.tgz - 解压到固定目录,例如
D:\plugins\dsh-session-trash - 对 DSH 说:
bash
plugin_manager action: install_bundle target: D:\plugins\dsh-session-trash
方式二:git 地址
bash
plugin_manager action: install_bundle target: github:xwhking/dsh-session-trash
方式三:直接DSH 桌面端
- 进入插件栏目
- 选择添加插件
- 输入git地址
- 安装就好了,然后启用
装完
刷新页面,侧栏出现垃圾桶图标,会话菜单出现「删除对话」。
改保留天数
profile 的 cordis.patch.yml:
yaml
- id: session-trash
name: 'dsh-session-trash'
config:
retentionDays: 3
改完重新启用插件。
六、数据存放
| 内容 | 路径 |
|---|---|
| 回收站记录 | ~/.dsh/dsh-session-trash/state.json |
| 回收站里的日志 | ~/.dsh/dsh-session-trash/files/<会话ID>/ |
| 原始会话日志 | ~/.dsh/sessions/<工作区>/<会话ID>/ |
| 投影缓存 | ~/.dsh/storages/session_projcache/sessions/<会话ID>.json |
| 上次失败原因 | ~/.dsh/dsh-session-trash/last-error.json |
安全:只注册一条同源路由 /session-trash/api,只接受回环 Host + 同源 Origin,其它 403。