@xrn1997/dsh-session-delete
v0.8.0
Published
在 DeepSeek Harness 里删除会话:删除=移入回收站(可恢复),另设显式彻底删除
Maintainers
Readme
@xrn1997/dsh-session-delete
给 DeepSeek Harness(DSH)加一个删除会话的能力。DSH 官方有归档、没有删除——归档只是把会话从列表里挪走,文件还在。本插件补上删除,并且让删除可恢复:删除 = 移入回收站,另有一个显式的「彻底删除」。

- 安装:
dsh plugin --profile <profile> add @xrn1997/dsh-session-delete - 许可:Apache-2.0
- 数据:回收站本体留在本机
$DSH_HOME/session-trash/(默认~/.dsh/session-trash/),不联网、不上传
目录
功能特性
- 删除 = 移入回收站:会话行「⋯」→「删除」,可随时恢复;删完有一条停 6 秒的撤销提示。删的是当前正打开的会话时,对话会随删除关闭(不会停在「会话不可用」),点撤销会把它重新打开
- 按整组删:父会话在盘上的子会话与更深后代一起走;任一成员在跑 ⇒ 整组拒绝、零副作用
- 批量删除:宿主会话列表「⋯」→「多选」,一次确认、一次执行;失败的留在框里可重试,成功的整批撤销
- 回收站面板:左清单右详情,按项目分组、可折叠、可拖分栏;看得见正文再决定恢复不恢复
- 详情看得到附件:消息里的图片内联、可点开放大,普通文件给下载 chip;图片加载失败换成占位,不把破图留在屏上(文件下载失败没有页面内提示,浏览器可能把错误响应存成文件)
- 恢复:单条即点即回,批量带确认;回到各自的原项目目录(删除前你自己归档过的仍保持归档)
- 显式彻底删除:单条彻底删除(行右的垃圾桶图标)与页脚「清空回收站…」共用同一个二次确认;不自动过期
- 手动清理残留:插件设置页有一张「维护」卡,随时检查两类残留——父会话已不在的子会话,和
.dsh里已没有任何引用的图片副本;看过数量与体积再由你决定清不清,不自动检查、不自动清理 - 可调项有表单:插件详情页的「可调项」卡直接改三只旋钮(孤儿预览条数、附件响应上限、JSON 扫描上限),保存写回 profile 的 patch 层;也可以继续直接改
cordis.patch.yml - 失败不吞:宿主读不到时把原文上屏并给「重试」;不可用时不注册任何入口
- 文案随宿主语言:中文 / English 挂在宿主 locale 服务上
安装
dsh plugin --profile <profile> add @xrn1997/dsh-session-delete
dsh plugin --profile <profile> remove @xrn1997/dsh-session-delete装完重启宿主(Node 半不走 HMR)。卸载只移除插件,$DSH_HOME/session-trash/(默认 ~/.dsh/session-trash/)下已有的目录不会被自动清理。
装法:
- npm 安装(推荐):使用预构建产物,秒装、无需构建授权。
- GitHub Release 装(不依赖本包在 npm 上的发布,也不需要构建工具链):发版工作流在
V*tag 上产出预构建 tarball。装最新 Release:dsh plugin --profile <profile> add https://github.com/xrn1997/dsh-session-delete/releases/latest/download/dsh-session-delete.tgz钉版本就换成https://github.com/xrn1997/dsh-session-delete/releases/download/V<版本>/xrn1997-dsh-session-delete-<版本>.tgz;tarball 自带lib/,装的是预构建产物,宿主能否挂载仍由兼容闸与真机验证决定。宿主不认 URL 形态的参数时,把.tgz下到本地再按下面离线分发那条装。Releases 页还没有对应版本时,用 npm 或离线分发。 - 离线分发:
pnpm pack出 tarball 后dsh plugin --profile <profile> add ./xrn1997-dsh-session-delete-<版本>.tgz(scoped 包的文件名带作者段)。包里带预构建产物(prepack会替你跑build),这条路不需要为构建脚本授权。
兼容性分两层,别混:
- 装得上由
package.json的engines.dsh决定:宿主拿运行中的版本比这个区间,不满足即拒绝并回滚。窗口是>=0.1.7-rc.2 <0.3.0-0(预发布版本参与匹配)。地板由两件硬依赖定:sidebar.session.row.leading(0.1.7-rc.2 首现)与workspaceRegistry.unarchiveSession;0.1.7-rc.2是第一个同时具备全部所需槽位与服务方法的代次,CLI 台架验过四个槽位齐全、激活零错误。更低的0.1.7-rc.1缺行首勾选槽位;0.1.7-alpha、0.1.6、0.1.5 还缺会话行菜单/行尾槽位或unarchiveSession,不要装。 - 真跑过由
xrn1997.dshReleases记录,只列桌面真机实测过的宿主:DSH Desktop 0.2.0-rc.2、0.2.1-rc.1、0.2.1-rc.2、0.2.1-rc.3、0.2.1-rc.5、0.2.2-rc.1(均compatible)。窗口内的其他代次装得上但没在桌面真机上验过,不作为推荐目标;窗口外的一律拒装。 - 部署注意:exact Fetch 路由的 owner principal 校验(非 owner 回 403)自
0.2.1-alpha.3起才有;更早的代次(含0.2.0-rc.2)只有宿主/api的 trusted-host / 浏览器认证。单机 web / 桌面标准组合可用;要跑多 Peer 部署,优先名单里带这道校验的实测代次(0.2.1-rc.1起)。
用法
删一条:会话行「⋯」→「删除」→ 确认框。确认框在点之前就说明这一组的规模(「含 N 个子会话,将一起移入回收站」,N>0 才出现),删完那条提示点「撤销」即恢复。

