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

@huo15/wechat-service

v2.2.2

Published

OpenClaw 微信服务号(公众号)插件 v2.2.2:注册 ClawHub plugin tag 让 `openclaw plugins install @huo15/wechat-service` 不带版本号也能装;首次显式声明 openclaw.compat.pluginApi=>=2026.3.23(之前历史版本未设)。继承 v2.2.1 角色权限 + AI 对话护栏 + 自动回复。消息收发、菜单管理、模板/订阅消息、客服消息、素材草稿与图文发布、二维码/标签/JS-SDK/数据分析,支持多账号

Readme

@huo15/wechat-service

📖 正文内容

OpenClaw 微信服务号(公众号)渠道插件:把微信公众号变成你的 AI 协作入口。 一粉一会话隔离 · 12 个 agent tool · 覆盖 60+ 个微信公众平台官方 API · 多账号矩阵路由 · 知识库双写

@huo15/wechat-service v2.1.2
└─ 12 个 agent tool / 60+ 个 WeChat MP API / 架构按 @huo15/wecom 同构

✨ 能力总览

| 维度 | 说明 | |------|------| | 🚀 一粉一会话 | 动态 Agent 派生:每个 openid 自动一个独立 agent;管理员名单可旁路 | | 📨 消息全栈 | 客服消息(10 类)/ 模板消息(CRUD + 公模板库)/ 一次性 + 长期订阅通知 | | 📰 内容发布 | 素材管理 + 草稿箱 + freepublish 流水线 + 群发(按标签/openid,预览,撤回) | | 🔐 网页授权 | OAuth2.0 全流程(snsapi_base / snsapi_userinfo) + JS-SDK 签名 | | 📊 数据分析 | datacube 17 项指标(用户增减、图文阅读分享、消息分析、接口调用) | | 🤖 智能开放 | OCR 7 类(身份证/银行卡/驾驶证/行驶证/营业执照/车牌/通用) + 图像处理 3 项 | | 🎫 卡券精简 | create / get / batchget / delete / consume / decrypt encrypt_code | | 🧠 多账号矩阵 | accounts.<id> 隔离 webhook 路径、access_token、agent 路由 | | 🛡️ 权限控制(v2.1.0+) | permissionMode=admin-only:写操作仅 main agent / adminUsers | | 💾 知识库双写 | 本地 markdown(Karpathy 风格)+ Odoo knowledge.article 同步 |


📦 安装

# 通过 OpenClaw 安装(推荐)
/install @huo15/wechat-service

# 或直接 npm
npm install @huo15/wechat-service

🚀 初始化

方式 A — 交互式向导(推荐)

/setup wechat-service

向导收集:AppID / AppSecret / 服务器 Token / EncodingAESKey / 加密模式 / 原始 ID / 账号名。完成后会回显 webhook URL 和公众号后台需要填的字段。

方式 B — CLI 非交互式(v2.0.0+,适合 CI / Docker)

export WECHAT_SERVICE_APP_ID="wx1234567890"
export WECHAT_SERVICE_APP_SECRET="xxx"
export WECHAT_SERVICE_ENCODING_AES_KEY="x_x_43_chars_x"

openclaw channels add --channel wechat-service --name "我的公众号" --token "MY_TOKEN"

非 default 账号用 WECHAT_SERVICE_<UPPER_ACCOUNTID>_APP_ID 这种带 accountId 前缀的 env:

export WECHAT_SERVICE_SHOP_A_APP_ID="wx_shop_a"
openclaw channels add --channel wechat-service --account shop-a

🔌 Webhook URL

主路径:

https://你的域名/plugins/wechat-service/{accountId}

兼容路径:/wechat-service/{accountId}。填到「微信公众平台 → 基本配置 / 开发者中心 → 服务器配置 → URL」,Token / EncodingAESKey 与配置保持一致即可。保存时公众平台发的 GET echostr 校验,插件自动响应(明文 + 安全模式都支持)。


