Passer au contenu principal
D

dsh-session-delete

dubai1210/dsh-session-delete

Deletes a DSH session from the session menu, and lists the workspace files that session touched so you choose which ones to remove with it. Deletion is permanent (no undo), and files written through shell commands are not tracked.

Installer

dsh plugin --profile web add github:dubai1210/dsh-session-delete

README

DSH Session Delete

Listed on dsh-plugin.org

在会话「⋯」菜单的「归档会话」下面多一项 删除会话:点一下、确认一次,这个会话的对话记录消失、它在工作区留下的过程残留被清掉,它做出来的成果保留。

DSH 自带的「归档」只是把会话从列表里挪走,文件还在、可以取消归档恢复。这个插件补上真正不可逆的那一步。

功能

  • 菜单项插在 sidebar.workspaces.session.menu.item 插槽 order 410,即「归档会话」之后、「会话 ID」之前
  • 垃圾桶图标,点击先关闭菜单,再弹出二次确认框
  • 确认框打开时先做一次只读扫描,列出「会删掉哪些过程文件」「会保留多少成果文件」,可取消勾选只删对话
  • 确认后 Host 侧一次性完成清理,所有已打开的窗口立刻把该行移除

删除范围

对象处理
对话记录~/.dsh/sessions/<project>/<session-id>/ 整目录删除(session.v4.jsonl.zstd 等世代日志)
投影缓存storages/session_projcache 里该会话的行(含投影后的消息正文)
上下文洞察缓存storages/dsh-context/overview-cache.v1.json 里该会话的条目,否则「上下文洞察」仍能列出它
工作区里的过程残留该会话新建的脚本、下载的工具、临时文件和脚手架目录,逐个 rm,随后清掉因此变空的目录(不越过会话 cwd)
正在运行的 agent先 workspace/session-stop(回退 cancel({kind:"user"}) + agent.scope.dispose()),再等 350 ms 让最后一次 flush 落盘,避免删完立刻被重建
工作区归属从每个工作区记录的 sessionIds 中 detachSession
归档 / 置顶集合全局 archivedSessionIds、pinnedSessionIds 中移除
客户端列表ctx.emit("api-session/removed", id) → 所有窗口实时移除该行

成果文件、你原来就有并被它改过的文件,都不在删除范围内。详见下一节。

删除不进回收站,对话记录不可恢复。

哪些文件算残留,哪些算成果

判定在 lib/classify.js,先保后删:

一律保留

情况理由
会话修改过的文件(kind === "modified")改的是你的东西,删了无法还原
通过 present 工具交付的文件会话明确交给你的成果
最后一次回复正文里点名的文件同上
位于 git 仓库内的文件是项目代码,能靠 git 回滚
文档/数据/媒体扩展名:.docx .xlsx .pptx .pdf .md .txt .csv .png .jpg .mp4 .json .yaml .html 等成果形态
判不出来的扩展名宁可留着

会被清理(仅当文件是该会话新建的)

类型例子
脚手架目录内的文件node_modules/ dist/ build/ tmp/ temp/ .cache/ __pycache__/ .venv/ target/ coverage/
脚本/源码.js .mjs .cjs .ts .py .ps1 .sh .bat .rb .pl .php .lua .go .rs .java …
下载或构建产物.exe .msi .zip .7z .tar .gz .apk .jar .whl .dll .so …
临时文件.log .bak .tmp .out .err .orig .rej .swp
隐藏文件以 . 开头的
因此变空的目录顺手删掉,不越过会话 cwd

「新建」的判定:该会话对它的第一次操作是写、且此前没读过它 —— DSH 要求覆盖已有文件前先读,所以「写而无读」即表示文件原本不存在。

做不到的部分(明确写在这里,避免误解):

  • 通过 shell 命令写出的文件不在归属范围内。bash / ops_bash 的命令行只有字符串,没有可解析的目标路径,插件不会去猜。所以 pip install、curl -o、python make.py 产生的东西会留在磁盘上
  • 子会话(subagent)写出的文件不计入父会话;要清就删对应子会话
  • 「修改」类文件只保留、不还原 —— 原内容已被覆盖,本插件不做备份;需要旧版本请靠自己的 git

安装

npm(推荐,插件中心可见「一键安装」):

dsh plugin --profile web add @l1vide/dsh-session-delete

源码安装(GitHub):

dsh plugin --profile web add github:Dubai1210/dsh-session-delete

本地目录安装(开发调试):

dsh plugin --profile desktop add link:/path/to/dsh-session-delete

安装后刷新一次 DSH 窗口(Ctrl+R)让 client bundle 加载;如果菜单里没有出现新项,重启一次 DSH。

