DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

Yelj20001223 /

Yelj20001223/dsh-plugin-session-delete

Verified

Permanently delete DSH conversations from the web GUI session row menu: batch selection, running-turn refusal, and automatic switch away from a deleted chat

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@360c2bee

dsh-plugin-session-delete

彻底删除对话 —— 给 DSH Web GUI 的会话右键菜单加一个「删除对话…」入口,把选中的会话从磁盘上真正删掉。

DSH 原生只有「归档」(archive):归档只是把会话从侧栏隐藏,日志文件仍然留在 ~/.dsh/sessions/ 下。官方在 @deepseek-ai/dsh-session-persistence-jsonl 的已知限制里写得很明白:"Nothing deletes session files — logs accumulate under root until removed externally; the seam has no deletion API." 这个插件就是那个 external remover。

它做什么

  1. 右键菜单入口:侧栏每个会话行的「…」菜单底部多一项「删除对话…」(排在官方「归档会话」之后)。
  2. 多选 + 二次确认:弹框列出全部会话(含已归档、子会话),可以多选;必须手动输入 DELETE 才能确认,删之前清清楚楚告诉你后果不可撤销。
  3. 真正落盘删除:宿主侧删掉该会话自己的目录(<root>/--<project>--/<id>/,含全部格式代际的日志),并清掉投影缓存里对应的那条记录。
  4. 拦住正在跑的会话:有活动 Agent(正在产出一个回合)的会话会被拒绝(blocked),不会去动一个还有写入者在缓冲的日志。只是"打开着"不算 —— 那正是右键的那一行,空闲时不持有写入者。
  5. 删完自动切走:如果删掉的正是当前打开的那个对话,主面板会自动回到空白新会话页。
  6. 列表立即同步:删除后宿主发出 api-session/removed,所有已连接的页面无需刷新即可移除该行。

安装

# 从仓库根目录(<harness>)执行;desktop profile 由桌面端管理,用桌面端命令行
dsh plugin --profile desktop add link:<仓库路径>/session-delete

用 link:,不要用 file:。 两者差别是致命的:

写法 结果 改完代码之后
file:<路径> pnpm 建真实副本 必须重新 add 才生效,否则跑的还是旧字节
link:<路径> Windows 上建目录联接 立即生效(配合 HMR 甚至不用重启)

卸载即还原:

dsh plugin --profile desktop remove dsh-plugin-session-delete

安全设计

删除是不可逆的,所以宿主侧不信任客户端送来的任何路径,只信任两件东西:持久化后端的 stat() 和日志自己的 header。

风险 处理
客户端伪造路径 / 目录穿越 客户端只能送会话 id。路径由 root + header 的 cwd + header 的 id 重新推导,id 走与后端逐字节相同的 ~XXXX 转义,且必须严格位于 root 之内。
任意字符串被当作删除成功 stat() 找不到对应日志的 id 一律返回失败,绝不报告成"已删除"。
删到还有写入者的会话 有活动 Agent(正在产出回合)的 id 在探测前、删除前各拦一次,返回 blocked。只是打开着、空闲的会话不拦——它不持有写入者,且删完会清掉主面板。
跨站页面 / DNS rebinding 打到本机端口 路由只接受 Host 等于实际监听地址、且 Origin(若存在)同源的请求;否则 403。
删错目录 只删整个会话目录,且删前先 stat 证明它是目录;删完不动任何兄弟目录。

路由只有两条,都挂在同样的校验之后:

GET  /session-delete/candidates   → { ok, sessions: [{ sessionId, title, cwd, origin, createdAt, sizeBytes, archived, running }] }
POST /session-delete/delete       → { ok, deleted[], blocked[{sessionId, reason}], failed[{sessionId, message}] }
       body: { "sessionIds": ["<id>", …] }   (1..500)

结构

session-delete/
├── package.json          # dsh.bundle.patch + dsh.client 声明
├── cordis.patch.yml      # 往 profile 里 insert 一行宿主插件
├── lib/index.js          # 宿主半:两条 HTTP 路由 + 删除例程(手写 ESM,无需构建)
├── lib/client.js         # 浏览器半:lazy-CJS bundle(手写,无需构建)
└── tests/                # 两个可执行规格

lib/ 是提交进仓库的产物,没有构建步骤:宿主半是普通 ESM,浏览器半是 window.__ModuleLoader__.load({ id, factory }) 形式的 lazy-CJS,require() 只取平台基线里的 react 与 @deepseek-ai/dsh-client-ui-primitives(不打包自己的副本)。改完源码直接生效,HMR 会重挂。

测试

node tests/host.spec.mjs      # 宿主半:在临时目录里种一份真实会话数据的副本,跑真 HTTP
node tests/client.spec.mjs    # 浏览器半:假 module loader + 极简 hook dispatcher,跑真组件

两个都是自包含的:

  • host.spec.mjs 从 $DSH_HOME/sessions(或 DSH_SESSIONS_DIR)只读复制样本到系统临时目录,全程不碰真实会话;覆盖候选列表、请求加固、blocked 语义(跑着的拦、开着的放行)、永久删除、列表同步、目录穿越与"日志 header 指名根外路径"的 containment 用例、以及卸载时路由注销。

  • client.spec.mjs 需要拿到 @deepseek-ai/dsh-client-ui-primitives 的导出面,按此顺序找:DSH_PRIMITIVES_PATH → 已安装的 profile → shipped app.asar(后者优先用运行时自己的 asar 感知 fs,普通 Node 下退回本仓库自带的 asar 索引读取器)。用桌面端自带的运行时跑最省事:

    # Windows
    $env:ELECTRON_RUN_AS_NODE=1; & '<安装目录>\DeepSeek Harness.exe' tests\client.spec.mjs
    

    覆盖入口契约、中英文案 key 对齐、确认门槛、删除往返、以及被拒绝后弹框保持打开。

已知限制

  • 删除不可撤销:没有回收站。lib/index.js 的删除是 rm(dir, { recursive: true, force: true })。
  • 只删会话日志目录:附件(~/.dsh/attachments/)与工作区记录不做级联清理,会话消失后它们不再被引用。
  • 子会话可单独删除:列表里带 subagent 标记的会话也是独立目录,可以选;删父会话不会连带删子会话。
  • 删掉打开着的空闲会话依赖两层保护:客户端会清掉主面板;写入者自己的文件句柄会让删除在 Windows 上直接失败(另一个句柄没有删除共享就 unlink 不掉),而不是删一半。所以真遇到"会话开着且写入者尚未释放",结果是明确报错,不是静默损坏。
  • 运行中判定是进程内视角:另一个 DSH 进程正在写的会话,本进程看不到它的 Agent,因此判定为可删。后端有单写者锁,这种情形属于"操作者明确要删"。
—/ 5

No ratings yet

Verified DSH bundle

Commit 360c2bee5074

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout