dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
🤖 100% 由 AI 编写完成。把 QQ 接入 DeepSeek Harness 的桥接插件。提供执行期安全门禁、外部插件沙箱、模型无痕热切、看门狗失败降级与完整 Web UI。零外部 npm 依赖。
把 QQ 接进 DeepSeek Harness:QQ 私聊/群消息变成 DSH 会话里的用户消息,agent 的回复发回 QQ。
每个 QQ 会话对应一个独立的 DSH 会话,统一归组到「QQ 聊天」工作区。QQ 会话固定用 qq-chat preset,由本仓库的 @local/dsh-qq-guard 插件提供执行期工具门禁(deny-by-default),确保 QQ 那头的人拿不到本机执行能力。
QQ ──► NapCat (OneBot v11 正向 WS) ──► qq-bridge ──► DSH Web API
▲ │
└── agent 回复 ─────┘当前版本:v0.5.1(2026-10-24)
本版做了什么:修 v0.5.0 的真机盲点——老 QQ 会话拿不到新工具(模型说「没有发图工具」)。
tool-addition 增量下发。v0.5.0 之前建的 QQ 会话,基线里没有 qq_send_image;在 opencode-go/deepseek 这条路由上模型始终看不到它(真机验证:同一句话在新建 qq-chat 会话里模型会正常调用 qq_send_image,在老会话里连显式点名都拒绝)。重启 DSH 不够—— 工具基线随会话历史持久化。
/config 新增 toolEpoch(工具能力版本);桥接给每条会话记下建会话时的epoch,发现不一致就在下一条消息时把该会话的 DSH 上下文自动重建一次(旧会话归档、不删历史), 新工具随之进入基线。启动时会同步拉一次热配置,避免重启后第一条消息仍落在旧基线。
features(设置页刚打开技能时【能力】段会立刻重推);系统提示词新增【工具可用性(以本段为准)】权威块,压掉自定义人设/历史里「这里没有发语音/发图工具」这类过时说法; qq_send_image 描述明确「对方要图就直接调用,别回答没有发图工具」。
qq-bridge/config.json 写{ "capability": { "autoRefreshOnUpgrade": false } },之后需要自己「清空上下文」一次。
上一版(v0.5.0,2026-10-24):四项 P2 收口 —— 发图片、外部插件真实生效、桥接性能、UI 手感。
qq_send_image 工具(官方 defineTool 编译参数,url / file 二选一),桥接用 OneBot image 段发送并等回执再回答模型(下载/拒收的失败原因原样抛给模型)。 设置页「技能与插件」新增 sk-image(老配置里没有也显示,默认开),系统提示词同步引导模型使用。
message / before-context 事件转发进沙箱执行插件 hook(可改写文本、丢弃消息、追加外部上下文); 插件 registerTool() 注册的工具自动代理成 qq_ext_ 暴露给 QQ 会话(沙箱单飞 + 10s 超时)。 失败一律 best-effort,不影响聊天;GET /dsh-qq-guard/external/runtime 可看常驻状态 / 已加载 hook 与工具。
图片 ingress 后台预取(并发 2 / LRU 32 / TTL 60s,复用 in-flight Promise)、TTS 语音指令脱离主串行链。
2–3 秒轮询全部下沉到叶子组件(切 Tab / 轮询不再带着整个面板重渲染)、耗时按钮加纯 CSS spinner。
上一版(v0.4.0,正式版,2026-10-24):把 QQ 桥接从「能跑但一堆静默失效」推到「人设、语音、搜索三条主链路都真机打通」。
applyGuard() 第一步就 return,人设 section / qq_send_voice / restrict / 执行期白名单四件事全没跑(当时 QQ 会话 既没有系统人设、也没有执行期门禁)。改成 composedPreset + restrict 探针两层判定、 兜底 fail-closed,并新增「真宿主 + 真实 mountPreset」的回归测试。
complete 人设(6554 字实锤),provider 也不覆盖system(直连 API 验证)。真正盖掉它的是 dsh-mnemon:把 USER.md / MEMORY.md 快照当 user 消息插进每一步。现在 guard 在 agent 创建之后用 {prepend:true} 挂到 agent.ctx 上,把这类消息摘掉。这也是隐私修复:此前群友对话能让模型读到主人的长期记忆。 (顺序陷阱有真 cordis 对照实验:装载时 prepend / push 都会泄漏,只有「agent 创建后 prepend」干净。)
Sec-MS-GEC v2)。换成免 Key 的 baidu provider(默认),edge 失败自动降级;qq_send_voice 改成等桥接回执, 失败直接抛错给模型。真机回执:已发送语音(baidu,96KB,via=base64,retcode=0) → QQ 收到语音条。
DEEPSEEK_API_KEY。「网页搜索」齿轮里可填Key / baseUrl / model,经 /config 热同步写进 DSH 的 web-search-deepseek,2 秒生效。
sessions.json 的 activityLevel,null = 跟随全局),私聊不受影响。
未实装条目明确标「开发中」并给出原因。
qq_send_voice 用官方 defineTool() 编译参数、web_search 补挂载、人设不再每 2 秒重复推送、Host 会话上报白名单补齐 persona/activityLevel。
上一版(v0.3.1-alpha,同日早些时候):guard 在 preset 内整体失活(P0)、qq_send_voice 非法 schema、web_search 未挂载、人设每 2 秒重复推送、单群独立响应档位、技能配置弹窗。
更早(v0.3.0-alpha):
at 段转成 @昵称 (拿不到昵称退回 @QQ号 ),并保证与正文之间有一个空格。qq_send_voice + Edge TTS / OpenAI 兼容 TTS,经 NapCat record 段发送。personaPresets。上一版(v0.2.0-beta.1):
agent/request 瀑布里按会话覆写本次请求的 provider/model,不碰 session/selectModel、不改 DSH 全局默认;POST /dsh-qq-guard/model 为桥接下发的入口。llm/stream 上看门狗把「模型挂着不吐字」翻成终态错误,agent/request-error 在同一轮内切到备用模型;GET /dsh-qq-guard/system-events 暴露最近 20 条底层事件。replyTimeoutMs / modelWatchdogMs / antiDebounceMs 进配置与设置页,桥接热读。更早(v0.1.1-beta.1):
plugin.json / skill.json),支持动态配置表单,默认全部关闭。ctx.subprocess 独立进程 + --permission + module.registerHooks 拦截 node:fs / node:child_process / 越界引用,支持对自包含模块执行 setup() 冒烟测试。2026-10-24 的四个真机 Bug 已全部修复,根因与验证见
plugins/dsh-qq-guard/README.md 的「2026-10-24 修复记录」一节。下面保留现状待办,都是「离线验不到、必须真机跑一次」的项目。
已发送语音(baidu,96KB,via=base64,retcode=0),NapCat 收 mp3 base64 并转成 QQ 语音条。若哪天换 edge/openai 后端失败,失败原因会经回执 回到模型与日志(不会静默)。
(写入 DSH 的 web-search-deepseek),没配 Key 时工具会如实报 WEB_PROVIDER_CREDENTIAL_MISSING,别把它当「插件没接上」。
DSH 的代理策略只读启动环境变量,要用本机代理得 HTTPS_PROXY=… 重启 DSH。
agent/created 给每个 agent 挂监听,插件热重载不会重挂已存在的 agent, 必须重启一次让新会话走新代码。验证看 QQ 会话是否还会冒出 USER.md 的内容。
进程不重启还是旧逻辑(设置页改完能落盘,但旧进程不认新字段)。
plugins/dsh-qq-guard/ DSH 插件(Host + 浏览器半身)
├─ index.js qq-chat preset 的工具门禁 + 设置页数据路由 + 状态路由
├─ client.js 设置页 UI(分片节奏 / 群聊 @ / 标点处理 / 进程管理)
├─ cordis.patch.yml bundle patch:插入 qq-chat preset + 顶层 settings 行
├─ napcat.mjs NapCat 进程管理(启动 / 停止 / 三层在线判定)
├─ bridge-runner.mjs 桥接进程管理(autoStart / 单实例 / 崩溃重启上限)
├─ sandbox/ 外部插件沙箱执行链路
│ ├─ protocol.mjs Host ↔ 子进程的 NDJSON 协议(零依赖、两侧共用)
│ ├─ manager.mjs Host 侧:拉起子进程 / 超时 / 熔断 / testLoad + invoke
│ └─ child.mjs 子进程入口:--permission + registerHooks 拦危险内置模块
└─ test-*.mjs 离线回归(假 ctx / 假 subprocess,不真起进程)
qq-bridge/ 独立桥接进程(零 npm 依赖)
├─ start.mjs 入口:读配置 → 起桥接 → 打印状态
├─ src/onebot.mjs OneBot v11 正向 WS 客户端(文本分片 / 语音 / 图片)
├─ src/dsh.mjs DSH Web API 客户端(离线铸会话 Cookie)
├─ src/bridge.mjs 主逻辑:白名单 / 串行投递 / 回复审计 / 图片预取
├─ src/external-hooks.mjs 外部插件 hook 客户端(message / before-context,best-effort)
├─ src/runtime-config.mjs 从插件轮询热配置
└─ test-offline.mjs 离线自测(不连 QQ、不启 NapCat、不碰 DSH 会话)两份代码要一起用:插件负责门禁和设置页,桥接负责收发消息。
plugins/dsh-qq-guardrole: guard,装在 qq-chat preset 内)tools.restrict:把危险工具从该作用域的工具清单里隐藏;tools.guard:执行期白名单兜底,任何不在白名单内的调用一律拒绝。tools.guard 是全局的,会把浏览器里的正常会话一起锁死。这个坑在代码注释里写了来龙去脉。role: settings,装在 profile 顶层):分片节奏、气泡长度、群聊 @ 位置、标点处理、白名单、人设、外部插件、NapCat / 桥接进程管理。/dsh-qq-guard/config(桥接轮询热更新)、/dsh-qq-guard/status(状态上报)、/dsh-qq-guard/napcat、/dsh-qq-guard/bridge、/dsh-qq-guard/external-plugins/test(沙箱冒烟测试)、/dsh-qq-guard/external/hook(桥接转发的插件 hook,best-effort)、/dsh-qq-guard/external/runtime(常驻沙箱快照)。registerTool() 的工具执行都只在子进程内发生(单飞 + 超时熔断)。qq-bridgeWebSocket / fetch(Node ≥ 22)。~/.dsh/.credentials.yaml 里持久化的 client-connection/browser-session 签名密钥离线铸造会话 Cookie。权限等同浏览器会话,所以白名单不是可选项。sk- Key / 桥接令牌 → 整条不发)+ 同会话串行投递。qq_send_image 入队 → 桥接用 OneBot image 段发送(http(s) URL 由 NapCat 下载,也接受 base64:// / file:/// / 绝对路径),等回执才算成功,失败原因回给模型。message / before-context 事件转发给 Host 常驻沙箱执行(可改写文本 / 丢弃消息 / 追加外部上下文),HTTP 失败或超时一律按原样放行。前提:Node ≥ 22、运行中的 NapCat(开好正向 WS 服务端)、运行中的 DSH 桌面端。
# 1) 插件:以 link 方式装进 profile(路径换成你放本仓库的位置)
dsh plugin --profile desktop add "link:<本仓库>/plugins/dsh-qq-guard"
# 2) 重启 DSH(bundle 层要重启才组装)
# 3) 桥接:复制配置再改
cp qq-bridge/config.example.json qq-bridge/config.json
node qq-bridge/start.mjs --dry-run # 只校验配置 + DSH 鉴权,不连 QQ
node qq-bridge/start.mjs # 正式启动qq-chat preset 由 cordis.patch.yml 自动插入,不需要手改 profile yaml。
qq-bridge/config.json:
字段 · 说明 dsh.sessionCwd · QQ 会话落在哪个工作区目录(必填) onebot.wsUrl / onebot.accessToken · NapCat 正向 WS 地址与令牌,两边必须一致 allow.private / allow.groups · 白名单。留空 = 谁都不理(刻意的默认值) deny · 黑名单,优先级高于白名单
插件设置页的优先级高于 config.json:桥接每条消息现读热配置,改设置不用重启。