dsh-mesh
Identified★ 3Enable multiple DSH instances on a local area network to interconnect: superiors dispatch tasks, subordinates execute them, results are reported back, and approvals are forwarded.
DSH Mesh · 多机互联
让局域网里的多台 DSH,像一支团队一样工作。
一台 DSH 当“上级”,把任务派给其他 DSH;子级在自己的工作区里干活,完成后把结果和文件交回来;遇到敏感操作,子级把审批请求送到上级,由上级点“允许”或“拒绝”。
为什么需要它
- 不想一台台远程桌面/SSH 操作。 A 机器上的 agent 可以直接把任务派给 B、C、D。
- 每台机器保留自己的环境。 模型、工具、文件、审批策略都在各自机器上,不混在一起。
- 结果自动回来。 子级完成后,成果进入上级的 Mesh 收件箱;A 的 agent 读取后向用户说明,不会把子级原文当成用户消息塞进聊天。
- 权限边界清楚。 子级默认不给上级任何权限;给多少,上级才能用多少。
功能一览
| 能力 | 说明 |
|---|---|
| 局域网发现 | 同网段自动发现,也可手动填 IP/端口 |
| 6 位配对码 | 第一次连接输入一次,之后用令牌自动重连 |
| 一个插件、两种角色 | 谁拨号谁是上级;B 可以同时是 A 的子级、C 的上级 |
| 纯上级模式 | A 可以关闭自己的监听端口,只保留出站连接 |
| 子级授权 | 默认“不授予”;可选仅查看 / 工作区内修改 / 完全权限 |
| 自动短名 + @ 菜单 | 连上的子级自动叫 服务器A/B/C;聊天里输入 @ 直接选 |
| 检查更新 / 一键更新 | Mesh 面板里检查 GitHub 新版本,一键拉取并热重载 |
| 任务会话 | 子级为每个任务创建独立 DSH 会话和工作区,界面可见 |
| 续聊 | 同一个任务可以在子级原有会话里继续追问,不新开会话、不用重新交代背景 |
| 任务面板 | 按服务器分标签切换,卡片默认折叠、点开看详情;↑派出 / ↓接收 一眼区分 |
| 删除记录 | 已结束的任务可单条删除或「清理已结束」;只删 Mesh 记录,会话与工作区保留 |
| 安全加固 | 配对码单次可用 + 失败换码 + 限速锁定;令牌走 Header、只存哈希;本地接口防 CSRF;监听默认关、地址可配 |
| 不浪费令牌 | 未授权/权限不足在派发前就被拒绝,授权清单常驻上级提示词 |
| 令牌控制 | 结果全文落盘,模型默认只读摘要;需要细节时再按需读文件 |
| 结果回传 | 文本 + 文件进入 Mesh 收件箱;agent 读取后向用户说明,不塞进聊天 |
| 审批转发 | 子级 approval 送到父级,父级允许/拒绝;超时失败 |
| 双向在线状态 | 上级和子级都显示对方在线/离线 |
| 断线补投 | 成果发送失败重试 5 次,父级重连后继续投递 |
| 防转派 | 上级派给 B 的任务,不能再被 B 转派给 C |
快速开始
准备
- 每台机器都安装了 DSH
^0.2.2-rc.1,并且能正常对话。 - 机器在同一个局域网内;子级机器放行 TCP
45900(可在设置里改)。 - 四台机器尽量使用同一个 DSH 版本。
1. 在每台机器安装插件
用 Release 里的打包文件(当前最省事,已发布):
dsh plugin --profile <profile> add https://github.com/Fishexploi/dsh-mesh/releases/download/v0.4.3/fishboy-dsh-mesh-0.4.3.tgz
或者从源码本地安装:
git clone https://github.com/Fishexploi/dsh-mesh.git
打开 DSH:设置 → 插件 → 从本地安装,选择克隆下来的 dsh-mesh 目录。
安装后重载/重启一次,左侧栏会出现 Mesh 图标。
npm 包
@fishboy/dsh-mesh还在上架流程中(npm 上dsh-mesh已被别的项目占用,所以用了 scope)。发布后可以直接dsh plugin --profile <profile> add @fishboy/dsh-mesh。
从 0.3.x 升级到 0.4.x 要注意的三件事(协议号没变,新旧可以互通,但同版本体验一致):
- 监听默认姿态变了:新装的节点默认不监听、且只绑
127.0.0.1。已经配对过的老节点升级后保持原样,不会被切断;但如果你要给新的子级机器配对,记得先在那台机器上打开「开放 Mesh 端口」并选「所有网卡」。 - 配对码变成单次使用:配对成功后码立即作废,之后靠令牌重连。想重新配对,在子级点「刷新」生成新码。
- 令牌不再放在 URL 里:新版本走
Authorization: Bearer;仅当对面是 0.4.0 之前的版本时才回退到查询串,所以一半升级也不会断连。
0.4.2 起,插件自身的故障不会再拖垮整个 DSH 启动:如果同一份客户端 bundle 被组装了两次,插件只忽略那一次重复注册(不再抛 duplicate factory registration 让 web 启动失败);apply() 内部出错(端口被占、状态文件损坏等)也只会记录日志并降级为"插件未启动",DSH 照常打开。已经因为重复副本崩过的机器,先清掉多余副本(运行 sync\purge-mesh.ps1,或把 node_modules\@fishboy\dsh-mesh 整个删掉再装),然后更新。
0.4.3 起,更新前的包名检查只在模块名真的改变时才生效:用工作区目录 + 链接安装时(import.meta.url 会解析成真实路径、不在 node_modules 下),旧版本会误判为"profile 里没有这个模块"而拒绝更新;现在同名更新直接放行,只有真正改名才需要定位 profile 并迁移。
0.4.1 起「一键更新」会自己处理包名迁移:0.4.1 之前,插件包名从 dsh-mesh 改成了 @fishboy/dsh-mesh,而旧机器的 profile 还指向老名字,直接更新会导致启动失败(import failed)。现在更新会在写文件之前先把 profile 的依赖键、bundles 行改名并在 scoped 位置建好链接,所以从 0.3.x / 0.4.0 升级不需要手动跑迁移脚本。已经因为这个问题起不来的机器,仍需在崩溃界面点「禁用第三方插件」进入后跑一次 sync\repair-profile.ps1。
建议两台机器都更新到 0.4.0——审批转发、限速、CSRF 防护在两端生效才完整。
想把当前机器的插件一并同步到另一台机器,见 sync/README.md:运行
sync\install.cmd会合并@fishboy/dsh-mesh、dshmarket、dsh-mnemon、dsh-plugin-startup-animation和dsh-pet的依赖并执行pnpm install。
2. 子级开放监听并打开配对码
⚠️ 0.4.0 起监听默认是关的,而且默认只监听本机,所以第一次要先在 B 机器上:
- 打开 Mesh → 设置 → 开放 Mesh 端口;
- 监听地址 选「所有网卡(0.0.0.0,局域网可见)」——选「仅本机」上级是连不进来的(面板会提示);
- 保存后顶部会出现 6 位配对码。
如果 B 的防火墙弹窗,允许 DSH 监听 45900(端口可在设置里改)。
3. 上级连接子级
在 A 机器点开 Mesh:
- 同网段:在“局域网发现”里找到 B,点“配对连接”,输入 B 的配对码。
- 跨网段/广播被拦:在“手动连接”里填 B 的 IP、
45900、配对码。
连接成功后,双方都会显示对方“在线”。
4. 子级给上级授权
在 B 的 Mesh → 我的上级 里,把“授予上级的权限”切到需要的档位:
仅可查看工作区内修改完全权限
默认是不授予。 上级连上来之后没有任何权限,必须由子级手动打开开关;任务权限也不能超过这个档位。
5. 上级派任务
在 A 的 我的下级 里选 B → “派任务” → 写任务、选权限 → 发送。
B 会创建一个独立 DSH 会话,标题是 Mesh · 任务名,工作区在设置里配置的根目录下。
B 的本地用户可以看到任务进行中,也可以停止任务,但不能替上级处理审批。
6. 也可以直接在聊天里 @ 派任务
连上的子级会自动获得一个短名字:服务器A、服务器B、服务器C……
在面板里仍然能看到它真实的机器名;短名字只用于上级本地,方便 @。
不用打开 Mesh 面板,在任意聊天输入 @,候选菜单里会出现 服务器 分组:
- 选
服务器A; - 继续输入任务内容;
- 回车发送。
也可以直接手打:
@服务器A 检查一下登录模块,把发现的问题列出来
发送后,不是把这句话原封不动转发给服务器A。A 的 agent 会先理解你的真实需求,再给服务器A 写一份完整的任务(目标、上下文、约束、交付物、汇报格式),然后通过 mesh_task 派发。
结果不会以“你的消息”形式插进聊天,而是进入 Mesh 收件箱;A 的 agent 读取后向你说明。你可以在 Mesh 的“任务”里看到原始接收记录。
默认权限是“工作区内修改”;如果子级只授予了“仅可查看”,会自动降到只读。
需要“完全权限”时,还是建议在 Mesh 面板里明确选择。
目前“理解需求再派发”依赖 A 的模型判断;如果 A 没有调用
mesh_task,它会继续用普通聊天回答。你可以直接说“把这个任务派给服务器A”,让意图更明确。
@后面的名字用面板显示的 服务器A/B/C,或直接用节点 id。真实机器名仍会显示在下级卡片的第二行。
更新
Mesh 面板顶部会显示当前版本号:
- 检查更新:读取 GitHub
main分支的package.json,和本机版本比较。 - 一键更新到 x.y.z:优先在插件目录执行
git pull --ff-only;不是 git 安装时,回退为从 GitHub 下载更新文件。 - 更新完成后,如果当前 profile 启用了 HMR,会自动重载插件;页面会自动刷新。
- 没有 HMR 时会提示“请重启 DSH”。
更新源固定为
Fishexploi/dsh-mesh的main分支。发布新版本时,先把package.json的version改大再推送,别人点“检查更新”才会看到新版本。如果你在插件目录里改过源码,
git pull可能失败,此时会走文件覆盖;本地改动会被新版本覆盖,建议先提交或备份。
权限模型
| 档位 | 子级本地执行 | 需要上级审批 |
|---|---|---|
| 仅可查看 | 只读工作区,写操作被拒绝或上报 | 敏感操作上报 |
| 工作区内修改 | 工作区内可读写 | 越界、联网、提权等操作上报 |
| 完全权限 | 不做审批拦截 | 由子级本地承担风险 |
规则很简单:
- 子级是权限的源头。 上级选得再高,也不能超过子级授予的档位。
- 每次任务单独选权限。 同一个上级,不同任务可以用不同档位。
- 没授权就不派,不花冤枉 token。 派任务前先看目标子级的授权:
- 未授权(
none):直接拒绝,任务不会发出,也不会消耗子级的 token;上级会明确告诉你"对方还没给你权限,去子级开通"; - 任务需要的权限高于已授予(例如要写文件但只给了只读):在分析阶段就停下,告诉你需要哪一档、为什么,而不是把整条任务写完再失败;
- 上级 agent 的提示词里始终带着"每台子级 → 当前授权等级",所以它不需要先花 token 去猜。
- 未授权(
- 审批默认 10 分钟超时。 上级一直不处理,任务失败,不会自动放行。
审批与结果
审批
子级 agent 触发 approval 时:
- 子级插件拦截请求,不弹给子级本地用户;
- 请求发到上级的 Mesh → 审批;
- 上级看到“哪个任务、哪个工具、什么原因”,点“允许一次”或“拒绝”;
- 决定回传,子级继续或终止。
如果上级不在线,任务会等到超时,然后失败。
审批不会再“悄悄卡住”(0.3.2 起):
- 子级发出审批请求时,父级会话会立刻收到一条提示(哪台服务器、哪个任务、什么工具),不用自己去翻面板;
- 转发覆盖了两类审批:普通工具审批,以及“沙箱拒绝后申请升级权限档位”那种(它走的是宿主上下文,以前会落在子级本地没人看见);
- 父级可以直接让我处理:
mesh_approve { decision: allowed-once | rejected },也可以照旧在面板点; - 任务跑了 5 分钟既没审批标记也没结果,会补一条“可能卡在子级本地审批或子级繁忙”的提醒,不会让你一直等到超时才后知后觉。
结果
任务结束后,子级把文本结果和结果文件回传,并进入上级的 Mesh 收件箱:
- 不再用
agent.followup把子级原文作为用户消息塞进聊天; - 插件只注入一条很短的“有新结果”提示;
- A 的 agent 调用
mesh_inbox读取原始结果,再向你说明; - 你随时可以在 Mesh 的“任务”里查看原始接收记录和文件;
- 发送失败会重试 5 次;仍失败则显示“成果发送失败,等待上级上线后调取”,父级重连后补投。
续聊:在同一个任务里继续
任务结束后还能接着聊,而且不新开会话:
- 在 Mesh 面板的任务卡片上点 继续追问,或让上级 agent 调用
mesh_reply; - 追问会送进子级原来那条
Mesh · 任务名会话,历史和任务工作区都还在; - 子级不用重新交代背景,只要读它自己写的文件(建议
REPORT.md)就能接上; - 新结果照常投递到收件箱,卡片上会显示“续聊 N”轮次。
续聊要求双方都是 0.2.0 及以上;下级版本旧时会明确提示“请先更新下级”。子级那条会话需要还能被恢复(DSH 会话仍在其本地存储里);如果会话已被删除,续聊会失败并给出原因,此时改用
mesh_task新派一个任务。
任务面板
任务多了以后面板会很长,所以改成了三层收敛:
- 按服务器分标签:顶部是「全部」加每个服务器一个标签,标签上显示条数,有未读结果时带一个小绿点;点标签只显示那台服务器的任务。
- 卡片折叠:默认只显示一行(方向、标题、状态、时间),点一下才展开详情、结果和按钮。列表默认只列 12 条,超出点「显示全部 N 条」。
- 方向区分:派出给下级的任务用品牌色左边条 +
↑ 服务器A标签,被上级委派的任务用橙色边条 +↓ 上级名标签,一眼分得清是在指挥别人还是被别人指挥。
记录清理:
- 展开卡片点「删除记录」删单条;任务区右上角「清理已结束」按当前标签批量清理。
- 只删 Mesh 记录(以及落盘的结果文件和下载的附件),DSH 会话和工作区不删——删错了不丢工作。
- 未读结果默认保留,正在执行/排队的任务不会被清理。
- 被委派端(子级)面板上操作完全一样,删的是它自己那份记录;两边是各自独立的账本。
续聊每轮会覆盖同一份
results/<taskId>.md(保留最新一轮),轮次记录在任务卡片上。
令牌与落盘
跨机传输本身不花令牌,花令牌的是模型看到的东西。所以结果走“全文落盘 + 摘要入上下文”:
| 位置 | 内容 |
|---|---|
<stateDir>/results/<taskId>.md | 结果全文(带标题、节点、状态、字符数),上级随时可读 |
| 注入聊天的那条提示 | 一行,约 100 字,只说哪条任务回来了、全文已落盘 |
mesh_inbox 默认返回 | 每条结果的前 previewChars 字符(默认 1200)+ 全文路径 + 真实字符数 |
mesh_inbox { full: true } | 显式要全文时才读盘,且有单次上限 |
mesh_tasks | 只列任务元信息,不再携带结果正文 |
另外两条减少令牌的规则写进了给子级的任务说明里:详细报告写进工作区的 REPORT.md,回给上级的话控制在 800 字左右。追问时只发新增要求,不重发历史。
面板 设置 → 结果摘要字数 可以调小这个预算;调小更省令牌,代价是模型需要多读一次文件才能看到细节。
它是怎么工作的
A(上级) ──── 拨号 / 任务 / 审批 ────▶ B(下级)
▲ │
└────── 结果 / 审批请求 / 心跳 ◀───────┘
B(上级) ──── 拨号 / 任务 / 审批 ────▶ C(下级)
- 谁拨号,谁是上级;谁接受,谁是下级。
- 同一个插件装在每台机器上;B 可以同时是 A 的子级和 C 的上级。
- A 只连了 B,就只能直接给 B 发任务;要指挥 C,A 必须自己连 C。B 不能把 A 的任务转派给 C。
- 传输是局域网 HTTP + NDJSON 长连接,没有第三方运行时依赖;默认端口
45900。 - UDP
45901只用于“局域网发现”,被防火墙拦时用手动连接即可。
安全边界
默认姿态(0.4.0 起)
- 默认只监听
127.0.0.1,且监听开关默认关闭——新装的节点不会自动对局域网开放。要让别的机器连进来,得在 设置 → 监听地址 选「所有网卡(0.0.0.0)」并打开「开放 Mesh 端口」。升级上来的老节点保持原来的行为,不会被切断。 - UDP 局域网发现跟随监听开关,可以单独关掉;关掉后手动填 IP 照样能连。
- 明文 HTTP,没有 TLS。 只建议在可信局域网用;跨网段请走 WireGuard / Tailscale 之类的加密隧道,或反代加 TLS。不要把端口暴露到公网。
- 子级默认零授权。 新连上的上级没有任何权限;子级可以随时收回或断开。
- 不是远程 shell。 上级发的是任务,子级的 agent、沙箱、工具策略仍然生效。
- 结果按不可信内容处理。 子级输出回到上级后,不要让上级无条件执行高风险动作。
已经做的加固(0.4.0 起)
| 项 | 做法 |
|---|---|
| 配对码 | 6 位、crypto 随机;同一来源 失败 3 次就换码、5 次锁定 10 分钟;配对成功后配对码立即作废,之后只认令牌;比较用常量时间 |
| 配对审计 | 记录最近 20 次配对尝试(时间 / 来源 IP / 是否成功),面板显示最近几条 |
| 令牌传输 | 走 Authorization: Bearer 头;只有 0.4.0 之前的老节点才回退到 URL 查询串(避免强拆老版本) |
| 令牌存储 | 子级 state.json 只存令牌的 SHA-256,不存明文 |
| 本地接口 | /mesh/api/* 只接受回环连接 + application/json + 同源 Origin,并带 nosniff——防止你随便打开一个网页就被脚本驱动去派任务 |
| 频率限制 | 每个上级 120 次/分钟 的操作上限;同一来源打开事件流 10 次/分钟 上限 |
| 信息收敛 | /mesh/info 只回协议号,不再泄露节点名/端口/ID |
仍然存在的风险(需要你知道)
- 明文传输:局域网内能抓包的人可以看到任务内容;令牌已经不在 URL 里,但 RPC body 仍是明文。要彻底解决只能上 TLS 或隧道。
- 子级本地可以自行批准:如果审批请求因为版本不一致没有转发到上级,子级本地界面上能点允许。升级到同一版本后行为一致。
- 插件是可信 in-process JS,没有沙箱:装插件等于让它在你机器上跑代码,装之前看源码。
常见问题
点了“配对连接”没有反应?
新版本会弹出一个输入配对码的对话框。如果还是旧界面,先 Ctrl+R 刷新页面,或者重启一次 DSH。
配对码正确但连不上?
- 检查子级是否放行 TCP
45900; - 检查子级是不是已经绑定了一个上级——当前版本一个子级只能有一个上级,要先在子级断开旧上级;
- 检查两台机器是不是在同一网段。
任务报 DeepSeek Messages transport failed?
这是子级自己的模型请求失败,不是 Mesh 传输失败。先在子级的 DSH 里正常发一条消息,确认模型、网络和凭证都正常;Mesh 只负责把任务送过去。
聊天里 @服务器A 没有派发?
- 名字用面板显示的 服务器A/B/C,或节点 id;
- 子级必须在线,并且已经给上级授予权限;
- 这条消息要先由 A 的 agent 理解再调用
mesh_task,不是插件直接转发;如果它没有派发,直接说“把这个任务派给服务器A”; - 消息格式是
@服务器A 任务内容,@服务器A后面要有空格。
“继续追问”提示下级版本过旧,或提示会话无法恢复?
- 续聊要求双方都是 0.2.0 及以上:先在子级面板里“检查更新 → 一键更新”;
- “会话无法恢复”说明子级那条
Mesh · 任务名会话已经不在它的本地存储里了(被删除或换了 profile),这条任务只能改用mesh_task重新派; - 追问期间子级必须在线,且这条任务不能还在跑。
当前限制
| 限制 | 说明 |
|---|---|
| 单上级 | 一个节点只能有一个上级,可以有多个下级 |
| 无 TLS | 依赖可信局域网;后续再加 |
ask_user_question 未转发 | 目前只转发 approval |
| 重启中断任务 | 节点重启或插件重载时正在跑的任务标记失败,并把失败结果补投给上级,不会一直显示“进行中” |
| 续聊依赖会话 | 续聊复用子级那条任务会话;会话被删掉就只能新派任务 |
| 续聊只带当轮文件 | 每轮回传本轮新生成的文件,前几轮的文件不会重复发送 |
| 文件上限 | 16 个文件 / 单文件 1.5 MB / 总计 8 MB |
| DSH pre-1.0 | 插件 API 还会变;多台机器锁同一版本 |
开发与测试
Host 端传输有一个零依赖的测试脚本:
node test-harness.mjs
它会启动两个回环地址上的 Mesh 节点,完成配对、授权、任务下发、结果确认和审批转发;现在还覆盖结果落盘与摘要预算(长报告只留预览、全文可从 resultFile 读回、mesh_tasks 不再携带正文)、续聊(mesh_reply 在原会话里再跑一轮、结果再次进收件箱)和记录清理(单条删除 / 按服务器清空已结束记录、正在跑的任务拒绝删除、落盘文件同步清理)。
项目结构
dsh-mesh/
├─ index.js Host 端:监听、拨号、任务、审批、文件
├─ client.js 左侧栏图标 + Mesh 主面板
├─ cordis.patch.yml Bundle 入口
├─ locale/ 插件管理器标题与描述
├─ icon.svg
└─ test-harness.mjs
License
MIT © 2026 DSH Mesh contributors
如果这个插件帮到了你,欢迎点一个 Star ⭐
Comments
Loading…
Similar plugins
by peng456
Discovers other DSH instances on the local network by UDP multicast or port scan, lists them in a sidebar panel together with the capabilities each one reports, and dispatches tasks between machines i
★ 8
↓ 816/wk
MIT
JavaScript
Nov 9, 2026
dsh plugin --profile web add dsh-plugin-meshDSH: Windows2MacOS — drive the same project on online Windows and macOS machines from one DeepSeek account, across networks and regions. P2P hole punching is the default path (relay + shared server as rendezvous, ledger and fallback), with a bundled STUN responder, Tailscale/public-VPS/tunnel shapes, Rabbit relay + per-machine Localside + eight DSH tools (replicate / split), nine aggregate verdicts and signed requests.
★ 2
MIT
JavaScript
dsh plugin --profile web add @twinsearth/w2m-dsh-pluginby FxRayHughes
Link DeepSeek Harness (DSH) instances on the LAN: delegate subagents to another machine's DSH, continue its sessions, with signed auto-discovery and a visual settings page
★ 0
NOASSERTION
JavaScript
Oct 23, 2026
dsh plugin --profile web add @local/dsh-peer-linkby WODE25500
Share the DSH workspace over the local network: phones, tablets and other computers browse, download and upload files via browser with no DSH login. Token gate, path boundary, read-only mode and rate
★ 1
↓ 490/wk
MIT
TypeScript
Aug 26, 2026
dsh plugin --profile web add dsh-lan-shareby zhe97396-tech
MCP gateway for dsh that connects each server on first use and disconnects it after an idle window; tool lists are cached on disk, existing mcpServers files can be imported, and child-process environm
★ 0
MIT
JavaScript
Oct 19, 2026
dsh plugin --profile web add dsh-lazy-mcpby songofhawk
Multi-machine, multi-agent orchestration and control plane for DSH: discovers Agents and workspaces across devices, routes tasks by machine, repository, capability, and load to local or remote Agent r
★ 4
↓ 159/wk
JavaScript
Sep 29, 2026
dsh plugin --profile web add dsh-alpha