前言¶
在本地调试或长时间运行 DSH(DeepSeek Harness)时,侧边栏的会话列表会逐渐积累大量废弃会话。只删磁盘上的 session*.jsonl 文件,内存里还保留着进程内的会话条目和 Agent 引用,导致列表里仍然出现这条记录,点进去还能读到内存内容。此外,投影缓存、工作区记账与全文索引里的残留也会一直存在。dsh-session-purge 插件通过右键菜单提供了一套完整的清理流程,删除时会话目录、投影缓存、工作区记账、进程内会话条目与 Agent 引用,以及全文索引,确保只影响目标会话。
插件定位¶
devve-1/dsh-session-purge 是 DeepSeek Harness 的客户端插件,由维护者 DEVVE-1 开发。它通过侧边栏右键菜单提供“删除会话”入口,二次确认后清理该会话的所有持久化痕迹,同时保证其他会话不受影响。
核心功能¶
删除范围¶
删除操作覆盖以下位置:
- 会话目录:
$DSH_HOME/sessions/<project>/<sessionId>/,包括所有代际的session*.jsonl[.zstd],目录删空后顺带回收空掉的 project 目录。 - 投影缓存:
$DSH_HOME/storages/session_projcache/sessions/<sessionId>.json,先走 storageDomain 的内存表写链,再兜底删除文件。 - 工作区记账:
$DSH_HOME/storages/workspace.json中该会话在sessionIds、pinnedSessionIds、archivedSessionIds里的全部引用。 - 进程内状态:
ctx.sessions与ctx.agents中的活条目,触发session/disposed事件,客户端会话列表同步移除该行。 - 全文索引:主动触发一次索引对账,让该会话的 FTS 记录立刻消失。
附件($DSH_HOME/attachments)与派生图片缓存($DSH_HOME/cache)是多会话共享的,不会清理。
安全边界¶
- 会话 id 先过正则
^[A-Za-z0-9][A-Za-z0-9._-]*$(长度 ≤ 200),再映射成单个路径段;删除前断言目标确实是会话根目录下以该 id 命名的一级目录,杜绝路径穿越。 - 不以“运行时还持有这个 Agent”为拒绝条件。DSH 的 Agent 注册表会把进程内打开过的会话一直持有着,真正该拦的是“有东西在跑”,由
workspace/session-activity报出。 - 会话有在跑的工作(turn / job / subagent / schedule):确认后走和归档同一条
workspace/session-stop通道,然后轮询等待清空(默认最多 4s,可用settleMs调),停不干净就报session-active且不动任何文件。 - 删除前先把活会话摘掉。会话列表是把进程内还活着的会话无条件并进来的,只删磁盘的话列表里会一直留着这一行、点开还能看到内存里的内容。摘掉之后
session/disposed会发出去,客户端自行去掉那一行,jsonl 后端关掉写句柄。 - 摘活会话会让写句柄异步收尾(
writer.close()把缓冲落一次盘),所以删完文件后进行自适应复查:默认每 40ms 探一次会话目录,连续两轮干净才收工(从没摘过活会话的只要一轮),总预算residualBudgetMs(默认 1.5s)兜底,清掉的都记进residualPaths。 - 搜索索引对账给
searchBudgetMs(默认 800ms)的同步预算:冷索引第一次对账可能要读一遍全部会话日志,超预算就中止并把对账丢到后台继续,响应不等它。索引本来就在每次查询前自行对齐,所以延迟清掉不会让被删内容被搜出来。 - 被删的 id 进一个进程内墓碑集合,并挂一条
agent/pre-step拦门(形状同归档会话的 gate),迟到的投递只会以blocked收场。 - HTTP 接口只在 webServer 上注册一条 exact 路由
/session-purge,并要求:POST+application/json+Host必须是回环地址(localhost/127.x/::1)+Origin与Host同源 +Sec-Fetch-Site不能是cross-site。不设置任何 CORS 头。
接口¶
POST /session-purge
content-type: application/json
{ "sessionId": "session-...", "stop": true }
200 { "ok": true, "result": { sessionId, removedPaths, residualPaths, projectionCache,
detachedWorkspaces, detachedLive, searchReconciled,
activityStopped, liveAgent, elapsedMs } }
409 { "ok": false, "code": "session-active", "message": "...", "activity": [...] }
400 / 403 / 405 / 413 / 415 / 500 其余校验失败
searchReconciled 取 done(索引已对完账)/ background(超预算转后台)/ unavailable(索引不可用或被关闭)。elapsedMs 是这次删除在 Host 侧的实际耗时。
安装与启用¶
插件包已经是一个可直接加载的 bundle(package.json 的 dsh.bundle.patch + dsh.client),Host 半边 lib/index.js、浏览器半边 lib/client.js 都是最终产物,无需构建。
通过 plugin_manager 安装¶
从 GitHub 仓库装(plugin_manager 的 install_bundle 支持 git 地址):
install_bundle target = https://github.com/DEVVE-1/dsh-session-purge
本地目录装(target 填本目录的绝对路径):
install_bundle target = <本目录绝对路径>
通过本地脚本安装¶
进入插件目录,用运行时自带的 pnpm 把本目录作为 file: 依赖装进 profile:
cd <本目录>
$node = "$env:DSH_HOME\dsh-runtimes\dsh-primary-runtime\dependencies\node\bin\node.exe"
& $node .\install.mjs --dry-run
& $node .\install.mjs # 默认 desktop profile,可加 --profile <name>
脚本会:用 pnpm 把包名追加到 dsh.profile.bundles → 按哈希把包内容同步进安装目录 → 复查。它要写 profile 目录(在 DSH 工作区之外),所以只能由你自己执行。
手动安装¶
cd $env:DSH_HOME\profiles\desktop
pnpm add file:<本目录绝对路径>
然后把包名加进 profile package.json 的 dsh.profile.bundles:
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"session-purge"
]
}
}
Live profile 会即时 recompose;否则重启应用。装好后刷新一次页面,浏览器半边才会进入模块表。
典型用法¶
安装完成后,在左侧边栏右键点击某个会话,菜单里会出现「删除会话」选项。点击后弹出二次确认框,确认后执行删除。该会话及其所有痕迹会被清理,其他会话保持不变。
适用场景与注意¶
- 适合需要频繁清理废弃会话的 DSH 本地开发场景。
- 插件以当前 DSH 进程权限运行,安装前建议检查源码与许可证。
- 插件依赖内部形状(
store+detachEntered),上游改结构时会静默降级而不是报错。 - 删除时如果会话有在跑的工作,会先尝试停止,停不干净则拒删并返回
session-active。
结尾¶
dsh-session-purge 通过侧边栏右键菜单提供了一套完整的会话清理流程,确保删除会话时所有持久化痕迹都被清干净,不影响其他会话。如需查看源码或更新版本,可访问插件目录或 GitHub 仓库。