npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

koishi-plugin-msg-router

v1.4.3

Published

Koishi OneBot 指令路由:支持手动/动态转译、权限与频率控制、双向 WebSocket 和 QQ Markdown

Downloads

627

Readme

koishi-plugin-msg-router

npm

一个面向 Koishi 的 OneBot v11 指令中转路由插件。插件仅接管配置中指定的指令,将会话转换为 OneBot v11 消息事件并通过 WebSocket 交给外部后端处理;未配置的指令保持 Koishi 原有处理流程,不受影响。

后端可以通过标准 OneBot API 动作向群聊或私聊回发文本、图片、语音等消息。针对 QQ 官方适配器,插件还支持原生 Markdown 文本和 Markdown 键盘,并在不支持 Markdown 的平台上自动降级为普通文本。

主要用途

  • 按需接管指令:每条路由独立配置指令列表,只转发明确指定的指令
  • 手动或动态转译:可以在配置页维护指令映射,也可以由后端通过接口动态声明
  • Koishi 指令控制:映射可配置权限、帮助菜单隐藏、调用频率、群聊/私聊范围和平台限制
  • OneBot v11 兼容:向后端推送标准消息事件,并处理常用 OneBot API 动作
  • 双向 WebSocket:支持插件主动连接后端,也支持插件监听并同时维持多个后端连接
  • 多路由配置:不同指令可以连接不同后端,分别设置地址、鉴权和连接参数
  • 消息类型转换:支持文本、图片、@、回复、语音、视频和表情等常用消息段
  • QQ Markdown:支持 QQ 原生 Markdown 文本,其他平台自动使用普通文本降级
  • 连接管理:提供令牌鉴权、心跳检测、断线重连、请求超时和调试日志

控制台配置说明

总开关

  • enableQQMarkdown:是否启用 QQ 原生 Markdown 文本;关闭后 Markdown 内容按普通文本降级发送
  • enableCommandDeclaration:是否允许后端通过 WebSocket 动态声明要接管的指令,默认关闭
  • enableCommandTranslation:是否允许把对外指令转译为不同的后端目标指令
  • commandDeclarationAction:动态声明接口的 action,默认 msg_router.declare_commands
  • maxDeclaredCommands:每条路由最多允许动态声明的指令数量,默认 100
  • allowDynamicCommandPermissions:是否允许后端自行声明权限规则,默认关闭
  • minimumDynamicAuthority:动态指令的最低权限等级,默认 1;后端不得声明更低的 authority 权限
  • debug:是否输出 WebSocket 收发、指令匹配和消息解析等调试信息

正向 WS 路由列表

这张表用于“插件主动连接后端”的场景。

  • name:路由名称
  • enabled:是否启用
  • mode:固定为 client
  • endpoint:OneBot v11 WebSocket 地址
  • token:后端鉴权令牌,可不填
  • secret:HMAC 签名密钥,可不填
  • commands:触发这条路由的 Koishi 指令
  • commandMappings:手动指令转译表,可设置对外指令、后端目标指令、说明和启用状态
  • action:发送给后端的 action 名称
  • timeout:单次请求等待时间,单位毫秒
  • heartbeatInterval:发送 ping 的间隔,单位毫秒
  • reconnectInterval:断线后的重连间隔,单位毫秒
  • maxConcurrency:同时允许的请求数量
  • maxConnections:仅 server 模式有效,同时允许接入的后端连接数量上限,默认 16

反向 WS 路由列表

这张表用于“插件监听,后端主动连进来”的场景。

  • name:路由名称
  • enabled:是否启用
  • mode:固定为 server
  • listenHost:监听主机
  • listenPort:监听端口
  • token:后端鉴权令牌,可不填
  • secret:HMAC 签名密钥,可不填
  • commands:触发这条路由的 Koishi 指令
  • commandMappings:手动指令转译表,可独立于 commands 使用
  • action:发送给后端的 action 名称
  • timeout:单次请求等待时间,单位毫秒
  • heartbeatInterval:发送 ping 的间隔,单位毫秒
  • reconnectInterval:断线后的重连间隔,单位毫秒
  • maxConcurrency:同时允许的请求数量
  • maxConnections:同时允许接入的后端连接数量上限,默认 16;每个指令事件会广播给全部已连接后端

