Bundle
@duo-stack/dsh-session-manager
Session manager plugin for DeepSeek Harness: list, archive/unarchive, and delete sessions grouped by workspace.
- Source
- duo-stack
- License
- MIT
- Updated
- Updated yesterday
Readme
# dsh-session-manager
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)会话管理插件:按工作区分组列出会话,支持归档 / 取消归档 / 删除,并可批量清理归档会话。
插件安装后会作为设置页面的一个顶级分区出现,不改变宿主原有行为。归档 / 取消归档 / 删除会修改真实会话数据,请谨慎操作。
## 功能特性
- **未归档 / 归档 双页签**:页面顶部先切分为「未归档」与「归档」两个页签,样式与插件分区的「插件配置 / 插件列表」一致。
- **按工作区分组的卡片**:每个页签内按工作区分组展示,一个工作区对应一张卡片(卡片圆角与按钮样式参考模型分区)。
- **逐会话操作**:对每个会话提供 归档 / 取消归档 / 删除,删除通过 DSH 居中确认弹窗完成,不使用浏览器原生 `alert`。
- **批量删除归档会话**:归档页签的每张工作区卡片头部提供「删除本工作区归档会话」,工具条提供「删除全部归档会话」。
- **实时刷新、无需重启**:归档 / 取消归档 / 删除都通过 registry 官方机制同步更新内存态与磁盘,触发 `domain/changed`,左栏会话列表及页面即时刷新。
- **自动清理幽灵会话**:只列出磁盘上仍有内容目录的会话;因早期删除失败而残留「有记账、无目录」的幽灵会话不会显示,并会在插件启动时自动清理。
## 安装
通过官方 CLI 把插件安装到某个 profile:
```sh
dsh plugin --profile <profile> add @duo-stack/dsh-session-manager
```
安装后,使用该 profile 启动 DeepSeek Harness 即可加载插件:
```sh
dsh --profile <profile>
```
## 使用
启动后打开 **设置**,在左侧导航会出现分区 **「会话管理」**,这是插件的唯一界面入口。
- 在「未归档」页签中,可将会话 **归档** 或 **删除**。
- 在「归档」页签中,可将会话 **取消归档**、**删除**,或按工作区 / 全部 **批量删除**。
## API
宿主半侧在 `/session-manager/api/*` 注册以下 JSON 接口,供浏览器半侧调用:
| 方法 | 路径 | 说明 |
| --- | --- | --- |
| `GET` | `/session-manager/api/list` | 列出全部会话,按工作区分组,含归档标记 |
| `POST` | `/session-manager/api/archive` | 归档一个会话;`body: { sessionId, archived? }`(`archived` 缺省为 `true`) |
| `POST` | `/session-manager/api/unarchive` | 取消归档一个会话;`body: { sessionId }` |
| `POST` | `/session-manager/api/delete` | 删除一个会话;`body: { sessionId }` |
| `POST` | `/session-manager/api/deleteArchived` | 批量删除归档会话;`body: { workspaceId? }`(缺省删除全部,带 `workspaceId` 则仅删该工作区) |
## 项目结构
```
src/
index.js 宿主半侧:注册 HTTP API;复用 workspace registry 已打开的 domain 句柄,
通过 registry.archiveSession / setState / Workspace.detachSession 同步状态
core.js fs 适配层:读写 storages/workspace.json、session_projcache、sessions/<project>/<session>
domain.js 纯函数领域层(无 I/O):列表投影、归档/取消归档、删除、批量删除,白盒可测
paths.js 与 DSH projectKey / encodeSegment 一致的目录名编码
client/index.js 浏览器半侧:把「会话管理」页面注册为设置页面顶级分区(settings.section 槽)
lib/ 构建产物:lib/client.js(客户端懒加载 CJS 工厂 bundle)、lib/types/
scripts/
build-client.mjs 生成 lib/client.js
tests/
domain.test.mjs domain 层单元测试
cordis.patch.yml bundle patch:让宿主 Loader 激活本插件
```
架构上遵循 `domain.js`(纯状态变换)→ `core.js`(fs 读写)→ `index.js`(宿主适配)的分层:
- 纯函数领域层不触碰文件系统,便于白盒测试。
- fs 适配层负责把领域层结果落到磁盘。
- 宿主半侧复用 workspace registry 已打开的 domain 句柄(`storageDomain.get('workspace')`),避免二次 `open` 触发 `already-open`;删除用 `Workspace.detachSession`、取消归档用 `registry.setState`,都走领域写链并触发 `domain/changed`,让左栏实时刷新。
- 浏览器半侧通过 `@deepseek-ai/dsh-client-ui-primitives` 复用 DSH 的 `Button` / `Modal`,并使用 `--dsw-alias-*` 设计令牌注入卡片与弹窗样式,实现未归档 / 归档双页签、按工作区卡片与居中确认弹窗。
## 开发
### 构建客户端 bundle
```sh
npm run bundle:client
```
`lib/client.js` 由 `src/client/index.js` 经 `scripts/build-client.mjs` 包装生成(DSH 官方 preset 无法构建仓库外插件,因此手动复刻其懒加载工厂格式)。
### 测试
```sh
npm test # 等价 node tests/domain.test.mjs;也可 node --test tests/
```
## 已知限制
- **客户端 bundle 不能用 DSH 官方 preset 构建**:`packages/client/tsdown.client.ts` 的 `workspaceManifest` 仅扫描 `packages/*/*/package.json`,仓库外插件须自行产出 `lib/client.js`(本插件已按官方 banner / footer 工厂格式手工生成)。
- **谨慎操作**:归档 / 取消归档 / 删除会改动真实会话数据,请在测试环境确认后再使用。
## 许可证
本项目基于 [MIT License](LICENSE) 开源。
Install
dsh plugin --profile web add github:duo-stack/dsh-session-manager
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install duo-stack-dsh-session-manager from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.