DeepSeek Harness 插件

cheesehaqi/dsh-qq-onebot-bridge

Star 数 ★ 5 分类 通知与集成 收录于 2026-08-28

基于 OneBot v11 反向 WebSocket 的 QQ 双向桥:每群/每私聊用户独立会话、@引用语音转文字、私聊图片/动画表情识图、表情与贴纸工具。

安装

# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)

dsh plugin --profile web add github:cheesehaqi/dsh-qq-onebot-bridge

装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。

README

QQ ↔ DeepSeek Harness 双向桥插件(独立 bundle)。QQ 消息直接驱动 DSH agent 会话,agent 回复自动发回 QQ。

v0.4.0 主题:一切皆可调试。每条消息一个 traceId、每个"没回复"都有中文原因、任意历史消息都能离线重跑、假事件能喂进真实管线——而且这 6 条硬约束在自带控制台里随时可验收(见「调试」与「硬约束验收台」)。

功能总览

这里只列最近两个大版本新增的能力(v0.5 线与 v0.4 线)。更早的基础能力——双向消息桥、会话续接、持久化记忆、定时提醒、群管套件、TTS、生图、签到打卡、积分与小游戏、防撤回、敏感词过滤……——全都还在,逐版本记录见 CHANGELOG.md,开关与配置见下方「配置」。

v0.5 线

  • 看得见(v0.5.0):别人合并转发的聊天记录不再被静默丢弃——get_forward_msg 展开成正文交给模型;同时接通了早已封装却没人调用的能力:/成员(名单/详情)、/群信息、/好友(默认关)、/退群(默认关)、agent 工具 qq_recent_history / qq_member_info / qq_react(表情回应)
  • 找得回(v0.5.0):/文件、/文件 文件夹名、/取 文件名(下载后只发私聊)、/相册、/ocr(图片转文字);消息按天归档到 cwd/qq-history/,/找 关键词 与 agent 工具 qq_search_history 在最近 N 天里检索(控制台也有「群资产 · 历史检索」卡片)
  • 无人值守(v0.5.2):入站 webhook(127.0.0.1:8798,token / HMAC 二选一鉴权,限频 + 64 KiB 上限)把外部系统事件推进会话;定时播报(RSS / 天气 / MC,/播报 管理);掉线自愈(只拉起、不杀进程,带冷却与每小时上限)
  • 点一下就完事(v0.5.3):/戳 主动戳一戳、被戳回戳、私聊「正在输入」、自动贴表情、表情回应统计 /赞榜 /谁赞了、/点赞、标记已读(真机探针结论:该 NapCat 构建发不出内联按钮,故按能力探测降级)
  • 群运营工具箱(v0.5.4):/群打卡、/全体余量、/禁言名单、/群详细、/入群通知、/批量踢(两步确认 + 分批执行)、/待办 /完成待办 /取消待办、/移动文件 /重命名文件 /删文件 /新建文件夹、/传图、/群名 /群备注、/群权限、/历史可见、/周报
  • 控制台看得见(v0.5.5):性能面板(P50/P95)、定时任务面板、群配置页、回放 diff、注入场景库(17 个场景一键注入)
  • 群权限与申请补拉(v0.5.8):/设管理 /撤管理(enable 永远显式——探针发现省略就等于撤管理员)、/邀请策略(四个字面量)、/加群方式 1–5(只有 4/5 带问题/答案)、/打卡名册;/申请 把离线期间错过的入群申请/邀请/可疑好友拉回待审队列(request_id 就是审批要的 flag,所以拉回来真能批);机器人自己被设/撤管理员时记账,被撤后写命令直接说真话、零调用(/群搜索 因 NapCat 未定义参数语义而按住不做)
  • 兼容 DSH 0.2 与官方桌面端(v0.5.9):peer 范围放行 ^0.2.0-rc.2(CLI/web 宿主与 Electron 桌面端同一个运行时,两边都能直接装、不需要豁免);OneBot 端口被占时不再崩溃、也不拖住宿主启动——如实报错 + 15 秒退避重试,占用者退出后自动接管(一台机器只允许一个实例托管 QQ 桥)
  • 补丁版本不新增功能:v0.5.1 审查修复、v0.5.6 真机启动修复 + 完整审计、v0.5.7 纯文档(详单见 CHANGELOG.md)

