@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.
Files changed (55) hide show
  1. package/README.md +34 -28
  2. package/README.zh-CN.md +34 -28
  3. package/dist/index.d.ts +5 -15
  4. package/dist/index.js +5 -5
  5. package/dist/index.js.map +1 -1
  6. package/dist/src/accounts.d.ts +2 -1
  7. package/dist/src/accounts.js +61 -19
  8. package/dist/src/accounts.js.map +1 -1
  9. package/dist/src/api.d.ts +31 -2
  10. package/dist/src/api.js +41 -13
  11. package/dist/src/api.js.map +1 -1
  12. package/dist/src/bot.d.ts +10 -8
  13. package/dist/src/bot.js +231 -78
  14. package/dist/src/bot.js.map +1 -1
  15. package/dist/src/channel.d.ts +7 -106
  16. package/dist/src/channel.js +208 -71
  17. package/dist/src/channel.js.map +1 -1
  18. package/dist/src/config-schema.d.ts +0 -6
  19. package/dist/src/config-schema.js +2 -7
  20. package/dist/src/config-schema.js.map +1 -1
  21. package/dist/src/constants.d.ts +20 -0
  22. package/dist/src/constants.js +29 -0
  23. package/dist/src/constants.js.map +1 -1
  24. package/dist/src/crypto.js +7 -6
  25. package/dist/src/crypto.js.map +1 -1
  26. package/dist/src/monitor.d.ts +27 -14
  27. package/dist/src/monitor.js +67 -120
  28. package/dist/src/monitor.js.map +1 -1
  29. package/dist/src/outbound.d.ts +10 -44
  30. package/dist/src/outbound.js +277 -92
  31. package/dist/src/outbound.js.map +1 -1
  32. package/dist/src/reply-dispatcher.d.ts +2 -6
  33. package/dist/src/reply-dispatcher.js +131 -32
  34. package/dist/src/reply-dispatcher.js.map +1 -1
  35. package/dist/src/runtime.d.ts +1 -119
  36. package/dist/src/runtime.js +2 -1
  37. package/dist/src/runtime.js.map +1 -1
  38. package/dist/src/send-utils.d.ts +13 -0
  39. package/dist/src/send-utils.js +56 -4
  40. package/dist/src/send-utils.js.map +1 -1
  41. package/dist/src/token.js +7 -3
  42. package/dist/src/token.js.map +1 -1
  43. package/dist/src/types.d.ts +68 -6
  44. package/dist/src/webhook.d.ts +16 -16
  45. package/dist/src/webhook.js +92 -75
  46. package/dist/src/webhook.js.map +1 -1
  47. package/dist/src/wechat-kf-directives.d.ts +132 -9
  48. package/dist/src/wechat-kf-directives.js +535 -24
  49. package/dist/src/wechat-kf-directives.js.map +1 -1
  50. package/index.ts +22 -12
  51. package/openclaw.plugin.json +1 -3
  52. package/package.json +3 -2
  53. package/dist/src/chunk-utils.d.ts +0 -18
  54. package/dist/src/chunk-utils.js +0 -58
  55. package/dist/src/chunk-utils.js.map +0 -1
@@ -1,3 +1,26 @@
1
+ import { homedir } from "node:os";
2
+ /** Channel identifier — single source of truth for the plugin ID string. */
3
+ export const CHANNEL_ID = "wechat-kf";
4
+ /** Default webhook path registered on the framework's shared gateway. */
5
+ export const DEFAULT_WEBHOOK_PATH = `/${CHANNEL_ID}`;
6
+ /** Config key prefix for this channel in OpenClaw config. */
7
+ export const CONFIG_KEY = `channels.${CHANNEL_ID}`;
8
+ /** Build a log-tag prefix: `[wechat-kf]` or `[wechat-kf:kfId]`. */
9
+ export function logTag(kfId) {
10
+ return kfId ? `[${CHANNEL_ID}:${kfId}]` : `[${CHANNEL_ID}]`;
11
+ }
12
+ /** Default state directory for cursor and kfid persistence. */
13
+ export function defaultStateDir() {
14
+ return `${homedir()}/.openclaw/state/${CHANNEL_ID}`;
15
+ }
16
+ /** Cursor file name for a given kfId. */
17
+ export function cursorFileName(kfId) {
18
+ return `${CHANNEL_ID}-cursor-${kfId}.txt`;
19
+ }
20
+ /** Persisted file name for discovered kfids. */
21
+ export const KFIDS_FILE = `${CHANNEL_ID}-kfids.json`;
22
+ /** Persisted file name for disabled kfids. */
23
+ export const DISABLED_KFIDS_FILE = `${CHANNEL_ID}-disabled-kfids.json`;
1
24
  /** WeChat KF text message character limit */
