openclaw-weixin 2.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +175 -0
  2. package/CHANGELOG.zh_CN.md +171 -0
  3. package/LICENSE +28 -0
  4. package/README.md +371 -0
  5. package/README.zh_CN.md +358 -0
  6. package/dist/index.js +16 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/src/api/api.js +513 -0
  9. package/dist/src/api/api.js.map +1 -0
  10. package/dist/src/api/config-cache.js +64 -0
  11. package/dist/src/api/config-cache.js.map +1 -0
  12. package/dist/src/api/session-guard.js +49 -0
  13. package/dist/src/api/session-guard.js.map +1 -0
  14. package/dist/src/api/types.js +37 -0
  15. package/dist/src/api/types.js.map +1 -0
  16. package/dist/src/auth/accounts.js +318 -0
  17. package/dist/src/auth/accounts.js.map +1 -0
  18. package/dist/src/auth/login-qr.js +337 -0
  19. package/dist/src/auth/login-qr.js.map +1 -0
  20. package/dist/src/auth/pairing.js +104 -0
  21. package/dist/src/auth/pairing.js.map +1 -0
  22. package/dist/src/cdn/aes-ecb.js +19 -0
  23. package/dist/src/cdn/aes-ecb.js.map +1 -0
  24. package/dist/src/cdn/cdn-upload.js +72 -0
  25. package/dist/src/cdn/cdn-upload.js.map +1 -0
  26. package/dist/src/cdn/cdn-url.js +14 -0
  27. package/dist/src/cdn/cdn-url.js.map +1 -0
  28. package/dist/src/cdn/pic-decrypt.js +89 -0
  29. package/dist/src/cdn/pic-decrypt.js.map +1 -0
  30. package/dist/src/cdn/upload.js +115 -0
  31. package/dist/src/cdn/upload.js.map +1 -0
  32. package/dist/src/channel.js +498 -0
  33. package/dist/src/channel.js.map +1 -0
  34. package/dist/src/compat.js +70 -0
  35. package/dist/src/compat.js.map +1 -0
  36. package/dist/src/config/config-schema.js +20 -0
  37. package/dist/src/config/config-schema.js.map +1 -0
  38. package/dist/src/config/reply-progress.js +5 -0
  39. package/dist/src/config/reply-progress.js.map +1 -0
  40. package/dist/src/media/media-download.js +93 -0
  41. package/dist/src/media/media-download.js.map +1 -0
  42. package/dist/src/media/mime.js +73 -0
  43. package/dist/src/media/mime.js.map +1 -0
  44. package/dist/src/media/silk-transcode.js +64 -0
  45. package/dist/src/media/silk-transcode.js.map +1 -0
  46. package/dist/src/messaging/debug-mode.js +63 -0
  47. package/dist/src/messaging/debug-mode.js.map +1 -0
  48. package/dist/src/messaging/error-notice.js +29 -0
  49. package/dist/src/messaging/error-notice.js.map +1 -0
  50. package/dist/src/messaging/inbound.js +204 -0
  51. package/dist/src/messaging/inbound.js.map +1 -0
  52. package/dist/src/messaging/markdown-filter.js +367 -0
  53. package/dist/src/messaging/markdown-filter.js.map +1 -0
  54. package/dist/src/messaging/outbound-hooks.js +58 -0
  55. package/dist/src/messaging/outbound-hooks.js.map +1 -0
  56. package/dist/src/messaging/process-message.js +429 -0
  57. package/dist/src/messaging/process-message.js.map +1 -0
  58. package/dist/src/messaging/reply-progress-sender.js +93 -0
  59. package/dist/src/messaging/reply-progress-sender.js.map +1 -0
  60. package/dist/src/messaging/send-media.js +54 -0
  61. package/dist/src/messaging/send-media.js.map +1 -0
  62. package/dist/src/messaging/send.js +218 -0
  63. package/dist/src/messaging/send.js.map +1 -0
  64. package/dist/src/messaging/slash-commands.js +68 -0
  65. package/dist/src/messaging/slash-commands.js.map +1 -0
  66. package/dist/src/monitor/monitor.js +190 -0
  67. package/dist/src/monitor/monitor.js.map +1 -0
  68. package/dist/src/storage/state-dir.js +9 -0
  69. package/dist/src/storage/state-dir.js.map +1 -0
  70. package/dist/src/storage/sync-buf.js +64 -0
  71. package/dist/src/storage/sync-buf.js.map +1 -0
  72. package/dist/src/util/logger.js +120 -0
  73. package/dist/src/util/logger.js.map +1 -0
  74. package/dist/src/util/random.js +16 -0
  75. package/dist/src/util/random.js.map +1 -0
  76. package/dist/src/util/redact.js +52 -0
  77. package/dist/src/util/redact.js.map +1 -0
  78. package/index.ts +19 -0
  79. package/openclaw.plugin.json +20 -0
  80. package/package.json +109 -0