⚙️ 配置 Schema

channels:
  wechat-service:
    enabled: true
    defaultAccount: default

    # ① 多账号矩阵
    accounts:
      default:
        enabled: true
        name: 我的公众号
        appId: wx1234567890abcdef
        appSecret: ${WECHAT_SERVICE_APP_SECRET}
        token: ${WECHAT_SERVICE_TOKEN}
        encodingAESKey: ${WECHAT_SERVICE_AES_KEY}
        encryptMode: safe              # plain | compatible | safe
        originalId: gh_xxxxxxxxxx       # 可选
        replyMode: async                # async(默认)/ passive
        replyPlaceholderText: "收到,正在为你处理..."   # async 模式占位
        welcomeText: 欢迎关注!

        # ② 静态事件路由
        routing:
          defaultAgent: wechat-agent
          events:
            subscribe: onboarding-agent
            CLICK: menu-agent
            TEMPLATESENDJOBFINISH: webhook-agent

        # ③ 知识库双写
        knowledgeSync:
          enabled: true
          localPath: ~/knowledge/huo15
          odoo:
            url: https://huo15.com
            db: huo15
            username: [email protected]
            password: ${ODOO_PASSWORD}
            articleParentId: 123        # 可选

    # ④ 🆕 v0.2.0 动态 Agent 派生(与 @huo15/wecom 同构)
    dynamicAgents:
      enabled: true
      dmCreateAgent: true               # 每个 openid 一个 agent
      groupEnabled: false               # 公众号无群聊;保留是为了与 wecom schema 对齐
      adminUsers:                       # 管理员 openid:旁路动态路由 + admin-only 模式可执行写操作
        - oABC123xyz
      # 🆕 v2.1.0 权限控制
      permissionMode: admin-only        # "open"(默认)/ "admin-only"

    network:
      egressProxyUrl: ''
      timeoutMs: 15000

Agent ID 命名(动态 Agent):wechat-service-{accountId}-dm-{sanitized_openid},例:wechat-service-default-dm-oabc123xyz


🔗 顶层 bindings必须配!

⚠️ 不配 binding,agent 跑完后回复消息会被静默丢弃(OpenClaw 找不到 channel→agent 的反向路由)。这是最常踩的坑。

bindings 在 OpenClaw 顶层(不在 channels.wechat-service 里),把 channel + accountId 映射到 agent:

// ~/.openclaw/openclaw.json 顶层
{
  "bindings": [
    {
      "agentId": "main",
      "match": { "channel": "wechat-service", "accountId": "default" }
    }
  ]
}

多账号 / 多渠道场景:每个 <channel>:<accountId> 都要单独一条 binding:

"bindings": [
  { "agentId": "main",          "match": { "channel": "wecom",          "accountId": "default" } },
  { "agentId": "main",          "match": { "channel": "wechat-service", "accountId": "default" } },
  { "agentId": "shopa-agent",   "match": { "channel": "wechat-service", "accountId": "shop-a"  } },
  { "agentId": "support-agent", "match": { "channel": "wechat-service", "accountId": "support" } }
]

agentId: "main" 是 OpenClaw 默认 agent,不需要在 agents.list 显式注册。其他自定义 agent 要先注册:

"agents": {
  "list": [
    { "id": "main" },
    { "id": "shopa-agent" },
    { "id": "support-agent" }
  ]
}

📨 回复模式详解(replyMode + replyPlaceholderText

公众号 webhook 协议要求 5 秒内返回响应,但 LLM 通常要 5–30 秒才能产出回复。Plugin 提供两种模式应对:

模式 A:async默认,推荐

accounts:
  default:
    replyMode: async                                # 默认值
    replyPlaceholderText: "收到,正在为你处理..."     # 默认值

行为:

  1. webhook 收到消息 → 立即 返回被动回复 XML 含 placeholder 文本 → 粉丝立刻看到 "收到,正在为你处理..."
  2. 后台异步跑 agent → agent 产出回复 → 通过客服消息接口customservice/send)push 第二条给粉丝
  3. 粉丝在微信里看到两条消息:先是 placeholder(瞬间到达),然后是 agent 真回复(几秒后)

