dsh-plugin-archive-manager
DeepSeek Harness(DSH)Web 端插件:让会话归档可见、可恢复。
- 原位显示已归档会话:勾选后,已归档会话重新出现在工作区列表的原位置(DSH 底层保留工作区记账槽位),标题比未归档会话更暗。
- 视图选项新增"筛选条件"组:工作区视图选项菜单新增 筛选条件 组,含两个可同时勾选的项:已归档 与 未归档(默认勾选未归档)。勾选"已归档"即可看到已归档会话;不勾选"未归档"则只显示已归档会话。
- 行菜单一键取消归档:已归档会话的操作从"归档会话"变为"取消归档"(带专属图标),点击后持久化恢复会话。
English README: README.en.md。
截图
视图选项中的"筛选条件"组 —— 工作区视图选项菜单新增 筛选条件 组,含两个可同时勾选的项:已归档 与 未归档(默认勾选未归档)。勾选"已归档"即可原位看到已归档会话;不勾选"未归档"则只显示已归档会话。

行菜单一键取消归档 —— 已归档会话的操作从"归档会话"变为"取消归档"(带专属图标),点击后持久化恢复会话,回到原位置。

为什么需要它
DSH 支持归档会话(归档后从所有分组视图消失),但官方界面没有任何查看或取消归档的入口——官方 dsh-client-ui-workspace README 原话:*"sessions can be archived, but archived sessions have no viewing or unarchive surface."* 底层数据模型其实为取消归档预留了位置(归档只把 session id 加入全局归档集合,工作区记账槽位不动,官方注释写明 *"unarchiving restores its position"*),只是缺 API 和 UI。本插件补上这一环。
工作原理
一个 npm 包、两个半区:
| 半区 | 文件 | 职责 |
|---|---|---|
| Host(进程端) | lib/index.js | 给 ctx.workspaceRegistry 补上官方缺失的 unarchiveSession(sessionId)(与官方 archiveSession 完全对称:幂等、持久化、走同一条 domain/changed → host/archived-sessions-changed 广播链路),并注册 exact HTTP 路由 POST /api/dsh-archive-manager/unarchive 供浏览器半区调用。 |
| Browser(浏览器端) | lib/client.js | 遮蔽 sidebar.workspaces 槽位(优先级 -1,官方为 0;最低优先级渲染者胜出,这是框架官方支持的机制),用忠实复刻的工作区浏览区替换官方组件:头部 + 视图选项、搜索、分组/单列列表、拖拽排序、重命名/分叉/归档、工作区重命名/删除——并叠加筛选组、暗色标题与取消归档操作。 |
取消归档的数据流
1. 在已归档会话行上点击 取消归档。 2. 浏览器半区同源 fetch POST /api/dsh-archive-manager/unarchive,携带 { sessionId } 与必需的自定义头 x-dsh-archive-manager: 1。 3. Host 路由调用补上的 unarchiveSession,通过与官方归档完全相同的 setState 持久化路径,把该 id 从全局归档集合中移除。 4. 注册表写入触发 domain/changed;Host API 网关比对归档集合变化后向所有已连接客户端(含其他标签页)广播 host/archived-sessions-changed。 5. 客户端运行时更新 archivedSessionIds,浏览区自动重渲染——行恢复原色、菜单换回"归档会话"、筛选规则立即生效。
因为变更走的是官方持久化链路,跨重启持久、跨标签页一致,无需自定义 RPC 协议或额外事件管道。
查看已归档会话的对话内容
DSH 官方客户端有一条规则:当前会话一旦归档就强制清空对话选择(这是"归档会话无查看入口"设计的一部分),导致点击已归档行会立刻弹回空的新会话视图。本插件禁用了这条规则(对客户端 WorkspaceRuntime.project() 投影打了一个小补丁,卸载时自动还原),因此点击已归档会话可以正常打开并阅读其对话内容。随之而来的行为变化:归档"当前"会话时不再自动把对话区清回"新会话"——会话保持打开,并在列表中作为暗色行可见。
筛选语义
会话可见当且仅当 (已归档 && 勾选已归档) || (未归档 && 勾选未归档)。默认 未归档: 勾选、已归档: 不勾选——与官方行为完全一致。两项可同时勾选(全部显示);都不勾选则列表为空。筛选状态持久化在插件自己的 localStorage 键中,刷新后保留;分组/排序偏好会从官方 dsh.workspace.view.v5 键一次性迁移。
安装
插件面向 DSH 0.1.0-rc.x(在 0.1.0-rc.6 上验证)。
从 GitHub 安装(推荐)
npx @deepseek-ai/dsh plugin --profile web add github:piaohua/dsh-plugin-archive-manager
# or
dsh plugin --profile web add github:piaohua/dsh-plugin-archive-manager从 npm 安装(发布后)
npx @deepseek-ai/dsh plugin --profile web add dsh-plugin-archive-manager然后重启 dsh web。插件是一个 profile *bundle*(自带 cordis.patch.yml 插入自己的加载行),走 dsh plugin 的正常 reconcile 流程。
卸载:dsh plugin --profile web remove dsh-plugin-archive-manager 后重启,官方工作区浏览器原样恢复(遮蔽机制天然可逆)。
本地开发
# 在本仓库内
npm run build # 从 src/ 组装 lib/client.js(内嵌 CSS)
npm run verify # 发布前结构检查
node scripts/smoke.mjs # 在桩浏览器环境执行 bundle factory 冒烟测试
# 把本地目录装进 web profile(相对路径会锚定到当前目录)
npx @deepseek-ai/dsh plugin --profile web add file:/绝对路径/dsh-plugin-archive-manager包结构
dsh-plugin-archive-manager/
├── package.json # dsh.bundle.patch + dsh.client 声明
├── cordis.patch.yml # 组合补丁:插入本插件的加载行
├── lib/
│ ├── index.js # Host 半区:注册表 unarchiveSession + exact HTTP 路由
│ └── client.js # Browser 半区:__ModuleLoader__ bundle(遮蔽浏览器 + 新 UI)
├── scripts/
│ ├── build.mjs # 从 src/ 组装 lib/client.js
│ ├── verify.mjs # 发布前检查
│ └── smoke.mjs # bundle factory 冒烟测试
├── src/
│ ├── client.src.js # 浏览器 bundle 源码(含 CSS 占位符)
│ ├── rows.css # 官方行样式(重打标签,自包含)
│ ├── browser.css # 官方浏览区样式(重打标签,自包含)
│ ├── picker.css # 官方选择器样式(重打标签,自包含)
│ └── extra.css # 插件私有样式(暗色标题)
├── README.en.md # 英文说明
├── README.md # 本文件(中文,GitHub 默认显示)
└── LICENSE # MIT发布
构建产物(lib/)已提交入库,因此仓库本身即可通过上文 GitHub 方式安装。如需同时发布到 npm:
npm publish发布后按上文安装即可。
已知取舍与兼容性
- 浏览区是忠实复刻的重实现,不是官方组件。DSH 0.1.0-rc.x 的工作区浏览器内部没有可扩展槽位(只有两个目录选择洞),要改其行为,唯一受支持的方式就是遮蔽槽位。实现复刻了官方逻辑与样式(MIT 许可,CSS 重打标签独立注入),视觉与交互一致;但官方后续对工作区浏览区的改动不会自动流入本插件——需要跟随 DSH 版本更新插件。
- "添加工作区"改用 Host 原生目录选择(
pickDirectory)+ 路径输入回退,替代官方目录选择洞(该洞由被遮蔽的 entry 声明,本插件无权渲染)。会话空状态(英雄区)的选择器不受影响。 - 已归档会话的行菜单保留 重命名 / 分叉(两者对已归档会话仍然有效)。
- 卸载插件后官方浏览器原样恢复;筛选状态存在插件自己的
localStorage键,无残留。
License
MIT