dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
DSH 模型群聊:多模型角色群组对话面板。角色绑定不同 provider/model,群内共享对话记录;设置页支持启用/停用。

DSH Web GUI 的「模型群聊」插件:多模型角色群组对话面板。
兼容:dsh >= 0.2.0-rc.2(Web profile)
@ 弹出成员候选(↑↓ 选择、Enter/Tab 插入);@ 后继续键入则在群工作区内检索文件,插入 @path 芯片(只写入路径,不把文件正文再灌进 prompt)Ctrl/Cmd+V 粘贴截图、或拖入图片文件(PNG / JPEG / WebP / GIF);文本框上方单独显示缩略图(可逐张移除),发送后在消息气泡外以缩略图展示,点击可在面板内放大。图片走 DSH 的 durable attachment 通道(字节不进群聊存储,只落引用),只注入本次发言的角色上下文;不支持图片的模型由 harness 自动降级为文本占位;参与角色中有人明确不支持图片时,添加、粘贴和拖放都会拒绝。已选图片不自动删除,但须先移除才能发送~、绝对路径与相对 DSH 工作区根解析,右栏内置目录选择浏览器;未设置则不注入、不暴露工具read_file / list_dir 主动查看工作区(realpath 硬边界,逃逸/软链越界一律拒绝);权限档位于消息输入框下方左下角芯片切换(对齐主会话 /permission 三档:仅可查看 / 工作区内修改 / 完全权限;默认仅可查看,按群组记忆持久化)——工作区内修改档角色可请求执行 shell 命令(经 DSH ctx.shell 沙箱执行器:cwd 与沙箱策略均收紧到工作区、超时 120s),每条命令在会话流内逐条确认(允许 / 拒绝 / 停止,命令全文展示不截断);完全权限档免确认直接执行(对齐 DSH danger-full-access 语义),切换时经主会话同款风险确认弹窗;工具调用以折叠行内嵌于角色消息(含耗时与状态),摘要注入后续发言上下文;不支持 tools 的模型自动降级为纯文本dual-face 插件(对齐 dsh-web 家族的 dsh-usage 包形状)。包名 @roaming-ai/dsh-group-chat,bundle 行 id: group-chat(cordis.patch.yml)。
src/(core/ 纯逻辑、host/、client/、shared/ 两边共用的路径语法);pnpm build 先 tsc 产声明到 lib/types/,再 tsdown(shared/tsdown.client.ts 预设拷贝自 dsh-web)产出 lib/index.js(host ESM)+ lib/client.js(client 闭包工厂)src/index.ts + src/host/):inject = ['llm', 'fs', 'webServer', 'workspaceRegistry'],设置命名空间 group-chat。同名包每进程至多挂一次(mountOnce)。组合根 service.ts 装配:
state — 群组/会话/角色/消息内存表 + run 运行态persistence/ — 会话级文件落盘与启动 hydratematerials/ — 工作区路径解析、根下一层文本注入、目录浏览、@ 文件检索tools/ — read_file / list_dir / run_command 沙箱与确认闸门engine/ — runLoop 串行发言;设置工作区后进入「生成⇄工具」循环(只读工具自动执行,run_command 经 confirmCommand 逐条确认);整次循环结束后后台 retitle(标题/主题)与 fold(约束备忘),立刻 idle、不占 runbroadcast — 全量快照 + SSE 120ms 节流api/ — HTTP 护栏与动作分发GET /api/group-chat/state — 全量快照POST /api/group-chat/action — {kind: mutate|send|retrySpeak|stop|confirmCommand|models|efforts|browse|fileSearch, ...}(retrySpeak 原地覆盖失败卡;mutate 含 reactMessage 表情回应 toggle;efforts 查 provider/model 推理级别,60s 缓存;browse 为右栏目录浏览器;fileSearch 为输入框 @ 文件检索);快照 run 暴露完整发言计划 queue + 游标 queueIndex(进度轨道数据面)GET /api/group-chat/events — SSE,状态变化推送(120ms 节流)src/host/api/http.ts,语义对齐 dsh-web 家族的 loopback fence)src/client/,dsh.client 模块,inject = ['slots', 'configForms']):侧边栏 sidebar.panellist 入口 + main 键面板 + settings.section 设置页;经 fetch/SSE 访问 host API,按 sessionId 本地过滤渲染。UI 使用 DSW 原语(@deepseek-ai/dsh-client-ui-primitives,shell 静态种子模块)——Button/Input/Switch/Tooltip/统一描边图标与 MarkdownText 渲染器。未发送草稿按会话分槽、模块级跨挂载存活(主会话⇄群聊会卸载 composer)。设计文档位于 docs/:PRODUCT.md(产品定义)、DESIGN.md(界面设计契约)、PERSISTENCE.md(持久化契约)、TOOLS.md(工具执行护栏)。
通过官方 dsh plugin 装进 web profile。它在 $DSH_HOME/profiles/web 里转发给 pnpm;本包声明了 dsh.bundle,安装成功后会按真实包名 @roaming-ai/dsh-group-chat 自动写入 dsh.profile.bundles。不要手改 profile 的 package.json 或 cordis.patch.yml。
要求:已能运行 dsh web;Node ^22.19.0 || >=24;PATH 上有 pnpm。
dsh plugin --profile web add github:localSummer/dsh-group-chat#main
等价:dsh plugin --profile web add git+https://github.com/localSummer/dsh-group-chat.git
本包的 prepare 会在安装时构建 lib/。pnpm 若拦截构建脚本,把提示的 key 写进 $DSH_HOME/profiles/web/pnpm-workspace.yaml 的 allowBuilds,再重跑同一条命令。
相对路径按调用目录锚定(dsh plugin 的 cwd 是 profile 目录,不要在 profile 里写 . / ../)。
git clone https://github.com/localSummer/dsh-group-chat.git
cd dsh-group-chat
pnpm install && pnpm build
dsh plugin --profile web add link:$(pwd)
也可以给绝对路径:dsh plugin --profile web add /path/to/dsh-group-chat。
开发辅助(在本仓库内):pnpm watch(tsdown 增量构建)、pnpm test、pnpm typecheck。link: 安装后改源码需重建产物;host 通常仍要重启 dsh web。
重启 dsh web(或 dsh --profile web)。用 dump 确认组合层已挂上:
dsh --profile web --dump-config
应出现 # == @roaming-ai/dsh-group-chat 层,且含 id: group-chat 行。侧边栏有「群聊」入口,设置页有「模型群聊」开关。
dsh plugin --profile web remove @roaming-ai/dsh-group-chat
然后重启 DSH。会话数据留在 ~/.dsh/storages/group-chat/,卸载不会删除。
会话级文件隔离,根目录 ~/.dsh/storages/group-chat/(DSH_GROUP_CHAT_STORE 可覆盖;设计详见 docs/PERSISTENCE.md):
~/.dsh/storages/group-chat/
├── .lock
├── ledger.json # schema: 3,纯清单;群组含 permissionTier
└── <group-id>/
├── workspaceDir # 纯文本一行路径
├── roles.json # schema: 1,该群角色(含 thinking / reasoningEffort)
└── sessions/
└── session-<uuid>.json # schema: 1,自包含
schema: 3):群组 id/名/permissionTier + 会话 id 归属与顺序。v2 遗留 allowCommands 读取时迁移(true → 工作区内修改,false/无 → 仅可查看)groupId 由目录归属,不写入文件createdAt/消息;可选 namePinned / topicPinned、constraints / constraintsUpToSeq(空数组与水位 0 省略)、消息上的 toolCalls / error / failedRoleId / reactions / imagesimages 只存 durable 引用(attachmentId / mediaType / 尺寸 / 名称),字节由 harness attachment 服务持有(~/.dsh/attachments/v1/),不进本目录也不进快照roles.json 紧凑序列化,ledger pretty@deepseek-ai/dsh-atomic-write 的 writeFileAtomic:wx 独占创建 + 随机后缀 tmp + rename,无 per-file fsync 对齐 DSH 基座标准;每个实际发生 rename 的目录一次 fsync)、单实例 .lock(PID 存活检测,崩溃残留自动清理).corrupt-*,每前缀保留最近 1 份);ledger 有 id 而文件缺失则空消息重建;roles.json 坏仅空该群角色;ledger 坏可扫描群组目录回收(仅丢群组名);行级校验丢弃孤儿条目;hydrate 清 .tmp-*.migrated-*,从不删除)enabled 开关经 settings 服务持久化于 profile cordis.patch.yml 的 group-chat 条目;进行中的对话运行态(run,含「输出完毕」标记)不持久化,重启即清