DSH Plugins Marketplace

DSH Plugins

Plugins

/

dsh-session-reaper

G

dsh-session-reaper

Discovered

Session Deletion Plugin - By default, dsh does not allow deleting sessions. This plugin enables you to delete sessions. Deleted sessions will be moved to the Recycle Bin, where they can be restored or permanently deleted.

dsh-session-reaper

license node

给 DSH Web 侧栏的会话加上「删除」,并且删得可回退。

DSH 本身没有删除会话的能力:ui-workspace 的已知限制里写明「sessions can be archived but never deleted」,持久化层也明确不留删除 API。归档只是把会话从列表里藏起来, 日志仍留在 ~/.dsh/sessions 下持续占盘。这个插件补上这段缺口。

行为

  • 会话行「⋯」菜单里多一项 删除会话…(order 500,排在归档之后);
  • 点它弹确认框,显示标题与 session id;
  • 确认后会话日志整体移入回收站,不是就地删除;
  • 侧栏底部有 回收站 入口,带数量角标;
  • 回收站里可以逐条 恢复 或 彻底删除(需输入 DELETE 二次确认)。

不做批量删除,不做自动过期清理——回收站只在你手动清理时变小。

安装

安装的本质只有两步:让 pnpm 把包拉进 profile 的 node_modules,再把包名加进 bundles。 难点只在于「用哪一个 pnpm」——DSH 桌面版自带一套 node/pnpm,但装在哪个盘因机器而异, 所以下面的命令不写死任何路径。

第 1 步:找到能用的 pnpm

先看系统里有没有:

node --version
pnpm --version      # 或 npm --version
  • 有 node 和 pnpm(或 npm) → 直接用它们,跳到第 2 步。 DSH 自带的 node 是 24.x,系统 node 只要是 20 以上就没问题。

  • 没有 → 用 DSH 自带的那套,先把 DSH 安装目录记成 $DSH_HOME:

    $DSH_HOME = "D:\dsh"          # ← 改成你自己的实际路径
    & "$DSH_HOME\resources\runtime\primary-runtime\dependencies\node\bin\node.exe" `
      "$DSH_HOME\resources\runtime\primary-runtime\dependencies\pnpm\bin\pnpm.cjs" `
      --version
    

    能打印出版本号(形如 11.x)就说明这两个路径是对的。

第 2 步:装进 profile

# Windows
cd $env:USERPROFILE\.dsh\profiles\desktop
# Linux / macOS
cd ~/.dsh/profiles/desktop

然后二选一:

# 系统有 pnpm
pnpm add github:GGBound-1229/dsh-session-reaper
# 系统有 npm,没 pnpm
npm install github:GGBound-1229/dsh-session-reaper
# 两个都没有,用 DSH 自带的
& "$DSH_HOME\resources\runtime\primary-runtime\dependencies\node\bin\node.exe" `
  "$DSH_HOME\resources\runtime\primary-runtime\dependencies\pnpm\bin\pnpm.cjs" `
  add github:GGBound-1229/dsh-session-reaper

第 3 步:把包名加进 bundles

打开 ~/.dsh/profiles/desktop/package.json,在 dsh.profile.bundles 数组末尾加一行:

"bundles": [
  "@deepseek-ai/dsh-base",
  "@deepseek-ai/dsh-web-app",
  "dsh-session-reaper"
]

这一步不能省。 只加 dependencies 不加 bundles,包在磁盘上但 DSH 不会加载它; 只加 bundles 不加 dependencies,DSH 找不到包、启动报错。

第 4 步:重启 DSH

完全退出再打开。重启后侧栏会话行的「⋯」菜单里应该多一项 删除会话…。

装不上时的排查顺序

  1. pnpm add 报权限错误 → 用管理员权限重开终端,或确认 .dsh 目录可写;
  2. pnpm add 报找不到 git → 先装 git,GitHub 安装方式依赖它;
  3. 装完 node_modules 里有目录但菜单没变化 → 十有八九是漏了第 3 步的 bundles;
  4. 改了代码但不生效 → pnpm 的 file: 依赖是复制不是链接,改完要重新装一次。

删除的执行顺序(不要改动)

  1. workspaceRegistry.stopSessionActivity(id) —— 停掉这个会话上还在跑的工作;
  2. sessionPersistence.flush() —— 把待写数据落盘,避免移走目录后仍有写句柄;
  3. 校验路径确实落在 sessionsRoot 之内;
  4. 整个会话目录 rename 进回收站(跨卷时退化为复制+删除);
  5. workspace.detachSession(id) —— 走官方实体写路径解绑记账;
  6. workspaceRegistry.archiveSession(id) —— 计入归档集合,让客户端立刻隐藏这一行。

这个顺序是有原因的。WorkspaceRegistry.bootstrap() 在启动时会按 cwd 重新枚举持久化层里 所有 header,给工作区重新记账。所以日志目录必须先消失,否则下次启动这个会话会从磁盘 被重新扫回来、重新挂到工作区——看起来就是「删了又复活」。反过来(先解绑、再移目录)如果 中途失败,就会留下「记账没了但文件还在」的半死状态,下次启动一样会复活。

第 5 步失败时,第 4 步的移动会被回滚,不留下两边不一致的状态。

第 6 步解决的是纯客户端问题,不是可有可无的收尾,见下节。

为什么删除后要顺手归档