自定义 placeholder

replyPlaceholderText: "🤖 AI 助手收到啦~ 正在思考中,请稍候 5-10 秒"

关掉 placeholder(回到 v2.1.0 之前的行为)

replyPlaceholderText: ""    # 空字符串 → 不发占位,立即返 success

模式 B:passive(5 秒内必须出结果,否则降级)

replyMode: passive

行为:5 秒内如果 agent 已经产出 text,则把整段回复打包成被动回复 XML 直接返回(粉丝只看到一条消息,无延迟);超时则降级到 async 模式(同上)。

适合:纯模板回复 / 关键词路由 / 缓存命中 等确定能 5 秒内完成的场景。LLM 推理建议留在 async

Event 类回调不会发 placeholder

关注/扫码/菜单点击等 event 类回调始终返回 "success",避免微信侧把被动回复 XML 当事件确认从而触发额外重发。日志区分:

acked(placeholder)  ← user message + async + 占位生效
acked(success)      ← event 类回调 / passive 模式 / 占位关闭

⏰ 客服消息「48 小时窗口」硬性约束

微信平台规则(不是 plugin 限制):

  • 粉丝主动给公众号发完消息后,公众号有 48 小时窗口可以用 customservice/send 主动回复
  • 超过 48 小时禁用客服消息接口(errcode: 45015);想发就要走模板消息订阅消息(且粉丝事先订阅过)
  • 关注事件 / 扫码事件 / 点击菜单 也开 48h 窗口