删除按整组走:父会话在盘上的子会话与更深后代一起移走(传递闭包,一层层取到底)——那些行宿主本来就不显示。这里的子会话只指宿主 origin:"subagent" 的会话;用「在新对话中分支」产生的普通 fork 是独立会话,删父、恢复都不动它。任一成员在跑(包括列表里看不见的子会话)⇒ 整组拒绝、零副作用,报的是那个运行中的 id;本插件不替用户终止正在进行的活。
删一批:会话行「⋯」→「多选」进入显式模式。模式内点整行勾选/取消且不切换会话,行首出勾选框,浮条常驻(0 条也给退出入口),同一位置在「全选 / 取消全选」之间切换。确认框逐条列出这批会话,执行是一次批量请求:部分失败不关框、原文落在失败那一行,按钮变成「重试这 N 条」,成功的 6 秒内可整批撤销。

管回收站:侧栏面板里的「回收站」一行(与「插件」同层)。左清单右详情(中央列更窄时改成下钻,「← 返回清单」回来),按项目分组、组头可折叠、两栏之间那根线可拖。详情按块展示这条会话的对话全量:你的提问、宿主注入的上下文、助手文字与思考、工具调用与结果、系统消息与压缩摘要。工作步骤有四档(简洁 / 标准 / 详细 / 完全展开),默认「标准」把连续的过程块收成「工作步骤」一行,点开仍逐条折叠;长会话有更早页时正文工具栏出「加载更早」,点一次取一页;右缘常驻一道「提问」轨,一句提问一格,悬停出预览、点一下跳到那句(没加载的会先补页),简洁档里补回来的整页过程块被藏起来时也会自动继续往前翻。助手文字与思考按 Markdown 排版,你的提问保持原话。跟着父会话一起进来的子会话不占清单行,入口在父详情的「子会话」段(默认收起成一行摘要,点开才列出孩子):点一条即切到那个孩子的详情(会话信息、正文与分页同一套),头部「← 返回父会话」回到父。
- 恢复:单条不需要确认框,放回原项目目录(删除前你自己归档过的仍保持归档;旧版本留下的归档态条目会迁移式取消归档)。原工作区已被删掉也照常恢复(跳过账本挂接,恢复后在宿主的会话列表里归入「未分组」);回收站清单把这些条目直接归在「未分组」组里,点之前就看得见。
- 批量恢复 / 批量彻底删除:工具栏「多选」进入,页脚换成两颗动作按钮。组头那颗是三态勾选框,点它选上这个项目的全部会话(含折叠起来看不见的)。两者都先确认,逐条执行、失败不连坐,失败的原文留在它自己那行。
- 彻底删除 / 清空:共用同一个二次确认。单条那张卡片报的是这一次会释放多少(父 + 跟着进来的孩子 + 仍留在盘上的后代,与头部合计共用同一算式)。「清空回收站…」先把回收站目录与清单对账一遍再清,所以手工搬进
session-trash/的认得出的目录也归它管;认不出的外人目录不动也不列。 - 残留维护在插件设置页:父会话已不在(既不在会话列表、也不在回收站清册)的子会话宿主客户端整排不显示,回收站里也不会有;
.dsh附件库里也可能留下没有任何引用的图片副本。插件详情页的「维护」卡分「孤儿会话」「孤儿附件」两段,都是手动:点「检查」只读,看过数量、体积与图片缩略图再确认清理,清完自动重查;永久删除、不搬进回收站、绝不自动跑。回收站面板不再扫描残留,顶上只保留彻底删除 / 清空之后的附件清理提示。
回收站与数据
| 东西 | 位置 |
| --- | --- |
| 回收站本体 | $DSH_HOME/session-trash/<时间戳>-<原目录名>/(默认 ~/.dsh/session-trash/…) |
| 回收站清单 | 本插件自己的 storage domain(介质在 $DSH_HOME/storages/,默认 ~/.dsh/storages/) |
- 回收站与
$DSH_HOME/sessions/(默认~/.dsh/sessions/)同卷:搬进搬出靠整目录rename,原子、瞬时。 - 一格目录 = 一个会话:父会话与跟着它进来的子会话各占一格,面板上折成一行。手工翻回收站目录时看到比清单多的目录,那是子会话。
- 清单丢了不致命:会话文件自描述,解压后第一行即 header,含
id与cwd;读取回收站列表(以及清空、恢复、彻底删除与清理无主子会话前)会先与回收站目录对账。 - 不自动过期:不设天数上限,清空是显式动作;界面显示条数与共可释放量(与彻底删除确认同一口径)。
- 附件:宿主把对话里的图片/文件副本存在
$DSH_HOME/attachments/v1。彻底删除会话时,只清理只被这些会话引用的图片副本;共享副本保留,你磁盘上的原图不受影响。普通文件附件目前只渲染、不代删。设置页「维护」卡的「孤儿附件」段可以手动清掉.dsh里已经没有任何引用的图片副本,同样只动这些副本、源文件不受影响、共享引用保留。 - 无主子会话不在回收站里:它们的父会话已不存在;清理只清会话目录与会话独占的图片副本(宿主投影缓存不包含在内,共享图片保留,你磁盘上的原图不受影响)。检查与清理都在插件设置页的「维护」卡里手动发起。
- 回收站本体留在本机、不联网、不上传。
可调项
三只旋钮都有默认值;可以在宿主 profile 的 cordis.patch.yml 里改,也可以在插件设置页的「可调项」卡里改,都不需要改代码:
| 键 | 默认值 | 作用 |
| --- | --- | --- |
| orphanPreviewLimit | 200 | 设置页「孤儿附件」预览清单的条数(数量与字节仍按全量报告) |
| maxAttachmentBytes | 20971520(20 MiB) | GET /attachment 单次响应的字节上限 |
| maxJsonRefBytes | 10485760(10 MiB) | 附件引用扫描里单个 JSON 引用源的字节上限 |
- insert:
- id: xrn1997-session-delete
name: '@xrn1997/dsh-session-delete'
config:
orphanPreviewLimit: 200
maxAttachmentBytes: 20971520
maxJsonRefBytes: 104857600.6.1 及以前的行 id 是 session-delete;如果你的 profile 覆盖过这一行,升级后请把 id 同步成
xrn1997-session-delete,否则那份覆盖不再命中本行。
配置在插件激活时归一;未知键、非整数或越界会让这一条激活失败(不会用半套配置启动)。宿主的字段投影仍不认这枚手写的 Standard Schema(0.2.2-rc.1 实测 Config.listConfigs 回 status: unsupported),所以字段表单由插件设置页的「可调项」卡提供(ADR-0043):三只数字输入 + 保存,写回 profile 的 patch 层(宿主的 configEditor.edit,保存后这一行会重启)。也可以继续直接改 cordis.patch.yml,两条路改的是同一份配置。
界面语言
中文 / English 挂在宿主自己的 locale 服务上,跟随设置的界面语言;服务不可用时退回内置中文。
常见问题
装完侧栏没有「回收站」,会话菜单里也没有「删除」?
先重启宿主。若仍没有,确认这一代宿主上本插件激活过——取数通道探测不过时,本插件一个入口都不注册:页面上看不出它的存在,但也不会因此把宿主拖死。这是有意用「入口不出现」表达不可用,不是禁用态。
删完之后侧栏那一行怎么还在?
本插件只在宿主确实不再列它时才通告客户端把那一行去掉;拿不准时宁可沉默(那时说「已移除」是假话)。刚巧遇上就刷新页面,那一行会自己消失。本机运行期没打开过的冷会话走正常路径,删完即走。
正在运行的会话为什么删不掉?
判据用的是宿主自己的活跃检查(与官方归档的准入同源)。一律拒绝,不替用户终止正在进行的活——先停下这个会话再删。它正在跑的子会话也算:报告的是那个子会话的 id,而那一行宿主的列表里不显示,所以别看列表就以为删得掉。
批量删除/恢复为什么只成功了一部分?
执行是逐条的,失败不会连坐。批量删除的确认框不关,原文留在失败那一行,按钮变成「重试这 N 条」;批量恢复失败的条目留在清单自己那行,多选态保持,成功的已经消失。重试只处理失败名单。
把工作区删了,回收站里的会话还能恢复吗?
能。宿主的「删除工作区」只删注册、保留目录和每个会话日志;恢复照常回盘,只是跳过账本挂接,会话落在「未分组」。回收站清单里这类条目归在「未分组」组,批量恢复确认框也会逐条说明。
我把会话目录从回收站手工搬回 sessions/ 了,为什么列表里没有?
回收站目录只负责文件;恢复还要挂回工作区账本(旧版本留下的归档态条目会迁移式取消归档)。手工搬回不是恢复,下一次读清单会把对应行对账掉。请在面板里点「恢复」。
把宿主绑到局域网地址后,插件入口不出现,或操作报「需要宿主的 Web 身份」/「非受信来源」?
本插件把十段注册到宿主的 exact Fetch 路由(/api/dsh-session-delete-api/...),取数门槛就是宿主 /api 的那一套:浏览器、桌面壳的请求转发与本机 curl 都需要宿主签发的 Web 身份(dsh web 那次访问换来的 cookie),不再有回环免身份,也没有旧前缀 fallback。支持面是 web UI 与桌面端,二者都装 client-connection;入口探测回 401/403 时插件不注册任何入口(页面表现为插件不存在),不会摆出一个点下去必然失败的入口;操作中途身份失效,原文「需要宿主的 Web 身份」上屏。原文写「非受信来源」说的是另一件事:这条请求的归属不成立,Host 不被认为是本次部署的地址,或 Origin 与它对不上(宿主 /api 查 Host / sec-fetch-site / Origin;附件字节段另有插件的同源取数闸,同站/跨站页面与 authority 对不上的 Origin / Referer 都拒)。常见成因有两种:用自定义域名(含 hosts 文件)访问,却没把它写进宿主 client-connection 的 trustedHosts——宿主自己的页面同样要求这一条;或者反向代理改写了 Host,它必须保留客户端的原始 Host。绑定时另有一条前提:宿主只接受具体接口地址、拒绝 0.0.0.0,请绑到某个具体 IP(例如 webserver.host: 192.168.50.199)。
开发
构建、本地调试、门控、真机验证与发版见 docs/development.md;提交信息与 PR 约定见 CONTRIBUTING.md;架构地图与主人清单见 docs/architecture.md;界面规格见 docs/ui-spec.md;文档分层与放置见 docs/AGENTS.md;裁决见 docs/adr/;发布历史见 CHANGELOG.md。历史取舍在 git 历史里,README 不复述。
贡献
欢迎 Issue 与 PR。提交信息、PR 约定与发版边界见 CONTRIBUTING.md;提交前按 docs/development.md 的「复核门」跑 pnpm test 与 pnpm typecheck,并确认退出码;提交即表示你同意以 Apache-2.0 协议授权你的贡献。
许可
图标形状、控件与 Markdown 样式派生自 DeepSeek Harness 的 MIT 许可代码,lib/client.js 另内联了
react-markdown / remark-gfm 及其传递依赖(MIT / ISC);来源、落点与许可全文见
THIRD_PARTY_NOTICES.md。
