From ecc75ee3260ddf8398bc3327d6982d58ed480010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=AC=E6=98=8E?= <83812544+Ed1s0nZ@users.noreply.github.com> Date: Mon, 6 Jul 2026 13:55:51 +0800 Subject: [PATCH] Add files via upload --- docs/robot.md | 246 ++++++++++++++++++++++++++++++++++--- docs/robot_en.md | 219 ++++++++++++++++++++++++++++++--- go.mod | 14 ++- go.sum | 117 +++++++++++++++++- web/static/i18n/en-US.json | 34 +++++ web/static/i18n/zh-CN.json | 34 +++++ web/static/js/settings.js | 77 +++++++++++- web/templates/index.html | 165 +++++++++++++++++++++++++ 8 files changed, 870 insertions(+), 36 deletions(-) diff --git a/docs/robot.md b/docs/robot.md index 0d2333f9..0ce35959 100644 --- a/docs/robot.md +++ b/docs/robot.md @@ -2,7 +2,7 @@ [English](robot_en.md) -本文档说明如何通过**钉钉**、**飞书**与 **企业微信** 与 CyberStrikeAI 对话(长连接 / 回调模式),在手机端即可使用,无需在服务器上打开网页。按下面步骤操作可避免常见弯路。 +本文档说明如何通过**个人微信**、**钉钉**、**飞书**与 **企业微信** 与 CyberStrikeAI 对话(长连接 / 回调模式),在手机端即可使用,无需在服务器上打开网页。按下面步骤操作可避免常见弯路。 --- @@ -11,11 +11,14 @@ 1. 登录 CyberStrikeAI Web 端 2. 左侧导航进入 **系统设置** 3. 在左侧设置分类中点击 **机器人设置**(位于「基本设置」与「安全设置」之间) -4. 按平台勾选并填写(钉钉填 Client ID / Client Secret,飞书填 App ID / App Secret) -5. 点击 **应用配置** 保存 -6. **重启 CyberStrikeAI 应用**(只保存不重启,机器人不会连上) +4. 按平台配置: + - **个人微信**:点击「微信 / iLink」→「生成二维码并绑定」,用微信扫码确认(见 [3.4 个人微信](#34-个人微信-wechat--ilink)) + - **钉钉**:勾选并填写 Client ID / Client Secret + - **飞书**:勾选并填写 App ID / App Secret +5. 点击 **应用配置** 保存(微信扫码绑定成功后会**自动保存并启用**,一般无需再点) +6. **重启 CyberStrikeAI 应用**(钉钉/飞书:只保存不重启,长连接不会建立;微信绑定成功后会自动重启连接,通常无需手动重启) -配置会写入 `config.yaml` 的 `robots` 段,也可在配置文件中直接编辑。**修改钉钉/飞书配置后必须重启,长连接才会生效。** +配置会写入 `config.yaml` 的 `robots` 段,也可在配置文件中直接编辑。**修改钉钉/飞书配置后必须重启,长连接才会生效。** 个人微信绑定成功后程序会自动写入 `robots.wechat` 并重启 iLink 长轮询。 --- @@ -23,9 +26,14 @@ | 平台 | 说明 | |----------|------| +| 个人微信 | 使用微信 iLink 协议,Web 端扫码绑定后长轮询收消息,**无需公网回调** | | 钉钉 | 使用 Stream 长连接,程序主动连接钉钉接收消息 | | 飞书 | 使用长连接,程序主动连接飞书接收消息 | | 企业微信 | 使用 HTTP 回调接收消息,被动回包 + 主动调用企业微信发送消息 API | +| Telegram | Bot API 长轮询(getUpdates),**无需公网回调** | +| Slack | Socket Mode(出站 WebSocket),**无需公网回调** | +| Discord | Gateway WebSocket,**无需公网回调** | +| QQ 机器人 | QQ 开放平台 WebSocket(C2C / 群 @),**无需公网回调** | 下面第三节会按平台写清:在开放平台要做什么、要复制哪些字段、填到 CyberStrikeAI 的哪一栏。 @@ -151,9 +159,150 @@ --- +### 3.4 个人微信 (WeChat / iLink) + +> 个人微信采用「Web 扫码绑定 + iLink 长轮询」方式工作: +> - 在 CyberStrikeAI Web 端生成二维码 → 用**手机微信**扫码并确认绑定; +> - 绑定成功后自动写入 `config.yaml` 的 `robots.wechat`,并启动 iLink 长轮询(程序主动连接 `ilinkai.weixin.qq.com` 收消息); +> - **无需**在服务器上配置公网回调 URL,也**无需**去微信开放平台注册应用。 + +**与企业微信的区别** + +| 项目 | 个人微信 (iLink) | 企业微信 (WeCom) | +|------|------------------|------------------| +| 使用场景 | 个人微信私聊 | 企业微信自建应用 | +| 配置方式 | Web 端扫码绑定 | 管理后台配置回调 URL + Token | +| 是否需要公网 | 否(长轮询出站即可) | 是(需可被企业微信访问的 HTTPS 回调) | +| 配置段 | `robots.wechat` | `robots.wecom` | + +**绑定步骤(按顺序做)** + +1. **登录 CyberStrikeAI Web 端** + 左侧 **系统设置** → **机器人设置** → 点击 **微信 / iLink** 卡片。 + +2. **(可选)勾选「启用微信机器人」** + 首次绑定可跳过;绑定成功后会自动勾选并启用。 + +3. **生成二维码** + 点击 **「生成二维码并绑定」**。页面会显示二维码(约 **5 分钟**有效;过期请重新生成)。 + +4. **微信扫码确认** + - 用手机微信扫描页面二维码; + - 按手机提示完成确认; + - 若手机微信弹出**配对数字**,在 Web 页面对应输入框填写并点击 **提交**(仅部分账号需要)。 + +5. **等待绑定完成** + 页面显示「绑定成功,微信机器人已启用」即完成。`bot_token`、`ilink_bot_id` 等会自动写入 `config.yaml`,程序会自动重启 iLink 长轮询,**一般无需手动重启服务**。 + +6. **在手机微信里测试** + 打开与 CyberStrikeAI 机器人的**私聊**(绑定后微信内会出现对应会话),发送「帮助」或任意文字测试。 + +**CyberStrikeAI 微信栏位说明** + +| 栏位 | 说明 | +|------|------| +| 启用微信机器人 | 勾选后启动 iLink 长轮询;绑定成功后会自动勾选 | +| 生成二维码并绑定 | 发起扫码绑定流程 | +| **高级设置**(一般保持默认即可) | | +| API Base URL | 默认 `https://ilinkai.weixin.qq.com` | +| Bot Type | 默认 `3` | +| Bot Agent | 默认 `CyberStrikeAI/1.0` | +| iLink Bot ID | 绑定成功后自动填充,只读 | + +**使用方式** + +- 仅支持在与机器人的**私聊**中对话,直接发送文字即可,**不需要 @**。 +- 不支持群聊 @ 机器人(与钉钉/飞书群聊不同)。 +- 仅处理**文本消息**;图片、语音等会忽略或提示暂不支持。 + +**重新绑定** + +- 若需更换绑定的微信账号,在机器人设置页点击 **「重新绑定」**,再次扫码即可。 +- 若提示「该微信已绑定过,无需重复绑定」,说明该账号此前已完成绑定。 + +**常见问题** + +| 现象 | 处理 | +|------|------| +| 二维码过期 | 重新点击「生成二维码并绑定」(有效期约 5 分钟) | +| 扫码后要求输入数字 | 查看手机微信显示的配对数字,在 Web 页面输入并提交 | +| 绑定成功但发消息无回复 | 看程序日志是否有 `微信 iLink 长轮询已启动`、`微信收到消息`;确认已勾选「启用微信机器人」 | +| 断网或睡眠后无回复 | 程序会自动重连(约 5~60 秒);仍无回复可重启 CyberStrikeAI | +| 无法生成二维码 | 确认服务器能访问 `https://ilinkai.weixin.qq.com`(出站 HTTPS) | + +--- + +### 3.5 Telegram + +> Telegram 使用 **Bot API 长轮询**(`getUpdates`):程序主动连接 `api.telegram.org` 收消息,**无需公网回调**。 + +**配置步骤:** + +1. 在 Telegram 中找 **@BotFather**,发送 `/newbot` 创建机器人,获得 **Bot Token**。 +2. CyberStrikeAI → **系统设置** → **机器人设置** → **Telegram**。 +3. 勾选「启用 Telegram 机器人」,粘贴 **Bot Token**。 +4. (可选)填写 Bot Username(不含 `@`),或留空由程序自动 `getMe`。 +5. (可选)勾选「允许群聊」— 群聊中仅响应 **@机器人** 的消息。 +6. 点击 **应用配置**(会自动重启长轮询连接)。 + +**使用:** 与机器人私聊直接发消息;群聊需 @ 机器人(且已勾选允许群聊)。 + +--- + +### 3.6 Slack + +> Slack 使用 **Socket Mode**(出站 WebSocket):需 **Bot Token** 与 **App-Level Token**,**无需公网回调**。 + +**配置步骤:** + +1. 在 [Slack API](https://api.slack.com/apps) 创建 App → 启用 **Socket Mode**。 +2. **Basic Information** → **App-Level Tokens** → 创建 token(scope: `connections:write`),即 **xapp-** 开头。 +3. **OAuth & Permissions** → 添加 Bot Token Scopes:`app_mentions:read`、`chat:write`、`im:history`、`im:read` 等 → 安装到工作区,获得 **xoxb-** Bot Token。 +4. **Event Subscriptions** → 订阅 `message.im`、`app_mention` 等(Socket Mode 下在应用内配置)。 +5. 在 CyberStrikeAI 填入 Bot Token 与 App-Level Token → **应用配置**。 + +**使用:** 与 Bot 私聊直接发;频道中需 @ 机器人。 + +--- + +### 3.7 Discord + +> Discord 使用 **Gateway WebSocket**:程序主动连接 Discord Gateway,**无需公网回调**。 + +**配置步骤:** + +1. 在 [Discord Developer Portal](https://discord.com/developers/applications) 创建应用 → **Bot** → 复制 **Token**。 +2. 开启 **Privileged Gateway Intents** 中的 **Message Content Intent**(否则读不到消息正文)。 +3. OAuth2 → URL Generator → scopes: `bot` → 权限勾选 **Send Messages**、**Read Message History** 等 → 邀请 Bot 到服务器。 +4. CyberStrikeAI → **机器人设置** → **Discord** → 填入 Token → **应用配置**。 +5. (可选)勾选「允许服务器频道」— 频道中仅响应 **@机器人**。 + +**使用:** 与 Bot 私聊直接发;服务器频道需 @ 机器人(且已勾选允许服务器频道)。 + +--- + +### 3.8 QQ 机器人 + +> QQ 机器人使用 **QQ 开放平台 WebSocket**(官方 `botgo` SDK):支持 C2C 私聊与群 @,**无需公网回调**(WebSocket 出站连接)。 + +**配置步骤:** + +1. 在 [QQ 机器人开放平台](https://q.qq.com) 创建机器人,获取 **App ID** 与 **Client Secret**。 +2. 在沙箱中添加测试成员(上线前仅沙箱可对话)。 +3. 订阅 **C2C 消息**、**群 @ 消息** 等事件(WebSocket 模式)。 +4. CyberStrikeAI → **机器人设置** → **QQ 机器人** → 填入 App ID、Client Secret。 +5. 测试阶段勾选 **沙箱环境**;正式上线后取消沙箱并发布。 +6. 点击 **应用配置**。 + +**使用:** 与机器人 C2C 私聊直接发;QQ 群中需 @ 机器人。 + +> 注意:QQ 官方正逐步推广 Webhook 回调;当前实现使用 WebSocket(与钉钉/飞书类似的长连接模式)。若配置变更后连接未刷新,可重启 CyberStrikeAI 进程。 + +--- + ## 四、机器人命令 -在钉钉/飞书中向机器人发送以下**文本命令**(仅支持文本): +在任一已接入平台(钉钉/飞书/微信/Telegram/Slack/Discord/QQ 等)向机器人发送以下**文本命令**(仅支持文本): | 命令 | 说明 | |------|------| @@ -175,16 +324,25 @@ ## 五、如何使用(要 @ 机器人吗?) -- **单聊(推荐)**:在钉钉/飞书里**搜索并打开该机器人**,进入与机器人的**私聊**,直接输入「帮助」或任意文字即可,**不需要 @**。 -- **群聊**:若机器人被添加到群里,在群内只有 **@机器人** 后发送的消息才会被机器人收到并回复;不 @ 的群消息不会触发机器人。 +- **个人微信**:在与 CyberStrikeAI 机器人的**私聊**中直接发送即可,**不需要 @**(不支持群聊)。 +- **钉钉 / 飞书单聊(推荐)**:**搜索并打开该机器人**,进入**私聊**,直接输入「帮助」或任意文字即可,**不需要 @**。 +- **钉钉 / 飞书群聊**:若机器人被添加到群里,在群内只有 **@机器人** 后发送的消息才会被机器人收到并回复;不 @ 的群消息不会触发机器人。 -总结:和机器人**单聊时直接发**;在**群里用时需要 @机器人** 再发内容。 +总结:**个人微信、单聊时直接发**;**钉钉/飞书在群里用时需要 @机器人** 再发内容。 --- ## 六、推荐使用流程(避免漏步骤) -1. **在开放平台**:按第三节完成钉钉或飞书应用创建、凭证复制、机器人开通(钉钉务必选 **Stream 模式**)、权限与发布。 +**个人微信(最简单,无需开放平台)** + +1. CyberStrikeAI Web 端 → 系统设置 → 机器人设置 → **微信 / iLink** → **生成二维码并绑定**。 +2. 手机微信扫码确认(如需配对数字则在 Web 页填写)。 +3. 绑定成功后,在手机微信私聊中发「帮助」测试。 + +**钉钉 / 飞书** + +1. **在开放平台**:按第三节完成应用创建、凭证复制、机器人开通(钉钉务必选 **Stream 模式**)、权限与发布。 2. **在 CyberStrikeAI**:系统设置 → 机器人设置 → 勾选对应平台,粘贴 Client ID/App ID、Client Secret/App Secret → 点击 **应用配置**。 3. **重启 CyberStrikeAI 进程**(否则长连接不会建立)。 4. **在手机钉钉/飞书**:找到该机器人(单聊直接发,群聊需 @机器人),发「帮助」或任意内容测试。 @@ -199,6 +357,14 @@ ```yaml robots: + wechat: # 个人微信 iLink(扫码绑定后自动写入,一般无需手填) + enabled: true + bot_token: "your_bot_token@im.bot:..." + ilink_bot_id: "your_bot_id@im.bot" + ilink_user_id: "your_user_id@im.wechat" + base_url: "https://ilinkai.weixin.qq.com" + bot_type: "3" + bot_agent: "CyberStrikeAI/1.0" dingtalk: enabled: true client_id: "your_dingtalk_app_key" @@ -208,9 +374,33 @@ robots: app_id: "your_lark_app_id" app_secret: "your_lark_app_secret" verify_token: "" + wecom: + enabled: false + corp_id: "" + agent_id: 0 + token: "" + encoding_aes_key: "" + secret: "" + telegram: + enabled: false + bot_token: "" + allow_group_messages: false + slack: + enabled: false + bot_token: "" + app_token: "" + discord: + enabled: false + bot_token: "" + allow_guild_messages: false + qq: + enabled: false + app_id: "" + client_secret: "" + sandbox: true ``` -修改后需**重启应用**,长连接在应用启动时建立。 +修改钉钉/飞书/企业微信/Telegram/Slack/Discord/QQ 配置后,点击 **应用配置** 会自动重启对应长连接。个人微信扫码绑定成功后会自动写入并重启 iLink 连接。 --- @@ -235,7 +425,30 @@ curl -X POST "http://localhost:8080/api/robot/test" \ --- -## 九、钉钉发消息没反应时排查 +## 九、发消息没反应时排查 + +### 9.1 个人微信 + +按顺序检查: + +1. **是否已完成扫码绑定** + 机器人设置页应显示「已连接」或已绑定 Bot ID;`config.yaml` 中 `robots.wechat.bot_token` 不应为空。 + +2. **是否已启用** + 确认「启用微信机器人」已勾选;若刚修改过,可重启 CyberStrikeAI 进程。 + +3. **看程序日志** + - 启动后应看到:`微信 iLink 长轮询已启动`; + - 发消息后应有:`微信收到消息`;若没有,多为未绑定成功或 `bot_token` 失效,可尝试 **重新绑定**。 + - 若出现 `微信 iLink 长轮询异常,将自动重连`,等待自动重连或重启进程。 + +4. **网络** + 服务器需能访问 `https://ilinkai.weixin.qq.com`(出站 HTTPS)。绑定阶段若无法生成二维码,优先检查此项。 + +5. **断网或睡眠后** + 与钉钉/飞书类似,程序会**自动重连**(约 5~60 秒);仍无回复可重启 CyberStrikeAI。 + +### 9.2 钉钉 按顺序检查: @@ -260,8 +473,10 @@ curl -X POST "http://localhost:8080/api/robot/test" \ ## 十、常见弯路(避免踩坑) +- **个人微信与企业微信混淆**:个人微信走 `robots.wechat` + Web 扫码绑定;企业微信走 `robots.wecom` + 管理后台回调 URL,二者完全不同。 +- **个人微信二维码过期**:二维码约 5 分钟有效,过期需重新生成,不要一直扫旧码。 - **用错了机器人类型**:在钉钉**群里**添加的「自定义」机器人(Webhook + 加签)**不能**用来做对话,本程序只支持**开放平台「企业内部应用」**里的机器人。 -- **只保存没重启**:在 CyberStrikeAI 里改完机器人配置后必须**重启应用**,否则长连接不会建立。 +- **只保存没重启**:钉钉/飞书改完配置后必须**重启应用**,否则长连接不会建立(个人微信扫码绑定会自动重启连接)。 - **Client ID 抄错**:开放平台是 `504` 就填 `504`,不要填成 `5o4`;尽量用复制粘贴。 - **钉钉只开了 HTTP 回调没开 Stream**:本程序通过 **Stream 长连接**收消息,开放平台里机器人的消息接收方式必须选 **Stream 模式**。 - **应用没发布**:开放平台里修改了机器人或权限后,要在「版本管理与发布」里**发布新版本**,否则不生效。 @@ -270,6 +485,7 @@ curl -X POST "http://localhost:8080/api/robot/test" \ ## 十一、注意事项 -- 钉钉、飞书均**仅处理文本消息**;其他类型(如图片、语音)会提示暂不支持或忽略。 +- 各平台均**仅处理文本消息**;其他类型(如图片、语音)会提示暂不支持或忽略。 +- 个人微信仅支持**私聊**,不支持群聊 @ 机器人。 - 会话与 Web 端共用同一套对话数据:在机器人里创建的对话会在 Web 端「对话」列表中看到,反之亦然。 -- 机器人执行与 **Eino 单/多代理** 相同逻辑(`ProcessMessageForRobot`,含进度回调与过程详情入库),仅不向客户端推送 SSE,最后一次性回复钉钉/飞书/企业微信。默认 `robot_default_agent_mode: eino_single`。 +- 机器人执行与 **Eino 单/多代理** 相同逻辑(`ProcessMessageForRobot`,含进度回调与过程详情入库),仅不向客户端推送 SSE,最后一次性回复个人微信/钉钉/飞书/企业微信。默认 `robot_default_agent_mode: eino_single`。 diff --git a/docs/robot_en.md b/docs/robot_en.md index 6b2d55d1..8284f896 100644 --- a/docs/robot_en.md +++ b/docs/robot_en.md @@ -2,7 +2,7 @@ [中文](robot.md) -This document explains how to chat with CyberStrikeAI from **DingTalk**, **Lark (Feishu)**, and **WeCom (Enterprise WeChat)** using long-lived connections or HTTP callbacks—no need to open a browser on the server. Following the steps below helps avoid common mistakes. +This document explains how to chat with CyberStrikeAI from **personal WeChat**, **DingTalk**, **Lark (Feishu)**, and **WeCom (Enterprise WeChat)** using long-lived connections or HTTP callbacks—no need to open a browser on the server. Following the steps below helps avoid common mistakes. --- @@ -11,11 +11,14 @@ This document explains how to chat with CyberStrikeAI from **DingTalk**, **Lark 1. Log in to the CyberStrikeAI web UI. 2. Open **System Settings** in the left sidebar. 3. Click **Robot settings** (between “Basic” and “Security”). -4. Enable the platform and fill in credentials (DingTalk: Client ID / Client Secret; Lark: App ID / App Secret). -5. Click **Apply configuration** to save. -6. **Restart the CyberStrikeAI process** (saving alone does not establish the connection). +4. Configure per platform: + - **Personal WeChat**: Open **WeChat / iLink** → **Generate QR code and bind**, then scan with WeChat (see [Section 3.4](#34-personal-wechat-wechat--ilink)) + - **DingTalk**: Enable and fill in Client ID / Client Secret + - **Lark**: Enable and fill in App ID / App Secret +5. Click **Apply configuration** to save (WeChat binding saves and enables automatically on success—usually no extra click needed) +6. **Restart the CyberStrikeAI process** (DingTalk/Lark: saving alone does not establish the connection; WeChat auto-restarts the iLink poll after binding—usually no manual restart needed) -Settings are written to the `robots` section of `config.yaml`; you can also edit the file directly. **After changing DingTalk or Lark config, you must restart for the long-lived connection to take effect.** +Settings are written to the `robots` section of `config.yaml`; you can also edit the file directly. **After changing DingTalk or Lark config, you must restart for the long-lived connection to take effect.** Personal WeChat binding automatically writes `robots.wechat` and restarts the iLink long poll. --- @@ -23,9 +26,14 @@ Settings are written to the `robots` section of `config.yaml`; you can also edit | Platform | Description | |----------------|-------------| +| Personal WeChat| WeChat iLink protocol; scan QR in the web UI to bind, then long-poll for messages—**no public callback URL needed** | | DingTalk | Stream long-lived connection; the app connects to DingTalk to receive messages | | Lark (Feishu) | Long-lived connection; the app connects to Lark to receive messages | | WeCom (Qiye WX)| HTTP callback to receive messages; CyberStrikeAI replies via WeCom’s message sending API | +| Telegram | Bot API long polling (`getUpdates`); **no public callback URL needed** | +| Slack | Socket Mode (outbound WebSocket); **no public callback URL needed** | +| Discord | Gateway WebSocket; **no public callback URL needed** | +| QQ Bot | QQ Open Platform WebSocket (C2C / group @); **no public callback URL needed** | Section 3 below describes, per platform, what to do in the developer console and which fields to copy into CyberStrikeAI. @@ -148,9 +156,125 @@ In **Permission management** (权限管理), enable the following (names and ide --- +### 3.4 Personal WeChat (WeChat / iLink) + +> Personal WeChat uses **“web QR binding + iLink long polling”**: +> - Generate a QR code in the CyberStrikeAI web UI → scan and confirm with **WeChat on your phone**; +> - On success, `robots.wechat` in `config.yaml` is updated automatically and iLink long polling starts (the app connects outbound to `ilinkai.weixin.qq.com`); +> - **No** public callback URL on your server and **no** WeChat Open Platform app registration required. + +**Personal WeChat vs WeCom** + +| Item | Personal WeChat (iLink) | WeCom (Enterprise WeChat) | +|------|-------------------------|---------------------------| +| Use case | Private chat in personal WeChat | Custom app in WeCom | +| Setup | QR scan in web UI | Admin console callback URL + Token | +| Public IP needed? | No (outbound long poll only) | Yes (HTTPS callback reachable by WeCom) | +| Config key | `robots.wechat` | `robots.wecom` | + +**Binding steps (in order)** + +1. **Log in to CyberStrikeAI web UI** + **System settings** → **Robot settings** → click the **WeChat / iLink** card. + +2. **(Optional) Enable “Enable WeChat robot”** + You can skip this on first bind; it is checked automatically after a successful bind. + +3. **Generate QR code** + Click **“Generate QR code and bind”**. The QR code is valid for about **5 minutes**; regenerate if it expires. + +4. **Scan and confirm in WeChat** + - Scan the QR code with WeChat on your phone; + - Complete confirmation on the phone; + - If WeChat shows a **pairing code**, enter it on the web page and click **Submit** (only some accounts need this). + +5. **Wait for binding to complete** + When the page shows “Binding successful, WeChat robot enabled”, you’re done. `bot_token`, `ilink_bot_id`, etc. are saved to `config.yaml` and the iLink poll restarts automatically—**usually no manual service restart**. + +6. **Test in WeChat** + Open the **private chat** with the CyberStrikeAI bot in WeChat and send “帮助” (help) or any text. + +**Field reference (WeChat)** + +| Field | Description | +|-------|-------------| +| Enable WeChat robot | Starts iLink long polling when checked; auto-enabled after bind | +| Generate QR code and bind | Starts the scan-to-bind flow | +| **Advanced** (defaults are fine) | | +| API Base URL | Default `https://ilinkai.weixin.qq.com` | +| Bot Type | Default `3` | +| Bot Agent | Default `CyberStrikeAI/1.0` | +| iLink Bot ID | Filled automatically after bind (read-only) | + +**How to use** + +- **Private chat only**—send text directly; **no @ needed**. +- Group @-bot is **not** supported (unlike DingTalk/Lark groups). +- **Text messages only**; images, voice, etc. are ignored or not supported. + +**Re-bind** + +- To bind a different WeChat account, click **“Re-bind”** on the robot settings page and scan again. +- If you see “This WeChat account is already bound”, that account was bound before. + +**Common issues** + +| Symptom | What to do | +|---------|------------| +| QR code expired | Click “Generate QR code and bind” again (~5 min TTL) | +| Phone asks for a pairing code | Enter the digits shown in WeChat on the web page | +| Bound but no replies | Check logs for `微信 iLink 长轮询已启动` and `微信收到消息`; ensure “Enable WeChat robot” is on | +| No reply after sleep / network drop | Auto-reconnect in ~5–60 s; restart CyberStrikeAI if still stuck | +| Cannot generate QR code | Ensure outbound HTTPS to `https://ilinkai.weixin.qq.com` | + +--- + +### 3.5 Telegram + +> Telegram uses **Bot API long polling** (`getUpdates`): the app connects outbound to `api.telegram.org`—**no public callback URL needed**. + +1. Create a bot via **@BotFather** (`/newbot`) and copy the **Bot Token**. +2. CyberStrikeAI → **System settings** → **Robot settings** → **Telegram**. +3. Enable, paste the token, optionally allow group @ mentions → **Apply configuration**. + +--- + +### 3.6 Slack + +> Slack uses **Socket Mode** (outbound WebSocket): requires **Bot Token (xoxb-)** and **App-Level Token (xapp-)** with `connections:write`. + +1. Create an app at [api.slack.com](https://api.slack.com/apps) → enable **Socket Mode**. +2. Create an App-Level Token; install the app to get a Bot Token. +3. Subscribe to `message.im` and `app_mention` events. +4. Paste both tokens in CyberStrikeAI → **Apply configuration**. + +--- + +### 3.7 Discord + +> Discord uses **Gateway WebSocket**—**no public callback URL needed**. + +1. [Discord Developer Portal](https://discord.com/developers/applications) → create app → **Bot** → copy **Token**. +2. Enable **Message Content Intent** under Privileged Gateway Intents. +3. Invite the bot with `Send Messages` permission. +4. Paste token in CyberStrikeAI; optionally allow guild @ mentions → **Apply configuration**. + +--- + +### 3.8 QQ Bot + +> QQ Bot uses **QQ Open Platform WebSocket** (official `botgo` SDK) for C2C and group @—**no public callback URL needed**. + +1. Create a bot at [q.qq.com](https://q.qq.com) → get **App ID** and **Client Secret**. +2. Add sandbox testers before going live. +3. Subscribe to C2C and group @ events (WebSocket). +4. Fill in CyberStrikeAI; use **Sandbox** for testing → **Apply configuration**. + +--- + ## 4. Bot commands -Send these **text commands** to the bot in DingTalk or Lark (text only): +Send these **text commands** to the bot on any connected platform (text only): | Command | Description | |---------|-------------| @@ -172,15 +296,24 @@ Any other text is sent to the AI as a user message, same as in the web UI (e.g. ## 5. How to use (do I need to @ the bot?) -- **Direct chat (recommended)**: In DingTalk or Lark, **search for the bot and open a direct chat**. Type “帮助” or any message; **no @ needed**. -- **Group chat**: If the bot is in a group, only messages that **@ the bot** are received and answered; other group messages are ignored. +- **Personal WeChat**: Send directly in the **private chat** with the bot; **no @ needed** (group chat not supported). +- **DingTalk / Lark direct chat (recommended)**: **Search for the bot and open a direct chat**. Type “帮助” or any message; **no @ needed**. +- **DingTalk / Lark group chat**: If the bot is in a group, only messages that **@ the bot** are received and answered; other group messages are ignored. -Summary: **Direct chat** — just send; **in a group** — @ the bot first, then send. +Summary: **Personal WeChat and direct chat**—just send; **DingTalk/Lark in a group**—@ the bot first, then send. --- ## 6. Recommended flow (so you don’t skip steps) +**Personal WeChat (simplest—no open platform)** + +1. CyberStrikeAI web UI → System settings → Robot settings → **WeChat / iLink** → **Generate QR code and bind**. +2. Scan with WeChat and confirm (enter pairing code on the web page if prompted). +3. After binding, send “帮助” in the WeChat private chat to test. + +**DingTalk / Lark** + 1. **In the open platform**: Complete app creation, copy credentials, enable the bot (DingTalk: **Stream mode**), set permissions, and publish (Section 3). 2. **In CyberStrikeAI**: System settings → Robot settings → Enable the platform, paste Client ID/App ID and Client Secret/App Secret → **Apply configuration**. 3. **Restart the CyberStrikeAI process** (otherwise the long-lived connection is not established). @@ -196,6 +329,14 @@ Example `robots` section in `config.yaml`: ```yaml robots: + wechat: # Personal WeChat iLink (auto-filled after QR bind; usually no manual edit) + enabled: true + bot_token: "your_bot_token@im.bot:..." + ilink_bot_id: "your_bot_id@im.bot" + ilink_user_id: "your_user_id@im.wechat" + base_url: "https://ilinkai.weixin.qq.com" + bot_type: "3" + bot_agent: "CyberStrikeAI/1.0" dingtalk: enabled: true client_id: "your_dingtalk_app_key" @@ -205,9 +346,33 @@ robots: app_id: "your_lark_app_id" app_secret: "your_lark_app_secret" verify_token: "" + wecom: + enabled: false + corp_id: "" + agent_id: 0 + token: "" + encoding_aes_key: "" + secret: "" + telegram: + enabled: false + bot_token: "" + allow_group_messages: false + slack: + enabled: false + bot_token: "" + app_token: "" + discord: + enabled: false + bot_token: "" + allow_guild_messages: false + qq: + enabled: false + app_id: "" + client_secret: "" + sandbox: true ``` -**Restart the app** after changes; the long-lived connection is created at startup. +After changing DingTalk/Lark/WeCom/Telegram/Slack/Discord/QQ settings, **Apply configuration** restarts the corresponding connections. Personal WeChat QR binding saves and restarts automatically. --- @@ -232,7 +397,30 @@ API: `POST /api/robot/test` (requires login). Body: `{"platform":"optional","use --- -## 9. DingTalk: no response when sending messages +## 9. Troubleshooting: no response when sending messages + +### 9.1 Personal WeChat + +Check in this order: + +1. **Binding completed?** + Robot settings should show “Connected” or a bound Bot ID; `robots.wechat.bot_token` in `config.yaml` must not be empty. + +2. **Enabled?** + Confirm “Enable WeChat robot” is checked; restart CyberStrikeAI if you just changed settings. + +3. **Application logs** + - On startup: `微信 iLink 长轮询已启动`; + - After sending a message: `微信收到消息`; if missing, binding may have failed or `bot_token` is invalid—try **Re-bind**. + - `微信 iLink 长轮询异常,将自动重连`: wait for auto-reconnect or restart. + +4. **Network** + The server must reach `https://ilinkai.weixin.qq.com` (outbound HTTPS). If QR generation fails, check this first. + +5. **After sleep or network drop** + Same as DingTalk/Lark: **auto-reconnect** in ~5–60 s; restart if still no response. + +### 9.2 DingTalk Check in this order: @@ -257,8 +445,10 @@ Check in this order: ## 10. Common pitfalls +- **Personal WeChat vs WeCom**: Personal WeChat uses `robots.wechat` + web QR bind; WeCom uses `robots.wecom` + admin callback URL—they are completely different. +- **WeChat QR expired**: QR codes last ~5 minutes; regenerate instead of reusing an old one. - **Wrong bot type**: The “Custom” bot added in a DingTalk **group** (Webhook + sign secret) **cannot** be used for two-way chat. Only the **enterprise internal app** bot from the open platform is supported. -- **Saved but not restarted**: After changing robot settings in CyberStrikeAI you **must restart** the app, or the long-lived connection will not be established. +- **Saved but not restarted**: After changing DingTalk/Lark robot settings you **must restart** the app (WeChat QR bind restarts the connection automatically). - **Client ID typo**: If the platform shows `504`, use `504` (not `5o4`); prefer copy/paste. - **DingTalk: only HTTP callback, no Stream**: This app receives messages via **Stream**. In the open platform, message reception must be **Stream mode**. - **App not published**: After changing the bot or permissions in the open platform, **publish a new version** under “Version management and release”, or changes won’t apply. @@ -267,6 +457,7 @@ Check in this order: ## 11. Notes -- DingTalk and Lark: **text messages only**; other types (e.g. image, voice) are not supported and may be ignored. +- All platforms: **text messages only**; other types (e.g. image, voice) are not supported and may be ignored. +- Personal WeChat: **private chat only**—group @-bot is not supported. - Conversations are shared with the web UI: conversations created from the bot appear in the web “Conversations” list and vice versa. -- Bot execution uses the same **Eino single/multi-agent** path as the web UI (`ProcessMessageForRobot`, with progress callbacks and process details stored in the DB); only the final reply is sent back to DingTalk/Lark in one message (no SSE). Default: `robot_default_agent_mode: eino_single`. +- Bot execution uses the same **Eino single/multi-agent** path as the web UI (`ProcessMessageForRobot`, with progress callbacks and process details stored in the DB); only the final reply is sent back to personal WeChat/DingTalk/Lark/WeCom in one message (no SSE). Default: `robot_default_agent_mode: eino_single`. diff --git a/go.mod b/go.mod index de599372..4ee9b5d3 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,10 @@ module cyberstrike-ai // 若 go mod download 超时,可执行: go env -w GOPROXY=https://goproxy.cn,direct // 或使用 scripts/bootstrap-go.sh -go 1.24.0 - -toolchain go1.24.4 +go 1.25 require ( + github.com/bwmarrin/discordgo v0.29.0 github.com/bytedance/sonic v1.15.0 github.com/cloudwego/eino v0.8.13 github.com/cloudwego/eino-ext/adk/backend/local v0.0.0-20260416081055-0ebab92e14f2 @@ -21,7 +20,7 @@ require ( github.com/eino-contrib/jsonschema v1.0.3 github.com/gin-gonic/gin v1.9.1 github.com/google/uuid v1.6.0 - github.com/gorilla/websocket v1.5.0 + github.com/gorilla/websocket v1.5.3 github.com/larksuite/oapi-sdk-go/v3 v3.4.22 github.com/mattn/go-sqlite3 v1.14.18 github.com/modelcontextprotocol/go-sdk v1.2.0 @@ -29,6 +28,8 @@ require ( github.com/pkoukk/tiktoken-go v0.1.8 github.com/robfig/cron/v3 v3.0.1 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e + github.com/slack-go/slack v0.27.0 + github.com/tencent-connect/botgo v0.2.1 go.opentelemetry.io/otel v1.34.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.34.0 @@ -60,6 +61,7 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/go-resty/resty/v2 v2.6.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/jsonschema-go v0.3.0 // indirect @@ -78,6 +80,9 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/slongfield/pyfmt v0.0.0-20220222012616-ea85ff4c361f // indirect + github.com/tidwall/gjson v1.9.3 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect @@ -93,6 +98,7 @@ require ( golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 // indirect golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/sync v0.15.0 // indirect golang.org/x/sys v0.33.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect diff --git a/go.sum b/go.sum index f4ebc717..95a82311 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= github.com/airbrake/gobrake v3.6.1+incompatible/go.mod h1:wM4gu3Cn0W0K7GUuVWnlXZU11AGBXMILnrdOU8Kn00o= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= @@ -9,6 +10,8 @@ github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMU github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bugsnag/bugsnag-go v1.4.0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/bwmarrin/discordgo v0.29.0 h1:FmWeXFaKUwrcL3Cx65c20bTRW+vOb6k8AnaP+EgjDno= +github.com/bwmarrin/discordgo v0.29.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M= github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= github.com/bytedance/mockey v1.3.0 h1:ONLRdvhqmCfr9rTasUB8ZKCfvbdD2tohOg4u+4Q/ed0= @@ -20,6 +23,8 @@ github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCc github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/certifi/gocertifi v0.0.0-20190105021004-abcd57078448/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= github.com/cloudwego/eino v0.8.13 h1:z5dhaZNN8TWZbP/lgKxGmF26Ii8fPeUlQCGV/NTtms0= @@ -38,11 +43,13 @@ github.com/cloudwego/eino-ext/components/model/openai v0.1.13 h1:5XHRTiTD5bt9KQr github.com/cloudwego/eino-ext/components/model/openai v0.1.13/go.mod h1:mgIoqYYOc0eECCqvLbEYpOJrQNTNxkwXzSJzFU+v5sQ= github.com/cloudwego/eino-ext/libs/acl/openai v0.1.17 h1:EeVcR1TslRA2IdNW1h/2LaGbPlffwGhQm99jM3zWZiI= github.com/cloudwego/eino-ext/libs/acl/openai v0.1.17/go.mod h1:Zkcx6DPTR2NfWmtSXbhItswGw6hqUezNPhNcke0pOG8= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0= @@ -54,6 +61,7 @@ github.com/eino-contrib/jsonschema v1.0.3/go.mod h1:cpnX4SyKjWjGC7iN2EbhxaTdLqGj github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= @@ -76,6 +84,12 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= +github.com/go-resty/resty/v2 v2.6.0 h1:joIR5PNLM2EFqqESUjCMGXrWmXNHEU9CEiK813oKYS4= +github.com/go-resty/resty/v2 v2.6.0/go.mod h1:PwvJS6hvaPkjtjNg9ph+VrSD92bi5Zq73w/BIH7cC3Q= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= +github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -84,21 +98,38 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/jsonschema-go v0.3.0 h1:6AH2TxVNtk3IlvkkhjrtbUc4S8AvO0Xii0DxIygDg+Q= github.com/google/jsonschema-go v0.3.0/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/goph/emperror v0.17.2 h1:yLapQcmEsO0ipe9p5TaN22djm3OFV/TfM/fcYP0/J18= github.com/goph/emperror v0.17.2/go.mod h1:+ZbQ+fUNO/6FNiUo0ujtMjhgad9Xa6fQL9KhH4LNHic= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -114,6 +145,8 @@ github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2 github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -145,11 +178,19 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/nikolalohinski/gonja v1.5.3 h1:GsA+EEaZDZPGJ8JtpeGN78jidhOlxeJROpqMT9fTj9c= github.com/nikolalohinski/gonja v1.5.3/go.mod h1:RmjwxNiXAEqcq1HeK5SSMmqFJvKOfTfXhkJv6YBtPa4= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -159,6 +200,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rollbar/rollbar-go v1.0.2/go.mod h1:AcFs5f0I+c71bpHlXNNDbOWJiKwjFDtISeXco0L5PKQ= @@ -167,6 +210,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= +github.com/slack-go/slack v0.27.0 h1:VWOpUzOK6UAPCCQlFxl79jhv8a/b+GOSJMnWziDJ8B8= +github.com/slack-go/slack v0.27.0/go.mod h1:UEe+jmo9WLlwHB04qsOrTDvqM7Aa4rQL3O5wF3n0hx4= github.com/slongfield/pyfmt v0.0.0-20220222012616-ea85ff4c361f h1:Z2cODYsUxQPofhpYRMQVwWz4yUVpHF+vPi+eUdruUYI= github.com/slongfield/pyfmt v0.0.0-20220222012616-ea85ff4c361f/go.mod h1:JqzWyvTuI2X4+9wOHmKSQCYxybB/8j6Ko43qVmXDuZg= github.com/smarty/assertions v1.16.0 h1:EvHNkdRA4QHMrn75NZSoUQ/mAUXAYWfatfB01yTCzfY= @@ -180,14 +225,24 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tencent-connect/botgo v0.2.1 h1:+BrTt9Zh+awL28GWC4g5Na3nQaGRWb0N5IctS8WqBCk= +github.com/tencent-connect/botgo v0.2.1/go.mod h1:oO1sG9ybhXNickvt+CVym5khwQ+uKhTR+IhTqEfOVsI= +github.com/tidwall/gjson v1.9.3 h1:hqzS9wAHMO+KVBBkLxYdkEeeFHuqr95GfClRLKlgK0E= +github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= @@ -204,6 +259,7 @@ github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zI github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= @@ -238,6 +294,9 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= @@ -246,32 +305,71 @@ golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3 golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= @@ -279,7 +377,10 @@ golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -292,14 +393,28 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/web/static/i18n/en-US.json b/web/static/i18n/en-US.json index 51b867fd..1ec21b80 100644 --- a/web/static/i18n/en-US.json +++ b/web/static/i18n/en-US.json @@ -1316,6 +1316,40 @@ "appSecretPlaceholder": "Lark/Feishu App Secret", "verifyTokenLabel": "Verify Token (Optional)", "verifyTokenPlaceholder": "Event subscription Verification Token" + }, + "telegram": { + "title": "Telegram", + "subtitle": "Bot API long polling; direct chat and group @", + "enabled": "Enable Telegram bot", + "botToken": "Bot Token", + "botTokenHint": "Receives via getUpdates long poll; no public callback URL needed", + "botUsername": "Bot Username (optional)", + "allowGroup": "Allow group chat (respond to @ only)" + }, + "slack": { + "title": "Slack", + "subtitle": "Socket Mode; no public callback URL needed", + "enabled": "Enable Slack bot", + "botToken": "Bot Token (xoxb-)", + "appToken": "App-Level Token (xapp-)", + "appTokenHint": "Requires connections:write scope for Socket Mode" + }, + "discord": { + "title": "Discord", + "subtitle": "Gateway WebSocket; DMs and server @", + "enabled": "Enable Discord bot", + "botToken": "Bot Token", + "botTokenHint": "Create bot in Developer Portal; enable Message Content Intent", + "allowGuild": "Allow guild channels (respond to @ only)" + }, + "qq": { + "title": "QQ Bot", + "subtitle": "QQ Open Platform WebSocket; C2C and group @", + "enabled": "Enable QQ bot", + "appId": "App ID", + "clientSecret": "Client Secret", + "secretHint": "From QQ Bot Open Platform; use sandbox before going live", + "sandbox": "Sandbox environment" } }, "apply": { diff --git a/web/static/i18n/zh-CN.json b/web/static/i18n/zh-CN.json index 98d1f7bb..b04d5373 100644 --- a/web/static/i18n/zh-CN.json +++ b/web/static/i18n/zh-CN.json @@ -1304,6 +1304,40 @@ "appSecretPlaceholder": "飞书应用 App Secret", "verifyTokenLabel": "Verify Token(可选)", "verifyTokenPlaceholder": "事件订阅 Verification Token" + }, + "telegram": { + "title": "Telegram", + "subtitle": "Bot API 长轮询,私聊与群聊 @", + "enabled": "启用 Telegram 机器人", + "botToken": "Bot Token", + "botTokenHint": "通过 getUpdates 长轮询收消息,无需公网回调", + "botUsername": "Bot Username(可选)", + "allowGroup": "允许群聊(仅响应 @ 机器人)" + }, + "slack": { + "title": "Slack", + "subtitle": "Socket Mode,无需公网回调", + "enabled": "启用 Slack 机器人", + "botToken": "Bot Token (xoxb-)", + "appToken": "App-Level Token (xapp-)", + "appTokenHint": "需 connections:write 权限,用于 Socket Mode" + }, + "discord": { + "title": "Discord", + "subtitle": "Gateway WebSocket,私聊与服务器 @", + "enabled": "启用 Discord 机器人", + "botToken": "Bot Token", + "botTokenHint": "开发者门户创建 Bot,开启 Message Content Intent", + "allowGuild": "允许服务器频道(仅响应 @ 机器人)" + }, + "qq": { + "title": "QQ 机器人", + "subtitle": "QQ 开放平台 WebSocket,C2C 与群 @", + "enabled": "启用 QQ 机器人", + "appId": "App ID", + "clientSecret": "Client Secret", + "secretHint": "从 QQ 机器人开放平台获取;上线前可勾选沙箱", + "sandbox": "沙箱环境" } }, "apply": { diff --git a/web/static/js/settings.js b/web/static/js/settings.js index dcd19b09..87693df7 100644 --- a/web/static/js/settings.js +++ b/web/static/js/settings.js @@ -35,6 +35,18 @@ function getRobotStatus(type) { } else if (type === 'lark') { configured = !!(value('robot-lark-app-id') && value('robot-lark-app-secret')); enabled = checked('robot-lark-enabled'); + } else if (type === 'telegram') { + configured = !!value('robot-telegram-bot-token'); + enabled = checked('robot-telegram-enabled'); + } else if (type === 'slack') { + configured = !!(value('robot-slack-bot-token') && value('robot-slack-app-token')); + enabled = checked('robot-slack-enabled'); + } else if (type === 'discord') { + configured = !!value('robot-discord-bot-token'); + enabled = checked('robot-discord-enabled'); + } else if (type === 'qq') { + configured = !!(value('robot-qq-app-id') && value('robot-qq-client-secret')); + enabled = checked('robot-qq-enabled'); } if (enabled) { @@ -47,7 +59,7 @@ function getRobotStatus(type) { } function refreshRobotManager() { - ['wechat', 'wecom', 'dingtalk', 'lark'].forEach((type) => { + ['wechat', 'wecom', 'dingtalk', 'lark', 'telegram', 'slack', 'discord', 'qq'].forEach((type) => { const status = getRobotStatus(type); const pill = document.getElementById(`robot-card-${type}-status`); if (pill) { @@ -95,7 +107,11 @@ function bindRobotManagerEvents() { 'robot-wechat-enabled', 'robot-wechat-ilink-bot-id', 'robot-wecom-enabled', 'robot-wecom-token', 'robot-wecom-corp-id', 'robot-wecom-secret', 'robot-wecom-agent-id', 'robot-dingtalk-enabled', 'robot-dingtalk-client-id', 'robot-dingtalk-client-secret', - 'robot-lark-enabled', 'robot-lark-app-id', 'robot-lark-app-secret' + 'robot-lark-enabled', 'robot-lark-app-id', 'robot-lark-app-secret', + 'robot-telegram-enabled', 'robot-telegram-bot-token', 'robot-telegram-bot-username', 'robot-telegram-allow-group', + 'robot-slack-enabled', 'robot-slack-bot-token', 'robot-slack-app-token', + 'robot-discord-enabled', 'robot-discord-bot-token', 'robot-discord-allow-guild', + 'robot-qq-enabled', 'robot-qq-app-id', 'robot-qq-client-secret', 'robot-qq-sandbox' ]; robotInputIds.forEach((id) => { const el = document.getElementById(id); @@ -608,6 +624,10 @@ async function loadConfig(loadTools = true) { const wecom = robots.wecom || {}; const dingtalk = robots.dingtalk || {}; const lark = robots.lark || {}; + const telegram = robots.telegram || {}; + const slack = robots.slack || {}; + const discord = robots.discord || {}; + const qq = robots.qq || {}; const wechatEnabled = document.getElementById('robot-wechat-enabled'); if (wechatEnabled) wechatEnabled.checked = wechat.enabled === true; const wechatBase = document.getElementById('robot-wechat-base-url'); @@ -647,6 +667,34 @@ async function loadConfig(loadTools = true) { if (larkAppSecret) larkAppSecret.value = lark.app_secret || ''; const larkVerify = document.getElementById('robot-lark-verify-token'); if (larkVerify) larkVerify.value = lark.verify_token || ''; + const telegramEnabled = document.getElementById('robot-telegram-enabled'); + if (telegramEnabled) telegramEnabled.checked = telegram.enabled === true; + const telegramToken = document.getElementById('robot-telegram-bot-token'); + if (telegramToken) telegramToken.value = telegram.bot_token || ''; + const telegramUsername = document.getElementById('robot-telegram-bot-username'); + if (telegramUsername) telegramUsername.value = telegram.bot_username || ''; + const telegramAllowGroup = document.getElementById('robot-telegram-allow-group'); + if (telegramAllowGroup) telegramAllowGroup.checked = telegram.allow_group_messages === true; + const slackEnabled = document.getElementById('robot-slack-enabled'); + if (slackEnabled) slackEnabled.checked = slack.enabled === true; + const slackBotToken = document.getElementById('robot-slack-bot-token'); + if (slackBotToken) slackBotToken.value = slack.bot_token || ''; + const slackAppToken = document.getElementById('robot-slack-app-token'); + if (slackAppToken) slackAppToken.value = slack.app_token || ''; + const discordEnabled = document.getElementById('robot-discord-enabled'); + if (discordEnabled) discordEnabled.checked = discord.enabled === true; + const discordToken = document.getElementById('robot-discord-bot-token'); + if (discordToken) discordToken.value = discord.bot_token || ''; + const discordAllowGuild = document.getElementById('robot-discord-allow-guild'); + if (discordAllowGuild) discordAllowGuild.checked = discord.allow_guild_messages === true; + const qqEnabled = document.getElementById('robot-qq-enabled'); + if (qqEnabled) qqEnabled.checked = qq.enabled === true; + const qqAppId = document.getElementById('robot-qq-app-id'); + if (qqAppId) qqAppId.value = qq.app_id || ''; + const qqSecret = document.getElementById('robot-qq-client-secret'); + if (qqSecret) qqSecret.value = qq.client_secret || ''; + const qqSandbox = document.getElementById('robot-qq-sandbox'); + if (qqSandbox) qqSandbox.checked = qq.sandbox === true; bindRobotManagerEvents(); refreshRobotManager(); @@ -1535,6 +1583,31 @@ async function applySettings() { app_secret: document.getElementById('robot-lark-app-secret')?.value.trim() || '', verify_token: document.getElementById('robot-lark-verify-token')?.value.trim() || '', allow_chat_id_fallback: !!(prevRobots.lark && prevRobots.lark.allow_chat_id_fallback) + }, + telegram: { + enabled: document.getElementById('robot-telegram-enabled')?.checked === true, + bot_token: document.getElementById('robot-telegram-bot-token')?.value.trim() || '', + bot_username: document.getElementById('robot-telegram-bot-username')?.value.trim() || '', + allow_group_messages: document.getElementById('robot-telegram-allow-group')?.checked === true, + ...(prevRobots.telegram && typeof prevRobots.telegram === 'object' ? { + update_offset: prevRobots.telegram.update_offset || 0 + } : {}) + }, + slack: { + enabled: document.getElementById('robot-slack-enabled')?.checked === true, + bot_token: document.getElementById('robot-slack-bot-token')?.value.trim() || '', + app_token: document.getElementById('robot-slack-app-token')?.value.trim() || '' + }, + discord: { + enabled: document.getElementById('robot-discord-enabled')?.checked === true, + bot_token: document.getElementById('robot-discord-bot-token')?.value.trim() || '', + allow_guild_messages: document.getElementById('robot-discord-allow-guild')?.checked === true + }, + qq: { + enabled: document.getElementById('robot-qq-enabled')?.checked === true, + app_id: document.getElementById('robot-qq-app-id')?.value.trim() || '', + client_secret: document.getElementById('robot-qq-client-secret')?.value.trim() || '', + sandbox: document.getElementById('robot-qq-sandbox')?.checked === true } }, tools: [] diff --git a/web/templates/index.html b/web/templates/index.html index 9323efb6..da73ba6a 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -3357,6 +3357,46 @@ 配置 + + + + @@ -3522,6 +3562,115 @@ + + + + + + + + + + + +