实务建议:

  • agent 回复async 模式 + 客服消息(48h 内绝对够用)
  • 主动通知(超 48h、或粉丝从未交互)必须用模板消息(wechat_service_message send_template)或长期订阅通知(send_subscribe

🛠️ Agent Tools(12 个)

| Tool | 主要 action | |------|-------------| | wechat_service_menu | create / get / delete / create_conditional / delete_conditional / try_match | | wechat_service_message | 客服消息(10 类)+ 模板消息 CRUD + 公模板库 + 一次性订阅 + 长期订阅通知(共 25 个 actions) | | wechat_service_material | 临时/永久素材上传、图文素材、列表、删除 | | wechat_service_article | 草稿箱 CRUD + freepublish 发布流水线(含 describePublishStatus) | | wechat_service_user | 用户信息 / 粉丝列表 / 标签 CRUD / 黑名单 / 备注 | | wechat_service_qrcode | create(temp_id/temp_str/perm_id/perm_str)+ gen_shortkey + fetch_shortkey | | wechat_service_mass_send | 按标签 / openid 列表 / 预览群发 + 速度控制 + 撤回 | | wechat_service_jssdk | sign(JS-SDK config)/ get_ticket / invalidate_ticket | | wechat_service_oauth 🆕 v0.4.0 | build_authorize_url / code_to_token / refresh_token / userinfo / validate | | wechat_service_analytics 🆕 v0.4.0 | list_metrics + query metric:<name> —— 17 项 datacube 指标 | | wechat_service_intelligent 🆕 v1.0.0 | list_visions + run vision:<name> —— OCR 7 类 + 图像 3 项 | | wechat_service_card 🆕 v1.0.0 | create / get / batchget / delete / consume / decrypt(卡券精简) |

所有 tool 都支持 accountId 参数;不传时使用当前 agent 绑定的账号或 defaultAccount。未配置账号会直接返回结构化错误(isError=true)。


🎯 v0.2 → v2.1 演进路线(已落地)

v0.1.0  初始版本(消息/菜单/素材/草稿/用户/标签/二维码/JS-SDK/群发)
v0.2.0  ✅ Phase 0  动态 Agent 框架(模仿 @huo15/wecom)
v0.3.0  ✅ Phase 1  通知能力补全(模板消息 CRUD + 长期订阅通知)
v0.4.0  ✅ Phase 2  网页授权 OAuth + 数据统计 datacube
v1.0.0  ✅ Phase 3  智能开放 OCR/图像 + 卡券精简版
v1.0.1  🩹 Bugfix  channel id / config key kebab-case 对齐
v2.0.0  🏗️ 架构升级  src/ 按 @huo15/wecom 同构 + account-runtime + setup.applyAccountConfig
v2.0.1  📝 docs    刷新 SKILL.md description
v2.1.0  🛡️ 权限层  permissionMode=admin-only:写操作仅 main agent / adminUsers
v2.1.1  🩹 UX     async 模式立即返 placeholder 占位回复
v2.1.2  📚 docs   README 大扩 4 节配置 SOP(沉淀踩坑)  ← 当前 latest

详细变更见 CHANGELOG.md


🛡️ 权限模型(v2.1.0+)

公众号的 12 个 agent tool 共 80+ 个 action,按副作用分两类:

| 类别 | 例子 | admin-only 模式下谁能调 | |------|------|-------------------------| | read(读) | list_templates / get_info / OCR / OAuth flow / analytics.query | 所有 agent(主 agent 和粉丝的动态 agent 都可) | | write(写) | send_text(给任意 openid)/ mass_send.* / menu.create / card.create / article.publish / 模板&订阅消息发送 | main agent / adminUsers 列表 / OpenClaw owner |

重点:粉丝跟公众号的"自然对话"不受影响 —— agent 收到入向消息后的回复走 dispatcher 直接调客服消息接口,不经 tooladmin-only 模式只 block 粉丝在自己的动态 agent 里主动调 tool 越权的场景(譬如试图用 wechat_service_message.send_text 给别人发消息)。

# 启用方法(推荐生产配置)
channels:
  wechat-service:
    dynamicAgents:
      enabled: true
      adminUsers: [oABC_admin1, oXYZ_admin2]
      permissionMode: admin-only

被拒绝时 tool 返回结构化错误:

{
  "ok": false,
  "isError": true,
  "action": "send_text",
  "permissionMode": "admin-only",
  "agentId": "wechat-service-default-dm-onormal",
  "requesterSenderId": "oNORMAL",
  "error": "[wechat-service] action \"wechat_service_message.send_text\" 是 admin/write 操作..."
}

📐 多 Agent 路由

routing.events 允许把不同事件类型路由到不同 agent:

  • subscribe / unsubscribe — 关注 / 取消关注
  • CLICK / VIEW — 菜单点击 / 跳转
  • SCAN — 带参二维码扫描
  • LOCATION / location_select — 位置上报
  • TEMPLATESENDJOBFINISH / MASSSENDJOBFINISH — 模板 / 群发回调

未命中的事件走 routing.defaultAgent。设置 failClosedOnDefaultRoute: true 时,默认 agent 未配置会拒绝消息。

动态 Agent 优先级:当 dynamicAgents.enabled=true 时,路由先走静态 routing.events,再被动态 agent 覆盖(除非 senderId 在 adminUsers 里)。


💾 知识库双写

启用 knowledgeSync.enabled 后,每条入站消息 + agent 回复会同时写入:

  1. 本地 markdown{localPath}/wechat-service/{accountId}/{openid}/{YYYY-MM-DD}.md 一天一个文件,首次写入带 YAML frontmatter,后续追加 ## HH:mm:ss 段落。
  2. Odoo knowledge.article:按 title [wechat-service] {name} · {openid} · {date} 去重;存在则 write 追加 body,不存在则 create(可选 articleParentId)。

两路独立 best-effort:任一失败不影响另一路,也不会 throw 到消息处理链。


🔒 加密模式与签名

  • plain — 仅测试用,webhook 明文 XML
  • compatible — 同时接受明文和加密;推荐只在迁移期使用
  • safe推荐)— 强制加密。插件用 encodingAESKey + appId 解密 Encrypt 字段并校验 msg_signature