使用

  1. 在左侧工作区列表里找到目标会话行,点行尾的「⋯」
  2. 选择「归档会话」下面的「删除会话」
  3. 弹窗会先扫一次工作区,列出要清的过程文件;不想清就取消勾选
  4. 点「删除」
  5. 该会话行消失,对话记录和过程残留同时被清掉,成果文件还在

权限与风险

  • Host 半只注册同源 HTTP 路由:POST /dsh-session-delete/inspect(只读预检)、POST /dsh-session-delete/delete。同源校验照抄 DSH 官方插件的做法:拒绝 sec-fetch-site: cross-site、origin: null、以及 origin.host 与 host 头不一致的请求
  • 只操作本机 ~/.dsh 下的会话数据、工作区注册表,以及该会话自己留下的过程文件,不发起任何外部网络请求,不依赖任何第三方服务
  • 没有任何遥测、没有后台常驻任务
  • 风险点:删除是永久性的。被判定为「残留」的文件如果没有版本控制,删掉就没了;判定规则和预览清单就是为此存在的

兼容与运行要求

  • DSH:0.2.x(desktop profile 与 web profile 均可)
  • 平台:Windows / macOS / Linux
  • 运行时:Node.js >= 18(Host 半只用 node:fs/promises、node:path、node:zlib)
  • 依赖的服务:webServer、sessions、agents、sessionPersistence、workspaceRegistry、storageDomain,全部来自 DSH 基础 bundle,无额外依赖

能力分类

界面与体验(同时涉及会话与消息的数据清理)

实现说明

bundle 插件,两半:

Host — lib/index.js,导出 apply(ctx),注册两条 webServer exact 路由。删除流水线:

  1. lib/transcript.js 读转录日志(多帧 zstd)拿出该会话碰过的工作区文件
  2. lib/classify.js 把它分成「保留 / 残留」两堆(有 present、末尾回复、git 仓库、扩展名等信号)
  3. 只对「残留」逐个 rm,再清空目录
  4. 停活:ctx.parallel("workspace/session-stop", {sessionId}),失败则回退 agent.cancel() + scope.dispose();随后 sleep(350) 等 flush 落盘
  5. 清索引:session_projcache 行、dsh-context overview 缓存条目、每个工作区的 detachSession、unarchiveSession + unpinSession
  6. 定位会话目录并删除:stat(id).location.path → locate({cwd,id}) → 扫 <root>/*/<id>,三级回退;rm -r 带 3 次重试(Windows 反病毒/索引占用)
  7. 只有目录真的删掉后才 ctx.emit("api-session/removed", id)

会话元数据走 sessionPersistence.stat(id)(冷会话也能查到),查不到时返回 404 + {ok:false, error:"session not found"},客户端显示「删除失败」而不是假装成功。返回值 {ok, live, stopped, removedFiles, cacheRows, contextCacheDropped, headerFound, workspace:{removed,kept,failed,cwd}, error}。

文件归属解析在 lib/transcript.js:会话日志是多帧 zstd(每个追加批次一帧),一次性 zstdDecompressSync 只能解出第一帧,所以这里先按 frame header / block header 走一遍结构定位所有完整帧再逐帧解压;然后扫描 tool/call 事件,按工具名取路径参数(path / file_path / target_file,apply_patch 走 *** Update File: 行),用会话 cwd 规整并拒绝越界路径。

Client — client.js,window.__ModuleLoader__.load 注册懒工厂,往两个插槽注册:

  • sidebar.workspaces.session.menu.item → 删除菜单项(order 410)
  • shell.overlay → 确认弹窗(Modal + 清单 + 清理开关 + 取消/删除按钮)

打开弹窗先 fetch("/dsh-session-delete/inspect") 取清单,确认时 fetch("/dsh-session-delete/delete", {body:{sessionId, clean}}),同源、credentials: same-origin。

目录结构

dsh-session-delete/
├── package.json          # dsh.bundle.patch + dsh.client
├── cordis.patch.yml      # - insert: 宿主插件条目
├── lib/index.js          # Host 半:两条路由 + 删除流水线
├── lib/transcript.js     # Host 半:多帧 zstd 解码 + 会话写文件归属解析
├── lib/classify.js       # Host 半:残留 / 成果判定
├── client.js             # Client 半:菜单项 + 确认框
├── locale/en.json        # meta.title / meta.description
├── locale/zh.json
└── icon.svg

开发

改完文件后重新装一次即可热生效(Host 半需要重新加载):

dsh plugin --profile desktop add link:/path/to/dsh-session-delete

许可证

MIT,见 LICENSE。

Plugins associés