2
25
  export const WECHAT_TEXT_CHUNK_LIMIT = 2000;
3
26
  /** Timeout for token fetch requests (ms) */
@@ -17,4 +40,10 @@ export const TOKEN_EXPIRED_CODES = new Set([40014, 42001, 40001]);
17
40
  export const WECHAT_MSG_LIMIT_ERRCODE = 95026;
18
41
  /** Timeout for downloading media from external HTTP URLs (ms) */
19
42
  export const MEDIA_DOWNLOAD_TIMEOUT_MS = 60_000;
43
+ /** Max age (seconds) for inbound messages. Messages older than this are skipped. */
44
+ export const MAX_MESSAGE_AGE_S = 300; // 5 minutes
45
+ /** Format an unknown caught value for log messages (no stack traces). */
46
+ export function formatError(err) {
47
+ return err instanceof Error ? err.message : String(err);
48
+ }
20
49
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC;AAE5C,4CAA4C;AAC5C,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAE7C,yCAAyC;AACzC,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAE1C,sDAAsD;AACtD,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEvC,6EAA6E;AAC7E,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;AAElE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,KAAK,CAAC;AAE9C,iEAAiE;AACjE,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,4EAA4E;AAC5E,MAAM,CAAC,MAAM,UAAU,GAAG,WAAoB,CAAC;AAE/C,yEAAyE;AACzE,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,UAAU,EAAE,CAAC;AAErD,6DAA6D;AAC7D,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,UAAU,EAAE,CAAC;AAEnD,mEAAmE;AACnE,MAAM,UAAU,MAAM,CAAC,IAAa;IAClC,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,UAAU,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,UAAU,GAAG,CAAC;AAC9D,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,eAAe;IAC7B,OAAO,GAAG,OAAO,EAAE,oBAAoB,UAAU,EAAE,CAAC;AACtD,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,GAAG,UAAU,WAAW,IAAI,MAAM,CAAC;AAC5C,CAAC;AAED,gDAAgD;AAChD,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,UAAU,aAAa,CAAC;AAErD,8CAA8C;AAC9C,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,UAAU,sBAAsB,CAAC;AAEvE,6CAA6C;AAC7C,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC;AAE5C,4CAA4C;AAC5C,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAE7C,yCAAyC;AACzC,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAE1C,sDAAsD;AACtD,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEvC,6EAA6E;AAC7E,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;AAElE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,KAAK,CAAC;AAE9C,iEAAiE;AACjE,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAEhD,oFAAoF;AACpF,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC,CAAC,YAAY;AAElD,yEAAyE;AACzE,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC"}
@@ -6,13 +6,14 @@
6
6
  * - Plaintext format: random(16B) + msg_len(4B network order) + msg + receiveid
7
7
  */
8
8
  import { createCipheriv, createDecipheriv, createHash, randomBytes, timingSafeEqual } from "node:crypto";
9
+ import { logTag } from "./constants.js";
9
10
  export function deriveAesKey(encodingAESKey) {
10
11
  if (encodingAESKey.length !== 43) {
11
- throw new Error(`[wechat-kf] EncodingAESKey must be 43 characters, got ${encodingAESKey.length}`);
12
+ throw new Error(`${logTag()} EncodingAESKey must be 43 characters, got ${encodingAESKey.length}`);
12
13
  }
13
14
  const key = Buffer.from(`${encodingAESKey}=`, "base64");
14
15
  if (key.length !== 32) {
15
- throw new Error(`[wechat-kf] derived AES key must be 32 bytes, got ${key.length}`);
16
+ throw new Error(`${logTag()} derived AES key must be 32 bytes, got ${key.length}`);
16
17
  }
17
18
  return key;
18
19
  }
