@pawastation/wechat-kf 0.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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +291 -0
  3. package/README.zh-CN.md +401 -0
  4. package/dist/index.d.ts +27 -0
  5. package/dist/index.js +24 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/src/accounts.d.ts +37 -0
  8. package/dist/src/accounts.js +205 -0
  9. package/dist/src/accounts.js.map +1 -0
  10. package/dist/src/api.d.ts +29 -0
  11. package/dist/src/api.js +172 -0
  12. package/dist/src/api.js.map +1 -0
  13. package/dist/src/bot.d.ts +35 -0
  14. package/dist/src/bot.js +379 -0
  15. package/dist/src/bot.js.map +1 -0
  16. package/dist/src/channel.d.ts +113 -0
  17. package/dist/src/channel.js +183 -0
  18. package/dist/src/channel.js.map +1 -0
  19. package/dist/src/chunk-utils.d.ts +18 -0
  20. package/dist/src/chunk-utils.js +58 -0
  21. package/dist/src/chunk-utils.js.map +1 -0
  22. package/dist/src/config-schema.d.ts +56 -0
  23. package/dist/src/config-schema.js +38 -0
  24. package/dist/src/config-schema.js.map +1 -0
  25. package/dist/src/constants.d.ts +19 -0
  26. package/dist/src/constants.js +20 -0
  27. package/dist/src/constants.js.map +1 -0
  28. package/dist/src/crypto.d.ts +18 -0
  29. package/dist/src/crypto.js +80 -0
  30. package/dist/src/crypto.js.map +1 -0
  31. package/dist/src/fs-utils.d.ts +7 -0
  32. package/dist/src/fs-utils.js +13 -0
  33. package/dist/src/fs-utils.js.map +1 -0
  34. package/dist/src/monitor.d.ts +18 -0
  35. package/dist/src/monitor.js +131 -0
  36. package/dist/src/monitor.js.map +1 -0
  37. package/dist/src/outbound.d.ts +66 -0
  38. package/dist/src/outbound.js +234 -0
  39. package/dist/src/outbound.js.map +1 -0
  40. package/dist/src/reply-dispatcher.d.ts +40 -0
  41. package/dist/src/reply-dispatcher.js +120 -0
  42. package/dist/src/reply-dispatcher.js.map +1 -0
  43. package/dist/src/runtime.d.ts +130 -0
  44. package/dist/src/runtime.js +22 -0
  45. package/dist/src/runtime.js.map +1 -0
  46. package/dist/src/send-utils.d.ts +30 -0
  47. package/dist/src/send-utils.js +89 -0
  48. package/dist/src/send-utils.js.map +1 -0
  49. package/dist/src/send.d.ts +7 -0
  50. package/dist/src/send.js +13 -0
  51. package/dist/src/send.js.map +1 -0
  52. package/dist/src/token.d.ts +8 -0
  53. package/dist/src/token.js +57 -0
  54. package/dist/src/token.js.map +1 -0
  55. package/dist/src/types.d.ts +173 -0
  56. package/dist/src/types.js +3 -0
  57. package/dist/src/types.js.map +1 -0
  58. package/dist/src/unicode-format.d.ts +26 -0
  59. package/dist/src/unicode-format.js +157 -0
  60. package/dist/src/unicode-format.js.map +1 -0
  61. package/dist/src/webhook.d.ts +22 -0
  62. package/dist/src/webhook.js +138 -0
  63. package/dist/src/webhook.js.map +1 -0
  64. package/dist/src/wechat-kf-directives.d.ts +34 -0
  65. package/dist/src/wechat-kf-directives.js +65 -0
  66. package/dist/src/wechat-kf-directives.js.map +1 -0
  67. package/index.ts +32 -0
  68. package/openclaw.plugin.json +31 -0
  69. package/package.json +91 -0
