npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-session-pruner

v0.3.3

Published

会话生命周期管理:one-shot 完成归档/删除、可续与主会话闲置归档、容量保底、连带清理 projcache——全类型生命周期管理。

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/<工作区>/<会话ID> ~/.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-settingsschemastery)由 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