在 QQ 私聊与群聊中直接驱动 Agent 干活
35.2/100
综合分
6
GitHub 星标
2,010
npm 周下载
—/5
用户评分
数据截至 2026/9/17 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add dsh-qq-bridgenpm 源 · dsh-qq-bridge 的发布者账号已校验与本仓库一致
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:仅索引
是什么
dsh 原生插件 · platform
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 77 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查✓ 自动检查通过展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✓npm 包dsh-qq-bridge @ 0.1.3
✓Node 引擎要求 >=22.19 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/31 17:44:03
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 48 处,展示前 48 条)
- 写入本地文件lib/index.js:13
appendFileSync("/tmp/qq-start-debug.log", `${new Date().toISOString()} ${args.join(" ")} - 写入本地文件lib/index.js:60
appendFileSync("/tmp/dsh-qq-bridge-gw.log", `${new Date().toISOString()} ${message}\n`); - 读取密钥环境变量lib/index.js:99
const tokenUrl = process.env.QQBOT_TOKEN_URL; - 删除本地文件lib/index.js:212
rmSync(rt.lock.path, { force: true }); - 删除本地文件lib/index.js:275
rmSync(rt.lock.path, { force: true }); - 写入本地文件lib/index.js:564
mkdirSync(process.cwd(), { recursive: true }); - 写入本地文件lib/index.js:565
writeFileSync(process.cwd() + "/.boot-marker", JSON.stringify({ applied: true, at: Date.now(), pid: process.pid }, null, 2)); - 读取本地文件lib/core/config.js:141
raw = readFileSync(filePath, "utf8"); - 写入本地文件lib/core/config.js:182
mkdirSync(dir, { recursive: true }); - 写入本地文件lib/core/config.js:184
writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n", { mode: 0o600 }); - 写入本地文件lib/core/config.js:185
renameSync(tmp, filePath); - 发起网络请求lib/gateway/qq-auth.js:76
const res = await fetch(this.tokenUrl, { - 发起网络请求lib/gateway/qq-gateway.js:140
const gatewayRes = await fetch(`${this.apiBase}/gateway`, { - 发起网络请求lib/gateway/qq-gateway.js:148
const retryRes = await fetch(`${this.apiBase}/gateway`, { - 发起网络请求lib/gateway/qq-api.js:91
const res = await fetch(targetUrl, { method: "PUT", body: data, signal: putSignal }); - 发起网络请求lib/gateway/qq-api.js:143
const res = await fetch(`${this.base}/interactions/${encodeURIComponent(interactionId)}`, { - 发起网络请求lib/gateway/qq-api.js:158
const res2 = await fetch(`${this.base}/interactions/${encodeURIComponent(interactionId)}`, { - 发起网络请求lib/gateway/qq-api.js:189
res = await fetch(`${this.base}${path}`, { - 读取本地文件lib/instance-guard.js:24
const raw = readFileSync(path, "utf8"); - 读取本地文件lib/instance-guard.js:33
const mtime = statSync(path).mtimeMs; - 写入本地文件lib/instance-guard.js:50
writeFileSync(lockPath, payload, { flag: "wx", mode: 0o600 }); - 删除本地文件lib/instance-guard.js:68
rmSync(lockPath); - 读取本地文件lib/instance-guard.js:82
const data = JSON.parse(readFileSync(lockPath, "utf8")); - 读取本地文件lib/instance-guard.js:102
if (existsSync(lock.path)) - 删除本地文件lib/instance-guard.js:103
rmSync(lock.path); - 读取本地文件lib/instance-guard.js:118
const data = JSON.parse(readFileSync(lockPath, "utf8")); - 读取本地文件lib/instance-guard.js:128
if (!existsSync(dir)) - 写入本地文件lib/instance-guard.js:129
mkdirSync(dir, { recursive: true }); - 读取本地文件lib/session/qq-session.js:25
return JSON.parse(readFileSync(metaPathFor(base), "utf8")); - 写入本地文件lib/session/qq-session.js:33
mkdirSync(dirname(path), { recursive: true, mode: 0o700 }); - 写入本地文件lib/session/qq-session.js:34
writeFileSync(path, JSON.stringify(meta, null, 2) + "\n", { mode: 0o600 }); - 读取本地文件lib/session/workspace-registry.js:89
if (!statSync(real).isDirectory()) { - 读取本地文件lib/session/workspace-registry.js:108
return existsSync(path) && statSync(path).isDirectory(); - 读取本地文件lib/session/workspace-registry.js:108
return existsSync(path) && statSync(path).isDirectory(); - 读取本地文件lib/media/attachment-pipeline.js:135
const bytes = await readFile(downloaded.path); - 读取本地文件lib/media/outbound-media.js:57
const pinnedPath = await realpath(`/proc/self/fd/${opened.fd}`).catch(() => realpath(path)); - 读取本地文件lib/media/outbound-media.js:183
candidate = await realpath(normalized); - 读取本地文件lib/media/outbound-media.js:195
roots.push(await realpath(normalizeInputPath(rootInput, cwd))); - 写入本地文件lib/media/attachment-downloader.js:45
await mkdir(this.workspace, { recursive: true, mode: 0o700 }); - 删除本地文件递归lib/media/attachment-downloader.js:54
await rm(this.workspace, { recursive: true, force: true }).catch(() => undefined); - 写入本地文件lib/media/attachment-downloader.js:94
await pipeline(response, createWriteStream(filePath, { flags: "wx", mode: 0o600 }), { - 写入本地文件lib/media/attachment-downloader.js:97
await chmod(filePath, 0o600); - 读取本地文件lib/media/attachment-downloader.js:98
const info = await stat(filePath); - 删除本地文件lib/media/attachment-downloader.js:114
await rm(filePath, { force: true }).catch(() => undefined); - 读取本地文件lib/media/attachment-extractors.js:18
const bytes = await readFile(path); - 读取本地文件lib/media/attachment-extractors.js:43
const bytes = await readFile(path); - 读取本地文件lib/media/stt.js:25
const bytes = await readFile(input.path); - 发起网络请求lib/media/stt.js:31
response = await fetch(`${config.baseUrl.replace(/ +$/, "")}/audio/transcriptions`, {
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-agent@deepseek-ai/dsh-commands@deepseek-ai/dsh-llm@deepseek-ai/dsh-session@deepseek-ai/dsh-tools给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- QQ私聊群聊接入
- 每对话隔离持久会话
- 支持命令审批多媒体
将 QQ(私聊+群聊)接入 DeepSeek Harness 的双向桥插件:每个 QQ 对话一个隔离持久 Agent 会话,支持命令/审批/多媒体/出站文件
README
由 DeepSeek 最新模型翻译生成dsh-qq-bridge
npm version
npm downloads
License
GitHub repo
将 QQ 接入 DeepSeek Harness 的双向桥插件——通过 QQ 官方机器人 API v2(私聊 + 群聊),让你直接在 QQ 里驱动 DeepSeek Harness 的 Agent:每个 QQ 对话拥有独立、持久的隔离 Agent 会话,像在 Web 里一样使用完整的工具链、模型切换与工作区。
✨ 特性
- 🔌 零依赖网关:QQ 官方 WebSocket 协议(token 预刷新 / 心跳假死检测 / 指数退避重连 / Resume 补发),仅用 Node 内置能力
- 🧊 隔离会话:每 QQ 对话 ↔ 一个持久 DSH Agent(agents.create/resume),历史按 (对话, 工作区) 隔离,重启自动恢复
- ⚡ steering 插嘴:任务运行中继续发消息,立即注入下一步骤(DSH 原生)
- 📚 完整命令体系:/help /status /model /thinking /new /sessions /resume /compact /stop /workspace + 键盘按钮
- 🔐 首访审批:未授权用户自动生成审批码,管理员一键授权(支持普通用户/管理员两级)
展开完整文档(README 剩余 1 节)
dsh-qq-bridge
npm version
npm downloads
License
GitHub repo
将 QQ 接入 DeepSeek Harness 的双向桥插件——通过 QQ 官方机器人 API v2(私聊 + 群聊),让你直接在 QQ 里驱动 DeepSeek Harness 的 Agent:每个 QQ 对话拥有独立、持久的隔离 Agent 会话,像在 Web 里一样使用完整的工具链、模型切换与工作区。
✨ 特性
- 🔌 零依赖网关:QQ 官方 WebSocket 协议(token 预刷新 / 心跳假死检测 / 指数退避重连 / Resume 补发),仅用 Node 内置能力
- 🧊 隔离会话:每 QQ 对话 ↔ 一个持久 DSH Agent(agents.create/resume),历史按 (对话, 工作区) 隔离,重启自动恢复
- ⚡ steering 插嘴:任务运行中继续发消息,立即注入下一步骤(DSH 原生)
- 📚 完整命令体系:/help /status /model /thinking /new /sessions /resume /compact /stop /workspace + 键盘按钮
- 🔐 首访审批:未授权用户自动生成审批码,管理员一键授权(支持普通用户/管理员两级)
- 🖼️ 多媒体:图片直入视觉模型、语音 ASR/STT、TXT/PDF 有界提取;安全下载(SSRF 防护)
- 📤 出站文件:Agent 可调用 qq_send_local_file 把本地文件发回 QQ(白名单 + 硬链接/竞态防护)
- 🗂️ 多工作区:QQ 侧 /workspace 切换目录,会话历史按工作区隔离
- ✅ 实测可用:116 个单测 + 真实 QQ 沙箱文本闭环验证
移植自 pi-qq-bridge(Apache-2.0):宿主无关模块(网关/路由/命令/媒体/格式化)原样复用;宿主绑定层(会话创建/工具/命令)改为 DSH 官方 API。
架构
QQ 平台 WS 事件 → src/gateway/qq-gateway.ts(状态机/心跳/重连/Resume) → src/router.ts(去重 → 白名单/审批 → 命令 | FIFO 队列 → 隔离会话) → src/session/qq-session.ts(DSH 适配:ctx.agents.create/resume + followup/whenIdle) → 最终文本 → src/reply-formatter.ts(Markdown 分块 → 降级纯文本)→ QQApi 发送
| 模块 | 说明 |
| src/gateway/ | token 管理 / WS 网关 / REST 发送与上传(宿主无关,原样移植) |
| src/session/ | DSH 隔离会话:每 QQ 对话 ↔ 一个持久 DSH agent(sessionId qq--,cwd = 桥工作区);注册表懒创建/回收/工作区切换 |
| src/router.ts | 消息路由、steering 插嘴、回复预算(宿主无关) |
| src/commands/ | QQ 侧命令、授权矩阵、审批码、键盘(宿主无关) |
| src/media/ | 附件安全下载/嗅探/提取/STT/出站媒体(宿主无关;图片经 ctx.attachments) |
| src/core/ | 配置(schemaVersion 4 严格校验)/ 类型 / 错误码(宿主无关) |
关键宿主 API(详见 HOST-API.md):
- 会话:ctx.agents.create({sessionId, meta:{cwd}, agentOptions, setup}) / ctx.agents.resume({resumeSessionId})
- 运行:agent.followup(createUserMessage(...)) + agent.whenIdle() + 事件摘要(官方范式,见 dsh-headless)
- 插嘴/中止:agent.steer / agent.cancel({kind:'user'})
- 模型:ctx.agentDefaultModel + installModelSelection;ctx.llm.listProviders/listModels
- 工具:ctx.tools.register(defineTool(...))(agent 作用域,QQ 会话专属 qq_send_local_file)
- 命令:ctx.commands.register(全局,Web UI 可见)
- 图片:ctx.attachments.saveImage → ImageBlock
安装
开发/冒烟(dev profile,不碰运行中的 GUI)
1. 插件依赖(typescript/@types/node + unpdf)
cd ~/dsh-qq-bridge && pnpm install
2. dev profile(已存在 ~/.dsh/profiles/dev,bundles: dsh-base + dsh-headless)
dsh plugin --profile dev add ~/dsh-qq-bridge
3. 冒烟:headless 任务 + 插件 overlay
dsh --profile dev --patch ~/dsh-qq-bridge/dev-overlay.yml 'Reply with exactly: OK'
验证:qqbotdsh/.boot-marker 出现(apply 已执行)
挂载到 web profile(正式使用;需重启 dsh web)
dsh plugin --profile web add ~/dsh-qq-bridge
编辑 ~/.dsh/profiles/web/cordis.patch.yml 追加:
- insert:
- id: dsh-qq-bridge
name: 'dsh-qq-bridge'
重启 dsh web(注意:这是你正在用的 GUI 服务器)
配置
cp config.example.json ~/.dsh/qq-bridge/config.json
chmod 600 ~/.dsh/qq-bridge/config.json
填入 appId / clientSecret;sandbox 保持 true
字段与 pi-qq-bridge 一致(schemaVersion 4):allowUsers / allowGroups / workspaces / commands / sessions / replyFormat / progress / media / outboundMedia 等。
Windows 原生部署适配
在 Windows 原生(非 WSL)环境部署时注意以下三点(对应 PR #6/#8):
1. 工作区避开 C:/Users/...(含 Temp)
Windows 的 windows-acl 沙箱要求临时目录(temp root)在会话工作区之外;若默认工作区落在 C:/Users/(其子目录通常包含 Temp),会触发沙箱冲突(temp root must be outside the workspace)。
解决:在配置里显式指定一个非 home 的工作区,插件会自动优先选用它作为 QQ 会话的默认工作区:
{
"workspaces": [
{ "name": "default", "path": "" },
{ "name": "work", "path": "D:/dev/qq-workspace" } // 非 C:/Users 的目录 ] }
(插件逻辑:默认工作区优先取配置中第一个 path 非空且不以 c:/users/ 开头的 workspace。)
2. 出站文件 allowedRoots 白名单
qq_send_local_file 工具只允许发送 allowedRoots 列出的目录(OS 临时目录恒可用)。
Windows 路径请写绝对路径,例如:
{
"outboundMedia": {
"enabled": true,
"allowedRoots": ["D:/dev/qq-workspace", "C:/data/shared"]
}
}
注意:路径校验走 realpath,符号链接/硬链接会被拒绝;不允许用 C:/Users/... 作为出站根目录(与沙箱策略冲突)。
3. sandbox 策略说明
- 会话沙箱工作目录 = 会话工作区(见第 1 点),写入仅限工作区内;越界写入需审批(审批桥见 PR #3)
- windows-acl 沙箱在 Windows 原生环境启用;WSL/Linux 下为普通目录权限模型
- 若使用正式环境(sandbox: false),以上沙箱限制由平台侧接管,出站文件仍需 allowedRoots 白名单
本地命令(Web 聊天里输入,注册于 ctx.commands)
| 命令 | 说明 |
| /qqbot-start / /qqbot-stop | 启动/停止 QQ 网关 |
| /qqbot-status | 网关/会话/队列/配置/锁状态 |
| /qqbot-reconnect | 强制重连 |
| /qqbot-requests | 待审批访问申请列表 |
| /qqbot-approve [--yes] | 批准申请(admin 需 --yes 二次确认) |
| /qqbot-deny | 拒绝申请(1h 冷却) |
| /qqbot-revoke [--yes] | 撤销权限 |
| /workspace [名称] \| add \| remove | 工作区管理 |
QQ 侧命令(发给机器人)
/help /status /last /model /thinking /new /sessions /resume
/name /compact /stop /workspace(管理命令需 commands.admins)
测试
npm run typecheck # tsc --noEmit
npm test # 116 个测试(node:test;网关测试用本地 mock QQ 平台,含真实 WS 协议)
真宿主自测(无需 QQ 凭据)
在纯 dsh-base 的 dev-int profile 里跑(不要用 headless profile——headless 任务完成后会关停整棵树,与自测赛跑导致 agent 被 dispose):
一次性准备
dsh plugin --profile dev-int add ~/dsh-qq-bridge
每次验证
DSH_QQBRIDGE_SELFTEST=1 dsh --profile dev-int --patch ~/dsh-qq-bridge/dev-overlay.yml
cat ~/dsh-qq-bridge/.selftest-result.json # ok: true = 全链路通过
覆盖:agents.create(sessionId/cwd/setup)→ 真模型两轮调用 → 持久化 → 跨进程恢复 → newSession → resume → 命名。
全链路集成测试(mock QQ 平台 + 真 DSH 宿主 + 真模型)
无需 QQ 凭据即可验证完整业务闭环(WS 网关 ↔ 路由 ↔ 隔离会话 ↔ 模型 ↔ 回复):
一次性准备
cd ~/dsh-qq-bridge && pnpm install
cd ~ && dsh plugin --profile dev-int add ~/dsh-qq-bridge/scripts/integration-driver
每次验证(mock 固定端口 18432/18433)
QQBOT_CONFIG_PATH=~/dsh-qq-bridge/scripts/integration-config.json \
QQBOT_API_BASE=http://127.0.0.1:18432 \
QQBOT_TOKEN_URL=http://127.0.0.1:18432/app/getAppAccessToken \
dsh --profile dev-int --patch ~/dsh-qq-bridge/int-overlay.yml
cat ~/dsh-qq-bridge/.integration-result.json # ok: true = 闭环通过
覆盖:网关握手/心跳 → C2C 消息注入 → 白名单 → 队列 → 真 DSH 会话 → 真模型调用 → Markdown 格式化 → 被动回复回传。测试期环境变量:QQBOT_CONFIG_PATH / QQBOT_API_BASE / QQBOT_TOKEN_URL(mock 平台注入,不影响正式运行)。
🙏 致谢
本项目在设计与实现过程中参考了以下开源项目(协议处理、架构思路与安全设计深受启发),代码为独立实现:
- pi-agent-qqbot(Apache-2.0)— 原生会话绑定方案、被动回复预算(ReplyBudget)、网关所有权转移
- @xsqm/pi-qqbot(Apache-2.0)— 隔离 AgentSession 架构(本项目骨架来源)、附件安全下载管线、语义分块回复格式
- pi-qq-integration(MIT)— 轻量 WebSocket 客户端与 Access Token 管理参考
本插件直接移植自 pi-qq-bridge(Apache-2.0),其宿主无关模块(网关/路由/命令/媒体/格式化)原样复用。
状态与验证进度
- ✅ 沙箱 mock 全链路单测(116 个)
- ✅ dev profile 装载冒烟(apply/命令注册/网关生命周期)
- ✅ 真实 QQ 沙箱文本闭环(私聊 C2C:消息 → 隔离会话 → 模型回复 → 送达 QQ)
- ⚠️ 分片上传协议字段、op9 4009 行为、Markdown 拒绝特征——以上线实测为准
群聊支持状态(重要)
代码层面完整支持群聊(GROUP_AT_MESSAGE_CREATE 意图、allowGroups 白名单、群回复),但沙箱环境无法实测:QQ 开放平台沙箱要求把测试群加入沙箱配置的白名单,个人开发者账号无法在沙箱中配置群聊测试(平台限制,非代码问题)。
群聊接入正式环境的步骤:
1. 机器人应用通过平台提审上线(sandbox: false)
2. 把机器人拉入目标群
3. 获取群 openid(机器人入群后,群内 @ 机器人一次,从网关日志的 [router] 入站 ... group= 行取得)
4. 把群 openid 加入配置 allowGroups,重启桥
5. 群内 @ 机器人即可对话
开发期开关(默认全部关闭)
| 环境变量 | 作用 |
| DSH_QQBRIDGE_SELFTEST=1 | apply 时运行真宿主自测(src/dev/self-test.ts,结果写 .selftest-result.json) |
| DSH_QQBRIDGE_BOOT_MARKER=1 | 写开发期冒烟标记 .boot-marker |
| QQBOT_DEBUG_START=1 | 启动诊断写 /tmp/qq-start-debug.log |
| QQBOT_CONFIG_PATH / QQBOT_API_BASE / QQBOT_TOKEN_URL | 测试/集成环境覆盖(mock 平台) |
开发期 node_modules/@deepseek-ai 是指向 ~/.dsh/profiles/node_modules/@deepseek-ai 的符号链接(保证与宿主单一拷贝;发布版由 peerDependencies 解析)。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
xiaomengxinbb/dsh-qq-bridge
在 QQ 私聊与群聊中直接驱动 Agent 干活
相关插件 · 平台集成
智能体工程课walkinglabs/learn-harness-engineering
一门项目制课程,教你搭建环境、管理状态、做验证、加控制机制,让 AI 编程智能体稳定干活。
★ 21,155已汉化DSH
71.7
视频翻译配音liuzhao1225/YouDub-webui
开源视频本地化工作台:导入视频,识别、翻译并逐句克隆原声,生成字幕和配音成片。
★ 5,778已汉化Cordis
71.4
失败经验库Ikalus1988/MisakaNet
📚 零依赖、由 git 支撑的微课程库,让 AI 智能体异步分享并检索经过验证的调试经验。| https://misakanet.org
★ 550已汉化DSH
71.2
桌面智能体工作区freestylefly/wesight
WeSight 是开源桌面控制台,面向本地 AI 智能体。它帮你安装或复用 Claude…
★ 933已汉化MCP
71
IM 机器人接入xmanrui/dsh-im
让 DeepSeek Harness 触手可及 Connecting DeepSeek Harness
★ 3,110已汉化DeepSeek 客户端
70.9
中国平台研究引擎Jesseovo/last30days-skill-cn
给 AI Agent 的中文互联网研究 Skill:检索 8 大平台最近 30…
★ 2,031已汉化DSH
70.7