openclaw-weixin 3.0.2 → 3.1.1
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.
- package/CHANGELOG.md +38 -0
- package/CHANGELOG_EN.md +47 -0
- package/README.md +101 -50
- package/README_EN.md +113 -57
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/src/auth/accounts.js +313 -18
- package/dist/src/auth/accounts.js.map +1 -1
- package/dist/src/channel.js +106 -52
- package/dist/src/channel.js.map +1 -1
- package/dist/src/messaging/error-notice.js +2 -1
- package/dist/src/messaging/error-notice.js.map +1 -1
- package/dist/src/messaging/inbound.js +13 -8
- package/dist/src/messaging/inbound.js.map +1 -1
- package/dist/src/messaging/process-message.js +3 -2
- package/dist/src/messaging/process-message.js.map +1 -1
- package/dist/src/messaging/send.js +16 -10
- package/dist/src/messaging/send.js.map +1 -1
- package/dist/src/messaging/slash-commands.js +3 -0
- package/dist/src/messaging/slash-commands.js.map +1 -1
- package/dist/src/monitor/monitor.js +2 -0
- package/dist/src/monitor/monitor.js.map +1 -1
- package/docs/architecture.md +95 -103
- package/docs/architecture_EN.md +136 -0
- package/docs/backend-api.md +187 -196
- package/docs/backend-api_EN.md +347 -0
- package/docs/guide.md +45 -55
- package/docs/guide_EN.md +110 -0
- package/index.ts +2 -2
- package/openclaw.plugin.json +4 -1
- package/package.json +16 -9
- package/docs/backend-api.zh_CN.md +0 -338
- package/docs/guide.zh_CN.md +0 -99
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
# Backend API Protocol
|
|
2
|
+
|
|
3
|
+
[Back to detailed guide](./guide_EN.md) |
|
|
4
|
+
[简体中文](./backend-api.md)
|
|
5
|
+
|
|
6
|
+
This document covers every Weixin backend endpoint used by the plugin for QR
|
|
7
|
+
login, lifecycle notifications, messaging, and media. The two QR login requests
|
|
8
|
+
always use Tencent's fixed service. A backend selected by the account's
|
|
9
|
+
post-login `baseurl` must implement the lifecycle, messaging, and media
|
|
10
|
+
endpoints.
|
|
11
|
+
|
|
12
|
+
QR creation and all post-login endpoints use `POST`; QR status polling uses
|
|
13
|
+
`GET`. All requests include:
|
|
14
|
+
|
|
15
|
+
| Header | Description |
|
|
16
|
+
|--------|-------------|
|
|
17
|
+
| `iLink-App-Id` | Plugin application ID |
|
|
18
|
+
| `iLink-App-ClientVersion` | Plugin version encoded as an unsigned integer |
|
|
19
|
+
| `SKRouteTag` | Optional configured route tag |
|
|
20
|
+
|
|
21
|
+
`POST` requests additionally include `Content-Type: application/json`,
|
|
22
|
+
`AuthorizationType: ilink_bot_token`, and a random base64-encoded
|
|
23
|
+
`X-WECHAT-UIN`. Authenticated post-login requests also include
|
|
24
|
+
`Authorization: Bearer <bot-token>`; QR status `GET` requests do not include
|
|
25
|
+
these `POST`-specific headers.
|
|
26
|
+
|
|
27
|
+
Authenticated post-login `POST` bodies include `base_info`; QR creation does
|
|
28
|
+
not. The message examples below omit it for readability.
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"base_info": {
|
|
33
|
+
"channel_version": "<plugin version>",
|
|
34
|
+
"bot_agent": "OpenClaw"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`bot_agent` is for observability only. Its supported format and configuration
|
|
40
|
+
are documented in the [detailed guide](./guide_EN.md#custom-botagent-optional).
|
|
41
|
+
|
|
42
|
+
## Endpoint List
|
|
43
|
+
|
|
44
|
+
| Method | Path | Description |
|
|
45
|
+
|--------|------|-------------|
|
|
46
|
+
| `POST` | `/ilink/bot/get_bot_qrcode?bot_type=3` | Create a QR login session |
|
|
47
|
+
| `GET` | `/ilink/bot/get_qrcode_status?qrcode=<opaque-id>` | Poll QR login status; accepts optional `verify_code` |
|
|
48
|
+
| `POST` | `/ilink/bot/msg/notifystart` | Notify backend that the channel started |
|
|
49
|
+
| `POST` | `/ilink/bot/msg/notifystop` | Notify backend that the channel stopped |
|
|
50
|
+
| `POST` | `/ilink/bot/getupdates` | Long-poll for new messages |
|
|
51
|
+
| `POST` | `/ilink/bot/sendmessage` | Send a message (text/image/video/file) |
|
|
52
|
+
| `POST` | `/ilink/bot/getuploadurl` | Get CDN upload pre-signed parameters |
|
|
53
|
+
| `POST` | `/ilink/bot/getconfig` | Get account config (typing ticket, etc.) |
|
|
54
|
+
| `POST` | `/ilink/bot/sendtyping` | Send/cancel typing status |
|
|
55
|
+
|
|
56
|
+
The first two rows describe the fixed QR login service. They are not sent to the
|
|
57
|
+
account's post-login `baseurl`.
|
|
58
|
+
|
|
59
|
+
## QR Login and Lifecycle
|
|
60
|
+
|
|
61
|
+
Create a QR session with:
|
|
62
|
+
|
|
63
|
+
```http
|
|
64
|
+
POST /ilink/bot/get_bot_qrcode?bot_type=3
|
|
65
|
+
Content-Type: application/json
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"local_token_list": []
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The response contains an opaque `qrcode` identifier and
|
|
75
|
+
`qrcode_img_content`, the URL rendered as the QR code. Poll
|
|
76
|
+
`GET /ilink/bot/get_qrcode_status?qrcode=<opaque-id>` until it reaches a
|
|
77
|
+
terminal state. The optional `verify_code` query parameter handles verification
|
|
78
|
+
challenges.
|
|
79
|
+
|
|
80
|
+
| Field | Type | Description |
|
|
81
|
+
|-------|------|-------------|
|
|
82
|
+
| `status` | `string` | `wait`, `scaned`, `need_verifycode`, `verify_code_blocked`, `expired`, `scaned_but_redirect`, `binded_redirect`, or `confirmed` |
|
|
83
|
+
| `bot_token` | `string?` | Bot credential returned after confirmation |
|
|
84
|
+
| `ilink_bot_id` | `string?` | Required account ID after confirmation |
|
|
85
|
+
| `baseurl` | `string?` | Account API base URL |
|
|
86
|
+
| `ilink_user_id` | `string?` | ID of the user who scanned the QR code |
|
|
87
|
+
| `redirect_host` | `string?` | New polling host for `scaned_but_redirect` |
|
|
88
|
+
|
|
89
|
+
After authentication, call `/ilink/bot/msg/notifystart` when the channel starts
|
|
90
|
+
and `/ilink/bot/msg/notifystop` when it stops. Both receive the standard
|
|
91
|
+
`base_info` body and return:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"ret": 0,
|
|
96
|
+
"errmsg": ""
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
QR identifiers, verification codes, bot tokens, account IDs, user IDs, and
|
|
101
|
+
context tokens are sensitive. Never place real values in logs or examples.
|
|
102
|
+
|
|
103
|
+
## getUpdates
|
|
104
|
+
|
|
105
|
+
Long-polling endpoint. The server responds when new messages arrive or on
|
|
106
|
+
timeout.
|
|
107
|
+
|
|
108
|
+
**Request body:**
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"get_updates_buf": ""
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
| Field | Type | Description |
|
|
117
|
+
|-------|------|-------------|
|
|
118
|
+
| `get_updates_buf` | `string` | Sync cursor from the previous response; empty string for the first request |
|
|
119
|
+
|
|
120
|
+
**Response body:**
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"ret": 0,
|
|
125
|
+
"msgs": [],
|
|
126
|
+
"get_updates_buf": "<new cursor>",
|
|
127
|
+
"longpolling_timeout_ms": 35000
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
| Field | Type | Description |
|
|
132
|
+
|-------|------|-------------|
|
|
133
|
+
| `ret` | `number` | Return code, `0` = success |
|
|
134
|
+
| `errcode` | `number?` | Error code (e.g., `-14` = stale token) |
|
|
135
|
+
| `errmsg` | `string?` | Error description |
|
|
136
|
+
| `msgs` | `WeixinMessage[]` | Message list (structure below) |
|
|
137
|
+
| `get_updates_buf` | `string` | New sync cursor to pass in the next request |
|
|
138
|
+
| `longpolling_timeout_ms` | `number?` | Server-suggested long-poll timeout for the next request (ms) |
|
|
139
|
+
|
|
140
|
+
## sendMessage
|
|
141
|
+
|
|
142
|
+
Send a message to a user.
|
|
143
|
+
|
|
144
|
+
**Request body:**
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"msg": {
|
|
149
|
+
"to_user_id": "<target user ID>",
|
|
150
|
+
"context_token": "<conversation context token>",
|
|
151
|
+
"item_list": [
|
|
152
|
+
{
|
|
153
|
+
"type": 1,
|
|
154
|
+
"text_item": { "text": "Hello" }
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Response body:**
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"ret": 0,
|
|
166
|
+
"errmsg": ""
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## getUploadUrl
|
|
171
|
+
|
|
172
|
+
Get CDN upload pre-signed parameters. Call this endpoint before uploading a file
|
|
173
|
+
to obtain `upload_param` and `thumb_upload_param`.
|
|
174
|
+
|
|
175
|
+
**Request body:**
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"filekey": "<file identifier>",
|
|
180
|
+
"media_type": 1,
|
|
181
|
+
"to_user_id": "<target user ID>",
|
|
182
|
+
"rawsize": 12345,
|
|
183
|
+
"rawfilemd5": "<plaintext MD5>",
|
|
184
|
+
"filesize": 12352,
|
|
185
|
+
"no_need_thumb": true,
|
|
186
|
+
"aeskey": "<32-character hex AES key>"
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
| Field | Type | Description |
|
|
191
|
+
|-------|------|-------------|
|
|
192
|
+
| `filekey` | `string` | Per-upload file identifier |
|
|
193
|
+
| `media_type` | `number` | `1` = IMAGE, `2` = VIDEO, `3` = FILE, `4` = VOICE |
|
|
194
|
+
| `to_user_id` | `string` | Target user ID |
|
|
195
|
+
| `rawsize` | `number` | Original file plaintext size |
|
|
196
|
+
| `rawfilemd5` | `string` | Original file plaintext MD5 |
|
|
197
|
+
| `filesize` | `number` | Ciphertext size after AES-128-ECB encryption |
|
|
198
|
+
| `no_need_thumb` | `boolean?` | Set `true` to omit thumbnail upload parameters |
|
|
199
|
+
| `aeskey` | `string?` | AES-128 key as 32 hexadecimal characters |
|
|
200
|
+
| `thumb_rawsize` | `number?` | Thumbnail plaintext size when a thumbnail is requested |
|
|
201
|
+
| `thumb_rawfilemd5` | `string?` | Thumbnail plaintext MD5 when requested |
|
|
202
|
+
| `thumb_filesize` | `number?` | Thumbnail ciphertext size when requested |
|
|
203
|
+
|
|
204
|
+
**Response body:**
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"upload_param": "<original image upload encrypted parameters>",
|
|
209
|
+
"upload_full_url": "https://cdn.example.test/upload",
|
|
210
|
+
"thumb_upload_param": "<optional thumbnail upload parameters>"
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
| Field | Type | Description |
|
|
215
|
+
|-------|------|-------------|
|
|
216
|
+
| `upload_param` | `string?` | Parameters used to construct the CDN upload URL |
|
|
217
|
+
| `upload_full_url` | `string?` | Complete CDN upload URL; takes precedence over `upload_param` |
|
|
218
|
+
| `thumb_upload_param` | `string?` | Optional thumbnail upload parameters |
|
|
219
|
+
|
|
220
|
+
## getConfig
|
|
221
|
+
|
|
222
|
+
Get account configuration, including the typing ticket.
|
|
223
|
+
|
|
224
|
+
**Request body:**
|
|
225
|
+
|
|
226
|
+
```json
|
|
227
|
+
{
|
|
228
|
+
"ilink_user_id": "<user ID>",
|
|
229
|
+
"context_token": "<optional, conversation context token>"
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Response body:**
|
|
234
|
+
|
|
235
|
+
```json
|
|
236
|
+
{
|
|
237
|
+
"ret": 0,
|
|
238
|
+
"errmsg": "",
|
|
239
|
+
"typing_ticket": "<base64-encoded typing ticket>"
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## sendTyping
|
|
244
|
+
|
|
245
|
+
Send or cancel the typing status indicator.
|
|
246
|
+
|
|
247
|
+
**Request body:**
|
|
248
|
+
|
|
249
|
+
```json
|
|
250
|
+
{
|
|
251
|
+
"ilink_user_id": "<user ID>",
|
|
252
|
+
"typing_ticket": "<obtained from getConfig>",
|
|
253
|
+
"status": 1
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
| Field | Type | Description |
|
|
258
|
+
|-------|------|-------------|
|
|
259
|
+
| `status` | `number` | `1` = typing, `2` = cancel typing |
|
|
260
|
+
|
|
261
|
+
**Response body:**
|
|
262
|
+
|
|
263
|
+
```json
|
|
264
|
+
{
|
|
265
|
+
"ret": 0,
|
|
266
|
+
"errmsg": ""
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Message Structure
|
|
271
|
+
|
|
272
|
+
### WeixinMessage
|
|
273
|
+
|
|
274
|
+
| Field | Type | Description |
|
|
275
|
+
|-------|------|-------------|
|
|
276
|
+
| `seq` | `number?` | Message sequence number |
|
|
277
|
+
| `message_id` | `number?` | Unique message ID |
|
|
278
|
+
| `from_user_id` | `string?` | Sender ID |
|
|
279
|
+
| `to_user_id` | `string?` | Receiver ID |
|
|
280
|
+
| `client_id` | `string?` | Client-generated message ID |
|
|
281
|
+
| `create_time_ms` | `number?` | Creation timestamp (ms) |
|
|
282
|
+
| `update_time_ms` | `number?` | Update timestamp (ms) |
|
|
283
|
+
| `delete_time_ms` | `number?` | Deletion timestamp (ms) |
|
|
284
|
+
| `session_id` | `string?` | Session ID |
|
|
285
|
+
| `group_id` | `string?` | Group ID |
|
|
286
|
+
| `message_type` | `number?` | `1` = USER, `2` = BOT |
|
|
287
|
+
| `message_state` | `number?` | `0` = NEW, `1` = GENERATING, `2` = FINISH |
|
|
288
|
+
| `item_list` | `MessageItem[]?` | Message content list |
|
|
289
|
+
| `context_token` | `string?` | Conversation context token, must be passed back when replying |
|
|
290
|
+
| `run_id` | `string?` | OpenClaw run ID for generated replies |
|
|
291
|
+
|
|
292
|
+
### MessageItem
|
|
293
|
+
|
|
294
|
+
| Field | Type | Description |
|
|
295
|
+
|-------|------|-------------|
|
|
296
|
+
| `type` | `number` | `1` TEXT, `2` IMAGE, `3` VOICE, `4` FILE, `5` VIDEO, `11` TOOL_CALL_START, `12` TOOL_CALL_RESULT |
|
|
297
|
+
| `create_time_ms` | `number?` | Item creation timestamp |
|
|
298
|
+
| `update_time_ms` | `number?` | Item update timestamp |
|
|
299
|
+
| `is_completed` | `boolean?` | Whether a progress item is complete |
|
|
300
|
+
| `msg_id` | `string?` | Item message ID |
|
|
301
|
+
| `text_item` | `{ text: string }?` | Text content |
|
|
302
|
+
| `image_item` | `ImageItem?` | Image (with CDN reference and AES key) |
|
|
303
|
+
| `voice_item` | `VoiceItem?` | Voice (SILK encoded) |
|
|
304
|
+
| `file_item` | `FileItem?` | File attachment |
|
|
305
|
+
| `video_item` | `VideoItem?` | Video |
|
|
306
|
+
| `ref_msg` | `RefMessage?` | Referenced message |
|
|
307
|
+
| `tool_call_start_item` | `{ tool_name?: string; tool_call_id?: string }?` | Tool invocation metadata |
|
|
308
|
+
| `tool_call_result_item` | `{ tool_name?: string; tool_call_id?: string; status?: string }?` | Tool completion metadata |
|
|
309
|
+
|
|
310
|
+
### Nested Item Structures
|
|
311
|
+
|
|
312
|
+
| Structure | Fields |
|
|
313
|
+
|-----------|--------|
|
|
314
|
+
| `RefMessage` | `message_item?: MessageItem`, `title?: string` |
|
|
315
|
+
| `ImageItem` | `media?: CDNMedia`, `thumb_media?: CDNMedia`, `aeskey?: string`, `url?: string`, `mid_size?: number`, `thumb_size?: number`, `thumb_height?: number`, `thumb_width?: number`, `hd_size?: number` |
|
|
316
|
+
| `VoiceItem` | `media?: CDNMedia`, `encode_type?: number`, `bits_per_sample?: number`, `sample_rate?: number`, `playtime?: number`, `text?: string` |
|
|
317
|
+
| `FileItem` | `media?: CDNMedia`, `file_name?: string`, `md5?: string`, `len?: string` |
|
|
318
|
+
| `VideoItem` | `media?: CDNMedia`, `video_size?: number`, `play_length?: number`, `video_md5?: string`, `thumb_media?: CDNMedia`, `thumb_size?: number`, `thumb_height?: number`, `thumb_width?: number` |
|
|
319
|
+
| `ToolCallStartItem` | `tool_name?: string`, `tool_call_id?: string` |
|
|
320
|
+
| `ToolCallResultItem` | `tool_name?: string`, `tool_call_id?: string`, `status?: string` |
|
|
321
|
+
|
|
322
|
+
### CDN Media Reference (CDNMedia)
|
|
323
|
+
|
|
324
|
+
All media types (image/voice/file/video) are transferred via CDN using
|
|
325
|
+
AES-128-ECB encryption:
|
|
326
|
+
|
|
327
|
+
| Field | Type | Description |
|
|
328
|
+
|-------|------|-------------|
|
|
329
|
+
| `encrypt_query_param` | `string?` | Encrypted parameters for CDN download/upload |
|
|
330
|
+
| `aes_key` | `string?` | Base64-encoded AES-128 key |
|
|
331
|
+
| `encrypt_type` | `number?` | Encryption metadata mode |
|
|
332
|
+
| `full_url` | `string?` | Complete download URL returned by the backend |
|
|
333
|
+
|
|
334
|
+
## CDN Upload Flow
|
|
335
|
+
|
|
336
|
+
1. Calculate the file's plaintext size, MD5, and ciphertext size after
|
|
337
|
+
AES-128-ECB encryption
|
|
338
|
+
2. If a thumbnail is needed (image/video), calculate the thumbnail's plaintext
|
|
339
|
+
and ciphertext parameters as well
|
|
340
|
+
3. Call `getUploadUrl` to get `upload_full_url` or `upload_param` (and optional
|
|
341
|
+
`thumb_upload_param`)
|
|
342
|
+
4. Encrypt the file content with AES-128-ECB and `POST` it to the CDN URL as
|
|
343
|
+
`application/octet-stream`
|
|
344
|
+
5. Encrypt and upload the thumbnail in the same way when requested
|
|
345
|
+
6. Read `x-encrypted-param` from the CDN response and use it as
|
|
346
|
+
`encrypt_query_param` in the `CDNMedia` reference
|
|
347
|
+
7. Include the reference in the `MessageItem` and send
|
package/docs/guide.md
CHANGED
|
@@ -1,40 +1,35 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 详细指南
|
|
2
2
|
|
|
3
|
-
[
|
|
3
|
+
[返回 README](../README.md) | [English](./guide_EN.md)
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 安装说明
|
|
6
6
|
|
|
7
|
-
###
|
|
7
|
+
### 包名与状态兼容性
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
[
|
|
11
|
-
`channels.openclaw-weixin
|
|
12
|
-
`~/.openclaw/openclaw-weixin/`
|
|
9
|
+
npm 包、插件 ID 和 channel ID 均为 `openclaw-weixin`。README 中的
|
|
10
|
+
[安装命令](../README.md#connect-wechat)会保留
|
|
11
|
+
`channels.openclaw-weixin`、`plugins.entries.openclaw-weixin` 和
|
|
12
|
+
`~/.openclaw/openclaw-weixin/` 状态路径。
|
|
13
13
|
|
|
14
|
-
`--force`
|
|
15
|
-
|
|
16
|
-
not copy the entire state directory for this replacement.
|
|
14
|
+
`--force` 允许 OpenClaw 覆盖内部 ID 相同的现有插件安装;它不会改变来源信任或
|
|
15
|
+
安全策略。OpenClaw 会自动轮换配置备份;此次替换无需复制整个状态目录。
|
|
17
16
|
|
|
18
|
-
###
|
|
17
|
+
### 安装限制
|
|
19
18
|
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
package therefore ships its compiled `dist/index.js` runtime and does not
|
|
27
|
-
build on the user's machine.
|
|
19
|
+
- 此社区 npm 包需通过 CLI 安装;OpenClaw Control UI 不能安装任意 npm、git
|
|
20
|
+
或本地路径来源的插件。
|
|
21
|
+
- Nix 模式(`OPENCLAW_NIX_MODE=1`)会禁止插件安装、更新、卸载、启用和停用
|
|
22
|
+
命令;请改动 Nix 配置源后重新构建。
|
|
23
|
+
- OpenClaw 安装插件依赖时会禁用生命周期脚本,因此本包直接携带编译后的
|
|
24
|
+
`dist/index.js`,无需在用户机器上构建。
|
|
28
25
|
|
|
29
|
-
##
|
|
26
|
+
## 自定义 BotAgent(可选)
|
|
30
27
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
Declaring your own app name makes it much easier to trace your traffic in
|
|
35
|
-
backend logs.
|
|
28
|
+
登录后的每条鉴权请求会带一个自我声明的 `bot_agent` 字段——类似 HTTP
|
|
29
|
+
`User-Agent`——用于后台日志归因和监控聚合。**默认值为 `OpenClaw`**。声明自己的
|
|
30
|
+
应用名能让你的流量在后台日志中更容易识别。
|
|
36
31
|
|
|
37
|
-
|
|
32
|
+
在 `openclaw.json` 中加一行即可:
|
|
38
33
|
|
|
39
34
|
```json
|
|
40
35
|
{
|
|
@@ -46,64 +41,59 @@ Add one line to `openclaw.json`:
|
|
|
46
41
|
}
|
|
47
42
|
```
|
|
48
43
|
|
|
49
|
-
|
|
44
|
+
**格式规范**(UA 风格):
|
|
50
45
|
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
- ASCII
|
|
54
|
-
-
|
|
55
|
-
`OpenClaw` if nothing valid remains
|
|
46
|
+
- 一个或多个 `Name/Version` token,空格分隔
|
|
47
|
+
- 每个 token 可选地跟一个 ` (comment)`
|
|
48
|
+
- 仅允许 ASCII 字符;总长 ≤ 256 字节
|
|
49
|
+
- 不合规的 token 在清洗时静默丢弃;如果最终为空,回退到 `OpenClaw`
|
|
56
50
|
|
|
57
|
-
|
|
51
|
+
可直接使用的示例:
|
|
58
52
|
|
|
59
53
|
- `MyBot/1.2.0`
|
|
60
54
|
- `MyBot/1.2.0 (region=cn;env=prod)`
|
|
61
55
|
- `MyBot/1.2.0 LangChain/0.3.5`
|
|
62
56
|
- `MyBot/1.2.0-rc.1+build.5`
|
|
63
57
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
added in a future version if needed.
|
|
58
|
+
**注意**:`bot_agent` 仅用于观测,**不参与鉴权或路由**。当前本插件实例下所有
|
|
59
|
+
已注册的 agent 共享同一个 `botAgent` 声明;如有需要按 agent 单独标识的场景,
|
|
60
|
+
可在后续版本扩展配置。
|
|
68
61
|
|
|
69
|
-
##
|
|
62
|
+
## 卸载
|
|
70
63
|
|
|
71
64
|
> [!WARNING]
|
|
72
|
-
>
|
|
73
|
-
> [
|
|
65
|
+
> 替换腾讯版时不要卸载,请使用 README 中的
|
|
66
|
+
> [安装命令](../README.md#connect-wechat)原位替换。
|
|
74
67
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
`channels.openclaw-weixin` configuration during uninstall.
|
|
68
|
+
如果以后可能重装,请先备份 `~/.openclaw/openclaw.json`:新版 OpenClaw
|
|
69
|
+
卸载时会删除插件条目及其拥有的 `channels.openclaw-weixin` 配置。
|
|
78
70
|
|
|
79
71
|
```bash
|
|
80
72
|
openclaw plugins uninstall openclaw-weixin
|
|
81
73
|
```
|
|
82
74
|
|
|
83
|
-
##
|
|
75
|
+
## 故障排查
|
|
84
76
|
|
|
85
|
-
### "requires OpenClaw >=2026.6.1"
|
|
77
|
+
### "requires OpenClaw >=2026.6.1" 报错
|
|
86
78
|
|
|
87
|
-
|
|
79
|
+
你的 OpenClaw 版本太旧,不兼容当前插件版本。检查版本:
|
|
88
80
|
|
|
89
81
|
```bash
|
|
90
82
|
openclaw --version
|
|
91
83
|
```
|
|
92
84
|
|
|
93
|
-
|
|
94
|
-
publish a legacy compatibility line.
|
|
85
|
+
请先升级 OpenClaw。社区包不发布旧宿主兼容版本线。
|
|
95
86
|
|
|
96
|
-
### Channel
|
|
87
|
+
### Channel 显示 "OK" 但未连接
|
|
97
88
|
|
|
98
|
-
|
|
99
|
-
probe the channel again:
|
|
89
|
+
启用插件,重载或重启实际承载 OpenClaw 的运行单元,然后再次探测:
|
|
100
90
|
|
|
101
91
|
```bash
|
|
102
92
|
openclaw plugins enable openclaw-weixin
|
|
103
93
|
openclaw channels status --probe
|
|
104
94
|
```
|
|
105
95
|
|
|
106
|
-
##
|
|
96
|
+
## 开发者文档
|
|
107
97
|
|
|
108
|
-
- [
|
|
109
|
-
- [
|
|
98
|
+
- [后端 API 协议](./backend-api.md)
|
|
99
|
+
- [架构说明](./architecture.md)
|
package/docs/guide_EN.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Detailed Guide
|
|
2
|
+
|
|
3
|
+
[Back to README](../README_EN.md) | [简体中文](./guide.md)
|
|
4
|
+
|
|
5
|
+
## Installation Details
|
|
6
|
+
|
|
7
|
+
### Package Names and State
|
|
8
|
+
|
|
9
|
+
The npm package, plugin id, and channel id are all `openclaw-weixin`. The
|
|
10
|
+
[install command](../README_EN.md#connect-wechat) preserves the existing
|
|
11
|
+
`channels.openclaw-weixin`, `plugins.entries.openclaw-weixin`, and
|
|
12
|
+
`~/.openclaw/openclaw-weixin/` state paths.
|
|
13
|
+
|
|
14
|
+
`--force` allows OpenClaw to overwrite an existing plugin installation with the
|
|
15
|
+
same internal id; it does not change source-trust or security policy. OpenClaw
|
|
16
|
+
rotates backups of its config automatically; do not copy the entire state
|
|
17
|
+
directory for this replacement.
|
|
18
|
+
|
|
19
|
+
### Limitations
|
|
20
|
+
|
|
21
|
+
- Use the CLI for this community npm package. OpenClaw's Control UI does not
|
|
22
|
+
install arbitrary npm, git, or local-path plugin sources.
|
|
23
|
+
- In Nix mode (`OPENCLAW_NIX_MODE=1`), plugin install, update, uninstall,
|
|
24
|
+
enable, and disable commands are intentionally disabled. Add the package and
|
|
25
|
+
config to the Nix source, then rebuild instead.
|
|
26
|
+
- OpenClaw installs plugin dependencies with lifecycle scripts disabled. This
|
|
27
|
+
package therefore ships its compiled `dist/index.js` runtime and does not
|
|
28
|
+
build on the user's machine.
|
|
29
|
+
|
|
30
|
+
## Custom BotAgent (optional)
|
|
31
|
+
|
|
32
|
+
Every authenticated post-login request to the WeChat backend carries a
|
|
33
|
+
self-declared `bot_agent` identifier — analogous to an HTTP `User-Agent` — used
|
|
34
|
+
for log attribution and monitoring aggregation. The default is `OpenClaw`.
|
|
35
|
+
Declaring your own app name makes it much easier to trace your traffic in
|
|
36
|
+
backend logs.
|
|
37
|
+
|
|
38
|
+
Add one line to `openclaw.json`:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"channels": {
|
|
43
|
+
"openclaw-weixin": {
|
|
44
|
+
"botAgent": "MyBot/1.2.0"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Format** (UA-style):
|
|
51
|
+
|
|
52
|
+
- One or more `Name/Version` tokens, space-separated
|
|
53
|
+
- Each token may optionally be followed by ` (comment)`
|
|
54
|
+
- ASCII only; total length ≤ 256 bytes
|
|
55
|
+
- Invalid tokens are silently dropped during sanitization; falls back to
|
|
56
|
+
`OpenClaw` if nothing valid remains
|
|
57
|
+
|
|
58
|
+
Examples that pass through unchanged:
|
|
59
|
+
|
|
60
|
+
- `MyBot/1.2.0`
|
|
61
|
+
- `MyBot/1.2.0 (region=cn;env=prod)`
|
|
62
|
+
- `MyBot/1.2.0 LangChain/0.3.5`
|
|
63
|
+
- `MyBot/1.2.0-rc.1+build.5`
|
|
64
|
+
|
|
65
|
+
**Note**: `bot_agent` is for observability only — it is not used for
|
|
66
|
+
authentication or routing. All registered agents on this plugin instance
|
|
67
|
+
currently share the same `botAgent` declaration; per-agent overrides may be
|
|
68
|
+
added in a future version if needed.
|
|
69
|
+
|
|
70
|
+
## Uninstall
|
|
71
|
+
|
|
72
|
+
> [!WARNING]
|
|
73
|
+
> Do not uninstall when replacing Tencent's package. Use the
|
|
74
|
+
> [install command](../README_EN.md#connect-wechat) instead.
|
|
75
|
+
|
|
76
|
+
Back up `~/.openclaw/openclaw.json` first if you may want to reinstall: current
|
|
77
|
+
OpenClaw versions remove the plugin entry and owned
|
|
78
|
+
`channels.openclaw-weixin` configuration during uninstall.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
openclaw plugins uninstall openclaw-weixin
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Troubleshooting
|
|
85
|
+
|
|
86
|
+
### "requires OpenClaw >=2026.6.1" error
|
|
87
|
+
|
|
88
|
+
Your OpenClaw version is too old for this plugin version. Check with:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
openclaw --version
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Upgrade OpenClaw before installing this package. The community package does not
|
|
95
|
+
publish a legacy compatibility line.
|
|
96
|
+
|
|
97
|
+
### Channel shows "OK" but doesn't connect
|
|
98
|
+
|
|
99
|
+
Enable the plugin, reload or restart the actual unit that runs OpenClaw, and
|
|
100
|
+
probe the channel again:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
openclaw plugins enable openclaw-weixin
|
|
104
|
+
openclaw channels status --probe
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Developer Documentation
|
|
108
|
+
|
|
109
|
+
- [Backend API protocol](./backend-api_EN.md)
|
|
110
|
+
- [Architecture](./architecture_EN.md)
|
package/index.ts
CHANGED
|
@@ -7,8 +7,8 @@ import { WeixinConfigSchema } from "./src/config/config-schema.js";
|
|
|
7
7
|
|
|
8
8
|
export default {
|
|
9
9
|
id: "openclaw-weixin",
|
|
10
|
-
name: "
|
|
11
|
-
description: "Weixin channel
|
|
10
|
+
name: "WeChat",
|
|
11
|
+
description: "Community-maintained WeChat (Weixin) channel plugin for OpenClaw using the iLink bot API.",
|
|
12
12
|
configSchema: buildChannelConfigSchema(WeixinConfigSchema),
|
|
13
13
|
register(api: OpenClawPluginApi) {
|
|
14
14
|
// Fail-fast: reject incompatible host versions before any side-effects.
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "openclaw-weixin",
|
|
3
|
-
"
|
|
3
|
+
"name": "WeChat",
|
|
4
|
+
"description": "Community-maintained WeChat (Weixin) channel plugin for OpenClaw using the iLink bot API.",
|
|
5
|
+
"icon": "https://openclaw-weixin.newfuture.cc/logo.svg",
|
|
6
|
+
"version": "3.1.1",
|
|
4
7
|
"channels": ["openclaw-weixin"],
|
|
5
8
|
"channelConfigs": {
|
|
6
9
|
"openclaw-weixin": {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openclaw-weixin",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "Community-maintained
|
|
3
|
+
"version": "3.1.1",
|
|
4
|
+
"description": "Community-maintained WeChat (Weixin) channel plugin for OpenClaw using the iLink bot API.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Tencent",
|
|
7
7
|
"contributors": [
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"check:versions": "node scripts/check-versions.mjs",
|
|
50
50
|
"check:static": "npm run check:versions && npm run check:style && npm run typecheck && npm run typecheck:tests",
|
|
51
51
|
"check:fast": "npm run check:static && npm run test:unit",
|
|
52
|
+
"audit:all": "npm audit --audit-level=moderate",
|
|
52
53
|
"audit:deps": "npm audit --omit=dev --omit=peer --audit-level=moderate",
|
|
53
54
|
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
54
55
|
"build": "npm run clean && tsc",
|
|
@@ -67,23 +68,29 @@
|
|
|
67
68
|
"openclaw": ">=2026.6.1"
|
|
68
69
|
},
|
|
69
70
|
"devDependencies": {
|
|
70
|
-
"@biomejs/biome": "2.5.
|
|
71
|
+
"@biomejs/biome": "2.5.7",
|
|
71
72
|
"@types/node": "^26.1.2",
|
|
72
73
|
"@vitest/coverage-v8": "^4.1.10",
|
|
73
74
|
"openclaw": "2026.7.1",
|
|
74
75
|
"silk-wasm": "^3.7.1",
|
|
76
|
+
"tar": "7.5.22",
|
|
75
77
|
"typescript": "^7.0.2",
|
|
76
78
|
"vitest": "^4.1.10"
|
|
77
79
|
},
|
|
78
80
|
"overrides": {
|
|
79
|
-
"@
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
"tar": "7.5.22"
|
|
81
|
+
"openclaw@2026.7.1": {
|
|
82
|
+
"@hono/node-server": "2.1.0",
|
|
83
|
+
"tar": "7.5.22",
|
|
84
|
+
"undici": "8.9.0"
|
|
85
|
+
}
|
|
85
86
|
},
|
|
86
87
|
"openclaw": {
|
|
88
|
+
"compat": {
|
|
89
|
+
"pluginApi": ">=2026.6.1"
|
|
90
|
+
},
|
|
91
|
+
"build": {
|
|
92
|
+
"openclawVersion": "2026.7.1"
|
|
93
|
+
},
|
|
87
94
|
"extensions": [
|
|
88
95
|
"./index.ts"
|
|
89
96
|
],
|