@invago/mixin 1.0.7
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/README.md +281 -0
- package/README.zh-CN.md +291 -0
- package/eslint.config.mjs +25 -0
- package/index.ts +28 -0
- package/openclaw.plugin.json +9 -0
- package/package.json +1 -0
- package/src/blaze-service.ts +167 -0
- package/src/channel.ts +199 -0
- package/src/config-schema.ts +43 -0
- package/src/config.ts +63 -0
- package/src/crypto.ts +93 -0
- package/src/decrypt.ts +126 -0
- package/src/inbound-handler.ts +336 -0
- package/src/proxy.ts +42 -0
- package/src/reply-format.ts +281 -0
- package/src/runtime.ts +12 -0
- package/src/send-service.ts +553 -0
- package/tsconfig.json +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# MixinClaw
|
|
2
|
+
|
|
3
|
+
Connect [Mixin Messenger](https://mixin.one/messenger) to [OpenClaw](https://openclaw.ai).
|
|
4
|
+
|
|
5
|
+
**[Chinese Documentation](README.zh-CN.md)**
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
MixinClaw is an OpenClaw channel plugin. It runs in the same process as the OpenClaw Gateway, receives inbound messages from Mixin Blaze WebSocket, and delivers outbound messages over the Mixin HTTP API.
|
|
10
|
+
|
|
11
|
+
Important:
|
|
12
|
+
|
|
13
|
+
- Install the plugin on the same machine where the OpenClaw Gateway runs.
|
|
14
|
+
- OpenClaw config files use JSON5, so comments and trailing commas are allowed.
|
|
15
|
+
- The proxy configured by this plugin only affects this plugin.
|
|
16
|
+
|
|
17
|
+
## Recommended Install
|
|
18
|
+
|
|
19
|
+
Use the OpenClaw plugin installer:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
openclaw plugins install @invago/mixin
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`@invago/mixin` is the published npm package name. The OpenClaw runtime/plugin name remains `mixin`.
|
|
26
|
+
|
|
27
|
+
Then confirm the plugin is installed:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
openclaw plugins list
|
|
31
|
+
openclaw plugins info mixin
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Local Development Install
|
|
35
|
+
|
|
36
|
+
If you are developing locally, clone the repository and install dependencies:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
git clone https://github.com/invago/mixinclaw.git
|
|
40
|
+
cd mixinclaw
|
|
41
|
+
npm install
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Then install it into OpenClaw from the local path:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
openclaw plugins install .
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Create a Mixin Bot
|
|
51
|
+
|
|
52
|
+
Go to [Mixin Developers Dashboard](https://developers.mixin.one/dashboard), create a bot, and collect:
|
|
53
|
+
|
|
54
|
+
- `appId`
|
|
55
|
+
- `sessionId`
|
|
56
|
+
- `serverPublicKey`
|
|
57
|
+
- `sessionPrivateKey`
|
|
58
|
+
|
|
59
|
+
## Configuration
|
|
60
|
+
|
|
61
|
+
Edit your `openclaw.json` file manually and add both the channel configuration and the plugin enablement block:
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"channels": {
|
|
66
|
+
"mixin": {
|
|
67
|
+
"enabled": true,
|
|
68
|
+
"appId": "YOUR_APP_ID",
|
|
69
|
+
"sessionId": "YOUR_SESSION_ID",
|
|
70
|
+
"serverPublicKey": "YOUR_SERVER_PUBLIC_KEY_BASE64",
|
|
71
|
+
"sessionPrivateKey": "YOUR_SESSION_PRIVATE_KEY_BASE64",
|
|
72
|
+
"allowFrom": ["AUTHORIZED_USER_UUID"],
|
|
73
|
+
"proxy": {
|
|
74
|
+
"enabled": true,
|
|
75
|
+
"url": "socks5://127.0.0.1:10808",
|
|
76
|
+
"username": "proxy-user",
|
|
77
|
+
"password": "proxy-pass"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"plugins": {
|
|
82
|
+
"allow": ["mixin"],
|
|
83
|
+
"entries": {
|
|
84
|
+
"mixin": {
|
|
85
|
+
"enabled": true
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Notes:
|
|
93
|
+
|
|
94
|
+
- `channels.mixin` configures the channel itself.
|
|
95
|
+
- `plugins.allow` and `plugins.entries.mixin.enabled` are also required so OpenClaw loads this plugin.
|
|
96
|
+
- This plugin currently uses `allowFrom` as its sender allowlist. Do not assume other generic OpenClaw DM policy fields apply here unless the plugin explicitly supports them.
|
|
97
|
+
- If `proxy.url` already contains credentials, `proxy.username` and `proxy.password` can be omitted.
|
|
98
|
+
|
|
99
|
+
## Avoid Cross-Channel Session Mixing
|
|
100
|
+
|
|
101
|
+
Mixin group chats already stay isolated by channel, but direct-message sessions follow the OpenClaw `session.dmScope` policy. If you keep the default `main` scope, Mixin direct messages can share the same main session with other channels such as Feishu.
|
|
102
|
+
|
|
103
|
+
Recommended configuration:
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"session": {
|
|
108
|
+
"dmScope": "per-channel-peer"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Use `per-account-channel-peer` instead if you run multiple Mixin accounts and want direct-message sessions isolated by both channel and account.
|
|
114
|
+
|
|
115
|
+
## Configuration Reference
|
|
116
|
+
|
|
117
|
+
| Parameter | Required | Default | Description |
|
|
118
|
+
|-----------|----------|---------|-------------|
|
|
119
|
+
| `enabled` | No | `true` | Enable or disable this channel account |
|
|
120
|
+
| `appId` | Yes | - | Mixin App UUID |
|
|
121
|
+
| `sessionId` | Yes | - | Session UUID |
|
|
122
|
+
| `serverPublicKey` | Yes | - | Server Public Key (Base64) |
|
|
123
|
+
| `sessionPrivateKey` | Yes | - | Session Private Key (Ed25519 Base64) |
|
|
124
|
+
| `allowFrom` | No | `[]` | Authorized user UUID whitelist |
|
|
125
|
+
| `requireMentionInGroup` | No | `true` | Require trigger words in group chats |
|
|
126
|
+
| `debug` | No | `false` | Debug mode |
|
|
127
|
+
| `proxy.enabled` | No | `false` | Enable per-plugin proxy |
|
|
128
|
+
| `proxy.url` | Required when enabled | - | Proxy URL such as `http://127.0.0.1:7890` or `socks5://127.0.0.1:10808` |
|
|
129
|
+
| `proxy.username` | No | - | Proxy username |
|
|
130
|
+
| `proxy.password` | No | - | Proxy password |
|
|
131
|
+
|
|
132
|
+
## Proxy
|
|
133
|
+
|
|
134
|
+
- Both Mixin HTTP requests and Blaze WebSocket traffic use the same proxy.
|
|
135
|
+
- Supported proxy URL styles depend on the underlying proxy agent stack; typical values are `http://...`, `https://...`, and `socks5://...`.
|
|
136
|
+
- You must provide your own proxy software or proxy server. The plugin only consumes a proxy, it does not create one.
|
|
137
|
+
|
|
138
|
+
## Usage
|
|
139
|
+
|
|
140
|
+
- Direct message: `/status` or `Hello`
|
|
141
|
+
- Group message: `@Bot your question` with trigger words such as `?` or `help`
|
|
142
|
+
|
|
143
|
+
## Operations
|
|
144
|
+
|
|
145
|
+
Useful OpenClaw commands:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
openclaw plugins list
|
|
149
|
+
openclaw plugins info mixin
|
|
150
|
+
openclaw channels status --probe
|
|
151
|
+
openclaw status
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Plugin-specific command:
|
|
155
|
+
|
|
156
|
+
- Send `/mixin-outbox` to inspect the current pending queue size, next retry time, and latest error.
|
|
157
|
+
- Send `/mixin-outbox purge-invalid` to remove old `APP_CARD` / `APP_BUTTON_GROUP` entries that are stuck on permanent invalid-field errors.
|
|
158
|
+
|
|
159
|
+
## Delivery and Retry Behavior
|
|
160
|
+
|
|
161
|
+
- Outbound messages are persisted to a local outbox before send attempts.
|
|
162
|
+
- Failed sends are retried automatically until they succeed.
|
|
163
|
+
- Pending messages survive plugin restarts.
|
|
164
|
+
- Inbound Blaze messages are acknowledged before dispatch so Mixin receives a read receipt as early as possible.
|
|
165
|
+
|
|
166
|
+
## Explicit Reply Templates
|
|
167
|
+
|
|
168
|
+
When you want deterministic Mixin output instead of heuristic auto-selection, have the agent reply with exactly one fenced template block.
|
|
169
|
+
|
|
170
|
+
Text:
|
|
171
|
+
|
|
172
|
+
```text
|
|
173
|
+
```mixin-text
|
|
174
|
+
Short plain reply.
|
|
175
|
+
```
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Post:
|
|
179
|
+
|
|
180
|
+
```text
|
|
181
|
+
```mixin-post
|
|
182
|
+
# Release Notes
|
|
183
|
+
|
|
184
|
+
- Item 1
|
|
185
|
+
- Item 2
|
|
186
|
+
```
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Buttons:
|
|
190
|
+
|
|
191
|
+
```text
|
|
192
|
+
```mixin-buttons
|
|
193
|
+
{
|
|
194
|
+
"intro": "Choose an action",
|
|
195
|
+
"buttons": [
|
|
196
|
+
{ "label": "Open Docs", "action": "https://docs.openclaw.ai" },
|
|
197
|
+
{ "label": "Open Mixin", "action": "https://developers.mixin.one" }
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Card:
|
|
204
|
+
|
|
205
|
+
```text
|
|
206
|
+
```mixin-card
|
|
207
|
+
{
|
|
208
|
+
"title": "OpenClaw Docs",
|
|
209
|
+
"description": "Open the official documentation site.",
|
|
210
|
+
"action": "https://docs.openclaw.ai",
|
|
211
|
+
"coverUrl": "https://example.com/cover.png",
|
|
212
|
+
"shareable": true
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Rules:
|
|
218
|
+
|
|
219
|
+
- Explicit templates take priority over automatic detection.
|
|
220
|
+
- Replies containing tables or fenced code blocks are sent as `mixin-post` by default.
|
|
221
|
+
- `mixin-buttons` and `mixin-card` accept JSON only.
|
|
222
|
+
- Button and card links must use `http://` or `https://`.
|
|
223
|
+
- Mixin clients may require your target domains to be present in the bot app's `Resource Patterns` allowlist.
|
|
224
|
+
|
|
225
|
+
## Multi-Account Example
|
|
226
|
+
|
|
227
|
+
```json
|
|
228
|
+
{
|
|
229
|
+
"channels": {
|
|
230
|
+
"mixin": {
|
|
231
|
+
"accounts": {
|
|
232
|
+
"bot1": {
|
|
233
|
+
"name": "Customer Service Bot",
|
|
234
|
+
"appId": "...",
|
|
235
|
+
"sessionId": "...",
|
|
236
|
+
"serverPublicKey": "...",
|
|
237
|
+
"sessionPrivateKey": "...",
|
|
238
|
+
"allowFrom": ["..."]
|
|
239
|
+
},
|
|
240
|
+
"bot2": {
|
|
241
|
+
"name": "Tech Support Bot",
|
|
242
|
+
"appId": "...",
|
|
243
|
+
"sessionId": "...",
|
|
244
|
+
"serverPublicKey": "...",
|
|
245
|
+
"sessionPrivateKey": "...",
|
|
246
|
+
"proxy": {
|
|
247
|
+
"enabled": true,
|
|
248
|
+
"url": "http://127.0.0.1:7890"
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Troubleshooting
|
|
258
|
+
|
|
259
|
+
| Problem | What to check |
|
|
260
|
+
|---------|---------------|
|
|
261
|
+
| Plugin not loaded | Run `openclaw plugins list` and `openclaw plugins info mixin` |
|
|
262
|
+
| Channel not starting | Verify `channels.mixin` exists and credentials are complete |
|
|
263
|
+
| Not receiving messages | Check `allowFrom`, trigger words, and Blaze connectivity |
|
|
264
|
+
| Messages not sending | Check proxy reachability, outbox backlog, and `/mixin-outbox` output |
|
|
265
|
+
| Repeated inbound pushes | Check Blaze connectivity and confirm ACK logs/behavior |
|
|
266
|
+
|
|
267
|
+
## Security Notes
|
|
268
|
+
|
|
269
|
+
- Keep `sessionPrivateKey` private.
|
|
270
|
+
- Use `allowFrom` in production.
|
|
271
|
+
- Outbox files contain pending message bodies, so do not expose the `data/` directory.
|
|
272
|
+
|
|
273
|
+
## Links
|
|
274
|
+
|
|
275
|
+
- [OpenClaw Documentation](https://openclaw.ai)
|
|
276
|
+
- [OpenClaw Plugins](https://docs.openclaw.ai/tools/plugin)
|
|
277
|
+
- [OpenClaw Plugin CLI](https://docs.openclaw.ai/cli/plugins)
|
|
278
|
+
- [OpenClaw Configuration](https://docs.openclaw.ai/gateway/configuration)
|
|
279
|
+
- [OpenClaw Configuration Reference](https://docs.openclaw.ai/gateway/configuration-reference)
|
|
280
|
+
- [Mixin Developers Dashboard](https://developers.mixin.one/dashboard)
|
|
281
|
+
- [Mixin Bot API Documentation](https://developers.mixin.one/docs/bot-api)
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# MixinClaw
|
|
2
|
+
|
|
3
|
+
将 [Mixin Messenger](https://mixin.one/messenger) 接入 [OpenClaw](https://openclaw.ai)。
|
|
4
|
+
|
|
5
|
+
**[English Documentation](README.md)**
|
|
6
|
+
|
|
7
|
+
## 概览
|
|
8
|
+
|
|
9
|
+
MixinClaw 是一个 OpenClaw 频道插件。它运行在 OpenClaw Gateway 同一进程中,使用 Mixin Blaze WebSocket 接收消息,并通过 Mixin HTTP API 发送消息。
|
|
10
|
+
|
|
11
|
+
重要说明:
|
|
12
|
+
|
|
13
|
+
- 插件需要安装在 OpenClaw Gateway 所在的机器上。
|
|
14
|
+
- OpenClaw 配置文件是 `openclaw.json`,需要手动编辑。
|
|
15
|
+
- OpenClaw 配置文件是 JSON5 格式,支持注释和尾逗号。
|
|
16
|
+
- 这里配置的代理只作用于这个插件,不影响其他插件。
|
|
17
|
+
|
|
18
|
+
## 推荐安装方式
|
|
19
|
+
|
|
20
|
+
优先使用 OpenClaw 官方插件安装命令:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
openclaw plugins install @invago/mixin
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`@invago/mixin` 是发布后的 npm 包名,OpenClaw 内部的运行时/插件名称仍然是 `mixin`。
|
|
27
|
+
|
|
28
|
+
安装后可用以下命令确认:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
openclaw plugins list
|
|
32
|
+
openclaw plugins info mixin
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 本地开发安装
|
|
36
|
+
|
|
37
|
+
如果你是在本地开发,先克隆仓库并安装依赖:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git clone https://github.com/invago/mixinclaw.git
|
|
41
|
+
cd mixinclaw
|
|
42
|
+
npm install
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
然后通过本地路径安装到 OpenClaw:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
openclaw plugins install .
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## 创建 Mixin Bot
|
|
52
|
+
|
|
53
|
+
前往 [Mixin Developers Dashboard](https://developers.mixin.one/dashboard),创建机器人并记录以下凭证:
|
|
54
|
+
|
|
55
|
+
- `appId`
|
|
56
|
+
- `sessionId`
|
|
57
|
+
- `serverPublicKey`
|
|
58
|
+
- `sessionPrivateKey`
|
|
59
|
+
|
|
60
|
+
## 配置
|
|
61
|
+
|
|
62
|
+
手动编辑 `openclaw.json`,同时添加频道配置和插件启用配置:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"channels": {
|
|
67
|
+
"mixin": {
|
|
68
|
+
"enabled": true,
|
|
69
|
+
"appId": "你的 App ID",
|
|
70
|
+
"sessionId": "你的 Session ID",
|
|
71
|
+
"serverPublicKey": "服务端公钥 Base64",
|
|
72
|
+
"sessionPrivateKey": "会话私钥 Base64",
|
|
73
|
+
"allowFrom": ["授权用户 UUID"],
|
|
74
|
+
"proxy": {
|
|
75
|
+
"enabled": true,
|
|
76
|
+
"url": "socks5://127.0.0.1:10808",
|
|
77
|
+
"username": "proxy-user",
|
|
78
|
+
"password": "proxy-pass"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"plugins": {
|
|
83
|
+
"allow": ["mixin"],
|
|
84
|
+
"entries": {
|
|
85
|
+
"mixin": {
|
|
86
|
+
"enabled": true
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
说明:
|
|
94
|
+
|
|
95
|
+
- `channels.mixin` 负责配置这个频道本身。
|
|
96
|
+
- `plugins.allow` 和 `plugins.entries.mixin.enabled` 也需要配置,否则 OpenClaw 不会加载这个插件。
|
|
97
|
+
- 当前插件使用 `allowFrom` 作为发送者白名单,不要直接套用其他 OpenClaw 通用 DM 策略字段,除非插件明确支持。
|
|
98
|
+
- 如果 `proxy.url` 已经包含认证信息,可以不再填写 `proxy.username` 和 `proxy.password`。
|
|
99
|
+
|
|
100
|
+
## 避免跨通道串会话
|
|
101
|
+
|
|
102
|
+
Mixin 群聊本身会按频道隔离,但私聊会话是否独立,取决于 OpenClaw 的 `session.dmScope` 配置。如果保持默认的 `main`,Mixin 私聊可能会和飞书等其它通道共用同一个主会话。
|
|
103
|
+
|
|
104
|
+
推荐这样配置:
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"session": {
|
|
109
|
+
"dmScope": "per-channel-peer"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
如果你同时运行多个 Mixin 账号,并且希望私聊按“账号 + 频道”进一步隔离,可以改用 `per-account-channel-peer`。
|
|
115
|
+
|
|
116
|
+
## 配置参数
|
|
117
|
+
|
|
118
|
+
| 参数 | 必填 | 默认值 | 说明 |
|
|
119
|
+
|------|------|--------|------|
|
|
120
|
+
| `enabled` | 否 | `true` | 是否启用该频道账号 |
|
|
121
|
+
| `appId` | 是 | - | Mixin 应用 UUID |
|
|
122
|
+
| `sessionId` | 是 | - | 会话 UUID |
|
|
123
|
+
| `serverPublicKey` | 是 | - | 服务端公钥 Base64 |
|
|
124
|
+
| `sessionPrivateKey` | 是 | - | 会话私钥 Ed25519 Base64 |
|
|
125
|
+
| `allowFrom` | 否 | `[]` | 授权用户 UUID 白名单 |
|
|
126
|
+
| `requireMentionInGroup` | 否 | `true` | 群聊是否要求触发词 |
|
|
127
|
+
| `debug` | 否 | `false` | 调试模式 |
|
|
128
|
+
| `proxy.enabled` | 否 | `false` | 是否启用插件级代理 |
|
|
129
|
+
| `proxy.url` | 启用时必填 | - | 代理地址,例如 `http://127.0.0.1:7890` 或 `socks5://127.0.0.1:10808` |
|
|
130
|
+
| `proxy.username` | 否 | - | 代理用户名 |
|
|
131
|
+
| `proxy.password` | 否 | - | 代理密码 |
|
|
132
|
+
|
|
133
|
+
## 代理
|
|
134
|
+
|
|
135
|
+
- Mixin 的 HTTP 请求和 Blaze WebSocket 都会走同一个代理。
|
|
136
|
+
- 常见代理地址格式包括 `http://...`、`https://...`、`socks5://...`。
|
|
137
|
+
- 代理软件或代理服务器需要你自己提供,插件只负责使用代理。
|
|
138
|
+
|
|
139
|
+
## 使用方式
|
|
140
|
+
|
|
141
|
+
- 私聊:`/status` 或 `你好`
|
|
142
|
+
- 群聊:`@Bot 你的问题`,并带上 `?` 或 `help` 等触发词
|
|
143
|
+
|
|
144
|
+
## 运维
|
|
145
|
+
|
|
146
|
+
常用 OpenClaw 命令:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
openclaw plugins list
|
|
150
|
+
openclaw plugins info mixin
|
|
151
|
+
openclaw channels status --probe
|
|
152
|
+
openclaw status
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
插件内诊断命令:
|
|
156
|
+
|
|
157
|
+
- 发送 `/mixin-outbox` 可查看当前待发队列数量、下次重试时间和最近错误。
|
|
158
|
+
- 发送 `/mixin-outbox purge-invalid` 可删除历史遗留的 `APP_CARD` / `APP_BUTTON_GROUP` 永久无效重试项。
|
|
159
|
+
|
|
160
|
+
## 投递与重试行为
|
|
161
|
+
|
|
162
|
+
- 回复消息会先写入本地 outbox,再由后台 worker 发送。
|
|
163
|
+
- 发送失败会自动重试,直到发送成功。
|
|
164
|
+
- 插件重启后,未完成的消息仍会继续补发。
|
|
165
|
+
- 入站 Blaze 消息会在分发前尽快 ACK,尽量减少 Mixin 的重复推送。
|
|
166
|
+
|
|
167
|
+
## 显式回复模板
|
|
168
|
+
|
|
169
|
+
如果你希望 Mixin 回复严格按指定形式发送,而不是依赖自动判断,可以让 agent 只输出一个 fenced code block 模板。
|
|
170
|
+
|
|
171
|
+
文本:
|
|
172
|
+
|
|
173
|
+
```text
|
|
174
|
+
```mixin-text
|
|
175
|
+
简短纯文本回复
|
|
176
|
+
```
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
长文:
|
|
180
|
+
|
|
181
|
+
```text
|
|
182
|
+
```mixin-post
|
|
183
|
+
# 发布说明
|
|
184
|
+
|
|
185
|
+
- 条目 1
|
|
186
|
+
- 条目 2
|
|
187
|
+
```
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
按钮组:
|
|
191
|
+
|
|
192
|
+
```text
|
|
193
|
+
```mixin-buttons
|
|
194
|
+
{
|
|
195
|
+
"intro": "请选择操作",
|
|
196
|
+
"buttons": [
|
|
197
|
+
{ "label": "打开文档", "action": "https://docs.openclaw.ai" },
|
|
198
|
+
{ "label": "打开 Mixin", "action": "https://developers.mixin.one" }
|
|
199
|
+
]
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
卡片:
|
|
205
|
+
|
|
206
|
+
```text
|
|
207
|
+
```mixin-card
|
|
208
|
+
{
|
|
209
|
+
"title": "OpenClaw 文档",
|
|
210
|
+
"description": "打开官方文档站点。",
|
|
211
|
+
"action": "https://docs.openclaw.ai",
|
|
212
|
+
"coverUrl": "https://example.com/cover.png",
|
|
213
|
+
"shareable": true
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
规则:
|
|
219
|
+
|
|
220
|
+
- 显式模板优先级高于自动识别。
|
|
221
|
+
- 回复里只要出现表格或 fenced code block,默认就会走 `mixin-post` 长文。
|
|
222
|
+
- `mixin-buttons` 和 `mixin-card` 只接受 JSON。
|
|
223
|
+
- 按钮和卡片链接必须使用 `http://` 或 `https://`。
|
|
224
|
+
- Mixin 客户端可能要求目标域名已加入机器人应用的 `Resource Patterns` 白名单。
|
|
225
|
+
|
|
226
|
+
## 多账号示例
|
|
227
|
+
|
|
228
|
+
```json
|
|
229
|
+
{
|
|
230
|
+
"channels": {
|
|
231
|
+
"mixin": {
|
|
232
|
+
"accounts": {
|
|
233
|
+
"bot1": {
|
|
234
|
+
"name": "客服机器人",
|
|
235
|
+
"appId": "...",
|
|
236
|
+
"sessionId": "...",
|
|
237
|
+
"serverPublicKey": "...",
|
|
238
|
+
"sessionPrivateKey": "...",
|
|
239
|
+
"allowFrom": ["..."]
|
|
240
|
+
},
|
|
241
|
+
"bot2": {
|
|
242
|
+
"name": "技术支持机器人",
|
|
243
|
+
"appId": "...",
|
|
244
|
+
"sessionId": "...",
|
|
245
|
+
"serverPublicKey": "...",
|
|
246
|
+
"sessionPrivateKey": "...",
|
|
247
|
+
"proxy": {
|
|
248
|
+
"enabled": true,
|
|
249
|
+
"url": "http://127.0.0.1:7890"
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
"plugins": {
|
|
256
|
+
"allow": ["mixin"],
|
|
257
|
+
"entries": {
|
|
258
|
+
"mixin": {
|
|
259
|
+
"enabled": true
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## 故障排查
|
|
267
|
+
|
|
268
|
+
| 问题 | 检查项 |
|
|
269
|
+
|------|--------|
|
|
270
|
+
| 插件未加载 | 运行 `openclaw plugins list` 和 `openclaw plugins info mixin` |
|
|
271
|
+
| 频道未启动 | 检查 `channels.mixin` 是否存在,凭证是否完整 |
|
|
272
|
+
| 插件未启用 | 检查 `plugins.allow` 和 `plugins.entries.mixin.enabled` |
|
|
273
|
+
| 收不到消息 | 检查 `allowFrom`、触发词和 Blaze 连通性 |
|
|
274
|
+
| 消息发不出去 | 检查代理是否可达、outbox 堆积情况和 `/mixin-outbox` 输出 |
|
|
275
|
+
| 入站消息重复推送 | 检查 Blaze 连通性,并确认 ACK 是否正常发送 |
|
|
276
|
+
|
|
277
|
+
## 安全提示
|
|
278
|
+
|
|
279
|
+
- 妥善保管 `sessionPrivateKey`
|
|
280
|
+
- 生产环境务必配置 `allowFrom`
|
|
281
|
+
- outbox 文件会保存待发送消息正文,不要暴露 `data/` 目录
|
|
282
|
+
|
|
283
|
+
## 相关链接
|
|
284
|
+
|
|
285
|
+
- [OpenClaw 文档](https://openclaw.ai)
|
|
286
|
+
- [OpenClaw 插件文档](https://docs.openclaw.ai/tools/plugin)
|
|
287
|
+
- [OpenClaw 插件 CLI](https://docs.openclaw.ai/cli/plugins)
|
|
288
|
+
- [OpenClaw 配置说明](https://docs.openclaw.ai/gateway/configuration)
|
|
289
|
+
- [OpenClaw 配置参考](https://docs.openclaw.ai/gateway/configuration-reference)
|
|
290
|
+
- [Mixin Developers Dashboard](https://developers.mixin.one/dashboard)
|
|
291
|
+
- [Mixin Bot API 文档](https://developers.mixin.one/docs/bot-api)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import js from "@eslint/js";
|
|
2
|
+
import globals from "globals";
|
|
3
|
+
import tseslint from "typescript-eslint";
|
|
4
|
+
|
|
5
|
+
export default tseslint.config(
|
|
6
|
+
{
|
|
7
|
+
ignores: ["dist/**", "node_modules/**"],
|
|
8
|
+
},
|
|
9
|
+
js.configs.recommended,
|
|
10
|
+
...tseslint.configs.recommended,
|
|
11
|
+
{
|
|
12
|
+
files: ["**/*.ts"],
|
|
13
|
+
languageOptions: {
|
|
14
|
+
parserOptions: {
|
|
15
|
+
project: false,
|
|
16
|
+
},
|
|
17
|
+
globals: {
|
|
18
|
+
...globals.node,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
rules: {
|
|
22
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
);
|
package/index.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
|
+
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
3
|
+
import { mixinPlugin } from "./src/channel.js";
|
|
4
|
+
import { setMixinRuntime } from "./src/runtime.js";
|
|
5
|
+
|
|
6
|
+
// 全局错误处理
|
|
7
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
8
|
+
console.error('[mixin] Unhandled Rejection at:', promise, 'reason:', reason);
|
|
9
|
+
// 但不退出进程,让OpenClaw处理
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
process.on('uncaughtException', (error) => {
|
|
13
|
+
console.error('[mixin] Uncaught Exception:', error);
|
|
14
|
+
// 但不退出进程,让OpenClaw处理
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const plugin = {
|
|
18
|
+
id: "mixin",
|
|
19
|
+
name: "Mixin Messenger Channel",
|
|
20
|
+
description: "Mixin Messenger channel via Blaze WebSocket or HTTP Webhook",
|
|
21
|
+
configSchema: emptyPluginConfigSchema(),
|
|
22
|
+
register(api: OpenClawPluginApi): void {
|
|
23
|
+
setMixinRuntime(api.runtime);
|
|
24
|
+
api.registerChannel({ plugin: mixinPlugin });
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default plugin;
|
package/package.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"name":"@invago/mixin","version":"1.0.7","description":"Mixin Messenger channel plugin for OpenClaw","type":"module","main":"index.ts","scripts":{"dev":"nodemon --exec \"node --import jiti/register index.ts\" --ext ts","lint":"eslint src/**/*.ts index.ts","typecheck":"tsc --noEmit"},"peerDependencies":{"openclaw":">=2026.2.0"},"dependencies":{"@mixin.dev/mixin-node-sdk":"^7.4.1","@noble/curves":"^2.0.1","@noble/hashes":"^2.0.1","axios":"^1.6.0","express":"^5.2.1","proxy-agent":"^6.5.0","ws":"^8.18.3","zod":"^4.3.6"},"devDependencies":{"@eslint/js":"^10.0.1","@types/node":"^20.0.0","eslint":"^10.0.3","globals":"^17.4.0","jiti":"^1.21.0","nodemon":"^3.0.0","typescript":"^5.3.0","typescript-eslint":"^8.56.1"},"keywords":["openclaw","mixin","messenger","plugin","channel"],"author":"invagao","license":"MIT","repository":{"type":"git","url":"git+https://github.com/invago/mixinclaw.git"},"openclaw":{"extensions":["./index.ts"],"channel":{"id":"mixin","label":"Mixin Messenger","selectionLabel":"Mixin Messenger (Blaze WebSocket)","docsPath":"/channels/mixin","order":70,"aliases":["mixin-messenger","mixin"],"quickstartAllowFrom":true},"install":{"npmSpec":"@invago/mixin","localPath":"extensions/mixin"}}}
|