@@ -38,21 +39,21 @@ export function decrypt(encodingAESKey, encrypted) {
38
39
  // Remove PKCS#7 padding — validate ALL N padding bytes equal N
39
40
  const pad = decrypted[decrypted.length - 1];
40
41
  if (pad < 1 || pad > 32 || pad > decrypted.length) {
41
- throw new Error("[wechat-kf] invalid PKCS#7 padding");
42
+ throw new Error(`${logTag()} invalid PKCS#7 padding`);
42
43
  }
43
44
  for (let i = 1; i <= pad; i++) {
44
45
  if (decrypted[decrypted.length - i] !== pad) {
45
- throw new Error("[wechat-kf] invalid PKCS#7 padding");
46
+ throw new Error(`${logTag()} invalid PKCS#7 padding`);
46
47
  }
47
48
  }
48
49
  const content = decrypted.subarray(0, decrypted.length - pad);
49
50
  // Parse: random(16) + msg_len(4, big-endian) + msg + receiverId
50
51
  if (content.length < 20) {
51
- throw new Error("[wechat-kf] decrypted content too short");
52
+ throw new Error(`${logTag()} decrypted content too short`);
52
53
  }
53
54
  const msgLen = content.readUInt32BE(16);
54
55
  if (msgLen < 0 || 20 + msgLen > content.length) {
55
- throw new Error("[wechat-kf] invalid message length in decrypted content");
56
+ throw new Error(`${logTag()} invalid message length in decrypted content`);
56
57
  }
57
58
  const message = content.subarray(20, 20 + msgLen).toString("utf8");
58
59
  const receiverId = content.subarray(20 + msgLen).toString("utf8");
@@ -1 +1 @@
1
- {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/crypto.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/crypto.ts"],"names":[],"mappings":"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"}
@@ -1,18 +1,31 @@
1
1
  /**
2
- * Monitor starts webhook server and manages lifecycle
2
+ * Shared context manager for WeChat KF plugin
3
3
  *
4
- * Single webhook server for the enterprise. KfIds are discovered dynamically
5
- * from webhook callbacks. Polling fallback iterates all known kfids.
4
+ * Provides a rendezvous point between the "default" account (which sets up
5
+ * enterprise-level shared infrastructure) and per-kfId accounts (which need
6
+ * the shared crypto config and BotContext to start polling).
6
7
  */
7
- import type { Server } from "node:http";
8
- import { type Logger } from "./bot.js";
9
- import type { PluginRuntime } from "./runtime.js";
10
- import type { OpenClawConfig } from "./types.js";
11
- export type MonitorContext = {
12
- cfg: OpenClawConfig;
13
- runtime?: PluginRuntime;
14
- abortSignal?: AbortSignal;
15
- stateDir: string;
16
- log?: Logger;
8
+ import type { BotContext } from "./bot.js";
9
+ export type SharedContext = {
10
+ callbackToken: string;
11
+ encodingAESKey: string;
12
+ corpId: string;
13
+ appSecret: string;
14
+ webhookPath: string;
15
+ botCtx: BotContext;
17
16
  };
18
- export declare function startMonitor(ctx: MonitorContext): Promise<Server>;
17
+ export declare function setPairingKfId(externalUserId: string, openKfId: string): void;
18
+ export declare function getPairingKfId(externalUserId: string): string | undefined;
19
+ /** Set the shared context. Resolves any pending waitForSharedContext calls. */
20
+ export declare function setSharedContext(ctx: SharedContext): void;
21
+ /** Get the shared context, or null if not yet set. */
22
+ export declare function getSharedContext(): SharedContext | null;
23
+ /**
24
+ * Wait until the shared context is set.
25
+ * Rejects if the signal aborts before the context is ready.
26
+ */
27
+ export declare function waitForSharedContext(signal?: AbortSignal): Promise<SharedContext>;
28
+ /** Clear the shared context (used during shutdown). */
29
+ export declare function clearSharedContext(): void;
30
+ /** Reset all module-level state. @internal For testing only. */
31
+ export declare function _reset(): void;
@@ -1,131 +1,78 @@
1
1
  /**
2
- * Monitor starts webhook server and manages lifecycle
2
+ * Shared context manager for WeChat KF plugin
3
3
  *
4
- * Single webhook server for the enterprise. KfIds are discovered dynamically
5
- * from webhook callbacks. Polling fallback iterates all known kfids.
4
+ * Provides a rendezvous point between the "default" account (which sets up
5
+ * enterprise-level shared infrastructure) and per-kfId accounts (which need
6
+ * the shared crypto config and BotContext to start polling).
6
7
  */
7
- import { getChannelConfig, getKnownKfIds, loadKfIds } from "./accounts.js";
8
- import { handleWebhookEvent } from "./bot.js";
9
- import { getAccessToken } from "./token.js";
10
- import { createWebhookServer } from "./webhook.js";
11
- export async function startMonitor(ctx) {
12
- const { cfg, runtime, abortSignal, stateDir, log } = ctx;
13
- // Guard: if signal is already aborted, skip all resource creation
14
- if (abortSignal?.aborted) {
15
- log?.info("[wechat-kf] abort signal already triggered, skipping monitor start");
16
- // Return a dummy server that is not listening
17
- const dummyServer = createWebhookServer({
18
- port: 0,
19
- path: "/",
20
- callbackToken: "",
21
- encodingAESKey: "",
22
- corpId: "",
23
- onEvent: async () => { },
8
+ // ── Module-level state ──
9
+ let sharedCtx = null;
10
+ let readyResolve = null;
11
+ let readyPromise = null;
12
+ /** Cache: externalUserId openKfId for pairing approval notifications. */
13
+ const pairingKfIdCache = new Map();
14
+ export function setPairingKfId(externalUserId, openKfId) {
15
+ pairingKfIdCache.set(externalUserId, openKfId);
16
+ }
17
+ export function getPairingKfId(externalUserId) {
18
+ return pairingKfIdCache.get(externalUserId);
19
+ }
20
+ function ensureReadyPromise() {
21
+ if (!readyPromise) {
22
+ readyPromise = new Promise((resolve) => {
23
+ readyResolve = resolve;
24
24
  });
25
- return dummyServer;
26
25
  }
27
- const config = getChannelConfig(cfg);
28
- const { corpId, appSecret, token, encodingAESKey } = config;
29
- const webhookPort = config.webhookPort ?? 9999;
30
- const webhookPath = config.webhookPath ?? "/wechat-kf";
31
- if (!corpId || !appSecret || !token || !encodingAESKey) {
32
- throw new Error("[wechat-kf] missing required config fields (corpId, appSecret, token, encodingAESKey)");
33
- }
34
- // Load previously discovered kfids
35
- await loadKfIds(stateDir);
36
- // Validate access token on startup
37
- try {
38
- await getAccessToken(corpId, appSecret);
39
- log?.info(`[wechat-kf] access_token validated`);
26
+ return readyPromise;
27
+ }
28
+ /** Set the shared context. Resolves any pending waitForSharedContext calls. */
29
+ export function setSharedContext(ctx) {
30
+ sharedCtx = ctx;
31
+ // Resolve waiting callers
32
+ if (readyResolve) {
33
+ readyResolve();
34
+ readyResolve = null;
40
35
  }
41
- catch (err) {
42
- log?.warn?.(`[wechat-kf] access_token validation failed (will retry on first message): ${err}`);
36
+ }
37
+ /** Get the shared context, or null if not yet set. */
38
+ export function getSharedContext() {
39
+ return sharedCtx;
40
+ }
41
+ /**
42
+ * Wait until the shared context is set.
43
+ * Rejects if the signal aborts before the context is ready.
44
+ */
45
+ export function waitForSharedContext(signal) {
46
+ // Already available — fast path
47
+ if (sharedCtx)
48
+ return Promise.resolve(sharedCtx);
49
+ // Already aborted
50
+ if (signal?.aborted) {
51
+ return Promise.reject(new DOMException("The operation was aborted.", "AbortError"));
43
52
  }
44
- const botCtx = { cfg, runtime, stateDir, log };
45
- const server = createWebhookServer({
46
- port: webhookPort,
47
- path: webhookPath,
48
- callbackToken: token,
49
- encodingAESKey,
50
- corpId,
51
- onEvent: async (kfId, syncToken) => {
52
- if (!kfId) {
53
- log?.error("[wechat-kf] webhook callback missing OpenKfId, ignoring");
54
- return;
55
- }
56
- try {
57
- await handleWebhookEvent(botCtx, kfId, syncToken);
58
- }
59
- catch (err) {
60
- log?.error(`[wechat-kf:${kfId}] event processing error: ${err}`);
61
- }
62
- },
63
- });
64
- await new Promise((resolve, reject) => {
65
- const timeout = setTimeout(() => reject(new Error(`[wechat-kf] server.listen(:${webhookPort}) timed out`)), 10_000);
66
- const onError = (err) => {
67
- clearTimeout(timeout);
68
- reject(err);
53
+ const ready = ensureReadyPromise();
54
+ return new Promise((resolve, reject) => {
55
+ const onReady = () => {
56
+ signal?.removeEventListener("abort", onAbort);
57
+ resolve(sharedCtx);
69
58
  };
70
- server.once("error", onError);
71
- server.listen(webhookPort, () => {
72
- clearTimeout(timeout);
73
- server.removeListener("error", onError);
74
- log?.info(`[wechat-kf] webhook listening on :${webhookPort}${webhookPath}`);
75
- resolve();
76
- });
77
- });
78
- // ── Polling fallback ──
79
- // Poll sync_msg for each known kfid as fallback
80
- const POLL_INTERVAL_MS = 30000;
81
- let pollTimer = null;
82
- let polling = false;
83
- pollTimer = setInterval(async () => {
84
- if (abortSignal?.aborted)
85
- return;
86
- if (polling)
87
- return;
88
- polling = true;
89
- try {
90
- const kfIds = getKnownKfIds();
91
- if (kfIds.length === 0) {
92
- // No kfids discovered yet, nothing to poll
93
- return;
94
- }
95
- for (const kfId of kfIds) {
96
- if (abortSignal?.aborted)
97
- break;
98
- try {
99
- log?.info(`[wechat-kf:${kfId}] polling sync_msg...`);
100
- await handleWebhookEvent(botCtx, kfId, "");
101
- }
102
- catch (err) {
103
- log?.error(`[wechat-kf:${kfId}] poll error: ${err instanceof Error ? err.stack || err.message : err}`);
104
- }
105
- }
106
- }
107
- finally {
108
- polling = false;
109
- }
110
- }, POLL_INTERVAL_MS);
111
- log?.info(`[wechat-kf] polling fallback enabled (every ${POLL_INTERVAL_MS}ms)`);
112
- if (abortSignal) {
113
- const cleanup = () => {
114
- if (pollTimer) {
115
- clearInterval(pollTimer);
116
- pollTimer = null;
117
- }
118
- server.close();
119
- log?.info("[wechat-kf] webhook server + polling stopped");
59
+ const onAbort = () => {
60
+ reject(new DOMException("The operation was aborted.", "AbortError"));
120
61
  };
121
- // Double-check: signal may have been aborted between the top guard and here
122
- if (abortSignal.aborted) {
123
- cleanup();
124
- }
125
- else {
126
- abortSignal.addEventListener("abort", cleanup, { once: true });
127
- }
128
- }
129
- return server;
62
+ signal?.addEventListener("abort", onAbort, { once: true });
63
+ ready.then(onReady);
64
+ });
65
+ }
66
+ /** Clear the shared context (used during shutdown). */
67
+ export function clearSharedContext() {
68
+ sharedCtx = null;
69
+ pairingKfIdCache.clear();
70
+ }
71
+ /** Reset all module-level state. @internal For testing only. */
72
+ export function _reset() {
73
+ sharedCtx = null;
74
+ readyResolve = null;
75
+ readyPromise = null;
76
+ pairingKfIdCache.clear();
130
77
  }
131
78
  //# sourceMappingURL=monitor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"monitor.js","sourceRoot":"","sources":["../../src/monitor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"monitor.js","sourceRoot":"","sources":["../../src/monitor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,2BAA2B;AAE3B,IAAI,SAAS,GAAyB,IAAI,CAAC;AAC3C,IAAI,YAAY,GAAwB,IAAI,CAAC;AAC7C,IAAI,YAAY,GAAyB,IAAI,CAAC;AAE9C,2EAA2E;AAC3E,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAkB,CAAC;AAEnD,MAAM,UAAU,cAAc,CAAC,cAAsB,EAAE,QAAgB;IACrE,gBAAgB,CAAC,GAAG,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,cAAsB;IACnD,OAAO,gBAAgB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,kBAAkB;IACzB,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,YAAY,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAC3C,YAAY,GAAG,OAAO,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,gBAAgB,CAAC,GAAkB;IACjD,SAAS,GAAG,GAAG,CAAC;IAChB,0BAA0B;IAC1B,IAAI,YAAY,EAAE,CAAC;QACjB,YAAY,EAAE,CAAC;QACf,YAAY,GAAG,IAAI,CAAC;IACtB,CAAC;AACH,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,gBAAgB;IAC9B,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAoB;IACvD,gCAAgC;IAChC,IAAI,SAAS;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEjD,kBAAkB;IAClB,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;QACpB,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,YAAY,CAAC,4BAA4B,EAAE,YAAY,CAAC,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,KAAK,GAAG,kBAAkB,EAAE,CAAC;IAEnC,OAAO,IAAI,OAAO,CAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACpD,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC9C,OAAO,CAAC,SAAU,CAAC,CAAC;QACtB,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,MAAM,CAAC,IAAI,YAAY,CAAC,4BAA4B,EAAE,YAAY,CAAC,CAAC,CAAC;QACvE,CAAC,CAAC;QAEF,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,kBAAkB;IAChC,SAAS,GAAG,IAAI,CAAC;IACjB,gBAAgB,CAAC,KAAK,EAAE,CAAC;AAC3B,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,MAAM;IACpB,SAAS,GAAG,IAAI,CAAC;IACjB,YAAY,GAAG,IAAI,CAAC;IACpB,YAAY,GAAG,IAAI,CAAC;IACpB,gBAAgB,CAAC,KAAK,EAAE,CAAC;AAC3B,CAAC"}
@@ -5,12 +5,15 @@
5
5
  * This module implements the OpenClaw `ChannelPlugin.outbound` interface and
6
6
  * is called by the framework when the agent produces a final reply.
7
7
  *
8
- * Text chunking is handled by the framework itself via the declared `chunker`
9
- * function (P0-01), so `sendText` always receives a single pre-chunked piece.
8
+ * Text is first converted from markdown to Unicode formatting (formatText),
9
+ * then chunked via the runtime's `chunkTextWithMode` helper (respecting user
10
+ * `chunkMode` config). Framework auto-chunking is disabled (`chunker: null`)
11
+ * because it would chunk *before* formatting, causing post-format expansion
12
+ * (Unicode math-bold chars are 2 `.length` units each) to exceed the limit.
10
13
  *
11
- * For media, the file is read from disk (or downloaded from HTTP URL),
12
- * classified, uploaded to WeChat, and sent using the shared
13
- * `uploadAndSendMedia` helper from `send-utils.ts`.
14
+ * For media, the framework's `loadWebMedia` handles all URL formats
15
+ * (HTTP, file://, local paths, MEDIA: prefix, ~), then the buffer is
16
+ * uploaded to WeChat and sent using `uploadAndSendMedia` from `send-utils.ts`.
14
17
  *
15
18
  * WeChat KF session limits:
16
19
  * The API enforces a 48-hour / 5-message limit per session window.
@@ -25,42 +28,5 @@
25
28
  *
26
29
  * accountId = openKfId (dynamically discovered)
27
30
  */
28
- import type { OpenClawConfig } from "./types.js";
29
- export type SendTextParams = {
30
- cfg: OpenClawConfig;
31
- to: string;
32
- text: string;
33
- accountId: string;
34
- };
35
- export type SendMediaParams = {
36
- cfg: OpenClawConfig;
37
- to: string;
38
- text?: string;
39
- mediaUrl?: string;
40
- accountId: string;
41
- };
42
- export type SendResult = {
43
- channel: string;
44
- messageId: string;
45
- chatId: string;
46
- };
47
- export type SendPayloadParams = {
48
- cfg: OpenClawConfig;
49
- to: string;
50
- text?: string;
51
- accountId: string;
52
- payload: {
53
- text?: string;
54
- channelData?: Record<string, unknown>;
55
- [key: string]: unknown;
56
- };
57
- };
58
- export declare const wechatKfOutbound: {
59
- deliveryMode: "direct";
60
- chunker: (text: string, limit: number) => string[];
61
- chunkerMode: "text";
62
- textChunkLimit: number;
63
- sendText: ({ cfg, to, text, accountId }: SendTextParams) => Promise<SendResult>;
64
- sendMedia: ({ cfg, to, text, mediaUrl, accountId }: SendMediaParams) => Promise<SendResult>;
65
- sendPayload: ({ cfg, to, text, accountId, payload }: SendPayloadParams) => Promise<SendResult>;
66
- };
31
+ import type { ChannelOutboundAdapter } from "openclaw/plugin-sdk";
32
+ export declare const wechatKfOutbound: ChannelOutboundAdapter;