DeepSeek Harness Hub
← 返回列表

mrzhangkris/dsh-session-pruner

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
✓ 可直接安装

DSH 会话生命周期管理插件:one-shot 子代理自动清理 + 容量保底 + 连带清理…

自动检查通过:npm 包已发布且 engines 声明满足基线;该结论来自程序自动检查,未经人工实机验证。 · 最近上游提交 2026/9/3 · 已提供中文文档

DSH 会话生命周期管理插件:one-shot 子代理自动清理 + 容量保底 + 连带清理 projcache,从源头杜绝缓存膨胀卡顿

综合分
31.3
GitHub 分
31.3
用户评分
★ Stars
4
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add dsh-session-pruner
npm 包 dsh-session-pruner 已校验归属本仓库,走 npm 安装最省事
数据截至 2026/9/18(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查✓ 自动检查通过

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

npm 包dsh-session-pruner @ 0.3.3
Node 引擎未声明 engines.node
dsh CLI 依赖未声明 dsh 版本约束
入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/19 04:05:23

用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

dsh-session-pruner

DSH 会话生命周期管理插件 — 全类型会话生命周期管理:one-shot 完成即归档、可续子代理与主会话闲置归档、容量保底、连带清理 projcache 缓存。从源头杜绝会话库堆积导致的卡顿。

每类会话都有明确的归宿:跑完的一次性子代理自动归档、闲置的可续子代理/主会话归档、总量超限按优先级回收。先归档(可恢复)再到期删除,GUI 30 秒内自动同步,全程面板配置、热加载生效。

English · Apache-2.0 · npm · npm version · 更新日志

背景

DSH(DeepSeek Harness)的 session_projcache.json 缓存每个会话的完整投影(token 统计、context 压力等),且存储后端每次写入都全量序列化 + 原子替换。当会话库堆积上千个子代理会话时:

- 缓存膨胀到 100MB+,每次 checkpoint 全量重写 → 主进程 CPU 250%+
- 单线程事件循环被占满 → 所有会话加载卡顿,甚至 GET / 超时

管理会话生命周期(本插件)是治本:会话不堆积 → 缓存条目不产生 → 卡顿不复发。

功能:全类型生命周期

| 会话类型 | 触发 | 动作 | 默认 |
|---|---|---|---|
| one-shot 子代理 | subagent/end / agent/disposed 事件(+ 宽限) | 秒级归档(事件驱动) | 事件 + 3 分钟宽限 |
| continuable 子代理 | 闲置超过 N 天 | 归档(可恢复) | 关闭(0 天) |
| 主会话(main) | 闲置超过 N 天 | 归档(可恢复) | 关闭(0 天) |
| 任意类型 | 总量超过容量保底 | 按「one-shot → continuable → main」+ 最旧回收 | 400 个 |
| 归档目录 | 保留超过 N 小时 | 物理删除 | 24 小时 |

行为说明(v0.2.3+):one-shot 子代理统一按 oneShotMinAgeMinutes(默认 3 分钟)闲置阈值归档,有/无 end-seed 阈值一致。早期版本中「未写 end-seed 的 one-shot 需闲置满 1 小时才归档」的兜底已移除。

归档机制(可恢复)

被清理的会话先移入 ~/.dsh/sessions-archive/(保留 工作区/会话ID 结构)——GUI 立即消失(列表只读 sessions 目录),但文件还在,可手动恢复:

恢复:mv 回 sessions 目录
mv ~/.dsh/sessions-archive// ~/.dsh/sessions//

⚠️ 恢复后请立即 pin(或打开)该会话——打开前它不受 live 保护,
一个扫描周期内若命中闲置判定(如 one-shot 超阈值、main 超闲置天数)
会被再次归档。把会话 ID 加入设置卡片的「Pin 白名单」即可。

也可选「直接删除」(不归档,不可恢复)。

安全保护(双保险)

- 运行中的会话绝不动:live 会话(内存 session store 里还挂着、被打开/加载中)跳过——且 live 检查 fail-closed:store 查询异常时视为 live,不确定时绝不删除
- 闲置 = 最后一次日志写入:闲置按会话日志文件 mtime(最后写入时刻)判定,而非目录 mtime——DSH 追加写 session.jsonl.zstd,活跃会话的 mtime 持续刷新,永不被误判闲置
- one-shot:完成的一次性子代理统一按 oneShotMinAgeMinutes 闲置阈值归档(有无 end-seed 同阈值);容量保底额外跳过缺 session/end-seed 的会话
- 主会话默认不参与容量回收(可配置)
- 单点失败隔离:每个动作独立 try/catch

工作原理

双轨触发(事件为热路径,磁盘为权威)
┌─ 事件驱动(秒级):subagent/end + agent/disposed
│     ├─ 500ms 批窗口合并风暴 → oneShotMinAge 宽限复查
│     └─ 单会话判定(内存优先,磁盘只解压一个)→ 归档
└─ 定时对账(兜底,默认 60min)
├─ pruneArchive:归档目录超期物理删除
├─ 遍历 ~/.dsh/sessions// 解压会话日志(系统 zstd,多帧)
│     ├─ origin: main | subagent       (会话头)
│     ├─ mode: one-shot | continuable  (subagent/descriptor 事件)
│     └─ ended: 是否含 session/end-seed
├─ one-shot 闲置超阈值 ──→ 归档(archiveMode)
├─ continuable/main 闲置 N 天 ──→ 归档
├─ 总量 > cap ──→ 按优先级+最旧 归档(跳过运行中/live)
└─ 每次归档连带:删 projcache 行 + workspace 记账

GUI 同步双轨(变更驱动为主,全量兜底为辅):
- dirty-flag(主路径):host 每次归档写内存变更日志(单调 seq);client 每 3s
轮询 /plugins/dsh-session-pruner/archived,只有有变更才发 refreshList()
+ refreshSubagents()——侧边栏/任务管理面板秒级一致,无变更零 RPC。
- 全量兜底:client 每 uiRefreshSeconds 秒刷新两套数据源——主会话列表
refreshList() + 各父会话子代理目录 refreshSubagents()(dirty-flag
失效(host 旧版/路由不可用)时兜底,无需刷新页面)。

安装

从 npm(推荐)

dsh plugin --profile web add dsh-session-pruner

从源码(开发)

dsh plugin --profile web add /path/to/dsh-session-pruner

安装后重启 dsh web 生效(launchctl kickstart -k gui/$(id -u)/com.deepseek.dsh-web)。

配置(设置面板,热加载)

设置面板

安装后打开 设置 → 插件配置 → 会话生命周期管理 卡片,10 项配置保存即热加载(无需重启)。常用 6 项默认可见,4 项低频兜底收在「高级设置」折叠区(高级项有未保存更改时折叠标题会提示):

| 字段 | 默认 | 说明 |
|---|---|---|
| 扫描间隔(分钟) | 60 | 对账兜底周期(事件驱动为主路径) |
| 容量保底(会话数) | 400 | 超限按优先级+最旧回收 |
| 界面兜底刷新间隔(秒) | 30 | dirty-flag 为主(3s 变更检测),此为全量兜底 |
| 归档保留(小时) | 24 | 归档目录到期物理删除 |
| 归档方式 | 归档 | 归档(可恢复)/ 直接删除(不可恢复) |
| 可续子代理闲置归档(天) | 0 | 超过 N 天未活动归档,0 = 关闭 |
| 主会话闲置归档(天) | 0 | 超过 N 天未活动归档,0 = 关闭 |
| 超限时清理主会话 | 关 | 容量超限时 main 参与回收 |
| one-shot 闲置归档阈值(分钟) | 3 | 所有 one-shot 闲置超 N 分钟即归档(有/无 end-seed 统一) |
| Pin 白名单(每行一个会话 ID) | 空 | 名单内会话永不自动清理(恢复会话后建议立即 pin) |

卡片展开后还有实时状态行(30s 轮询):归档数量与最早到期时间、会话总量(含超限提示)、最近一轮清理数量与时间、已固定数量。

环境变量(兜底,面板配置优先):DSH_SESSION_PRUNER_INTERVAL_MS / _MAX / _CLEAN_MAIN / _ARCHIVE_HOURS / _ARCHIVE_MODE / _CONTINUABLE_IDLE_DAYS / _MAIN_IDLE_DAYS / _ONE_SHOT_MIN_AGE_MINUTES / _PINNED_IDS(逗号分隔)。

日志

输出在 guard 的 server-.out.log:

[dsh-session-pruner] armed: interval=60min cap=400 cleanMain=false
[dsh-session-pruner] hot-reloaded: interval=60min cap=400 ... contIdle=0d mainIdle=0d pinned=0
[dsh-session-pruner] archived a1b2c3d4 (subagent/one-shot) one-shot idle cache=true
[dsh-session-pruner] archive pruned: 2 expired

cache=true/false 表示 projcache 缓存行是否连带清理成功。

测试

npm test               # 回归套件:审计 PoC 校验 + 完整 e2e(隔离的临时 DSH_HOME)
node test/dry-run.js   # 只读扫描全库,验证识别逻辑(不删除)
node test/e2e.js       # 构造 fake one-shot 会话,验证真实清理链路
node test/poc-audit.js # 审计回归:ended 误判 / 双源漂移 / 归档孤儿 / pin 拦截

实现要点

- 多帧 zstd:DSH 会话日志是多 zstd frame 拼接(append 写入),Node zlib 只解单帧,插件调用系统 zstd 命令(macOS: brew install zstd)
- 缓存行删除:storageDomain.get('session_projcache').table('sessions').delete(id) 走官方写链(原子持久化 + 内存同步)
- workspace 记账:归档时同步从 workspace 域移除 sessionId,数据源与磁盘一致
- 零捆绑依赖:运行时模块(@deepseek-ai/dsh-settings、schemastery)由 DSH 宿主提供,插件自身不携带依赖
- 面板与热加载:installSettingsSection + 手写 client 卡片(__ModuleLoader__ bundle),onChange 即时重排定时器

开发文档

- docs/DEVELOPMENT-GUIDE.md — DSH 插件开发实践指南(架构、Host/Client、设置面板、部署运维、坑与解法),为后续插件开发打基础
- docs/DESIGN.md — 设计决策与理由(三层策略、双轨触发、fail-closed 安全矩阵、关键不变量)
- docs/TESTING.md — 测试矩阵、验证金字塔(V0/V2/V3)、发布 checklist
- docs/PROJECT-STATUS.md — 项目状态快照与 backlog,给新贡献者/新会话

已知限制

- 完成事件丢失时(如 host 中途重启),已完成的 one-shot 子代理要等下一轮对账扫描才发现——最坏一个 intervalMinutes(默认 60 分钟)
- mv 恢复的会话在打开前不受 live 保护——请 pin 住度过窗口期(见「归档机制」)
- 依赖系统 zstd 命令
- 根治性修复在上游:projcache 陈旧会话淘汰 / storage-json 增量写,见 deepseek-harness Discussion #1550

许可证

Apache-2.0

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群