前言¶
DSH 的「归档」只是一个标签。它会话写进取 storages/workspace.json 的 archivedSessionIds 之后,官方的 archived-session-gate 保证的是这个会话「在还原前不再跑模型步骤」,但它不保证这个会话不再占磁盘:会话日志仍留在 .dsh/sessions/<工作区>/<会话id>/,投影记录仍留在 .dsh/storages/session_projcache/sessions/<id>.json。
问题在于投影记录用的是 JSON 后端,官方注释写明读写共享统一的内存状态,也就是说全部记录常驻内存。按 README 里的实测:2395 条记录 / 169.5 MB JSON,其中 126 条已归档的记录占 40.8 MB(24.1%),条目数只占 5%。归档的大多是长篇会话,恰好是最占地方的那批。
下面介绍的沉眠阁(slumberpavilion)就是处理这件事的:把已归档会话的日志目录和投影记录真正移出 .dsh,落到 ~/DSH-Archive,并提供读取、还原、删除工具。维护者是 AngleNaris,分类为记忆。
这是什么¶
沉眠阁是一个 DSH 插件,做的事是三件事:每隔一段时间检查 archivedSessionIds,发现新归档的会话;把它的日志目录与投影记录移动到 ~/DSH-Archive(不是删除);在 manifest.json 里记下来源与去向,随时可以还原。
它保持免配置:安装并加载后即可使用,没有独立的用户配置界面,也不需要用户设置参数。搬移是插件的设计行为,不是可选动作。
核心功能¶
加载约 15 秒后首次扫描,之后后台按 20 秒间隔检查归档列表。插件只搬移已被 DSH 标记为归档的会话,不会主动把普通会话写成归档。使用 DSH_HOME 的宿主从该目录读取归档区。
搬移保留原文文件与还原清单。archive_delete 是单独的永久删除操作,不可恢复,且工具调用没有二次确认。
读取归档内容¶
这是插件区别于「直接把文件挪走」的部分:它把归档会话的多帧 zstd 日志按帧魔数 28 B5 2F FD 切开逐个解压,因为 DSH 的 session.v4.jsonl.zstd 是边写边追加的多帧格式,Node 的 zstdDecompressSync 只解第一帧就收工。README 里的实测结果:60.6 MB 的会话共 31,528 帧、56,701 行、零失败,压缩比约 ×3.8。
Agent 工具¶
插件注册五个工具,可直接在对话里调用:
| 工具 | 作用 |
|---|---|
archive_list |
列出归档会话,按体积降序 |
archive_read |
读一个归档会话,支持 keyword 过滤、compact 只留对话轮次、maxChars 逐条截断 |
archive_session |
执行归档:标记 + 立刻搬走,不用等后台扫描 |
archive_restore |
还原归档:搬回 .dsh、撤销归档标记、清清单 |
archive_delete |
永久删除一个归档会话(日志 + 投影文件 + 清单条目) |
单次命中是硬约束:ID 或片段模糊命中多条时拒绝执行并列出候选,避免搬错会话。归档正在跑的会话默认拒绝(WorkspaceActiveSessionError),加 stopActivity=true 则先请求停掉它的工作再归档。拒绝归档正在执行这条工具的那个会话。
archive_session 走宿主的 ctx.workspaceRegistry.archiveSession(),所以归档状态由 DSH 自己写进 workspace.json,不靠改文件;标记落盘后插件立刻执行一轮 sweep(),返回里报出最终目录。
archive_restore 的顺序是「搬文件 → unarchiveSession() → 清清单」。目标位置已有同名目录时拒绝;清单里记着原始 from,优先搬回原位,没有记录时退回 .dsh/sessions/<工作区>/<会话 ID>;投影记录跟着搬回,目标已存在的不覆盖。撤销标记失败时仍然搬文件,并在返回里明确警告「它仍算已归档,请在界面取消归档」。
安装与启用¶
在 DSH 插件商店安装沉眠阁并由宿主加载即可,无需填写配置或修改插件参数。
手动集成到 profile 时,在该 profile 目录安装 npm 包:
npm install slumberpavilion
然后在 profile 的 package.json 里把包装进 bundles:
"dependencies": {
"slumberpavilion": "^0.1.1"
},
"dsh": {
"profile": {
"bundles": [
"...",
"slumberpavilion"
]
}
}
重启 DSH。本地开发时可以用 file: 依赖加一条符号链接代替 npm 安装:
ln -s ../plugins/slumberpavilion ~/.dsh/profiles/desktop/node_modules/slumberpavilion
典型用法¶
归档搬移默认自动进行,无需额外启用。装好之后通常的路径有两种,效果一样。
方式一是命令行,不依赖 DSH,随时可用:
node lib/cli.js list 20
node lib/cli.js read f8ab825e 上下文压缩 50
node lib/cli.js info f8ab825e
方式二是对话里直接调工具。要归档某个会话,先跑一次带 dryRun=true 的 archive_session 看清目标,确认无误后去掉 dryRun 执行;要还原同理先 dryRun 再看目标目录。archive_delete 不可恢复且没有二次确认,调用前同样务必先跑 dryRun=true。
手动还原的话,manifest.json 里每个条目都记着 from(原路径)与 to(归档路径),把 to 移回 from,再去界面里取消归档并从清单删掉那一条。
兼容性¶
- README 声明的 DSH 宿主范围为
>=0.2.1-rc.2 <0.4.0-0;已记录的桌面实测版本仅为 DSH 0.2.1-rc.3。范围声明不代表其他版本均已完成实测。 - Node.js 要求
>=22.15.0,用于读取 zstd 会话日志;桌面版以其内置 Node.js 为准。 - 插件依赖宿主的
tools、workspaceRegistry服务,以及sessions、storages/workspace.json和storages/session_projcache/sessions的内部布局。宿主改变这些接口或文件布局时需要重新验证兼容性。 package.json在dsh.engines.dsh声明宿主范围,并在顶层engines.dsh保留同值供兼容读取。这两处都是发布元数据,无需用户配置。- 源码里的
Configschema 与cordis.patch.yml参数用于 Cordis 宿主装配、内部实现和测试,不代表本插件提供了用户设置界面。
已知边界¶
扫描只处理「已归档」的会话,归档标记由 DSH 写。移动后 workspace.json 里的 archivedSessionIds 不会清理,会指向一个不存在的会话;README 说明实测这不影响启动,列表按投影记录渲染,记录没了就不显示。
若会话日志已被 DSH 重新折叠出新的投影记录,下次扫描会再搬一次。判据覆盖顶层与各批次目录的 manifest.json,早先只读顶层那份,老批次条目会被当成没搬过、每轮空转一次。
archive_session 只认磁盘上还在 .dsh/sessions 里的会话;只剩归档副本的请用 archive_list / archive_read。
适用场景与注意¶
适合那些会话数量多、长篇归档会话占比高、因此 session_projcache 常驻内存明显吃紧的 DSH profile。这类会话继续留在 .dsh 里不会带来任何价值,搬走之后既省内存也能在需要时读回来。
使用前需要注意几点。插件以当前 DSH 进程的权限运行,装的是它会自己搬文件、改清单,archive_delete 不可恢复且没有二次确认,因此安装前应先检查源码与许可证(本项目为 MIT)。执行归档、还原、删除操作前先用 dryRun=true 看目标路径。
另外排障信息写在 %TEMP%\slumber-pavilion-diag.log,里面记一行 apply、一行 defineTool 是否取到、每个工具是否注册成功,改了代码重载插件后先看这个文件。
结尾¶
沉眠阁把「归档」从一个只改标签的动作,变成一个真正把日志与投影记录移出加载路径的动作;需要时能再读回来、搬回去或彻底删掉。项目地址:插件目录页 https://www.skillhub.cn/plugins/AngleNaris/slumberpavilion ,源码 https://github.com/AngleNaris/slumberpavilion 。