@@ -0,0 +1,379 @@
1
+ /**
2
+ * Message processing — pull messages via sync_msg and dispatch to OpenClaw agent.
3
+ *
4
+ * Architecture:
5
+ * - Each openKfId is an independent account with its own cursor and session
6
+ * - sync_msg is called with open_kfid filter to only pull messages for that kf account
7
+ * - Plugin layer: download media, save via MediaPaths/MediaTypes
8
+ * - OpenClaw runner: handles media understanding (transcription, vision, etc.)
9
+ */
10
+ import { mkdir, readFile } from "node:fs/promises";
11
+ import { join } from "node:path";
12
+ import { getChannelConfig, registerKfId, resolveAccount } from "./accounts.js";
13
+ import { downloadMedia, syncMessages } from "./api.js";
14
+ import { atomicWriteFile } from "./fs-utils.js";
15
+ import { createReplyDispatcher } from "./reply-dispatcher.js";
16
+ import { getRuntime } from "./runtime.js";
17
+ // ── Per-kfId async mutex ──
18
+ // Ensures that concurrent calls to handleWebhookEvent for the same openKfId
19
+ // (e.g. from webhook + polling simultaneously) are serialized.
20
+ const kfLocks = new Map();
21
+ // ── Message deduplication ──
22
+ // Tracks recently-processed msgids to avoid dispatching the same message twice,
23
+ // even if sync_msg returns overlapping batches from concurrent paths.
24
+ const processedMsgIds = new Set();
25
+ const DEDUP_MAX_SIZE = 10_000;
26
+ function isDuplicate(msgid) {
27
+ if (processedMsgIds.has(msgid))
28
+ return true;
29
+ if (processedMsgIds.size >= DEDUP_MAX_SIZE) {
30
+ // Evict the oldest half (Set preserves insertion order)
31
+ const entries = [...processedMsgIds];
32
+ processedMsgIds.clear();
33
+ for (const id of entries.slice(entries.length >>> 1)) {
34
+ processedMsgIds.add(id);
35
+ }
36
+ }
37
+ processedMsgIds.add(msgid);
38
+ return false;
39
+ }
40
+ /** Exposed for testing only — do not use in production code. */
41
+ export const _testing = {
42
+ kfLocks,
43
+ processedMsgIds,
44
+ isDuplicate,
45
+ DEDUP_MAX_SIZE,
46
+ handleEvent,
47
+ resetState() {
48
+ kfLocks.clear();
49
+ processedMsgIds.clear();
50
+ },
51
+ };
52
+ // ── Cursor persistence (per kfid) ──
53
+ async function loadCursor(stateDir, kfId) {
54
+ try {
55
+ return (await readFile(join(stateDir, `wechat-kf-cursor-${kfId}.txt`), "utf8")).trim();
56
+ }
57
+ catch {
58
+ return "";
59
+ }
60
+ }
61
+ let dirCreated = false;
62
+ async function saveCursor(stateDir, kfId, cursor) {
63
+ if (!dirCreated) {
64
+ await mkdir(stateDir, { recursive: true });
65
+ dirCreated = true;
66
+ }
67
+ await atomicWriteFile(join(stateDir, `wechat-kf-cursor-${kfId}.txt`), cursor);
68
+ }
69
+ // ── Message text extraction ──
70
+ // Descriptions of non-text messages injected into the AI agent's context.
71
+ // Kept in Chinese because end-users are Chinese WeChat users and the agent
72
+ // replies in Chinese. These are NOT displayed to end-users directly.
73
+ function extractText(msg) {
74
+ switch (msg.msgtype) {
75
+ case "text":
76
+ return msg.text?.content ?? "";
77
+ case "image":
78
+ return "[用户发送了一张图片]";
79
+ case "voice":
80
+ return "[用户发送了一段语音]";
81
+ case "video":
82
+ return "[用户发送了一段视频]";
83
+ case "file":
84
+ return "[用户发送了一个文件]";
85
+ case "location": {
86
+ const locDetail = [msg.location?.name, msg.location?.address].filter(Boolean).join(" ");
87
+ return locDetail ? `[位置: ${locDetail}]` : "[位置]";
88
+ }
89
+ case "link":
90
+ return `[链接: ${msg.link?.title ?? ""} ${msg.link?.url ?? ""}]`;
91
+ case "merged_msg": {
92
+ const merged = msg.merged_msg;
93
+ if (!merged)
94
+ return "[转发的聊天记录]";
95
+ const title = merged.title ?? "聊天记录";
96
+ const items = Array.isArray(merged.item) ? merged.item : [];
97
+ const lines = items.map((item) => {
98
+ const sender = item.sender_name ?? "未知";
99
+ let content = "";
100
+ try {
101
+ const parsed = JSON.parse(item.msg_content ?? "{}");
102
+ const parsedText = parsed.text;
103
+ if (parsedText?.content)
104
+ content = parsedText.content;
105
+ else if (parsed.image)
106
+ content = "[图片]";
107
+ else if (parsed.voice)
108
+ content = "[语音]";
109
+ else if (parsed.video)
110
+ content = "[视频]";
111
+ else if (parsed.file)
112
+ content = "[文件]";
113
+ else if (parsed.link)
114
+ content = `[链接: ${parsed.link?.title ?? ""}]`;
115
+ else
116
+ content = `[${parsed.msgtype ?? "未知类型"}]`;
117
+ }
118
+ catch {
119
+ content = item.msg_content ?? "";
120
+ }
121
+ return `${sender}: ${content}`;
122
+ });
123
+ return `[转发的聊天记录: ${title}]\n${lines.join("\n")}`;
124
+ }
125
+ case "channels": {
126
+ const ch = msg.channels;
127
+ const typeMap = { 1: "视频号动态", 2: "视频号直播", 3: "视频号名片" };
128
+ const typeName = ch?.sub_type != null ? (typeMap[ch.sub_type] ?? "视频号消息") : "视频号消息";
129
+ return `[${typeName}] ${ch?.nickname ?? ""}: ${ch?.title ?? ""}`;
130
+ }
131
+ case "miniprogram": {
132
+ const mp = msg.miniprogram;
133
+ return `[小程序] ${mp?.title ?? ""} (appid: ${mp?.appid ?? ""})`;
134
+ }
135
+ case "msgmenu": {
136
+ const menu = msg.msgmenu;
137
+ const head = menu?.head_content ?? "";
138
+ const items = Array.isArray(menu?.list) ? menu.list.map((item) => item.content ?? item.id).join(", ") : "";
139
+ return head ? `${head} [选项: ${items}]` : `[菜单消息: ${items}]`;
140
+ }
141
+ case "business_card":
142
+ return `[名片] userid: ${msg.business_card?.userid ?? ""}`;
143
+ case "event":
144
+ return null;
145
+ default:
146
+ return `[未支持的消息类型: ${msg.msgtype}]`;
147
+ }
148
+ }
149
+ // ── Event handling ──
150
+ async function handleEvent(ctx, _account, msg) {
151
+ const event = msg.event;
152
+ const { log } = ctx;
153
+ const kfId = msg.open_kfid;
154
+ switch (event?.event_type) {
155
+ case "enter_session":
156
+ log?.info(`[wechat-kf:${kfId}] user ${msg.external_userid} entered session` +
157
+ (event.welcome_code ? `, welcome_code=${event.welcome_code}` : "") +
158
+ (event.scene ? `, scene=${event.scene}` : ""));
159
+ break;
160
+ case "msg_send_fail":
161
+ log?.error(`[wechat-kf:${kfId}] message send failed: msgid=${event.fail_msgid}, type=${event.fail_type}`);
162
+ break;
163
+ case "servicer_status_change":
164
+ log?.info(`[wechat-kf:${kfId}] servicer status changed: ${event.servicer_userid} -> ${event.status}`);
165
+ break;
166
+ default:
167
+ log?.info(`[wechat-kf:${kfId}] unhandled event: ${event?.event_type}`);
168
+ }
169
+ }
170
+ // ── Core message handler (per kfid) ──
171
+ export async function handleWebhookEvent(ctx, openKfId, syncToken) {
172
+ // Acquire per-kfId mutex — chains onto any in-flight processing for this kfId
173
+ const prev = kfLocks.get(openKfId) ?? Promise.resolve();
174
+ let release;
175
+ const current = new Promise((r) => {
176
+ release = r;
177
+ });
178
+ kfLocks.set(openKfId, current);
179
+ try {
180
+ await prev;
181
+ await _handleWebhookEventInner(ctx, openKfId, syncToken);
182
+ }
183
+ finally {
184
+ release();
185
+ // Clean up map entry only if no newer caller has replaced it
186
+ if (kfLocks.get(openKfId) === current) {
187
+ kfLocks.delete(openKfId);
188
+ }
189
+ }
190
+ }
191
+ async function _handleWebhookEventInner(ctx, openKfId, syncToken) {
192
+ const { cfg, stateDir, log } = ctx;
193
+ const account = resolveAccount(cfg, openKfId); // kfid as accountId
194
+ const { corpId, appSecret } = account;
195
+ if (!corpId || !appSecret) {
196
+ log?.error("[wechat-kf] missing corpId/appSecret");
197
+ return;
198
+ }
199
+ // Register this kfid as discovered
200
+ await registerKfId(openKfId);
201
+ let cursor = await loadCursor(stateDir, openKfId);
202
+ let hasMore = true;
203
+ while (hasMore) {
204
+ const syncReq = {
205
+ limit: 1000,
206
+ open_kfid: openKfId, // Only pull messages for this kf account
207
+ };
208
+ if (cursor) {
209
+ // Have a persisted cursor — use it for incremental fetch (token is ignored)
210
+ syncReq.cursor = cursor;
211
+ }
212
+ else if (syncToken) {
213
+ // No cursor but webhook provided a token — use it for the first fetch
214
+ syncReq.token = syncToken;
215
+ }
216
+ else {
217
+ // Neither cursor nor token — will fetch the initial batch (up to 3 days history)
218
+ log?.info(`[wechat-kf:${openKfId}] no cursor or token, fetching initial batch`);
219
+ }
220
+ let resp;
221
+ try {
222
+ resp = await syncMessages(corpId, appSecret, syncReq);
223
+ }
224
+ catch (err) {
225
+ log?.error(`[wechat-kf:${openKfId}] sync_msg failed: ${err instanceof Error ? err.message : err}`);
226
+ return;
227
+ }
228
+ for (const msg of resp.msg_list ?? []) {
229
+ // Handle event messages (any origin) before normal message processing
230
+ if (msg.msgtype === "event") {
231
+ await handleEvent(ctx, account, msg);
232
+ continue;
233
+ }
234
+ if (msg.origin !== 3)
235
+ continue; // Only customer messages
236
+ // Dedup: skip messages we have already processed
237
+ if (isDuplicate(msg.msgid)) {
238
+ log?.info(`[wechat-kf:${openKfId}] skipping duplicate msg ${msg.msgid}`);
239
+ continue;
240
+ }
241
+ const text = extractText(msg);
242
+ if (text === null || text === "")
243
+ continue;
244
+ try {
245
+ await dispatchMessage(ctx, account, msg, text);
246
+ }
247
+ catch (err) {
248
+ log?.error(`[wechat-kf:${openKfId}] dispatch error for msg ${msg.msgid}: ${err instanceof Error ? err.stack || err.message : err}`);
249
+ }
250
+ }
251
+ // P1-02: Save cursor AFTER all messages in the batch are processed
252
+ // (at-least-once delivery). If the process crashes mid-batch, the
253
+ // cursor has not advanced and the batch will be re-fetched on restart.
254
+ // P1-01 msgid dedup ensures replayed messages are not dispatched twice.
255
+ if (resp.next_cursor) {
256
+ cursor = resp.next_cursor;
257
+ await saveCursor(stateDir, openKfId, cursor);
258
+ }
259
+ hasMore = resp.has_more === 1;
260
+ }
261
+ }
262
+ // ── Dispatch message to agent ──
263
+ async function dispatchMessage(ctx, account, msg, text) {
264
+ const { cfg, runtime, log } = ctx;
265
+ // ── DM policy check ──
266
+ const channelConfig = getChannelConfig(cfg);
267
+ const dmPolicy = channelConfig.dmPolicy ?? "open";
268
+ const externalUserId = msg.external_userid;
269
+ if (dmPolicy === "disabled") {
270
+ log?.info?.(`[wechat-kf] drop DM (dmPolicy: disabled)`);
271
+ return;
272
+ }
273
+ if (dmPolicy === "allowlist") {
274
+ const allowFrom = channelConfig.allowFrom ?? [];
275
+ if (!allowFrom.includes(externalUserId)) {
276
+ log?.info?.(`[wechat-kf] blocked sender ${externalUserId} (dmPolicy: allowlist)`);
277
+ return;
278
+ }
279
+ }
280
+ // "open" and "pairing" modes: allow message through
281
+ // Note: full pairing flow requires runtime API support, deferred to P2
282
+ const core = getRuntime();
283
+ const kfId = msg.open_kfid;
284
+ const from = `wechat-kf:${msg.external_userid}`;
285
+ const to = `user:${msg.external_userid}`;
286
+ // Download media
287
+ const mediaPaths = [];
288
+ const mediaTypes = [];
289
+ async function saveMedia(mediaId, mimeType, filename) {
290
+ try {
291
+ const buffer = await downloadMedia(account.corpId, account.appSecret, mediaId);
292
+ const saved = await core.channel.media.saveMediaBuffer(buffer, mimeType, "inbound", undefined, filename);
293
+ mediaPaths.push(saved.path);
294
+ mediaTypes.push(mimeType);
295
+ log?.info(`[wechat-kf:${kfId}] saved media: ${saved.path} (${mimeType})`);
296
+ }
297
+ catch (err) {
298
+ log?.error(`[wechat-kf:${kfId}] failed to save media ${mediaId}: ${err instanceof Error ? err.message : err}`);
299
+ }
300
+ }
301
+ if (account.corpId && account.appSecret) {
302
+ const mediaId = msg.image?.media_id || msg.voice?.media_id || msg.video?.media_id || msg.file?.media_id;
303
+ if (mediaId) {
304
+ const mimeMap = {
305
+ image: ["image/jpeg", `wechat_image_${msg.msgid}.jpg`],
306
+ voice: ["audio/amr", `wechat_voice_${msg.msgid}.amr`],
307
+ video: ["video/mp4", `wechat_video_${msg.msgid}.mp4`],
308
+ file: ["application/octet-stream", `wechat_file_${msg.msgid}`],
309
+ };
310
+ const [mime, filename] = mimeMap[msg.msgtype] ?? ["application/octet-stream", `wechat_media_${msg.msgid}`];
311
+ await saveMedia(mediaId, mime, filename);
312
+ }
313
+ }
314
+ // Route using kfid as accountId — each kfid gets its own session
315
+ // peer id includes kfid so different kf accounts get isolated sessions
316
+ const route = core.channel.routing.resolveAgentRoute({
317
+ cfg,
318
+ channel: "wechat-kf",
319
+ accountId: kfId,
320
+ peer: { kind: "direct", id: `${kfId}:${msg.external_userid}` },
321
+ });
322
+ // System event
323
+ const preview = text.replace(/\s+/g, " ").slice(0, 160);
324
+ core.system.enqueueSystemEvent(`WeChat-KF[${kfId}] DM from ${msg.external_userid}: ${preview}`, {
325
+ sessionKey: route.sessionKey,
326
+ contextKey: `wechat-kf:message:${msg.msgid}`,
327
+ });
328
+ // Format envelope
329
+ const envelopeOptions = core.channel.reply.resolveEnvelopeFormatOptions(cfg);
330
+ const body = core.channel.reply.formatAgentEnvelope({
331
+ channel: "WeChat-KF",
332
+ from: msg.external_userid,
333
+ timestamp: new Date(msg.send_time * 1000),
334
+ envelope: envelopeOptions,
335
+ body: text,
336
+ });
337
+ // Build inbound context
338
+ const inboundCtx = core.channel.reply.finalizeInboundContext({
339
+ Body: body,
340
+ RawBody: text,
341
+ CommandBody: text,
342
+ From: from,
343
+ To: to,
344
+ SessionKey: route.sessionKey,
345
+ AccountId: kfId,
346
+ ChatType: "direct",
347
+ SenderName: msg.external_userid,
348
+ SenderId: msg.external_userid,
349
+ Provider: "wechat-kf",
350
+ Surface: "wechat-kf",
351
+ MessageSid: msg.msgid,
352
+ Timestamp: msg.send_time * 1000,
353
+ WasMentioned: false,
354
+ CommandAuthorized: true,
355
+ OriginatingChannel: "wechat-kf",
356
+ OriginatingTo: to,
357
+ MediaPaths: mediaPaths.length > 0 ? mediaPaths : undefined,
358
+ MediaTypes: mediaTypes.length > 0 ? mediaTypes : undefined,
359
+ });
360
+ // Dispatch to agent
361
+ const { dispatcher, replyOptions, markDispatchIdle } = createReplyDispatcher({
362
+ cfg,
363
+ agentId: route.agentId,
364
+ runtime: runtime ?? {},
365
+ externalUserId: msg.external_userid,
366
+ openKfId: kfId,
367
+ accountId: kfId,
368
+ });
369
+ log?.info(`[wechat-kf:${kfId}] dispatching to agent (session=${route.sessionKey})`);
370
+ const { queuedFinal, counts } = await core.channel.reply.dispatchReplyFromConfig({
371
+ ctx: inboundCtx,
372
+ cfg,
373
+ dispatcher,
374
+ replyOptions,
375
+ });
376
+ markDispatchIdle?.();
377
+ log?.info(`[wechat-kf:${kfId}] dispatch complete (queuedFinal=${queuedFinal}, replies=${counts?.final})`);
378
+ }
379
+ //# sourceMappingURL=bot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot.js","sourceRoot":"","sources":["../../src/bot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * WeChat KF ChannelPlugin implementation
3
+ *
4
+ * Dynamically discovers kfids from webhook callbacks.
5
+ * Each kfid = one accountId = one independent session.
6
+ */
7
+ import type { Logger } from "./bot.js";
8
+ import { wechatKfOutbound } from "./outbound.js";
9
+ import type { PluginRuntime } from "./runtime.js";
10
+ import type { OpenClawConfig, ResolvedWechatKfAccount } from "./types.js";
11
+ type ChannelMeta = {
12
+ id: string;
13
+ label: string;
14
+ selectionLabel: string;
15
+ docsPath: string;
16
+ docsLabel: string;
17
+ blurb: string;
18
+ aliases?: string[];
19
+ order?: number;
20
+ };
21
+ type ChannelCapabilities = {
22
+ chatTypes: string[];
23
+ media: boolean;
24
+ reactions: boolean;
25
+ threads: boolean;
26
+ polls: boolean;
27
+ nativeCommands: boolean;
28
+ blockStreaming: boolean;
29
+ };
30
+ type AccountRuntimeStatus = {
31
+ accountId: string;
32
+ running: boolean;
33
+ lastStartAt: string | null;
34
+ lastStopAt: string | null;
35
+ lastError: string | null;
36
+ port: number | null;
37
+ };
38
+ type GatewayContext = {
39
+ cfg: OpenClawConfig;
40
+ runtime?: PluginRuntime;
41
+ abortSignal?: AbortSignal;
42
+ accountId: string;
43
+ log?: Logger;
44
+ setStatus?: (status: Partial<AccountRuntimeStatus>) => void;
45
+ };
46
+ type ChannelPlugin<T = unknown> = {
47
+ id: string;
48
+ meta: ChannelMeta;
49
+ capabilities: ChannelCapabilities;
50
+ agentPrompt: {
51
+ messageToolHints: () => string[];
52
+ };
53
+ reload: {
54
+ configPrefixes: string[];
55
+ };
56
+ configSchema: {
57
+ schema: unknown;
58
+ };
59
+ config: {
60
+ listAccountIds: (cfg: OpenClawConfig) => string[];
61
+ resolveAccount: (cfg: OpenClawConfig, accountId?: string) => T;
62
+ defaultAccountId: (cfg: OpenClawConfig) => string;
63
+ setAccountEnabled: (opts: {
64
+ cfg: OpenClawConfig;
65
+ accountId: string;
66
+ enabled: boolean;
67
+ }) => OpenClawConfig;
68
+ deleteAccount: (opts: {
69
+ cfg: OpenClawConfig;
70
+ accountId: string;
71
+ }) => OpenClawConfig;
72
+ isConfigured: (account: T) => boolean;
73
+ describeAccount: (account: T) => Record<string, unknown>;
74
+ resolveAllowFrom: (opts: {
75
+ cfg: OpenClawConfig;
76
+ }) => string[];
77
+ formatAllowFrom: (opts: {
78
+ allowFrom: string[];
79
+ }) => string[];
80
+ };
81
+ security: {
82
+ resolveDmPolicy: (opts: {
83
+ cfg: OpenClawConfig;
84
+ }) => Record<string, unknown>;
85
+ collectWarnings: (opts: {
86
+ cfg: OpenClawConfig;
87
+ }) => string[];
88
+ };
89
+ setup: {
90
+ resolveAccountId: (cfg: OpenClawConfig, accountId?: string) => string;
91
+ applyAccountConfig: (opts: {
92
+ cfg: OpenClawConfig;
93
+ accountId: string;
94
+ }) => OpenClawConfig;
95
+ };
96
+ outbound: typeof wechatKfOutbound;
97
+ status: {
98
+ defaultRuntime: AccountRuntimeStatus;
99
+ buildChannelSummary: (opts: {
100
+ snapshot: Record<string, unknown>;
101
+ }) => Record<string, unknown>;
102
+ buildAccountSnapshot: (opts: {
103
+ account: T;
104
+ runtime: Partial<AccountRuntimeStatus> | null;
105
+ }) => Record<string, unknown>;
106
+ };
107
+ gateway: {
108
+ _started: boolean;
109
+ startAccount: (ctx: GatewayContext) => Promise<void>;
110
+ };
111
+ };
112
+ export declare const wechatKfPlugin: ChannelPlugin<ResolvedWechatKfAccount>;
113
+ export {};