推荐配置示例

{
  "debug": false,
  "clientRoutes": [
    {
      "name": "AI 后端",
      "enabled": true,
      "mode": "client",
      "endpoint": "ws://127.0.0.1:8080",
      "token": "",
      "secret": "",
      "commands": ["ask", "translate", "summarize"],
      "action": "msg_router.forward_command",
      "timeout": 10000,
      "heartbeatInterval": 30000,
      "reconnectInterval": 5000,
      "maxConcurrency": 16,
      "maxConnections": 16
    }
  ],
  "serverRoutes": [
    {
      "name": "反向后端",
      "enabled": true,
      "mode": "server",
      "listenHost": "127.0.0.1",
      "listenPort": 8080,
      "token": "",
      "secret": "",
      "commands": ["reply", "summarize"],
      "action": "msg_router.forward_command",
      "timeout": 10000,
      "heartbeatInterval": 30000,
      "reconnectInterval": 5000,
      "maxConcurrency": 16,
      "maxConnections": 16
    }
  ]
}

模式说明

  • client 模式:插件主动连接后端
  • server 模式:插件自己监听,等待后端连接
  • server 模式下可以同时连接多个后端;每个命令事件会广播给所有在线连接。若还没有任何后端连上来,命令会等待到超时为止

协议约定

插件向后端发送带 action / echo 外壳的请求,其中 params 使用 OneBot v11 的标准消息事件结构。当前只把文本内容封装为 message 段:

{
  "action": "msg_router.forward_command",
  "params": {
    "time": 1710000000,
    "self_id": 123456789,
    "post_type": "message",
    "message_type": "group",
    "sub_type": "normal",
    "message_id": 10001,
    "user_id": 123456,
    "group_id": 654321,
    "message": [
      {
        "type": "text",
        "data": {
          "text": "hello"
        }
      }
    ],
    "raw_message": "hello",
    "font": 0,
    "sender": {
      "user_id": 123456,
      "nickname": "Alice"
    }
  },
  "auth": {
    "algorithm": "hmac-sha256",
    "signature": "hex-string",
    "timestamp": 1710000000000
  },
  "echo": "uuid"
}

后端响应示例:

{
  "status": "ok",
  "retcode": 0,
  "data": {
    "text": "reply text"
  },
  "echo": "uuid"
}

如果 data.text、data.message 或 data.reply 存在,插件会直接把它返回给用户。data.message 支持 OneBot 风格的文本段数组。

手动配置指令转译

每条正向或反向路由都提供 commandMappings 表格,可以直接在 Koishi 配置页面添加映射:

| 配置项 | 说明 | 示例 | | --- | --- | --- | | enabled | 是否启用这条映射 | true | | source | 用户实际执行、插件需要接管的指令 | 天气 | | target | 转发给后端的目标指令 | weather | | description | Koishi 指令系统中显示的说明 | 查询天气 | | permissions | Koishi 权限规则 | ["authority:2"] | | hidden | 是否从帮助菜单隐藏 | false | | maxUsage | 每名用户每天最多调用次数,0 不限制 | 20 | | minInterval | 同一用户连续调用的最小间隔(毫秒),0 不限制 | 3000 | | scope | all、group 或 private | group | | platforms | 允许的平台;空数组不限制 | ["qq"] |

配置后,用户执行 天气 上海,后端会收到 weather 上海。映射可以独立使用,不需要再把 天气 重复填写到 commands;如果两处都填写,commandMappings 中的目标指令优先。单条映射可以使用 enabled 独立关闭。

