DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Onebot Qq — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins
O

dsh-onebot-qq

Onebot Qq

Add a QQ channel to dsh via OneBot 11, compatible with NapCat / Lagrange / LLOneBot: automatic reconnection for reverse/forward WS, private and group chats, image/voice transcription, t2i text image cards, merged forwarding, and visual configuration in the settings page. QQ channel for dsh via OneBo

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:mario841859784/dsh-onebot#2cbf5b5fb9a3c8e928b92f1bb19f4c54efa32ce4
READMECompatibilityVersions

Description

Add a QQ channel to dsh via OneBot 11, compatible with NapCat / Lagrange / LLOneBot: automatic reconnection for reverse/forward WS, private and group chats, image/voice transcription, t2i text image cards, merged forwarding, and visual configuration in the settings page. QQ channel for dsh via OneBot 11.

Compatibility and provenance

Onebot Qq is published as dsh-onebot-qq and currently resolves to version 0.4.7. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
github
Registry updated
9/25/2026

Versions

0.4.7stable
9/25/2026
0.4.6stable
9/25/2026

Related plugins

Loading related plugins…

Latest
0.4.7
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
web
License
BSD-3-Clause
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
9/25/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in integrations-communication.

Acp App@deepseek-ai/dsh-acp-appThe dsh ACP profile bundle: automation-only JSON-RPC stdio and process lifecycle over dsh-baseRemote Web Ui@linxin666/dsh-remote-web-uiScan-to-pair remote access for the dsh web GUI that shares one official interface: a QR beside the settings button pairs phones and PCs into the same Web GUI (a portrait-touch adaptation layer for phones, full desktop on PCs) through one-time tokens and rDSCODE@toddzheng024/dscode-bundleA complete DeepSeek coding agent with persistent shell, Ultra collaboration and automatic permission review.Im Connect@michengai/dsh-im-connectDSH IM Connect — 将主流即时通讯平台接入本机 DeepSeek Harness · Connect major messaging platforms to local DeepSeek Harness agents

README

dsh-onebot

English | 中文

给 DeepSeek Harness 加上 QQ 通道。A QQ channel for dsh.

本插件把 dsh 变成一个 QQ 机器人(OneBot 11 协议,兼容 NapCat / Lagrange / LLOneBot / go-cqhttp), 与 dsh-vision 同款的外部插件形态:零 Python、纯 TS、 原生 Cordis 插件,挂载进 dsh 宿主进程,不改任何核心代码。

用户(QQ) ←→ NapCat ←→ dsh-onebot 插件 ←→ dsh Agent(每个会话一个)
                        ├─ 反向 WS 服务器 / 正向 WS 客户端(自动重连)
                        ├─ 入站:CQ 解析、图片下载、语音转写(STT)、引用/合并转发展开
                        └─ 出站:单条/t2i 卡片发送、Markdown 剥离、[[qq_forward]]、图片/语音/视频/文件工具

架构

dsh-onebot QQ 通道架构

可交互版本(暗/亮主题切换 + 引导视图):docs/dsh-onebot-architecture.html;矢量版:docs/dsh-onebot-architecture.svg。

功能

