READMESource: main@41190302
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):服务端拒绝 + 前端隐藏官方分组行的「+」按钮 - 🧭 入口在设置:设置 → 插件配置 → 「会话分组」卡片
安装
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/ 软链接 → workspace/<title>)或 <code>{path}</code></td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/session-group/rename</code></td>
<td>改名 <code>{workspaceId, title}</code></td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/session-group/delete</code></td>
<td>删分组引用 <code>{workspaceId}</code>(目录保留)</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/session-group/move</code></td>
<td>移动/挂载会话 <code>{workspaceId, sessionId}</code>(cwd 匹配才成功)</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/session-group/new-session</code></td>
<td>分组下新建会话 <code>{workspaceId, handoff?}</code>(handoff=交接说明,block 开启时 401)</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/session-group/set-config</code></td>
<td>运行时切换 <code>{blockGroupNewSession: bool}</code>(内存生效,持久化需改 patch)</td>
</tr>
</tbody></table>
<h2>配置(cordis.patch.yml config)</h2>
<pre><code class="language-yaml">- insert:
- id: dsh-session-group
name: dsh-session-group
config:
enabled: true
groupRoot: '' # 默认 <dshHome>/Group(.dsh 下)
workspacePath: '' # 默认取默认 workspace 的 path
blockGroupNewSession: true # true=禁止在分组下直接新建会话(默认开启)
</code></pre>
<h2>DSH 机制事实(源码 + 实测,勿误判)</h2>
<ol>
<li><strong>会话归属分组 = 会话 header 的 cwd 硬绑定</strong>:只有 cwd 恰好等于分组 path 的会话才能进该分组<ul>
<li><code>Workspace.attachSession</code> 强校验 <code>realpath(cwd) === path</code></li>
<li><code>session.create {workspaceId}</code> 时 cwd 自动设为分组 path → 自动 attach(实测:分组 sessionIds 立即可见)</li>
<li>分组 path 若为软链接,realpath 后是目标项目目录 → 会话 cwd 落在 workspace 项目(实测 header cwd 验证)</li>
</ul>
</li>
<li><strong>已有会话无法跨组移动</strong>(实测):<ul>
<li><code>workspace.attachSession</code> <strong>未暴露公开 RPC</strong>(返回 "not found")</li>
<li><code>workspace.insertSessionBefore</code> 跨组拒绝 <code>workspace-move-invalid: not accounted</code></li>
<li>GUI 拖拽只做组内排序(<code>commitSessionDrag</code> 仅同 accountKey)</li>
</ul>
</li>
<li><strong>直接改 workspace.json 无效</strong>:workspaceRegistry 内存快照无文件 watcher,且 <code>sessionIds</code> getter 按 <code>sessionPath(id)===path</code> 过滤,重启后仍被剔除</li>
<li>结论:让分组有会话的正规途径 = <strong>在分组下新建会话</strong>(cwd 自动=分组 path);"移动会话" = 归档原会话 + 分组下新建(用户约定)</li>
</ol>
<h2>验证</h2>
<pre><code class="language-sh">node test-core.mjs # 10 项断言:create(path/title 软链接)/move(匹配与不匹配)/new-session(含 handoff)/block/list/status/rename/delete
</code></pre>
<p>真机验证(测试实例 3083)已通过:</p>
<ul>
<li>create 采纳目录 → 分组出现;new-session → 会话自动归属分组(sessionIds 立即可见)</li>
<li>move cwd 不匹配 → 409 <code>cwd-mismatch</code>(带 hint)</li>
<li>blockGroupNewSession=true → new-session 401 <code>group-new-session-blocked</code>;=false 恢复</li>
</ul>
<h2>已知边界</h2>
<ul>
<li><strong>cwd 不符的已有会话无法移入分组</strong>(DSH 0.1.0-rc.6 机制限制,非本插件可绕);需要时请用「在分组下新建会话」</li>
<li><code>set-config</code> 仅运行时内存生效;持久化需同步改 <code>cordis.patch.yml</code> 的 config</li>
<li>host 侧 new-session 走 HTTP 回环转发公开 RPC,端口取 <code>PORT</code>/<code>TEST_DSH_PORT</code> 环境变量(默认 3081);反代/多实例场景需确认端口正确</li>
<li>删除分组保留目录与会话文件(官方语义:只移除侧边栏引用)</li>
<li>前端隐藏官方「+」按钮依赖 <code>aria-label^="actions.newSession"</code> 选择器,DSH 升级后需复核</li>
</ul>
<h2>License</h2>
<p>MIT</p>
|
No comments yet. Be the first to write one.