全局关闭 enableCommandTranslation 后,手动映射和动态声明仍会注册源指令,但不再替换指令名。permissions 使用 Koishi 原生权限服务;hidden 需要 help 插件,maxUsage 和 minInterval 需要 rate-limit 插件及数据库服务才能生效。

动态声明与指令转译接口

开启配置项 enableCommandDeclaration 后,已连接的后端可以通过 WebSocket 调用声明接口。接口 action 默认为 msg_router.declare_commands,也可以通过 commandDeclarationAction 修改。

下面的声明会让插件接管用户侧的 天气 和 菜单 指令。其中,用户执行 天气 上海 时,后端收到的消息内容会转译为 weather 上海;插件只替换指令名,后续参数保持不变。

{
  "action": "msg_router.declare_commands",
  "params": {
    "replace": true,
    "commands": [
      {
        "name": "天气",
        "target": "weather",
        "description": "查询天气",
        "permissions": ["authority:2"],
        "hidden": false,
        "maxUsage": 20,
        "minInterval": 3000,
        "scope": "group",
        "platforms": ["qq"]
      },
      {
        "name": "菜单",
        "target": "help"
      }
    ]
  },
  "echo": "declare-1"
}

成功响应:

{
  "status": "ok",
  "retcode": 0,
  "data": {
    "declared": [
      { "name": "天气", "target": "weather" },
      { "name": "菜单", "target": "help" }
    ],
    "removed": [],
    "rejected": []
  },
  "echo": "declare-1"
}

接口规则:

  • commands 可以是上述数组,也可以简写成 { "天气": "weather", "菜单": "help" }
  • 字符串声明(例如 "ping")表示不转译,源指令和目标指令相同
  • replace 默认为 true,会移除该路由之前动态声明、但本次未再次声明的指令
  • replace: false 表示增量更新;单项设置 enabled: false 可以移除动态指令
  • 动态声明支持与手动映射相同的 permissions、hidden、maxUsage、minInterval、scope 和 platforms
  • 默认不允许后端决定权限,动态指令统一采用 minimumDynamicAuthority;只有显式开启 allowDynamicCommandPermissions 后才读取后端提交的 permissions
  • 即使允许动态权限,低于 minimumDynamicAuthority 的 authority 规则仍会被拒绝;只声明自定义权限时,插件也会自动附加最低 authority 规则
  • 关闭 enableCommandTranslation 后仍允许动态声明,但会忽略 target,按原指令转发
  • 插件不会覆盖其他 Koishi 插件已经注册的指令,冲突项会出现在 rejected 中
  • 只配置动态声明、不填写静态 commands 的路由也会启动并等待后端声明

QQ Markdown 与键盘

后端通过 send_group_msg、send_private_msg 或 send_msg 回发消息时,可以使用 QQ 原生 Markdown 文本。插件在 QQ 官方适配器上会直接提交 markdown.content,并透传 keyboard;在其他平台上会把同一内容作为普通文本降级发送。

此功能可通过配置页面的 enableQQMarkdown 开关控制。关闭后不会调用 QQ 原生 Markdown 接口,而是把 content 或 fallback_text 作为普通消息发送。

{
  "action": "send_group_msg",
  "params": {
    "group_id": "群 openid",
    "message": [
      {
        "type": "markdown",
        "data": {
          "content": "# 标题\n**加粗内容**\n[查看详情](https://example.com)",
          "fallback_text": "标题\n加粗内容\nhttps://example.com",
          "keyboard": {
            "content": {
              "rows": []
            }
          }
        }
      }
    ]
  },
  "echo": "request-id"
}

如果后端本身直接使用 QQ 消息结构,也可以省略 message,直接在 params.markdown.content 中提供内容。fallback_text 可选;未提供时会直接使用 content 作为降级文本。

兼容说明

  • token 是可选项,不填时不会附加 Authorization 头
  • secret 也是可选项,不填时不会生成 auth
  • 如果后端没有返回可显示内容,插件会保持静默
  • 请求超时只会记录警告,不会把命令直接抛成错误
  • 同名指令不建议在多个路由里重复配置