ylib-openclaw-weixin 2.1.7 → 2.1.8-2
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 +18 -0
- package/README.zh_CN.md +18 -0
- package/index.ts +151 -47
- package/package.json +16 -6
- package/schema.json +211 -0
- package/scripts/generate-schema.mjs +30 -0
- package/src/api/api.ts +84 -9
- package/src/api/types.ts +14 -1
- package/src/auth/accounts.ts +34 -8
- package/src/auth/login-qr.ts +64 -33
- package/src/cdn/upload.ts +57 -7
- package/src/channel.ts +248 -51
- package/src/config/config-schema.ts +12 -2
- package/src/media/media-download.ts +9 -1
- package/src/media/mime.ts +6 -0
- package/src/messaging/endpoint-dispatch.ts +1553 -148
- package/src/messaging/error-notice.ts +11 -5
- package/src/messaging/im-runtime-telemetry.ts +97 -0
- package/src/messaging/inbound.ts +68 -9
- package/src/messaging/markdown-filter.ts +39 -2
- package/src/messaging/process-message.ts +179 -25
- package/src/messaging/send-media.ts +33 -6
- package/src/messaging/send.ts +567 -37
- package/src/messaging/slash-commands.ts +2 -1
- package/src/monitor/monitor.ts +183 -12
- package/src/storage/state-dir.ts +2 -2
package/README.md
CHANGED
|
@@ -310,3 +310,21 @@ Ensure `plugins.entries.openclaw-weixin.enabled` is `true` in `~/.openclaw/openc
|
|
|
310
310
|
openclaw config set plugins.entries.openclaw-weixin.enabled true
|
|
311
311
|
openclaw gateway restart
|
|
312
312
|
```
|
|
313
|
+
|
|
314
|
+
## Long Markdown Regression (One-Click)
|
|
315
|
+
|
|
316
|
+
Use this to run an end-to-end send with a real long markdown payload (links/images/code blocks included):
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
npm run regression:long-markdown -- \
|
|
320
|
+
--base-url https://weixin-gateway.example.com \
|
|
321
|
+
--to o9cq809SI88YrRxbFQXu39Lf3Xu8@im.wechat \
|
|
322
|
+
--context-token <context_token> \
|
|
323
|
+
--token <token> \
|
|
324
|
+
--repeat 120 \
|
|
325
|
+
--timeout-ms 45000
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Notes:
|
|
329
|
+
- This command builds first, then runs `scripts/regression-long-markdown.mjs`.
|
|
330
|
+
- It validates chunked sending behavior in real traffic.
|
package/README.zh_CN.md
CHANGED
|
@@ -309,3 +309,21 @@ openclaw plugins install @tencent-weixin/openclaw-weixin@legacy
|
|
|
309
309
|
openclaw config set plugins.entries.openclaw-weixin.enabled true
|
|
310
310
|
openclaw gateway restart
|
|
311
311
|
```
|
|
312
|
+
|
|
313
|
+
## 超长 Markdown 一键回归
|
|
314
|
+
|
|
315
|
+
用于在真实链路下发送“超长 markdown 样例”(含链接/图片/代码块):
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
npm run regression:long-markdown -- \
|
|
319
|
+
--base-url https://weixin-gateway.example.com \
|
|
320
|
+
--to o9cq809SI88YrRxbFQXu39Lf3Xu8@im.wechat \
|
|
321
|
+
--context-token <context_token> \
|
|
322
|
+
--token <token> \
|
|
323
|
+
--repeat 120 \
|
|
324
|
+
--timeout-ms 45000
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
说明:
|
|
328
|
+
- 命令会先构建,再执行 `scripts/regression-long-markdown.mjs`。
|
|
329
|
+
- 可用于验证分片发送在真实流量中的行为。
|
package/index.ts
CHANGED
|
@@ -2,7 +2,10 @@ import type { OpenClawPluginApi } from "ylib-openclaw/plugin-sdk";
|
|
|
2
2
|
import { buildChannelConfigSchema } from "ylib-openclaw/plugin-sdk";
|
|
3
3
|
|
|
4
4
|
import { weixinPlugin } from "./src/channel.js";
|
|
5
|
+
export { weixinPlugin } from "./src/channel.js";
|
|
5
6
|
import { resolveWeixinAccount } from "./src/auth/accounts.js";
|
|
7
|
+
import { getConfig, sendTyping } from "./src/api/api.js";
|
|
8
|
+
import { TypingStatus } from "./src/api/types.js";
|
|
6
9
|
import { assertHostCompatibility } from "./src/compat.js";
|
|
7
10
|
import { WeixinConfigSchema } from "./src/config/config-schema.js";
|
|
8
11
|
import {
|
|
@@ -10,7 +13,10 @@ import {
|
|
|
10
13
|
resolveWeixinAgentIdByBindings,
|
|
11
14
|
resolveWeixinEndpointConfig,
|
|
12
15
|
} from "./src/messaging/endpoint-dispatch.js";
|
|
13
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
sendMessageWeixin,
|
|
18
|
+
StreamingMarkdownFilter,
|
|
19
|
+
} from "./src/messaging/send.js";
|
|
14
20
|
import { setWeixinRuntime } from "./src/runtime.js";
|
|
15
21
|
|
|
16
22
|
export default {
|
|
@@ -41,18 +47,20 @@ export default {
|
|
|
41
47
|
};
|
|
42
48
|
const normalizeMockScope = (
|
|
43
49
|
params: any,
|
|
44
|
-
): { scopeType: "my_workspace" | "project"; projectId: string } => {
|
|
45
|
-
const rawScopeType = String(
|
|
50
|
+
): { scopeType: "workspace" | "my_workspace" | "project"; workspaceId: string; projectId: string } => {
|
|
51
|
+
const rawScopeType = String(
|
|
52
|
+
params?.scope_kind ||
|
|
53
|
+
params?.scopeKind ||
|
|
54
|
+
params?.scope_type ||
|
|
55
|
+
params?.scopeType ||
|
|
56
|
+
"",
|
|
57
|
+
)
|
|
46
58
|
.trim()
|
|
47
59
|
.toLowerCase();
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
) {
|
|
53
|
-
return { scopeType: "project", projectId: rawProjectId };
|
|
54
|
-
}
|
|
55
|
-
return { scopeType: "my_workspace", projectId: "" };
|
|
60
|
+
const workspaceId = String(
|
|
61
|
+
params?.workspace_id || params?.workspaceId || params?.project_id || params?.projectId || "",
|
|
62
|
+
).trim();
|
|
63
|
+
return { scopeType: "workspace", workspaceId, projectId: workspaceId };
|
|
56
64
|
};
|
|
57
65
|
const resolveMockTargetId = (params: any): string => {
|
|
58
66
|
return String(
|
|
@@ -63,6 +71,7 @@ export default {
|
|
|
63
71
|
"",
|
|
64
72
|
).trim();
|
|
65
73
|
};
|
|
74
|
+
const TRIGGER_TYPING_KEEPALIVE_INTERVAL_MS = 5000;
|
|
66
75
|
|
|
67
76
|
api.registerGatewayMethod(
|
|
68
77
|
"weixin.loginWithQrStart",
|
|
@@ -79,7 +88,9 @@ export default {
|
|
|
79
88
|
force: params?.force,
|
|
80
89
|
timeoutMs: params?.timeoutMs,
|
|
81
90
|
verbose: params?.verbose,
|
|
82
|
-
|
|
91
|
+
sessionKey: params?.sessionKey,
|
|
92
|
+
resumeOnly: params?.resumeOnly,
|
|
93
|
+
} as any);
|
|
83
94
|
return respond(true, result);
|
|
84
95
|
} catch (err) {
|
|
85
96
|
return respond(false, {
|
|
@@ -142,14 +153,38 @@ export default {
|
|
|
142
153
|
async ({ respond, cfg, params, accountId }: any) => {
|
|
143
154
|
const probeAccount = (weixinPlugin.status as any)?.probeAccount;
|
|
144
155
|
const resolveAccount = (weixinPlugin.config as any)?.resolveAccount;
|
|
145
|
-
if (
|
|
156
|
+
if (
|
|
157
|
+
typeof probeAccount !== "function" ||
|
|
158
|
+
typeof resolveAccount !== "function"
|
|
159
|
+
) {
|
|
146
160
|
return respond(false, {
|
|
147
161
|
error: "weixin status probeAccount not available",
|
|
148
162
|
});
|
|
149
163
|
}
|
|
150
164
|
try {
|
|
151
|
-
const
|
|
152
|
-
|
|
165
|
+
const forceProbeRaw = String(
|
|
166
|
+
params?.force_probe != null
|
|
167
|
+
? params?.force_probe
|
|
168
|
+
: params?.forceProbe != null
|
|
169
|
+
? params?.forceProbe
|
|
170
|
+
: "",
|
|
171
|
+
)
|
|
172
|
+
.trim()
|
|
173
|
+
.toLowerCase();
|
|
174
|
+
const forceProbe =
|
|
175
|
+
forceProbeRaw === "1" ||
|
|
176
|
+
forceProbeRaw === "true" ||
|
|
177
|
+
forceProbeRaw === "yes" ||
|
|
178
|
+
forceProbeRaw === "on";
|
|
179
|
+
const resolved = resolveAccount(
|
|
180
|
+
cfg,
|
|
181
|
+
params?.accountId ?? accountId,
|
|
182
|
+
);
|
|
183
|
+
const result = await probeAccount({
|
|
184
|
+
account: resolved,
|
|
185
|
+
forceProbe,
|
|
186
|
+
force_probe: forceProbe,
|
|
187
|
+
});
|
|
153
188
|
return respond(Boolean(result?.ok), result);
|
|
154
189
|
} catch (err) {
|
|
155
190
|
return respond(false, {
|
|
@@ -298,6 +333,7 @@ export default {
|
|
|
298
333
|
opts: {
|
|
299
334
|
baseUrl: account.baseUrl,
|
|
300
335
|
token: account.token,
|
|
336
|
+
accountId: account.accountId,
|
|
301
337
|
},
|
|
302
338
|
});
|
|
303
339
|
} catch (err) {
|
|
@@ -320,39 +356,107 @@ export default {
|
|
|
320
356
|
|
|
321
357
|
const senderId =
|
|
322
358
|
String(params?.senderId || targetId).trim() || targetId;
|
|
323
|
-
void
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
359
|
+
void (async () => {
|
|
360
|
+
let triggerTypingTicket = "";
|
|
361
|
+
let typingKeepaliveTimer: ReturnType<typeof setInterval> | null =
|
|
362
|
+
null;
|
|
363
|
+
let typingKeepaliveInFlight = false;
|
|
364
|
+
const sendTriggerTyping = async (status: number): Promise<void> => {
|
|
365
|
+
if (!triggerTypingTicket) return;
|
|
366
|
+
await sendTyping({
|
|
367
|
+
baseUrl: account.baseUrl,
|
|
368
|
+
token: account.token,
|
|
369
|
+
body: {
|
|
370
|
+
ilink_user_id: targetId,
|
|
371
|
+
typing_ticket: triggerTypingTicket,
|
|
372
|
+
status,
|
|
373
|
+
},
|
|
374
|
+
});
|
|
375
|
+
};
|
|
376
|
+
try {
|
|
377
|
+
try {
|
|
378
|
+
const cfgResp = await getConfig({
|
|
379
|
+
baseUrl: account.baseUrl,
|
|
380
|
+
token: account.token,
|
|
381
|
+
ilinkUserId: targetId,
|
|
382
|
+
});
|
|
383
|
+
triggerTypingTicket = String(cfgResp?.typing_ticket || "").trim();
|
|
384
|
+
if (triggerTypingTicket) {
|
|
385
|
+
await sendTriggerTyping(TypingStatus.TYPING);
|
|
386
|
+
typingKeepaliveTimer = setInterval(() => {
|
|
387
|
+
if (typingKeepaliveInFlight) return;
|
|
388
|
+
typingKeepaliveInFlight = true;
|
|
389
|
+
void sendTriggerTyping(TypingStatus.TYPING)
|
|
390
|
+
.catch((err) => {
|
|
391
|
+
const errText =
|
|
392
|
+
err instanceof Error ? err.message : String(err);
|
|
393
|
+
api.logger?.warn?.(
|
|
394
|
+
`[Weixin][MockTrigger] typing keepalive failed: ${errText}`,
|
|
395
|
+
);
|
|
396
|
+
})
|
|
397
|
+
.finally(() => {
|
|
398
|
+
typingKeepaliveInFlight = false;
|
|
399
|
+
});
|
|
400
|
+
}, TRIGGER_TYPING_KEEPALIVE_INTERVAL_MS);
|
|
401
|
+
}
|
|
402
|
+
} catch (err) {
|
|
403
|
+
const errText = err instanceof Error ? err.message : String(err);
|
|
404
|
+
api.logger?.warn?.(
|
|
405
|
+
`[Weixin][MockTrigger] typing start skipped: ${errText}`,
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
await dispatchWeixinViaEndpoint({
|
|
410
|
+
cfg,
|
|
411
|
+
accountId: account.accountId,
|
|
412
|
+
ctx: {
|
|
413
|
+
Body: content,
|
|
414
|
+
From: senderId,
|
|
415
|
+
To: targetId,
|
|
416
|
+
AccountId: account.accountId,
|
|
417
|
+
OriginatingChannel: "openclaw-weixin",
|
|
418
|
+
OriginatingTo: targetId,
|
|
419
|
+
MessageSid: `mock_${Date.now()}_${Math.random().toString(36).slice(2)}`,
|
|
420
|
+
Timestamp: Date.now(),
|
|
421
|
+
Provider: "openclaw-weixin",
|
|
422
|
+
ChatType: "direct",
|
|
423
|
+
},
|
|
424
|
+
endpointConfig,
|
|
425
|
+
routeAgentId: resolvedAgentId,
|
|
426
|
+
baseUrl: account.baseUrl,
|
|
427
|
+
token: account.token,
|
|
428
|
+
cdnBaseUrl: account.cdnBaseUrl,
|
|
429
|
+
});
|
|
430
|
+
} catch (err: unknown) {
|
|
431
|
+
const errText = err instanceof Error ? err.message : String(err);
|
|
432
|
+
if (api.logger?.error) {
|
|
433
|
+
api.logger.error(
|
|
434
|
+
`[Weixin][MockTrigger] async dispatch failed: ${errText}`,
|
|
435
|
+
);
|
|
436
|
+
} else {
|
|
437
|
+
// eslint-disable-next-line no-console -- fallback when runtime logger is unavailable
|
|
438
|
+
console.error(
|
|
439
|
+
`[Weixin][MockTrigger] async dispatch failed: ${errText}`,
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
} finally {
|
|
443
|
+
if (typingKeepaliveTimer) {
|
|
444
|
+
clearInterval(typingKeepaliveTimer);
|
|
445
|
+
typingKeepaliveTimer = null;
|
|
446
|
+
}
|
|
447
|
+
if (triggerTypingTicket) {
|
|
448
|
+
try {
|
|
449
|
+
await sendTriggerTyping(TypingStatus.CANCEL);
|
|
450
|
+
} catch (err) {
|
|
451
|
+
const errText =
|
|
452
|
+
err instanceof Error ? err.message : String(err);
|
|
453
|
+
api.logger?.warn?.(
|
|
454
|
+
`[Weixin][MockTrigger] typing cancel failed: ${errText}`,
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
354
458
|
}
|
|
355
|
-
});
|
|
459
|
+
})();
|
|
356
460
|
|
|
357
461
|
return respond(true, {
|
|
358
462
|
ok: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ylib-openclaw-weixin",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.8-2",
|
|
4
4
|
"description": "OpenClaw Weixin channel",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Tencent",
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
"!src/**/*.test.ts",
|
|
11
11
|
"!src/**/node_modules/",
|
|
12
12
|
"index.ts",
|
|
13
|
+
"schema.json",
|
|
14
|
+
"scripts/generate-schema.mjs",
|
|
13
15
|
"openclaw.plugin.json",
|
|
14
16
|
"README.md",
|
|
15
17
|
"README.zh_CN.md",
|
|
@@ -18,23 +20,31 @@
|
|
|
18
20
|
],
|
|
19
21
|
"scripts": {
|
|
20
22
|
"test": "vitest run --coverage",
|
|
23
|
+
"test:unit": "vitest run",
|
|
24
|
+
"test:e2e": "vitest run test/e2e",
|
|
25
|
+
"test:coverage": "vitest run --coverage",
|
|
21
26
|
"typecheck": "tsc --noEmit",
|
|
22
|
-
"build": "tsc"
|
|
27
|
+
"build": "tsc",
|
|
28
|
+
"regression:long-markdown": "npm run build && node ./scripts/regression-long-markdown.mjs",
|
|
29
|
+
"schema:generate": "node ./scripts/generate-schema.mjs",
|
|
30
|
+
"prepublishOnly": "npm run build && npm run schema:generate"
|
|
23
31
|
},
|
|
24
32
|
"engines": {
|
|
25
33
|
"node": ">=22"
|
|
26
34
|
},
|
|
27
35
|
"dependencies": {
|
|
36
|
+
"marked": "^15.0.12",
|
|
28
37
|
"qrcode-terminal": "0.12.0",
|
|
29
|
-
"
|
|
30
|
-
"
|
|
38
|
+
"ylib-openclaw": "2026.3.9-beta.5",
|
|
39
|
+
"zod": "4.3.6"
|
|
31
40
|
},
|
|
32
41
|
"devDependencies": {
|
|
42
|
+
"@vitest/coverage-istanbul": "^3.2.4",
|
|
33
43
|
"@vitest/coverage-v8": "^3.1.0",
|
|
34
|
-
"ylib-openclaw": "2026.3.9-beata.1",
|
|
35
44
|
"silk-wasm": "^3.7.1",
|
|
36
45
|
"typescript": "^5.8.0",
|
|
37
|
-
"vitest": "^3.1.0"
|
|
46
|
+
"vitest": "^3.1.0",
|
|
47
|
+
"ylib-openclaw": "2026.3.9-beta.5"
|
|
38
48
|
},
|
|
39
49
|
"openclaw": {
|
|
40
50
|
"extensions": [
|
package/schema.json
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
{
|
|
2
|
+
"pluginId": "openclaw-weixin",
|
|
3
|
+
"channel": "weixin",
|
|
4
|
+
"rawSchema": {
|
|
5
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"name": {
|
|
9
|
+
"type": "string"
|
|
10
|
+
},
|
|
11
|
+
"nickname": {
|
|
12
|
+
"type": "string"
|
|
13
|
+
},
|
|
14
|
+
"enabled": {
|
|
15
|
+
"type": "boolean"
|
|
16
|
+
},
|
|
17
|
+
"baseUrl": {
|
|
18
|
+
"default": "https://ilinkai.weixin.qq.com",
|
|
19
|
+
"type": "string"
|
|
20
|
+
},
|
|
21
|
+
"cdnBaseUrl": {
|
|
22
|
+
"default": "https://novac2c.cdn.weixin.qq.com/c2c",
|
|
23
|
+
"type": "string"
|
|
24
|
+
},
|
|
25
|
+
"routeTag": {
|
|
26
|
+
"type": "number"
|
|
27
|
+
},
|
|
28
|
+
"botToken": {
|
|
29
|
+
"type": "string"
|
|
30
|
+
},
|
|
31
|
+
"botId": {
|
|
32
|
+
"type": "string"
|
|
33
|
+
},
|
|
34
|
+
"modelName": {
|
|
35
|
+
"default": "main",
|
|
36
|
+
"type": "string"
|
|
37
|
+
},
|
|
38
|
+
"agentId": {
|
|
39
|
+
"default": "main",
|
|
40
|
+
"type": "string"
|
|
41
|
+
},
|
|
42
|
+
"gatewayBaseUrl": {
|
|
43
|
+
"type": "string"
|
|
44
|
+
},
|
|
45
|
+
"gatewayToken": {
|
|
46
|
+
"type": "string"
|
|
47
|
+
},
|
|
48
|
+
"uploadHost": {
|
|
49
|
+
"type": "string"
|
|
50
|
+
},
|
|
51
|
+
"showFinalAnswerOnly": {
|
|
52
|
+
"default": false,
|
|
53
|
+
"type": "boolean"
|
|
54
|
+
},
|
|
55
|
+
"scopeType": {
|
|
56
|
+
"default": "workspace",
|
|
57
|
+
"readOnly": true,
|
|
58
|
+
"type": "string"
|
|
59
|
+
},
|
|
60
|
+
"workspaceId": {
|
|
61
|
+
"default": "",
|
|
62
|
+
"readOnly": true,
|
|
63
|
+
"type": "string"
|
|
64
|
+
},
|
|
65
|
+
"projectId": {
|
|
66
|
+
"default": "",
|
|
67
|
+
"readOnly": true,
|
|
68
|
+
"type": "string"
|
|
69
|
+
},
|
|
70
|
+
"scope_kind": {
|
|
71
|
+
"readOnly": true,
|
|
72
|
+
"type": "string"
|
|
73
|
+
},
|
|
74
|
+
"scopeKind": {
|
|
75
|
+
"readOnly": true,
|
|
76
|
+
"type": "string"
|
|
77
|
+
},
|
|
78
|
+
"scope_type": {
|
|
79
|
+
"readOnly": true,
|
|
80
|
+
"type": "string"
|
|
81
|
+
},
|
|
82
|
+
"workspace_id": {
|
|
83
|
+
"readOnly": true,
|
|
84
|
+
"type": "string"
|
|
85
|
+
},
|
|
86
|
+
"project_id": {
|
|
87
|
+
"readOnly": true,
|
|
88
|
+
"type": "string"
|
|
89
|
+
},
|
|
90
|
+
"accounts": {
|
|
91
|
+
"type": "object",
|
|
92
|
+
"propertyNames": {
|
|
93
|
+
"type": "string"
|
|
94
|
+
},
|
|
95
|
+
"additionalProperties": {
|
|
96
|
+
"type": "object",
|
|
97
|
+
"properties": {
|
|
98
|
+
"name": {
|
|
99
|
+
"type": "string"
|
|
100
|
+
},
|
|
101
|
+
"nickname": {
|
|
102
|
+
"type": "string"
|
|
103
|
+
},
|
|
104
|
+
"enabled": {
|
|
105
|
+
"type": "boolean"
|
|
106
|
+
},
|
|
107
|
+
"baseUrl": {
|
|
108
|
+
"default": "https://ilinkai.weixin.qq.com",
|
|
109
|
+
"type": "string"
|
|
110
|
+
},
|
|
111
|
+
"cdnBaseUrl": {
|
|
112
|
+
"default": "https://novac2c.cdn.weixin.qq.com/c2c",
|
|
113
|
+
"type": "string"
|
|
114
|
+
},
|
|
115
|
+
"routeTag": {
|
|
116
|
+
"type": "number"
|
|
117
|
+
},
|
|
118
|
+
"botToken": {
|
|
119
|
+
"type": "string"
|
|
120
|
+
},
|
|
121
|
+
"botId": {
|
|
122
|
+
"type": "string"
|
|
123
|
+
},
|
|
124
|
+
"modelName": {
|
|
125
|
+
"default": "main",
|
|
126
|
+
"type": "string"
|
|
127
|
+
},
|
|
128
|
+
"agentId": {
|
|
129
|
+
"default": "main",
|
|
130
|
+
"type": "string"
|
|
131
|
+
},
|
|
132
|
+
"gatewayBaseUrl": {
|
|
133
|
+
"type": "string"
|
|
134
|
+
},
|
|
135
|
+
"gatewayToken": {
|
|
136
|
+
"type": "string"
|
|
137
|
+
},
|
|
138
|
+
"uploadHost": {
|
|
139
|
+
"type": "string"
|
|
140
|
+
},
|
|
141
|
+
"showFinalAnswerOnly": {
|
|
142
|
+
"default": false,
|
|
143
|
+
"type": "boolean"
|
|
144
|
+
},
|
|
145
|
+
"scopeType": {
|
|
146
|
+
"default": "workspace",
|
|
147
|
+
"readOnly": true,
|
|
148
|
+
"type": "string"
|
|
149
|
+
},
|
|
150
|
+
"workspaceId": {
|
|
151
|
+
"default": "",
|
|
152
|
+
"readOnly": true,
|
|
153
|
+
"type": "string"
|
|
154
|
+
},
|
|
155
|
+
"projectId": {
|
|
156
|
+
"default": "",
|
|
157
|
+
"readOnly": true,
|
|
158
|
+
"type": "string"
|
|
159
|
+
},
|
|
160
|
+
"scope_kind": {
|
|
161
|
+
"readOnly": true,
|
|
162
|
+
"type": "string"
|
|
163
|
+
},
|
|
164
|
+
"scopeKind": {
|
|
165
|
+
"readOnly": true,
|
|
166
|
+
"type": "string"
|
|
167
|
+
},
|
|
168
|
+
"scope_type": {
|
|
169
|
+
"readOnly": true,
|
|
170
|
+
"type": "string"
|
|
171
|
+
},
|
|
172
|
+
"workspace_id": {
|
|
173
|
+
"readOnly": true,
|
|
174
|
+
"type": "string"
|
|
175
|
+
},
|
|
176
|
+
"project_id": {
|
|
177
|
+
"readOnly": true,
|
|
178
|
+
"type": "string"
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
"required": [
|
|
182
|
+
"baseUrl",
|
|
183
|
+
"cdnBaseUrl",
|
|
184
|
+
"modelName",
|
|
185
|
+
"agentId",
|
|
186
|
+
"showFinalAnswerOnly",
|
|
187
|
+
"scopeType",
|
|
188
|
+
"workspaceId",
|
|
189
|
+
"projectId"
|
|
190
|
+
],
|
|
191
|
+
"additionalProperties": false
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
"channelConfigUpdatedAt": {
|
|
195
|
+
"type": "string"
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
"required": [
|
|
199
|
+
"baseUrl",
|
|
200
|
+
"cdnBaseUrl",
|
|
201
|
+
"modelName",
|
|
202
|
+
"agentId",
|
|
203
|
+
"showFinalAnswerOnly",
|
|
204
|
+
"scopeType",
|
|
205
|
+
"workspaceId",
|
|
206
|
+
"projectId"
|
|
207
|
+
],
|
|
208
|
+
"additionalProperties": false
|
|
209
|
+
},
|
|
210
|
+
"schemaVersion": 1
|
|
211
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
7
|
+
const entryPath = path.join(root, "dist", "index.js");
|
|
8
|
+
const outputPath = path.join(root, "schema.json");
|
|
9
|
+
|
|
10
|
+
if (!fs.existsSync(entryPath)) {
|
|
11
|
+
throw new Error("dist/index.js not found, run build first");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const mod = await import(pathToFileURL(entryPath).href);
|
|
15
|
+
const plugin = mod.default;
|
|
16
|
+
const rawSchema = plugin?.configSchema?.schema;
|
|
17
|
+
if (!rawSchema || typeof rawSchema !== "object" || Array.isArray(rawSchema)) {
|
|
18
|
+
throw new Error("failed to resolve weixin plugin raw schema from dist/index.js");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const payload = {
|
|
22
|
+
pluginId: "openclaw-weixin",
|
|
23
|
+
channel: "weixin",
|
|
24
|
+
rawSchema,
|
|
25
|
+
schemaVersion: 1,
|
|
26
|
+
// generatedAt: new Date().toISOString(),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
fs.writeFileSync(outputPath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
30
|
+
console.log(`[schema] generated ${outputPath}`);
|