服务器 URL 校验(GET echostr)兼容 signature + msg_signature 两种签名方式。


📡 公众号后台必做的 6 件事(缺一不可)

登录 https://mp.weixin.qq.com 找管理员账号,按顺序操作:

| # | 后台位置 | 字段 | 注意 | |---|---------|------|------| | 1 | 设置与开发 → 基本配置 → 服务器配置 | URL | 填 https://你的域名/plugins/wechat-service/<accountId>,accountId 跟 ~/.openclaw/openclaw.json 一致 | | 2 | 同上 | Token | 跟 plugin 配置 accounts.<id>.token 一字不差(无空格、大小写敏感) | | 3 | 同上 | EncodingAESKey | 43 位完整字符串,跟 accounts.<id>.encodingAESKey 一致 | | 4 | 同上 | 加密模式 | 选「安全模式」对应 plugin 的 encryptMode: safe(推荐) | | 5 | 设置与开发 → 基本配置 → IP 白名单 | 加入 OpenClaw gateway 的出口公网 IP | ⚠️ 不加无法调任何 wechat API(包括 access_token / 客服消息 / 模板消息),报 errcode: 40164 | | 6 | 设置与开发 → 接口权限 | 确认开通:客服消息 / 模板消息 / 用户管理 / 素材管理 / 群发接口 / 自定义菜单 / 数据分析 等 | 未认证号 / 个人号 / 订阅号有些接口禁用,需要服务号或已认证 |

取出口 IP 的方法

# 在 gateway 跑的那台机器上
curl -s ifconfig.me ; echo

如果 gateway 跑在本地 mac、用 frpc 反代到公网,出口 IP 是 mac 这边的公网 IP(因为 outbound 不走隧道,是 mac 直连 wechat API)。建议把 gateway 部署到固定公网 IP 的 VPS,避免每次 IP 变都要改白名单。


🧰 故障排查(常见错误对照 + 日志关键字)

错误码速查

| 现象 / 错误码 | 含义 | 排查 | |--------------|------|------| | 后台「请求失败,HTTP 返回非 200」 | webhook 不可达 | curl https://你的域名/plugins/wechat-service/<id> 看 200/404;查 frpc 隧道;查 gateway 是否在跑 | | signature_invalid | Token 不一致 / 大小写 / 前后空格 | 重新对照 plugin 配置和后台 Token 字段,完全一致 | | route-failuresigned=true | 签名算到了但结果不一致 | 同上,Token 校对 | | errcode: 40164 | IP 不在白名单 | 加 mac 出口 IP 到后台白名单(上面第 5 步) | | errcode: 45015 | 48 小时窗口已过 | 客服消息超 48h 不能发,改用模板消息 / 订阅消息 | | errcode: 45047 | 客服消息超出每日上限 | 等次日重置或降发频 | | errcode: 48001 | 接口权限未开通 | 后台「接口权限」页申请相应能力 | | errcode: 40001 | access_token 失效 | 不用动,plugin 自动刷新;持续报错检查 AppSecret 是否被重置 | | unknown channel id: wechatService | 老配置 key 不对 | 升级到 v1.0.1+,把 channels.wechatService 改成 channels["wechat-service"](kebab-case) | | Channel does not support add | plugin v1.x 没暴露 setup adapter | 升级到 v2.0.0+ | | ~/.openclaw/openclaw.json.clobbered.<ts> 不断生成 | 配置 validator 拒收,自动备份 → 还原 last-good | 看 .clobbered.* 里写了啥 → 修配置 → 重启 gateway | | 粉丝发消息没反应 | bindings 缺 wechat-service 反向路由 | 顶层 bindings 里加 {agentId, match:{channel:wechat-service,accountId:...}} |

