@qqbot/dsh-plugin-qq — QQ ↔ DSH 桥接插件
35.9/100
综合分
2
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/29 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
该插件未发布到 npm,按作者文档从 GitHub 源安装即可(静态检查只覆盖 npm 路径,不代表插件不可用)。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add flyinstar/dsh-qq-bridge该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · platform
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 11 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装仓库 package.json 标记 private,未发布到 npm,需从源码安装
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✗npm 包@qqbot/dsh-plugin-qq(未发布到 npm,仅可源码安装)
✓Node 引擎要求 >=22 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/30 00:33:16
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件发起外部网络请求
查看扫描证据(共 70 处,展示前 65 条)
- 写入本地文件index.js:693
void mkdir(dirname(reminderRoot), { recursive: true }) - 读取本地文件index.js:785
names = readdirSync(dir); - 读取本地文件index.js:792
const parsed = JSON.parse(await readFile(join(dir, name), 'utf8')); - 写入本地文件index.js:823
await mkdir(dir, { recursive: true }); - 读取本地文件index.js:2701
sketch = perceptualHash(await readFile(resolve(cwd, path))); - 写入本地文件index.js:4559
void mkdir(stickerRoot, { recursive: true }).catch((error) => { - 发起网络请求client.js:1864
const response = await fetch(REMINDER_TASKS_PATH, { - 发起网络请求client.js:2026
const response = await fetch(SESSION_ROUTE_PATH, { - 发起网络请求client.js:2058
const response = await fetch(SESSION_ROUTE_PATH, { - 读取本地文件image.js:166
const info = await stat(target).catch(() => undefined); - 读取本地文件image.js:170
bytes = await readFile(target); - 读取本地文件media.js:289
const info = await stat(target).catch(() => undefined); - 读取本地文件media.js:293
return readFile(target); - 读取本地文件media.js:330
entries = await readdir(directory, { withFileTypes: true }); - 读取本地文件media.js:338
const info = await stat(full).catch(() => undefined); - 删除本地文件media.js:344
await unlink(stale.full).catch(() => {}); - 读取本地文件media.js:375
const existing = await stat(target).catch(() => undefined); - 写入本地文件media.js:377
await utimes(target, new Date(), new Date()).catch(() => {}); - 写入本地文件media.js:381
await writeFile(target, built.png); - 写入本地文件media.js:403
await mkdir(directory, { recursive: true }); - 读取本地文件media.js:404
const existing = await stat(target).catch(() => undefined); - 写入本地文件media.js:407
await utimes(target, new Date(), new Date()).catch(() => {}); - 写入本地文件media.js:409
await writeFile(target, bytes); - 读取本地文件sticker-frames.js:68
const entries = await readdir(stickerRoot, { withFileTypes: true }).catch(() => []); - 写入本地文件sticker-frames.js:86
await mkdir(sheets, { recursive: true }).catch(() => {}); - 读取本地文件sticker-frames.js:91
const bytes = await readFile(join(stickerRoot, name)); - 读取本地文件sticker-frames.js:117
const existing = await readFile(target).catch(() => undefined); - 写入本地文件sticker-frames.js:121
await writeFile(target, built.png); - 读取本地文件sticker-frames.js:127
const entries = await readdir(sheets, { withFileTypes: true }).catch(() => []); - 删除本地文件sticker-frames.js:130
await unlink(join(sheets, entry.name)).catch(() => {}); - 读取本地文件napcat.js:320
if (!existsSync(dir)) return { found: false, reason: `目录不存在:${dir}` }; - 写入本地文件napcat.js:410
await copyFile(found.file, backup); - 读取本地文件napcat.js:460
if (existsSync(configDir)) { - 读取本地文件sticker.js:60
return readdirSync(stickerRoot, { withFileTypes: true }) - 读取本地文件sticker.js:273
const occupied = existing.includes(fileName) || (await stat(target).catch(() => undefined)) !== undefined; - 写入本地文件sticker.js:277
await mkdir(stickerRoot, { recursive: true }); - 读取本地文件sticker.js:354
const size = (await stat(join(stickerRoot, found)).catch(() => undefined))?.size; - 读取本地文件sticker.js:360
if ((await stat(targetPath).catch(() => undefined)) !== undefined) { - 读取本地文件sticker.js:363
const size = (await stat(sourcePath)).size; - 写入本地文件sticker.js:364
await rename(sourcePath, targetPath); - 写入本地文件sticker.js:379
await rename(targetPath, sourcePath).catch(() => {}); - 写入本地文件sticker.js:383
await rename(targetPath, sourcePath).catch(() => {}); - 发起网络请求key-rotation.js:72
const response = await fetch(url, { - 写入本地文件memory.js:314
await mkdir(paths.logDir, { recursive: true }); - 写入本地文件memory.js:315
await appendFile(file, `${JSON.stringify(line)}\n`, 'utf8'); - 写入本地文件memory.js:326
await mkdir(paths.dir, { recursive: true }); - 写入本地文件memory.js:489
await mkdir(memoryRoot, { recursive: true }); - 读取本地文件memory.js:607
const info = statSync(absolute); - 读取本地文件memory.js:611
const fresh = { key, text: readFileSync(absolute, 'utf8') }; - 读取本地文件memory.js:672
months = readdirSync(memoryPaths(key).archiveDir) - 写入本地文件memory.js:729
await mkdir(memoryRoot, { recursive: true }); - 读取本地文件memory.js:862
const info = statSync(absolute); - 读取本地文件memory.js:865
return { text: readFileSync(absolute, 'utf8'), key: `${info.size}:${info.mtimeMs}` }; - 写入本地文件memory.js:1197
await mkdir(dirname(absolute), { recursive: true }); - 删除本地文件memory.js:1378
for (const old of kept.slice(0, Math.max(0, kept.length - HISTORY_KEEP))) await unlink(join(dir, old)).catch(() => {}); - 写入本地文件filestore.js:22
await writeFile(temp, `${JSON.stringify(payload, null, 2)}\n`, 'utf8'); - 写入本地文件filestore.js:23
await rename(temp, absolute); - 写入本地文件filestore.js:33
await writeFile(temp, text, 'utf8'); - 写入本地文件filestore.js:34
await rename(temp, absolute); - 写入本地文件filestore.js:47
await writeFile(temp, bytes); - 写入本地文件filestore.js:48
await rename(temp, absolute); - 读取本地文件filestore.js:70
return await readFile(absolute, 'utf8'); - 读取本地文件filestore.js:103
return await readdir(absolute); - 读取本地文件docfile.js:57
info = statSync(absolute); - 读取本地文件docfile.js:67
text = readFileSync(absolute, 'utf8');
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-llm@deepseek-ai/dsh-tools@deepseek-ai/schemastery给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
README
由 DeepSeek 最新模型翻译生成展开完整文档(README 剩余 1 节)
@qqbot/dsh-plugin-qq — QQ ↔ DSH 桥接插件 个人自用项目,顺手传到 GitHub 方便朋友下载。文档里的配置与取舍都是照着我这一台机器的用法写的,没有做成通用插件,也不保证开箱即用 ——想拿去玩的话,照着文档慢慢改就行。 把 QQ(通过 OneBot v11,如 NapCat / Lagrange / go-cqhttp)接到 DeepSeek Harness: - 入站:QQ 私聊或群里 @机器人 的消息 → 交给一个专属的 DSH 智能体会话处理 → 结果自动发回 QQ。 - 出站:任何 DSH 智能体(包括 Web UI 里的主会话)都能调用 qq_send_* 主动发消息 / 图片。 - 像群友一样说话:几条消息攒成一轮、回复拆成短气泡、按打字节奏发出、引用 / @ 指向该指的人。 - 它自己的小动作:群里刷同一个字时跟着复读;安静下来后偶尔主动冒个泡;聊起来之后免 @ 接话、回完再补一句;别人撤回消息时会清掉引用(默认假装没看到)。 - 图片与表情包:能 read_image 真的看图(动图会额外拆一张分镜图,不只看到第一帧);能发表情包;能把你发的表情存进自己的收藏目录。 - 定时提醒:让它在明早 8 点提醒谁、每周一 @ 谁开会 —— 到点由插件直接发,重启不丢。 - 长期记忆:每句话落盘,每天由独立摘要会话整理成「这个群记得什么」;聊天时按当前消息检索相关条目(含全局人物表与梗),不再只读文件开头,文件满了会滚进 archive/ 而不是删掉。 它能做什么 | 能力 | 一句话 | 细节 | | 双向聊天 | 一个 QQ 会话 = 一个持久 Session,重启后 resume,聊天记忆不丢 | 会话与轮次 | | 人格与表达 | 「是谁」写 PERSONA.md,「怎么说」写 STYLE.md,都热读 | 人格与表达 | | 群友式说话 | 攒批、气泡条数(模型自己写)、分条与打字延迟、私聊「正在输入」、引用 / @、[[@昵称]] | 说话方式与节奏 | | 自动复读 | 群里刷同一个字 / 同一张表情时,插件不经过模型跟着发 | 自动复读 | | 主动开口 | 冷场冒泡、免 @ 接话、回完补一句(私聊永远不主动打扰) | 主动开口 | | 图片与表情包 | 看图(动图拆分镜图)、发表情、存表情;链接 / 视频 / 语音 / 戳一戳各有下场 | 图片与感知 | | 被撤回的消息 | 清引用是安全层;要不要调侃是配置 | 被撤回的消息 | | 定时提醒 | 到点发固定文案 / 让模型换语气 / 到点做事,可 @ 人 | 定时提醒 | | 长期记忆 | 转录 → 每日摘要 → MEMORY.md / archive/ / PEOPLE.md / COGNITION.md / STICKERS.md → 检索式注入 | 长期记忆 | | 工具与能力面 | 自带最小 qq 预设 + allowTools 白名单 | 工具与能力面 | | 运维 | doctor / status / logs / restart,三套部署共用 | 运维 | 30 秒开始 1. 装好 DSH,在 Web UI 的 Models 页填一次模型凭据。 2. 拿代码:到 Releases 下载发布包,或者 git clone 本仓库。 Windows 上解压后双击 scripts\napcat-setup.cmd,它会把 NapCat 与插件一起配好。 3. 让 NapCat 开一个 WebSocket 服务器(不是 websocketClients),端口与 endpoint 一致(默认 3001),扫码登录。 4. 起常驻进程:dsh --profile qqbot --port 3081 --no-open(或 deploy/qqbot.service)。 5. 私聊机器人发一句话,它在 QQ 里回你就说明整条链路通了。 想让它像某个具体的人:照写人设:模板与问答走 —— 复制两份模板改四处,或者让智能体用 18 道选择题问你一遍,再跑一个自检脚本看看「模型会看到什么」。 | 你的平台 | 照着哪一页装 | | Windows(桌面版 DSH 与 NapCat 在同一台机器上) | Windows 桌面版 | | Linux / 容器(NapCat 跑在 docker 里) | 安装与运行 | 改了什么、这个版本有什么,见 CHANGELOG.md。 工作原理 QQ 客户端 ──▶ NapCat ──(OneBot v11 WebSocket)──▶ 本插件 │ 每个会话映射一个 DSH Session │ Agent 产出最终回复 ──▶ 发回 QQ - 一个 QQ 会话(一个私聊对象 / 一个群)= 一个持久化 Session。Session id 由会话 key 经 SHA-256 派生,是确定性的:Harness 重启后同一个人再发消息,插件会 resume 原有会话。 /reset 不改这个算法,只是把「第几轮」也算进摘要(见会话与轮次)。 - 智能体的回复取该 turn 里最后一条有文本的 assistant 消息;中间步骤的工具调用不会发给 QQ。 - 前后脚到的消息先攒一个窗口(batchWindowMs,默认 2 秒)再投给智能体;回复会拆成几条短消息、按打字节奏发出,被叫到时按 replyStyle 引用 / @ 该指的人 —— 它自己凑上来的「搭话」不挂任何指向(见说话方式与节奏)。 - 群消息默认只在被 @ 时触发;私聊 / 群里的「没有正文」消息、复读、主动搭话、表情包那几条旁路各有自己的闸门,默认值都偏保守(见安全提醒)。 配置 全部配置项在 cordis.patch.yml 的 config: 下(schema 在 config.js,字段上的中文 .description() 就是给用户看的说明),也可以在 Web UI 的 设置 → QQ Bridge 里改。完整的字段表与设置页说明见配置项。 ⚠️ 不要手写一个只有几个字段的 config: 去覆盖它。 DSH 的 patch 是整块替换、不是深合并:只写一个 resetUsers 也会把 agentPreset / allowTools / proactive 一起顶掉,QQ 会话会挂上带 shell 的默认预设。改配置走仓库 patch 或 Web UI;每台部署不同的值走环境变量。 常改的几项: | 字段 | 默认 | 说明 | | endpoint | ws://127.0.0.1:3001 | OneBot v11 正向 WebSocket 地址(QQBOT_ENDPOINT) | | accessToken | '' | OneBot access_token(QQBOT_ACCESS_TOKEN) | | cwd | 进程当前目录 | QQ 会话 Agent 的工作目录,也是媒体 / 记忆 / 人设的落点 | | groupTrigger | mention | 群消息触发:mention / prefix / all | | allowUsers / allowGroups | [] | 私聊 / 群白名单;空 = 不限制 | | agentPreset | qq | QQ 会话挂的 Agent 预设(自带的最小预设,没有 shell) | | allowTools | 18 个工具 | QQ 会话的工具白名单;默认没有 write / edit / bash | | proactive | true | 允许它在群里主动开口(私聊不会) | | activeFollow | true | 群里聊起来之后免 @ 接话:@ 一次之后那个人的下一条不用再 @,最多连着回 10 条、间隔超过 3 分钟算断聊(刻意放松「只在被 @ 时说话」) | | memory | true | 长期记忆:转录 + 每日摘要 + 认知库 + 人物表 + 检索式注入 + 两个记忆工具 | | recallMode | ignore | 被撤回的消息:清引用永远做,调侃要显式开 tease | | reminder | true | 定时提醒;默认只能提醒自己,@ 别人 / @全体默认关 | | apiKeyRotate | true | 每天 04:00 从 data/api-keys.txt 轮换一把探测通过的 key | 安全(先看这三条) - QQ 消息是不可信输入:默认 approvalPolicy: never、群消息只在被 @ 时触发。activeFollow / proactive / privateAfterthought 默认开,是刻意放松了「只在被叫到时说话」,每一条都有自己的闸门与上限;不放心就关掉。 - qq_save_sticker 是唯一让 QQ 会话按自己给的字节直接写磁盘的工具:只写表情包目录、文件名洗成单层、同名不覆盖、张数受上限约束。qq_rename_sticker 也能动那个目录,但它只能给已收藏的文件换个名字(不引入新字节、失败会回滚)。qq_remind_create 也会落盘,但写的是 reminderFile 里由纯函数校验过字段的任务。除此之外 QQ 会话没有 write / edit / bash。 - 会写全局状态的两处:apiKeyRotate 改 $DSH_HOME/.credentials.yaml;linkPreview 默认关(开了等于替群里任何人访问任意 URL)。定时提醒会把「未来要说的话」写进 data/reminders.json 并在到点发出,所以默认只能提醒自己、@ 别人默认关。细节与取舍见安全提醒。 文档地图 | 文档 | 内容 | | 安装与运行 | Linux / 容器:下载、NapCat 要求、qqbot profile、systemd、凭据 | | Windows 桌面版 | 一键脚本、隐藏窗口、提权、装进 desktop profile、自检与排查 | | 配置项 | 全部字段、Web UI 设置页、改配置的正确姿势 | | 人格与表达 | PERSONA.md / STYLE.md 的格式、组合规则、三道防线 | | 写人设:模板与问答 | 两份复制就能用的模板、一份会提问的提示词、一个不用启动机器人的自检脚本 | | 说话方式与节奏 | 攒批、气泡条数(模型自己写)、分条 / 打字延迟、指向、[[@昵称]]、空消息 | | 自动复读 | 文字与表情包复读、画面指纹、带宽账 | | 主动开口 | 偶尔主动说话、活跃对话、私聊补一句 | | 图片、表情包与感知 | 看图、发表情、存表情、base64、链接 / 视频 / 语音 / 戳一戳 | | 被撤回的消息 | 三层处理、模式矩阵、配置与实现要点 | | 定时提醒 | 三种模式、时间规则、权限与额度、重启/断线//reset | | 长期记忆 | 转录、每日摘要、检索式注入、冷热分层、人物表、认知库、表情包目录、五个 skill | | 会话与轮次 | 确定性 Session id、/reset、旧会话存档、Web UI 的「重置对话」按钮 | | 工具与能力面 | 工具表、agentPreset、allowTools | | 运维 | scripts/ops.mjs、doctor 的 finding、八个排查场景、key 轮换 | | 本机开发与测试 | 依赖、重启规则、node --test、行为覆盖清单 | | 安全提醒 | 所有扩大能力面 / 主动发消息的开关与默认值 | | AGENTS.md | 给要改这个项目的 agent 的代码说明书(不面向用户) | 开发 node --test test/ # 全部用例 node --test test/settings.test.mjs # 只跑配置取值口径 改完源码必须重启 Harness(Loader 按 URL 缓存模块,停用 / 启用插件拿不回新代码)。 本机依赖怎么铺、测试覆盖了什么、Windows / 沙箱里的跑法,见本机开发与测试;代码结构、模块依赖与「改哪里」的索引见 AGENTS.md。 许可 MIT。
预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
flyinstar/dsh-qq-bridge
@qqbot/dsh-plugin-qq — QQ ↔ DSH 桥接插件
相关插件 · 平台集成
智能体工程课walkinglabs/learn-harness-engineering
一门项目制课程,教你搭建环境、管理状态、做验证、加控制机制,让 AI 编程智能体稳定干活。
★ 21,155已汉化DSH
71.7
视频翻译配音liuzhao1225/YouDub-webui
开源视频本地化工作台:导入视频,识别、翻译并逐句克隆原声,生成字幕和配音成片。
★ 5,792已汉化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
这是你的仓库?认领条目