dsh-qqbot
QQ 官方机器人插件,作为 DeepSeek Harness 的树外插件维护(不在 harness 源码树内)。一个包、两个半:
- host 半(
lib/index.js):/qqbot on|off命令、绑定会话、WebSocket 网关、QQ 端审批转发。 - client 半(
lib/client.js,经dsh.client声明随同一条挂载行自动加载):输入区工具行的「连接 QQ」开关 + 设置面板的 QQ Bot 设置页签。
安装
从 npm 装进你运行的 profile(无需本地构建):
dsh plugin --profile <name> add -w dsh-qqbot # 最新版
dsh plugin --profile <name> add -w dsh-qqbot@1.0.1 # 或固定版本
等价的手动方式(进入 profile 目录执行 pnpm):
cd "$env:DSH_HOME/profiles/<name>" # DSH_HOME 未设置时是 ~/.dsh/profiles/<name>
pnpm add -w dsh-qqbot
注意:
- 必须带
-w:profile 目录自带pnpm-workspace.yaml,不带-w时 pnpm 报ERR_PNPM_ADDING_TO_ROOT直接失败。 - 本包没有
dsh.bundle声明,不会进入 profile 的 bundles 层,这符合预期——由下面的 patch 行按包名挂载;client 半由dsh.client扫描同一条挂载行自动进浏览器。 - 升级到新版本:重新
add一次新版本号,然后重启 dsh。registry 版是安装时的快照(不再指向源码目录),改本地源码不影响它。
本地开发(link 到源码)
改插件源码时用 link: 直接指向源码目录:
cd E:\Project\dsh-plugins\dsh-qqbot
pnpm install
pnpm run build
dsh plugin --profile <name> add -w link:E:/Project/dsh-plugins/dsh-qqbot
- 用
link:而不是裸路径:裸路径是file:语义(快照副本),改源码不生效;link:直接指向源码目录,重新pnpm run build后即时生效,无需重新 add。 - 改完发布版后切回本地版用同一条
link:命令(pnpm add会把依赖 spec 从 registry 改写成 link)。 - 反之,切回发布版:
dsh plugin --profile <name> add -w dsh-qqbot@<版本>。
在 profile 自己的 cordis.patch.yml($DSH_HOME/profiles/<name>/cordis.patch.yml)挂载(凭据在设置界面填写,不再写在这里):
- insert:
- id: qqbot
name: 'dsh-qqbot'
不要放进 $DSH_HOME/cordis.patch.yml(home 层):它作用于所有 profile,而只有装过这个包的 profile 才能解析——其他 profile(如 headless)会直接启动失败。
配置(设置界面)
重启 dsh 后打开 设置(左下角)→ QQ Bot 页签,填写:
| 字段 | 说明 |
|---|---|
| AppID | QQ 开放平台机器人应用的 AppID。写穿不回显:页面只显示「已配置/未配置」状态,输入框填写新值以覆盖;「清除 AppID」可移除。 |
| AppSecret | 写穿不回显:页面只显示「已配置/未配置」,留空表示保持现有密钥;「清除密钥」可移除。 |
点击「保存」后立即生效:host 半按需从 credential 服务读取(credentials/updated 提交即触发),已连接的网关会用新身份自动重连,凭据被清空则自动断开。
存储位置:$DSH_HOME/.credentials.yaml(明文,等价于环境变量;由 harness 的 credential 服务管理)。页面写入的引用名是 QQBOT_CRED_APP_ID / QQBOT_CRED_APP_SECRET——故意与 QQBOT_APP_ID/QQBOT_APP_SECRET 环境变量不同名:credential 服务的环境层会遮蔽同名引用并使其只读,shell 里一旦导出过 QQBOT_APP_ID,页面就会永远变灰,因此设置页用自己的引用名,UI 写入永远优先于环境变量。之所以走 credential 服务而不是 settings 命名空间:harness 的 settings wire 面只服务硬编码的命名空间白名单(agent-loop、shell 等),树外插件注册的命名空间不会被暴露;credential 面接受任意引用名,无需改 harness。
配置解析顺序:credential 库(设置页写入)→ settings.yaml 的 qqbot: 段 → cordis.yml 行的 config 基础层 → 环境变量 QQBOT_APP_ID / QQBOT_APP_SECRET(无头环境可用环境变量兜底)。沙箱开关不在此页:仅在 cordis.yml 的 config.sandbox: true 里配置。四处都没有 AppID/AppSecret 时插件照常挂载,/qqbot on 会报错并指向设置页。
测试
pnpm test
host 的 protocol / gateway / qqbot / settings-controller 四套用例可直接跑(59 例,settings-controller 通过 vi.mock 替换 runtime 客户端模块以绕过浏览器 bundle)。tests/*.client.spec.ts(x) 被 vitest 排除:它们 import @deepseek-ai/dsh-client-runtime/client,而 registry 上发布的是浏览器 bundle(lib/client.js,import 时执行 window.__ModuleLoader__.load(...)),node/jsdom 无法加载。这些用例在 harness 源码树内开发期已验证,客户端开关与设置页的验证走浏览器手动确认(见「使用」)。
使用
- 设置 → QQ Bot 页签填写 AppID/AppSecret(首次必填)。
- 输入框下方点击「连接 QQ」按钮连接本会话(没试过多连,慎重)。
- QQ 群 @机器人 或私聊发消息,答案回到原聊天;工具调用需要审批时,把「允许/拒绝」发回 QQ 即可。

peer 依赖解析
两种安装方式的依赖解析不同:
- registry 版(推荐):包从 profile 的
node_modules向上解析 peer(@deepseek-ai/cordis、dsh-*Service Definition 等),与 harness 及 profile 的$DSH_HOME/profiles/node_modules回退共享同一份实例,没有双实例问题。 link:开发版:symlink 目标在 harness 之外,Node 从真实路径(realpath)向上解析,peer 命中 dsh-qqbot 项目自己的node_modules(pnpm install装的最新 registry 版)。这带来两个后果:- 插件与 harness 各持一份
@deepseek-ai/cordis(双实例)。当前启动与挂载正常,但若插件代码对ctx做跨实例判断(instanceof等)会失效。 - peer 版本按
^取最新(例如dsh-session@0.1.0-rc.6),可能比正在运行的 harness(rc.5)新。运行时服务走 harness 注入的 ctx,一般兼容;harness 升级或插件用到新 API 时需对齐 peer 版本。
- 插件与 harness 各持一份
版本耦合说明
client 半的浏览器 bundle 必须用 harness 的客户端加载协议构建:tsdown.config.ts 里硬编码了 PLATFORM_MODULES(模块表 external 列表,含 @deepseek-ai/dsh-client-runtime/client 的 store 豁免)和 __ModuleLoader__.load({ id }) 的包名 id。如果 harness 更新了这份平台模块列表或 __ModuleLoader__ 协议,需要同步更新 tsdown.config.ts,否则浏览器端加载会失败。
设置页依赖 harness 的:credential 能力(host 的 credentials 服务 + api.credentials wire 面,由 base 组合的 @deepseek-ai/dsh-credentials-local 提供)和 settings 面板(settings.section 槽位 + settings 服务,用于 qqbot: 段的 base 层解析),这些都在 web 基础组合里,无需额外挂载行;如果换成自定义 profile,需保证上述行在场。
发布
以 npm 身份 belowthetree 发布:
pnpm run build
npm login # 首次,登录 belowthetree 账号
npm publish
用户即可按名字安装:
dsh plugin --profile web add dsh-qqbot -w
No comments yet. Be the first to write one.