一个 DeepSeek Harness 插件:在侧栏会话行的「⋯」菜单里加一行 「删除会话…」。确认后:
- 该会话的日志目录与投影缓存被移到操作系统自己的回收站(Windows 的「回收站」);
- 它同时从工作区会话列表里摘掉,归档集合里的残留也一并清掉。
回收站就是你电脑上那个:还原用你熟悉的方式(资源管理器 → 回收站 → 还原)。本插件不在 DSH 里面另造回收站。
- ✅ 「⋯」菜单里一行
role="menuitem"的「删除会话…」,排在官方 pin(100) / rename(200) / fork(300) / archive(400) 之后(本插件order: 500),左侧是官方垃圾桶图标 - ✅ 二次确认对话框挂在官方
shell.overlay浮层(遮罩、Esc、焦点自己管,不随菜单卸载) - ✅ 中文/英文跟随界面语言(同一套字典,键集合经测试校验一致)
- ✅ 不替换任何官方 UI:只用自己的包名命名空间 id 往官方槽位里加
- ✅ 动手前先做只读定位;定位不到就什么都不做
| 步 | 做什么 | 官方依据 |
|---|---|---|
| 1 | 定位 ~/.dsh/sessions/<工作区>/<session-id> |
只读扫描,不拼用户输入 |
| 2 | 停住该会话 | workspaceRegistry.archiveSession(id, { stopActivity: true }) —— 归档集合正是 agent/pre-step 门读的东西,这就是官方的「停」信号,避免日志被还在跑的 Agent 写 |
| 3 | 回收日志目录 + 投影缓存 | Microsoft.VisualBasic.FileIO.FileSystem … SendToRecycleBin |
| 4 | 摘掉该行 | Workspace.detachSession(id),随后 unarchiveSession(id) 清掉第 2 步留下的归档记录 |
全程在一次 HTTP 请求里完成(宿主半体拥有整条链)。
失败是回滚,不是半途状态。 第 3 步失败就什么都不摘、并把第 2 步的归档撤销,会话的可见性回到原样。没有「直接永久删除」的兜底——回收站拒绝时静默抹掉用户日志,不是这个插件该做的决定。
| 状态 | |
|---|---|
| Windows | ✅ 支持。Microsoft.VisualBasic.FileIO.FileSystem(Windows PowerShell 5.1 与 7 都带)让 shell 回收而不是 unlink。PowerShell 走绝对路径 %SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe——GUI 启动不继承 shell 的 PATH,所以不能假设 pwsh 在 PATH 上 |
| macOS / Linux | ⛔ 未实现。会明确回 501 且不做任何改动,而不是猜一种删除方式 |
- 只有「清空回收站」不可逆 —— 那是 Windows 自己的行为,不是本插件的。
- 「幽灵行」:被删的会话若在本次运行里被加载过(新建或点开),它仍活在宿主的内存会话表里。官方没有把它移除的接口——
ctx.sessions只有create / prepare / enter / announce / flush / get / list / fork;AgentHandle.dispose()属于创建它的那一方(agent 工厂的复合拆除链),插件拿不到。于是那一行会留在侧栏(失去工作区归属后落到「未分组」),要等下次启动 DSH 才彻底消失。- 实测:刷新页面清不掉它。 曾有一版把确认按钮绑成「确认并刷新界面」(
location.reload()),验证结果是那一行依然在——因为尸体在宿主内存里,页面重取也拿得到;该绑定已移除,按钮回到单纯的「确认」。 - 成功的弹窗不区分这两种情形:结论框固定两行——「已删除:日志已移入系统回收站。」+「本会话将在重启 DSH 后消失。」这句话对两种情况都成立(本次运行没加载过的会话当场就没了,加载过的重启后也没了),所以没必要让用户分辨。宿主仍会在响应里回
wasLive,供诊断使用。 - 注意:字节此时已经在回收站里,那行只是一条指向空处的记录;没被本次运行加载过的会话删掉不会留行。
- 实测:刷新页面清不掉它。 曾有一版把确认按钮绑成「确认并刷新界面」(
- 宿主若没有
workspaceRegistry(非 Web 组合),回收照做,但列表行可能要等到下次启动才消失;这一步会在返回结果里说明,不会假装成功。 - 归档(把行藏起来但保留日志)仍是官方 ⋯ 里那一行的职责,本插件不提供。
用 Settings → Plugins 安装,或让插件管理器装本地目录。它会写成:
"dependencies": { "dsh-session-delete": "link:<本目录绝对路径>" }并把 "dsh-session-delete" 追加进 profile 的 dsh.profile.bundles。装的是 link:(符号链接),所以本目录就是唯一真源。
把本目录放进 profile(例如 ~/.dsh/profiles/desktop/),然后:
dependencies加"dsh-session-delete": "file:./dsh-session-delete"dsh.profile.bundles追加"dsh-session-delete"- 在 profile 目录
pnpm install,然后重启 DSH
cordis.patch.yml 把插件行插进 profile 层;client 端由官方 dsh-client-modules 扫描 dsh.client 声明后自动注入浏览器。
卸载:Settings → Plugins 里卸载,或从 dependencies / dsh.profile.bundles 里删掉再 pnpm install。
| 改哪半 | 生效方式 |
|---|---|
lib/client.js(浏览器半体) |
宿主每次投递都从磁盘读 → 刷新页面即可 |
lib/index.js(宿主半体) |
模块在挂载时导入一次,改文件不会重新导入 → 需要重启 DSH |
node tools/dry-run.mjs [--scratch <dir>] [--composition <module-list>] [--keep]在系统临时目录里搭一个暂存 profile 跑 85 项检查,最后断言真实 Harness 家目录一字未动(包括逐个比对真实会话日志目录)。覆盖:安装形态、发布契约、dsh.client.inject ∩ 组合、classic-script 编译、客户端 apply() 与两处注册、菜单行有/无 sessionId 的渲染、官方 MenuItemButton 的 onSelect 契约、有序删除流程、以及宿主半体的定位/删除/回滚/隔离。
回收站在 dry run 里是可注入的 stand-in:它把字节搬走而不是交给系统回收站,所以 dry run 绝不会往你的回收站放任何东西。真实回收站路径由一次单独的一次性目录探针验证(见提交历史)。
宿主会一直扣着客户端入口,直到清单里每一个 seam 都存在。列了不在组合里的名字 = 这个插件在该宿主上永远不会加载(市场为这条规则付过代价,issue #554)。
本包只列确实存在于组合里、且确实用到的三个包:
| seam | 用途 |
|---|---|
@deepseek-ai/dsh-client-locale |
ctx.locale |
@deepseek-ai/dsh-client-ui-settings |
ctx.slots(市场的映射里,提供 slot 服务的 seam) |
@deepseek-ai/dsh-client-ui-workspace |
它声明了 sidebar.workspaces.session.menu.item 这个槽位 |
不要加 @deepseek-ai/dsh-client-runtime(市场已从自己的清单删掉;它属于宿主基础设施链)或 @deepseek-ai/dsh-client-ui-slots(被 runtime 内联的纯核心库,npm 清单里连 dsh 字段都没有,不是客户端模块)。
文件必须以单行 window.__ModuleLoader__.load({ id: "dsh-session-delete", factory: (require) => { 开头,且不能有 BOM(宿主会从文件头嗅探 loader id)。同时必须是 classic script(官方用 vm.Script 编译校验),所以 bundle 里不能出现 import/export。
peerDependencies / engines.dsh 故意留空。 宿主会按 dsh peer range 决定是否跳过整个 bundle(只闸 @deepseek-ai/dsh 与 @deepseek-ai/dsh-*)。声明一个与被测宿主不匹配的区间,代价是插件完全不被加载——比不声明更糟。本机已验证的运行时是 0.2.0-rc.2,等确定要支持哪些版本后再补:
"peerDependencies": { "@deepseek-ai/dsh": "^<验证过的版本>" },
"engines": { "dsh": "^<同一个版本>" }两者机制不同:engines.dsh 是市场安装时的前置校验,peerDependencies 是宿主启动时的跳过判定。
MIT