类别能力
连接反向 WS(NapCat ws-reverse 拨入,默认端口 8643)或正向 WS(拨出,默认 ws://127.0.0.1:3001);断线自动重连(2s→60s 退避)
入站私聊/群聊、段数组优先解析(CQ 字符串回退)、CQ 反转义、@/回复触发检测(fail-closed;回复仅认机器人自己的消息)、图片四路解析(url/base64/file/hash)、大图自动压缩(长边 ≤inboundImageMaxPx,GIF 不压)、文件段双通道接收(CDN 直链 get_private_file_url + get_file base64/url 回退)、表情 id→emoji/卡片/戳一戳段类型、引用消息自动取原文(get_msg)、合并转发自动展开(get_forward_msg)
语音ffmpeg 转 16kHz WAV + whisper 转写(openai-whisper / whisper.cpp / 自定义命令);非阻塞:语音消息先以 [语音] 占位进入回合(不阻塞回复),转写完成后以「(语音转写:…)」补递(默认超时 60s);转写失败/超时保留 [语音] 占位
文字图t2i 卡片渲染器(@napi-rs/canvas):标题/粗斜体/删除线/引用/列表/代码块/表格/行内 code 胶囊/彩色 emoji/中文标点禁则;与 Hermes 原版同款数值(800px/26px/禁则集合/右缘 790)
出站正文 ≤ textImageThreshold(默认 150)字符单条发送、超过阈值渲染 t2i 文字图卡片(AstrBot 风格:标题/引用/列表/表格/代码块/彩色 emoji;渲染失败、PNG 超 outboundImageMaxBytes 或 <=0 禁用卡片时回退单条纯文本)、Markdown 剥离为 QQ 纯文本、[[qq_forward]] 合并转发(群/私聊)、实时中间消息(interimMessages:每条中间文本立即发出、实时可见;各自在 interimRecallMs(默认 90s)后自动单独撤回;回合结束时先把整轮中间消息渲染成一张 t2i 小结卡、立即撤回仍在屏幕上的原文、再发送最终回复——不用回合末合并转发,避免长回合「原文超 2 分钟撤不回+转发卡重复」;interimRecall: false 时降级为只发不撤(无小结卡、不撤回))、宿主「计划书/提问卡」自动中继(模型调用 exit_plan_mode / ask_user_question 时把计划全文/问题选项发到 QQ)、正在输入提示(set_input_status,仅私聊)
命令斜杠命令(仅管理员):/new 开新会话、/stop 停止生成、/model 查看或切换当前会话模型(--default 修改部署默认;无参输出两级序号列表,回复序号选 provider → 再回复序号选模型)、/workspace 查看或切换工作区(无参编号列表,回复序号即选)、/preset 查看或切换 agent 预设(无参编号列表,回复序号即选)、/session 查看可切回历史会话并按序号切回(/new、/workspace、/preset 切换下来的旧会话进列表,可来回切,历史上下文恢复)、/status 会话全景、/retry 重跑上一条、/id 会话标识、/ver 版本、/ocr 识别最近图片、/mode 切换出站模式(跨重启持久化)、/plan 计划模式、/permission 切换宿主权限预设(QQ 别名 w=工作区可写+需审批、f=全权+免审批;完整预设名照传,未知名由宿主报错并回显可用列表;无参查看当前与可用列表,序号按 available 顺序)、/goal 目标记录(跨重启持久化)、/help 帮助;未知斜杠命令默认拦截并提示相近命令(unknownCommand: passthrough 改为透传给模型)
工具qq_send_image(≤9 张,路径或 URL)、qq_send_voice、qq_send_video、qq_send_file、qq_send_forward、qq_napcat_api(14 个白名单 action)、qq_group_history(文件编辑工具 code_safe_edit 等已拆至独立插件 dsh-safe-edit,见下文「安全编辑」)
权限管理员白名单(ONEBOT_ALLOWED_USERS)、dm/group 策略(open/allowlist/disabled)、群聊 @提及 gating、受限用户 [受限用户:仅问答] 软限制、出站敏感内容审计
会话每个 QQ 会话一个持久 Agent(session id 稳定派生),重启后自动 resume;按 agentPreset/workspacePath 挂载到 preset 与工作区;每轮结束 flush 落盘
运维热加载:profile 层 patch 的 config 覆盖与 insert 新增/删除均热生效——插件 fiber 秒级原地重启(宿主进程不重启;代价:QQ 桥一次秒级重连、在途回合中断);touch/内容未变不触发任何动作;bundle 自带 patch、仓库模板、部署副本的 patch 文件与根配置 cordis.yml 的改动不热生效;临时媒体 TTL 过期清理
提示词自动注入 QQ 平台说明(纯文本输出、图片/语音标注 [图片]/[语音] 占位、工具与命令指引、禁宿主交互卡);按每个 QQ 会话 agent 自身作用域注入,Web 会话不可见

兼容性

项要求
dsh≥ 0.1.5-rc.1(engines.dsh;@deepseek-ai/* peer 依赖 ≥0.1.5-rc.1,JsonValue 由 dsh-util-values 提供)
Node.js≥ 22
OneBot 11 实现NapCat / Lagrange / LLOneBot / go-cqhttp(reverse 或 forward WebSocket)
可选依赖语音转写需 ffmpeg + whisper CLI;t2i 文字图在 Linux 需 Noto CJK 字体

最后验证:2026-09-12(M4 交互与持久化:未知命令拦截 / 序号选择 / workspace 持久化——vitest 306 用例全绿、构建通过;M0 安全语义保持:reverse 空 token 拒绝启动、默认仅监听 127.0.0.1 为 BREAKING 变更,见下方配置表说明)。

安装

前置:dsh(≥0.1.5-rc.1)在 PATH 上;NapCat 或其他 OneBot 11 实现已运行。

npm 安装(发布通道,与下方源码安装二选一,勿混装)

dsh plugin --profile web add dsh-onebot-qq

(或用 Web 界面的 Plugins 页安装。)随后:

  1. 在 profile 目录 <DSH_HOME>/profiles/web/ 的 pnpm-workspace.yaml 中写入两行 (实测 pnpm 12 不读项目级 .npmrc,见 docs/npm-e2e-report.md D1):

    autoInstallPeers: false
    hoist: false
    

    ——防止 pnpm 自动拉入 registry 上陈旧的 @deepseek-ai/* 独立副本。npm/pnpm 版本差异: 此配置仅 pnpm 12 用户必须(pnpm 12 已不读 .npmrc);npm 用户无此问题——实测 npm 默认 peer 自动安装拉入的 registry 现版本满足 peer 范围(docs/npm-e2e-report.md §1 #2)。 运行期 peer 统一由宿主解析层完成:插件 import 的 @deepseek-ai/* 只要声明在该包 peerDependencies 里,就会被宿主拦截并重定向到宿主安装树的同一实例, 无需任何 npm override。

  2. 把包内 cordis.patch.yml 模板的两行 insert 合并进 profile 层 <DSH_HOME>/profiles/web/cordis.patch.yml:主条目 name: 'dsh-onebot-qq', host-plane 行 name: 'dsh-onebot-qq/settings-remote';config 覆盖须挂 patch 顶层同 id 行(详见模板头注释)。

  3. 不要在 profile 的 package.json 手写任何 @deepseek-ai/* 依赖——手写副本会 覆盖宿主安装树成为拦截目标,造成版本错位双包。

  4. 若安装被兼容门拒绝(dsh 版本不在 peer 范围内),按官方口径用 dsh plugin allow-version ... --accept-risk 显式豁免。

方式二:git clone 源码安装

git clone <repo> ~/dsh-plugins/dsh-onebot
cd ~/dsh-plugins/dsh-onebot
npm install --include=dev
./scripts/build.sh          # 链接宿主 @deepseek-ai 包 + tsc 编译 src/ → lib/

部署副本必须带完整 node_modules 链接集(scripts/link-host.sh 产物):files 只打包 lib/, 但运行时 peer 依赖 @deepseek-ai/* 是链接到宿主安装的——只复制 lib/ 会挂载失败(插件入口会 显式报「peer 依赖解析失败」错误)。宿主无 dsh 在 PATH 上(如 fnOS 应用形态)时用逃生门: DSH_ROOT=<宿主node_modules路径> ./scripts/build.sh。

fnOS 应用形态宿主构建:fnOS 应用中心安装的 dsh 没有 dsh CLI 在 PATH 上,build.sh 的自动定位 (PATH 二进制 → npx store)会失败并显式报 cannot locate the dsh install。此时用 DSH_ROOT 显式指定 宿主 node_modules 根(该目录下须有 @deepseek-ai/,否则报错退出而非静默回退):

DSH_ROOT=<fnOS 应用数据目录>/node_modules ./scripts/build.sh

构建完成后把部署副本(lib/ + 完整 node_modules 链接集)放到目标位置再挂载;运行副本缺链接集同样会挂载失败(见上方说明)。

挂载到 ~/.dsh/config.yaml(没有就新建):

- insert:
    - id: dsh-onebot
      name: '$HOME/dsh-plugins/dsh-onebot/lib/index.js'
      config:
        mode: reverse        # reverse = NapCat 拨入;forward = 插件拨出
        port: 8643
        # accessToken: '与NapCat一致的token'   # 必配:reverse 模式留空将拒绝启动(M0 安全加固)
        # botQQ: ''          # 留空自动从 meta 事件学习
        adminUsers: ['你的QQ号']   # 必配:至少一个管理员,否则私聊/斜杠命令不可用

⚠️ 首次配置必须设置至少一个管理员(adminUsers 或环境变量 ONEBOT_ALLOWED_USERS): dmPolicy: open(默认)只允许管理员私聊,斜杠命令也仅管理员可用;不设置则无人能对话。 开发调试可临时 allowAllUsers: true(或 ONEBOT_ALLOW_ALL_USERS=true)放行所有用户。

重启 dsh(dsh web 或你的启动方式),日志出现 [dsh-onebot] mounted 即挂载成功。

NapCat 侧(必须配置,两种模式二选一):

  • reverse 模式(NapCat 拨入 dsh,推荐):NapCat 网络设置里新增「WebSocket 客户端」, 「上报地址」填 dsh 的 WS 地址 ws://<dsh 所在机器 IP>:<port>/ws(如 ws://192.168.1.100:8643/ws), 「token」填插件 accessToken 相同的值;dsh 与 NapCat 不同机时不能用 127.0.0.1。
  • forward 模式(dsh 拨出到 NapCat):NapCat 网络设置里启用「WebSocket 服务端」(默认监听 0.0.0.0:3001),插件 url 配置为 ws://<NapCat 所在机器 IP>:3001(同机可用 ws://127.0.0.1:3001),token 两边一致。

两侧 token 必须一致;消息上报格式建议选「数组」(插件段数组优先解析,CQ 字符串仅回退)。 配置完成后重启 dsh,日志出现 [dsh-onebot] mounted 且 NapCat 显示连接成功即就绪。

部署位置要求:NapCat 必须部署在 dsh 可达的局域网内(同一网段/能互通), WS 连接、图片下载、文件解析都依赖这条网络通路;NapCat 与 dsh 不在同一台机器时, 需要在 NapCat 侧开启「文件转 URL」开关,get_file 才会返回可下载的 http(s) url (否则返回容器内路径,本插件无法访问)。

配置

完整配置项见 src/index.ts 的 Config schema(schemastery 校验,均有默认值)。常用:

键默认说明
modereversereverse/forward
host / port127.0.0.1 / 8643reverse 监听;跨机部署(NapCat 从其他机器拨入)需显式改为 0.0.0.0
urlws://127.0.0.1:3001forward 目标
reconnectMaxAttempts100自动重连放弃上限:连续失败达到该次数后停止重连,日志输出上限值与恢复指引;0 = 无限重连(退避封顶 60s)
accessToken空OneBot token;reverse 模式必填,留空插件拒绝启动(fail-closed);forward 可为空
botQQ空机器人 QQ(空=自动学习)
ignoreSelftrue忽略机器人自己发出的消息(防自循环)
requireMentiontrue群聊需 @ 或回复机器人的消息才响应(回复他人消息不触发;被回复消息无法判定时回落视为提及,fail-open)
rateLimitPerMinute30每会话每分钟普通消息上限(60s 滑动窗口):超限跳过处理并限流提示(每窗口至多一条),命令不受限;0 = 禁用
unknownCommandintercept未知斜杠命令处置:intercept(默认)拦截并提示相近命令(前缀匹配优先,编辑距离 ≤2 兜底且仅输入长度 ≥4 时启用,至多 3 个候选;无候选提示发 /help 或去掉开头 / 重发);passthrough 维持旧行为透传给模型。非 /纯单词 开头的文本(如路径 /tmp/x)不受影响
dmPolicyopen私聊策略:open(仅管理员)/allowlist(白名单)/disabled
groupPolicyopen群聊策略:open(所有人)/allowlist/disabled
restrictedMemberPrefixtrue群聊非管理员消息注入 [受限用户:仅问答] 前缀(软限制)
adminUsers[]管理员 QQ;也可用 ONEBOT_ALLOWED_USERS 环境变量。必须至少设置一个,否则私聊(dmPolicy=open)与斜杠命令无人可用

⚠️ BREAKING(M0 安全加固):reverse 模式下 accessToken 留空会拒绝启动(fail-closed);host 默认从 0.0.0.0 改为 127.0.0.1(仅本机监听),跨机部署需显式配置 host: 0.0.0.0。

环境变量:ONEBOT_ALLOWED_USERS(逗号分隔管理员)、ONEBOT_ALLOW_ALL_USERS=true(开发用)。

设置页

dsh Web GUI 的设置页提供本插件的可视化配置(host-plane Remote onebotSettings,写入 profile 层 cordis.patch.yml 中 dsh-onebot 条目的 config 覆盖行——与手改 patch、宿主原生设置页是同一个持久层)。

三组 19 键

组键
connection(连接)mode、host、port、url、accessToken、botQQ
permissions(权限)requireMention、adminUsers、dmPolicy、groupPolicy、allowAllUsers、allowFrom、groupAllowFrom
behavior(行为)interimMessages、interimRecall、interimRecallMs、sendErrorNotice、unknownCommand、rateLimitPerMinute

accessToken 在设置页做密码型输入,快照返回侧脱敏(不回显明文);写入侧仍在 patch 文件明文落盘。

与 patch config 的优先级

schema 默认值 ← bundle/底层 patch(继承层) ← profile 覆盖行(设置页写这里);同一层内后写的 patch 条目胜出。设置页键与手改 patch 是同一层的同一行,不存在两套优先级。三组 19 键之外的键 (media/STT/性能/agentPreset 等低频键)不设 UI,仍在同一行 config 手改 patch。

生效方式

每次保存(设置页或手改同一覆盖行)= 插件 fiber 秒级原地重启生效,宿主进程与 Web GUI 不重启; 代价:QQ 桥一次秒级重连、在途回合中断、频控窗口与中间消息缓冲清零(会话映射/历史不受影响)。 与当前覆盖行全等的保存是 no-op,不触发重启;写入导致插件激活失败时 patch 文件自动回滚、旧配置继续运行。

会话工作区(workspace)选择

每个 QQ 会话创建时按以下优先级确定工作目录(写入 session meta,创建时冻结,不随配置变化):

  1. 该会话的 /workspace 覆盖(per-chat 记录,跨 /new 保留)
  2. 配置 workspacePath
  3. 宿主进程 cwd(process.cwd())

/workspace <目录> 切换(realpath + 目录校验):记录覆盖后会 retire 当前 agent, 下一条消息以新目录重建会话,旧会话保留在磁盘。/workspace 无参数输出编号列表 (当前目录标「← 当前」),回复 /workspace <序号> 即可切换;/workspace list 列出全部 workspace 记录。

/workspace 的 per-chat 覆盖已持久化进映射文件(chat-sessions.json,加法格式、兼容旧文件): 重启、会话恢复失败均不丢失,对 /new 同样保持——只要该 chat 用的是非默认目录, 重启后 /workspace 与新会话都会继续使用原目录。

会话自动挂载到 GUI 工作区:仅当会话 cwd 等于配置的 workspacePath(未配置时为宿主 cwd) 才自动创建 workspace;沿用旧 cwd 的遗留会话只在已有 workspace 拥有该路径时挂载,不会自动新建。

斜杠命令速查(全部仅管理员)

命令作用
/new开启新会话(清空上下文,旧会话保留在磁盘)
/stop停止当前生成
/model [--default] <provider> <model>查看或切换当前会话模型;--default 修改部署默认。无参输出两级序号列表:回复序号选 provider → 再回复序号选模型并切换当前会话
/workspace [路径|序号|list]查看或切换工作区;无参输出编号列表(标「← 当前」),回复 /workspace <序号> 即切换;/workspace list 列出全部记录
/preset [id|序号]查看当前/可用预设(无参编号列表,回复序号即选),或切换 preset(重建会话,新会话 header 记录)
/session [序号]查看本会话可切回的历史会话(无参编号列表,每项含内容预览、建立时间与退休时间,id 截短显示;日志不可读的项显示「(内容不可读)」且不影响其余项),回复序号切回:当前会话退休进列表、目标会话恢复其历史上下文(含 per-chat 设置),支持来回切换;列表跨重启保留(switchable-sessions.json,每 chat 上限 20 条)
/status会话全景:chat/session/preset/model/cwd/出站模式/agent/可切回数 状态
/retry重跑上一条用户消息(上一轮出错后重试)
/id只看 chat/session/cwd(排查用)
/ver插件版本 + git commit
/ocr识别本会话最近一张入站图片(NapCat ocr_image)
/mode [interim|instant]切换本会话出站模式(per-chat 覆盖,跨重启持久化)
/plan [off|内容]宿主计划模式(/plan 进入;/plan off 直接退出,无 Web 审批卡;/plan <内容> 进入并处理该内容)
/permission [w|f|预设名|序号]切换宿主权限 preset(沙箱模式+审批策略,切换立即生效):w/ws/write/工作区→workspace-write(工作区内可写+需审批)、f/full/danger/全权→danger-full-access(全盘读写+免审批);完整预设名照原样转发(未知名由宿主报错并回显可用列表);无参渲染中文权限菜单(当前权限+可用预设编号列表+用法行,未知预设名标「部署自定义」;宿主回文格式变化时回退转发原文+快捷提示),纯数字序号按 available 顺序(现场解析,不落快照)
/goal [目标|clear]记录/更新本会话目标(每轮自动附带提醒,跨重启持久化)
/help分组命令卡片(▍会话/输出/查询/操作/其他),每条带参数用法;报错提示均附用法或下一步动作

/preset 切换为进程内 per-chat 覆盖(跨 /new 保留):下一条消息重建会话并以新 preset 写入 header,重启后 resume 按记录恢复;/mode、/goal 的 per-chat 状态已持久化进映射文件(v0.4.0 起,跨重启 保留),/workspace 的覆盖同样持久化;/plan 仍为进程内覆盖,重启回退到默认。 /session 的可切回列表按 chat 持久化在媒体目录的 switchable-sessions.json(读写纪律与 retired-sessions.json 一致:文件缺失=全新、损坏保留内存、原子写;每 chat 上限 20 条、去重、最新在前)。列表每项渲染一条内容预览 (该会话事件日志第一条真实用户输入:kind 'user' 或本插件署名的 QQ 消息优先,缺失时回退任何 user/message; 提取全部 text 块拼接、剥去 QQ 入站的 <user_message> 包裹与拼接在边界外的可信前缀([受限用户:仅问答] / [HH:MM 昵称(QQ)],包裹不完整或空正文则原样回退)后换行折叠、按码点截断 ≤40 字,emoji 不拆半;找不到用户输入显示「(无对话内容)」)、 建立时间(会话 header 的 createdAt,取不到则省略)、退休时间与截短 id(前 8+…+后 8 字符,保留两侧便于辨认)。 预览经 sessionPersistence 的 read handle 冷读日志前 24 个事件取得(不开写所有权,读完即 close);单会话日志 缺失/损坏/读取失败只降级该项为「(内容不可读)」,其余项与切回功能不受影响。切换成功后目标会话解除退休 标记,重启 resume 与空闲淘汰后的再激活都走常规路径找回它;切回目标 resume 失败时该 id 立即硬退休并移出列表, chat 回退到下一条消息新建会话,不会卡死。损坏(碰撞/恢复失败)退休的会话绝不进列表、不可切回。 序号选择基于命令输出列表的快照,5 分钟内有效(过期提示重新查看);纯数字参数仅在有对应有效列表时 按序号解释,否则维持原参数语义。例外:/permission 的纯数字序号不落快照,每次现场取宿主 available 列表解释(1/2),越界或不可解析时回退用法提示。未知斜杠命令默认拦截并提示相近命令,配置 unknownCommand: passthrough 可改为透传给模型。

安全编辑(code_safe_edit)

受守卫的宿主文件编辑由独立插件 dsh-safe-edit 提供(~/dsh-plugins/dsh-safe-edit/,2026-08-18 从本插件拆出,对所有通道全局注册)。三个工具: 思路借鉴 irmia_devkit_open 的 safe_edit(AGPL-3.0,独立 TypeScript 清洁实现)。工具与边界见 dsh-safe-edit 仓库/说明:

  • code_safe_edit:read → 路径白名单 → 自动备份 → 匹配(精确 → 剥行号前缀 → 空白对齐/Aider 式)→ 替换 → 语法检查(js/cjs/mjs 走 node --check)→ 失败自动回滚
  • code_safe_rollback / code_list_backups
  • 边界随会话 sandbox 策略:danger-full-access 无限制、workspace-write 限会话工作区、read-only 拒绝;无策略服务回落 safeEditRoot(默认 /Users/mario/workspace)
  • 模型可优先使用此工具(code-safe-edit skill 全渠道引导;QQ 平台提示词引导内置 read/edit 惯例,不绑定具体工具名)

dm / group 访问策略(初始化必选)

私聊(dmPolicy)与群聊(groupPolicy)各自三选一,选项含义如下:

选项dmPolicy(私聊)groupPolicy(群聊)
open仅管理员可私聊(adminUsers/ONEBOT_ALLOWED_USERS;设 allowAllUsers: true 则所有人可)所有群可聊(群内消息受 requireMention 控制:需 @ 或回复机器人的消息才触发;群成员带 [受限用户:仅问答] 软限制)
allowlist仅 allowFrom 白名单 QQ 可私聊(不要求是管理员)仅 groupAllowFrom 白名单群可聊
disabled私聊全部拒绝群聊全部拒绝

初始化建议:

  • 只想自己用 → dmPolicy: open + 配好 adminUsers(私聊只有你能发);
  • 想开放给几个熟人 → dmPolicy: allowlist + allowFrom: ['QQ1','QQ2'];
  • 群聊专用机器人 → groupPolicy: open(配合默认 requireMention: true,群成员需 @ 才触发);
  • 只允许特定群 → groupPolicy: allowlist + groupAllowFrom。

t2i 字体依赖

文字图卡片需要三类字体(CJK / 等宽 / 彩色 emoji),插件启动时从系统与固定路径自动注册, 缺失时对应字符渲染为豆腐块。

  • macOS:零安装——自动使用系统自带 Hiragino Sans GB / Songti SC、Menlo、Apple Color Emoji。

  • Linux(Debian/Ubuntu,一条命令补齐):

    sudo apt install fonts-noto-cjk fonts-dejavu-core fonts-noto-color-emoji
    
    依赖提供文件(插件自动注册路径)用途
    fonts-noto-cjk/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc中文正文/标题(ttc 自动提取 SC 面,回退 JP/Mono 面)
    fonts-dejavu-core/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf代码块/行内 code 等宽
    fonts-noto-color-emoji/usr/share/fonts/truetype/noto/NotoColorEmoji.ttf彩色 emoji
    可选 fonts-wqy-zenhei / fonts-wqy-microhei/usr/share/fonts/truetype/wqy/*.ttcCJK 备选(Noto 缺失时)
    可选 fonts-unifont/usr/share/fonts/opentype/unifont/*.otf最后兜底
  • 自定义:fontFiles 指定额外字体文件(重启生效);fontFamilies 指定优先使用的家族名。 渲染器带墨水自检——缺字体的家族会被自动剔除并回退,不会静默出豆腐块卡片。

权限与数据

  • 网络:与 OneBot 11 网关建立 WebSocket 连接(reverse 监听或 forward 拨出);入站图片/文件从 QQ CDN 下载。
  • 文件:入站媒体与会话映射写入 <dsh-home>/media/onebot/(mediaDir,6 小时过期清理);会话数据由 dsh 宿主持久化。
  • 系统调用:语音转写调用本机 ffmpeg 与 whisper CLI(可 sttEnabled: false 关闭)。
  • 敏感信息:accessToken 与管理员白名单存于 dsh 配置,不写入日志;出站内容经敏感信息审计。
  • 不收集:无遥测,除用户配置的 OneBot 网关与图片 CDN 外不调用任何第三方服务。

给模型的平台说明(自动注入)

  • QQ 不渲染 Markdown → 输出纯文本(编号/短横线列表、行内反引号)。
  • 发图/文件/语音/视频用 qq_send_* 工具;合并转发用 qq_send_forward。
  • 用户发来的图片/语音/视频在文本中标注为 [图片]/[语音]/[视频] 占位(路径不进入文本);无可用看图工具时如实告知用户。
  • 群聊消息带 [HH:MM 昵称(QQ)] 前缀;受限用户消息带 [受限用户:仅问答] 前缀(仅回答,禁止文件/终端/配置操作)。
  • 本通道为 QQ,宿主无 Web 交互卡:禁止调用 ask_user_question / exit_plan_mode(确认卡仅 Web 可用,会阻塞对话),提问/确认走纯文本;宿主计划模式下输出纯文本计划并提示「/plan off 退出」。
  • 斜杠命令由插件拦截(16 个,仅管理员,/help 查看);未知斜杠命令默认拦截并提示相近命令,配置 unknownCommand: passthrough 时透传给模型;非 /纯单词 开头的文本(如路径)仍正常交给模型。
  • 修改宿主文件走内置 read/edit(行级 hash 锚点、dsh-better-edit 自动 undo),勿用 write 整文件覆盖(清空 undo 历史)。

卸载

  1. 从 ~/.dsh/profiles/<profile>/cordis.patch.yml 删除 dsh-onebot 的 insert 条目;
  2. 重启 dsh,日志不再出现 [dsh-onebot] mounted 即卸载完成;
  3. 可选:删除插件目录与 <dsh-home>/media/onebot/ 残留媒体。

开发

./scripts/build.sh                 # 编译 src/ → lib/
./node_modules/.bin/vitest run     # 306 个测试:单元 + 真实 WS 对端 + 全管线

要点(来自移植源 DEVLOG 的教训):

  • CQ 反转义:NapCat 会把 URL 里的 & 转成 &amp;,下载前必须反转义(CDN 403 的根因)。
  • @ 检测 fail-closed:不知道机器人 QQ 时,群消息一律视为未 @,不自动回复。
  • 断线即失败 pending:WS 断开时立即 reject 所有未完成 action,避免 10-30s 干等与泄漏。
  • 重连去重:并发断线只允许一个重连任务,防止双 WS 连接。
  • int(target) 兜底:chat_id 解析进 try/catch,坏目标不能炸掉宿主。
  • 临时媒体 6h 过期清理:只写不删会无限堆积。
  • t2i 按码点迭代:JS 字符串索引会拆开 emoji 代理对(高代理位被分类成 CJK → 渲染成黑色字形),绘制/测量必须用 Array.from/for...of。
  • t2i 度量=绘制:换行/列宽统一走 segWidth(胶囊/粗体/斜体附加宽),像素级右缘验证 ≤790(非白判定 not(r>245&&g>245&&b>245))。

故障排查

症状原因与处理
群聊不响应requireMention: true 时需 @ 或回复机器人的消息才触发;@ 检测 fail-closed——确认 botQQ 已从 meta 事件学习,或显式配置
图片下载 403NapCat 会把 URL 中的 & 转成 &amp;(解析已自动反转义);仍失败可查日志中 media 下载行
文件接收失败非本机部署 NapCat 时需开启「文件转 URL」开关,否则 get_file 返回容器内路径不可达;确认 dsh 与 NapCat 网络互通
文字图中文豆腐块Linux 未装 CJK 字体:apt install fonts-noto-cjk,并用 fontFiles 指定 SC 字体文件
崩溃循环 / 工具注册冲突同一插件文件被 insert 两次(双实例)——检查 patch 无重复条目
语音一直只有 [语音] 占位、没有转写补递ffmpeg 或 whisper 不可用,或转写超时:安装后重启、调大 sttTimeoutMs,或 sttEnabled: false 关闭
插件挂载失败 / peer 依赖解析失败部署副本缺完整 node_modules 链接集:只复制 lib/ 不够,运行时 peer 依赖 @deepseek-ai/* 需经 scripts/link-host.sh 链接到宿主安装;插件入口会 fail-loud 显式报「peer 依赖解析失败」,按报错补齐链接集后重启
build.sh 报 cannot locate the dsh install宿主无 dsh 在 PATH(如 fnOS 应用形态)且未找到 npx store:设 DSH_ROOT=<宿主 node_modules 路径> 后重跑 ./scripts/build.sh(该目录下须有 @deepseek-ai/,设错路径会显式报错而非静默回退)
改了设置页 / patch 但不生效按顺序排查:① 确认改的是被监视的文件——profile 层 <DSH_HOME>/profiles/web/cordis.patch.yml 或 home 层 <DSH_HOME>/cordis.patch.yml(仓库 patch 模板、部署副本、bundle 自带 patch 均不被监视,需同步到上述文件);② 内容须真的变化(touch 同内容文件是 no-op);③ 看宿主日志有无激活失败——insert 新增条目激活失败(如 peer 缺失)会显式报错、条目失活,等待重启重试;④ 设置页的持久层是 profile 层 dsh-onebot 覆盖行,改到别处(如已被宿主废弃改名的 settings.yaml)不会生效
日志在哪dsh 宿主日志;插件历史根因与修复见 DEVLOG.md

开发记录

完整时间线/根因/修复见 DEVLOG.md(移植自 Hermes onebot 插件的 DEVLOG 惯例)。

License

BSD-3-Clause

allowFrom / groupAllowFrom[]白名单用户/群
interimMessagestrue工具调用之间的中间文本是否立即发送;false 只发最终回复
interimRecalltrue中间消息撤回与回合末小结卡开关;false = 只发不撤(降级:无小结卡、不撤回,中间消息留在屏幕上)
sendErrorNoticetrue一轮运行出错时向用户发送 ⚠️ 错误提示
sensitivePatterns[]出站敏感内容审计正则(内置 rm -rf/关机/删库/密钥 等模式;留空用内置默认)
sttEnabledtrue语音转写(需 ffmpeg + whisper CLI)
sttEngineautoSTT 引擎:auto(自动探测 whisper-cli/whisper/mlx_whisper)/openai/whisper-cpp/custom
sttModelsmallwhisper 模型
sttCommand空custom 引擎的程序名/路径
sttArgs[]custom 引擎参数模板,{file} 与 {out} 会被替换
sttTimeoutMs60000语音转写超时(毫秒;v0.4.0 起默认 60s,此前 300s):超时保留 [语音] 占位;<=0 回落内置 60s
textImageThreshold150t2i 卡片阈值:正文长度 ≤ 该值单条发送;> 该值渲染为文字图卡片。渲染失败、PNG 超 outboundImageMaxBytes 或 <=0 禁用卡片时回退单条纯文本
cardFooterdsh卡片页脚品牌("Powered by ")
fontFiles / fontFamilies[]t2i 字体文件/家族覆盖(Linux 部署必看:需安装 Noto CJK)
mediaDir<dsh-home>/media/onebot入站媒体/映射文件目录
tempTtlHours6入站临时媒体文件保留时长(小时),到期自动清理
inboundImageMaxPx2048入站图片长边上限(px):超过则等比压缩后交给视觉模型(透明 PNG 保留、GIF 不压);<=0 禁用(旧名 imageMaxSize deprecated,本版兼容读取)
outboundImageMaxBytes8388608出站图片大小上限(字节):t2i 小结卡等出站图片超限时自动回退纯文本(旧名 maxImageBytes deprecated,本版兼容读取)
maxVoiceBytes15728640出站语音大小上限(字节)
maxFileBytes20971520出站视频/文件大小上限(字节)
inboundFileMaxBytes20971520QQ 入站文件大小上限(字节):超限文件拒收并提示(旧名 maxInboundFileBytes deprecated,本版兼容读取)
allowPrivateHostsfalse下载媒体 URL 时允许私网/环回地址(仅跳过私网检查,协议白名单与限长仍生效);仅本机反代等可信场景开启,公网部署保持 false
agentPreset空会话挂载的 agent preset(留空=默认)
workspacePath空会话挂载的工作区(留空=宿主进程 cwd;未配置时插件启动会 warn 一次建议显式配置——宿主未提供可编程查询的默认工作区)。/workspace 的 per-chat 覆盖已持久化进映射文件,重启不丢
chatIdleEvictDays7会话空闲淘汰天数:chat 超过该天数无任何活动时,在下一条入站消息处理前清理其内存态 agent(会话先 flush 落盘、映射保留,同一 chat 之后再发消息可 resume 恢复原会话);0 = 禁用