dsh-bot-gateway
v0.3.9-beta
Published
DSH Bot Gateway:把 QQ(NapCat OneBot v11 / 官方机器人)/Telegram/飞书/钉钉 接成 DSH 的远程任务网关 —— 聊天里发消息即可建任务/续聊/查进度/收交付物(Cordis 宿主插件,零运行时依赖)
Maintainers
Readme
DSH Bot Gateway — 把聊天软件变成 DSH 的远程入口
版本:0.3.0-beta(更新记录见 CHANGELOG.md,设计契约见 SPEC.md,交接手册见 HANDOVER.md)
安装(正常 npm 渠道)
插件是标准 npm 包 dsh-bot-gateway(零运行时依赖,Cordis 宿主插件,宿主 + 浏览器双半边一体):
# 方式 A(官方 channels,推荐):装进 DSH profile 后重启 DSH
dsh plugin --profile <profile名> add dsh-bot-gateway
# 方式 B(从本地 tgz 安装,发布前验证用):
dsh plugin --profile <profile名> add ./dsh-bot-gateway-<版本>.tgz
# 方式 C(手工,任意 DSH 版本):装进 profile 的 node_modules 后重启
npm i dsh-bot-gateway # 在 <dsh-home> 或 profiles/<name> 下执行然后在机器级组合 <dsh-home>\cordis.patch.yml 挂载(零配置开箱即用,运行时数据默认落
$DSH_HOME/bot-gateway/;需要自定义路径才写 config):
- insert:
- id: bot-gateway
name: dsh-bot-gateway
# config: { tasksRoot, statePath, settingsPath } 可选,默认 dsh-home/bot-gateway/版本升级:发布新版 → dsh plugin --profile <name> add dsh-bot-gateway@<新版本> → 重启 DSH。
改源码 = 改仓库发布新版(npm 标准流),不再有 junction / ?v= 热重载(见「六、改代码」)。
桌面截图监控(desktopWatch)
配置入口:看板「设置」→ desktopWatch(持久化在 settings.json,保存即热生效)。
enabled: true开启后,网关用 Electron desktopCapturer(非 Windows 原生截图工具) 每intervalSec(默认 60)秒捕获全部显示器,主动推送到 onebot11allowUsers(或desktopWatch.pushTo显式指定的目标)。- QQ 官方机器人协议不允许主动推送 —— 定时推送走 NapCat 个人号通道;
QQ 官方用户可在 5 分钟被动窗口内发
/桌面按需要一张。 - 截图落盘在
dsh-home/bot-gateway/screen-shots/,滚动保留最近keepLast(默认 60)张。 - 任意通道发
/桌面(或/desktop)立即现拍一张当前桌面发回 —— 捕获进程优先处理 按需请求,不吃上一周期的存货。 - 锁屏处理:屏幕锁定时截的图不是锁屏 —— 捕获端自动改抓桌面应用窗口的实时画面
(取画面最大的有效窗口;文件名带
-L标记,/桌面回复会注明「屏幕处于锁定状态」); 系统连窗口画面都冻结时回退最后一张可用全屏帧。黑帧一律不落盘。 - 免打扰时段(
dnd: { enabled, start, end },如23:00 → 08:00,可跨零点): 时段内不自动推送 —— 截图照拍、滚动保留照做,期间新图只存档,时段结束后也不会 积压补发(整段静默);补发队列同样冻结到时段外;/桌面手动要图不受限。 - 捕获依赖 electron.exe:默认自动探测 DSH 桌面工作区
(
Desktop\DSH\node_modules\electron\dist\electron.exe),也可用electronPath显式指定, 或设环境变量BOT_GATEWAY_ELECTRON/DSH_WORKSPACE。
把 QQ(NapCat / OneBot v11 + QQ 官方机器人)、Telegram、飞书、钉钉接入 DSH: 在手机聊天软件里发一条消息,就能创建任务、续聊、查进度、停止任务 —— 与本地任务拥有完全相同的权限与模型能力。
NapCat 一键安装 + 全部账号设置都在网页看板完成,无需改配置文件。
DSH 版本适配表
| 插件版本 | 适配 DSH 版本 | 说明 |
|---|---|---|
| 0.3.0-beta | 0.2.1-alpha.1(实测) | 电脑重启后 NapCat(QQ) 自动快速登录不再每次手动扫码(修复 wsl 登录轮询被守卫拦截的 bug + 启动自动 SetQuickLogin);WSL 完全无窗口启动(powershell Hidden 包裹 + 冷启动预暖,桌面不再弹终端窗口);testedDshVersion → 0.2.1-alpha.1 |
| 0.2.3-beta | 0.1.7-rc.1(实测) | 兼容声明更新:host 服务依赖与浏览器半边契约逐项核对 0.1.7 实现一致;testedDshVersion → 0.1.7-rc.1;含 0.2.2-beta 全部能力 |
| 0.2.2-beta | 0.1.7-rc.1(实测) | 新增 /pair 手机配对命令(全局管理员私聊获取配对二维码;依赖 DSH 未来发布的 mobileCompanion 服务,未发布前友好提示) |
| 0.2.1-beta | 0.1.2-rc.1(实测) | 设置页面 UI 与 DSH 主题对齐(继承 --dsw-* 设计令牌,换肤实时跟随) |
| 0.2.0-beta | 0.1.2-rc.1(实测) | npm 标准包重构(main=宿主入口、exports["./client"]、单裸包名行挂载,无 junction/?v=);含 0.1.0-beta 全部能力:桌面截图监控(现拍 + 锁屏处理)/ 免打扰时段 / 多媒体承载 / AGENTS.md 规则手册 / QFace 表情真值 / 联络官派发 |
| 0.1.0-beta | 0.1.2-rc.1(实测) | 桌面截图监控 / 多媒体承载 / AGENTS.md 规则手册 / QFace 表情真值 / 联络官派发(file:// /v= 挂载时代) |
| 0.0.6-beta ~ 0.0.7-beta | 0.1.2-alpha.4(实测) | 浏览器半边适配 0.1.2 的按包名注册机制(工厂 id dsh-bot-gateway);宿主半边兼容 0.1.1-rc.2 |
| 0.0.1-beta ~ 0.0.5-beta | 0.1.1-rc.2(实测) | 发布时仅存在该 DSH 版本;装在 0.1.2 上宿主半边可用,但 GUI 设置分区不会出现(client 工厂 id 与 0.1.2 花名册行 id 不匹配) |
- 适配范围由
package.json的dsh.compat = { minDshVersion, testedDshVersion }声明。 - 查看当前 DSH 版本:
dsh --version或 GUI「设置 → 关于」。 - 自检浏览器半边注册状态(0.1.2+ 的 Web 鉴权使外部探测失效,用插件自证端点):
curl http://127.0.0.1:<后端端口>/bot-gateway/api/client→registered: true即正常。
入口已固化进 GUI:DSH 网页界面「设置 ⚙」面板 →「机器人网关」分区 (「通用」与「模型」之间),内嵌完整看板 —— 无需记忆 URL,后端端口漂移自动跟随。 备用直达:
http://127.0.0.1:<后端端口>/bot-gateway/。
项目特性:零 npm 依赖(全部协议手写,仅用 node: 内建与全局 API); npm 标准包(Cordis 宿主插件,
main即宿主入口,单裸包名行 = 宿主 + 浏览器双半边); 13 组离线单测 + jsQR 解码回环验证。
┌─────────────┐ OneBot v11 WS ┌──────────────────────────────────┐
│ NapCat/QQ │◄──────────────────►│ bot-gateway (DSH 宿主插件) │
│ Telegram │ TG Long Poll │ ├─ 命令路由 /new /status /stop │
│ 飞书 │ 飞书长连接 WS │ ├─ TaskManager + state.json │
│ 钉钉 │ 钉钉 Stream WS │ └─ agents.create + preset 挂载 │
└─────────────┘ └──────────────┬───────────────────┘
▲ │ followup / whenIdle
│ NapCat WSL 发行版(官方镜像, ▼
│ 自带完整 Linux QQ,插件一键安装托管) DSH Agent(工具齐全、会话持久化、
独立工作目录,权限继承宿主)- 源码仓库:
C:\Users\lcl\Desktop\DSH插件开发\DSH Bot\(git,发布源;npm 包从它构建) - 控制台(主入口):DSH GUI「设置 ⚙」→「机器人网关」分区(推荐,端口无关);
备用直达:
http://127.0.0.1:<后端端口>/bot-gateway/—— 每个平台一个独立设置页: 📊 总览(平台状态 + 任务列表)|🐱 QQ 个人号(NapCat 安装/扫码/OneBot11)|🤖 QQ 官方机器人|✈️ Telegram|🐦 飞书|💬 钉钉|⚙️ 通用设置(模型/任务参数)
一、支持的平台
| 平台 | 协议 | 模式 | 扫码 | |---|---|---|---| | QQ(NapCat) | OneBot v11 | 正向 WS(我们连 NapCat)/ 反向 WS(NapCat 连我们) | ✅ 看板扫码中继 | | QQ 官方机器人 | QQ Bot WebSocket | 官方 wss 网关 + 被动回复 | —(后台配置) | | Telegram | Bot API | 长轮询 getUpdates | —(@BotFather 建 bot) | | 飞书 | 长连接 | 官方 callback/ws(protobuf 帧) | —(开放平台配置) | | 钉钉 | Stream Mode | 官方 gateway/connections/open | —(开发者后台配置) |
二、快速开始(QQ · 全程网页操作)
0. 前置:无(WSL2 为 Windows 内置组件)
NapCat 部署默认采用 wsl 模式:插件把官方 mlikiowa/napcat-docker 镜像(自带完整 Linux QQ
与 NapCat)导入为 Windows 内置的 WSL2 发行版并全程托管 —— 无需安装 Docker Desktop 或任何
第三方软件。
- 本机已有 Docker 镜像:安装时直接
docker export复用,零下载(约 40 秒完成迁移) - 本机没有 Docker:插件经 Alpine 构建器从 Docker Hub 直拉镜像层并在本地合并成发行版
- 前置条件仅有 WSL2(Win10/11 内置;若未启用:管理员 PowerShell 运行
wsl --install并重启)
备选 docker 模式:本机已装 Docker Desktop 时可切换(安装 = docker pull,崩溃自动重启)。 历史说明:曾尝试 NapCat.Shell.Windows.Node.zip(自包含 node.exe + QQNT 核心), 但上游 v4.18.19 该包缺少 wrapper.node 依赖的
crypto.dll/ssl.dll(这两个文件只在 QQ 官方安装包内,且腾讯 CDN 对该包做了地域封锁),本机无法补齐 —— 已弃用。
1. 一键安装 NapCat(网页)
- 打开 http://127.0.0.1:53035/bot-gateway/
- 在「🐱 NapCatQQ 进程托管中心」卡片点击 🚀 一键安装 NapCat (WSL2 内置运行,免 Docker)
- 等待进度条走完(首次约 1.5GB 下载;本机有 Docker 镜像则秒装),发行版自动启动
插件自动完成:获取镜像 rootfs → wsl --import 导入发行版 → 生成 webui.json(随机 token)
onebot11.json(WS 服务器 3001)并同步进发行版 → 启动常驻托管进程(entrypoint.sh → Xvfb 虚拟屏 → Linux QQ)。端口经 WSL2 localhost 转发暴露3001(OneBot WS)与6099(WebUI), 适配器无感知。从 docker 模式切换过来时,旧容器会自动停止释放端口。
2. 扫码登录
- 看板「扫码登录」卡片显示实时二维码(插件把 NapCat 返回的
txz.qq.com登录链接 本地渲染为 QR 图片 —— 该链接是给手机 QQ 扫的,浏览器打开只是说明页) - 手机 QQ 扫码 → 卡片变绿即登录成功(登录态持久化在发行版 VHD,重启后可「快速登录」免扫码)
3. 设置允许的 QQ 号(安全闸门!)
- 切换到「🐱 QQ 个人号」页(顶部导航切换;URL hash 自动记忆,如
#/napcat) - 「允许用户 (allowUsers)」填你自己的 QQ 号(每行或逗号分隔)
- 点 💾 保存 QQ 个人号设置 —— 立即热生效,无需重启
不知道自己的 QQ 号?先随便发条消息给机器人,未授权回复会把你的用户标识原样告诉你, 再回来填上。
allowUsers留空 = 拒绝所有人。
4. 发消息试一试
手机 QQ 私聊机器人(或群里 @机器人):
/new 帮我在桌面上创建一个 notes.txt,内容写"远程任务测试"几秒后机器人回复「▶️ [xxxx] 开始执行…」,任务完成后回报结果。
任务模型默认
agentrouter/glm-5.3,可在设置页「任务模型」里改。
二·五、用户隔离 · 人格 · 自进化(0.1.0-beta)
每个与机器人发起会话的用户自动获得一个专用文件夹(<dsh-home>\bot-gateway\users\<来源-账号>\),
内含多层记忆(容量有上限,由后台记忆整理子代理自动瘦身治理,成年累月不膨胀):
| 要素 | 路径 | 作用 |
|---|---|---|
| 自进化档案 | PROFILE.md | 机器人对该用户的长期认知(≤4KB,偏好/习惯/重要信息),每轮先读、持续自我更新;看板可直接编辑 |
| 情感记忆 | soul/soul.md + soul/moments.md | 关系基调/里程碑/相处备忘 + 重要时刻(≤120 行,超限自动蒸馏) |
| 对话日志 | data/logbook.md | 按日期的往期对话摘要(会话轮换封卷时写入)——「我们那天聊了什么」的回忆入口 |
| 关注事项 | data/focus.md | 用户某段时间特别关注的事(考试/求职/项目/健康),带热度与跟进建议;机器人主动跟进进展,不需要用户反复叮嘱,超 30 天未动自动归档 |
| 媒体库 | data/media/ + index.jsonl | 用户发来的图片/文档/语音/视频按月分区落盘 + 追加式索引;机器人用 read_image 看图、grep 索引找「那张图」 |
| 数据库 | data/ 其余 | 该用户的结构化数据:游戏进度、记账流水、心情日记、积分榜 |
| 技能包 | skills/ | 剧本/玩法/检查单等 .md 技能说明,机器人按需读取,也可为用户定制新技能包写入 |
联络官模式(默认开,看板可关):主会话是常驻对话伙伴 —— 闲聊直接聊、有温度; 复杂任务派子代理执行、自己盯进度汇报,不会干活干到不理人。每轮先揣摩你当下的状态 (忙不忙、心情如何、在等什么),再决定怎么回;你交代的关注事项它会自己记着、自己追。 任务跑着你插话,它会当场判断:是改主意(马上调方向)、是新任务(派出去不打断手头的)、 还是就聊两句(顺嘴接住)。
说话方式:像朋友在 QQ 上打字那样回你 —— 短句、口语、有态度;没有列表腔、 客服腔、作文腔,也不拿状态小图标装点门面。
文件权限硬限制:除「全局管理员」外的所有人格,会话都运行在 DSH 原生 workspace-write
沙箱下 —— 可写根 = 会话工作目录 = 该用户的专用文件夹,读写越界即被拒;
--cwd / /cwd 对受限人格自动拒绝。远程用户无需也无法响应审批弹窗
(会话审批策略固定 never)。
六种人格(看板「👥 用户」页下拉即切,下一条消息生效;新用户默认人格可在 「⚙️ 通用设置」里配置):
| 人格 | 沙箱 | 定位 |
|---|---|---|
| 🛠️ 全能助手(默认) | 锁定用户文件夹 | 完整任务执行,只是被限制在自己的文件夹内 |
| 🎭 剧本杀主持人 | 锁定用户文件夹 | 沉浸式 DM:发线索、演 NPC、推进章节、复盘;进度存 data/,剧本放 skills/ |
| 🎮 小游戏 | 锁定用户文件夹 | 猜谜/接龙/21点/文字冒险,带 data/scores.md 积分榜 |
| 💌 伴侣 | 锁定用户文件夹 | 倾听共情、记重要日子与偏好(写入 PROFILE.md 与 data/) |
| 📅 生活助手 | 锁定用户文件夹 | 日程提醒、记账、菜谱、习惯打卡;越用越懂你 |
| 👑 全局管理员 | 无沙箱 | 受信用户(如你自己的 QQ):可 /cwd 指定任意工作目录,慎用 |
管理操作(看板「👥 用户」页):
- 人格切换:即时写入档案,下一条消息生效;已运行的会话即时收到新沙箱策略
- 封禁/恢复:封禁后该用户消息被直接拒绝
- 档案编辑:直接查看/修改 PROFILE.md(与机器人自进化写入的是同一份文件)
- 重置工作区:解除粘性会话绑定,下一条消息按当前人格重新建档建会话(原记录保留)
三、其他平台配置(每平台一个独立设置页)
QQ 官方机器人(q.qq.com 注册)
「🤖 QQ 官方机器人」页填 appId + clientSecret,勾选启用,保存即连。页面顶部的扫码绑定卡片
自动从官方 API 拉取机器人信息(名称/头像)并本地生成添加到群二维码 —— 手机 QQ 扫码即可把机器人
加进你的群(无需手动复制链接)。官方机器人要求被动回复(收到消息 5 分钟内、最多 5 条),网关已自动
处理 msg_seq 递增。群里使用需要开启「机器人可以被@」。未上架的机器人可在控制台沙箱配置添加测试人员。
Telegram
@BotFather 创建 bot 拿 token;allowUsers 填你的数字 user id(给 @userinfobot 发消息可查)。
大陆网络可设 apiBase 指向自建反代。
飞书(open.feishu.cn 创建企业自建应用)
开放平台 → 事件与回调 → 选择「使用长连接接收事件」,订阅 im.message.receive_v1,
权限开 im:message、im:message:send_as_bot。
钉钉(open-dev.dingtalk.com 创建应用 + 机器人)
开发者后台 → 机器人配置 → 消息接收模式选 Stream 模式,无需公网 IP。
设置存储与生效
所有网页设置持久化在 <dsh-home>\bot-gateway\settings.json(原子写盘),每页独立保存
(服务端深合并部分配置,互不影响其他平台),保存即触发 reconfigure 热生效:
旧适配器卸载 → 新配置装配,NapCat 进程/容器不受影响。cordis.patch.yml 里只剩安装路径类配置,无需再改。
四、命令参考
| 命令 | 说明 |
|---|---|
| /new <描述> [--cwd <绝对路径>] | 创建新任务(同账号沿用同一持久会话;--cwd 仅该账号首个任务生效) |
| /status [taskId] | 查看任务实时状态(正在调什么工具、第几轮等) |
| /list | 列出本聊天最近 10 个任务 |
| /stop [taskId] | 停止运行中的任务(仅当前活跃任务会真正取消执行中的轮次) |
| /switch <taskId> | 切换本聊天的活跃任务 |
| /cwd <绝对路径 \| reset> | 设置 / 重置本聊天的默认工作目录(账号绑定会话前有效) |
| /help | 命令帮助 |
| (直接发文本) | 无活跃任务时自动当新任务;任务运行中会当场判断你是改主意、加新活还是想聊两句,分别处理 |
任务运行时每 3 分钟自动推送一条进度(设置页可调)。
工作目录规则(默认):
<dsh-home>\bot-gateway\tasks\<日期>-<任务id>-<标题slug>\,互不污染;
用 --cwd 或 /cwd 可显式指定任意目录。
账号粘性会话(0.0.5-beta 起):
- 每个远程账号(一个群或一个私聊用户)固定一个持久 DSH 会话:该账号的
所有消息、所有任务(含
/new)都进同一会话,跨 DSH 重启自动 resume 续用; - 会话在 DSH 侧边栏的标题被钉住为
来源-用户类型-账号-远程会话(如QQ-群组-88888-远程会话、QQ-用户-10001-远程会话),LLM 自动 命名被永久压制,一眼可辨来源; - 工作区随会话一起粘住(DSH 会话与 cwd 绑定不可更换):该账号首个任务确立
工作目录后,后续
--cwd//cwd不再更换(会提示已绑定); - 若会话被手动删除(文件进了 session-cleaner 回收站),下一条消息会自动 换新会话自愈,任务不中断。
五、安全须知(务必阅读)
- 远程任务继承宿主全部权限。当前宿主是
danger-full-access(完整读写、任意命令), 远程任务同样拥有。allowUsers是唯一闸门 —— 只加自己的账号。 - 群聊默认需要 @机器人 才响应(
groupTrigger: mention),且可再加allowGroups白名单限定群号。 - 状态看板只监听本机回环(127.0.0.1),并有 Host/CSRF 校验,外网访问不到。
- NapCat 容器端口(3001/6099)只映射到 127.0.0.1,容器内配置强制
0.0.0.0仅服务于端口映射。 state.json(任务注册表)与任务工作区都在dsh-home\bot-gateway\下,删除该目录即清空所有远程任务痕迹。
六、改代码 & 版本升级
改运行配置(推荐方式):看板设置页保存即 reconfigure 热生效,或改 cordis.patch.yml
里本条的 config 保存即热重载 —— 两者都无需动版本号。
改源码 / 版本升级:插件已是 npm 标准包,采用标准发布流,不再有 ?v= 缓存链:
# 1. 改源码(git 仓库),跑测试
npm test
# 2. 发布新版本(package.json version + index.mjs PLUGIN_VERSION 同步)
npm pack # 本地 tgz 验证(files 白名单,见 package.json)
npm publish # 需要 npm 登录(npm adduser / token)
# 3. 目标机安装新版本后重启 DSH
dsh plugin --profile <name> add dsh-bot-gateway为什么没有热重载了:ESM 缓存按 URL 键控,
?v=机制曾在 file:// 开发态下绕过缓存; npm 包的标准做法是「安装新版本 → 重启」(DSH 冷启动必读最新代码,无缓存问题)。 本机当初的 junction 开发挂载已退役,源码目录只作为发布源使用。
诊断利器:<dsh-home>\bot-gateway\debug.log 记录 agent 挂载、每轮事件数、被循环吞掉的
agent/error——排查"任务没反应"先看它。
七、架构与扩展性
7.0 项目与版本管理
- 产品版本:
package.jsonversion与index.mjs的PLUGIN_VERSION(发布时同步)—— 看板徽标 //api/status/ 启动日志展示;变更记录在CHANGELOG.md - 测试:
npm test跑全部 13 组离线套件(脚本清单见 package.json) - 入库范围:源码 + 文档 + 测试;
runtime-data/(含 token 的运行时状态)与test/jsQR.cjs(第三方测试依赖)已由 .gitignore 排除 - 发布范围:
package.jsonfiles白名单(宿主入口 + client + lib/ + 文档), 测试与探针不随包发布
7.1 双半边架构(宿主 + 浏览器)
插件由组合树的一行组成(在 <dsh-home>\cordis.patch.yml 机器级补丁层 ——
注意不是 profiles\web\cordis.patch.yml:DSH Desktop 桌面壳在后端启动失败时会把
整个 profiles 目录隔离为 profiles.broken-<时间戳> 并重建,profile 级补丁会随之丢失;
机器级补丁不受影响,重启后始终生效):
| 行 | name | 作用 |
|---|---|---|
| bot-gateway | dsh-bot-gateway(裸包名) | 一行两半边:宿主 = 包 main(index.mjs,全部适配器/NapCat 托管/看板路由);浏览器 = client-modules 按名扫描 package.json 的 dsh.client 声明,经 exports["./client"] 把 client.js 纳入花名册 |
浏览器半边注册机制(0.1.2+):
client-modules 从 Loader 条目定位
package.json(裸包名行直指<dsh-home>\node_modules\dsh-bot-gateway\package.json),按清单名dsh-bot-gateway注册浏览器半边 —— 无需单独的 client 行 (旧 0.1.1 时代需要client-entry.mjs空占位 + 第二行,已随 npm 化废弃);client.js的工厂注册 id 与slots.register分区 id 必须是dsh-bot-gateway(= 包清单name):0.1.2 的arrive()严格要求 工厂注册 id === 花名册行 id,不匹配时设置分区静默缺失;分发 URL 为组合 URL(
/plugins/??<id>/client.js&rev=<rev>,rev 为不透明分配值)—— 对插件透明,外部无法靠探测 URL 验证注册,用/bot-gateway/api/client自证(见上文适配表)。client.js(浏览器 bundle):经典脚本 +__ModuleLoader__.loadCJS 工厂,require("react")/ slots 服务取自 shell 静态种子表;向settings.section插槽注册「机器人网关」分区(order=5),内容为同源 iframe 内嵌/bot-gateway/解析路径:
<dsh-home>\node_modules\dsh-bot-gateway\(npm 标准包布局;profiles\<name>\node_modules可放 junction 镜像保证 profile 解析稳定)启动自检日志:每次挂载/卸载/挂路由写入
<dsh-home>\bot-gateway\boot.log(后端 stderr 对桌面用户不可见;启动后若看板 404,先看这个文件定位)
在新机器上安装(见文首「安装(正常 npm 渠道)」):dsh plugin --profile <name> add
dsh-bot-gateway(或 npm i dsh-bot-gateway 装进 profile 的 node_modules),再在机器级
patch 加裸包名行,重启 DSH 生效。
启动可靠性(0.0.3-beta 关键修复):看板路由用 ctx.inject(['webServer'], …)
子纤维注册 —— webServer 是异步就绪的服务(listen + webStartup 依赖链),启动竞态下
可能晚于本插件 apply;旧实现一次性 ctx.get 会永远错过并静默禁用看板(表现为
重启后 /bot-gateway/ 404 空白页、设置分区 iframe 空白)。子纤维保证服务出现即挂载。
7.2 文件布局
index.mjs 插件入口(宿主半边):DEFAULTS 合并(patch.yml ← settings.json 双层)、
reconfigure 热重配、NapCat 管理器装配、看板路由注册
client.js 浏览器半边 bundle:注册 DSH GUI「设置」面板的「机器人网关」
分区(settings.section 插槽,同源 iframe 内嵌看板)
client-entry.mjs 裸包名行的空操作宿主占位(见 7.1 双半边架构)
package.json 项目元信息 + 测试脚本(零 npm 依赖,type: module,
含 main/exports/dsh.client 客户端声明)
CHANGELOG.md / SPEC.md 更新日志 / 设计规格(实现契约)
.gitignore 排除运行时状态与第三方测试依赖
lib/core.js Gateway:TaskManager、命令路由、runTurn 驱动、
session/event 进度通知、state.json 持久化与重启恢复
lib/util.js 日志、退避重连、消息分块、makeUserMessage、RFC6455 WS 服务器
lib/settings.js SettingsStore:settings.json 原子读写(tmp+rename)与深合并
lib/napcat-process.js NapCat 一键安装与托管:wsl 模式(镜像 rootfs → WSL2 发行版,
docker export 快路径 / Docker Hub 直拉慢路径,常驻 wsl.exe 托管)
+ docker 模式(pull/run/start/stop)+ windows 模式(实验性)
lib/napcat.js NapCat WebAPI 客户端(扫码中继;自动兼容新旧两代鉴权:
旧版 {token} 明文 / 新版 {hash: sha256(token+".napcat")})
lib/webui.js WebUI 服务端:路由挂载(HTML 外壳 + app.js + 12 个 API),
三层安全校验:回环 + Host端口 + CSRF;QQ 官方机器人信息/
绑定二维码代理(60s 缓存)
lib/qrcode.js 自包含 QR Code 生成器(无第三方依赖):GF(256) Reed-Solomon、
掩码惩罚评分自动选优、PNG 编码(Node 内置 zlib);
V1-V6 / EC-M,最长 106 字节
lib/webui-app.js 前端应用(独立脚本文件):每平台独立设置页 + hash 路由 +
分视图部分保存(深合并);独立文件规避模板字符串嵌套转义问题
lib/pb.js 飞书 pbbp2.Frame protobuf 编解码
lib/adapters/*.js 5 个平台适配器,统一工厂签名:
createAdapter(kind, adapterConfig, deps) →
{ kind, start(), stop(), status(), sendText(chatTarget, text) }加新平台只需三步:
- 新建
lib/adapters/<platform>.js,实现createAdapter工厂签名(收消息 → 调deps.core.onMessage({ adapter, chatId, userId, text, isGroup, reply }),reply是回发函数;发送 → 实现sendText) - 在
index.mjs的DEFAULTS.adapters加默认配置 + 装配注册 + 设置页加表单 - bump 版本号(见上节)
DSH 侧接入要点(对齐 dsh-host-apiproxy 的 ensureSession 模式):
agents.get(sessionId) 活跃复用 → 持久化命中走 agents.resume → 全新会话走
agents.create(绝不能先 sessions.create 再 agents.create,会撞 "already exists")。
创建时必须传 setup: (agentCtx) => presets.mount(agentCtx, presetId) 挂载工具集,
否则模型没有任何工具、只会空谈;setup 返回值必须是 undefined。
八、测试
cd <bot-gateway 源码目录>
npm test # 或逐个执行:
node test\smoke.mjs # 冒烟:工具函数、配置合并、命令解析
node test\settings-test.mjs # SettingsStore 深合并/原子写盘、NapCat 配置生成(docker+windows)、reconfigure 流程
node test\ws-server-test.mjs # RFC6455 WS 服务器(分片/ping/close)
node test\adapter-test.mjs # 5 适配器协议与事件链
node test\stagec-test.mjs # protobuf 编解码 + 飞书/钉钉适配器
node test\qrcode-test.mjs # QR 生成器结构自检(定位/时序/暗模块/比例)
node test\media-test.mjs # 媒体入库:分区落盘/JSONL 索引/去重/限额/检索/消毒
node test\qrcode-decode-test.mjs # QR 生成↔jsQR 解码回环(含 UTF-8 中文)
node test\image-outbound-test.mjs # 图片出站:提取/安全校验/路径脱敏/降级
node test\wsl-slowpath-test.mjs # WSL 慢路径端到端:Alpine 构建器直拉 Docker Hub 镜像(需 WSL2)
# 端到端(需 DSH Desktop 运行中;起 Mock NapCat 推 /new 任务并断言完成回复):
node test\mock-onebot-server.mjs --expect-v=<当前V> --port=3999 --wait-ms=300000第三方测试依赖:
qrcode-decode-test依赖 jsQR 1.4.0(MIT)作为解码预言机, 该文件不随仓库分发(.gitignore 已排除),首次运行前获取:curl.exe -sL -o test\jsQR.cjs https://cdn.jsdelivr.net/npm/[email protected]/dist/jsQR.js缺失时该测试自动跳过(退出码 0),不影响其余套件。
e2e 用独立端口(如 3999)避开真实 NapCat 容器占用的 3001;测试前先通过看板设置页把 OneBot11 url 临时切到
ws://127.0.0.1:3999(顺手实测 reconfigure 热切换),测完切回。
测试辅助工具:test\inspect-session.mjs <关键词>(查任务会话)、
test\zcat-session.mjs <journal.zstd>(多帧 zstd 解压会话日志)、
test\ws-probe.mjs <ws-url>(WS 连通性探测)、test\pe-imports.mjs <dll>(PE 导入表解析)。
