前言¶
在 DSH 里做多会话协作时,常见做法是在一个长会话里手动记录「张三干 A、李四干 B」,回头看谁回复了什么。这种做法在会话多、上下文长时很容易出错:把别人的输出误当成自己的结果,或者重启后根本想不起某张工单投出去没有。
下面介绍的 dsh-supergroup 就是针对这个痛点的一个插件。它不改变 DSH 的会话机制,而是加一层编排:一个主会话带若干执行会话,按 sessionId 派工、按 rpcId 回收结果、重启后自动对账。维护者是 LXS652,分类为工作流,许可证 MIT,项目版本 1.0.1。
这是什么¶
一句话定位:dsh-supergroup 是 DeepSeek Harness 的一组会话编排插件,把一个主会话和若干执行会话组成一个「整体」,主会话负责拆解与派工,执行会话各干各的,结果按投递时生成的 rpcId 精确回到主会话。
它要解决的问题很具体:
- 派工不靠标题、昵称或当前选中会话,而是按确定的
sessionId投递,避免「派给谁」的歧义。 - 结果回收不靠「猜下一条回复」,而是按投递时生成的
requestId(即rpcId)锚定,该 id 会随消息进入会话历史。 - 宿主重启后,账本先恢复,再对「投递了但没等到结算」的工单做历史对账,能自动证明完成的才收敛,证明不了的留给人裁决。
- 对账只做只读历史和改状态,绝不自动重发——因为外部副作用可能已经发生。
安装只需要往 DSH profile 里加一个 insert 条目,无外部依赖。
核心能力¶
下面列出的是 README 中明确写出的能力,按功能分述。
编排模型¶
一个 DSH profile 里可以同时存在多个「整体」,每个整体有独立的主会话(lead)、成员名单和工单账本视图。成员最多 8 个,lead 不能出现在成员里。
派工通过 ms2_dispatch 完成,消息进入成员会话,账本写 dispatch,工单进入 delivered 状态。回收有两条路:一是 session/event 快路径,收到带同一 rpcId 的 user/message 后跟随该回合到 turn/end;二是历史对账,在启动、ms2_status、/ms2 panel 三个时机读取会话历史,按 rpcId 精确锚定。
重启自愈¶
宿主重启时,delivered 先转成 uncertain(不知道结果是否已经产生)。启动对账继续查历史:
- 找到
turn/end且completed,结算为completed,保留reason: "restart"作为证据,source标为history-reconcile-after-restart; - 找不到证据,保持
uncertain,原因写进observeStats; uncertain也可以由主会话用ms2_resolve人工accept/fail。
需要强调的是:插件从不为了「催结果」重投工单。
侧栏面板¶
- 左栏按工作区分组列出会话,「折叠批量会话」「折叠空白会话」两个勾选互相独立;
- 点「创建一个整体」进入三步向导:选主会话 → 选执行会话(可多选,空白会话也可选)→ 填整体名;
- 每张整体卡片显示主会话、成员、工单数与在途数,卡片内可改名、全量替换成员、解散整体;
- 有在途工单(
delivered/uncertain)时,解散或移除对应成员会被拒绝,并返回具体requestId。
权限隔离¶
成员不能调用 ms2_* 协调工具,也不能用跨会话工具,业务工具照常可用。派工、裁决、改名、改成员、解散权限只在整体 lead 手上。
安装与启用¶
当前版本有两条安装路径,新装优先走路 A:直接改 profile 的 patch 文件,不依赖 bundle 机制。
路 A:往 cordis.patch.yml 追加 insert 条目¶
1、把插件目录放到一个固定位置,确认入口文件存在:<你的工作区>/dsh-supergroup/src/plugin2.mjs。
2、打开 ~/.dsh/profiles/<profile>/cordis.patch.yml,在文件末尾追加:
- insert:
- id: dsh-supergroup
name: file:///<你的工作区>/dsh-supergroup/src/plugin2.mjs
config:
registryFile: '<你的 DSH_HOME>\data\registry.json'
groupsFile: '<你的 DSH_HOME>\data\groups.json'
ledgerFile: '<你的 DSH_HOME>\data\tasks.jsonl'
这里要注意三点:name 必须是绝对路径的 file:/// 形式且指向入口文件 src/plugin2.mjs(不是目录);Windows 路径把反斜杠写成 /;条目必须包在 insert: 列表里,不能用 plugin: 字段,也不要裸写 - id: dsh-supergroup——没有对应已有条目时会被当成覆盖,宿主只记一条 patch: entry ... not found 然后静默跳过。
3、重启 DSH。侧栏应出现「超级代理部署」图标,ms2_status 应可用。
配置上,groupsFile 省略时会跟随 registryFile 落到同目录的 groups.json,eventsLogFile 省略时落在账本同目录的 session-events.log。可选配置:startupReconcileAttempts(默认 50,夹在 1..50)、startupReconcileIntervalMs(默认 200,夹在 1..200)、bootstrapGroups(首次启动预置整体,数组项为 {name, lead, members})、startupReport(默认 false)、selfTest(传入对象时运行内置自检)。
路 B:作为 bundle 安装¶
如果 profile 已经用 bundle 机制,则三件事必须同时成立,缺一不会加载:
1、profile 的 package.json 在 dependencies 里登记本包,例如 "dsh-supergroup": "file:<你的工作区>/dsh-supergroup";
2、同一个 package.json 的 dsh.profile.bundles 数组包含 "dsh-supergroup";
3、在 profile 目录执行 pnpm install,让包真正进入 node_modules。
三者齐备后,bundle 会读取包内的 cordis.patch.yml,其中 name 使用包名 dsh-supergroup,而不是 file:// 路径。
装完没反应怎么查¶
1、确认改的是当前 profile 的 cordis.patch.yml,条目追加在文件末尾、位于 insert: 列表内。
2、用 dsh --dump-config 看最终配置。Desktop 的 profile 可能被 Electron 独占,可以复制一份再对副本 dump:
cp -al ~/.dsh/profiles/<profile> ~/.dsh/profiles/<profile>-probe
3、grep dsh-supergroup 检查 dump 输出;若 stderr 出现 patch: entry ... not found,说明条目没进入 insert:,或 id 写错。
4、仍无图标时,再确认入口文件存在、name 是 file:/// 文件 URL,且 DSH 已完全重启——客户端 bundle 不热更。
典型用法¶
工具层面,主会话通过以下 ms2_* 工具完成日常编排:
| 工具 | 参数 | 作用 |
|---|---|---|
ms2_status |
留空或 list |
查看当前调用者可见的整体、成员、工单、恢复项与对账统计 |
ms2_group |
{"action":"create","name":"...","lead":"session-...","members":["session-..."]} |
创建整体;list 列出可见整体 |
ms2_members |
{"group":"整体名或 id","request":"list\|add <id>\|remove <id>\|lead <id>"} |
查看或增删成员 |
ms2_dispatch |
{"group":"整体名或 id","memberId":"session-...","text":"..."} |
把一张工单投给成员 |
ms2_resolve |
{"requestId":"...","action":"accept\|fail"} |
主会话裁决一条等待人工的工单 |
一个可复现的最小流程:
1、主会话里执行 ms2_group,创建整体 {"action":"create","name":"research","lead":"session-A","members":["session-B","session-C"]};
2、把任务拆成两张工单,分别用 ms2_dispatch 投给 session-B、session-C,每张工单各自生成 requestId;
3、结果走 session/event 快路径回流,或在下次 ms2_status / /ms2 panel 时由历史对账补结算;
4、如果某张工单成了 uncertain,在主会话里用 ms2_resolve 按证据 accept 或 fail。
命令层面,面板侧栏还支持以下命令,命令后的内容是 rawInput(不含 /ms2 前缀):
/ms2 panel
/ms2 create {"name":"...","lead":"session-...","members":["session-..."]}
/ms2 dissolve <groupId>
/ms2 group rename {"group":"g-...","name":"..."}
/ms2 group members {"group":"g-...","members":["session-..."]}
这些命令由客户端面板通过 ctx.remote.commands.execute 投到目标会话。只有整体 lead 能解散、改名、改成员;成员名单是全量覆盖;被移除成员若有 delivered / uncertain 工单,整次修改拒绝。
适用场景与注意¶
适合谁:需要在单个 DSH profile 内管理多个执行会话、希望派工有明确归属、要求结果可追溯、并且看重重启后状态不丢失的用户。它把「谁来做、做没做完、重启后账本是否对得上」这三件事交给了工程化的账本和对账,而不是靠人工记忆。
需要注意的边界,README 已逐条写明,下面挑重点:
- 对账时机固定:只有启动、
ms2_status、/ms2 panel三个入口触发,没有后台轮询,不调用就不会主动结算。 - 不做隔离:插件只做会话编排,成员共享文件系统、网络和
cwd,不提供进程、目录或网络隔离,需要注意成员之间的可见范围。 - 没有外部效果的 exactly-once:账本保证工单状态可恢复,但成员在完成前执行的副作用(发消息、改文件、调外部 API)无法由插件回滚;需要重试前请自行确认幂等性。
- 会话必须存在:派工只按
sessionId投递,不探测会话是否仍有效,失效会话会在历史对账时表现为找不到锚点。 - 暂不支持主会话转移:lead 是整体创建时确定的会话。
另外,该插件以当前 dsh 进程权限运行,安装前应检查源码与许可证(MIT)是否符合你的环境要求。插件在 SkillHub 社区目录的分类是工作流,社区目录是独立站点,与 DeepSeek 无官方从属关系。
结尾¶
dsh-supergroup 补的是这样一块:多会话编排里最难的不是「发出去」,而是「发出去之后能不能对得上账」。它用 sessionId 解决归属,用 rpcId 解决回收,用落盘账本和历史对账解决重启后的自愈。如果你在 DSH 里已经跑起了多条执行会话,可以把它作为一层轻量的协调骨架试试。
插件目录页:https://www.skillhub.cn/plugins/LXS652/dsh-supergroup
源码与文档:https://github.com/LXS652/dsh-supergroup