删完会话,服务端数据是对的:日志进了回收站、workspace.json 里也没有它了。 但界面上会冒出一个「未分组」分组,里面挂着刚删掉的会话,直到下次启动才消失。

原因在客户端。侧栏分组用的是 owningGroupKey():拿会话 id 去各 workspace 的 sessionIds 里找归属,找不到就返回空串,而空串正是「未分组」的 key。 与此同时,客户端的会话投影(list.ids)由另一条数据流维护,它不会因为我们移走了 日志就立刻知道这个会话没了。于是这个会话「可见但无归属」,正好落进 groupByWorkspace() 收集 stray 的那一支。

归档是唯一能立刻把会话从列表里藏起来、又不依赖投影重建的机制—— sessionVisible() 对默认过滤器直接返回 !archived.has(id)。 所以删除时一并归档,恢复时取消归档,彻底删除时把 id 从集合里摘掉免得无限增长。

归档只影响可见性,不动日志、不改工作区记账,当「界面上的临时开关」用是安全的。 归档失败也不致命:界面上会暂时多一个未分组条目,重启后自愈。

存储

  • 会话日志:~/.dsh/sessions/--<normalized-cwd>--/session-<uuid>/
  • 回收站:~/.dsh/session-reaper/
    • entries/<ISO时间戳>__<sessionId>/ —— 移过来的会话目录本身
    • index.json —— 条目索引(标题、原路径、大小、删除时间)

恢复需要 index.json 里的 originalDir,所以要手工恢复请用它,别只搬目录。

端点

全部挂在 /dsh-session-reaper 下,每个都过 connection.requestRejection 信任围栏:

方法路径作用
GET/list列出回收站
POST/delete{sessionId} 移入回收站
POST/restore{entryId} 从回收站恢复
POST/purge{entryId} 彻底删除

安全边界

  • 不给模型注册任何工具,模型无法自己调用这个插件;
  • 只接受本机已认证客户端(connection.requestRejection);
  • session id 必须匹配 ^session-[0-9a-f-]{36}$;
  • 所有文件路径 path.resolve 后必须落在 sessionsRoot 或回收站之内;
  • 删除路径里不存在对会话目录的递归删除,只有 rename;递归删除只出现在 「从回收站彻底删除」这一处,且需要输入 DELETE;
  • 零第三方运行时依赖,只用 node:fs / node:path / node:os;
  • apply() 全程 try/catch,插件任何故障只记一行日志,DSH 照常启动。

已知坑(踩过,别再踩)

Cordis 的 ctx.inject 必须一个服务一个声明。 一次性声明多个时,只要其中一个服务 不存在,整个插件会被拒绝挂载,而且不报错。所以这里对 sessionPersistence / workspaceRegistry / webServer 各调一次 ctx.inject。

客户端插件只能 require('react') / require('react-dom')。 拿不到 @deepseek-ai/dsh-client-ui-primitives,也拿不到内置包注入的 hooks(比如菜单的 useMenuOpenState)。所以 UI 用原生元素自绘,菜单项与对话框之间用一个模块级 store 通信。

安装后要跑一次 pnpm install。 profile 里的 file: 依赖由 pnpm 复制进 node_modules,手工建 junction 不会被登记,DSH 的 bundle 解析器不认识这个包。

关闭

在 profile 的 cordis.patch.yml 里给这一行加上 enabled: false:

- id: dsh-session-reaper
  name: dsh-session-reaper
  config:
    enabled: false

或者直接从 profile package.json 的 dsh.profile.bundles 里删掉本包名。

Comments

Loading…

Similar plugins

DSH-SessionDelete

by yauntyour

DSH 会话删除插件:在「归档会话」下方新增「删除会话」

Manifest valid

★ 0

MIT

TypeScript

Oct 18, 2026

dsh plugin --profile web add dsh-session-delete

by Github-CJX

DSH 会话管理插件归档/活跃会话、查看归档对话内容、删除会话。

Terminal & ClientsManifest valid

★ 0

MIT

JavaScript

Sep 9, 2026

dsh plugin --profile web add @local/dsh-session-dustbin

by TheHeartFickle

DSH 会话管理插件 —— 对话回退 + 归档会话,长会话可回滚、可整理。

Sessions & MessagesManifest valid

★ 0

MIT

JavaScript

Sep 29, 2026

dsh plugin --profile web add @the-heart-fickle/dsh-session-manager

by WovenJunct

一个简单的删除dsh会话的插件,简单可用。

Development & InfrastructureManifest valid

★ 7

MIT

JavaScript

Oct 6, 2026

dsh plugin --profile web add dsh-plugin-simple-delete-session

by ShiraGawaAnri

DSH 会话/归档清理插件:在 **设置** 面板里新增两个页面,用来查看并清理 DSH 的残留会话与归档会话。

Manifest valid

★ 0

MIT

JavaScript

Aug 16, 2026

dsh plugin --profile web add @dsh-external/dsh-session-cleanup

by masknull

DSH 插件:在侧栏会话行的 ⋯ 菜单中增加「删除会话」(永久删除,不可恢复),不接管也不禁用任何官方插件行。 | DSH plugin: add a permanent "delete session" action to the sidebar session row menu, with zero official-row takeover.

Sessions & MessagesManifest valid

★ 0

NOASSERTION

JavaScript

Sep 28, 2026

dsh plugin --profile web add dsh-delete-session