@pawastation/wechat-kf 0.1.2 → 0.2.0
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 +34 -28
- package/README.zh-CN.md +34 -28
- package/dist/index.d.ts +5 -15
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/src/accounts.d.ts +2 -1
- package/dist/src/accounts.js +61 -19
- package/dist/src/accounts.js.map +1 -1
- package/dist/src/api.d.ts +31 -2
- package/dist/src/api.js +41 -13
- package/dist/src/api.js.map +1 -1
- package/dist/src/bot.d.ts +10 -8
- package/dist/src/bot.js +231 -78
- package/dist/src/bot.js.map +1 -1
- package/dist/src/channel.d.ts +7 -106
- package/dist/src/channel.js +208 -71
- package/dist/src/channel.js.map +1 -1
- package/dist/src/config-schema.d.ts +0 -6
- package/dist/src/config-schema.js +2 -7
- package/dist/src/config-schema.js.map +1 -1
- package/dist/src/constants.d.ts +20 -0
- package/dist/src/constants.js +29 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/crypto.js +7 -6
- package/dist/src/crypto.js.map +1 -1
- package/dist/src/monitor.d.ts +27 -14
- package/dist/src/monitor.js +67 -120
- package/dist/src/monitor.js.map +1 -1
- package/dist/src/outbound.d.ts +10 -44
- package/dist/src/outbound.js +277 -92
- package/dist/src/outbound.js.map +1 -1
- package/dist/src/reply-dispatcher.d.ts +2 -6
- package/dist/src/reply-dispatcher.js +131 -32
- package/dist/src/reply-dispatcher.js.map +1 -1
- package/dist/src/runtime.d.ts +1 -119
- package/dist/src/runtime.js +2 -1
- package/dist/src/runtime.js.map +1 -1
- package/dist/src/send-utils.d.ts +13 -0
- package/dist/src/send-utils.js +56 -4
- package/dist/src/send-utils.js.map +1 -1
- package/dist/src/token.js +7 -3
- package/dist/src/token.js.map +1 -1
- package/dist/src/types.d.ts +68 -6
- package/dist/src/webhook.d.ts +16 -16
- package/dist/src/webhook.js +92 -75
- package/dist/src/webhook.js.map +1 -1
- package/dist/src/wechat-kf-directives.d.ts +132 -9
- package/dist/src/wechat-kf-directives.js +535 -24
- package/dist/src/wechat-kf-directives.js.map +1 -1
- package/index.ts +22 -12
- package/openclaw.plugin.json +1 -3
- package/package.json +3 -2
- package/dist/src/chunk-utils.d.ts +0 -18
- package/dist/src/chunk-utils.js +0 -58
- package/dist/src/chunk-utils.js.map +0 -1
package/index.ts
CHANGED
|
@@ -2,30 +2,40 @@
|
|
|
2
2
|
* WeChat KF (微信客服) OpenClaw Channel Plugin
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
6
|
+
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
5
7
|
import { wechatKfPlugin } from "./src/channel.js";
|
|
6
|
-
import {
|
|
8
|
+
import { setRuntime } from "./src/runtime.js";
|
|
9
|
+
import { handleWechatKfWebhook } from "./src/webhook.js";
|
|
7
10
|
|
|
8
|
-
export {
|
|
11
|
+
export {
|
|
12
|
+
sendBusinessCardMessage,
|
|
13
|
+
sendCaLinkMessage,
|
|
14
|
+
sendLocationMessage,
|
|
15
|
+
sendMiniprogramMessage,
|
|
16
|
+
sendMsgMenuMessage,
|
|
17
|
+
sendTextMessage,
|
|
18
|
+
syncMessages,
|
|
19
|
+
} from "./src/api.js";
|
|
9
20
|
export { wechatKfPlugin } from "./src/channel.js";
|
|
10
21
|
export { computeSignature, decrypt, encrypt, verifySignature } from "./src/crypto.js";
|
|
11
22
|
export { getAccessToken } from "./src/token.js";
|
|
12
23
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
const plugin: {
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
description: string;
|
|
28
|
+
configSchema: ReturnType<typeof emptyPluginConfigSchema>;
|
|
29
|
+
register: (api: OpenClawPluginApi) => void;
|
|
30
|
+
} = {
|
|
19
31
|
id: "wechat-kf",
|
|
20
32
|
name: "WeChat KF",
|
|
21
33
|
description: "WeChat Customer Service (企业微信客服) channel plugin",
|
|
22
|
-
|
|
23
|
-
// Channel config is handled via openclaw.plugin.json configSchema
|
|
24
|
-
// and the runtime schema in channel.ts → configSchema.
|
|
25
|
-
configSchema: { type: "object", additionalProperties: false, properties: {} },
|
|
34
|
+
configSchema: emptyPluginConfigSchema(),
|
|
26
35
|
register(api: OpenClawPluginApi) {
|
|
27
36
|
setRuntime(api.runtime);
|
|
28
37
|
api.registerChannel({ plugin: wechatKfPlugin });
|
|
38
|
+
api.registerHttpHandler(handleWechatKfWebhook);
|
|
29
39
|
},
|
|
30
40
|
};
|
|
31
41
|
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "wechat-kf",
|
|
3
3
|
"name": "WeChat Customer Service",
|
|
4
4
|
"description": "OpenClaw channel plugin for WeChat Customer Service (企业微信客服) via WeCom KF API",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.2.0",
|
|
6
6
|
"channels": ["wechat-kf"],
|
|
7
7
|
"configSchema": {
|
|
8
8
|
"type": "object",
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
"appSecret": { "type": "string", "description": "Self-built app secret (应用密钥)" },
|
|
13
13
|
"token": { "type": "string", "description": "Webhook callback token" },
|
|
14
14
|
"encodingAESKey": { "type": "string", "description": "43-character base64 AES key", "minLength": 43, "maxLength": 43 },
|
|
15
|
-
"webhookPort": { "type": "integer", "minimum": 1, "maximum": 65535, "default": 9999 },
|
|
16
15
|
"webhookPath": { "type": "string", "default": "/wechat-kf" },
|
|
17
16
|
"dmPolicy": { "type": "string", "enum": ["open", "pairing", "allowlist", "disabled"], "default": "open" },
|
|
18
17
|
"allowFrom": { "type": "array", "items": { "type": "string" } }
|
|
@@ -22,7 +21,6 @@
|
|
|
22
21
|
"appSecret": { "label": "App Secret", "placeholder": "Your WeCom app secret", "sensitive": true },
|
|
23
22
|
"token": { "label": "Callback Token", "placeholder": "Webhook verification token", "sensitive": true },
|
|
24
23
|
"encodingAESKey": { "label": "Encoding AES Key", "placeholder": "43-character base64 key", "sensitive": true },
|
|
25
|
-
"webhookPort": { "label": "Webhook Port", "placeholder": "9999" },
|
|
26
24
|
"webhookPath": { "label": "Webhook Path", "placeholder": "/wechat-kf" },
|
|
27
25
|
"dmPolicy": { "label": "DM Policy", "placeholder": "open" },
|
|
28
26
|
"allowFrom": { "label": "Allowlist", "placeholder": "List of allowed external user IDs" }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pawastation/wechat-kf",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "OpenClaw channel plugin for WeChat Customer Service (企业微信客服) — enables AI-powered customer service bots via WeCom KF API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -61,11 +61,12 @@
|
|
|
61
61
|
},
|
|
62
62
|
"packageManager": "pnpm@10.6.3",
|
|
63
63
|
"engines": {
|
|
64
|
-
"node": ">=
|
|
64
|
+
"node": ">=22.12.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@biomejs/biome": "^2.4.2",
|
|
68
68
|
"@types/node": "^25.2.3",
|
|
69
|
+
"openclaw": "^2026.2",
|
|
69
70
|
"typescript": "^5.9.3",
|
|
70
71
|
"vitest": "^3.0.0"
|
|
71
72
|
},
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Text chunking utilities for WeChat KF message splitting.
|
|
3
|
-
*
|
|
4
|
-
* Splits long text into chunks that fit within the WeChat character limit,
|
|
5
|
-
* preferring natural boundaries (newlines, then whitespace) before hard-cutting.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Split `text` into chunks of at most `limit` characters.
|
|
9
|
-
*
|
|
10
|
-
* Strategy (per chunk):
|
|
11
|
-
* 1. If remaining text fits within `limit`, emit it as the final chunk.
|
|
12
|
-
* 2. Look for the last newline (`\n`) within the first `limit` characters.
|
|
13
|
-
* 3. Failing that, look for the last whitespace character.
|
|
14
|
-
* 4. Failing that, hard-cut at exactly `limit` characters.
|
|
15
|
-
*
|
|
16
|
-
* Chunks are trimmed; empty chunks are never returned.
|
|
17
|
-
*/
|
|
18
|
-
export declare function chunkText(text: string, limit: number): string[];
|
package/dist/src/chunk-utils.js
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Text chunking utilities for WeChat KF message splitting.
|
|
3
|
-
*
|
|
4
|
-
* Splits long text into chunks that fit within the WeChat character limit,
|
|
5
|
-
* preferring natural boundaries (newlines, then whitespace) before hard-cutting.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Split `text` into chunks of at most `limit` characters.
|
|
9
|
-
*
|
|
10
|
-
* Strategy (per chunk):
|
|
11
|
-
* 1. If remaining text fits within `limit`, emit it as the final chunk.
|
|
12
|
-
* 2. Look for the last newline (`\n`) within the first `limit` characters.
|
|
13
|
-
* 3. Failing that, look for the last whitespace character.
|
|
14
|
-
* 4. Failing that, hard-cut at exactly `limit` characters.
|
|
15
|
-
*
|
|
16
|
-
* Chunks are trimmed; empty chunks are never returned.
|
|
17
|
-
*/
|
|
18
|
-
export function chunkText(text, limit) {
|
|
19
|
-
if (limit <= 0)
|
|
20
|
-
return [];
|
|
21
|
-
if (text.length <= limit) {
|
|
22
|
-
const trimmed = text.trim();
|
|
23
|
-
return trimmed.length > 0 ? [trimmed] : [];
|
|
24
|
-
}
|
|
25
|
-
const chunks = [];
|
|
26
|
-
let remaining = text;
|
|
27
|
-
while (remaining.length > 0) {
|
|
28
|
-
if (remaining.length <= limit) {
|
|
29
|
-
const trimmed = remaining.trim();
|
|
30
|
-
if (trimmed.length > 0) {
|
|
31
|
-
chunks.push(trimmed);
|
|
32
|
-
}
|
|
33
|
-
break;
|
|
34
|
-
}
|
|
35
|
-
const window = remaining.slice(0, limit);
|
|
36
|
-
// Try to split at the last newline within the window
|
|
37
|
-
let splitIdx = window.lastIndexOf("\n");
|
|
38
|
-
// Fall back to last whitespace
|
|
39
|
-
if (splitIdx <= 0) {
|
|
40
|
-
splitIdx = window.lastIndexOf(" ");
|
|
41
|
-
}
|
|
42
|
-
if (splitIdx <= 0) {
|
|
43
|
-
splitIdx = window.lastIndexOf("\t");
|
|
44
|
-
}
|
|
45
|
-
// Hard-cut if no suitable boundary found
|
|
46
|
-
if (splitIdx <= 0) {
|
|
47
|
-
splitIdx = limit;
|
|
48
|
-
}
|
|
49
|
-
const chunk = remaining.slice(0, splitIdx).trim();
|
|
50
|
-
if (chunk.length > 0) {
|
|
51
|
-
chunks.push(chunk);
|
|
52
|
-
}
|
|
53
|
-
// Advance past the split point (skip the delimiter character when splitting on boundary)
|
|
54
|
-
remaining = remaining.slice(splitIdx).trimStart();
|
|
55
|
-
}
|
|
56
|
-
return chunks;
|
|
57
|
-
}
|
|
58
|
-
//# sourceMappingURL=chunk-utils.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-utils.js","sourceRoot":"","sources":["../../src/chunk-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,KAAa;IACnD,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAC1B,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7C,CAAC;IAED,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,SAAS,GAAG,IAAI,CAAC;IAErB,OAAO,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,IAAI,SAAS,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;YACjC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvB,CAAC;YACD,MAAM;QACR,CAAC;QAED,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAEzC,qDAAqD;QACrD,IAAI,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAExC,+BAA+B;QAC/B,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YAClB,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACrC,CAAC;QACD,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YAClB,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC;QAED,yCAAyC;QACzC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YAClB,QAAQ,GAAG,KAAK,CAAC;QACnB,CAAC;QAED,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QAClD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;QAED,yFAAyF;QACzF,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE,CAAC;IACpD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|