dsh-archive-session-manager
DSH(DeepSeek Harness)插件:管理已归档会话 —— 删除、批量清理,以及修复会话归属。
DSH 平台本身没有「删除会话」的入口,归档会话只能一直留着。本插件补上这个能力,并提供几项随附的维护工具。
功能
- 删除单个归档会话:会话「···」菜单里,已归档的会话多出一项「删除会话」(带确认对话框,永久删除磁盘记录)。
- 归档会话管理页(设置 → 归档会话):列出全部归档会话(标题 / 时间 / 目录 / 磁盘占用),支持多选、全选、批量删除、批量取消归档与刷新。
- 归位失效会话:把「磁盘上有、但不在任何工作区记账里」的会话(它们会显示在侧栏的「未分组」)重新挂回其工作目录对应的工作区。只修归属,不删文件;子智能体会被自动跳过。
- 一键摘除误记账的子智能体:子智能体不该占用用户工作区的归属槽位。若历史版本把子智能体挂进了记账,可一键摘除 —— 只改记账、不动磁盘。
- 清理遗留空会话:找出「建了但从未有过对话」的历史会话目录并永久删除。这是唯一按内容判据批量删文件的功能,因此走两步确认,且宿主会二次校验(任何有对话内容的会话一律拒删)。它需要全库扫描,所以改为按需触发(点「开始扫描」),不在打开页面时自动运行。
- 清理幽灵记账:清掉「记账里还记着、磁盘上已不存在」的失效条目。
入口放在设置页而非侧栏:这是低频的批量维护操作,不是会话内的日常动作。
安装
dsh plugin --profile web add github:felixpu/dsh-archive-session-manager
⚠️ 安装或升级后需要重启 DSH:宿主半身与客户端 bundle 都在进程启动时装载,不重启不会生效。
使用
删除一个归档会话
- 先归档它(平台自带的「归档」菜单项);
- 在会话「···」菜单里选「删除会话」;
- 在确认对话框里确认。
⚠️ 删除不可恢复。该会话派生的子智能体会话会一并删除(见「设计要点」)。
归档会话管理页
设置 → 归档会话。勾选若干行后可批量删除或批量取消归档,右侧有刷新。页面会按实际情况显示各项维护入口。
维护项一览
| 入口 | 作用 | 是否动磁盘文件 | 何时运行 |
|---|---|---|---|
| 归位失效会话 | 把未记账的会话挂回其工作目录对应的工作区(消掉侧栏「未分组」) | 否 | 打开页面时自动预览 |
| 摘除误记账的子智能体 | 把子智能体从工作区归属记账里摘掉 | 否 | 打开页面时自动预览 |
| 清理幽灵记账 | 清掉磁盘上已不存在的记账条目 | 否 | 打开页面时自动预览 |
| 清理遗留空会话 | 删除「从未有过对话」的空会话目录 | 是 | 点「开始扫描」后才运行 |
前两项只改记账,都会先给只读预览再执行。
「清理遗留空会话」需要读取全部会话日志才能判断「有没有对话」,是一次全库扫描 (可能耗时数秒),因此不会在打开页面时自动运行 —— 请点该项右侧的「开始扫描」。
安全边界(设计决定)
- 只有已归档的会话可以删除。未归档会话没有删除入口;直接调接口也会被逐条拒绝(
not-archived)。归档本身就是平台表达「确认不再使用」的动作,插件不另造一套确认语义。 - 只有正在执行任务的会话拒绝删除;被打开过但处于空闲的会话允许删除 —— 它只是常驻内存,并没有进行中的写入。
- 会话目录路径严格限制在
$DSH_HOME/sessions/之下并做前缀校验,拒绝任何越界。 - 删除不可恢复。需要备份时请自行复制
~/.dsh/sessions/下对应目录。 - 空会话清理在服务端重算判据,不信任前端传来的 id:有对话内容的一律拒删。
设计要点
「删除」为什么是一组动作
DSH 平台没有会话级删除 API:sessionPersistence 只有 create / open / flush / stat / list,sessionController 与 workspaceRegistry 也都没有删除会话的方法(后者的 delete 删的是工作区)。
所以本插件的「删除」由四步组成:
- 驱逐内存态 —— 让平台真正忘掉这个会话;
- 删除磁盘目录;
- 从归档集合移除;
- 从工作区记账摘除。
顺序有讲究:必须先驱逐、再删目录。会话收尾时会做最后一次落盘,而落盘会重新创建目录 —— 顺序反了,刚删掉的目录会被建回来。
被打开过的会话为什么需要特殊处理
在浏览器里打开过的会话会常驻在宿主进程内存里,并被两条内存通路持续列出来。此时只删磁盘文件没有用:刷新后它照样会出现。
本插件会先把它从平台内存里驱逐出去(上一条的第 1 步),再删磁盘与记账 —— 正常情况删除当场生效。
如果某次驱逐被平台拒绝,该条目会以「待重启」的形式单列在管理页,并提供一个**「重试驱逐」**按钮:
- 它不会出现在侧栏,也不会混进归档会话列表;
- 点「重试驱逐」即可当场清掉;重启 DSH 也会自动收敛。
侧栏里的「未分组」是什么
会话只要不在任何工作区的记账里,就会落进侧栏的「未分组」分组。常见来源有两个:
- 删除了一个曾被打开的归档会话 —— 归属被摘掉、但会话仍留在内存里,于是变成「没有归属的会话」。本插件删除时会先驱逐内存态,因此不会再产生这种情况;若你曾用早期版本删过,可能已经留下这类条目。
- 历史遗留的未记账会话 —— 从未被挂进任何工作区。
两种情况都用管理页的「归位失效会话」处理:把这类会话挂回其工作目录对应的工作区,「未分组」随之消失。归位会跳过子智能体 —— 它们本就不作为列表行显示,塞进工作区记账属于脏数据。
删除为什么连带子智能体
会话可以派生子智能体(subagent)—— 每个子智能体有自己的会话记录(独立目录、独立日志), 但它们从不作为列表行显示,只在父会话行上以「N 个子智能体」的形式出现。
平台的删除是会话级的,不会自动级联。也就是说:删掉父会话后,它的子智能体记录会永久留在磁盘上, 而界面上没有任何入口能看到或清理它们 —— 长此以往会累积出大量无人认领的子会话目录。
所以本插件在删除父会话时,会连带删除它的子智能体会话(含多层派生)。 判定严格依据会话头里的「这是子智能体」标记,而不是「有父会话字段」—— 后者会把正常的延续会话(用户可见、在侧栏有行)误判进来删掉。
语言 / Language
本插件界面支持中文与英文,跟随平台语言设置:设置 → 通用 → 语言。 切换后界面文案立即生效,无需刷新页面或重装插件。
The UI is available in Chinese and English, following the platform language setting under Settings → General → Language. Switching applies immediately — no reload or reinstall needed.
展示元数据(locale)
locale/en.json 与 locale/zh.json 提供插件展示元数据(meta.title / meta.description)——
即插件列表里显示的名称与说明。Plugin Manager 与设置页无需激活插件即可读取,
因此安装后、甚至未启动时就能显示本地化名称。
{ "meta": { "title": "…", "description": "…" } }
它与上面的界面文案是两套东西:界面文案走客户端 ctx.locale.register(运行时,随语言切换立即变),
展示元数据走这两个静态 JSON(宿主读 manifest,不回退到界面字典)。
⚠️ 两个容易漏的点(漏任一个都会静默失效,宿主不报错):
- 必须在
package.json的exports里导出./locale/*.json—— 宿主经 Node 模块解析器 读取该资源,未导出的子路径会得到ERR_PACKAGE_PATH_NOT_EXPORTED,被当作「没有 locale」跳过。 files需包含locale—— 否则pnpm pack/npm publish的产物里不会带上它。
icon.svg 走顶层 icon 字段(相对路径),不需要 exports。
常见问题
删除了,但列表里还有它? 先刷新页面。若管理页出现「待重启」条目,那是驱逐被平台拒绝时的兜底,点「重试驱逐」即可;再不行重启 DSH。
侧栏出现「未分组」了,是删除造成的吗? 见上文「侧栏里的『未分组』是什么」。用「归位失效会话」把它们挂回工作区即可。
为什么「删除会话」只出现在已归档的会话上? 归档是平台表达「确认不再使用」的动作,插件沿用这个语义、不另造确认流程。想删就先归档。
删除会连带删掉子智能体吗? 会(这是有意为之)。会话派生出的子智能体会话会随父会话一并删除。原因:平台的删除是会话级的、 不会自动级联,而子智能体从不作为列表行显示 —— 若不连带清理,它们会永久留在磁盘上且没有任何入口可删。 删除确认框与结果提示里都会写明这一点。子智能体是父会话内部的调用记录,不是独立会话。
打开管理页为什么不再自动检查空会话了? 因为那需要读取全部会话日志才能判断「有没有对话」,是重活(会话多时可达数秒)。 改为点「开始扫描」按需触发后,页面打开不再受影响。
「清理遗留空会话」会误删我的会话吗? 不会。判据是「日志里没有任何用户消息」,且在服务端重算、逐条二次校验;有任何对话内容的一律拒删。删除前也有只读预览。
开发者文档
实现细节、平台内部机制(含源码位置)、实测记录与排查方法:docs/DEVELOPMENT.md。 升级后验证清单:docs/VERIFICATION.md。
许可证
MIT
No comments yet. Be the first to write one.