🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

归档会话清理 ao882866-ux/dsh-archive-trash

DeepSeek 客户端v0.4.1
ao882866-ux17 天前有提交已提供中文文档扫描:未发现敏感能力兼容 / 相关生态

为 dsh 已归档会话添加垃圾桶图标,一键删除,极简会话管理。

35.5/100
综合分
4
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/25 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/ao882866-ux/dsh-archive-trash.git

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
生态插件
可安装,未声明 dsh 能力
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 17 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意

npm 同名包「dsh-archive-trash」归属 hongdougao111/dsh-archive-trash,装到的可能不是本插件

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包dsh-archive-trash @ 0.4.1
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/11/3 15:20:52

安全扫描自动 · 静态分析源码
v2.7.0
🟢 扫描:未发现敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。

发起外部网络请求
查看扫描证据(共 1 处,展示前 1 条)
  • 发起网络请求
    lib/index.js:1148
    async fetch(request) {
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 删除已归档会话
  • 侧边栏垃圾桶图标
  • 一键永久删除

DeepSeek Harness 插件:从侧边栏会话行永久删除已归档会话

README

由 DeepSeek 最新模型翻译生成
dsh-archive-trash 给 DSH 已归档会话加一个垃圾桶图标,一键删除,会话管理极简。 一个 DeepSeek Harness 插件,在侧栏已归档会话行上添加垃圾桶按钮,让你真正清理掉不再需要的会话。 归档(archive)在 DSH 里的语义是「从工作区分组界面隐藏」—— 它不删数据。 DSH 自带「归档」与「取消归档」,但归档后的会话长期积累后没有清理入口。 本插件补上这一块:在「仅显示已归档」的列表里,每个归档会话的行上出现一个垃圾桶按钮,两段式确认后永久删除。 功能 | 能力 | 说明 | | 删除入口 | 侧栏会话行的悬停按钮条(sidebar.workspaces.session.row.action),紧邻 DSH 自带的归档按钮 | | 删除范围 | 只对已归档会话出现;普通会话行上没有该按钮 | | 删除外观 | DSH 同款垃圾桶图标(IconTrashOutlineRegular 路径内联),图形 14(与自带归档按钮同尺寸),盒子 16×16 保持对齐 | | 删除交互 | 两段式:点图标 → 图标变红(确认态)→ 再点才执行;失焦或 5 秒后自动取消 | | 删除效果 | 永久删除(日志目录 + 投影缓存 + 归档标记 + 工作区归属),不可恢复 |
展开完整文档(README 剩余 1 节)
dsh-archive-trash

给 DSH 已归档会话加一个垃圾桶图标,一键删除,会话管理极简。

一个 DeepSeek Harness 插件,在侧栏已归档会话行上添加垃圾桶按钮,让你真正清理掉不再需要的会话。

归档(archive)在 DSH 里的语义是「从工作区分组界面隐藏」—— 它不删数据。
DSH 自带「归档」与「取消归档」,但归档后的会话长期积累后没有清理入口。
本插件补上这一块:在「仅显示已归档」的列表里,每个归档会话的行上出现一个垃圾桶按钮,两段式确认后永久删除。

功能

| 能力 | 说明 |
| 删除入口 | 侧栏会话行的悬停按钮条(sidebar.workspaces.session.row.action),紧邻 DSH 自带的归档按钮 |
| 删除范围 | 只对已归档会话出现;普通会话行上没有该按钮 |
| 删除外观 | DSH 同款垃圾桶图标(IconTrashOutlineRegular 路径内联),图形 14(与自带归档按钮同尺寸),盒子 16×16 保持对齐 |
| 删除交互 | 两段式:点图标 → 图标变红(确认态)→ 再点才执行;失焦或 5 秒后自动取消 |
| 删除效果 | 永久删除(日志目录 + 投影缓存 + 归档标记 + 工作区归属),不可恢复 |
| 子代理会话 | 删除主会话时自动级联删除它的子代理(智能体团队)会话,不留孤儿 |

截图

归档列表里,每个已归档会话的行上会出现本插件的垃圾桶按钮 ——就在 DSH 自带的归档按钮右边:

侧栏会话行上的删除按钮

左侧灰色圈是 DSH 自带的「归档」,右侧红圈是本插件的「永久删除」。

安装

本插件自带 cordis.patch.yml 与已构建的 lib/,不需要 npm / pnpm,也不需要本地构建。

推荐:在 DSH 插件界面安装

打开 设置 → 插件 → 添加插件,在「包名或地址」里填入本仓库地址:

https://github.com/ao882866-ux/dsh-archive-trash

安装完成后按提示重启 DSH。

其他方式

命令行(桌面端的 desktop profile 由应用独占,CLI 会拒绝写入)
dsh plugin --profile <profile> add github:ao882866-ux/dsh-archive-trash

手动复制:把 lib/ 与 package.json、cordis.patch.yml 放进 <profile>/node_modules/dsh-archive-trash/,再把包名加进 profile package.json 的 dsh.profile.bundles:

"bundles": [ "...", "dsh-archive-trash" ]

profile 默认在 ~/.dsh/profiles/desktop(可用 DSH_HOME 覆盖)。

⚠️ 改完必须重启 DSH

宿主模块一旦被 import 就进 ESM 缓存,改写 lib/index.js 不会让 apply() 重跑 —— 即使 profile 配了 patchReload: "live"。改动宿主代码后必须重启,否则跑着的仍是旧逻辑。

也不要只依赖手写进 cordis.patch.yml 的 - insert::在 profile 里装/卸任何插件时 DSH 会重写该文件,手写的 insert 会消失。用 dsh.profile.bundles 注册才是持久的。

使用

1. 侧栏「筛选会话」里选 仅显示已归档;
2. 每个归档会话行上会出现垃圾桶按钮,点一下进入确认态(图标变红);
3. 再点一下才真正删除;失焦或 5 秒不动会自动取消。

不需要另开设置页 —— 你本来就在「已归档」列表里看这些会话,再让你去设置里找第二个列表既重复又别扭。

删除主会话时,它的子代理会话会一并删除。分叉(fork)出来的会话不会被删 —— 那是独立会话,你还要接着聊。

实现说明

为什么删除必须自己实现

DSH 没有会话删除 API:

- ctx.sessionQuery 只有读(list / search / readTitle / readEvents …);
- ctx.workspaceRegistry 只有 archiveSession / unarchiveSession;
- ctx.workspaceController(Remote 面)同样只有 archive / unarchive / pin。

所以删除只能操作磁盘上的四份状态:

| 目标 | 位置 |
| 会话日志目录 | $DSH_HOME/sessions/<转义 cwd>/<sessionId>/ |
| 投影缓存 | $DSH_HOME/storages/session_projcache/sessions/<sessionId>.json |
| 工作区归属 | Workspace.detachSession(sessionId) |
| 归档集合 | workspaceRegistry.unarchiveSession(sessionId) |

此外还要把活着的会话从内存摘除(ctx.sessions),否则
sessionQuery.listSessions() 仍会把它列出来。

删除顺序

删除会触碰磁盘上的多份状态,顺序是刻意设计的: 先摘除活着的会话 → 删文件并确认删净 → 最后才摘归档标记与工作区归属。

1. 先把活着的会话从 ctx.sessions 摘除(liveEntryFor + detachEntered)。
摘除会触发 session/disposed → 持久化写入句柄 close()(释放单写者租约,避免删完之后后台 append 又把日志文件建出来),并让客户端丢弃该行。
必须在删文件之前完成,否则后台写入可能重建日志。
2. 删日志目录并复核删净(removeTree:删完检查存在性,仍在则重试)。
同名会话在多个 bucket 下都有目录时全部删除。
3. 删投影缓存(失败不算致命 —— 它不是会话本体)。
4. 到这里才摘归档标记(unarchiveSession)。
5. 从工作区摘除归属(detachSession)。

为什么归档标记必须最后摘

侧栏的可见性判据是:

// dsh-client-ui-workspace 的 sessionVisible(),archivedFilter === 'default' return !archived.has(session.id)

注意 「取消归档」恰恰会让这一行变得可见。所以归档标记必须在数据确实删净之后才摘:若先摘标记而删文件失败(文件被占用 / EPERM / 瞬时 I/O),会话就会留在磁盘上却不再归档,以普通会话身份回到列表。

按上面的顺序,失败方向永远是安全的:

| 失败位置 | 结果 | 用户感受 |
| 第 1~3 步 | 会话原样还在、仍然归档 | 「删除失败,可重试」,会话仍在归档列表里 |
| 第 4 步 | 文件已删净、归档集合还留着(幽灵条目) | 本插件仍然允许删除这种条目,可清理 |

也就是说:绝不会出现「不再归档、却还在磁盘上」的会话。

客户端侧配套:删除成功后调用 ctx.sessions.refresh() 重新拉取列表基线。
宿主摘除活动会话会转发 api-session/removed,但会话在删除前若已不在内存中(进程重启后从未打开过),就不会有这个事件,只能靠主动刷新兜底。

工作区归属必须在删日志之前快照

DSH 0.2 起,Workspace.sessionIds 是一个过滤 getter:

get sessionIds() {
return this.record.sessionIds.filter((id) => this.host.candidateMatches(id, this.record.path))
}

candidateMatches 依赖「该会话的日志头是否还在」。日志一旦删掉,getter 就会把这个 id 过滤掉 —— 于是「sessionIds.includes(id) 为真才 detachSession」这种写法永远不会成立,归属被永久留在 workspace.json 里。

残留的后果:侧栏用同一个 getter,所以暂时看不见它;但任何绕过 getter 的读取路径(启动引导、格式迁移、其他插件、旧版本)都会把它当成「未分组」会话带出来—— 点开时读不到日志又消失,重启后重复同一循环。

所以顺序是:先快照归属(此时日志还在)→ 删文件 → 再按快照摘除。
日志已被外部清理的「幽灵条目」连 getter 都看不见,故退回原始 workspace.json 定位归属。

⚠️ 写入仍走 workspace 服务,不直接改文件 —— 它负责写队列与事件广播,绕过它会与其他写操作竞争。插件只读原始文档来定位归属。

级联删除子代理会话

子代理(智能体团队)会话是独立会话:有自己的日志目录、自己的投影缓存,只是头里多了 origin: 'subagent' 与 parentSession。所以只删主会话会把它们留成孤儿 —— 占着磁盘,却再也无法通过父会话被找到。

删除主会话时会递归收集它的全部子代理后代并逐个删除。

血缘判据(关键,错了会误删)

// 与 DSH 自己一致:dsh-session-persistence-jsonl 的 prepareStoredMigration
source.header.origin === 'subagent' && source.header.parentSession === id

⚠️ 必须同时判两个字段:

- 只看 parentSession 会把 fork(分叉) 也算进来。fork 同样带 parentSession,但它是独立会话 —— 用户分叉出来就是要接着聊的,删掉原会话不该连带删它。
- 只看 origin === 'subagent' 则无法确定父是谁。

顺序:深的先删,主会话最后

后代按由深到浅(叶子在前)排序后逐个删除,最后才删主会话。这样中途失败不会留下「父已删、子成孤儿」——孤儿子代理再也没法通过父会话被找到,只能永久留在磁盘上。

子代理全部删净之后才动主会话。任一子代理正在运行时会整体跳过,主会话保持归档,可稍后重试。

血缘读取:磁盘是唯一权威

1. 先扫磁盘 sessions/ 下的日志文件(只读开头 64KB,解 zstd 第一帧),且只接受满足 header.id === 所在目录名 的头;
2. ctx.sessionPersistence.list() 只作为补漏,且不得覆盖磁盘已确认的头。

⚠️ 为什么要求「头里的 id == 目录名」:头里的 id 是日志文件的自称,而我们要删的是磁盘目录。血缘一律以目录名为准,两者不一致的条目不参与级联,以免误伤其他会话。

这正是 DSH 自己的不变量(dsh-session-persistence-jsonl 的 assertStoredId:「session header id "X" does not match session id "Y"」),真实数据的可解析会话全部满足,所以这个约束零代价。

血缘读取整体失败时降级为「只删主会话」,而不阻断删除 ——宁可留下孤儿子代理让用户手动清理,也不能因为解析不了血缘就整个删不掉。

两种 id 校验:入口用形态,磁盘用路径安全

这是刻意分开的两个概念:

| 场景 | 校验 | 判据 | 为什么 |
| RPC 入口(id 来自客户端,可伪造) | isPlausibleSessionId | 必须是 session-<uuid> / 裸 uuid | 只放行已知形态,防伪造请求 |
| 磁盘发现的 id(目录名 / 日志头) | isSafePathSegment | 只要拼进路径不会逃出基目录 | 真实数据里有 fusion-worker-<uuid> 这类非 uuid 形态的会话目录,用形态校验会漏删 |
isSafePathSegment 拒绝:空串、.、..、路径分隔符、:(盘符 / NTFS ADS)、控制字符与 NUL、超长(>200)。

安全约定

删除不可恢复(deleteSession 直接 fs.rm),所以宿主侧设了六道闸门(都在 lib/index.js,不在客户端 —— 客户端不做任何安全判定,否则伪造请求就能绕过):

1. 只允许删除当前确实处于归档状态的会话。判据是 id ∈ workspace.json 的 archivedSessionIds —— 伪造的 archive.delete 碰不到未归档的会话。
2. 入口 id 必须通过形态校验(isPlausibleSessionId)。id 会拼进文件路径,所以只放行 session-<uuid> / 裸 uuid 形态,拒绝路径分隔符与 ..。
3. 所有路径拼接都做包含性检查(containedPath):projectionCachePath 与每个待删目录都必须落在 $DSH_HOME 对应基目录内,越界返回 undefined 并跳过。这是结构性防护 —— 不依赖「调用方已经校验过 id」。
4. 磁盘 id 用路径安全校验(isSafePathSegment),且要求头里的 id 与所在目录名一致。
5. 正在运行的会话拒绝删除。DSH 的写路径持有单写者句柄,日志被抽走会让下一次 append 失败,表现为会话无故损坏。子代理会话同样受此闸门约束。
6. 级联删除只认 origin === 'subagent' 的血缘,且子代理先于主会话处理 ——这既保证不留孤儿,也保证不误删 fork。

客户端另有两段式确认(点一次只上膛、图标变红,再点才执行;失焦或 5 秒自动取消)—— 不可逆操作绝不能一击执行。

删除成功写 warn 级日志(含会话 id 与级联删掉的子代理数量)、失败写 error 级日志,便于事后追溯。

日志目录已缺失的条目仍可删除

会话被外部清理后,归档列表里可能留下日志目录已不存在的条目。这类幽灵条目 恰恰最该清理,所以「目录不存在」不构成拒绝理由:宿主照常摘掉归档标记与投影缓存,只是没有目录可删。

RPC 端点

| 方法 | 作用 |
| archive.list | 列出归档会话(含标题 / 工作区 / 大小 / 运行状态) |
| archive.restore | 取消归档(单条) |
| archive.restoreMany | 取消归档(批量) |
| archive.delete | 永久删除(单条,含级联删除其子代理会话) |
| archive.deleteMany | 永久删除(批量,逐条同样级联) |

开发

普通安装不需要这一步。只有要改 client-src/ 或 lib/index.js 时才需要:

pnpm install # 或 npm install
pnpm build # 重新生成 lib/client.js

⚠️ pnpm 10+ 会拦截依赖的构建脚本,若不处理,pnpm install 会以 exit 1 结束(ERR_PNPM_IGNORED_BUILDS),随后 pnpm build 也会因依赖状态检查失败而报错 —— esbuild 必须跑 postinstall 才能落地平台二进制。

仓库已带 pnpm-workspace.yaml 显式放行 esbuild,正常克隆下来即可直接安装。
若你的环境仍提示,执行一次 pnpm approve-builds --all 即可。
用 npm 不会阻塞(只警告)。

结构

lib/pure.js 纯函数:排序 / 检索 / 可删除性判定 / 血缘解析(可单测,无 IO) lib/index.js 宿主:RPC 处理器 + HTTP 端点注册 + 文件系统操作 lib/client.js 客户端 bundle(由 client-src/ 经 esbuild 打包) client-src/ UI 源码(React.createElement,不用 JSX)

客户端 bundle 的产物形态必须符合 DSH 客户端模块加载器契约:

window.__ModuleLoader__.load({ id: '<包名>', factory: (require) => { ... } })

id 必须是包名(dsh-archive-trash),react / react-dom 必须保持 external(宿主 shell 提供单例;打进来会产生第二个 React 实例,hooks 直接报错)。

宿主侧 inject = [],connection 通过 ctx.inject(['connection'], ...) 可选挂载:该服务只由 Web bundle 提供,headless / CLI profile 里不存在,静态 inject 会让插件在那些 profile 里永久 pending,导致整个 profile 以「1 entry did not activate」启动失败。

已知限制

- 删除不可恢复,没有回收站。这是刻意的设计选择。
- 标题来源:优先 ctx.sessionQuery.readTitleSnapshots(权威、live-preferred),
不可用时回退读投影缓存文件。两者都没有的会话显示「(无标题)」。
- 最后活动时间:优先取投影缓存文件的 mtime(「最后一次被写」的直接证据),否则退回 header 的 createdAt(创建时间)。
- 事件数:来自 sessionPersistence.stat();服务不可用时为 0(不臆造)。
- 工作区归属优先按 sessionId 解析(会话可被移动),退回按 cwd 匹配(大小写不敏感 —— Windows 路径大小写不敏感)。
- 删除失败时不会留下「未归档但仍在磁盘」的会话:删文件失败 → 会话原样保持归档,可重试;只有摘标记失败 → 留下可再次删除的幽灵条目。
- 同名会话在多个 bucket 下都有目录时会全部删除;目录若在删除后被后台写入重建,removeTree 会重试至多 5 次(每次退避 60ms),仍失败则整体报失败并保持归档状态。
- 级联删除子代理会话(智能体团队):删除主会话时,会递归删除其后代中 origin === 'subagent' 的会话。fork(分叉)不会被删除。
子代理正在运行时整体跳过,主会话保持归档,可稍后重试。
- 删除会同时摘掉工作区归属,所以删掉的会话不会在重启后以「未分组」形式回来。日志已被外部清理的幽灵条目同样会摘掉归属。
- 非 uuid 形态的会话 id 也能删(如 fusion-worker-<uuid>):磁盘 id 走路径安全校验而非 uuid 形态校验,故不会漏删。

License

MIT
预览分享卡片长什么样 ↓ao882866-ux/dsh-archive-trash
分享 · DeepSeek Harness Hub
ao882866-ux/dsh-archive-trash

为 dsh 已归档会话添加垃圾桶图标,一键删除,极简会话管理。

这是你的仓库?认领条目

回到顶部