v0.4 线

  • 一切皆可调试(v0.4.0):6 条硬约束全部落地,并且在控制台里可随时验收——① 每个「没回复」都带中文 reason ② 一条消息一个 traceId 贯穿 ③ 可回放(录制 · 离线重跑真实管线)④ 可体检(一键体检报告)⑤ 可导出诊断包(默认脱敏)⑥ 可注入假事件;每条消息走结构化事件 + SSE 实时事件流
  • 自带控制台(v0.4.0):control/(端口 8799)——会话列表、实时事件流、trace 检索、体检报告、诊断包导出、录制与离线回放、事件注入、硬约束验收台
  • 依赖修复(v0.4.1):改用 @deepseek-ai/schemastery,修好干净环境的安装依赖(issue #1)

架构

QQ 客户端 ←→ OneBot 实现(NapCat / LLOneBot / OpenShamrock / Lagrange…)
                  │ 反向 WebSocket(OneBot 连我们;端口 6700)
                  ▼
        dsh-qq-onebot-bridge(本插件)
                  │ ctx.agents.create / followup
                  ▼
        DSH agent 会话(每群/每私聊用户一个)

旁路(都不参与回复决策,出问题也不影响发消息):
  每条入站事件 ──► qq-inbox.jsonl          (录制:可离线回放)
  每个决策点   ──► qq-trace.jsonl          (结构化事件:stage/ok/reason/耗时/traceId)
  快照每 2s    ──► qq-runtime.json         (会话/闸门/生效配置/录制与注入状态)
  qq-inject.jsonl ◄── 控制台写、桥轮询读   (注入:默认 dry-run,出站全拦截)

独立控制台 control/(进程 8799,不依赖 DSH 桌面端)
  ├─ 读:端口/进程、事件流、决策链、体检、录制列表、运行快照
  ├─ 写:启停宿主/NapCat/TTS、释放端口、离线回放(沙箱 + dry-run)、事件注入
  └─ 鉴权:仅 127.0.0.1 + token + 同源 Origin 校验

安装 / 卸载

# 安装(本地目录):先在被安装的目录里装运行时依赖,再注册插件
# 本地目录走 pnpm 的 link:,不会自动安装被链接包自己的依赖(ws)
cd <本目录> && npm install --omit=dev
dsh plugin --profile web add <本目录>

# 卸载(随时可移除,独立 bundle 不影响其它插件)
dsh plugin --profile web remove dsh-qq-onebot-bridge

装/卸后重启 dsh web 生效。

官方依赖(@deepseek-ai/dsh-*、@deepseek-ai/schemastery)声明为 peerDependencies,由 DSH 随 profile 一起装好,插件目录里不需要重复安装。

官方桌面端(DSH Desktop)

官方桌面端(Electron 版 DeepSeek Harness.exe)跑的是 ~/.dsh/profiles/desktop 这个 profile,由应用独占管理(CLI 会拒绝 dsh --profile desktop),它和 CLI 版共用同一个 DSH 运行时版本——所以本插件从 v0.5.9 起声明的 peer 范围同时覆盖 ^0.1.x 与 ^0.2.0-rc.2,两边都能直接装、不需要 dsh plugin allow-version 豁免。

装法与 web 版一致,只是走桌面端的插件管理界面:

  1. 桌面端 → 设置 → 插件 → 安装,选本地目录(就是本插件所在的目录,也就是 dsh plugin --profile web add 时填的那个路径),或直接填 GitHub 仓库地址;
  2. 配置同样写在 ~/.dsh/profiles/desktop/cordis.patch.yml(id: dsh-qq-onebot-bridge 的 config),不要写进仓库;
  3. 重启桌面端生效。

手动/本地目录安装(不经市场)时注意:光有依赖还不够,必须同时把 dsh-qq-onebot-bridge 加进该 profile package.json 的 dsh.profile.bundles,加载器才会挂载它——只装依赖的话它只会出现在"已装依赖"里而不工作(本机实测)。市场安装会自动处理这一步。

⚠️ 一台机器只允许一个实例托管 QQ 桥:web 宿主与桌面端可以都装本插件,但两者抢同一个 OneBot 端口(默认 6700),只有一个能绑上——另一个会在日志里说明原因并每 15 秒重试,等端口释放后自动接管(v0.5.9 起不再崩溃、也不会拖住宿主启动)。不要用"给另一个 profile 改个端口"来让两个都跑:它们共用同一份 cwd(qq-sessions.json / qq-memory/ / qq-reminders.json / 积分与统计…都在那儿),两个实例同时读写会互相覆盖,injectDryRun:false 时注入队列里的动作还会真的发两遍。要固定由某一个托管,正确做法是只在一个 profile 里启用本插件(另一个从 dsh.profile.bundles 里去掉),或者把 cwd 也分成两个不同目录。

在 DSH 设置里开关功能(v0.6「QQ助手」页)

装好插件、重启一次宿主(让面板路由挂上)之后:DSH → 设置 → QQ助手。

  • 日常四组直接铺开:对话基础 / 群运营工具箱 / 娱乐与互动 / 语音与媒体;安全与风控 · 记录与通知 · 高级与调试三组标"进阶"、默认折叠。共 7 组 59 个开关(从 224 个配置键里精选)。
  • 每行都写清楚:中文标签 + 一句话"关掉会怎样" + 配置键名(方便你去配置文件里找同名键),右侧是拨动开关;行尾徽标 非默认(与 schema 默认值不同)、待重启(配置文件里的值与当前生效值不一致)。
  • 点一下即写入:只改 profile 的 cordis.patch.yml 里本插件那一个 config 块(其它条目与注释原样保留);白名单之外的键、非布尔值一律拒绝。写入是先写临时文件再 rename 的原子替换,并留一份 .bak-qqai 备份。
  • 生效方式:写入后 DSH 会热重载本插件条目(QQ 桥会短暂重连一两秒);若宿主没开热重载,重启宿主后生效。
  • 没装 web 服务的宿主(如 TUI profile)不会有这一页——此时用 ctx.inject(['webServer']) 的那段代码根本不会执行,插件照常工作。
  • 页面最上面是一组「相关链接」(v0.6.3 起,原来在页面最底下):依次是 QQ助手账号(登录 / 扫码)(→ 宿主的 /qqai/account,点开即已登录的 NapCat 页面)、更新日志(v0.6.3)(GitHub 的 CHANGELOG.md)、调试文档(README 调试章节)、调试台(独立控制台)(压在最底下)。地址由 package.json / qq-control.json 推导。
    • 调试台是独立进程,插件不会自动启动它:面板会探一次 127.0.0.1:8799 并如实标「运行中 / 未启动」;没启动时那一行直接给出可复制的启动命令。
    • 点「调试台」走宿主的 /qqai/console:跑着就 302 到带 token 的地址(省掉手抄 token),没跑就回一页说明先跑哪条命令——不会再出现"点进去只看到连不上"。token 只在服务端读,不进面板数据。

想改的键不在面板里?直接编辑 profile 的 cordis.patch.yml(面板顶行会显示它是哪个文件)。面板刻意只放"日常会动的开关",不做成任意配置编辑器。

配置

profile 的 cordis.patch.yml 覆盖 id: dsh-qq-onebot-bridge 的 config(完整示例见 examples/cordis.patch.example.yml):

⚠️ 别改错文件:仓库根目录也有一个同名 cordis.patch.yml,那是安装用的 bundle patch(4 行,只有 insert: - id: …),不要往里填配置。真正要改的是 profile 目录里的那份,例如 ~/.dsh/profiles/web/cordis.patch.yml(Windows:C:\Users\<你>\.dsh\profiles\web\cordis.patch.yml)——它在仓库外,密钥写在那里才不会进 git。

键 默认 说明
host 127.0.0.1 反向 WS 监听地址
port 6700 反向 WS 监听端口
accessToken '' OneBot 端须携带的 Bearer token(空=不校验)
allowUsers [] 私聊用户白名单(空=拒绝所有私聊,务必填入自己的 QQ 号)
allowGroups [] 群白名单(空=拒绝所有群消息,列出机器人服务的群号)
botQq 0 机器人 QQ 号(用于群内 @ 检测;0=任何群消息视为@)
replyOnlyWhenMentioned true 群聊仅 @机器人 才回复
acceptPrivate true 是否回复私聊(私聊仍需 allowUsers 放行)
autoCollectStickers false 自动收藏消息里的图片表情到本地图库
faceEnabled true 表情功能总开关([face:] 标记 + qq_face_* 工具)
sessionMode chat 群会话分组:chat=每群一会话;user=每群每人一会话
cwd '' 会话工作目录(同时决定 qq-faces/、qq-replies/、qq-bridge-debug.log 的位置)
provider '' LLM provider 覆盖(空=agent 默认)
model '' LLM 模型覆盖(空=agent 默认)
maxMessageLength 1700 单条出站消息最大字符数(超出自动分段)
botName 小鲸鱼 机器人显示名(合并转发卡片的署名)
sessionResumeEnabled true 宿主重启后 resume 上次会话(完整记录续接);关掉则每次重启都新建会话
agentMediaToolsEnabled true 暴露 qq_send_image / qq_send_file / qq_send_voice / qq_recall 工具
fileSendDirs [] agent 允许发送文件的额外目录(会话 cwd 始终允许)
fileSendMaxBytes 52428800 agent 可发送的单文件大小上限(字节,默认 50 MiB)
imageSendMaxBytes 4194304 图片超过此大小(默认 4 MiB)先用 ffmpeg 压缩再发
recallWindowSeconds 110 出站消息可被 qq_recall / /撤回 撤回的时间窗(秒)
forwardLongReplies false 群聊超长回复改发合并转发卡片
forwardThresholdChars 600 触发合并转发的字数阈值
actionRatePerMinute 20 写操作闸门:全部会话合计每分钟上限
actionRatePerDay 500 写操作闸门:全部会话合计每日上限
actionAuditEnabled true 写操作与拒绝记录写入 cwd/qq-actions.log
keywordEnabled false 关键词问答库(默认关闭):命中本地词库直接回复,不走模型、不需要 @
keywordFile '' 词库文件路径(空=cwd/qq-keywords.json);支持 exact/contains/regex、随机多答、图片、作用域与冷却
fortuneEnabled true 今日人品/运势、抽签、塔罗(按 QQ 号+日期确定性生成,纯本地)
diceEnabled true 骰子(.r 3d6)与随机抽人(/抽一个 A B C)
pointsEnabled false 积分经济(默认关闭):/积分 /排行榜 /转账 @某人 数量
pointsPerMessage 1 每条消息获得的积分(0=聊天不得分)
pointsDailyCap 20 每人每日通过聊天可得积分上限
pointsCheckinBonus 5 每日签到额外奖励积分
gameEnabled false 群内小游戏(默认关闭):成语接龙、猜数字
idiomChainTimeoutSeconds 120 接龙闲置超时(秒)
guessNumberMax 100 猜数字上限(1~N)
guessNumberMaxTries 10 猜数字可用次数
antiRecallEnabled false 防撤回(默认关闭):缓存最近消息,被撤回时补发内容
antiRecallInGroup true 补发到群里(false=私聊发给第一个管理员)
antiRecallImages true 一并补发被撤回的图片(最多 3 张)
antiRecallCacheSize 50 每会话缓存的消息条数
antiRecallMaxAgeMinutes 120 缓存消息可恢复时长(分钟)
antiRecallCooldownSeconds 5 同一会话两次补发的最小间隔
filterEnabled false 敏感词过滤(默认关闭)
filterWordsFile '' 词表路径(空=cwd/qq-badwords.txt;# 注释、re: 正则、改动自动热重载)
filterAction warn 处置方式:warn 提醒 / recall 撤回 / mute 禁言
filterMuteSeconds 300 mute 处置与刷屏升级时的禁言秒数
filterWhitelist [] 白名单词/正则(命中即放行)
floodEnabled false 刷屏防护(默认关闭)
floodWindowSeconds 10 刷屏统计窗口(秒)
floodMaxMessages 8 窗口内允许的消息条数
floodMuteSeconds 300 刷屏升级禁言秒数
floodStrikeLimit 3 警告几次后禁言
verifyEnabled false 入群/加好友验证(默认关闭):请求进队列并私聊推送管理员
verifyKeyword '' 口令:验证消息包含它则自动放行(空=全部人工审批)
verifyTimeoutSeconds 300 请求超时时间(超时出队并提醒管理员)
verifyMaxPending 20 待审队列上限
statsEnabled false 发言统计(默认关闭):/统计 今日活跃榜、/周榜 周榜,并作为日报数据源
statsKeepDays 30 发言统计保留天数
groupReadEnabled true 只读群信息:/荣誉 /公告 /群精华
mcStatusEnabled true /mc <host[:port]> 查询 Minecraft Java 服务器状态(Server List Ping,无 Key)
mcStatusTimeoutMs 5000 MC 状态查询超时(毫秒)
recurringReminderEnabled true 重复提醒:「每天8点」「每周一9点」「每个工作日15点」
dailyReportEnabled false 每日群日报(默认关闭):到点让 agent 总结当天聊天并发到群里
dailyReportTime 22:00 日报时间(本地 HH:mm)
dailyReportChats [] 固定接收日报的会话(如 ["g:100000001"];为空则用 /日报 on 的开关,再为空则回落到全部群白名单)
sttEnabled false 语音转文字总开关
sttBaseUrl https://open.bigmodel.cn/api/paas/v4 STT 端点(OpenAI 兼容 /audio/transcriptions)
sttModel glm-asr-2512 STT 模型(智谱 glm-asr-2512 / SiliconFlow FunAudioLLM/SenseVoiceSmall)
sttApiKey '' STT API Key(可复用智谱 GLM 系列的 key)
privateImageView true 私聊中主动下载查看对方发送的图片/动画表情(存 cwd/qq-images/,agent 用 describe_image 查看)
visionMode tool 识图方式:tool=存盘后由 visionToolName 工具查看(稳定);native=原生多模态附件直传模型(DSH 0.1.1+,文本模型自动降级)
visionToolName describe_image tool 模式下使用的识图工具名
imageRetentionDays 14 下载图片(qq-images/qq-replies)保留天数,宿主启动时清理更旧的
imageTrashEnabled true 删除策略:只回收不销毁——过期图片移动到 cwd/qq-trash/<日期>/ 而不是删除(失败则保留原文件)
imageTrashDir '' 回收目录(空=cwd/qq-trash);该目录不会自动清理,由你自行处理(本机可 scripts/safe-delete.ps1 送进回收站)
memoryEnabled true 每会话持久化记忆(最近对话存 cwd/qq-memory/,宿主重启后自动恢复;/new 清除)
memoryMaxEntries 30 每个会话保留的对话条数上限
rateLimitEnabled false 回复限流开关(默认关闭);开启后每会话窗口内最多回复 rateLimitMaxReplies 条
rateLimitMaxReplies 10 限流窗口内每会话最大回复数
rateLimitWindowSeconds 60 限流滑动窗口(秒)
dedupEnabled true 消息去重(同一 message_id 窗口内重复投递忽略,防重连重发)
dedupWindowSeconds 300 去重窗口(秒)
reminderEnabled true 定时提醒总开关(群聊需 @,私聊直接说;存 cwd/qq-reminders.json 跨重启保留)
reminderMaxPerChat 10 每个会话最多同时保留的提醒数
quietHoursEnabled false 避开高峰期开关(默认关闭);开启后工作日静默时段内不回复任何入站消息(不消耗模型调用),已排定的定时提醒/投票开奖照常
quietHours ['9:00-12:00', '14:00-18:00'] 静默时段(本地时间 H:MM-H:MM,全角冒号自动归一化;可跨午夜如 22:00-2:00)
quietWeekendExempt true 周六/周日不受静默时段限制
ttsEnabled false 语音回复总开关(默认关闭;开启后每条文字回复后跟随一条语音)
ttsProvider azure 合成方案:azure(微软晓晓)/ openai(任意 OpenAI 兼容 /audio/speech)/ local(本地 GPT-SoVITS 语音克隆,零 API 成本)
ttsApiKey '' Azure / OpenAI 兼容服务的 key(local 不需要)
ttsVoice zh-CN-XiaoxiaoNeural 云端音色名
ttsStyle chat Azure 语气风格(cheerful/sad…)
ttsMaxChars 120 语音朗读最大字符数(超出截断,只影响语音不影响文字)
ttsLocalUrl http://127.0.0.1:9880 本地 GPT-SoVITS api_v2 服务地址
ttsLocalRefAudio '' 本地 TTS 必填:音色参考音频绝对路径(3-10 秒 wav,如 D:/voice/xiaojingyu.wav)
ttsLocalPromptText '' 参考音频的台词(可留空)
ttsLocalTextLang zh 合成文本语言
ttsLocalPromptLang zh 参考音频台词语言
ttsLocalConvertToMp3 true 本地 wav 输出用 ffmpeg 自动转 mp3 再发送(QQ/NapCat 兼容性更好)
pokeEnabled true 戳一戳回复开关(白名单会话内被戳随机卖萌回复)
pokeReplies [...] 戳一戳回复文案列表(随机选一条)
pokeCooldownSeconds 15 每会话戳一戳回复最小间隔(秒,防刷)
voiceReadingEnabled true 语音朗读:@机器人引用文字说「读一下/念出来」,或 /读 <文字>(走 ttsProvider 合成)
checkinEnabled false 每日签到(默认关闭):说「签到」打卡,连续/累计天数存 cwd/qq-checkin/;「签到榜」看排行
checkinKeyword 签到 签到触发词
welcomeEnabled false 入群欢迎语(默认关闭):新人进群自动 @+欢迎文案(机器人自己入群不触发)
welcomeText '' 欢迎文案(空=内置默认文案)
imageGenEnabled false 生图开关(默认关闭):/画 <描述词> 生成图片(群聊需 @机器人)
imageGenProvider openai 生图后端:openai=任意 OpenAI 兼容 /images/generations(DALL·E/CogView/SiliconFlow…);local=本地 SD WebUI(AUTOMATIC1111)
imageGenBaseUrl '' 后端地址(空=按 provider 取默认:api.openai.com 或 127.0.0.1:7860)
imageGenApiKey '' OpenAI 兼容服务 key(local 不需要)
imageGenModel '' 模型 id(空=服务默认,如 gpt-image-1;local 忽略)
imageGenSize 1024x1024 图片尺寸 WxH(local 支持任意尺寸如 768x512)
imageGenSteps 20 采样步数(仅 local)
imageGenCfgScale 7 CFG 提示词强度(仅 local)
imageGenSampler '' 采样器(仅 local,空=WebUI 默认)
imageGenCooldownSeconds 60 每会话两次生图最小间隔(秒,成本/刷屏防护)
imageGenDailyLimit 20 每会话每日生图上限
imageGenMaxPromptChars 400 描述词最大字数(超出截断)
imageGenCommand /画 生图触发命令
traceEnabled true 全链路结构化事件(每条消息一个 traceId,每个分支带 reason);关掉则控制台只剩端口/日志能力
traceLevel debug debug 记录全部事件(含每次静默/拒绝);warn 只留问题,用于长期运行省磁盘
traceMemorySize 500 内存里保留的最近事件数(控制台决策链用),落盘另受 4MiB 轮转上限约束
traceFile '' 事件文件路径(空=cwd/qq-trace.jsonl)
recordInbound true 录制:把收到的每条消息/通知/请求写进 qq-inbox.jsonl(可离线回放);只写本机、不影响回复
inboxFile '' 录制文件路径(空=cwd/qq-inbox.jsonl,按 2MiB 轮转)
inboxRedact false 录制时把 6 位以上数字(QQ 号)脱敏后再落盘,便于把录制文件发给别人
injectEnabled false 事件注入通道(默认关闭):开启后桥每 injectIntervalMs 轮询 qq-inject.jsonl,把新行喂进真实管线
injectFile '' 注入队列路径(空=cwd/qq-inject.jsonl);启动时已有的历史行会被跳过并记一条原因
injectDryRun true 强烈建议保持 true:注入触发的所有出站调用(发消息/撤回/群管…)都被拦截并计数,绝不真发 QQ;异步 agent 回合的回复同样被拦下(原文记进事件流)
injectIntervalMs 2000 注入队列轮询间隔(毫秒,最小 500)

用户侧(OneBot 实现)配置

以 NapCat 为例:OneBot11 配置里把 WebSocket 客户端地址填成:

ws://127.0.0.1:6700/

其它实现同理(LLOneBot 填反向 WebSocket、OpenShamrock 填被动 WebSocket、go-cqhttp 填 ws-reverse)。若本插件配了 accessToken,OneBot 端填同一 token。

语音转文字(STT)

触发规则(最终版):

场景 行为
群聊:@机器人 + 引用(回复)一条语音 ✅ 转写被引用语音并以文字回复
群聊:单独发语音(不@/不引用) ❌ 不触发
私聊:直接发语音 ✅ 转写并回复(不受 acceptPrivate 限制)
私聊:文字 + 引用语音 ✅ 转写被引用语音

实现链路:消息里的引用 → get_msg 找到被引用消息 → 其中含 record 段 → OneBot get_record(out_format mp3/wav,响应含 base64)→ POST {sttBaseUrl}/audio/transcriptions(multipart 字段 file 二进制)→ 转写文本注入会话。

注意事项:

  • 智谱 GLM-ASR-2512 限 wav/mp3、≤ 30 秒、≤ 25MB;更长的语音请换 SiliconFlow 等端点
  • 智谱接口的 multipart 字段必须是 file(二进制)——文档里写的 file_base64 实测会报 1214 错误

会话分组

  • 群聊:sessionMode: chat(默认)下每个群一个独立会话,全群共享上下文;user 下每群每人一个会话
  • 私聊:每个私聊用户一个独立会话,与群聊完全隔离
  • 会话创建时 agent 系统提示注入 chatScope("你正在 QQ 群 xxx 里聊天"/"你在和用户 xxx 私聊"),并要求不串上下文
  • /new 仅重置当前会话;会话存内存,宿主重启后重建(不持久化)

表情系统

  • 回复文本里写 [face:鼓掌] 等标记会替换为对应 CQ 表情段(黄脸表见 lib/faces.js,约 70 个)
  • faceEnabled=true 时每个会话注册 qq_face_list / qq_face_send 工具
  • 手动把图片放进 cwd/qq-faces/ 自动登记为可发送表情(文件名=表情名),删除文件自动剔除
  • autoCollectStickers=true 时自动收藏群消息里的图片表情

命令与调试

  • /new:结束当前会话并开新会话
  • /status:查看当前会话状态与 sessionId 前缀
  • 调试日志:{cwd}/qq-bridge-debug.log(消息路由、语音转写、agent 事件,按时间戳追加)
  • 宿主错误日志:启动 dsh web 时把 stderr 重定向到文件(如 D:\qq-work\qq-host-err.log)可查启动崩溃
  • 关键日志标记:voice fetched via get_record、quoted voice transcribed、followup sent (voice)、group msg without @bot ignored

测试

55 个单测脚本,共 3434 项断言(test/*-unit.mjs)+ 3 个真机脚本:

# 1) 单元测试:不联网、不起宿主,纯逻辑 + 临时目录(推荐每次改完都跑)
node test/control-unit.mjs        # 也可以逐个跑:node test/<name>-unit.mjs
#    36 个文件:桥的分支/命令/守卫、控制台 HTTP 与体检、录制回放与注入、注入安全边界、硬约束验收台…
#    一次性全跑(PowerShell):
#    Get-ChildItem test -Filter '*-unit.mjs' | ForEach-Object { node $_.FullName }

# 2) 回放的端到端验收:真实桥代码 + 真实 OneBot 服务端,沙箱 + dry-run,不需要宿主
node test/replay-live.mjs

# 3) 真机脚本(需要宿主/控制台已在运行,自己扮演 OneBot 客户端连 6700)
node test/live-e2e.mjs        # 消息 → 回复 全链路
node test/live-stream.mjs     # 实时事件流 / 决策链 / 体检接口(控制台 8799)
node test/replay-live-host.mjs --token <控制台 token>   # 录制 → 离线回放 → 注入

老版本的 sim-*.mjs 协议模拟脚本保留在 test/ 下,仍可用于手工排查(node test/sim-group.mjs 等,需宿主运行)。 语音转文字链路建议直接用 QQ 实测(模拟脚本需真实 STT 调用)。

记忆与人设说明(重要)

本插件不内置任何人设、偏好或群规则。小鲸鱼人设、问答偏好、群内行为规则等记忆内容由 dsh-mnemon 插件的运行时记忆(~/.mnemon/runtime/USER.md + MEMORY.md)注入每个 QQ 会话——插件只负责"功能",记忆只负责"灵魂",两者完全解耦。换人设只改 Mnemon 记忆,换功能只动本插件。

⚠️ 风险与合规说明(使用前必读)

账号风控风险

  • 本插件通过第三方协议实现(NapCat 等)接入 QQ,不是腾讯官方接口,与《QQ 软件许可及服务协议》相悖,QQ 官方明确禁止非官方客户端/协议
  • 使用第三方协议存在账号被限制登录、冻结、甚至永久封禁的风险,且可能波及其他正常使用的 QQ 账号(同设备/同 IP)
  • 建议使用机器人小号运行,绝不要用大号/常用号
  • 常见风控诱因:高频发言、短时间大量消息、发送营销/广告/违规内容、被多人举报、异常登录设备
  • 缓解建议:降低回复频率、仅在小群/自用场景运行、不 24 小时刷屏、严格内容合规

内容风控

  • agent 生成的一切内容都会以机器人账号身份发出,使用者对该账号发布的内容负全部责任
  • 建议在人设/系统提示中约束输出合规内容;违规内容既触发账号处罚,也可能带来法律责任

安全风险

  • allowUsers / allowGroups 未配置(为空)时,插件默认拒绝所有私聊与群消息——请显式填入自己的 QQ 号与群号后再使用;配置白名单后,白名单外的任何人都无法驱动你的 agent
  • 插件只监听 127.0.0.1,不要改成 0.0.0.0 暴露公网
  • 语音与图片会上传到第三方云服务(STT API)处理,敏感语音请勿发送

合规提示

  • 仅用于个人学习、内部小范围交流;不得用于批量营销、广告、骚扰、群控等用途
  • 遵守所在地区法律法规与腾讯平台规则
  • 使用第三方协议风险自负,本插件不提供任何免封号承诺

免责声明

本插件仅供技术学习与个人研究使用。使用者应自行评估并承担使用第三方 QQ 协议的全部风险与后果。

安全注意

  • allowUsers / allowGroups 为空时默认拒绝一切消息——使用前务必填入自己的 QQ 号与群号
  • 端口仅监听 127.0.0.1;不要对外暴露
  • OneBot 实现本身有 QQ 封号风险,使用第三方机器人协议需自行评估

调试(v0.4「一切皆可调试」)

每条入站消息都有一个 traceId,每个决策点(包括每一次"不回复/丢弃/降级")都会留下 stage + ok + reason + 耗时。这是本版本的核心设计理念:出问题时不用猜。

想看什么 在哪看
6 条硬约束此刻达标吗 控制台最上面「硬约束验收台」:6 行状态灯 + 机器上现有的证据 + 该点哪里的提示,每 30 秒自动重算
单条消息的完整决策链 控制台「实时事件流」点任意一行 → 「决策链」显示时间轴、停在哪一步、为什么
为什么机器人不回复 「实时事件流」筛"仅被拒/失败",最常见原因直接列出(如 mention: 群聊未 @ 机器人)
每个端口的占用与在线 控制台「端口 / 进程」(6700 的连接数即机器人在线)
一键排查 控制台「一键体检」:15-19 项 pass/fail + 修复建议(依赖路径、端口、链路、快照、错误、闸门拒绝…)
生效配置(为什么功能没生效) 控制台「运行快照」里的"关闭中的开关";完整字段在 qq-runtime.json 的 features(不含任何密钥)
打包给别人看 「导出诊断包」→ 一个 zip(事件流/审计/桥日志/宿主日志/运行快照/体检报告/环境信息)
文件级排查 qq-trace.jsonl(结构化事件,可 jq/grep)、qq-bridge-debug.log、qq-actions.log(写操作审计)、qq-host-out.log/err.log

相关配置:traceEnabled(默认开)、traceLevel(debug 全量 / warn 只留问题)、traceMemorySize、traceFile。 调试接口(控制台,token + Origin 双重校验):/api/trace、/api/stream(SSE)、/api/runtime、/api/diagnose、/api/export。

录制 · 离线回放 · 事件注入(v0.4 阶段 3)

前两项解决了"现在发生了什么",这三项解决"这条消息当时为什么这样、换成别的输入会怎样"。

能力 怎么用 说明
录制 自动 桥收到的每条消息/通知/请求都追加到 qq-inbox.jsonl(可 JSON 逐行解析、按大小轮转),只写本机、不改任何回复行为
离线回放 控制台「录制 · 回放 · 注入」→ 某行「回放这条」/「回放最近 5 条」 在沙箱目录里用真实桥代码重跑这条消息:dry-run 拦截所有出站、不建任何 QQ 连接、源目录一个字节都不改。结论逐条给出"会回复/静默/出错 + 原因 + 会发送什么"
事件注入 控制台填 群号/QQ 号/文本 → 「注入」 写一行到 qq-inject.jsonl,桥按 injectIntervalMs(默认 2s)轮询后走真实管线处理;injectDryRun(默认开)下所有出站调用被拦截并计数,注入内容永远不会真的发到 QQ

回放的保真度来自运行时快照里的线上决策配置(白名单、安静时段、各功能开关等 28 项,见 qq-runtime.json 的 replay):否则插件默认值里"白名单为空 = 拒绝一切"会让回放全部判成静默。回放里不含真实模型输出——模型那一轮用一条带 [回放] 前缀的模拟回复代替,用来验证链路与分支,不验证措辞。

排障要点:

  • 注入通道未开启时会直接报错并说明开关名(injectEnabled),不会静默丢进队列;
  • 注入触发的 agent 回合是异步的:dry-run 窗口只在同步阶段开着,所以模型真正的回复会在事件流里被单独拦下(注入回合的模型回复已被拦截(dry-run,未发送):<原文>)——注入既能走真实管线,又不会漏发一条;真人消息不受影响(收到真实消息立即解除该标记);
  • 回放的帧在事件流里标为 replay: 离线回放(沙箱 + dry-run,不碰 QQ),注入的帧标为 inject: 来自注入器,两者不会互相误判;
  • 桥启动时若队列里已有历史行,会跳过它们并在事件流里记一条"本次启动跳过 N 行(只处理启动后新增的行)",避免重启后重放旧注入;
  • 注入的帧不会被二次录制(否则回放/注入会互相激发);
  • 回放沙箱默认保留最近 5 次,更旧的移入回收站(qq-replay/_trash/<日期>/),不做物理删除。

相关配置:recordInbound(默认开)、inboxFile、inboxRedact、injectEnabled(默认关)、injectFile、injectDryRun(默认开)、injectIntervalMs。 调试接口:/api/inbox、/api/replay、/api/inject、/api/queue/clear。

硬约束验收台(v0.4 阶段 4)

上面两条解决了"现在发生了什么"和"当时为什么这样"。验收台解决第三个问题:设计理念有没有真的落地。

GET /api/acceptance 把 6 条硬约束逐条用机器上现有的产物算成 ✅ 达标 / ⚠️ 有提示 / ❌ 不达标 / ❔ 证据不足,并给出证据与下一步:

约束 判定用的证据
① 无静默分支 最近 500 条事件里所有 ok:false(被拒/失败)事件是否都带非空 reason;缺的会点名 stage
② 可关联(traceId) 消息级事件的 traceId 覆盖率、有多少条消息真正走完 inbound→reply
③ 可回放 录制条数 + 最近一次回放的统计与安全保证(dry-run 开、QQ 连接 0、cwd 已沙箱化);dry-run 被关掉直接判不达标
④ 可体检 体检通过数/失败数/blocker 数与结论,失败项点名
⑤ 可导出 诊断包会收集的产物有几类在位(或最近一次导出的体积与文件名)
⑥ 可注入 通道开关、dry-run 开关(关掉→不达标,因为会真发 QQ)、已消费行数、以及拦下过几次异步 agent 回合的回复

每一项都能点「去看 →」跳到对应卡片(事件流/决策链/回放结果/体检/日志/注入);结论为 all-green / partial / unknown / broken 四种。 纯函数实现(control/lib/acceptance.mjs),所以每条分支都有断言覆盖;面板每 30 秒自动刷新,回放结束后立刻重算。

看得见 · 找得回(v0.5)

v0.5 做两件事:把已经封装好、却从没接上线的能力接通,再补上"群里的东西能找回来"。

合并转发展开(先修一个违反硬约束的洞)

以前别人把「聊天记录」合并转发给机器人时,parseMessage 里根本没有 forward 分支,这条消息在传输层就被静默丢掉——连 trace 都没有,直接违反 v0.4 的第一条硬约束。现在:

  • forwards 会被识别,经 get_forward_msg 展开成 [转发聊天记录] 昵称: 内容 交给模型(默认最多 50 条 / 4000 字,只展开一层,不递归)
  • 群里仍然要 @ 机器人才处理(空文本不再绕过 @ 门与 acceptPrivate 门——这两个门都补上了)
  • forwardExpandEnabled: false 可关闭;回放/注入模式(dry-run)不访问 QQ,注入时可用 forwardText 直接喂一份正文

接通的既有能力

能力 用法
群成员 /成员 看名单(按身份/等级排序,标注头衔与禁言中)· /成员 @某人 / /成员 昵称 / /成员 QQ号 看详情(身份/等级/头衔/入群时间/最后发言/禁言状态);agent 工具 qq_member_info
群资料 /群信息(群名/群号/人数与上限/群主/建群时间)
好友列表 /好友(隐私项,默认关闭 friendListEnabled,且仅私聊里的管理员可用)
群历史 agent 工具 qq_recent_history(拉本会话最近 N 条,群聊/私聊都支持)
表情回应 agent 工具 qq_react(给消息贴 👍 之类,而不是发一条消息;写操作,过闸门)
退群 /退群 确认(默认关闭 leaveGroupEnabled,必须显式二次确认,走闸门)

群资产(只读为主)

命令 说明
/文件 列群文件与文件夹(文件名/大小/上传者/时间)
/文件 <文件夹名> 进文件夹列文件
/取 <文件名> 下载群文件到 cwd/qq-files/ 并只发到发起人私聊(不往群里丢文件);精确/前缀/模糊匹配,文件名消毒(去路径、去 Windows 非法字符、保留名加前缀)
/相册 列群相册(NapCat get_qun_album_list)
/ocr 引用一张图片发 /ocr,用 NapCat 的 ocr_image 读出图里的文字(不消耗模型)

历史检索与归档

  • 每条白名单会话的真实消息按天归档到 cwd/qq-history/YYYY-MM-DD.jsonl;注入/回放的假事件不入档,/ 开头的命令也不入档(否则每次 /找 X 都会命中自己刚敲的查询词)
  • /找 关键词(空格分隔 = 同时包含,大小写不敏感)检索本会话最近 N 天;agent 工具 qq_search_history 同源同口径
  • 保留期默认 90 天,过期分片在宿主启动时移入 qq-trash/<日期>/ 而不是删除
  • 控制台新增「群资产 · 历史检索」卡片:看归档体积与时间范围、直接检索(与群内 /找 复用同一套解析)

新增配置(括号内为默认值):forwardExpandEnabled(true) forwardMaxNodes(50) forwardMaxChars(4000) memberQueryEnabled(true) memberListLimit(20) friendListEnabled(false) historyQueryEnabled(true) historyQueryLimit(20) reactToolEnabled(true) leaveGroupEnabled(false) ocrEnabled(true) ocrMaxImages(3) groupFileEnabled(true) groupFileDownloadEnabled(true) groupFileListLimit(20) groupFileMaxBytes(50 MiB) albumEnabled(true) historyArchiveEnabled(true) historyArchiveDir("") historyArchiveKeepDays(90) historySearchEnabled(true) historySearchDays(7) historySearchLimit(20)。

独立控制台(control/,v0.4.0)

插件自带一个独立的本地运维端,不依赖 DSH 桌面端:宿主挂掉时它照常可用,端口与进程一目了然。

# 启动(默认 http://127.0.0.1:8799,启动后打印带 token 的地址)
npm run control            # 或 node control/bin/qq-control.mjs --open
# 也可以双击 control/启动控制台.bat
能力 说明
端口总览 控制台 8799 / 宿主 3080 / OneBot 6700 / NapCat 6099 / GPT-SoVITS 9880 的监听状态、占用 PID 与进程名;6700 的连接数即"机器人在线"
启停 启动/停止/重启宿主(自动带 --no-open,日志重定向到 qq-host-out.log/qq-host-err.log)、启动/停止 NapCat 与 QQ、启动/停止 GPT-SoVITS、一键全停
启动预检 起宿主前检查 3080/6700,被占则直接报「端口←进程#PID」,而不是静默失败
释放端口 对占用受管端口的进程一键 taskkill /T /F(护栏:只允许受管端口占用者与已知机器人进程,绝不误杀无关 PID)
日志 宿主 stdout / stderr / 桥调试日志,自动跟随、可切行数
扫码状态 显示 NapCat 二维码图片是否存在、是否新鲜,并一键打开 6099 扫码页
配置 qq-control.json 是端口与路径的唯一真源(自动探测 node、dsh bin.js、NapCat、TTS 脚本;可在 UI 里改路径);6700 被 NapCat 配置写死,勿改
调试 「录制 · 回放 · 注入」:列出 qq-inbox.jsonl 里录到的每条消息,可一键离线回放(沙箱 + dry-run)或注入合成事件;注入队列状态(行数 / 本次已消费 / dry-run)直接显示
验收 顶部「硬约束验收台」:6 条硬约束的实时证据(无静默分支 / traceId 贯穿 / 可回放 / 可体检 / 可导出 / 可注入),不达标项直接说明该点哪里;GET /api/acceptance
安全 只绑 127.0.0.1;所有 API 需要 token;带 Origin 的跨站请求一律拒绝

以后若想做真正的托盘/桌面程序,直接包一层 Electron/Tauri 复用同一套 HTTP API 即可,逻辑无需重写。

隐私与脱敏

出问题排查往往要把日志发给别人,所以本插件对"数据会去哪"有明确约定:

项 约定
诊断包 「导出诊断包」默认勾选脱敏:QQ 号按位掩码(保留前两位)、消息原文替换为「[已脱敏 N 字]」,包内附 REDACTED.json 说明口径;取消勾选才导出明文(会有提醒)
运行产物 qq-inbox.jsonl(消息原文)、qq-trace.jsonl(会话键 + 文本片段)、qq-runtime.json、qq-actions.log 等只写本机工作目录,且全部被 .gitignore 覆盖(qq-*/、qq-*.json、qq-*.jsonl、qq-*.log 通配 + 逐项列出),cwd 恰好在仓库里也不会误提交
录制脱敏 inboxRedact: true 可在录制阶段就把 QQ 号脱敏
仓库本身 不含任何密钥/口令/真实 QQ 号:密钥只存在于你的 DSH profile 配置(仓库外);test/privacy-unit.mjs 每次跑测试都会重新扫描全部被跟踪文件(真实号从你本机私有配置或 DSH_QQ_PRIVATE_IDS 现取,测试文件里不含真实号)
控制台 只绑 127.0.0.1,所有接口需 token(存在被忽略的 qq-control.json),拒绝跨站 Origin

部署事实:本插件是 DSH bundle,运行在 DSH profile 内,@deepseek-ai/dsh-*、@deepseek-ai/schemastery 等官方 peer 依赖随 profile 一起装好。官方包必须写全作用域名:不带作用域的 schemastery 是另一个包(3.18.0),只有在"别的插件恰好把它 hoist 到共享 node_modules"时才能解析——v0.4.0 之前 lib/ 正是这么写的,换到干净环境立刻 ERR_MODULE_NOT_FOUND(issue #1);现已统一用作用域名,并由 test/static-unit.mjs 静态守住(裸名/未声明的 import 直接测试失败)。ws 是普通运行时依赖,本地目录安装要按上面「安装」一节先 npm install。把 lib/ 单独拷出来裸跑仍然跑不起来(设计如此,不是缺依赖)。

更新日志

最近五个版本(始终滚动展示):

  • v0.6.3 — 「账号入口 + 面板内一键启动 NapCat」:设置页「QQ助手」面板顶部新增一组 「相关链接」(整体不拆、贴着头放,顺序 account → changelog → readme-debug → console),第一条即 「QQ助手账号(登录 / 扫码)」——指向宿主自己的 GET /qqai/account:服务端读 bootmain/config/webui.json 里的 token 后 302 到 /webui/?token=<token>,点开就是已登录的 NapCat 页面,不用手抄密钥(token 只出现在 302 的 Location,不进面板载荷)。落点形状按 NapCat 4.18.28 的前端实现 + 本机实测确定:hash 由前端计算、落点必须带尾斜杠。同一面板新增 「快捷操作」:启动 NapCat 与 重新登录(扫码),实时状态取自载荷的 napcat 字段;重新登录只按加载器 PID 清理,绝不按镜像名杀 QQ。启动成功后 二维码直接显示在面板里(GET /qqai/napcat/qr 提供 cache/qrcode.png,超过 5 分钟视为过期),面板会自动等待并显示它。启动路径重做:子进程不得带 detached(本机实测带 detached 时命令根本不执行)、提权后需自行 cd /d(%cd% 会变成 System32)、复杂命令不再经 cmd /c 传参(引号会被打乱),改为生成可审计的垫片脚本 <cwd>\qq-napcat-launch.cmd 并由提权命令只执行它;成功判据改为垫片心跳,失败一律如实回报。修复:浏览器点击入口被同源守卫判 403(导航请求不带 Origin,自 v0.6.0 起存在)、桌面端相对入口无法打开(改为 ?format=json + window.open 绝对地址)、点「刷新二维码」整页白屏(整对象 setState 且缺少渲染边界)。隐私:面板回显日志前对密钥打码、启动日志用 icacls 收紧权限、仓库移除机器人真实昵称,并新增「真机日志片段 / 私有昵称」两道自动检查。settings-unit 86 → 178 条断言;全量 57 套 / 3851 断言全绿
  • v0.6.2 — 「功能说明补全」:真机反馈"有些功能说明不是很全,比如 AI 生图就写了串英文、没说需要额外软件或模型"。59 个开关里原来有 21 行提示是空的——现在每行都讲清"做什么 / 需要准备什么 / 关掉会怎样"(25–235 字),并给需要外部条件的开关加上依赖小标签:需外部服务(生图 API、TTS:本地 GPT-SoVITS 或云端)、需密钥(转写)、需词表文件(内容过滤/关键词)、需配置、需群管理员、需 NapCat 扩展、不需模型;16 个开箱即用的不带标签。说明支持极简加粗并带 title 全文。新增 5 条守卫(含"schema 里带 apiKey/baseUrl/provider/model 的功能必须标依赖"这条证据型检查);「非默认」徽标补上方向(实测 9 个非默认全是"默认关被打开",现在写成 非默认·默认关 / 非默认·默认开)。另外把依赖口径写在明处:TTS 与生图 DSH 与本插件都不自带(要你自备服务或密钥)、语音转文字 DSH 自带(实验性「语音输入」bundle,需在该 profile 里自行启用,首次用会下载本地 SenseVoice 模型),语音与媒体那一组加了组级提示,依赖标记改成「需自备服务 / 需自备密钥 / 需自备词表」;需要额外安装的一律默认关(voiceReadingEnabled 由默认开改为默认关),并有断言钉住。并把语音转文字改成默认走 DSH 自带的本地识别(sttProvider 默认 dsh:宿主服务 speechToText + 本地 SenseVoice,音频不出本机、不需密钥;QQ 语音统一用 ffmpeg 转 16kHz 单声道 WAV,仍可显式设成 cloud 走云端),新增 est/stt-unit.mjs(24 条)。全量 57 套 / 3765 断言全绿
  • v0.6.1 — 「开关配色修正」:真机反馈"关了以后感觉按钮消失了一样"。原因是 OFF 态被做成了卡片同色轨道 + 白圆点,浅色主题下白底白点=隐形。现在照抄平台自己的开关样式(dsh-client-ui-primitives 的 Switch.module.css):轨道 OFF --dsw-alias-border-l3(浅色 #0000001f / 深色 #ffffff29)、ON --dsw-alias-brand-primary;圆点 OFF --dsw-alias-switch-thumb、ON --dsw-alias-label-primary-foreground;几何也对齐(36×20 / 内边距 2 / 圆点 16 / 位移 16 / 120ms)。语义改用 role="switch" + aria-checked(与官方一致,视觉不会和无障碍语义打架)。新增 4 条断言钉住官方 token 与"状态 → aria-checked"映射。全量 56 套 / 3728 断言全绿
  • v0.6.0 — 「轻量化设计」:DSH 设置里多了一页「QQ助手」,常用开关点一下就启停——7 组 59 个开关(从 224 个配置键里精选;进阶三组默认折叠),每行显示中文标签、"关掉会怎样"、配置键名,并标出「非默认」「待重启」;点一下即写入 profile 的 cordis.patch.yml,只改本插件那一段(原子写 + .bak-qqai 备份;白名单外/非布尔一律 400 拒绝),随后 DSH 热重载该插件、开关生效。轻量体现在:零新增依赖(客户端只用宿主自带的 react,手写 window.__ModuleLoader__.load bundle,不引构建器)、样式全走 DSH 主题变量、ctx.inject(['webServer']) 所以没有 web 服务的宿主上这段根本不执行;路由会在插件重挂时注销,不会撞 duplicate route。另收口 v0.5.9 后真机跑出的问题:@ 被客户端发成纯文本时也算 @、命令粘参(/设管理123)不再丢给模型、写操作失败不再把 NapCat 原始 JSON 贴进群、bot_offline 有明确告警。static-unit 21 → 26,新增 settings-unit(86 条),全量 56 套 / 3724 断言全绿
  • v0.5.9 — 「兼容 DSH 0.2 与官方桌面端」:DSH 运行时升到 0.2.0-rc.2 后,profile 因为插件的 peer 范围只声明到 ^0.1.x 而直接拒载(skipping profile bundle … is incompatible with dsh 0.2.0-rc.2)——QQ 桥因此静默停摆了六天;官方新出的桌面端用的是同一个运行时版本,一起修。① 六个 @deepseek-ai/dsh-* 的 peer 范围加 ^0.2.0-rc.2:CLI/web 宿主与桌面端都能直接加载,不再需要 dsh plugin allow-version 豁免(真机验证:撤销豁免后 --dump-config 不再 skip,插件正常挂载、6700 正常监听)。② 端口被占不再崩、不再卡启动:OneBotServer.start() 从"返回 void + emit('error') 无订阅者直接抛 + Promise 永不 resolve"改成如实返回 { ok:false, code, reason },插件入口按 15 秒退避重试;真机三实例实测——占用者被杀后重试者 15 秒内自动接管 6700 并启动桥。③ stop() 对"从未监听成功"的实例也安全(重试不泄漏 Server)。④ 新增静态守卫:dsh-* 的 peer 范围必须覆盖 0.2 线,下次运行时升级忘了改这里会直接测试红。⑤ 控制台「打开扫码页」不再点进「token 无效」:新增 GET /api/napcat/webui,从 webui.json 读出 NapCat 自己的 token 拼进地址(token 不落快照、不进诊断包)。⑥ 群里 @ 了机器人却一个字都不回(真机抓到的现场 bug):有些 QQ 客户端把 @机器人 发成纯文本(正文里是 "@昵称"、一个 at 段都没有),只认 at 段的门禁会把它静默丢掉;现在按名字(自动学昵称/群名片 + 新配置 mentionAliases)也算 @,并且会把 @名字 摘掉,让 /命令 回到行首(否则命令会被当成聊天丢给模型)。onebot-api-unit 44 → 61、control-unit 152 → 161、commands-unit 72 → 78、static-unit 17 → 21,全量 55 套 / 3633 断言全绿

更早的版本(v0.4 线及之前)见 CHANGELOG.md —— 完整历史、每个版本的缺陷清单与测试计数都在那里。

内容来自项目 README(GitHub)↗

链接

同类插件

查看整个分类 →

社区评论

评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。