DeepSeek Harness 会话清理插件:dsh-session-purge

前言

在本地调试或长时间运行 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 仓库。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye