diff --git a/external_plugins/wechat-connector/.zcode-plugin/plugin.json b/external_plugins/wechat-connector/.zcode-plugin/plugin.json new file mode 100644 index 00000000..81f1e3be --- /dev/null +++ b/external_plugins/wechat-connector/.zcode-plugin/plugin.json @@ -0,0 +1,16 @@ +{ + "name": "wechat-connector", + "description": "Send notifications to WeCom (WeChat Work) group robots via the official webhook API — outbound text and markdown group notifications from ZCode.", + "description_i18n": { + "en": "Send notifications to WeCom (WeChat Work) group robots via the official webhook API — outbound text and markdown group notifications from ZCode.", + "zh-CN": "通过企业微信群机器人官方 webhook 接口发送群通知:支持文本与 Markdown 消息、多渠道配置与频控处理。" + }, + "version": "0.1.0", + "author": { + "name": "zhaohongjun20-creator", + "url": "https://github.com/zhaohongjun20-creator" + }, + "license": "MIT", + "keywords": ["wechat", "wecom", "webhook", "notification", "group-robot", "qyapi"], + "skills": "./skills" +} diff --git a/external_plugins/wechat-connector/DESIGN.md b/external_plugins/wechat-connector/DESIGN.md new file mode 100644 index 00000000..3a4a554b --- /dev/null +++ b/external_plugins/wechat-connector/DESIGN.md @@ -0,0 +1,112 @@ +# wechat-connector 微信接入插件 · 设计草案 v0.2 + +日期:2026-11-01 | 状态:v0.2 —— M1 已实现并实测通过(errcode 0);M2 规划中 + +## 1. 目标与范围 + +让 ZCode 通过**微信官方接口**收发消息: + +| 能力 | 方向 | 通道 | 版本 | +|---|---|---|---| +| 群通知(文本 / Markdown) | 出站 | 企业微信群机器人 webhook | M1 | +| 对话机器人 | 双向 | 微信公众号(开发用测试号) | M2 | +| 图片 / 模板卡片、多群多渠道 | — | 同上 | M3 | + +**明确不做**:个人微信客户端自动化 / 协议机器人——违反微信使用条款、有封号风险,不碰。 + +## 2. 总体架构 + +``` +ZCode 会话 + │ skills(纯指令文档,教 agent 怎么做) + │ ├─ wechat-send:发通知(curl → 机器人 webhook) + │ └─ wechat-bot:收发对话(读 mailbox → 生成回复 → curl 客服接口) + │ + ├──(M2 起)gateway:常驻小服务(Node,无重依赖) + │ 微信服务器 → HTTP 回调 → 验签 → 追加 mailbox/inbox.jsonl → 立即回空串 + │ + ├──(M2 起)responder:回复引擎,可插拔 + │ A. zcode-session:ZCode 定时任务读 mailbox,用当前会话模型生成回复(能调全部工具) + │ B. llm-api:常驻脚本轮询 mailbox,直接调 OpenAI 兼容接口生成回复(默认 DeepSeek) + │ + └── 运行时数据 ~/.zcode/wechat/ + config.json(多个 webhook 渠道、appid/secret/token) + mailbox/inbox.jsonl(网关写,ZCode 读) + mailbox/seen.json(MsgId 去重) +``` + +设计原则:**先零依赖,后加组件**。 + +- M1 不需要任何常驻进程:skill 教 agent 用 `curl` 直接调 webhook,密钥从环境变量读。 +- M2 才引入 gateway + mailbox;收发用 Read/curl 即可完成,先不写 MCP server,等工具面变大后再封装成 MCP(留作演进项)。 + +## 3. 接口约定 + +**出站(企业微信 webhook)** + +- `POST https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=XXX` +- msgtype:`text`(支持 @mention)/ `markdown` / `image`(base64+md5)/ 模板卡片 +- 频控:每机器人 20 条/分钟,超出时排队或合并;失败退避重试 3 次 + +**入站(公众号回调,gateway 暴露)** + +- `GET /wechat/callback`:微信验证,echostr 原样返回 +- `POST /wechat/callback`:验签 `sha1(sort(token, timestamp, nonce))`,解析 XML 得 FromUser / Content / MsgId +- 收到即回空串(规避 5 秒被动回复超时与重推),消息落 mailbox 异步处理 +- 回复走客服接口 `POST message/custom/send`(测试号无 48h 窗口限制) + +**回复引擎(M2,可插拔)** + +- 方案 A `zcode-session`:定时自动化(如每 2 分钟)拉 mailbox,ZCode 用当前模型生成并发出回复——能查文件、跑命令,适合"半自动助理";依赖 ZCode 会话在跑。 +- 方案 B `llm-api`(默认先做):独立 responder 脚本常驻轮询 mailbox,直接调 OpenAI 兼容接口生成并回复。默认接 DeepSeek:`base_url=https://api.deepseek.com`、`model=deepseek-chat`、密钥 `DEEPSEEK_API_KEY`;换其他模型只改 base_url/model 两个变量。7×24 无人值守,成本最低。 + +**配置优先级**:环境变量 > `config.json`。 +`WECHAT_WEBHOOK_URL`、`WECHAT_APPID` / `WECHAT_SECRET` / `WECHAT_TOKEN` / `WECHAT_ENCODING_AES_KEY`、`DEEPSEEK_API_KEY`(M2 方案 B)。 +密钥永不写入插件源码、不进 git。 + +## 4. 插件目录结构(按 ZCode 插件规范) + +``` +plugins/ + marketplace.json # 本地测试市场 + wechat-connector/ + .zcode-plugin/plugin.json # name: wechat-connector, version 0.1.0 + skills/wechat-send/SKILL.md + skills/wechat-bot/SKILL.md # M2 + gateway/index.mjs + package.json # M2 + DESIGN.md / README.md +``` + +manifest 只声明真实存在的组件(M1 仅 `"skills": "./skills"`),M2 起再按需加 `"mcpServers"`。 + +## 5. 里程碑与验收 + +| 里程碑 | 内容 | 验收标准(代表性用例) | +|---|---|---| +| M1 出站通知 | wechat-send skill + 配置模板 + 冒烟脚本 | 对 ZCode 说"往研发群发:今晚 8 点发布"→ 群里收到该消息 | +| M2 双向对话 | gateway + mailbox + wechat-bot skill + responder(默认 DeepSeek 方案 B) | 给测试号发"你好"→ 1 分钟内收到机器人回复 | +| M3 增强 | 图片/卡片消息、多群渠道管理、消息日志查询 | 另行评审 | + +回复引擎方案 A 由 ZCode 定时自动化驱动(每 2 分钟处理一次新消息),平时也可以手动说一句"看看微信";方案 B 由 responder 自己轮询,完全不依赖 ZCode 在线。 + +## 6. 安全与合规 + +- 回调验签,可选 AES 加密模式;验签失败一律 403 +- MsgId 去重,防微信重推导致重复回复 +- webhook URL 视同密码,不入库不入 git +- 频控 + 退避重试,防止刷屏被封 webhook +- 全程走官方 API,无逆向协议、无第三方机器人框架 + +## 7. 风险与限制 + +- 公众号被动回复有 5 秒超时 → 已用"回空 + 异步 mailbox"模式规避 +- 测试号回调需要公网可达的 80/443 → 本地开发用内网穿透(cpolar / ngrok / frp),或直接部署到云服务器 +- 未认证订阅号的客服接口有 48 小时会话窗口限制 → 先在测试号上开发,不受此限 +- 企业微信 webhook 每机器人 20 条/分钟,大量通知需合并发送 + +## 8. 设计决策记录(已确认) + +1. 通道:企业微信群机器人(出站,M1)+ 公众号(双向,M2);个人微信客户端自动化永不支持。 +2. 架构:M1 零依赖(skill + curl);M2 起引入 gateway(Node)+ 本地信箱;回复引擎可插拔(A:ZCode 会话 / B:OpenAI 兼容 API,默认 DeepSeek)。 +3. 实现语言:Node/JavaScript(gateway 与未来 MCP),skill 为纯 Markdown。 +4. M2 的 gateway 部署位置:待定(本地 + 内网穿透,或云服务器)。 diff --git a/external_plugins/wechat-connector/LICENSE b/external_plugins/wechat-connector/LICENSE new file mode 100644 index 00000000..12431f45 --- /dev/null +++ b/external_plugins/wechat-connector/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 zhaohongjun20-creator + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/external_plugins/wechat-connector/README.md b/external_plugins/wechat-connector/README.md new file mode 100644 index 00000000..05406bf9 --- /dev/null +++ b/external_plugins/wechat-connector/README.md @@ -0,0 +1,82 @@ +# wechat-connector — WeChat Connector for ZCode + +A ZCode plugin that sends notifications to WeCom (WeChat Work / 企业微信) group robots through Tencent's **official webhook API**. No reverse-engineered protocols and no client automation — just an HTTPS call to the group robot webhook you create in your own group, so there is no account-ban risk from unofficial clients. + +[中文说明](README_CN.md) + +## Features + +- Send **text** and **Markdown** messages to one or more WeCom groups +- Multi-channel configuration: several groups / webhook URLs as named channels +- Rate-limit aware: 20 messages/minute per robot, with retry guidance built into the skill +- Official API only, zero background services for outbound notifications (a single `curl` call) +- Ships as a ZCode skill (`wechat-send`), so any ZCode session can use it once installed + +## Install + +**Option A — from the official community marketplace (recommended after review):** +add the `zcode-plugins-official` marketplace in your ZCode client, then install *WeChat Connector (微信接入)*. + +**Option B — from this repository:** +add this repository as a plugin marketplace in your ZCode client (if your version supports git sources), or clone it and add the local directory: + +```bash +git clone https://github.com/zhaohongjun20-creator/wechat-connector.git +# then in ZCode: Plugin Marketplace → Add → Add Plugin Marketplace → select the cloned folder +``` + +## Configuration + +The webhook URL is treated as a secret. It is read from (in priority order): + +1. Environment variable `WECHAT_WEBHOOK_URL` +2. Config file `~/.zcode/wechat/config.json` (Windows: `C:\Users\\.zcode\wechat\config.json`): + +```json +{ + "default_channel": "default", + "channels": { + "default": { "webhook": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=***" } + } +} +``` + +Ask the agent to "send to channel XX" and it matches the key under `channels`. + +### Create a group robot (mobile app is enough) + +WeCom group chat → top-right "…" → **Group robots (群机器人) → Add robot** → copy the webhook URL. The robot must stay in the group; if it is removed, the webhook is invalidated and the API returns `errcode 93000`. + +## Usage + +After installing, say to ZCode: + +> Send to the WeCom group: release tonight at 8 PM + +The agent resolves the webhook, posts the message, and reports the API result (`errcode 0` means delivered). + +## Side effects & security + +This section discloses everything the plugin touches, as required for community plugins: + +- **Network access**: the skill sends HTTPS `POST` requests to `https://qyapi.weixin.qq.com` (Tencent's official endpoint) containing the webhook URL and the message content. +- **Command execution**: the skill instructs the agent to run `curl` for the HTTP call. +- **File writes**: message payloads are written as temporary JSON files in the system temp directory. +- **Credentials**: webhook URLs (and future API tokens) live only in `~/.zcode/wechat/config.json` or environment variables on your machine. They are never committed to the plugin source, and are sent nowhere except Tencent's API endpoint. +- **No** MCP server, **no** hooks, **no** third-party code or assets. + +## How it works + +The plugin ships one skill, `skills/wechat-send/SKILL.md`. It documents the official webhook message format (text / markdown / image, mention lists, rate limits, error codes) and instructs the agent to resolve the webhook from config, write a UTF-8 JSON payload (avoiding Windows codepage issues), post it with `curl --data-binary`, and verify the `errcode` in the response. + +## Roadmap + +- **M1 (shipped)**: outbound group notifications via WeCom group robot webhook +- **M2 (planned)**: two-way conversation via a WeChat Official Account (test account for development) + pluggable reply engine — option A: ZCode session as the brain; option B: any OpenAI-compatible API (default target: DeepSeek) +- **M3 (planned)**: rich messages (images / template cards), channel management, message log queries + +Design details: [DESIGN.md](DESIGN.md) (in Chinese). + +## License + +[MIT](LICENSE) diff --git a/external_plugins/wechat-connector/README_CN.md b/external_plugins/wechat-connector/README_CN.md new file mode 100644 index 00000000..814aff73 --- /dev/null +++ b/external_plugins/wechat-connector/README_CN.md @@ -0,0 +1,80 @@ +# wechat-connector — ZCode 微信接入插件 + +通过企业微信群机器人**官方 webhook 接口**发送群通知的 ZCode 插件。不碰逆向协议、不做客户端自动化——只是向你自己在群里创建的群机器人发一条 HTTPS 请求,没有封号风险。 + +[English](README.md) + +## 功能 + +- 向一个或多个企业微信群发送**文本**和 **Markdown** 消息 +- 多渠道配置:多个群 / webhook 地址以命名渠道管理 +- 频控感知:每个机器人 20 条/分钟,skill 内置退避重试指引 +- 全程官方 API,出站通知零常驻服务(一次 `curl` 调用) +- 以 ZCode skill(`wechat-send`)形式提供,安装后任何 ZCode 会话都能用 + +## 安装 + +**方式 A —— 官方社区市场(评审通过后推荐):** 在 ZCode 客户端添加 `zcode-plugins-official` 市场,安装"微信接入(WeChat Connector)"。 + +**方式 B —— 从本仓库安装:** 若你的客户端版本支持 git 源,直接把本仓库添加为插件市场;或先克隆再添加本地目录: + +```bash +git clone https://github.com/zhaohongjun20-creator/wechat-connector.git +# 然后在 ZCode:插件市场 → 添加 → 添加插件市场 → 选择克隆出的文件夹 +``` + +## 配置 + +webhook 地址视同密码,按以下优先级读取: + +1. 环境变量 `WECHAT_WEBHOOK_URL` +2. 配置文件 `~/.zcode/wechat/config.json`(Windows:`C:\Users\<用户名>\.zcode\wechat\config.json`): + +```json +{ + "default_channel": "default", + "channels": { + "default": { "webhook": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=***" } + } +} +``` + +对 agent 说"发到 XX 群",会按渠道名匹配 `channels` 下的键。 + +### 创建群机器人(手机版即可) + +企业微信群聊 → 右上角"…" → **群机器人 → 添加机器人** → 复制 webhook 地址。机器人必须留在群里;一旦被移出,webhook 立即失效(接口返回 `errcode 93000`)。 + +## 用法 + +安装后对 ZCode 说: + +> 往企业微信群发:今晚 8 点发布 + +agent 会解析 webhook、发送消息并回报接口结果(`errcode 0` 即送达)。 + +## 副作用与安全声明 + +按社区插件要求,完整披露本插件的一切外部影响: + +- **网络访问**:skill 会向 `https://qyapi.weixin.qq.com`(腾讯官方接口)发起 HTTPS `POST`,内容为 webhook 地址与消息文本。 +- **命令执行**:skill 指示 agent 运行 `curl` 完成 HTTP 调用。 +- **文件写入**:消息 payload 以临时 JSON 文件写入系统临时目录。 +- **凭据**:webhook 地址(以及后续的 API token)只保存在本机 `~/.zcode/wechat/config.json` 或环境变量中,绝不写入插件源码,除腾讯接口外不发送到任何地方。 +- **没有** MCP 服务、**没有** hooks、**没有**第三方代码或素材。 + +## 工作原理 + +插件只包含一个 skill:`skills/wechat-send/SKILL.md`。其中记录了官方 webhook 的消息格式(text / markdown / image、@提及、频控、错误码),并指示 agent:从配置解析 webhook → 以 UTF-8 写出 JSON payload(规避 Windows 代码页问题)→ 用 `curl --data-binary` 发送 → 校验响应中的 `errcode`。 + +## 路线图 + +- **M1(已交付)**:企业微信群机器人出站通知 +- **M2(规划中)**:公众号双向对话 + 可插拔回复引擎(方案 A:ZCode 会话当大脑;方案 B:任意 OpenAI 兼容接口,默认 DeepSeek) +- **M3(规划中)**:富消息(图片 / 模板卡片)、渠道管理、消息日志查询 + +设计细节见 [DESIGN.md](DESIGN.md)。 + +## 许可证 + +[MIT](LICENSE) diff --git a/external_plugins/wechat-connector/skills/wechat-send/SKILL.md b/external_plugins/wechat-connector/skills/wechat-send/SKILL.md new file mode 100644 index 00000000..03405bb2 --- /dev/null +++ b/external_plugins/wechat-connector/skills/wechat-send/SKILL.md @@ -0,0 +1,66 @@ +--- +name: wechat-send +description: Send text or markdown notifications to a WeCom (企业微信) group robot via official webhook API. Use when the user asks to send a message / notice / notification to a WeCom group, 企业微信群, 群通知, or 企业微信机器人. +--- + +# wechat-send — 企业微信群机器人通知 + +通过企业微信群机器人 webhook 发送群通知,全程走官方 API,无需任何常驻服务。 + +## 1. 取 webhook 地址 + +按优先级: + +1. 环境变量 `WECHAT_WEBHOOK_URL`; +2. 配置文件 `~/.zcode/wechat/config.json`(Windows 下通常是 `C:\Users\<用户名>\.zcode\wechat\config.json`),结构: + +```json +{ + "default_channel": "default", + "channels": { + "default": { "webhook": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=***" } + } +} +``` + +用户说"发到 XX 群"时,按渠道名匹配 `channels` 的键;未指明则用 `default_channel`。 + +**安全**:webhook URL 视同密码——不要在回复中原样展示 key,不要写入任何会提交到仓库的文件。 + +## 2. 发送(Windows / Git Bash 编码注意) + +不要把含中文的 JSON 直接放进 curl 命令行参数(Windows 代码页会破坏 UTF-8)。先用 Write 工具把 payload 写成 UTF-8 临时文件,再发送: + +文本消息(临时文件,如 `$TMP/wechat-payload.json`): + +```json +{"msgtype": "text", "text": {"content": "今晚 8 点发布"}} +``` + +Markdown 消息: + +```json +{"msgtype": "markdown", "markdown": {"content": "## 发布通知\n今晚 **8 点** 发布,请留意"}} +``` + +发送: + +```bash +curl -sS -X POST -H "Content-Type: application/json" \ + --data-binary @"$TMP/wechat-payload.json" \ + "$WEBHOOK" +``` + +注意必须用 `--data-binary`(不要用 `-d`,它会剥掉换行);Git Bash 下路径用正斜杠。 + +**校验**:响应为 `{"errcode": 0, "errmsg": "ok"}` 才算成功。`errcode` 非 0 时: +- `45009`(接口超频):等 30 秒重试一次; +- `93000` 或 invalid webhook:提示用户检查 webhook 地址是否失效(机器人被移除会失效); +- 其他错误:把 errcode/errmsg 原样报告给用户。 + +## 3. 限制与礼仪 + +- 每个机器人 **20 条/分钟**:多条内容尽量合并为一条;确实要分批时每条间隔 3 秒以上。 +- 单条 text / markdown 内容上限 4096 字节(UTF-8),超长先分段。 +- 除非用户明确要求,不要用 `"mentioned_list": ["@all"]`。 +- 这是群通知通道,不是个人聊天,不要用来做对话轮询。 diff --git a/marketplace.json b/marketplace.json index c7f09a06..91daddfa 100644 --- a/marketplace.json +++ b/marketplace.json @@ -1443,6 +1443,38 @@ "mcp", "verification" ] + }, + { + "name": "wechat-connector", + "source": "./external_plugins/wechat-connector", + "displayName": "WeChat Connector", + "displayName_i18n": { + "en": "WeChat Connector", + "zh-CN": "微信接入" + }, + "description": "Send notifications to WeCom (WeChat Work) group robots via the official webhook API — outbound text and markdown group notifications from ZCode.", + "description_i18n": { + "en": "Send notifications to WeCom (WeChat Work) group robots via the official webhook API — outbound text and markdown group notifications from ZCode.", + "zh-CN": "通过企业微信群机器人官方 webhook 接口发送群通知:支持文本与 Markdown 消息、多渠道配置与频控处理。" + }, + "version": "0.1.0", + "author": { + "name": "zhaohongjun20-creator", + "url": "https://github.com/zhaohongjun20-creator" + }, + "homepage": "https://github.com/zhaohongjun20-creator/zcode-wechat", + "repository": "https://github.com/zhaohongjun20-creator/zcode-wechat", + "license": "MIT", + "category": "productivity", + "keywords": [ + "wechat", + "wecom", + "wechat-work", + "webhook", + "notification", + "group-robot", + "qyapi" + ] } ] } \ No newline at end of file