@@ -0,0 +1,358 @@
1
+ # openclaw-weixin
2
+
3
+ [English](./README.md)
4
+
5
+ 这是 [Tencent/openclaw-weixin](https://github.com/Tencent/openclaw-weixin)
6
+ 的社区维护发行版,为 OpenClaw 提供支持扫码登录的微信渠道。
7
+
8
+ > 社区 npm 包名、插件 ID 和 channel ID 均为 `openclaw-weixin`。现有的
9
+ > `channels.openclaw-weixin`、
10
+ > `plugins.entries.openclaw-weixin` 和
11
+ > `~/.openclaw/openclaw-weixin/` 数据继续使用原 ID。
12
+
13
+ ## 兼容性
14
+
15
+ | 要求 | 最低版本 |
16
+ |------|----------|
17
+ | OpenClaw | `2026.7.1` |
18
+ | Node.js | `>=22.22.3 <23`、`>=24.15.0 <25` 或 `>=25.9.0` |
19
+
20
+ 插件会在启动时检查 OpenClaw 宿主版本,低于最低版本时拒绝加载。推荐使用
21
+ Node.js 24.15.0。
22
+
23
+ ## 前提条件
24
+
25
+ 已安装 [OpenClaw](https://docs.openclaw.ai/install),且 `openclaw` CLI 可用。
26
+
27
+ 查看版本:`openclaw --version`
28
+
29
+ ## 安装
30
+
31
+ ```bash
32
+ openclaw plugins install npm:openclaw-weixin
33
+ openclaw config set plugins.entries.openclaw-weixin.enabled true
34
+ openclaw channels login --channel openclaw-weixin
35
+ openclaw gateway restart
36
+ ```
37
+
38
+ 终端会显示二维码,用手机扫码并确认授权;凭据会自动保存。重启后检查:
39
+
40
+ ```bash
41
+ openclaw plugins list
42
+ openclaw channels status --probe
43
+ ```
44
+
45
+ ## 从腾讯官方包原位切换
46
+
47
+ 请从 `@tencent-weixin/openclaw-weixin` 原位切换,**不要先卸载腾讯官方包**。
48
+ 新版 OpenClaw 在卸载插件时会删除该插件拥有的 channel 配置。
49
+
50
+ ```bash
51
+ openclaw plugins install npm:openclaw-weixin --force
52
+ openclaw gateway restart
53
+ openclaw plugins list
54
+ openclaw channels status --probe
55
+ ```
56
+
57
+ 强制安装会替换拥有同一个内部 `openclaw-weixin` 插件/channel ID 的包。新旧包
58
+ 不能同时启用。由于内部 ID 与状态目录未改变,原有 channel 配置和登录凭据通常
59
+ 会保留。
60
+
61
+ ## 安装限制
62
+
63
+ - 此社区 npm 包需通过 CLI 安装;OpenClaw Control UI 不能安装任意 npm、git
64
+ 或本地路径来源的插件。
65
+ - Nix 模式(`OPENCLAW_NIX_MODE=1`)会禁止插件安装、更新、卸载、启用和停用
66
+ 命令;请改动 Nix 配置源后重新构建。
67
+ - OpenClaw 安装插件依赖时会禁用生命周期脚本,因此本包直接携带编译后的
68
+ `dist/index.js`,无需在用户机器上构建。
69
+
70
+ ## 添加更多微信账号
71
+
72
+ ```bash
73
+ openclaw channels login --channel openclaw-weixin
74
+ ```
75
+
76
+ 每次扫码登录都会创建一个新的账号条目,支持多个微信号同时在线。
77
+
78
+ ## 多账号上下文隔离
79
+
80
+ 默认情况下,私聊可能共用同一会话桶。**多个微信号同时登录**时,建议按「账号 + 渠道 + 对端」隔离:
81
+
82
+ ```bash
83
+ openclaw config set session.dmScope per-account-channel-peer
84
+ ```
85
+
86
+ ## 自定义 BotAgent(可选)
87
+
88
+ 每条出站请求会带一个自我声明的 `bot_agent` 字段——类似 HTTP `User-Agent`——用于
89
+ 后台日志归因和监控聚合。**默认值为 `OpenClaw`**。声明自己的应用名能让你的流量
90
+ 在后台日志中更容易识别。
91
+
92
+ 在 `openclaw.json` 中加一行即可:
93
+
94
+ ```json
95
+ {
96
+ "channels": {
97
+ "openclaw-weixin": {
98
+ "botAgent": "MyBot/1.2.0"
99
+ }
100
+ }
101
+ }
102
+ ```
103
+
104
+ **格式规范**(UA 风格):
105
+
106
+ - 一个或多个 `Name/Version` token,空格分隔
107
+ - 每个 token 可选地跟一个 ` (comment)`
108
+ - 仅允许 ASCII 字符;总长 ≤ 256 字节
109
+ - 不合规的 token 在清洗时静默丢弃;如果最终为空,回退到 `OpenClaw`
110
+
111
+ 可直接使用的示例:
112
+
113
+ - `MyBot/1.2.0`
114
+ - `MyBot/1.2.0 (region=cn;env=prod)`
115
+ - `MyBot/1.2.0 LangChain/0.3.5`
116
+ - `MyBot/1.2.0-rc.1+build.5`
117
+
118
+ **注意**:`bot_agent` 仅用于观测,**不参与鉴权或路由**。当前本插件实例下所有
119
+ 已注册的 agent 共享同一个 `botAgent` 声明;如有需要按 agent 单独标识的场景,
120
+ 可在后续版本扩展配置。
121
+
122
+ ## 后端 API 协议
123
+
124
+ 本插件通过 HTTP JSON API 与后端网关通信。二次开发者若需对接自有后端,需实现以下接口。
125
+
126
+ 所有接口均为 `POST`,请求和响应均为 JSON。通用请求头:
127
+
128
+ | Header | 说明 |
129
+ |--------|------|
130
+ | `Content-Type` | `application/json` |
131
+ | `AuthorizationType` | 固定值 `ilink_bot_token` |
132
+ | `Authorization` | `Bearer <token>`(登录后获取) |
133
+ | `X-WECHAT-UIN` | 随机 uint32 的 base64 编码 |
134
+
135
+ ### 接口列表
136
+
137
+ | 接口 | 路径 | 说明 |
138
+ |------|------|------|
139
+ | getUpdates | `getupdates` | 长轮询获取新消息 |
140
+ | sendMessage | `sendmessage` | 发送消息(文本/图片/视频/文件) |
141
+ | getUploadUrl | `getuploadurl` | 获取 CDN 上传预签名 URL |
142
+ | getConfig | `getconfig` | 获取账号配置(typing ticket 等) |
143
+ | sendTyping | `sendtyping` | 发送/取消输入状态指示 |
144
+
145
+ ### getUpdates
146
+
147
+ 长轮询接口。服务端在有新消息或超时后返回。
148
+
149
+ **请求体:**
150
+
151
+ ```json
152
+ {
153
+ "get_updates_buf": ""
154
+ }
155
+ ```
156
+
157
+ | 字段 | 类型 | 说明 |
158
+ |------|------|------|
159
+ | `get_updates_buf` | `string` | 上次响应返回的同步游标,首次请求传空字符串 |
160
+
161
+ **响应体:**
162
+
163
+ ```json
164
+ {
165
+ "ret": 0,
166
+ "msgs": [...],
167
+ "get_updates_buf": "<新游标>",
168
+ "longpolling_timeout_ms": 35000
169
+ }
170
+ ```
171
+
172
+ | 字段 | 类型 | 说明 |
173
+ |------|------|------|
174
+ | `ret` | `number` | 返回码,`0` = 成功 |
175
+ | `errcode` | `number?` | 错误码(如 `-14` = 会话超时) |
176
+ | `errmsg` | `string?` | 错误描述 |
177
+ | `msgs` | `WeixinMessage[]` | 消息列表(结构见下方) |
178
+ | `get_updates_buf` | `string` | 新的同步游标,下次请求时回传 |
179
+ | `longpolling_timeout_ms` | `number?` | 服务端建议的下次长轮询超时(ms) |
180
+
181
+ ### sendMessage
182
+
183
+ 发送一条消息给用户。
184
+
185
+ **请求体:**
186
+
187
+ ```json
188
+ {
189
+ "msg": {
190
+ "to_user_id": "<目标用户 ID>",
191
+ "context_token": "<会话上下文令牌>",
192
+ "item_list": [
193
+ {
194
+ "type": 1,
195
+ "text_item": { "text": "你好" }
196
+ }
197
+ ]
198
+ }
199
+ }
200
+ ```
201
+
202
+ ### getUploadUrl
203
+
204
+ 获取 CDN 上传预签名参数。上传文件前需先调用此接口获取 `upload_param` 和 `thumb_upload_param`。
205
+
206
+ **请求体:**
207
+
208
+ ```json
209
+ {
210
+ "filekey": "<文件标识>",
211
+ "media_type": 1,
212
+ "to_user_id": "<目标用户 ID>",
213
+ "rawsize": 12345,
214
+ "rawfilemd5": "<明文 MD5>",
215
+ "filesize": 12352,
216
+ "thumb_rawsize": 1024,
217
+ "thumb_rawfilemd5": "<缩略图明文 MD5>",
218
+ "thumb_filesize": 1040
219
+ }
220
+ ```
221
+
222
+ | 字段 | 类型 | 说明 |
223
+ |------|------|------|
224
+ | `media_type` | `number` | `1` = IMAGE, `2` = VIDEO, `3` = FILE |
225
+ | `rawsize` | `number` | 原文件明文大小 |
226
+ | `rawfilemd5` | `string` | 原文件明文 MD5 |
227
+ | `filesize` | `number` | AES-128-ECB 加密后的密文大小 |
228
+ | `thumb_rawsize` | `number?` | 缩略图明文大小(IMAGE/VIDEO 时必填) |
229
+ | `thumb_rawfilemd5` | `string?` | 缩略图明文 MD5(IMAGE/VIDEO 时必填) |
230
+ | `thumb_filesize` | `number?` | 缩略图密文大小(IMAGE/VIDEO 时必填) |
231
+
232
+ **响应体:**
233
+
234
+ ```json
235
+ {
236
+ "upload_param": "<原图上传加密参数>",
237
+ "thumb_upload_param": "<缩略图上传加密参数>"
238
+ }
239
+ ```
240
+
241
+ ### getConfig
242
+
243
+ 获取账号配置,包括 typing ticket。
244
+
245
+ **请求体:**
246
+
247
+ ```json
248
+ {
249
+ "ilink_user_id": "<用户 ID>",
250
+ "context_token": "<可选,会话上下文令牌>"
251
+ }
252
+ ```
253
+
254
+ **响应体:**
255
+
256
+ ```json
257
+ {
258
+ "ret": 0,
259
+ "typing_ticket": "<base64 编码的 typing ticket>"
260
+ }
261
+ ```
262
+
263
+ ### sendTyping
264
+
265
+ 发送或取消输入状态指示。
266
+
267
+ **请求体:**
268
+
269
+ ```json
270
+ {
271
+ "ilink_user_id": "<用户 ID>",
272
+ "typing_ticket": "<从 getConfig 获取>",
273
+ "status": 1
274
+ }
275
+ ```
276
+
277
+ | 字段 | 类型 | 说明 |
278
+ |------|------|------|
279
+ | `status` | `number` | `1` = 正在输入,`2` = 取消输入 |
280
+
281
+ ### 消息结构
282
+
283
+ #### WeixinMessage
284
+
285
+ | 字段 | 类型 | 说明 |
286
+ |------|------|------|
287
+ | `seq` | `number?` | 消息序列号 |
288
+ | `message_id` | `number?` | 消息唯一 ID |
289
+ | `from_user_id` | `string?` | 发送者 ID |
290
+ | `to_user_id` | `string?` | 接收者 ID |
291
+ | `create_time_ms` | `number?` | 创建时间戳(ms) |
292
+ | `session_id` | `string?` | 会话 ID |
293
+ | `message_type` | `number?` | `1` = USER, `2` = BOT |
294
+ | `message_state` | `number?` | `0` = NEW, `1` = GENERATING, `2` = FINISH |
295
+ | `item_list` | `MessageItem[]?` | 消息内容列表 |
296
+ | `context_token` | `string?` | 会话上下文令牌,回复时需回传 |
297
+
298
+ #### MessageItem
299
+
300
+ | 字段 | 类型 | 说明 |
301
+ |------|------|------|
302
+ | `type` | `number` | `1` TEXT, `2` IMAGE, `3` VOICE, `4` FILE, `5` VIDEO |
303
+ | `text_item` | `{ text: string }?` | 文本内容 |
304
+ | `image_item` | `ImageItem?` | 图片(含 CDN 引用和 AES 密钥) |
305
+ | `voice_item` | `VoiceItem?` | 语音(SILK 编码) |
306
+ | `file_item` | `FileItem?` | 文件附件 |
307
+ | `video_item` | `VideoItem?` | 视频 |
308
+ | `ref_msg` | `RefMessage?` | 引用消息 |
309
+
310
+ #### CDN 媒体引用 (CDNMedia)
311
+
312
+ 所有媒体类型(图片/语音/文件/视频)通过 CDN 传输,使用 AES-128-ECB 加密:
313
+
314
+ | 字段 | 类型 | 说明 |
315
+ |------|------|------|
316
+ | `encrypt_query_param` | `string?` | CDN 下载/上传的加密参数 |
317
+ | `aes_key` | `string?` | base64 编码的 AES-128 密钥 |
318
+
319
+ ### CDN 上传流程
320
+
321
+ 1. 计算文件明文大小、MD5,以及 AES-128-ECB 加密后的密文大小
322
+ 2. 如需缩略图(图片/视频),同样计算缩略图的明文和密文参数
323
+ 3. 调用 `getUploadUrl` 获取 `upload_param`(和 `thumb_upload_param`)
324
+ 4. 使用 AES-128-ECB 加密文件内容,PUT 上传到 CDN URL
325
+ 5. 缩略图同理加密并上传
326
+ 6. 使用返回的 `encrypt_query_param` 构造 `CDNMedia` 引用,放入 `MessageItem` 发送
327
+
328
+ > 完整的类型定义见 [`src/api/types.ts`](src/api/types.ts),API 调用实现见 [`src/api/api.ts`](src/api/api.ts)。
329
+
330
+ ## 卸载
331
+
332
+ 如果以后可能重装,请先备份 `~/.openclaw/openclaw.json`:新版 OpenClaw
333
+ 卸载时会删除插件条目及其拥有的 `channels.openclaw-weixin` 配置。
334
+
335
+ ```bash
336
+ openclaw plugins uninstall openclaw-weixin
337
+ ```
338
+
339
+ ## 故障排查
340
+
341
+ ### "requires OpenClaw >=2026.7.1" 报错
342
+
343
+ 你的 OpenClaw 版本太旧,不兼容当前插件版本。检查版本:
344
+
345
+ ```bash
346
+ openclaw --version
347
+ ```
348
+
349
+ 请先升级 OpenClaw。社区包不发布旧宿主兼容版本线。
350
+
351
+ ### Channel 显示 "OK" 但未连接
352
+
353
+ 确保 `~/.openclaw/openclaw.json` 中 `plugins.entries.openclaw-weixin.enabled` 为 `true`:
354
+
355
+ ```bash
356
+ openclaw config set plugins.entries.openclaw-weixin.enabled true
357
+ openclaw gateway restart
358
+ ```
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
2
+ import { weixinPlugin } from "./src/channel.js";
3
+ import { assertHostCompatibility } from "./src/compat.js";
4
+ import { WeixinConfigSchema } from "./src/config/config-schema.js";
5
+ export default {
6
+ id: "openclaw-weixin",
7
+ name: "Weixin",
8
+ description: "Weixin channel (getUpdates long-poll + sendMessage)",
9
+ configSchema: buildChannelConfigSchema(WeixinConfigSchema),
10
+ register(api) {
11
+ // Fail-fast: reject incompatible host versions before any side-effects.
12
+ assertHostCompatibility(api.runtime?.version);
13
+ api.registerChannel({ plugin: weixinPlugin });
14
+ },
15
+ };
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,2CAA2C,CAAC;AAGrF,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEnE,eAAe;IACb,EAAE,EAAE,iBAAiB;IACrB,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,qDAAqD;IAClE,YAAY,EAAE,wBAAwB,CAAC,kBAAkB,CAAC;IAC1D,QAAQ,CAAC,GAAsB;QAC7B,wEAAwE;QACxE,uBAAuB,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAE9C,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;IAChD,CAAC;CACF,CAAC"}