日志 grep 模板

# 实时跟踪 wechat-service 全链路
tail -f /tmp/openclaw-gateway.log | grep -E "wechat-service|customer_service|errcode"

# 看一条消息从 inbound 到 outbound 全流程
grep -E "reqId=<具体id>|wechat-service-outbound" /tmp/openclaw-gateway.log

# 单看 outbound 是否真的发出去
grep "wechat-service-outbound sent" /tmp/openclaw-gateway.log

# 看签名/解密失败
grep -E "signature_invalid|decrypt_failed" /tmp/openclaw-gateway.log

# 看是不是 IP 白名单问题
grep "40164" /tmp/openclaw/openclaw-*.log

# 看配置是否被 clobber
ls -lt ~/.openclaw/openclaw.json.clobbered.* 2>/dev/null | head -3

期待看到的成功链路

粉丝发消息后日志按顺序应出现:

[wechat-service] inbound(http): reqId=xxx ... method=POST signed=true
[wechat-service] acked(placeholder) reqId=xxx accountId=default msgType=text from=oXXX
[wechat-service] inbound dispatch accountId=default agent=main from=oXXX
[wechat-service-outbound] sent text to openid=oXXX accountId=default (len=NNN)   ← 关键

少最后一条 = agent 没产出回复 / outbound 路由错 / 客服消息发送失败。按错误码对照排查。


🚦 完整最小可用配置(一键复制粘贴

下面这段直接覆盖 ~/.openclaw/openclaw.json 即可(替换 4 处 __REPLACE__):

{
  "agents": {
    "list": [
      { "id": "main" }
    ]
  },
  "bindings": [
    {
      "agentId": "main",
      "match": { "channel": "wechat-service", "accountId": "default" }
    }
  ],
  "channels": {
    "wechat-service": {
      "enabled": true,
      "defaultAccount": "default",
      "accounts": {
        "default": {
          "enabled": true,
          "name": "我的公众号",
          "appId": "__REPLACE_WX_APP_ID__",
          "appSecret": "__REPLACE_APP_SECRET__",
          "token": "__REPLACE_TOKEN__",
          "encodingAESKey": "__REPLACE_43_CHAR_AES_KEY__",
          "encryptMode": "safe",
          "replyMode": "async",
          "replyPlaceholderText": "收到,正在为你处理..."
        }
      },
      "dynamicAgents": {
        "enabled": false
      }
    }
  },
  "plugins": {
    "entries": {
      "wechat-service": { "enabled": true }
    }
  }
}

填好 4 个 __REPLACE__ 字段(来自公众号后台「基本配置」+ AppSecret),然后:

# 重启 gateway 加载新配置
pkill -9 -x openclaw-gateway && sleep 2
nohup openclaw gateway run --bind loopback --port 18789 --force \
  > /tmp/openclaw-gateway.log 2>&1 &

# 验证
sleep 5
openclaw channels list | grep 微信服务号
# 期待:微信服务号(公众号) default: configured, enabled

生产上线前再加dynamicAgents.enabled: true + adminUsers + permissionMode: admin-only(一粉一会话隔离 + 权限控制)。


🧪 脚本

npm run typecheck   # tsc --noEmit
npm test            # vitest run(13 个文件 184 个用例)
npm run build       # tsc → dist/

CI 在每次 publish 前会跑 prepublishOnly: typecheck


📚 资源

  • 微信公众平台官方文档:https://developers.weixin.qq.com/doc/service/guide/
  • OpenClaw 文档:https://docs.openclaw.ai/zh-CN
  • 本地知识库~/knowledge/huo15/2026-04-29-wechat-service-v2-wecom-mirror-refactor.md
  • 公司 Odoo 技术知识库:https://www.huo15.com/odoo/knowledge/

公司名称: 青岛火一五信息科技有限公司 联系邮箱: [email protected] | QQ群: 1093992108

📄 License

ISC © jobzhao([email protected]