Skip to content
dsh.fish
Bundle

dsh-session-group

DSH 会话分组(Workspace)管理:创建分组、重命名/删除分组引用、移动会话到分组、在分组下新建会话(设置页入口)

Source
EIGHTfs
License
MIT
Updated
Updated 20 days ago

Readme

# dsh-session-group

DSH 会话分组(Workspace)管理插件:**创建分组(.dsh/Group 软链接方案)、重命名/删除分组引用、在分组下新建会话(工作移交)、禁止手动新建**。设置页一键操作。

> 机制依据:源码 + 实测三重印证(见下文「DSH 机制事实」)。分组 = 采纳一个目录路径(`workspace.create`),**项目本体不移动**。

## 功能

- 📁 **创建分组**:给分组名 → 自动建 `.dsh/Group/<title>` **软链接 → `workspace/<title>`** 并采纳为分组;项目实际写在 workspace,不污染 .dsh
- 🏷️ **重命名 / 删除**:改分组显示名;删除只移除分组引用(目录与会话保留)
- ✨ **在分组下新建会话(工作移交)**:转发公开 RPC `session.create {workspaceId}` → cwd 自动取分组 path(=workspace 项目目录)→ 自动归属;支持 `handoff` 参数把交接说明作为新会话首条消息发出
- 🔄 **移动会话 = 归档原会话 + 分组下新建会话**(2026-08-18 用户约定):DSH 机制不允许已有会话跨 cwd 移动,正确语义是把工作移交给分组新会话,原会话用 dsh-session-manager 归档(可还原)
- 🚫 **禁止在分组下直接新建会话**(`blockGroupNewSession`,默认 **true**):服务端拒绝 + 前端隐藏官方分组行的「+」按钮
- 🧭 **入口在设置**:设置 → 插件配置 → 「会话分组」卡片

## 安装

```sh
mkdir -p ~/.dsh/profiles/web/node_modules/dsh-session-group
cp -r lib package.json cordis.patch.yml ~/.dsh/profiles/web/node_modules/dsh-session-group/

node -e "const fs=require('fs');const p=JSON.parse(fs.readFileSync('~/.dsh/profiles/web/package.json'));p.dependencies['dsh-session-group']='file:./node_modules/dsh-session-group';fs.writeFileSync('~/.dsh/profiles/web/package.json',JSON.stringify(p,null,2))"

cat >> ~/.dsh/profiles/web/cordis.patch.yml << 'EOF'
- insert:
    - id: dsh-session-group
      name: dsh-session-group
EOF

# 重启 DSH
```

测试实例(隔离)部署:源码放 `node_modules_local/` + file: 依赖 + patch insert + 软链(见 dsh-test-env skill),重启测试实例。

## 使用(设置 → 插件配置 → 会话分组)

- **创建分组**:输入分组名(在配置的 `groupRoot` 下建目录)或绝对路径 → 创建
- **分组列表**:显示 标题/path/会话数;可 重命名 / 删除
- **移动会话**:填会话 ID + 选目标分组 → 移动(cwd 匹配才成功)
- **分组下新建会话**:选分组 → 新建(自动归属该分组;可填交接说明 handoff,作为新会话首条消息)
- **禁止开关**:默认开启,勾选后隐藏侧边栏所有分组行的「+ 新建会话」按钮,并拒绝服务端请求
- **移动会话**:DSH 机制限制下"移动" = 归档原会话(dsh-session-manager)+ 在分组下新建会话(工作移交)

## API

| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/session-group/status` | 状态(分组数/groupRoot/workspaceRoot/profile/block) |
| GET | `/api/session-group/list` | 全部分组(含 sessionIds/path/title) |
| POST | `/api/session-group/create` | 创建分组 `{title}`(.dsh/Group/<title> 软链接 → workspace/<title>)或 `{path}` |
| POST | `/api/session-group/rename` | 改名 `{workspaceId, title}` |
| POST | `/api/session-group/delete` | 删分组引用 `{workspaceId}`(目录保留) |
| POST | `/api/session-group/move` | 移动/挂载会话 `{workspaceId, sessionId}`(cwd 匹配才成功) |
| POST | `/api/session-group/new-session` | 分组下新建会话 `{workspaceId, handoff?}`(handoff=交接说明,block 开启时 401) |
| POST | `/api/session-group/set-config` | 运行时切换 `{blockGroupNewSession: bool}`(内存生效,持久化需改 patch) |

## 配置(cordis.patch.yml config)

```yaml
- insert:
    - id: dsh-session-group
      name: dsh-session-group
      config:
        enabled: true
        groupRoot: ''                # 默认 <dshHome>/Group(.dsh 下)
        workspacePath: ''            # 默认取默认 workspace 的 path
        blockGroupNewSession: true   # true=禁止在分组下直接新建会话(默认开启)
```

## DSH 机制事实(源码 + 实测,勿误判)

1. **会话归属分组 = 会话 header 的 cwd 硬绑定**:只有 cwd 恰好等于分组 path 的会话才能进该分组
   - `Workspace.attachSession` 强校验 `realpath(cwd) === path`
   - `session.create {workspaceId}` 时 cwd 自动设为分组 path → 自动 attach(实测:分组 sessionIds 立即可见)
   - 分组 path 若为软链接,realpath 后是目标项目目录 → 会话 cwd 落在 workspace 项目(实测 header cwd 验证)
2. **已有会话无法跨组移动**(实测):
   - `workspace.attachSession` **未暴露公开 RPC**(返回 "not found")
   - `workspace.insertSessionBefore` 跨组拒绝 `workspace-move-invalid: not accounted`
   - GUI 拖拽只做组内排序(`commitSessionDrag` 仅同 accountKey)
3. **直接改 workspace.json 无效**:workspaceRegistry 内存快照无文件 watcher,且 `sessionIds` getter 按 `sessionPath(id)===path` 过滤,重启后仍被剔除
4. 结论:让分组有会话的正规途径 = **在分组下新建会话**(cwd 自动=分组 path);"移动会话" = 归档原会话 + 分组下新建(用户约定)

## 验证

```sh
node test-core.mjs   # 10 项断言:create(path/title 软链接)/move(匹配与不匹配)/new-session(含 handoff)/block/list/status/rename/delete
```

真机验证(测试实例 3083)已通过:
- create 采纳目录 → 分组出现;new-session → 会话自动归属分组(sessionIds 立即可见)
- move cwd 不匹配 → 409 `cwd-mismatch`(带 hint)
- blockGroupNewSession=true → new-session 401 `group-new-session-blocked`;=false 恢复

## 已知边界

- **cwd 不符的已有会话无法移入分组**(DSH 0.1.0-rc.6 机制限制,非本插件可绕);需要时请用「在分组下新建会话」
- `set-config` 仅运行时内存生效;持久化需同步改 `cordis.patch.yml` 的 config
- host 侧 new-session 走 HTTP 回环转发公开 RPC,端口取 `PORT`/`TEST_DSH_PORT` 环境变量(默认 3081);反代/多实例场景需确认端口正确
- 删除分组保留目录与会话文件(官方语义:只移除侧边栏引用)
- 前端隐藏官方「+」按钮依赖 `aria-label^="actions.newSession"` 选择器,DSH 升级后需复核

## License

MIT

Install

dsh plugin --profile web add github:EIGHTfs/dsh-session-group

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source