@lanmers/wecom-openclaw-plugin 1.0.12
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 +220 -0
- package/dist/index.cjs.js +3591 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.esm.js +3565 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/src/channel.d.ts +3 -0
- package/dist/src/const.d.ts +64 -0
- package/dist/src/dm-policy.d.ts +29 -0
- package/dist/src/group-policy.d.ts +29 -0
- package/dist/src/interface.d.ts +154 -0
- package/dist/src/mcp/index.d.ts +6 -0
- package/dist/src/mcp/schema.d.ts +11 -0
- package/dist/src/mcp/tool.d.ts +55 -0
- package/dist/src/mcp/transport.d.ts +61 -0
- package/dist/src/mcp-config.d.ts +29 -0
- package/dist/src/media-handler.d.ts +36 -0
- package/dist/src/media-uploader.d.ts +131 -0
- package/dist/src/message-parser.d.ts +72 -0
- package/dist/src/message-sender.d.ts +23 -0
- package/dist/src/monitor.d.ts +27 -0
- package/dist/src/onboarding.d.ts +5 -0
- package/dist/src/openclaw-compat.d.ts +48 -0
- package/dist/src/reqid-store.d.ts +31 -0
- package/dist/src/runtime.d.ts +3 -0
- package/dist/src/state-manager.d.ts +76 -0
- package/dist/src/timeout.d.ts +20 -0
- package/dist/src/utils.d.ts +96 -0
- package/dist/src/version.d.ts +2 -0
- package/openclaw.plugin.json +14 -0
- package/package.json +73 -0
- package/skills/wecom-contact-lookup/SKILL.md +162 -0
- package/skills/wecom-doc/SKILL.md +363 -0
- package/skills/wecom-doc/references/doc-api.md +224 -0
- package/skills/wecom-doc-manager/SKILL.md +64 -0
- package/skills/wecom-doc-manager/references/api-create-doc.md +56 -0
- package/skills/wecom-doc-manager/references/api-edit-doc-content.md +68 -0
- package/skills/wecom-doc-manager/references/api-export-document.md +88 -0
- package/skills/wecom-edit-todo/SKILL.md +249 -0
- package/skills/wecom-get-todo-detail/SKILL.md +143 -0
- package/skills/wecom-get-todo-list/SKILL.md +127 -0
- package/skills/wecom-meeting-create/SKILL.md +158 -0
- package/skills/wecom-meeting-create/references/example-full.md +30 -0
- package/skills/wecom-meeting-create/references/example-reminder.md +46 -0
- package/skills/wecom-meeting-create/references/example-security.md +22 -0
- package/skills/wecom-meeting-manage/SKILL.md +136 -0
- package/skills/wecom-meeting-query/SKILL.md +330 -0
- package/skills/wecom-preflight/SKILL.md +141 -0
- package/skills/wecom-schedule/SKILL.md +159 -0
- package/skills/wecom-schedule/references/api-check-availability.md +56 -0
- package/skills/wecom-schedule/references/api-create-schedule.md +38 -0
- package/skills/wecom-schedule/references/api-get-schedule-detail.md +81 -0
- package/skills/wecom-schedule/references/api-update-schedule.md +30 -0
- package/skills/wecom-schedule/references/ref-reminders.md +24 -0
- package/skills/wecom-smartsheet-data/SKILL.md +71 -0
- package/skills/wecom-smartsheet-data/references/api-get-records.md +61 -0
- package/skills/wecom-smartsheet-data/references/cell-value-formats.md +120 -0
- package/skills/wecom-smartsheet-schema/SKILL.md +92 -0
- package/skills/wecom-smartsheet-schema/references/field-types.md +43 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../../src/runtime.ts","../../src/openclaw-compat.ts","../../src/const.ts","../../src/message-parser.ts","../../src/timeout.ts","../../src/message-sender.ts","../../src/media-handler.ts","../../src/media-uploader.ts","../../src/group-policy.ts","../../src/dm-policy.ts","../../src/reqid-store.ts","../../src/state-manager.ts","../../src/monitor.ts","../../src/utils.ts","../../src/onboarding.ts","../../src/channel.ts","../../src/version.ts","../../src/mcp/transport.ts","../../src/mcp/schema.ts","../../src/mcp/tool.ts","../../index.ts"],"sourcesContent":["import type { PluginRuntime } from \"openclaw/plugin-sdk\";\n\nlet runtime: PluginRuntime | null = null;\n\nexport function setWeComRuntime(r: PluginRuntime): void {\n runtime = r;\n}\n\nexport function getWeComRuntime(): PluginRuntime {\n if (!runtime) {\n throw new Error(\"WeCom runtime not initialized - plugin not registered\");\n }\n return runtime;\n}\n","/**\n * openclaw plugin-sdk 高版本方法兼容层\n *\n * 部分方法(如 loadOutboundMediaFromUrl、detectMime、getDefaultMediaLocalRoots)\n * 仅在较新版本的 openclaw plugin-sdk 中才导出。\n *\n * 本模块在加载时一次性探测 SDK 导出,存在则直接 re-export SDK 版本,\n * 不存在则导出 fallback 实现。其他模块统一从本文件导入,无需关心底层兼容细节。\n */\n\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\n\n// ============================================================================\n// 类型定义\n// ============================================================================\n\n/** 与 openclaw plugin-sdk 中 WebMediaResult 兼容的类型 */\nexport type WebMediaResult = {\n buffer: Buffer;\n contentType?: string;\n kind?: string;\n fileName?: string;\n};\n\nexport type OutboundMediaLoadOptions = {\n maxBytes?: number;\n mediaLocalRoots?: readonly string[];\n};\n\nexport type DetectMimeOptions = {\n buffer?: Buffer;\n headerMime?: string | null;\n filePath?: string;\n};\n\n// ============================================================================\n// SDK 一次性探测(模块加载时执行,结果缓存)\n// ============================================================================\n\ninterface SdkExports {\n loadOutboundMediaFromUrl?: (url: string, opts?: OutboundMediaLoadOptions) => Promise<WebMediaResult>;\n detectMime?: (opts: DetectMimeOptions) => Promise<string | undefined>;\n getDefaultMediaLocalRoots?: () => readonly string[];\n}\n\nconst _sdkReady: Promise<SdkExports> = import(\"openclaw/plugin-sdk\")\n .then((sdk) => {\n const exports: SdkExports = {};\n if (typeof sdk.loadOutboundMediaFromUrl === \"function\") {\n exports.loadOutboundMediaFromUrl = sdk.loadOutboundMediaFromUrl;\n }\n if (typeof sdk.detectMime === \"function\") {\n exports.detectMime = sdk.detectMime;\n }\n if (typeof sdk.getDefaultMediaLocalRoots === \"function\") {\n exports.getDefaultMediaLocalRoots = sdk.getDefaultMediaLocalRoots;\n }\n return exports;\n })\n .catch(() => {\n // openclaw/plugin-sdk 不可用或版本过低,全部使用 fallback\n return {} as SdkExports;\n });\n\n// ============================================================================\n// detectMime —— 检测 MIME 类型\n// ============================================================================\n\nconst MIME_BY_EXT: Record<string, string> = {\n \".heic\": \"image/heic\",\n \".heif\": \"image/heif\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".png\": \"image/png\",\n \".webp\": \"image/webp\",\n \".gif\": \"image/gif\",\n \".ogg\": \"audio/ogg\",\n \".mp3\": \"audio/mpeg\",\n \".m4a\": \"audio/x-m4a\",\n \".mp4\": \"video/mp4\",\n \".mov\": \"video/quicktime\",\n \".pdf\": \"application/pdf\",\n \".json\": \"application/json\",\n \".zip\": \"application/zip\",\n \".gz\": \"application/gzip\",\n \".tar\": \"application/x-tar\",\n \".7z\": \"application/x-7z-compressed\",\n \".rar\": \"application/vnd.rar\",\n \".doc\": \"application/msword\",\n \".xls\": \"application/vnd.ms-excel\",\n \".ppt\": \"application/vnd.ms-powerpoint\",\n \".docx\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n \".xlsx\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \".pptx\": \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n \".csv\": \"text/csv\",\n \".txt\": \"text/plain\",\n \".md\": \"text/markdown\",\n \".amr\": \"audio/amr\",\n \".aac\": \"audio/aac\",\n \".wav\": \"audio/wav\",\n \".webm\": \"video/webm\",\n \".avi\": \"video/x-msvideo\",\n \".bmp\": \"image/bmp\",\n \".svg\": \"image/svg+xml\",\n};\n\n/** 通过 buffer 魔术字节嗅探 MIME 类型(动态导入 file-type,不强依赖) */\nasync function sniffMimeFromBuffer(buffer: Buffer): Promise<string | undefined> {\n try {\n const { fileTypeFromBuffer } = await import(\"file-type\");\n const type = await fileTypeFromBuffer(buffer);\n return type?.mime ?? undefined;\n } catch {\n return undefined;\n }\n}\n\n/** fallback 版 detectMime,参考 weclaw/src/media/mime.ts */\nasync function detectMimeFallback(opts: DetectMimeOptions): Promise<string | undefined> {\n const ext = opts.filePath ? path.extname(opts.filePath).toLowerCase() : undefined;\n const extMime = ext ? MIME_BY_EXT[ext] : undefined;\n\n const sniffed = opts.buffer ? await sniffMimeFromBuffer(opts.buffer) : undefined;\n\n const isGeneric = (m?: string) =>\n !m || m === \"application/octet-stream\" || m === \"application/zip\";\n\n if (sniffed && (!isGeneric(sniffed) || !extMime)) {\n return sniffed;\n }\n if (extMime) {\n return extMime;\n }\n const headerMime = opts.headerMime?.split(\";\")?.[0]?.trim().toLowerCase();\n if (headerMime && !isGeneric(headerMime)) {\n return headerMime;\n }\n if (sniffed) {\n return sniffed;\n }\n if (headerMime) {\n return headerMime;\n }\n return undefined;\n}\n\n/**\n * 检测 MIME 类型(兼容入口)\n *\n * 支持两种调用签名以兼容不同使用场景:\n * - detectMime(buffer) → 旧式调用\n * - detectMime({ buffer, headerMime, filePath }) → 完整参数\n *\n * 优先使用 SDK 版本,不可用时使用 fallback。\n */\nexport async function detectMime(\n bufferOrOpts: Buffer | DetectMimeOptions,\n): Promise<string | undefined> {\n const sdk = await _sdkReady;\n\n const opts: DetectMimeOptions = Buffer.isBuffer(bufferOrOpts)\n ? { buffer: bufferOrOpts }\n : bufferOrOpts;\n\n if (sdk.detectMime) {\n try {\n return await sdk.detectMime(opts);\n } catch {\n // SDK detectMime 异常,降级到 fallback\n }\n }\n return detectMimeFallback(opts);\n}\n\n// ============================================================================\n// loadOutboundMediaFromUrl —— 从 URL/路径加载媒体文件\n// ============================================================================\n\n/** 安全的本地文件路径校验,参考 weclaw/src/web/media.ts */\nasync function assertLocalMediaAllowed(\n mediaPath: string,\n localRoots: readonly string[] | undefined,\n): Promise<void> {\n if (!localRoots || localRoots.length === 0) {\n throw new Error(`Local media path is not under an allowed directory: ${mediaPath}`);\n }\n\n let resolved: string;\n try {\n resolved = await fs.realpath(mediaPath);\n } catch {\n resolved = path.resolve(mediaPath);\n }\n\n for (const root of localRoots) {\n let resolvedRoot: string;\n try {\n resolvedRoot = await fs.realpath(root);\n } catch {\n resolvedRoot = path.resolve(root);\n }\n if (resolvedRoot === path.parse(resolvedRoot).root) {\n continue;\n }\n if (resolved === resolvedRoot || resolved.startsWith(resolvedRoot + path.sep)) {\n return;\n }\n }\n\n throw new Error(`Local media path is not under an allowed directory: ${mediaPath}`);\n}\n\n/** 从远程 URL 获取媒体 */\nasync function fetchRemoteMedia(\n url: string,\n maxBytes?: number,\n): Promise<{ buffer: Buffer; contentType?: string; fileName?: string }> {\n const res = await fetch(url, { redirect: \"follow\" });\n if (!res.ok) {\n throw new Error(`Failed to fetch media from ${url}: HTTP ${res.status} ${res.statusText}`);\n }\n\n const buffer = Buffer.from(await res.arrayBuffer());\n if (maxBytes && buffer.length > maxBytes) {\n throw new Error(`Media from ${url} exceeds max size (${buffer.length} > ${maxBytes})`);\n }\n\n const headerMime = res.headers.get(\"content-type\")?.split(\";\")?.[0]?.trim();\n\n let fileName: string | undefined;\n const disposition = res.headers.get(\"content-disposition\");\n if (disposition) {\n const match = /filename\\*?\\s*=\\s*(?:UTF-8''|\")?([^\";]+)/i.exec(disposition);\n if (match?.[1]) {\n try {\n fileName = path.basename(decodeURIComponent(match[1].replace(/[\"']/g, \"\").trim()));\n } catch {\n fileName = path.basename(match[1].replace(/[\"']/g, \"\").trim());\n }\n }\n }\n if (!fileName) {\n try {\n const parsed = new URL(url);\n const base = path.basename(parsed.pathname);\n if (base && base.includes(\".\")) fileName = base;\n } catch { /* ignore */ }\n }\n\n const contentType = await detectMimeFallback({ buffer, headerMime, filePath: fileName ?? url });\n\n return { buffer, contentType, fileName };\n}\n\n/** 展开 ~ 为用户主目录 */\nfunction resolveUserPath(p: string): string {\n if (p.startsWith(\"~\")) {\n return path.join(os.homedir(), p.slice(1));\n }\n return p;\n}\n\n/** fallback 版 loadOutboundMediaFromUrl,参考 weclaw/src/web/media.ts */\nasync function loadOutboundMediaFromUrlFallback(\n mediaUrl: string,\n options: OutboundMediaLoadOptions = {},\n): Promise<WebMediaResult> {\n const { maxBytes, mediaLocalRoots } = options;\n\n // 去除 MEDIA: 前缀\n mediaUrl = mediaUrl.replace(/^\\s*MEDIA\\s*:\\s*/i, \"\");\n\n // 处理 file:// URL\n if (mediaUrl.startsWith(\"file://\")) {\n try {\n mediaUrl = fileURLToPath(mediaUrl);\n } catch {\n throw new Error(`Invalid file:// URL: ${mediaUrl}`);\n }\n }\n\n // 远程 URL\n if (/^https?:\\/\\//i.test(mediaUrl)) {\n const fetched = await fetchRemoteMedia(mediaUrl, maxBytes);\n return {\n buffer: fetched.buffer,\n contentType: fetched.contentType,\n fileName: fetched.fileName,\n };\n }\n\n // 展开 ~ 路径\n if (mediaUrl.startsWith(\"~\")) {\n mediaUrl = resolveUserPath(mediaUrl);\n }\n\n // 本地文件:安全校验\n await assertLocalMediaAllowed(mediaUrl, mediaLocalRoots);\n\n // 读取本地文件\n let data: Buffer;\n try {\n const stat = await fs.stat(mediaUrl);\n if (!stat.isFile()) {\n throw new Error(`Local media path is not a file: ${mediaUrl}`);\n }\n data = await fs.readFile(mediaUrl);\n } catch (err: any) {\n if (err?.code === \"ENOENT\") {\n throw new Error(`Local media file not found: ${mediaUrl}`);\n }\n throw err;\n }\n\n if (maxBytes && data.length > maxBytes) {\n throw new Error(`Local media exceeds max size (${data.length} > ${maxBytes})`);\n }\n\n const mime = await detectMimeFallback({ buffer: data, filePath: mediaUrl });\n const fileName = path.basename(mediaUrl) || undefined;\n\n return {\n buffer: data,\n contentType: mime,\n fileName,\n };\n}\n\n/**\n * 从 URL 或本地路径加载媒体文件(兼容入口)\n *\n * 优先使用 SDK 版本,不可用时使用 fallback。\n * SDK 版本抛出的业务异常(如 LocalMediaAccessError)会直接透传。\n */\nexport async function loadOutboundMediaFromUrl(\n mediaUrl: string,\n options: OutboundMediaLoadOptions = {},\n): Promise<WebMediaResult> {\n const sdk = await _sdkReady;\n\n if (sdk.loadOutboundMediaFromUrl) {\n return sdk.loadOutboundMediaFromUrl(mediaUrl, options);\n }\n return loadOutboundMediaFromUrlFallback(mediaUrl, options);\n}\n\n// ============================================================================\n// getDefaultMediaLocalRoots —— 获取默认媒体本地路径白名单\n// ============================================================================\n\n/** 解析 openclaw 状态目录 */\nfunction resolveStateDir(): string {\n const stateOverride = process.env.OPENCLAW_STATE_DIR?.trim() || process.env.CLAWDBOT_STATE_DIR?.trim();\n if (stateOverride) return stateOverride;\n return path.join(os.homedir(), \".openclaw\");\n}\n\n/**\n * 获取默认媒体本地路径白名单(兼容入口)\n *\n * 优先使用 SDK 版本,不可用时手动构建白名单(与 weclaw/src/media/local-roots.ts 逻辑一致)。\n */\nexport async function getDefaultMediaLocalRoots(): Promise<readonly string[]> {\n const sdk = await _sdkReady;\n\n if (sdk.getDefaultMediaLocalRoots) {\n try {\n return sdk.getDefaultMediaLocalRoots();\n } catch {\n // SDK 版本异常,降级到 fallback\n }\n }\n\n // fallback: 手动构建默认白名单\n const stateDir = path.resolve(resolveStateDir());\n return [\n path.join(stateDir, \"media\"),\n path.join(stateDir, \"agents\"),\n path.join(stateDir, \"workspace\"),\n path.join(stateDir, \"sandboxes\"),\n ];\n}\n","/**\n * 企业微信渠道常量定义\n */\n\n/**\n * 企业微信渠道 ID\n */\nexport const CHANNEL_ID = \"wecom\" as const;\n\n/**\n * 企业微信 WebSocket 命令枚举\n */\nexport enum WeComCommand {\n /** 认证订阅 */\n SUBSCRIBE = \"aibot_subscribe\",\n /** 心跳 */\n PING = \"ping\",\n /** 企业微信推送消息 */\n AIBOT_CALLBACK = \"aibot_callback\",\n /** clawdbot 响应消息 */\n AIBOT_RESPONSE = \"aibot_response\",\n}\n\n// ============================================================================\n// 超时和重试配置\n// ============================================================================\n\n/** 图片下载超时时间(毫秒) */\nexport const IMAGE_DOWNLOAD_TIMEOUT_MS = 30_000;\n\n/** 文件下载超时时间(毫秒) */\nexport const FILE_DOWNLOAD_TIMEOUT_MS = 60_000;\n\n/** 消息发送超时时间(毫秒) */\nexport const REPLY_SEND_TIMEOUT_MS = 15_000;\n\n/** 消息处理总超时时间(毫秒) */\nexport const MESSAGE_PROCESS_TIMEOUT_MS = 5 * 60 * 1000;\n\n/** WebSocket 心跳间隔(毫秒) */\nexport const WS_HEARTBEAT_INTERVAL_MS = 30_000;\n\n/** WebSocket 最大重连次数 */\nexport const WS_MAX_RECONNECT_ATTEMPTS = 100;\n\n// ============================================================================\n// 消息状态管理配置\n// ============================================================================\n\n/** messageStates Map 条目的最大 TTL(毫秒),防止内存泄漏 */\nexport const MESSAGE_STATE_TTL_MS = 10 * 60 * 1000;\n\n/** messageStates Map 清理间隔(毫秒) */\nexport const MESSAGE_STATE_CLEANUP_INTERVAL_MS = 60_000;\n\n/** messageStates Map 最大条目数 */\nexport const MESSAGE_STATE_MAX_SIZE = 500;\n\n// ============================================================================\n// 消息模板\n// ============================================================================\n\n/** \"思考中\"流式消息占位内容 */\nexport const THINKING_MESSAGE = \"<think></think>\";\n\n/** 仅包含图片时的消息占位符 */\nexport const MEDIA_IMAGE_PLACEHOLDER = \"<media:image>\";\n\n/** 仅包含文件时的消息占位符 */\nexport const MEDIA_DOCUMENT_PLACEHOLDER = \"<media:document>\";\n// ============================================================================\n// 默认值\n// ============================================================================\n\n// ============================================================================\n// MCP 配置\n// ============================================================================\n\n/** 获取 MCP 配置的 WebSocket 命令 */\nexport const MCP_GET_CONFIG_CMD = \"aibot_get_mcp_config\";\n\n/** MCP 配置拉取超时时间(毫秒) */\nexport const MCP_CONFIG_FETCH_TIMEOUT_MS = 15_000;\n\n// ============================================================================\n// 默认值\n// ============================================================================\n\n/** 默认媒体大小上限(MB) */\nexport const DEFAULT_MEDIA_MAX_MB = 5;\n\n/** 文本分块大小上限 */\nexport const TEXT_CHUNK_LIMIT = 4000;\n\n// ============================================================================\n// 媒体上传相关常量\n// ============================================================================\n\n/** 图片大小上限(字节):10MB */\nexport const IMAGE_MAX_BYTES = 10 * 1024 * 1024;\n\n/** 视频大小上限(字节):10MB */\nexport const VIDEO_MAX_BYTES = 10 * 1024 * 1024;\n\n/** 语音大小上限(字节):2MB */\nexport const VOICE_MAX_BYTES = 2 * 1024 * 1024;\n\n/** 文件大小上限(字节):20MB */\nexport const FILE_MAX_BYTES = 20 * 1024 * 1024;\n\n/** 文件绝对上限(字节):超过此值无法发送,等于 FILE_MAX_BYTES */\nexport const ABSOLUTE_MAX_BYTES = FILE_MAX_BYTES;\n\n/** 上传分片大小(字节,Base64 编码前):512KB */\nexport const UPLOAD_CHUNK_SIZE = 512 * 1024;\n","/**\n * 企业微信消息内容解析模块\n *\n * 负责从 WsFrame 中提取文本、图片、引用等内容\n */\n\n// ============================================================================\n// 消息体类型(来自 SDK WsFrame.body)\n// ============================================================================\n\nexport interface MessageBody {\n msgid: string;\n aibotid?: string;\n chatid?: string;\n chattype: \"single\" | \"group\";\n from: {\n userid: string;\n };\n response_url?: string;\n msgtype: string;\n text?: {\n content: string;\n };\n image?: {\n url?: string;\n aeskey?: string;\n };\n voice?: {\n content?: string;\n };\n mixed?: {\n msg_item: Array<{\n msgtype: \"text\" | \"image\";\n text?: { content: string };\n image?: { url?: string; aeskey?: string };\n }>;\n };\n file?: {\n url?: string;\n aeskey?: string;\n };\n quote?: {\n msgtype: string;\n text?: { content: string };\n voice?: { content: string };\n image?: { url?: string; aeskey?: string };\n file?: { url?: string; aeskey?: string };\n };\n}\n\n// ============================================================================\n// 解析结果类型\n// ============================================================================\n\nexport interface ParsedMessageContent {\n textParts: string[];\n imageUrls: string[];\n imageAesKeys: Map<string, string>;\n fileUrls: string[];\n fileAesKeys: Map<string, string>;\n quoteContent: string | undefined;\n}\n\n// ============================================================================\n// 解析函数\n// ============================================================================\n\n/**\n * 解析消息内容(支持单条消息、图文混排和引用消息)\n * @returns 提取的文本数组、图片URL数组和引用消息内容\n */\nexport function parseMessageContent(body: MessageBody): ParsedMessageContent {\n const textParts: string[] = [];\n const imageUrls: string[] = [];\n const imageAesKeys = new Map<string, string>();\n const fileUrls: string[] = [];\n const fileAesKeys = new Map<string, string>();\n let quoteContent: string | undefined;\n\n // 处理图文混排消息\n if (body.msgtype === \"mixed\" && body.mixed?.msg_item) {\n for (const item of body.mixed.msg_item) {\n if (item.msgtype === \"text\" && item.text?.content) {\n textParts.push(item.text.content);\n } else if (item.msgtype === \"image\" && item.image?.url) {\n imageUrls.push(item.image.url);\n if (item.image.aeskey) {\n imageAesKeys.set(item.image.url, item.image.aeskey);\n }\n }\n }\n } else {\n // 处理单条消息\n if (body.text?.content) {\n textParts.push(body.text.content);\n }\n // 处理语音消息(语音转文字后的文本内容)\n if (body.msgtype === \"voice\" && body.voice?.content) {\n textParts.push(body.voice.content);\n }\n if (body.image?.url) {\n imageUrls.push(body.image.url);\n if (body.image.aeskey) {\n imageAesKeys.set(body.image.url, body.image.aeskey);\n }\n }\n // 处理文件消息\n if (body.msgtype === \"file\" && body.file?.url) {\n fileUrls.push(body.file.url);\n if (body.file.aeskey) {\n fileAesKeys.set(body.file.url, body.file.aeskey);\n }\n }\n }\n\n // 处理引用消息\n if (body.quote) {\n if (body.quote.msgtype === \"text\" && body.quote.text?.content) {\n quoteContent = body.quote.text.content;\n } else if (body.quote.msgtype === \"voice\" && body.quote.voice?.content) {\n quoteContent = body.quote.voice.content;\n } else if (body.quote.msgtype === \"image\" && body.quote.image?.url) {\n // 引用的图片消息:将图片 URL 加入下载列表\n imageUrls.push(body.quote.image.url);\n if (body.quote.image.aeskey) {\n imageAesKeys.set(body.quote.image.url, body.quote.image.aeskey);\n }\n } else if (body.quote.msgtype === \"file\" && body.quote.file?.url) {\n // 引用的文件消息:将文件 URL 加入下载列表\n fileUrls.push(body.quote.file.url);\n if (body.quote.file.aeskey) {\n fileAesKeys.set(body.quote.file.url, body.quote.file.aeskey);\n }\n }\n }\n\n return { textParts, imageUrls, imageAesKeys, fileUrls, fileAesKeys, quoteContent };\n}\n","/**\n * 超时控制工具模块\n *\n * 为异步操作提供统一的超时保护机制\n */\n\n/**\n * 为 Promise 添加超时保护\n *\n * @param promise - 原始 Promise\n * @param timeoutMs - 超时时间(毫秒)\n * @param message - 超时错误消息\n * @returns 带超时保护的 Promise\n */\nexport function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n message?: string,\n): Promise<T> {\n if (timeoutMs <= 0 || !Number.isFinite(timeoutMs)) {\n return promise;\n }\n\n let timeoutId: ReturnType<typeof setTimeout>;\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new TimeoutError(message ?? `Operation timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n });\n\n return Promise.race([promise, timeoutPromise]).finally(() => {\n clearTimeout(timeoutId);\n });\n}\n\n/**\n * 超时错误类型\n */\nexport class TimeoutError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TimeoutError\";\n }\n}\n","/**\n * 企业微信消息发送模块\n *\n * 负责通过 WSClient 发送回复消息,包含超时保护\n */\n\nimport type { RuntimeEnv } from \"openclaw/plugin-sdk\";\nimport { type WSClient, type WsFrame, generateReqId } from \"@wecom/aibot-node-sdk\";\nimport { REPLY_SEND_TIMEOUT_MS } from \"./const.js\";\nimport { withTimeout } from \"./timeout.js\";\n\n// ============================================================================\n// 消息发送\n// ============================================================================\n\n/**\n * 发送企业微信回复消息\n * 供 monitor 内部和 channel outbound 使用\n *\n * @returns messageId (streamId)\n */\nexport async function sendWeComReply(params: {\n wsClient: WSClient;\n frame: WsFrame;\n text?: string;\n runtime: RuntimeEnv;\n /** 是否为流式回复的最终消息,默认为 true */\n finish?: boolean;\n /** 指定 streamId,用于流式回复时保持相同的 streamId */\n streamId?: string;\n}): Promise<string> {\n const { wsClient, frame, text, runtime, finish = true, streamId: existingStreamId } = params;\n\n if (!text) {\n return \"\";\n }\n\n const streamId = existingStreamId || generateReqId(\"stream\");\n\n if (!wsClient.isConnected) {\n runtime.error?.(`[wecom] WSClient not connected, cannot send reply`);\n throw new Error(\"WSClient not connected\");\n }\n\n // 使用 SDK 的 replyStream 方法发送消息,带超时保护\n await withTimeout(\n wsClient.replyStream(frame, streamId, text, finish),\n REPLY_SEND_TIMEOUT_MS,\n `Reply send timed out (streamId=${streamId})`,\n );\n runtime.log?.(`[plugin -> server] streamId=${streamId}, finish=${finish}`);\n\n return streamId;\n}\n","/**\n * 企业微信媒体(图片)下载和保存模块\n *\n * 负责下载、检测格式、保存图片到本地,包含超时保护\n */\n\nimport type { OpenClawConfig, RuntimeEnv } from \"openclaw/plugin-sdk\";\nimport type { WSClient } from \"@wecom/aibot-node-sdk\";\nimport { fileTypeFromBuffer } from \"file-type\";\nimport { getWeComRuntime } from \"./runtime.js\";\nimport { IMAGE_DOWNLOAD_TIMEOUT_MS, FILE_DOWNLOAD_TIMEOUT_MS, DEFAULT_MEDIA_MAX_MB } from \"./const.js\";\nimport { withTimeout } from \"./timeout.js\";\nimport type { ResolvedWeComAccount } from \"./utils.js\";\n\n// ============================================================================\n// 图片格式检测辅助函数(基于 file-type 包)\n// ============================================================================\n\n/**\n * 检查 Buffer 是否为有效的图片格式\n */\nasync function isImageBuffer(data: Buffer): Promise<boolean> {\n const type = await fileTypeFromBuffer(data);\n return type?.mime.startsWith(\"image/\") ?? false;\n}\n\n/**\n * 检测 Buffer 的图片内容类型\n */\nasync function detectImageContentType(data: Buffer): Promise<string> {\n const type = await fileTypeFromBuffer(data);\n if (type?.mime.startsWith(\"image/\")) {\n return type.mime;\n }\n return \"application/octet-stream\";\n}\n\n// ============================================================================\n// 图片下载和保存\n// ============================================================================\n\n/**\n * 下载并保存所有图片到本地,每张图片的下载带超时保护\n */\nexport async function downloadAndSaveImages(params: {\n imageUrls: string[];\n imageAesKeys?: Map<string, string>;\n account: ResolvedWeComAccount;\n config: OpenClawConfig;\n runtime: RuntimeEnv;\n wsClient: WSClient;\n}): Promise<Array<{ path: string; contentType?: string }>> {\n const { imageUrls, config, runtime, wsClient } = params;\n const core = getWeComRuntime();\n const mediaList: Array<{ path: string; contentType?: string }> = [];\n\n for (const imageUrl of imageUrls) {\n try {\n runtime.log?.(`[wecom] Downloading image: url=${imageUrl}`);\n const mediaMaxMb = config.agents?.defaults?.mediaMaxMb ?? DEFAULT_MEDIA_MAX_MB;\n const maxBytes = mediaMaxMb * 1024 * 1024;\n\n let imageBuffer: Buffer;\n let imageContentType: string;\n let originalFilename: string | undefined;\n const imageAesKey = params.imageAesKeys?.get(imageUrl);\n\n try {\n // 优先使用 SDK 的 downloadFile 方法下载(带超时保护)\n const result = await withTimeout(\n wsClient.downloadFile(imageUrl, imageAesKey),\n IMAGE_DOWNLOAD_TIMEOUT_MS,\n `Image download timed out: ${imageUrl}`,\n );\n imageBuffer = result.buffer;\n originalFilename = result.filename;\n imageContentType = await detectImageContentType(imageBuffer);\n runtime.log?.(`[wecom] Image downloaded: size=${imageBuffer.length}, contentType=${imageContentType}, filename=${originalFilename ?? '(none)'}`);\n } catch (sdkError) {\n // 如果 SDK 方法失败,回退到原有方式(带超时保护)\n runtime.log?.(`[wecom] SDK download failed, fallback: ${String(sdkError)}`);\n const fetched = await withTimeout(\n core.channel.media.fetchRemoteMedia({ url: imageUrl }),\n IMAGE_DOWNLOAD_TIMEOUT_MS,\n `Manual image download timed out: ${imageUrl}`,\n ) as { buffer: Buffer; contentType?: string };\n runtime.log?.(`[wecom] Image fetched: contentType=${fetched.contentType}, size=${fetched.buffer.length}`);\n\n imageBuffer = fetched.buffer;\n imageContentType = fetched.contentType ?? \"application/octet-stream\";\n const isValidImage = await isImageBuffer(fetched.buffer);\n\n if (!isValidImage) {\n runtime.log?.(`[wecom] WARN: Downloaded data is not a valid image format`);\n }\n }\n\n const saved = await core.channel.media.saveMediaBuffer(\n imageBuffer,\n imageContentType,\n \"inbound\",\n maxBytes,\n originalFilename,\n );\n mediaList.push({ path: saved.path, contentType: saved.contentType });\n runtime.log?.(`[wecom][plugin] Image saved: path=${saved.path}, contentType=${saved.contentType}`);\n } catch (err) {\n runtime.error?.(`[wecom] Failed to download image: ${String(err)}`);\n }\n }\n\n return mediaList;\n}\n\n/**\n * 下载并保存所有文件到本地,每个文件的下载带超时保护\n */\nexport async function downloadAndSaveFiles(params: {\n fileUrls: string[];\n fileAesKeys?: Map<string, string>;\n account: ResolvedWeComAccount;\n config: OpenClawConfig;\n runtime: RuntimeEnv;\n wsClient: WSClient;\n}): Promise<Array<{ path: string; contentType?: string }>> {\n const { fileUrls, config, runtime, wsClient } = params;\n const core = getWeComRuntime();\n const mediaList: Array<{ path: string; contentType?: string }> = [];\n\n for (const fileUrl of fileUrls) {\n try {\n runtime.log?.(`[wecom] Downloading file: url=${fileUrl}`);\n const mediaMaxMb = config.agents?.defaults?.mediaMaxMb ?? DEFAULT_MEDIA_MAX_MB;\n const maxBytes = mediaMaxMb * 1024 * 1024;\n\n let fileBuffer: Buffer;\n let fileContentType: string;\n let originalFilename: string | undefined;\n const fileAesKey = params.fileAesKeys?.get(fileUrl);\n\n try {\n // 使用 SDK 的 downloadFile 方法下载(带超时保护)\n const result = await withTimeout(\n wsClient.downloadFile(fileUrl, fileAesKey),\n FILE_DOWNLOAD_TIMEOUT_MS,\n `File download timed out: ${fileUrl}`,\n );\n fileBuffer = result.buffer;\n originalFilename = result.filename;\n\n // 检测文件类型\n const type = await fileTypeFromBuffer(fileBuffer);\n fileContentType = type?.mime ?? \"application/octet-stream\";\n runtime.log?.(`[wecom] File downloaded: size=${fileBuffer.length}, contentType=${fileContentType}, filename=${originalFilename ?? '(none)'}`);\n } catch (sdkError) {\n // 如果 SDK 方法失败,回退到 fetchRemoteMedia(带超时保护)\n runtime.log?.(`[wecom] SDK file download failed, fallback: ${String(sdkError)}`);\n const fetched = await withTimeout(\n core.channel.media.fetchRemoteMedia({ url: fileUrl }),\n FILE_DOWNLOAD_TIMEOUT_MS,\n `Manual file download timed out: ${fileUrl}`,\n ) as { buffer: Buffer; contentType?: string };\n runtime.log?.(`[wecom] File fetched: contentType=${fetched.contentType}, size=${fetched.buffer.length}`);\n\n fileBuffer = fetched.buffer;\n fileContentType = fetched.contentType ?? \"application/octet-stream\";\n }\n\n const saved = await core.channel.media.saveMediaBuffer(\n fileBuffer,\n fileContentType,\n \"inbound\",\n maxBytes,\n originalFilename,\n );\n mediaList.push({ path: saved.path, contentType: saved.contentType });\n runtime.log?.(`[wecom][plugin] File saved: path=${saved.path}, contentType=${saved.contentType}`);\n } catch (err) {\n runtime.error?.(`[wecom] Failed to download file: ${String(err)}`);\n }\n }\n\n return mediaList;\n}\n","/**\n * 企业微信出站媒体上传工具模块\n *\n * 负责:\n * - 从 mediaUrl 加载文件 buffer(远程 URL 或本地路径均支持)\n * - 检测 MIME 类型并映射为企微媒体类型\n * - 文件大小检查与降级策略\n */\n\nimport type { WeComMediaType, WSClient, WsFrameHeaders } from \"@wecom/aibot-node-sdk\";\nimport {\n loadOutboundMediaFromUrl,\n detectMime,\n type WebMediaResult,\n} from \"./openclaw-compat.js\";\nimport {\n IMAGE_MAX_BYTES,\n VIDEO_MAX_BYTES,\n VOICE_MAX_BYTES,\n FILE_MAX_BYTES,\n ABSOLUTE_MAX_BYTES,\n} from \"./const.js\";\n\n// ============================================================================\n// 类型定义\n// ============================================================================\n\n/** 媒体文件解析结果 */\nexport interface ResolvedMedia {\n /** 文件数据 */\n buffer: Buffer;\n /** 检测到的 MIME 类型 */\n contentType: string;\n /** 文件名(从 URL 提取或默认生成) */\n fileName: string;\n}\n\n/** 文件大小检查结果 */\nexport interface FileSizeCheckResult {\n /** 最终确定的企微媒体类型(可能被降级) */\n finalType: WeComMediaType;\n /** 是否需要拒绝(超过绝对限制) */\n shouldReject: boolean;\n /** 拒绝原因(仅 shouldReject=true 时有值) */\n rejectReason?: string;\n /** 是否发生了降级 */\n downgraded: boolean;\n /** 降级说明(仅 downgraded=true 时有值) */\n downgradeNote?: string;\n}\n\n// ============================================================================\n// MIME → 企微媒体类型映射\n// ============================================================================\n\n/**\n * 根据 MIME 类型检测企微媒体类型\n *\n * @param mimeType - MIME 类型字符串\n * @returns 企微媒体类型\n */\nexport function detectWeComMediaType(mimeType: string): WeComMediaType {\n const mime = mimeType.toLowerCase();\n\n // 图片类型\n if (mime.startsWith(\"image/\")) {\n return \"image\";\n }\n\n // 视频类型\n if (mime.startsWith(\"video/\")) {\n return \"video\";\n }\n\n // 语音类型\n if (\n mime.startsWith(\"audio/\") ||\n mime === \"application/ogg\" // OGG 音频容器\n ) {\n return \"voice\";\n }\n\n // 其他类型默认为文件\n return \"file\";\n}\n\n// ============================================================================\n// 媒体文件加载\n// ============================================================================\n\n/**\n * 从 mediaUrl 加载媒体文件\n *\n * 支持远程 URL(http/https)和本地路径(file:// 或绝对路径),\n * 利用 openclaw plugin-sdk 的 loadOutboundMediaFromUrl 统一处理。\n *\n * @param mediaUrl - 媒体文件的 URL 或本地路径\n * @param mediaLocalRoots - 允许读取本地文件的安全白名单目录\n * @returns 解析后的媒体文件信息\n */\nexport async function resolveMediaFile(\n mediaUrl: string,\n mediaLocalRoots?: readonly string[],\n): Promise<ResolvedMedia> {\n // 使用兼容层加载媒体文件(优先 SDK,不可用时 fallback)\n // 传入足够大的 maxBytes,由我们自己在后续步骤做大小检查\n const result: WebMediaResult = await loadOutboundMediaFromUrl(mediaUrl, {\n maxBytes: ABSOLUTE_MAX_BYTES,\n mediaLocalRoots,\n });\n\n if (!result.buffer || result.buffer.length === 0) {\n throw new Error(`Failed to load media from ${mediaUrl}: empty buffer`);\n }\n\n // 检测真实 MIME 类型\n let contentType = result.contentType || \"application/octet-stream\";\n\n // 如果没有返回准确的 contentType,尝试通过 buffer 魔术字节检测\n if (\n contentType === \"application/octet-stream\" ||\n contentType === \"text/plain\"\n ) {\n const detected = await detectMime(result.buffer);\n if (detected) {\n contentType = detected;\n }\n }\n\n // 提取文件名\n const fileName = extractFileName(mediaUrl, result.fileName, contentType);\n\n return {\n buffer: result.buffer,\n contentType,\n fileName,\n };\n}\n\n// ============================================================================\n// 文件大小检查与降级\n// ============================================================================\n\n/** 企微语音消息仅支持 AMR 格式 */\nconst VOICE_SUPPORTED_MIMES = new Set([\"audio/amr\"]);\n\n/**\n * 检查文件大小并执行降级策略\n *\n * 降级规则:\n * - voice 非 AMR 格式 → 降级为 file(企微后台仅支持 AMR)\n * - image 超过 10MB → 降级为 file\n * - video 超过 10MB → 降级为 file\n * - voice 超过 2MB → 降级为 file\n * - file 超过 20MB → 拒绝发送\n *\n * @param fileSize - 文件大小(字节)\n * @param detectedType - 检测到的企微媒体类型\n * @param contentType - 文件的 MIME 类型(用于语音格式校验)\n * @returns 大小检查结果\n */\nexport function applyFileSizeLimits(\n fileSize: number,\n detectedType: WeComMediaType,\n contentType?: string,\n): FileSizeCheckResult {\n const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);\n\n // 先检查绝对上限(20MB)\n if (fileSize > ABSOLUTE_MAX_BYTES) {\n return {\n finalType: detectedType,\n shouldReject: true,\n rejectReason: `文件大小 ${fileSizeMB}MB 超过了企业微信允许的最大限制 20MB,无法发送。请尝试压缩文件或减小文件大小。`,\n downgraded: false,\n };\n }\n\n // 按类型检查大小限制\n switch (detectedType) {\n case \"image\":\n if (fileSize > IMAGE_MAX_BYTES) {\n return {\n finalType: \"file\",\n shouldReject: false,\n downgraded: true,\n downgradeNote: `图片大小 ${fileSizeMB}MB 超过 10MB 限制,已转为文件格式发送`,\n };\n }\n break;\n\n case \"video\":\n if (fileSize > VIDEO_MAX_BYTES) {\n return {\n finalType: \"file\",\n shouldReject: false,\n downgraded: true,\n downgradeNote: `视频大小 ${fileSizeMB}MB 超过 10MB 限制,已转为文件格式发送`,\n };\n }\n break;\n\n case \"voice\":\n // 企微语音消息仅支持 AMR 格式,非 AMR 一律降级为文件\n if (contentType && !VOICE_SUPPORTED_MIMES.has(contentType.toLowerCase())) {\n return {\n finalType: \"file\",\n shouldReject: false,\n downgraded: true,\n downgradeNote: `语音格式 ${contentType} 不支持,企微仅支持 AMR 格式,已转为文件格式发送`,\n };\n }\n if (fileSize > VOICE_MAX_BYTES) {\n return {\n finalType: \"file\",\n shouldReject: false,\n downgraded: true,\n downgradeNote: `语音大小 ${fileSizeMB}MB 超过 2MB 限制,已转为文件格式发送`,\n };\n }\n break;\n\n case \"file\":\n // file 类型在绝对上限内即可\n break;\n }\n\n // 无需降级\n return {\n finalType: detectedType,\n shouldReject: false,\n downgraded: false,\n };\n}\n\n// ============================================================================\n// 辅助函数\n// ============================================================================\n\n/**\n * 从 URL/路径中提取文件名\n */\nfunction extractFileName(\n mediaUrl: string,\n providedFileName?: string,\n contentType?: string,\n): string {\n // 优先使用提供的文件名\n if (providedFileName) {\n return providedFileName;\n }\n\n // 尝试从 URL 中提取\n try {\n const urlObj = new URL(mediaUrl, \"file://\");\n const pathParts = urlObj.pathname.split(\"/\");\n const lastPart = pathParts[pathParts.length - 1];\n if (lastPart && lastPart.includes(\".\")) {\n return decodeURIComponent(lastPart);\n }\n } catch {\n // 尝试作为普通路径处理\n const parts = mediaUrl.split(\"/\");\n const lastPart = parts[parts.length - 1];\n if (lastPart && lastPart.includes(\".\")) {\n return lastPart;\n }\n }\n\n // 使用 MIME 类型生成默认文件名\n const ext = mimeToExtension(contentType || \"application/octet-stream\");\n return `media_${Date.now()}${ext}`;\n}\n\n/**\n * MIME 类型转文件扩展名\n */\nfunction mimeToExtension(mime: string): string {\n const map: Record<string, string> = {\n \"image/jpeg\": \".jpg\",\n \"image/png\": \".png\",\n \"image/gif\": \".gif\",\n \"image/webp\": \".webp\",\n \"image/bmp\": \".bmp\",\n \"image/svg+xml\": \".svg\",\n \"video/mp4\": \".mp4\",\n \"video/quicktime\": \".mov\",\n \"video/x-msvideo\": \".avi\",\n \"video/webm\": \".webm\",\n \"audio/mpeg\": \".mp3\",\n \"audio/ogg\": \".ogg\",\n \"audio/wav\": \".wav\",\n \"audio/amr\": \".amr\",\n \"audio/aac\": \".aac\",\n \"application/pdf\": \".pdf\",\n \"application/zip\": \".zip\",\n \"application/msword\": \".doc\",\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\":\n \".docx\",\n \"application/vnd.ms-excel\": \".xls\",\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\":\n \".xlsx\",\n \"text/plain\": \".txt\",\n };\n return map[mime] || \".bin\";\n}\n\n// ============================================================================\n// 公共媒体上传+发送流程\n// ============================================================================\n\n/** uploadAndSendMedia 的参数 */\nexport interface UploadAndSendMediaOptions {\n /** WSClient 实例 */\n wsClient: WSClient;\n /** 媒体文件的 URL 或本地路径 */\n mediaUrl: string;\n /** 目标会话 ID(用于 aibot_send_msg 主动发送) */\n chatId: string;\n /** 允许读取本地文件的安全白名单目录 */\n mediaLocalRoots?: readonly string[];\n /** 日志函数 */\n log?: (...args: any[]) => void;\n /** 错误日志函数 */\n errorLog?: (...args: any[]) => void;\n}\n\n/** uploadAndSendMedia 的返回结果 */\nexport interface UploadAndSendMediaResult {\n /** 是否发送成功 */\n ok: boolean;\n /** 发送后返回的 messageId */\n messageId?: string;\n /** 最终的企微媒体类型 */\n finalType?: WeComMediaType;\n /** 是否被拒绝(文件过大) */\n rejected?: boolean;\n /** 拒绝原因 */\n rejectReason?: string;\n /** 是否发生了降级 */\n downgraded?: boolean;\n /** 降级说明 */\n downgradeNote?: string;\n /** 错误信息 */\n error?: string;\n}\n\n/**\n * 公共媒体上传+发送流程\n *\n * 统一处理:resolveMediaFile → detectType → sizeCheck → uploadMedia → sendMediaMessage\n * 媒体消息统一走 aibot_send_msg 主动发送,避免多文件场景下 reqId 只能用一次的问题。\n * channel.ts 的 sendMedia 和 monitor.ts 的 deliver 回调都使用此函数。\n */\nexport async function uploadAndSendMedia(\n options: UploadAndSendMediaOptions,\n): Promise<UploadAndSendMediaResult> {\n const { wsClient, mediaUrl, chatId, mediaLocalRoots, log, errorLog } = options;\n\n try {\n // 1. 加载媒体文件\n log?.(`[wecom] Uploading media: url=${mediaUrl}`);\n const media = await resolveMediaFile(mediaUrl, mediaLocalRoots);\n\n // 2. 检测企微媒体类型\n const detectedType = detectWeComMediaType(media.contentType);\n\n // 3. 文件大小检查与降级策略\n const sizeCheck = applyFileSizeLimits(media.buffer.length, detectedType, media.contentType);\n\n if (sizeCheck.shouldReject) {\n errorLog?.(`[wecom] Media rejected: ${sizeCheck.rejectReason}`);\n return {\n ok: false,\n rejected: true,\n rejectReason: sizeCheck.rejectReason,\n finalType: sizeCheck.finalType,\n };\n }\n\n const finalType = sizeCheck.finalType;\n\n // 4. 分片上传获取 media_id\n const uploadResult = await wsClient.uploadMedia(media.buffer, {\n type: finalType,\n filename: media.fileName,\n });\n log?.(`[wecom] Media uploaded: media_id=${uploadResult.media_id}, type=${finalType}`);\n\n // 5. 统一通过 aibot_send_msg 主动发送媒体消息\n const result = await wsClient.sendMediaMessage(chatId, finalType, uploadResult.media_id);\n const messageId = result?.headers?.req_id ?? `wecom-media-${Date.now()}`;\n log?.(`[wecom] Media sent via sendMediaMessage: chatId=${chatId}, type=${finalType}`);\n\n return {\n ok: true,\n messageId,\n finalType,\n downgraded: sizeCheck.downgraded,\n downgradeNote: sizeCheck.downgradeNote,\n };\n } catch (err) {\n const errMsg = String(err);\n errorLog?.(`[wecom] Failed to upload/send media: url=${mediaUrl}, error=${errMsg}`);\n return {\n ok: false,\n error: errMsg,\n };\n }\n}\n\n// ============================================================================\n// 被动回复媒体上传+发送流程\n// ============================================================================\n\n/** uploadAndReplyMedia 的参数 */\nexport interface UploadAndReplyMediaOptions {\n /** WSClient 实例 */\n wsClient: WSClient;\n /** 媒体文件的 URL 或本地路径 */\n mediaUrl: string;\n /** 原始 WebSocket 帧(用于 aibot_respond_msg 被动回复,携带 req_id) */\n frame: WsFrameHeaders;\n /** 允许读取本地文件的安全白名单目录 */\n mediaLocalRoots?: readonly string[];\n /** 日志函数 */\n log?: (...args: any[]) => void;\n /** 错误日志函数 */\n errorLog?: (...args: any[]) => void;\n}\n\n/**\n * 被动回复媒体上传+发送流程\n *\n * 统一处理:resolveMediaFile → detectType → sizeCheck → uploadMedia → replyMedia\n * 通过 aibot_respond_msg 被动回复通道发送媒体消息,可以覆盖之前的 THINKING_MESSAGE。\n *\n * 适用场景:回包只有媒体没有文本时,第一个媒体文件用此方法发送以清理 thinking 状态。\n */\nexport async function uploadAndReplyMedia(\n options: UploadAndReplyMediaOptions,\n): Promise<UploadAndSendMediaResult> {\n const { wsClient, mediaUrl, frame, mediaLocalRoots, log, errorLog } = options;\n\n try {\n // 1. 加载媒体文件\n log?.(`[wecom] Uploading media (reply mode): url=${mediaUrl}`);\n const media = await resolveMediaFile(mediaUrl, mediaLocalRoots);\n\n // 2. 检测企微媒体类型\n const detectedType = detectWeComMediaType(media.contentType);\n\n // 3. 文件大小检查与降级策略\n const sizeCheck = applyFileSizeLimits(media.buffer.length, detectedType, media.contentType);\n\n if (sizeCheck.shouldReject) {\n errorLog?.(`[wecom] Media rejected: ${sizeCheck.rejectReason}`);\n return {\n ok: false,\n rejected: true,\n rejectReason: sizeCheck.rejectReason,\n finalType: sizeCheck.finalType,\n };\n }\n\n const finalType = sizeCheck.finalType;\n\n // 4. 分片上传获取 media_id\n const uploadResult = await wsClient.uploadMedia(media.buffer, {\n type: finalType,\n filename: media.fileName,\n });\n log?.(`[wecom] Media uploaded: media_id=${uploadResult.media_id}, type=${finalType}`);\n\n // 5. 通过 aibot_respond_msg 被动回复发送媒体消息(会覆盖 THINKING_MESSAGE)\n const result = await wsClient.replyMedia(frame, finalType, uploadResult.media_id);\n const messageId = result?.headers?.req_id ?? `wecom-reply-media-${Date.now()}`;\n log?.(`[wecom] Media sent via replyMedia (passive reply): type=${finalType}`);\n\n return {\n ok: true,\n messageId,\n finalType,\n downgraded: sizeCheck.downgraded,\n downgradeNote: sizeCheck.downgradeNote,\n };\n } catch (err) {\n const errMsg = String(err);\n errorLog?.(`[wecom] Failed to upload/reply media: url=${mediaUrl}, error=${errMsg}`);\n return {\n ok: false,\n error: errMsg,\n };\n }\n}\n","/**\n * 企业微信群组访问控制模块\n *\n * 负责群组策略检查(groupPolicy、群组白名单、群内发送者白名单)\n */\n\nimport type { OpenClawConfig, RuntimeEnv } from \"openclaw/plugin-sdk\";\nimport { CHANNEL_ID } from \"./const.js\";\nimport type { ResolvedWeComAccount, WeComConfig, WeComGroupConfig } from \"./utils.js\";\n\n// ============================================================================\n// 检查结果类型\n// ============================================================================\n\n/**\n * 群组策略检查结果\n */\nexport interface GroupPolicyCheckResult {\n /** 是否允许继续处理消息 */\n allowed: boolean;\n}\n\n// ============================================================================\n// 内部辅助函数\n// ============================================================================\n\n/**\n * 解析企业微信群组配置\n */\nfunction resolveWeComGroupConfig(params: {\n cfg?: WeComConfig;\n groupId?: string | null;\n}): WeComGroupConfig | undefined {\n const groups = params.cfg?.groups ?? {};\n const wildcard = groups[\"*\"];\n const groupId = params.groupId?.trim();\n if (!groupId) {\n return undefined;\n }\n\n const direct = groups[groupId];\n if (direct) {\n return direct;\n }\n\n const lowered = groupId.toLowerCase();\n const matchKey = Object.keys(groups).find((key) => key.toLowerCase() === lowered);\n if (matchKey) {\n return groups[matchKey];\n }\n return wildcard;\n}\n\n/**\n * 检查群组是否在允许列表中\n */\nfunction isWeComGroupAllowed(params: {\n groupPolicy: \"open\" | \"allowlist\" | \"disabled\";\n allowFrom: Array<string | number>;\n groupId: string;\n}): boolean {\n const { groupPolicy } = params;\n if (groupPolicy === \"disabled\") {\n return false;\n }\n if (groupPolicy === \"open\") {\n return true;\n }\n // allowlist 模式:检查群组是否在允许列表中\n const normalizedAllowFrom = params.allowFrom.map((entry) =>\n String(entry).replace(new RegExp(`^${CHANNEL_ID}:`, \"i\"), \"\").trim()\n );\n if (normalizedAllowFrom.includes(\"*\")) {\n return true;\n }\n const normalizedGroupId = params.groupId.trim();\n return normalizedAllowFrom.some(\n (entry) => entry === normalizedGroupId || entry.toLowerCase() === normalizedGroupId.toLowerCase()\n );\n}\n\n/**\n * 检查群组内发送者是否在允许列表中\n */\nfunction isGroupSenderAllowed(params: {\n senderId: string;\n groupId: string;\n wecomConfig: WeComConfig;\n}): boolean {\n const { senderId, groupId, wecomConfig } = params;\n\n const groupConfig = resolveWeComGroupConfig({\n cfg: wecomConfig,\n groupId,\n });\n\n const perGroupSenderAllowFrom = (groupConfig?.allowFrom ?? []).map((v) => String(v));\n\n if (perGroupSenderAllowFrom.length === 0) {\n return true;\n }\n\n if (perGroupSenderAllowFrom.includes(\"*\")) {\n return true;\n }\n\n return perGroupSenderAllowFrom.some((entry) => {\n const normalized = entry.replace(new RegExp(`^${CHANNEL_ID}:`, \"i\"), \"\").trim();\n return normalized === senderId || normalized === `user:${senderId}`;\n });\n}\n\n// ============================================================================\n// 公开 API\n// ============================================================================\n\n/**\n * 检查群组策略访问控制\n * @returns 检查结果,包含是否允许继续处理\n */\nexport function checkGroupPolicy(params: {\n chatId: string;\n senderId: string;\n account: ResolvedWeComAccount;\n config: OpenClawConfig;\n runtime: RuntimeEnv;\n}): GroupPolicyCheckResult {\n const { chatId, senderId, account, config, runtime } = params;\n const wecomConfig = (config.channels?.[CHANNEL_ID] ?? {}) as WeComConfig;\n\n const defaultGroupPolicy = config.channels?.[CHANNEL_ID]?.groupPolicy;\n const groupPolicy = account.config.groupPolicy ?? defaultGroupPolicy ?? \"open\"\n // const { groupPolicy, providerMissingFallbackApplied } = resolveOpenProviderRuntimeGroupPolicy({\n // providerConfigPresent: config.channels?.[CHANNEL_ID] !== undefined,\n // groupPolicy: wecomConfig.groupPolicy,\n // defaultGroupPolicy,\n // });\n\n // warnMissingProviderGroupPolicyFallbackOnce({\n // providerMissingFallbackApplied,\n // providerKey: CHANNEL_ID,\n // accountId: account.accountId,\n // log: (msg) => runtime.log?.(msg),\n // });\n\n const groupAllowFrom = wecomConfig.groupAllowFrom ?? [];\n const groupAllowed = isWeComGroupAllowed({\n groupPolicy,\n allowFrom: groupAllowFrom,\n groupId: chatId,\n });\n\n if (!groupAllowed) {\n runtime.log?.(\n `[WeCom] Group ${chatId} not allowed (groupPolicy=${groupPolicy})`,\n );\n return { allowed: false };\n }\n\n const senderAllowed = isGroupSenderAllowed({\n senderId,\n groupId: chatId,\n wecomConfig,\n });\n\n if (!senderAllowed) {\n runtime.log?.(\n `[WeCom] Sender ${senderId} not in group ${chatId} sender allowlist`,\n );\n return { allowed: false };\n }\n\n return { allowed: true };\n}\n\n/**\n * 检查发送者是否在允许列表中(通用)\n */\nexport function isSenderAllowed(senderId: string, allowFrom: string[]): boolean {\n if (allowFrom.includes(\"*\")) {\n return true;\n }\n return allowFrom.some((entry) => {\n const normalized = entry.replace(new RegExp(`^${CHANNEL_ID}:`, \"i\"), \"\").trim();\n return normalized === senderId || normalized === `user:${senderId}`;\n });\n}\n","/**\n * 企业微信 DM(私聊)访问控制模块\n *\n * 负责私聊策略检查、配对流程\n */\n\nimport type { RuntimeEnv } from \"openclaw/plugin-sdk\";\nimport type { WSClient, WsFrame } from \"@wecom/aibot-node-sdk\";\nimport { getWeComRuntime } from \"./runtime.js\";\nimport { CHANNEL_ID } from \"./const.js\";\nimport type { ResolvedWeComAccount } from \"./utils.js\";\nimport { sendWeComReply } from \"./message-sender.js\";\nimport { isSenderAllowed } from \"./group-policy.js\";\n\n// ============================================================================\n// 检查结果类型\n// ============================================================================\n\n/**\n * DM Policy 检查结果\n */\nexport interface DmPolicyCheckResult {\n /** 是否允许继续处理消息 */\n allowed: boolean;\n /** 是否已发送配对消息(仅在 pairing 模式下) */\n pairingSent?: boolean;\n}\n\n// ============================================================================\n// 公开 API\n// ============================================================================\n\n/**\n * 检查 DM Policy 访问控制\n * @returns 检查结果,包含是否允许继续处理\n */\nexport async function checkDmPolicy(params: {\n senderId: string;\n isGroup: boolean;\n account: ResolvedWeComAccount;\n wsClient: WSClient;\n frame: WsFrame;\n runtime: RuntimeEnv;\n}): Promise<DmPolicyCheckResult> {\n const { senderId, isGroup, account, wsClient, frame, runtime } = params;\n const core = getWeComRuntime();\n\n // 群聊消息不检查 DM Policy\n if (isGroup) {\n return { allowed: true };\n }\n\n const dmPolicy = account.config.dmPolicy ?? \"open\";\n const configAllowFrom = (account.config.allowFrom ?? []).map((v) => String(v));\n\n // 如果 dmPolicy 是 disabled,直接拒绝\n if (dmPolicy === \"disabled\") {\n runtime.log?.(`[WeCom] Blocked DM from ${senderId} (dmPolicy=disabled)`);\n return { allowed: false };\n }\n\n // 如果是 open 模式,允许所有人\n if (dmPolicy === \"open\") {\n return { allowed: true };\n }\n\n // OpenClaw <= 2026.2.19 signature: readAllowFromStore(channel, env?, accountId?)\n const oldStoreAllowFrom = await core.channel.pairing.readAllowFromStore('wecom', undefined, account.accountId).catch(() => []);;\n // Compatibility fallback for newer OpenClaw implementations.\n const newStoreAllowFrom = await core.channel.pairing\n .readAllowFromStore({ channel: CHANNEL_ID, accountId: account.accountId })\n .catch(() => []);\n\n // 检查发送者是否在允许列表中\n const storeAllowFrom = [...oldStoreAllowFrom, ...newStoreAllowFrom];\n\n const effectiveAllowFrom = [...configAllowFrom, ...storeAllowFrom];\n const senderAllowedResult = isSenderAllowed(senderId, effectiveAllowFrom);\n\n if (senderAllowedResult) {\n return { allowed: true };\n }\n\n // 处理未授权用户\n if (dmPolicy === \"pairing\") {\n const { code, created } = await core.channel.pairing.upsertPairingRequest({\n channel: CHANNEL_ID,\n id: senderId,\n accountId: account.accountId,\n meta: { name: senderId },\n });\n\n if (created) {\n runtime.log?.(`[WeCom] Pairing request created for sender=${senderId}`);\n try {\n await sendWeComReply({\n wsClient,\n frame,\n text: core.channel.pairing.buildPairingReply({\n channel: CHANNEL_ID,\n idLine: `您的企业微信用户ID: ${senderId}`,\n code,\n }),\n runtime,\n finish: true,\n });\n } catch (err) {\n runtime.error?.(`[WeCom] Failed to send pairing reply to ${senderId}: ${String(err)}`);\n }\n } else {\n runtime.log?.(`[WeCom] Pairing request already exists for sender=${senderId}`);\n }\n return { allowed: false, pairingSent: created };\n }\n\n // allowlist 模式:直接拒绝未授权用户\n runtime.log?.(`[WeCom] Blocked unauthorized sender ${senderId} (dmPolicy=${dmPolicy})`);\n return { allowed: false };\n}\n","import os from \"node:os\";\nimport path from \"node:path\";\nimport {\n readJsonFileWithFallback,\n writeJsonFileAtomically,\n withFileLock,\n} from \"openclaw/plugin-sdk\";\n\n// ============================================================================\n// 类型定义\n// ============================================================================\n\n/** 单条 reqId 记录 */\ninterface ReqIdEntry {\n /** 请求 ID */\n reqId: string;\n /** 记录时间戳(毫秒) */\n ts: number;\n}\n\n/** 磁盘存储的数据结构:chatId → ReqIdEntry */\ntype ReqIdStoreData = Record<string, ReqIdEntry>;\n\n/** Store 配置 */\ninterface ReqIdStoreOptions {\n /** TTL 毫秒数,超时的 reqId 视为过期(默认 24 小时) */\n ttlMs?: number;\n /** 内存最大条目数(默认 200) */\n memoryMaxSize?: number;\n /** 磁盘最大条目数(默认 500) */\n fileMaxEntries?: number;\n /** 磁盘写入防抖时间(毫秒),默认 1000ms */\n flushDebounceMs?: number;\n}\n\n// ============================================================================\n// 常量\n// ============================================================================\n\nconst DEFAULT_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 天\nconst DEFAULT_MEMORY_MAX_SIZE = 200;\nconst DEFAULT_FILE_MAX_ENTRIES = 500;\nconst DEFAULT_FLUSH_DEBOUNCE_MS = 1000;\n\nconst DEFAULT_LOCK_OPTIONS = {\n stale: 60_000,\n retries: {\n retries: 6,\n factor: 1.35,\n minTimeout: 8,\n maxTimeout: 180,\n randomize: true,\n },\n} as const;\n\n// ============================================================================\n// 状态目录解析\n// ============================================================================\n\nfunction resolveStateDirFromEnv(env: NodeJS.ProcessEnv = process.env): string {\n const stateOverride = env.OPENCLAW_STATE_DIR?.trim() || env.CLAWDBOT_STATE_DIR?.trim();\n if (stateOverride) {\n return stateOverride;\n }\n if (env.VITEST || env.NODE_ENV === \"test\") {\n return path.join(os.tmpdir(), [\"openclaw-vitest\", String(process.pid)].join(\"-\"));\n }\n return path.join(os.homedir(), \".openclaw\");\n}\n\nfunction resolveReqIdFilePath(accountId: string): string {\n const safe = accountId.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n return path.join(resolveStateDirFromEnv(), \"wecom\", `reqid-map-${safe}.json`);\n}\n\n// ============================================================================\n// 公开接口\n// ============================================================================\n\nexport interface PersistentReqIdStore {\n /** 设置 chatId 对应的 reqId(写入内存 + 防抖写磁盘) */\n set(chatId: string, reqId: string): void;\n /** 获取 chatId 对应的 reqId(异步:优先内存,miss 时查磁盘并回填内存) */\n get(chatId: string): Promise<string | undefined>;\n /** 同步获取 chatId 对应的 reqId(仅内存) */\n getSync(chatId: string): string | undefined;\n /** 删除 chatId 对应的 reqId */\n delete(chatId: string): void;\n /** 启动时从磁盘预热内存,返回加载条目数 */\n warmup(onError?: (error: unknown) => void): Promise<number>;\n /** 立即将内存数据刷写到磁盘(用于优雅退出) */\n flush(): Promise<void>;\n /** 清空内存缓存 */\n clearMemory(): void;\n /** 返回内存中的条目数 */\n memorySize(): number;\n}\n\n// ============================================================================\n// 核心实现\n// ============================================================================\n\nexport function createPersistentReqIdStore(\n accountId: string,\n options?: ReqIdStoreOptions,\n): PersistentReqIdStore {\n const ttlMs = options?.ttlMs ?? DEFAULT_TTL_MS;\n const memoryMaxSize = options?.memoryMaxSize ?? DEFAULT_MEMORY_MAX_SIZE;\n const fileMaxEntries = options?.fileMaxEntries ?? DEFAULT_FILE_MAX_ENTRIES;\n const flushDebounceMs = options?.flushDebounceMs ?? DEFAULT_FLUSH_DEBOUNCE_MS;\n\n const filePath = resolveReqIdFilePath(accountId);\n\n // 内存层:chatId → ReqIdEntry\n const memory = new Map<string, ReqIdEntry>();\n\n // 防抖写入相关\n let dirty = false;\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n // ========== 内部辅助函数 ==========\n\n /** 检查条目是否过期 */\n function isExpired(entry: ReqIdEntry, now: number): boolean {\n return ttlMs > 0 && now - entry.ts >= ttlMs;\n }\n\n /** 验证磁盘条目的合法性 */\n function isValidEntry(entry: unknown): entry is ReqIdEntry {\n return (\n typeof entry === \"object\" &&\n entry !== null &&\n typeof (entry as ReqIdEntry).reqId === \"string\" &&\n typeof (entry as ReqIdEntry).ts === \"number\" &&\n Number.isFinite((entry as ReqIdEntry).ts)\n );\n }\n\n /** 清理磁盘数据中的无效值,返回干净的 Record */\n function sanitizeData(value: unknown): ReqIdStoreData {\n if (!value || typeof value !== \"object\") {\n return {};\n }\n const out: ReqIdStoreData = {};\n for (const [key, entry] of Object.entries(value as Record<string, unknown>)) {\n if (isValidEntry(entry)) {\n out[key] = entry;\n }\n }\n return out;\n }\n\n /**\n * 内存容量控制:淘汰最旧的条目。\n * 利用 Map 的插入顺序 + touch(先 delete 再 set) 实现类 LRU 效果。\n */\n function pruneMemory(): void {\n if (memory.size <= memoryMaxSize) return;\n const sorted = [...memory.entries()].sort((a, b) => a[1].ts - b[1].ts);\n const toRemove = sorted.slice(0, memory.size - memoryMaxSize);\n for (const [key] of toRemove) {\n memory.delete(key);\n }\n }\n\n /** 磁盘数据容量控制:先清过期,再按时间淘汰超量 */\n function pruneFileData(data: ReqIdStoreData, now: number): void {\n if (ttlMs > 0) {\n for (const [key, entry] of Object.entries(data)) {\n if (now - entry.ts >= ttlMs) {\n delete data[key];\n }\n }\n }\n const keys = Object.keys(data);\n if (keys.length <= fileMaxEntries) return;\n keys\n .sort((a, b) => data[a].ts - data[b].ts)\n .slice(0, keys.length - fileMaxEntries)\n .forEach((key) => delete data[key]);\n }\n\n /** 防抖写入磁盘 */\n function scheduleDiskFlush(): void {\n dirty = true;\n if (flushTimer) return;\n flushTimer = setTimeout(async () => {\n flushTimer = null;\n if (!dirty) return;\n await flushToDisk();\n }, flushDebounceMs);\n }\n\n /** 立即写入磁盘(带文件锁,参考 createPersistentDedupe 的 checkAndRecordInner) */\n async function flushToDisk(): Promise<void> {\n dirty = false;\n const now = Date.now();\n try {\n await withFileLock(filePath, DEFAULT_LOCK_OPTIONS, async () => {\n // 读取现有磁盘数据并合并\n const { value } = await readJsonFileWithFallback<ReqIdStoreData>(filePath, {});\n const data = sanitizeData(value);\n\n // 将内存中未过期的数据合并到磁盘数据(内存优先)\n for (const [chatId, entry] of memory) {\n if (!isExpired(entry, now)) {\n data[chatId] = entry;\n }\n }\n\n // 清理过期和超量\n pruneFileData(data, now);\n\n // 原子写入\n await writeJsonFileAtomically(filePath, data);\n });\n } catch (error) {\n // 磁盘写入失败不影响内存使用,降级到纯内存模式\n // console.error(`[WeCom] reqid-store: flush to disk failed: ${String(error)}`);\n }\n }\n\n // ========== 公开 API ==========\n\n function set(chatId: string, reqId: string): void {\n const entry: ReqIdEntry = { reqId, ts: Date.now() };\n // touch:先删再设,保持 Map 插入顺序(类 LRU)\n memory.delete(chatId);\n memory.set(chatId, entry);\n pruneMemory();\n scheduleDiskFlush();\n }\n\n async function get(chatId: string): Promise<string | undefined> {\n const now = Date.now();\n\n // 1. 先查内存\n const memEntry = memory.get(chatId);\n if (memEntry && !isExpired(memEntry, now)) {\n return memEntry.reqId;\n }\n if (memEntry) {\n memory.delete(chatId); // 过期则删除\n }\n\n // 2. 内存 miss,回查磁盘并回填内存\n try {\n const { value } = await readJsonFileWithFallback<ReqIdStoreData>(filePath, {});\n const data = sanitizeData(value);\n const diskEntry = data[chatId];\n if (diskEntry && !isExpired(diskEntry, now)) {\n // 回填内存\n memory.set(chatId, diskEntry);\n return diskEntry.reqId;\n }\n } catch {\n // 磁盘读取失败,降级返回 undefined\n }\n\n return undefined;\n }\n\n function getSync(chatId: string): string | undefined {\n const now = Date.now();\n const entry = memory.get(chatId);\n if (entry && !isExpired(entry, now)) {\n return entry.reqId;\n }\n if (entry) {\n memory.delete(chatId);\n }\n return undefined;\n }\n\n function del(chatId: string): void {\n memory.delete(chatId);\n scheduleDiskFlush();\n }\n\n async function warmup(onError?: (error: unknown) => void): Promise<number> {\n const now = Date.now();\n try {\n const { value } = await readJsonFileWithFallback<ReqIdStoreData>(filePath, {});\n const data = sanitizeData(value);\n let loaded = 0;\n for (const [chatId, entry] of Object.entries(data)) {\n if (!isExpired(entry, now)) {\n memory.set(chatId, entry);\n loaded++;\n }\n }\n pruneMemory();\n return loaded;\n } catch (error) {\n onError?.(error);\n return 0;\n }\n }\n\n async function flush(): Promise<void> {\n if (flushTimer) {\n clearTimeout(flushTimer);\n flushTimer = null;\n }\n await flushToDisk();\n }\n\n function clearMemory(): void {\n memory.clear();\n }\n\n function memorySize(): number {\n return memory.size;\n }\n\n return {\n set,\n get,\n getSync,\n delete: del,\n warmup,\n flush,\n clearMemory,\n memorySize,\n };\n}\n","/**\n * 企业微信全局状态管理模块\n *\n * 负责管理 WSClient 实例、消息状态(带 TTL 清理)、ReqId 存储\n * 解决全局 Map 的内存泄漏问题\n */\n\nimport type { WSClient } from \"@wecom/aibot-node-sdk\";\nimport type { MessageState } from \"./interface.js\";\nimport { createPersistentReqIdStore, type PersistentReqIdStore } from \"./reqid-store.js\";\nimport {\n MESSAGE_STATE_TTL_MS,\n MESSAGE_STATE_CLEANUP_INTERVAL_MS,\n MESSAGE_STATE_MAX_SIZE,\n} from \"./const.js\";\n\n// ============================================================================\n// WSClient 实例管理\n// ============================================================================\n\n/** WSClient 实例管理 */\nconst wsClientInstances = new Map<string, WSClient>();\n\n/**\n * 获取指定账户的 WSClient 实例\n */\nexport function getWeComWebSocket(accountId: string): WSClient | null {\n return wsClientInstances.get(accountId) ?? null;\n}\n\n/**\n * 设置指定账户的 WSClient 实例\n */\nexport function setWeComWebSocket(accountId: string, client: WSClient): void {\n wsClientInstances.set(accountId, client);\n}\n\n/**\n * 删除指定账户的 WSClient 实例\n */\nexport function deleteWeComWebSocket(accountId: string): void {\n wsClientInstances.delete(accountId);\n}\n\n// ============================================================================\n// 消息状态管理(带 TTL 清理,防止内存泄漏)\n// ============================================================================\n\n/** 消息状态条目(带创建时间戳,用于 TTL 清理) */\ninterface MessageStateEntry {\n state: MessageState;\n createdAt: number;\n}\n\n/** 消息状态管理 */\nconst messageStates = new Map<string, MessageStateEntry>();\n\n/** 定期清理定时器 */\nlet cleanupTimer: ReturnType<typeof setInterval> | null = null;\n\n/**\n * 启动消息状态定期清理(自动 TTL 清理 + 容量限制)\n */\nexport function startMessageStateCleanup(): void {\n if (cleanupTimer) return;\n\n cleanupTimer = setInterval(() => {\n pruneMessageStates();\n }, MESSAGE_STATE_CLEANUP_INTERVAL_MS);\n\n // 允许进程退出时不阻塞\n if (cleanupTimer && typeof cleanupTimer === \"object\" && \"unref\" in cleanupTimer) {\n cleanupTimer.unref();\n }\n}\n\n/**\n * 停止消息状态定期清理\n */\nexport function stopMessageStateCleanup(): void {\n if (cleanupTimer) {\n clearInterval(cleanupTimer);\n cleanupTimer = null;\n }\n}\n\n/**\n * 清理过期和超量的消息状态条目\n */\nfunction pruneMessageStates(): void {\n const now = Date.now();\n\n // 1. 清理过期条目\n for (const [key, entry] of messageStates) {\n if (now - entry.createdAt >= MESSAGE_STATE_TTL_MS) {\n messageStates.delete(key);\n }\n }\n\n // 2. 容量限制:如果仍超过最大条目数,按时间淘汰最旧的\n if (messageStates.size > MESSAGE_STATE_MAX_SIZE) {\n const sorted = [...messageStates.entries()].sort((a, b) => a[1].createdAt - b[1].createdAt);\n const toRemove = sorted.slice(0, messageStates.size - MESSAGE_STATE_MAX_SIZE);\n for (const [key] of toRemove) {\n messageStates.delete(key);\n }\n }\n}\n\n/**\n * 设置消息状态\n */\nexport function setMessageState(messageId: string, state: MessageState): void {\n messageStates.set(messageId, {\n state,\n createdAt: Date.now(),\n });\n}\n\n/**\n * 获取消息状态\n */\nexport function getMessageState(messageId: string): MessageState | undefined {\n const entry = messageStates.get(messageId);\n if (!entry) return undefined;\n\n // 检查 TTL\n if (Date.now() - entry.createdAt >= MESSAGE_STATE_TTL_MS) {\n messageStates.delete(messageId);\n return undefined;\n }\n return entry.state;\n}\n\n/**\n * 删除消息状态\n */\nexport function deleteMessageState(messageId: string): void {\n messageStates.delete(messageId);\n}\n\n/**\n * 清空所有消息状态\n */\nexport function clearAllMessageStates(): void {\n messageStates.clear();\n}\n\n// ============================================================================\n// ReqId 持久化存储管理(按 accountId 隔离)\n// ============================================================================\n\n/**\n * ReqId 持久化存储管理\n * 参考 createPersistentDedupe 模式:内存 + 磁盘双层、文件锁、原子写入、TTL 过期、防抖写入\n * 重启后可从磁盘恢复,确保主动推送消息时能获取到 reqId\n */\nconst reqIdStores = new Map<string, PersistentReqIdStore>();\n\nfunction getOrCreateReqIdStore(accountId: string): PersistentReqIdStore {\n let store = reqIdStores.get(accountId);\n if (!store) {\n store = createPersistentReqIdStore(accountId);\n reqIdStores.set(accountId, store);\n }\n return store;\n}\n\n// ============================================================================\n// ReqId 操作函数\n// ============================================================================\n\n/**\n * 设置 chatId 对应的 reqId(写入内存 + 防抖写磁盘)\n */\nexport function setReqIdForChat(chatId: string, reqId: string, accountId = \"default\"): void {\n getOrCreateReqIdStore(accountId).set(chatId, reqId);\n}\n\n/**\n * 获取 chatId 对应的 reqId(异步:优先内存,miss 时查磁盘并回填内存)\n */\nexport async function getReqIdForChatAsync(chatId: string, accountId = \"default\"): Promise<string | undefined> {\n return getOrCreateReqIdStore(accountId).get(chatId);\n}\n\n/**\n * 获取 chatId 对应的 reqId(同步:仅内存,保留向后兼容)\n */\nexport function getReqIdForChat(chatId: string, accountId = \"default\"): string | undefined {\n return getOrCreateReqIdStore(accountId).getSync(chatId);\n}\n\n/**\n * 删除 chatId 对应的 reqId\n */\nexport function deleteReqIdForChat(chatId: string, accountId = \"default\"): void {\n getOrCreateReqIdStore(accountId).delete(chatId);\n}\n\n/**\n * 启动时预热 reqId 缓存(从磁盘加载到内存)\n */\nexport async function warmupReqIdStore(\n accountId = \"default\",\n log?: (...args: unknown[]) => void,\n): Promise<number> {\n const store = getOrCreateReqIdStore(accountId);\n return store.warmup((error) => {\n log?.(`[WeCom] reqid-store warmup error: ${String(error)}`);\n });\n}\n\n/**\n * 立即将 reqId 数据刷写到磁盘(用于优雅退出)\n */\nexport async function flushReqIdStore(accountId = \"default\"): Promise<void> {\n const store = reqIdStores.get(accountId);\n if (store) {\n await store.flush();\n }\n}\n\n// ============================================================================\n// 全局 cleanup(断开连接时释放所有资源)\n// ============================================================================\n\n/**\n * 清理指定账户的所有资源\n */\nexport async function cleanupAccount(accountId: string): Promise<void> {\n // 1. 断开 WSClient\n const wsClient = wsClientInstances.get(accountId);\n if (wsClient) {\n try {\n wsClient.disconnect();\n } catch {\n // 忽略断开连接时的错误\n }\n wsClientInstances.delete(accountId);\n }\n\n // 2. flush reqId 存储到磁盘\n const store = reqIdStores.get(accountId);\n if (store) {\n try {\n await store.flush();\n } catch {\n // 忽略 flush 错误\n }\n // 注意:不删除 store,因为重连后可能还需要\n }\n}\n\n/**\n * 清理所有资源(用于进程退出)\n */\nexport async function cleanupAll(): Promise<void> {\n // 停止定期清理\n stopMessageStateCleanup();\n\n // 清理所有 WSClient\n for (const [accountId, wsClient] of wsClientInstances) {\n try {\n wsClient.disconnect();\n } catch {\n // 忽略\n }\n }\n wsClientInstances.clear();\n\n // flush 所有 reqId 存储\n for (const [, store] of reqIdStores) {\n try {\n await store.flush();\n } catch {\n // 忽略\n }\n }\n\n // 清空消息状态\n clearAllMessageStates();\n}\n","/**\n * 企业微信 WebSocket 监控器主模块\n *\n * 负责:\n * - 建立和管理 WebSocket 连接\n * - 协调消息处理流程(解析→策略检查→下载图片→路由回复)\n * - 资源生命周期管理\n *\n * 子模块:\n * - message-parser.ts : 消息内容解析\n * - message-sender.ts : 消息发送(带超时保护)\n * - media-handler.ts : 图片下载和保存(带超时保护)\n * - group-policy.ts : 群组访问控制\n * - dm-policy.ts : 私聊访问控制\n * - state-manager.ts : 全局状态管理(带 TTL 清理)\n * - timeout.ts : 超时工具\n */\n\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport type { OpenClawConfig, RuntimeEnv } from \"openclaw/plugin-sdk\";\nimport { WSClient, generateReqId } from \"@wecom/aibot-node-sdk\";\nimport type { WsFrame, Logger } from \"@wecom/aibot-node-sdk\";\nimport { getWeComRuntime } from \"./runtime.js\";\nimport { getDefaultMediaLocalRoots } from \"./openclaw-compat.js\";\nimport type { ResolvedWeComAccount, WeComConfig } from \"./utils.js\";\nimport {\n CHANNEL_ID,\n THINKING_MESSAGE,\n MEDIA_IMAGE_PLACEHOLDER,\n MEDIA_DOCUMENT_PLACEHOLDER,\n MESSAGE_PROCESS_TIMEOUT_MS,\n WS_HEARTBEAT_INTERVAL_MS,\n WS_MAX_RECONNECT_ATTEMPTS,\n} from \"./const.js\";\nimport type { WeComMonitorOptions, MessageState } from \"./interface.js\";\nimport { parseMessageContent, type MessageBody } from \"./message-parser.js\";\nimport { sendWeComReply } from \"./message-sender.js\";\nimport { downloadAndSaveImages, downloadAndSaveFiles } from \"./media-handler.js\";\nimport { uploadAndSendMedia } from \"./media-uploader.js\";\nimport { checkGroupPolicy } from \"./group-policy.js\";\nimport { checkDmPolicy } from \"./dm-policy.js\";\nimport {\n setWeComWebSocket,\n setMessageState,\n deleteMessageState,\n setReqIdForChat,\n warmupReqIdStore,\n startMessageStateCleanup,\n stopMessageStateCleanup,\n cleanupAccount,\n} from \"./state-manager.js\";\nimport { withTimeout } from \"./timeout.js\";\n\n/**\n * 去除文本中的 `<think>...</think>` 标签(支持跨行),返回剩余可见文本。\n * 用于判断大模型回复中是否包含实际用户可见内容(而非仅有 thinking 推理过程)。\n */\nfunction stripThinkTags(text: string): string {\n return text;\n // return text.replace(/<think>[\\s\\S]*?<\\/think>/g, \"\").trim();\n}\n\n// ============================================================================\n// 媒体本地路径白名单扩展\n// ============================================================================\n\n/**\n * 解析 openclaw 状态目录(与 plugin-sdk 内部逻辑保持一致)\n */\nfunction resolveStateDir(): string {\n const stateOverride = process.env.OPENCLAW_STATE_DIR?.trim() || process.env.CLAWDBOT_STATE_DIR?.trim();\n if (stateOverride) return stateOverride;\n return path.join(os.homedir(), \".openclaw\");\n}\n\n/**\n * 在 getDefaultMediaLocalRoots() 基础上,将 stateDir 本身也加入白名单,\n * 并合并用户在 WeComConfig 中配置的自定义 mediaLocalRoots。\n *\n * getDefaultMediaLocalRoots() 仅包含 stateDir 下的子目录(media/agents/workspace/sandboxes),\n * 但 agent 生成的文件可能直接放在 stateDir 根目录下(如 ~/.openclaw-dev/1.png),\n * 因此需要将 stateDir 本身也加入白名单以避免 LocalMediaAccessError。\n *\n * 用户可在 openclaw.json 中配置:\n * {\n * \"channels\": {\n * \"wecom\": {\n * \"mediaLocalRoots\": [\"~/Downloads\", \"~/Documents\"]\n * }\n * }\n * }\n */\nasync function getExtendedMediaLocalRoots(config?: WeComConfig): Promise<string[]> {\n // 从兼容层获取默认白名单(内部已处理低版本 SDK 的 fallback)\n const defaults = await getDefaultMediaLocalRoots();\n const roots: string[] = [...defaults];\n\n const stateDir = path.resolve(resolveStateDir());\n if (!roots.includes(stateDir)) {\n roots.push(stateDir);\n }\n // 合并用户在 WeComConfig 中配置的自定义路径\n if (config?.mediaLocalRoots) {\n for (const r of config.mediaLocalRoots) {\n const resolved = path.resolve(r.replace(/^~(?=\\/|$)/, os.homedir()));\n if (!roots.includes(resolved)) {\n roots.push(resolved);\n }\n }\n }\n return roots;\n}\n\n// ============================================================================\n// 媒体发送错误提示\n// ============================================================================\n\n/**\n * 根据媒体发送结果生成纯文本错误摘要(用于替换 thinking 流式消息展示给用户)。\n *\n * 使用纯文本而非 markdown 格式,因为 replyStream 只支持纯文本。\n */\nfunction buildMediaErrorSummary(\n mediaUrl: string,\n result: { rejectReason?: string; error?: string },\n): string {\n if (result.error?.includes(\"LocalMediaAccessError\")) {\n return `⚠️ 文件发送失败:没有权限访问路径 ${mediaUrl}\\n请在 openclaw.json 的 mediaLocalRoots 中添加该路径的父目录后重启生效。`;\n }\n if (result.rejectReason) {\n return `⚠️ 文件发送失败:${result.rejectReason}`;\n }\n return `⚠️ 文件发送失败:无法处理文件 ${mediaUrl},请稍后再试。`;\n}\n\n// ============================================================================\n// 重新导出(保持向后兼容)\n// ============================================================================\n\nexport type { WeComMonitorOptions } from \"./interface.js\";\nexport { WeComCommand } from \"./const.js\";\nexport {\n getWeComWebSocket,\n setReqIdForChat,\n getReqIdForChatAsync,\n getReqIdForChat,\n deleteReqIdForChat,\n warmupReqIdStore,\n flushReqIdStore,\n} from \"./state-manager.js\";\nexport { sendWeComReply } from \"./message-sender.js\";\n\n// ============================================================================\n// 消息上下文构建\n// ============================================================================\n\n/**\n * 构建消息上下文\n */\nfunction buildMessageContext(\n frame: WsFrame,\n account: ResolvedWeComAccount,\n config: OpenClawConfig,\n text: string,\n mediaList: Array<{ path: string; contentType?: string }>,\n quoteContent?: string\n) {\n const core = getWeComRuntime();\n const body = frame.body as MessageBody;\n const chatId = body.chatid || body.from.userid;\n const chatType = body.chattype === \"group\" ? \"group\" : \"direct\";\n\n // 解析路由信息\n const route = core.channel.routing.resolveAgentRoute({\n cfg: config,\n channel: CHANNEL_ID,\n accountId: account.accountId,\n peer: {\n kind: chatType,\n id: chatId,\n },\n });\n\n // 构建会话标签\n const fromLabel = chatType === \"group\" ? `group:${chatId}` : `user:${body.from.userid}`;\n\n // 当只有媒体没有文本时,使用占位符标识媒体类型\n const hasImages = mediaList.some((m) => m.contentType?.startsWith(\"image/\"));\n const messageBody = text || (mediaList.length > 0 ? (hasImages ? MEDIA_IMAGE_PLACEHOLDER : MEDIA_DOCUMENT_PLACEHOLDER) : \"\");\n\n // 构建多媒体数组\n const mediaPaths = mediaList.length > 0 ? mediaList.map((m) => m.path) : undefined;\n const mediaTypes = mediaList.length > 0\n ? (mediaList.map((m) => m.contentType).filter(Boolean) as string[])\n : undefined;\n\n // 构建标准消息上下文\n return core.channel.reply.finalizeInboundContext({\n Body: messageBody,\n RawBody: messageBody,\n CommandBody: messageBody,\n\n MessageSid: body.msgid,\n\n From: chatType === \"group\" ? `${CHANNEL_ID}:group:${chatId}` : `${CHANNEL_ID}:${body.from.userid}`,\n To: `${CHANNEL_ID}:${chatId}`,\n SenderId: body.from.userid,\n\n SessionKey: route.sessionKey,\n AccountId: account.accountId,\n\n ChatType: chatType,\n ConversationLabel: fromLabel,\n\n Timestamp: Date.now(),\n\n Provider: CHANNEL_ID,\n Surface: CHANNEL_ID,\n\n OriginatingChannel: CHANNEL_ID,\n OriginatingTo: `${CHANNEL_ID}:${chatId}`,\n\n CommandAuthorized: true,\n\n ResponseUrl: body.response_url,\n ReqId: frame.headers.req_id,\n WeComFrame: frame,\n\n MediaPath: mediaList[0]?.path,\n MediaType: mediaList[0]?.contentType,\n MediaPaths: mediaPaths,\n MediaTypes: mediaTypes,\n MediaUrls: mediaPaths,\n\n ReplyToBody: quoteContent,\n });\n}\n\n// ============================================================================\n// 消息处理和回复\n// ============================================================================\n\n/** deliver 回调所需的上下文 */\ninterface DeliverContext {\n wsClient: WSClient;\n frame: WsFrame;\n state: MessageState;\n account: ResolvedWeComAccount;\n runtime: RuntimeEnv;\n}\n\n/**\n * 发送\"思考中\"消息\n */\nasync function sendThinkingReply(params: {\n wsClient: WSClient;\n frame: WsFrame;\n streamId: string;\n runtime: RuntimeEnv;\n}): Promise<void> {\n const { wsClient, frame, streamId, runtime } = params;\n try {\n await sendWeComReply({\n wsClient,\n frame,\n text: THINKING_MESSAGE,\n runtime,\n finish: false,\n streamId,\n });\n } catch (err) {\n runtime.error?.(`[wecom] Failed to send thinking message: ${String(err)}`);\n }\n}\n\n/**\n * 累积文本并判断是否有可见内容(去除 <think> 标签后)\n */\nfunction accumulateText(state: MessageState, text: string): void {\n state.accumulatedText += text;\n if (!state.hasText && stripThinkTags(state.accumulatedText)) {\n state.hasText = true;\n }\n}\n\n/**\n * 上传并发送一批媒体文件(统一走主动发送通道)\n *\n * replyMedia(被动回复)无法覆盖 replyStream 发出的 thinking 流式消息,\n * 因此所有媒体统一走 aibot_send_msg 主动发送。\n */\nasync function sendMediaBatch(\n ctx: DeliverContext,\n mediaUrls: string[],\n): Promise<void> {\n const { wsClient, frame, state, account, runtime } = ctx;\n const body = frame.body as MessageBody;\n const chatId = body.chatid || body.from.userid;\n const mediaLocalRoots = await getExtendedMediaLocalRoots(account.config);\n\n runtime.log?.(`[wecom][debug] mediaLocalRoots=${JSON.stringify(mediaLocalRoots)}, mediaUrls=${JSON.stringify(mediaUrls)}, hasText=${!!state.hasText}`);\n\n for (const mediaUrl of mediaUrls) {\n const result = await uploadAndSendMedia({\n wsClient,\n mediaUrl,\n chatId,\n mediaLocalRoots,\n log: (...args: any[]) => runtime.log?.(...args),\n errorLog: (...args: any[]) => runtime.error?.(...args),\n });\n\n if (result.ok) {\n state.hasMedia = true;\n } else {\n state.hasMediaFailed = true;\n runtime.error?.(`[wecom] Media send failed: url=${mediaUrl}, reason=${result.rejectReason || result.error}`);\n // 收集错误摘要,后续在 finishThinkingStream 中直接替换 thinking 流展示给用户\n const summary = buildMediaErrorSummary(mediaUrl, result);\n state.mediaErrorSummary = state.mediaErrorSummary\n ? `${state.mediaErrorSummary}\\n\\n${summary}`\n : summary;\n }\n }\n}\n\n/**\n * 关闭 thinking 流(发送 finish=true 的流式消息)\n *\n * thinking 是通过 replyStream 用 streamId 发的流式消息,\n * 只有同一 streamId 的 replyStream(finish=true) 才能关闭它。\n *\n * ⚠️ 注意:企微会忽略空格等不可见内容,必须用有可见字符的文案才能真正\n * 替换掉 thinking 动画,否则 thinking 会一直残留。\n *\n * 关闭策略(按优先级):\n * 1. 有可见文本 → 用完整文本关闭\n * 2. 有媒体成功发送(通过 deliver 回调) → 用友好提示\"文件已发送\"\n * 3. 媒体发送失败 → 直接用错误摘要替换 thinking\n * 4. 其他 → 用通用\"处理完成\"提示\n * (agent 可能已通过内置 message 工具直接发送了文件,\n * 该路径走 outbound.sendMedia 完全绕过 deliver 回调,\n * 所以 state 中无记录,但文件已实际送达)\n */\nasync function finishThinkingStream(ctx: DeliverContext): Promise<void> {\n const { wsClient, frame, state, runtime } = ctx;\n const visibleText = stripThinkTags(state.accumulatedText);\n\n let finishText: string;\n if (visibleText) {\n // 有可见文本:用完整文本关闭流(覆盖 thinking 为真实内容)\n finishText = state.accumulatedText;\n } else if (state.hasMedia) {\n // 媒体成功发送:用友好提示告知用户\n finishText = \"📎 文件已发送,请查收。\";\n } else if (state.hasMediaFailed && state.mediaErrorSummary) {\n // 媒体发送失败:直接用错误摘要替换 thinking 流(不再额外发 sendMessage)\n finishText = state.mediaErrorSummary;\n } else {\n // 核心无可见文本且 deliver 中未处理过媒体。\n //\n // 不使用错误提示,因为 agent 可能已通过内置 message 工具直接调用\n // outbound.sendMedia 成功发送了文件——该路径完全绕过 monitor 的 deliver\n // 回调,所以 state.deliverCalled / state.hasMedia 均为 false,但文件\n // 实际已送达用户。此时显示 \"未生成回复\" 会误导用户。\n finishText = \"✅ 处理完成。\";\n }\n\n await sendWeComReply({ wsClient, frame, text: finishText, runtime, finish: true, streamId: state.streamId });\n}\n\n/**\n * 路由消息到核心处理流程并处理回复\n */\nasync function routeAndDispatchMessage(params: {\n ctxPayload: ReturnType<typeof buildMessageContext>;\n config: OpenClawConfig;\n account: ResolvedWeComAccount;\n wsClient: WSClient;\n frame: WsFrame;\n state: MessageState;\n runtime: RuntimeEnv;\n onCleanup: () => void;\n}): Promise<void> {\n const { ctxPayload, config, account, wsClient, frame, state, runtime, onCleanup } = params;\n const core = getWeComRuntime();\n const ctx: DeliverContext = { wsClient, frame, state, account, runtime };\n\n // 防止 onCleanup 被多次调用(onError 回调与 catch 块可能重复触发)\n let cleanedUp = false;\n const safeCleanup = () => {\n if (!cleanedUp) { cleanedUp = true; onCleanup(); }\n };\n\n try {\n await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({\n ctx: ctxPayload,\n cfg: config,\n dispatcherOptions: {\n deliver: async (payload, info) => {\n state.deliverCalled = true;\n // runtime.log?.(`[openclaw -> plugin] kind=${info.kind}, text=${payload.text ?? ''}, mediaUrl=${payload.mediaUrl ?? ''}, mediaUrls=${JSON.stringify(payload.mediaUrls ?? [])}`);\n\n // 累积文本\n if (payload.text) {\n accumulateText(state, payload.text);\n }\n\n // 发送媒体(统一走主动发送)\n const mediaUrls = payload.mediaUrls?.length ? payload.mediaUrls : payload.mediaUrl ? [payload.mediaUrl] : [];\n if (mediaUrls.length > 0) {\n try {\n await sendMediaBatch(ctx, mediaUrls);\n } catch (mediaErr) {\n // sendMediaBatch 内部异常(如 getDefaultMediaLocalRoots 不可用等)\n // 必须标记 state,否则 finishThinkingStream 会显示\"处理完成\"误导用户\n state.hasMediaFailed = true;\n const errMsg = String(mediaErr);\n const summary = `⚠️ 文件发送失败:内部处理异常,请升级 openclaw 到最新版本后重试。\\n错误详情:${errMsg}`;\n state.mediaErrorSummary = state.mediaErrorSummary\n ? `${state.mediaErrorSummary}\\n\\n${summary}`\n : summary;\n runtime.error?.(`[wecom] sendMediaBatch threw: ${errMsg}`);\n }\n }\n\n // 中间帧:有可见文本时流式更新\n if (info.kind !== \"final\" && state.hasText && state.accumulatedText) {\n await sendWeComReply({ wsClient, frame, text: state.accumulatedText, runtime, finish: false, streamId: state.streamId });\n }\n },\n onError: (err, info) => {\n runtime.error?.(`[wecom] ${info.kind} reply failed: ${String(err)}`);\n },\n },\n });\n\n // 关闭 thinking 流\n await finishThinkingStream(ctx);\n safeCleanup();\n } catch (err) {\n runtime.error?.(`[wecom][plugin] Failed to process message: ${String(err)}`);\n // 即使 dispatch 抛异常,也需要关闭 thinking 流,\n // 避免 deliver 已成功发送媒体但后续出错时 thinking 消息残留或被错误文案覆盖\n try {\n await finishThinkingStream(ctx);\n } catch (finishErr) {\n runtime.error?.(`[wecom] Failed to finish thinking stream after dispatch error: ${String(finishErr)}`);\n }\n safeCleanup();\n }\n}\n\n/**\n * 处理企业微信消息(主函数)\n *\n * 处理流程:\n * 1. 解析消息内容(文本、图片、引用)\n * 2. 群组策略检查(仅群聊)\n * 3. DM Policy 访问控制检查(仅私聊)\n * 4. 下载并保存图片\n * 5. 初始化消息状态\n * 6. 发送\"思考中\"消息\n * 7. 路由消息到核心处理流程\n *\n * 整体带超时保护,防止单条消息处理阻塞过久\n */\nasync function processWeComMessage(params: {\n frame: WsFrame;\n account: ResolvedWeComAccount;\n config: OpenClawConfig;\n runtime: RuntimeEnv;\n wsClient: WSClient;\n}): Promise<void> {\n const { frame, account, config, runtime, wsClient } = params;\n const body = frame.body as MessageBody;\n const chatId = body.chatid || body.from.userid;\n const chatType = body.chattype === \"group\" ? \"group\" : \"direct\";\n const messageId = body.msgid;\n const reqId = frame.headers.req_id;\n\n // Step 1: 解析消息内容\n const { textParts, imageUrls, imageAesKeys, fileUrls, fileAesKeys, quoteContent } = parseMessageContent(body);\n let text = textParts.join(\"\\n\").trim();\n\n // // 群聊中移除 @机器人 的提及标记\n // if (body.chattype === \"group\") {\n // text = text.replace(/@\\S+/g, \"\").trim();\n // }\n\n // 如果文本为空但存在引用消息,使用引用消息内容\n if (!text && quoteContent) {\n text = quoteContent;\n runtime.log?.(\"[wecom][plugin] Using quote content as message body (user only mentioned bot)\");\n }\n\n // 如果既没有文本也没有图片也没有文件也没有引用内容,则跳过\n if (!text && imageUrls.length === 0 && fileUrls.length === 0) {\n runtime.log?.(\"[wecom][plugin] Skipping empty message (no text, image, file or quote)\");\n return;\n }\n\n // Step 2: 群组策略检查(仅群聊)\n if (chatType === \"group\") {\n const groupPolicyResult = checkGroupPolicy({\n chatId,\n senderId: body.from.userid,\n account,\n config,\n runtime,\n });\n\n if (!groupPolicyResult.allowed) {\n return;\n }\n }\n\n // Step 3: DM Policy 访问控制检查(仅私聊)\n const dmPolicyResult = await checkDmPolicy({\n senderId: body.from.userid,\n isGroup: chatType === \"group\",\n account,\n wsClient,\n frame,\n runtime,\n });\n\n if (!dmPolicyResult.allowed) {\n return;\n }\n\n // Step 4: 下载并保存图片和文件\n const [imageMediaList, fileMediaList] = await Promise.all([\n downloadAndSaveImages({\n imageUrls,\n imageAesKeys,\n account,\n config,\n runtime,\n wsClient,\n }),\n downloadAndSaveFiles({\n fileUrls,\n fileAesKeys,\n account,\n config,\n runtime,\n wsClient,\n }),\n ]);\n const mediaList = [...imageMediaList, ...fileMediaList];\n\n // Step 5: 初始化消息状态\n setReqIdForChat(chatId, reqId, account.accountId);\n\n const streamId = generateReqId(\"stream\");\n const state: MessageState = { accumulatedText: \"\", streamId };\n setMessageState(messageId, state);\n\n const cleanupState = () => {\n deleteMessageState(messageId);\n };\n\n // Step 6: 发送\"思考中\"消息\n const shouldSendThinking = account.sendThinkingMessage ?? true;\n if (shouldSendThinking) {\n await sendThinkingReply({ wsClient, frame, streamId, runtime });\n }\n\n // Step 7: 构建上下文并路由到核心处理流程(带整体超时保护)\n const ctxPayload = buildMessageContext(frame, account, config, text, mediaList, quoteContent);\n // runtime.log?.(`[plugin -> openclaw] body=${text}, mediaPaths=${JSON.stringify(mediaList.map(m => m.path))}${quoteContent ? `, quote=${quoteContent}` : ''}`);\n\n try {\n await withTimeout(\n routeAndDispatchMessage({\n ctxPayload,\n config,\n account,\n wsClient,\n frame,\n state,\n runtime,\n onCleanup: cleanupState,\n }),\n MESSAGE_PROCESS_TIMEOUT_MS,\n `Message processing timed out (msgId=${messageId})`,\n );\n } catch (err) {\n runtime.error?.(`[wecom][plugin] Message processing failed or timed out: ${String(err)}`);\n // 确保 thinking 流被关闭,防止异常/超时时 thinking 消息一直残留\n try {\n if (shouldSendThinking) {\n await sendWeComReply({\n wsClient,\n frame,\n text: \"处理消息时出现异常,请稍后重试。\",\n runtime,\n finish: true,\n streamId: state.streamId,\n });\n }\n } catch (finishErr) {\n runtime.error?.(`[wecom] Failed to finish thinking stream on error: ${String(finishErr)}`);\n }\n cleanupState();\n }\n}\n\n// ============================================================================\n// 创建 SDK Logger 适配器\n// ============================================================================\n\n/**\n * 创建适配 RuntimeEnv 的 Logger\n */\nfunction createSdkLogger(runtime: RuntimeEnv, accountId: string): Logger {\n return {\n debug: (message: string, ...args: any[]) => {\n runtime.log?.(`[${accountId}] ${message}`, ...args);\n },\n info: (message: string, ...args: any[]) => {\n runtime.log?.(`[${accountId}] ${message}`, ...args);\n },\n warn: (message: string, ...args: any[]) => {\n runtime.log?.(`[${accountId}] WARN: ${message}`, ...args);\n },\n error: (message: string, ...args: any[]) => {\n runtime.error?.(`[${accountId}] ${message}`, ...args);\n },\n };\n}\n\n// ============================================================================\n// 主函数\n// ============================================================================\n\n/**\n * 监听企业微信 WebSocket 连接\n * 使用 aibot-node-sdk 简化连接管理\n */\nexport async function monitorWeComProvider(options: WeComMonitorOptions): Promise<void> {\n const { account, config, runtime, abortSignal } = options;\n\n runtime.log?.(`[${account.accountId}] Initializing WSClient with SDK...`);\n\n // 启动消息状态定期清理\n startMessageStateCleanup();\n\n return new Promise((resolve, reject) => {\n const logger = createSdkLogger(runtime, account.accountId);\n\n const wsClient = new WSClient({\n botId: account.botId,\n secret: account.secret,\n wsUrl: account.websocketUrl,\n logger,\n heartbeatInterval: WS_HEARTBEAT_INTERVAL_MS,\n maxReconnectAttempts: WS_MAX_RECONNECT_ATTEMPTS,\n });\n\n // 清理函数:确保所有资源被释放\n const cleanup = async () => {\n stopMessageStateCleanup();\n await cleanupAccount(account.accountId);\n };\n\n // 处理中止信号\n if (abortSignal) {\n abortSignal.addEventListener(\"abort\", async () => {\n runtime.log?.(`[${account.accountId}] Connection aborted`);\n await cleanup();\n resolve();\n });\n }\n\n // 监听连接事件\n wsClient.on(\"connected\", () => {\n runtime.log?.(`[${account.accountId}] WebSocket connected`);\n });\n\n // 监听认证成功事件\n wsClient.on(\"authenticated\", () => {\n runtime.log?.(`[${account.accountId}] Authentication successful`);\n setWeComWebSocket(account.accountId, wsClient);\n });\n\n // 监听断开事件\n wsClient.on(\"disconnected\", (reason) => {\n runtime.log?.(`[${account.accountId}] WebSocket disconnected: ${reason}`);\n });\n\n // 监听重连事件\n wsClient.on(\"reconnecting\", (attempt) => {\n runtime.log?.(`[${account.accountId}] Reconnecting attempt ${attempt}...`);\n });\n\n // 监听错误事件\n wsClient.on(\"error\", (error) => {\n runtime.error?.(`[${account.accountId}] WebSocket error: ${error.message}`);\n // 认证失败时拒绝 Promise\n if (error.message.includes(\"Authentication failed\")) {\n cleanup().finally(() => reject(error));\n }\n });\n\n // 监听所有消息\n wsClient.on(\"message\", async (frame: WsFrame) => {\n try {\n await processWeComMessage({\n frame,\n account,\n config,\n runtime,\n wsClient,\n });\n } catch (err) {\n runtime.error?.(`[${account.accountId}] Failed to process message: ${String(err)}`);\n }\n });\n\n // 启动前预热 reqId 缓存,确保完成后再建立连接,避免 getSync 在预热完成前返回 undefined\n warmupReqIdStore(account.accountId, (...args) => runtime.log?.(...args))\n .then((count) => {\n runtime.log?.(`[${account.accountId}] Warmed up ${count} reqId entries from disk`);\n })\n .catch((err) => {\n runtime.error?.(`[${account.accountId}] Failed to warmup reqId store: ${String(err)}`);\n })\n .finally(() => {\n // 无论预热成功或失败,都建立连接\n wsClient.connect();\n });\n });\n}\n","/**\n * 企业微信公共工具函数\n */\n\nimport { DEFAULT_ACCOUNT_ID } from \"openclaw/plugin-sdk\";\nimport type { OpenClawConfig } from \"openclaw/plugin-sdk\";\nimport { CHANNEL_ID } from \"./const.js\";\n\n// ============================================================================\n// 配置类型定义\n// ============================================================================\n\n/**\n * 企业微信群组配置\n */\nexport interface WeComGroupConfig {\n /** 群组内发送者白名单(仅列表中的成员消息会被处理) */\n allowFrom?: Array<string | number>;\n}\n\n/**\n * 企业微信单个账户配置\n */\nexport interface WeComAccountConfig {\n /** 账户唯一标识(用于区分不同账户) */\n name: string;\n /** 机器人 ID */\n botId: string;\n /** 机器人密钥 */\n secret: string;\n /** 是否启用该账户 */\n enabled?: boolean;\n /** WebSocket URL(可选,默认使用全局配置) */\n websocketUrl?: string;\n}\n\n/**\n * 企业微信配置类型(支持多账户)\n */\nexport interface WeComConfig {\n enabled?: boolean;\n websocketUrl?: string;\n /** 旧版单账户配置(兼容用,会被迁移到 accounts) */\n botId?: string;\n secret?: string;\n name?: string;\n /** 多账户配置数组(新版) */\n accounts?: WeComAccountConfig[];\n allowFrom?: Array<string | number>;\n dmPolicy?: \"open\" | \"allowlist\" | \"pairing\" | \"disabled\";\n /** 群组访问策略:\"open\" = 允许所有群组(默认),\"allowlist\" = 仅允许 groupAllowFrom 中的群组,\"disabled\" = 禁用群组消息 */\n groupPolicy?: \"open\" | \"allowlist\" | \"disabled\";\n /** 群组白名单(仅 groupPolicy=\"allowlist\" 时生效) */\n groupAllowFrom?: Array<string | number>;\n /** 每个群组的详细配置(如群组内发送者白名单) */\n groups?: Record<string, WeComGroupConfig>;\n /** 是否发送\"思考中\"消息,默认为 true */\n sendThinkingMessage?: boolean;\n /** 额外允许访问的本地媒体路径白名单(支持 ~ 表示 home 目录),如 [\"~/Downloads\", \"~/Documents\"] */\n mediaLocalRoots?: string[];\n}\n\nexport const DefaultWsUrl = \"wss://openws.work.weixin.qq.com\";\n\nexport interface ResolvedWeComAccount {\n accountId: string;\n name: string;\n enabled: boolean;\n websocketUrl: string;\n botId: string;\n secret: string;\n /** 是否发送\"思考中\"消息,默认为 true */\n sendThinkingMessage: boolean;\n config: WeComConfig;\n}\n\n/**\n * 迁移旧版配置到新版 accounts 数组格式\n */\nfunction migrateToAccounts(wecomConfig: WeComConfig): WeComConfig {\n // 如果已经有 accounts 数组,无需迁移\n if (wecomConfig.accounts && wecomConfig.accounts.length > 0) {\n return wecomConfig;\n }\n\n // 如果有旧的 botId/secret 配置,迁移到 accounts\n if (wecomConfig.botId || wecomConfig.secret) {\n const accountName = wecomConfig.name || \"default\";\n return {\n ...wecomConfig,\n accounts: [\n {\n name: accountName,\n botId: wecomConfig.botId || \"\",\n secret: wecomConfig.secret || \"\",\n enabled: wecomConfig.enabled ?? true,\n websocketUrl: wecomConfig.websocketUrl,\n },\n ],\n // 保留旧字段用于向后兼容(但优先使用 accounts)\n botId: undefined,\n secret: undefined,\n };\n }\n\n return wecomConfig;\n}\n\n/**\n * 从 accounts 数组中解析所有已启用的账户\n */\nfunction resolveAccountsFromConfig(wecomConfig: WeComConfig): ResolvedWeComAccount[] {\n const accounts = wecomConfig.accounts ?? [];\n\n if (accounts.length === 0) {\n return [];\n }\n\n return accounts.map((account) => ({\n accountId: account.name,\n name: account.name,\n enabled: account.enabled ?? true,\n websocketUrl: account.websocketUrl || wecomConfig.websocketUrl || DefaultWsUrl,\n botId: account.botId ?? \"\",\n secret: account.secret ?? \"\",\n sendThinkingMessage: wecomConfig.sendThinkingMessage ?? true,\n config: wecomConfig,\n }));\n}\n\n/**\n * 解析企业微信账户配置(返回所有已启用的账户)\n */\nexport function resolveWeComAccounts(cfg: OpenClawConfig): ResolvedWeComAccount[] {\n const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {}) as WeComConfig;\n\n // 迁移旧配置到新格式\n const migratedConfig = migrateToAccounts(wecomConfig);\n\n return resolveAccountsFromConfig(migratedConfig);\n}\n\n/**\n * 根据 name 查找单个账户配置\n */\nexport function resolveWeComAccountByName(\n cfg: OpenClawConfig,\n name: string,\n): ResolvedWeComAccount | null {\n const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {}) as WeComConfig;\n const migratedConfig = migrateToAccounts(wecomConfig);\n\n const accounts = migratedConfig.accounts ?? [];\n const account = accounts.find((a) => a.name === name);\n\n if (!account) {\n return null;\n }\n\n return {\n accountId: account.name,\n name: account.name,\n enabled: account.enabled ?? true,\n websocketUrl: account.websocketUrl || migratedConfig.websocketUrl || DefaultWsUrl,\n botId: account.botId ?? \"\",\n secret: account.secret ?? \"\",\n sendThinkingMessage: migratedConfig.sendThinkingMessage ?? true,\n config: migratedConfig,\n };\n}\n\n/**\n * 解析企业微信账户配置(兼容旧版,返回第一个账户或默认账户)\n * @deprecated 请使用 resolveWeComAccounts 或 resolveWeComAccountByName\n */\nexport function resolveWeComAccount(cfg: OpenClawConfig): ResolvedWeComAccount {\n const accounts = resolveWeComAccounts(cfg);\n\n if (accounts.length > 0) {\n return accounts[0];\n }\n\n // 返回空账户(兼容旧代码)\n const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {}) as WeComConfig;\n return {\n accountId: DEFAULT_ACCOUNT_ID,\n name: \"企业微信\",\n enabled: false,\n websocketUrl: wecomConfig.websocketUrl || DefaultWsUrl,\n botId: \"\",\n secret: \"\",\n sendThinkingMessage: true,\n config: wecomConfig,\n };\n}\n\n/**\n * 获取所有账户 ID(从 accounts 数组中提取)\n */\nexport function listWeComAccountIds(cfg: OpenClawConfig): string[] {\n const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {}) as WeComConfig;\n const migratedConfig = migrateToAccounts(wecomConfig);\n\n const accounts = migratedConfig.accounts ?? [];\n if (accounts.length > 0) {\n return accounts.map((a) => a.name);\n }\n\n // 兼容旧配置\n if (wecomConfig.botId || wecomConfig.secret) {\n return [wecomConfig.name || DEFAULT_ACCOUNT_ID];\n }\n\n return [];\n}\n\n/**\n * 设置企业微信账户配置\n */\nexport function setWeComAccount(\n cfg: OpenClawConfig,\n account: Partial<WeComConfig>,\n): OpenClawConfig {\n const existing = (cfg.channels?.[CHANNEL_ID] ?? {}) as WeComConfig;\n const merged: WeComConfig = {\n enabled: account.enabled ?? existing?.enabled ?? true,\n botId: account.botId ?? existing?.botId ?? \"\",\n secret: account.secret ?? existing?.secret ?? \"\",\n allowFrom: account.allowFrom ?? existing?.allowFrom,\n dmPolicy: account.dmPolicy ?? existing?.dmPolicy,\n // 以下字段仅在已有配置值或显式传入时才写入,onboarding 时不主动生成\n ...(account.websocketUrl || existing?.websocketUrl\n ? { websocketUrl: account.websocketUrl ?? existing?.websocketUrl }\n : {}),\n ...(account.name || existing?.name\n ? { name: account.name ?? existing?.name }\n : {}),\n ...(account.sendThinkingMessage !== undefined || existing?.sendThinkingMessage !== undefined\n ? { sendThinkingMessage: account.sendThinkingMessage ?? existing?.sendThinkingMessage }\n : {}),\n };\n\n return {\n ...cfg,\n channels: {\n ...cfg.channels,\n [CHANNEL_ID]: merged,\n },\n };\n}\n\n/**\n * 添加或更新单个账户配置\n */\nexport function setWeComAccountByName(\n cfg: OpenClawConfig,\n name: string,\n accountConfig: Partial<WeComAccountConfig>,\n): OpenClawConfig {\n const existing = (cfg.channels?.[CHANNEL_ID] ?? {}) as WeComConfig;\n const migratedConfig = migrateToAccounts(existing);\n\n const accounts = migratedConfig.accounts ?? [];\n const existingIndex = accounts.findIndex((a) => a.name === name);\n\n const newAccount: WeComAccountConfig = {\n name,\n botId: accountConfig.botId ?? \"\",\n secret: accountConfig.secret ?? \"\",\n enabled: accountConfig.enabled ?? true,\n websocketUrl: accountConfig.websocketUrl,\n };\n\n let newAccounts: WeComAccountConfig[];\n if (existingIndex >= 0) {\n // 更新现有账户\n newAccounts = [...accounts];\n newAccounts[existingIndex] = { ...newAccounts[existingIndex], ...newAccount };\n } else {\n // 添加新账户\n newAccounts = [...accounts, newAccount];\n }\n\n return {\n ...cfg,\n channels: {\n ...cfg.channels,\n [CHANNEL_ID]: {\n ...migratedConfig,\n accounts: newAccounts,\n // 保留全局配置\n dmPolicy: existing.dmPolicy,\n allowFrom: existing.allowFrom,\n groupPolicy: existing.groupPolicy,\n groupAllowFrom: existing.groupAllowFrom,\n groups: existing.groups,\n sendThinkingMessage: existing.sendThinkingMessage,\n mediaLocalRoots: existing.mediaLocalRoots,\n },\n },\n };\n}\n\n/**\n * 根据 name 删除账户\n */\nexport function deleteWeComAccount(cfg: OpenClawConfig, name: string): OpenClawConfig {\n const existing = (cfg.channels?.[CHANNEL_ID] ?? {}) as WeComConfig;\n const migratedConfig = migrateToAccounts(existing);\n\n const accounts = migratedConfig.accounts ?? [];\n const newAccounts = accounts.filter((a) => a.name !== name);\n\n // 如果删除后没有账户了,保留空数组\n return {\n ...cfg,\n channels: {\n ...cfg.channels,\n [CHANNEL_ID]: {\n ...migratedConfig,\n accounts: newAccounts,\n },\n },\n };\n}\n\n/**\n * 设置账户启用状态\n */\nexport function setWeComAccountEnabled(\n cfg: OpenClawConfig,\n name: string,\n enabled: boolean,\n): OpenClawConfig {\n return setWeComAccountByName(cfg, name, { enabled });\n}\n","/**\n * 企业微信 onboarding adapter for CLI setup wizard.\n */\n\nimport {\n addWildcardAllowFrom,\n type ChannelOnboardingAdapter,\n type ChannelOnboardingDmPolicy,\n type OpenClawConfig,\n type WizardPrompter,\n} from \"openclaw/plugin-sdk\";\nimport type { ResolvedWeComAccount } from \"./utils.js\";\nimport {\n resolveWeComAccounts,\n resolveWeComAccountByName,\n setWeComAccountByName,\n listWeComAccountIds,\n} from \"./utils.js\";\nimport { CHANNEL_ID } from \"./const.js\";\n\nconst channel = CHANNEL_ID;\n\n/**\n * 企业微信设置帮助说明\n */\nasync function noteWeComSetupHelp(prompter: WizardPrompter): Promise<void> {\n await prompter.note(\n [\n \"企业微信机器人需要以下配置信息:\",\n \"1. 账户名称:用于区分不同账户(必填)\",\n \"2. Bot ID:企业微信机器人id\",\n \"3. Secret:企业微信机器人密钥\",\n ].join(\"\\n\"),\n \"企业微信设置\",\n );\n}\n\n/**\n * 提示输入账户名称\n */\nasync function promptAccountName(\n prompter: WizardPrompter,\n existingNames: string[],\n): Promise<string> {\n // 生成默认名称\n let defaultName = \"bot1\";\n let counter = 1;\n while (existingNames.includes(defaultName)) {\n counter++;\n defaultName = `bot${counter}`;\n }\n\n return String(\n await prompter.text({\n message: \"账户名称(用于区分不同机器人)\",\n initialValue: defaultName,\n validate: (value) => {\n const name = value?.trim();\n if (!name) return \"Required\";\n if (existingNames.includes(name)) {\n return `名称 \"${name}\" 已存在,请使用其他名称`;\n }\n return undefined;\n },\n }),\n ).trim();\n}\n\n/**\n * 提示输入 Bot ID\n */\nasync function promptBotId(\n prompter: WizardPrompter,\n account: ResolvedWeComAccount | null,\n): Promise<string> {\n return String(\n await prompter.text({\n message: \"企业微信机器人 Bot ID\",\n initialValue: account?.botId ?? \"\",\n validate: (value) => (value?.trim() ? undefined : \"Required\"),\n }),\n ).trim();\n}\n\n/**\n * 提示输入 Secret\n */\nasync function promptSecret(\n prompter: WizardPrompter,\n account: ResolvedWeComAccount | null,\n): Promise<string> {\n return String(\n await prompter.text({\n message: \"企业微信机器人 Secret\",\n initialValue: account?.secret ?? \"\",\n validate: (value) => (value?.trim() ? undefined : \"Required\"),\n }),\n ).trim();\n}\n\n/**\n * 设置企业微信 dmPolicy\n */\nfunction setWeComDmPolicy(\n cfg: OpenClawConfig,\n dmPolicy: \"pairing\" | \"allowlist\" | \"open\" | \"disabled\",\n accountId?: string,\n): OpenClawConfig {\n const account = accountId\n ? resolveWeComAccountByName(cfg, accountId)\n : resolveWeComAccounts(cfg)[0];\n\n if (!account) return cfg;\n\n const existingAllowFrom = account.config.allowFrom ?? [];\n const allowFrom =\n dmPolicy === \"open\"\n ? addWildcardAllowFrom(existingAllowFrom.map((x) => String(x)))\n : existingAllowFrom.map((x) => String(x));\n\n return setWeComAccountByName(cfg, account.accountId, {\n dmPolicy,\n allowFrom,\n });\n}\n\nconst dmPolicy: ChannelOnboardingDmPolicy = {\n label: \"企业微信\",\n channel,\n policyKey: `channels.${CHANNEL_ID}.dmPolicy`,\n allowFromKey: `channels.${CHANNEL_ID}.allowFrom`,\n getCurrent: (cfg) => {\n const accounts = resolveWeComAccounts(cfg);\n if (accounts.length === 0) return \"open\";\n return accounts[0].config.dmPolicy ?? \"open\";\n },\n setPolicy: (cfg, policy, accountId) => {\n return setWeComDmPolicy(cfg, policy, accountId);\n },\n promptAllowFrom: async ({cfg, prompter, accountId}) => {\n const account = accountId\n ? resolveWeComAccountByName(cfg, accountId)\n : resolveWeComAccounts(cfg)[0];\n\n if (!account) {\n return cfg;\n }\n\n const existingAllowFrom = account.config.allowFrom ?? [];\n\n const entry = await prompter.text({\n message: \"企业微信允许来源(用户ID或群组ID,每行一个,推荐用于安全控制)\",\n placeholder: \"user123 或 group456\",\n initialValue: existingAllowFrom[0] ? String(existingAllowFrom[0]) : undefined,\n });\n\n const allowFrom = String(entry ?? \"\")\n .split(/[\\n,;]+/g)\n .map((s) => s.trim())\n .filter(Boolean);\n\n return setWeComAccountByName(cfg, account.accountId, { allowFrom });\n },\n};\n\nexport const wecomOnboardingAdapter: ChannelOnboardingAdapter = {\n channel,\n getStatus: async ({cfg}) => {\n const accounts = resolveWeComAccounts(cfg);\n const configured = accounts.some(\n (a) => a.botId?.trim() && a.secret?.trim()\n );\n const accountNames = accounts.map((a) => a.name).join(\", \");\n\n return {\n channel,\n configured,\n statusLines: [\n `企业微信: ${configured ? `${accountNames || \"已配置\"}` : \"需要 Bot ID 和 Secret\"}`,\n ],\n selectionHint: configured ? accountNames || \"已配置\" : \"需要设置\",\n };\n },\n configure: async ({cfg, prompter, forceAllowFrom, accountId}) => {\n // 如果指定了 accountId,则更新该账户;否则创建新账户或更新第一个账户\n let targetAccountId = accountId;\n const existingAccounts = resolveWeComAccounts(cfg);\n const existingNames = existingAccounts.map((a) => a.name);\n\n if (!targetAccountId) {\n // 没有指定账户,提示输入新账户名称\n const accountName = await promptAccountName(prompter, existingNames);\n targetAccountId = accountName;\n }\n\n // 获取现有账户配置(如果有)\n const existingAccount = resolveWeComAccountByName(cfg, targetAccountId);\n\n if (!existingAccount?.botId?.trim() || !existingAccount?.secret?.trim()) {\n await noteWeComSetupHelp(prompter);\n }\n\n // 提示输入必要的配置信息:Bot ID 和 Secret\n const botId = await promptBotId(prompter, existingAccount);\n const secret = await promptSecret(prompter, existingAccount);\n\n // 使用 setWeComAccountByName 更新或添加账户\n const cfgWithAccount = setWeComAccountByName(cfg, targetAccountId, {\n botId,\n secret,\n enabled: true,\n });\n\n // 保留全局策略配置\n if (existingAccounts.length > 0 && existingAccounts[0].config.dmPolicy) {\n // 已有全局配置,保持不变\n }\n\n return {cfg: cfgWithAccount, accountId: targetAccountId};\n },\n dmPolicy,\n disable: (cfg, accountId) => {\n if (accountId) {\n return setWeComAccountByName(cfg, accountId, { enabled: false });\n }\n // 没有指定账户,禁用所有账户\n const accounts = resolveWeComAccounts(cfg);\n let result = cfg;\n for (const account of accounts) {\n result = setWeComAccountByName(result, account.accountId, { enabled: false });\n }\n return result;\n },\n};\n","import {\n DEFAULT_ACCOUNT_ID,\n formatPairingApproveHint,\n type ChannelPlugin,\n type ChannelStatusIssue,\n type OpenClawConfig,\n} from \"openclaw/plugin-sdk\";\n\nimport { getWeComRuntime } from \"./runtime.js\";\nimport { monitorWeComProvider } from \"./monitor.js\";\nimport { getWeComWebSocket } from \"./state-manager.js\";\nimport { wecomOnboardingAdapter } from \"./onboarding.js\";\nimport type { WeComConfig, ResolvedWeComAccount } from \"./utils.js\";\nimport {\n resolveWeComAccounts,\n resolveWeComAccountByName,\n setWeComAccountByName,\n deleteWeComAccount,\n setWeComAccountEnabled,\n listWeComAccountIds,\n} from \"./utils.js\";\nimport { CHANNEL_ID, TEXT_CHUNK_LIMIT } from \"./const.js\";\nimport { uploadAndSendMedia } from \"./media-uploader.js\";\n\n/**\n * 使用 SDK 的 sendMessage 主动发送企业微信消息\n * 无需依赖 reqId,直接向指定会话推送消息\n */\nasync function sendWeComMessage({\n to,\n content,\n accountId,\n }: {\n to: string;\n content: string;\n accountId?: string;\n}): Promise<{ channel: string; messageId: string; chatId: string }> {\n const resolvedAccountId = accountId ?? DEFAULT_ACCOUNT_ID;\n\n // 从 to 中提取 chatId(格式是 \"${CHANNEL_ID}:chatId\" 或直接是 chatId)\n const channelPrefix = new RegExp(`^${CHANNEL_ID}:`, \"i\");\n const chatId = to.replace(channelPrefix, \"\");\n\n // 获取 WSClient 实例\n const wsClient = getWeComWebSocket(resolvedAccountId);\n if (!wsClient) {\n throw new Error(`WSClient not connected for account ${resolvedAccountId}`);\n }\n\n // 使用 SDK 的 sendMessage 主动发送 markdown 消息\n const result = await wsClient.sendMessage(chatId, {\n msgtype: 'markdown',\n markdown: { content },\n });\n\n const messageId = result?.headers?.req_id ?? `wecom-${Date.now()}`;\n\n return {\n channel: CHANNEL_ID,\n messageId,\n chatId,\n };\n}\n\n// 企业微信频道元数据\nconst meta = {\n id: CHANNEL_ID,\n label: \"企业微信\",\n selectionLabel: \"企业微信 (WeCom)\",\n detailLabel: \"企业微信智能机器人\",\n docsPath: `/channels/${CHANNEL_ID}`,\n docsLabel: CHANNEL_ID,\n blurb: \"企业微信智能机器人接入插件\",\n systemImage: \"message.fill\",\n};\nexport const wecomPlugin: ChannelPlugin<ResolvedWeComAccount> = {\n id: CHANNEL_ID,\n meta: {\n ...meta,\n quickstartAllowFrom: true,\n },\n pairing: {\n idLabel: \"wecomUserId\",\n normalizeAllowEntry: (entry) => entry.replace(new RegExp(`^(${CHANNEL_ID}|user):`, \"i\"), \"\").trim(),\n notifyApproval: async ({ cfg, id }) => {\n // sendWeComMessage({\n // to: id,\n // content: \" pairing approved\",\n // accountId: cfg.accountId,\n // });\n // Pairing approved for user\n },\n },\n onboarding: wecomOnboardingAdapter,\n capabilities: {\n chatTypes: [\"direct\", \"group\"],\n reactions: false,\n threads: false,\n media: true,\n nativeCommands: false,\n blockStreaming: true,\n },\n reload: {configPrefixes: [`channels.${CHANNEL_ID}`]},\n config: {\n // 列出所有账户 ID\n listAccountIds: (cfg) => listWeComAccountIds(cfg),\n\n // 解析账户配置(根据 accountId 查找)\n resolveAccount: (cfg, accountId) => {\n const id = accountId ?? DEFAULT_ACCOUNT_ID;\n return resolveWeComAccountByName(cfg, id);\n },\n\n // 获取默认账户 ID(第一个启用的账户)\n defaultAccountId: (cfg) => {\n const accounts = resolveWeComAccounts(cfg);\n const enabled = accounts.filter((a) => a.enabled);\n return enabled.length > 0 ? enabled[0].accountId : DEFAULT_ACCOUNT_ID;\n },\n\n // 设置账户启用状态\n setAccountEnabled: ({cfg, accountId, enabled}) => {\n const id = accountId ?? DEFAULT_ACCOUNT_ID;\n return setWeComAccountEnabled(cfg, id, enabled);\n },\n\n // 删除账户\n deleteAccount: ({cfg, accountId}) => {\n const id = accountId ?? DEFAULT_ACCOUNT_ID;\n return deleteWeComAccount(cfg, id);\n },\n\n // 检查是否已配置\n isConfigured: (account) =>\n Boolean(account.botId?.trim() && account.secret?.trim()),\n\n // 描述账户信息\n describeAccount: (account) => ({\n accountId: account.accountId,\n name: account.name,\n enabled: account.enabled,\n configured: Boolean(account.botId?.trim() && account.secret?.trim()),\n botId: account.botId,\n websocketUrl: account.websocketUrl,\n }),\n\n // 解析允许来源列表\n resolveAllowFrom: ({cfg, accountId}) => {\n const id = accountId ?? DEFAULT_ACCOUNT_ID;\n const account = resolveWeComAccountByName(cfg, id);\n return (account?.config.allowFrom ?? []).map((entry) => String(entry));\n },\n\n // 格式化允许来源列表\n formatAllowFrom: ({allowFrom}) =>\n allowFrom\n .map((entry) => String(entry).trim())\n .filter(Boolean),\n },\n security: {\n resolveDmPolicy: ({account}) => {\n const basePath = `channels.${CHANNEL_ID}.`;\n return {\n policy: account?.config.dmPolicy ?? \"open\",\n allowFrom: account?.config.allowFrom ?? [],\n policyPath: `${basePath}dmPolicy`,\n allowFromPath: basePath,\n approveHint: formatPairingApproveHint(CHANNEL_ID),\n normalizeEntry: (raw) => raw.replace(new RegExp(`^${CHANNEL_ID}:`, \"i\"), \"\").trim(),\n };\n },\n collectWarnings: ({account, cfg}) => {\n const warnings: string[] = [];\n\n if (!account) return warnings;\n\n // DM 策略警告\n const dmPolicy = account.config.dmPolicy ?? \"open\";\n if (dmPolicy === \"open\") {\n const hasWildcard = (account.config.allowFrom ?? []).some(\n (entry) => String(entry).trim() === \"*\"\n );\n if (!hasWildcard) {\n warnings.push(\n `- 企业微信私信:dmPolicy=\"open\" 但 allowFrom 未包含 \"*\"。任何人都可以发消息,但允许列表为空可能导致意外行为。建议设置 channels.${CHANNEL_ID}.allowFrom=[\"*\"] 或使用 dmPolicy=\"pairing\"。`,\n );\n }\n }\n\n // 群组策略警告\n const defaultGroupPolicy = cfg.channels?.defaults?.groupPolicy;\n const groupPolicy = account.config.groupPolicy ?? defaultGroupPolicy ?? \"open\"\n if (groupPolicy === \"open\") {\n warnings.push(\n `- 企业微信群组:groupPolicy=\"open\" 允许所有群组中的成员触发。设置 channels.${CHANNEL_ID}.groupPolicy=\"allowlist\" + channels.${CHANNEL_ID}.groupAllowFrom 来限制群组。`,\n );\n }\n\n return warnings;\n },\n },\n messaging: {\n normalizeTarget: (target) => {\n const trimmed = target.trim();\n if (!trimmed) return undefined;\n return trimmed;\n },\n targetResolver: {\n looksLikeId: (id) => {\n const trimmed = id?.trim();\n return Boolean(trimmed);\n },\n hint: \"<userId|groupId>\",\n },\n },\n directory: {\n self: async () => null,\n listPeers: async () => [],\n listGroups: async () => [],\n },\n outbound: {\n deliveryMode: \"gateway\",\n chunker: (text, limit) => getWeComRuntime().channel.text.chunkMarkdownText(text, limit),\n textChunkLimit: TEXT_CHUNK_LIMIT,\n sendText: async ({to, text, accountId}) => {\n return sendWeComMessage({to, content: text, accountId: accountId ?? undefined});\n },\n sendMedia: async ({to, text, mediaUrl, mediaLocalRoots, accountId}) => {\n const resolvedAccountId = accountId ?? DEFAULT_ACCOUNT_ID;\n const channelPrefix = new RegExp(`^${CHANNEL_ID}:`, \"i\");\n const chatId = to.replace(channelPrefix, \"\");\n\n // 获取 WSClient 实例\n const wsClient = getWeComWebSocket(resolvedAccountId);\n if (!wsClient) {\n throw new Error(`WSClient not connected for account ${resolvedAccountId}`);\n }\n\n // 如果没有 mediaUrl,fallback 为纯文本\n if (!mediaUrl) {\n return sendWeComMessage({to, content: text || \"\", accountId: resolvedAccountId});\n }\n\n const result = await uploadAndSendMedia({\n wsClient,\n mediaUrl,\n chatId,\n mediaLocalRoots,\n });\n\n if (result.rejected) {\n return sendWeComMessage({to, content: `⚠️ ${result.rejectReason}`, accountId: resolvedAccountId});\n }\n\n if (!result.ok) {\n // 上传/发送失败,fallback 为文本 + URL\n const fallbackContent = text\n ? `${text}\\n📎 ${mediaUrl}`\n : `📎 ${mediaUrl}`;\n return sendWeComMessage({to, content: fallbackContent, accountId: resolvedAccountId});\n }\n\n // 如有伴随文本,额外发送一条 markdown\n if (text) {\n await sendWeComMessage({to, content: text, accountId: resolvedAccountId});\n }\n\n // 如果有降级说明,额外发送提示\n if (result.downgradeNote) {\n await sendWeComMessage({to, content: `ℹ️ ${result.downgradeNote}`, accountId: resolvedAccountId});\n }\n\n return {\n channel: CHANNEL_ID,\n messageId: result.messageId!,\n chatId,\n };\n },\n },\n status: {\n defaultRuntime: {\n accountId: DEFAULT_ACCOUNT_ID,\n running: false,\n lastStartAt: null,\n lastStopAt: null,\n lastError: null,\n },\n collectStatusIssues: (accounts): ChannelStatusIssue[] =>\n accounts.flatMap((entry) => {\n const accountId = String(entry.accountId ?? DEFAULT_ACCOUNT_ID);\n const enabled = entry.enabled !== false;\n const configured = entry.configured === true;\n if (!enabled) {\n return [];\n }\n const issues: ChannelStatusIssue[] = [];\n if (!configured) {\n issues.push({\n channel: CHANNEL_ID,\n accountId,\n kind: \"config\",\n message: \"企业微信机器人 ID 或 Secret 未配置\",\n fix: `Run: openclaw channels add wecom --account ${accountId} --bot-id <id> --secret <secret>`,\n });\n }\n return issues;\n }),\n buildChannelSummary: ({snapshot}) => ({\n configured: snapshot.configured ?? false,\n running: snapshot.running ?? false,\n lastStartAt: snapshot.lastStartAt ?? null,\n lastStopAt: snapshot.lastStopAt ?? null,\n lastError: snapshot.lastError ?? null,\n }),\n probeAccount: async () => {\n return {ok: true, status: 200};\n },\n buildAccountSnapshot: ({account, runtime}) => {\n const configured = Boolean(\n account?.botId?.trim() &&\n account?.secret?.trim()\n );\n return {\n accountId: account?.accountId ?? DEFAULT_ACCOUNT_ID,\n name: account?.name,\n enabled: account?.enabled ?? false,\n configured,\n running: runtime?.running ?? false,\n lastStartAt: runtime?.lastStartAt ?? null,\n lastStopAt: runtime?.lastStopAt ?? null,\n lastError: runtime?.lastError ?? null,\n };\n },\n },\n gateway: {\n startAccount: async (ctx) => {\n const account = ctx.account;\n\n // 启动 WebSocket 监听\n return monitorWeComProvider({\n account,\n config: ctx.cfg,\n runtime: ctx.runtime,\n abortSignal: ctx.abortSignal,\n });\n },\n logoutAccount: async ({cfg, accountId}) => {\n const nextCfg = {...cfg} as OpenClawConfig;\n const id = accountId ?? DEFAULT_ACCOUNT_ID;\n\n // 删除指定账户\n const nextWecom = deleteWeComAccount(nextCfg, id);\n\n // 检查是否还有其他账户\n const remainingAccounts = listWeComAccountIds(nextCfg);\n\n if (remainingAccounts.length === 0) {\n // 没有剩余账户,删除整个频道配置\n const nextChannels = {...nextCfg.channels};\n delete (nextChannels as Record<string, unknown>)[CHANNEL_ID];\n if (Object.keys(nextChannels).length > 0) {\n nextCfg.channels = nextChannels;\n } else {\n delete nextCfg.channels;\n }\n await getWeComRuntime().config.writeConfigFile(nextCfg);\n } else {\n // 有剩余账户,写入更新后的配置\n await getWeComRuntime().config.writeConfigFile(nextWecom);\n }\n\n const resolved = resolveWeComAccountByName(cfg, id);\n const loggedOut = !resolved?.botId && !resolved?.secret;\n\n return {cleared: true, envToken: false, loggedOut};\n },\n },\n};\n","import { readFileSync } from \"node:fs\";\nimport { resolve, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/** 从 package.json 中读取版本号,兼容打包产物和直接运行 .ts 两种场景 */\nconst getVersion = (): string => {\n try {\n // ESM 环境使用 import.meta.url,CJS 环境使用全局 __dirname\n const currentDir = dirname(fileURLToPath(import.meta.url));\n\n // 直接运行 .ts 时在 src/ 下,打包后在 dist/ 下,都向上一级找 package.json\n const pkgPath = resolve(currentDir, \"..\", \"package.json\");\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n return pkg.version ?? \"\";\n } catch {\n return \"\";\n }\n};\n\n/** 插件版本号,来源于 package.json */\nexport const PLUGIN_VERSION: string = getVersion();\n","/**\n * MCP Streamable HTTP 传输层模块\n *\n * 负责:\n * - MCP JSON-RPC over HTTP 通信(发送请求、解析响应)\n * - Streamable HTTP session 生命周期管理(initialize 握手 → Mcp-Session-Id 维护 → 失效重建)\n * - 自动检测无状态 Server:如果 initialize 响应未返回 Mcp-Session-Id,\n * 则标记为无状态模式,后续请求跳过握手和 session 管理\n * - SSE 流式响应解析\n * - MCP 配置运行时缓存(通过 WSClient 拉取 URL 并缓存在内存中)\n */\n\nimport { generateReqId } from \"@wecom/aibot-node-sdk\";\nimport { DEFAULT_ACCOUNT_ID } from \"openclaw/plugin-sdk\";\nimport { getWeComWebSocket } from \"../state-manager.js\";\nimport { MCP_GET_CONFIG_CMD, MCP_CONFIG_FETCH_TIMEOUT_MS } from \"../const.js\";\nimport { withTimeout } from \"../timeout.js\";\nimport { PLUGIN_VERSION } from \"../version.js\";\n\n// ============================================================================\n// 类型定义\n// ============================================================================\n\n/** MCP JSON-RPC 请求体 */\ninterface JsonRpcRequest {\n jsonrpc: \"2.0\";\n id?: string;\n method: string;\n params?: Record<string, unknown>;\n}\n\n/** MCP JSON-RPC 响应体 */\ninterface JsonRpcResponse {\n jsonrpc: \"2.0\";\n id: number | string;\n result?: unknown;\n error?: {\n code: number;\n message: string;\n data?: unknown;\n };\n}\n\n/**\n * Streamable HTTP 会话信息\n *\n * 每个 MCP Server category 维护一个独立的会话,包含:\n * - sessionId: 服务端通过 Mcp-Session-Id 响应头返回的会话标识\n * - initialized: 是否已完成 initialize 握手\n * - stateless: 服务端未返回 Mcp-Session-Id 时标记为无状态模式,后续请求跳过 session 管理\n */\ninterface McpSession {\n sessionId: string | null;\n initialized: boolean;\n stateless: boolean;\n}\n\n// ============================================================================\n// 内部状态\n// ============================================================================\n\n/** HTTP 请求超时时间(毫秒) */\nconst HTTP_REQUEST_TIMEOUT_MS = 30_000;\n\n/** 日志前缀 */\nconst LOG_TAG = \"[mcp]\";\n\n/**\n * MCP JSON-RPC 错误\n *\n * 携带服务端返回的 JSON-RPC error.code,\n * 用于上层按错误码进行差异化处理(如特定错误码触发缓存清理)。\n */\nexport class McpRpcError extends Error {\n constructor(\n public readonly code: number,\n message: string,\n public readonly data?: unknown,\n ) {\n super(message);\n this.name = \"McpRpcError\";\n }\n}\n\n/**\n * MCP HTTP 错误\n *\n * 携带 HTTP 状态码,用于精确判断 session 失效(404)等场景,\n * 避免通过字符串匹配 \"404\" 导致的误判。\n */\nexport class McpHttpError extends Error {\n constructor(\n public readonly statusCode: number,\n message: string,\n ) {\n super(message);\n this.name = \"McpHttpError\";\n }\n}\n\n/**\n * 需要清理缓存的 JSON-RPC 错误码集合\n *\n * 当 MCP Server 返回以下错误码时,说明服务端状态已发生变化(如配置变更、\n * 服务重启等),需要清理对应 category 的全部缓存,确保下次请求重新\n * 拉取配置并重建会话。\n *\n * - -32001: 服务不可用(Server Unavailable)\n * - -32002: 配置已变更(Config Changed)\n * - -32003: 认证失败(Auth Failed)\n */\nconst CACHE_CLEAR_ERROR_CODES = new Set([-32001, -32002, -32003]);\n\n/** MCP 配置缓存:category → response.body(完整配置) */\nconst mcpConfigCache = new Map<string, Record<string, unknown>>();\n\n/** Streamable HTTP 会话缓存:category → session */\nconst mcpSessionCache = new Map<string, McpSession>();\n\n/** 已确认为无状态的 MCP Server 品类集合(跳过后续握手) */\nconst statelessCategories = new Set<string>();\n\n/** 正在进行中的 initialize 请求(防止并发重复初始化),key 为 category */\nconst inflightInitRequests = new Map<string, Promise<McpSession>>();\n\n// ============================================================================\n// MCP 配置拉取与缓存\n// ============================================================================\n\n/**\n * 通过 WSClient 拉取指定 category 的 MCP 完整配置\n *\n * @param category - MCP 品类名称,如 doc、contact\n * @param accountId - 账户 ID(可选,默认使用 DEFAULT_ACCOUNT_ID)\n * @returns 完整的 response.body 配置对象(至少包含 url 字段)\n */\nasync function fetchMcpConfig(\n category: string,\n accountId: string = DEFAULT_ACCOUNT_ID,\n): Promise<Record<string, unknown>> {\n const wsClient = getWeComWebSocket(accountId);\n if (!wsClient) {\n throw new Error(`WSClient 未连接,无法拉取 MCP 配置 (accountId=\"${accountId}\")`);\n }\n\n const reqId = generateReqId(\"mcp_config\");\n\n const response = await withTimeout(\n wsClient.reply(\n { headers: { req_id: reqId } },\n { biz_type: category, plugin_version: PLUGIN_VERSION },\n MCP_GET_CONFIG_CMD,\n ),\n MCP_CONFIG_FETCH_TIMEOUT_MS,\n `MCP config fetch for \"${category}\" timed out after ${MCP_CONFIG_FETCH_TIMEOUT_MS}ms`,\n );\n\n if (response.errcode !== undefined && response.errcode !== 0) {\n const errMsg = `MCP 配置请求失败: errcode=${response.errcode}, errmsg=${response.errmsg ?? \"unknown\"}`;\n console.error(`${LOG_TAG} ${errMsg}`);\n throw new Error(errMsg);\n }\n\n const body = response.body as { url?: string } | undefined;\n if (!body?.url) {\n throw new Error(\n `MCP 配置响应缺少 url 字段 (category=\"${category}\")`,\n );\n }\n\n console.log(`${LOG_TAG} 配置拉取成功 (category=\"${category}\", accountId=\"${accountId}\")`);\n return body as Record<string, unknown>;\n}\n\n/**\n * 获取指定品类的 MCP Server URL\n *\n * 优先从内存缓存中读取,未命中时通过 WSClient 拉取并缓存。\n *\n * @param category - MCP 品类名称\n * @param accountId - 账户 ID\n * @returns MCP Server URL\n */\nasync function getMcpUrl(category: string, accountId: string = DEFAULT_ACCOUNT_ID): Promise<string> {\n // 使用 accountId + category 作为缓存 key,实现多账户隔离\n const cacheKey = `${accountId}:${category}`;\n\n // 查内存缓存\n const cached = mcpConfigCache.get(cacheKey);\n if (cached) return cached.url as string;\n\n // 缓存未命中,通过 WSClient 拉取\n const body = await fetchMcpConfig(category, accountId);\n\n // 写入缓存\n mcpConfigCache.set(cacheKey, body);\n\n console.log(`${LOG_TAG} getMcpUrl ${category} (${accountId}): ${body.url}`);\n\n return body.url as string;\n}\n\n// ============================================================================\n// HTTP 底层通信\n// ============================================================================\n\n/**\n * 发送原始 HTTP 请求到 MCP Server(底层方法)\n *\n * 自动携带 Mcp-Session-Id 请求头(如果有),\n * 并从响应头中更新 sessionId。\n */\nasync function sendRawJsonRpc(\n url: string,\n session: McpSession,\n body: JsonRpcRequest,\n): Promise<{ response: Response; rpcResult: unknown; newSessionId: string | null }> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), HTTP_REQUEST_TIMEOUT_MS);\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json, text/event-stream\",\n };\n // Streamable HTTP:携带会话 ID\n if (session.sessionId) {\n headers[\"Mcp-Session-Id\"] = session.sessionId;\n }\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } catch (err) {\n if (err instanceof DOMException && err.name === \"AbortError\") {\n throw new Error(`MCP 请求超时 (${HTTP_REQUEST_TIMEOUT_MS}ms)`);\n }\n throw new Error(`MCP 网络请求失败: ${err instanceof Error ? err.message : String(err)}`);\n } finally {\n clearTimeout(timeoutId);\n }\n\n // 从响应头提取新的 sessionId(不直接修改入参,由调用方决定如何更新)\n const newSessionId = response.headers.get(\"mcp-session-id\");\n\n if (!response.ok) {\n throw new McpHttpError(\n response.status,\n `MCP HTTP 请求失败: ${response.status} ${response.statusText}`,\n );\n }\n\n // Streamable HTTP:notification 响应可能无响应体(204 或 content-length: 0)\n const contentLength = response.headers.get(\"content-length\");\n if (response.status === 204 || contentLength === \"0\") {\n return { response, rpcResult: undefined, newSessionId };\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n\n // 处理 SSE 流式响应\n if (contentType.includes(\"text/event-stream\")) {\n return { response, rpcResult: await parseSseResponse(response), newSessionId };\n }\n\n // 普通 JSON 响应 — 先读取文本,防止空内容导致 JSON.parse 报错\n const text = await response.text();\n if (!text.trim()) {\n return { response, rpcResult: undefined, newSessionId };\n }\n\n const rpc = JSON.parse(text) as JsonRpcResponse;\n if (rpc.error) {\n throw new McpRpcError(\n rpc.error.code,\n `MCP 调用错误 [${rpc.error.code}]: ${rpc.error.message}`,\n rpc.error.data,\n );\n }\n return { response, rpcResult: rpc.result, newSessionId };\n}\n\n// ============================================================================\n// Session 管理\n// ============================================================================\n\n/**\n * 对指定 URL 执行 Streamable HTTP 的 initialize 握手\n *\n * 发送 initialize → 接收 serverInfo → 发送 initialized 通知。\n * 如果服务端未返回 Mcp-Session-Id,则标记为无状态模式,后续请求跳过 session 管理。\n */\nasync function initializeSession(url: string, sessionKey: string): Promise<McpSession> {\n const session: McpSession = { sessionId: null, initialized: false, stateless: false };\n\n console.log(`${LOG_TAG} 开始 initialize 握手 (sessionKey=\"${sessionKey}\")`);\n\n // 1. 发送 initialize 请求\n const initBody: JsonRpcRequest = {\n jsonrpc: \"2.0\",\n id: generateReqId(\"mcp_init\"),\n method: \"initialize\",\n params: {\n protocolVersion: \"2025-03-26\",\n capabilities: {},\n clientInfo: { name: \"wecom_mcp\", version: \"1.0.0\" },\n },\n };\n\n const { newSessionId: initSessionId } = await sendRawJsonRpc(url, session, initBody);\n\n // 用返回的 newSessionId 更新 session(不再依赖副作用修改)\n if (initSessionId) {\n session.sessionId = initSessionId;\n }\n\n // 检查服务端是否返回了 Mcp-Session-Id\n // 如果没有返回,说明该 Server 是无状态实现,无需维护 session\n if (!session.sessionId) {\n session.stateless = true;\n session.initialized = true;\n statelessCategories.add(sessionKey);\n mcpSessionCache.set(sessionKey, session);\n console.log(`${LOG_TAG} 无状态 Server 确认 (sessionKey=\"${sessionKey}\")`);\n return session;\n }\n\n // 2. 发送 initialized 通知(JSON-RPC notification 不带 id 字段)\n const notifyBody: JsonRpcRequest = {\n jsonrpc: \"2.0\",\n method: \"notifications/initialized\",\n };\n // initialized 通知不需要等待响应,但 Streamable HTTP 要求通过 POST 发送\n const { newSessionId: notifySessionId } = await sendRawJsonRpc(url, session, notifyBody);\n\n // 如果 initialized 通知的响应也携带了 sessionId,以最新的为准\n if (notifySessionId) {\n session.sessionId = notifySessionId;\n }\n\n session.initialized = true;\n mcpSessionCache.set(sessionKey, session);\n console.log(`${LOG_TAG} 有状态 Session 建立成功 (sessionKey=\"${sessionKey}\", sessionId=\"${session.sessionId}\")`);\n return session;\n}\n\n/**\n * 获取或创建指定 URL 的 MCP 会话\n *\n * - 已确认无状态的 category:直接返回空 session,跳过握手\n * - 已有可用有状态会话:直接返回缓存\n * - 其他情况:执行 initialize 握手,并发请求会被合并\n */\nasync function getOrCreateSession(url: string, sessionKey: string): Promise<McpSession> {\n // 已确认为无状态的 Server,直接返回空 session 跳过握手\n if (statelessCategories.has(sessionKey)) {\n const cached = mcpSessionCache.get(sessionKey);\n if (cached) return cached;\n // 首次发现被清除(理论上不会走到这里),重新走握手探测\n }\n\n const cached = mcpSessionCache.get(sessionKey);\n if (cached?.initialized) return cached;\n\n // 防止并发重复初始化\n const inflight = inflightInitRequests.get(sessionKey);\n if (inflight) return inflight;\n\n const promise = initializeSession(url, sessionKey).finally(() => {\n inflightInitRequests.delete(sessionKey);\n });\n inflightInitRequests.set(sessionKey, promise);\n return promise;\n}\n\n// ============================================================================\n// SSE 解析\n// ============================================================================\n\n/**\n * 解析 SSE 流式响应,提取最终的 JSON-RPC result\n *\n * 按照 SSE 规范,同一事件中的多个 `data:` 行会用换行符拼接。\n * 空行分隔不同事件,取最后一个完整事件的数据。\n */\nasync function parseSseResponse(response: Response): Promise<unknown> {\n const text = await response.text();\n const lines = text.split(\"\\n\");\n\n // 按 SSE 规范解析:空行分隔事件,同一事件内的 data 行用换行拼接\n let currentDataParts: string[] = [];\n let lastEventData = \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"data: \")) {\n currentDataParts.push(line.slice(6));\n } else if (line.startsWith(\"data:\")) {\n // data: 后无空格时,值为空字符串\n currentDataParts.push(line.slice(5));\n } else if (line.trim() === \"\" && currentDataParts.length > 0) {\n // 空行表示事件结束,拼接所有 data 行\n lastEventData = currentDataParts.join(\"\\n\").trim();\n currentDataParts = [];\n }\n }\n\n // 处理最后一个未以空行结尾的事件\n if (currentDataParts.length > 0) {\n lastEventData = currentDataParts.join(\"\\n\").trim();\n }\n\n if (!lastEventData) {\n throw new Error(\"SSE 响应中未包含有效数据\");\n }\n\n try {\n const rpc = JSON.parse(lastEventData) as JsonRpcResponse;\n if (rpc.error) {\n throw new McpRpcError(\n rpc.error.code,\n `MCP 调用错误 [${rpc.error.code}]: ${rpc.error.message}`,\n rpc.error.data,\n );\n }\n return rpc.result;\n } catch (err) {\n if (err instanceof SyntaxError) {\n throw new Error(`SSE 响应解析失败: ${lastEventData.slice(0, 200)}`);\n }\n throw err;\n }\n}\n\n// ============================================================================\n// 公共 API\n// ============================================================================\n\n/**\n * 清理指定品类的所有 MCP 缓存(配置、会话、无状态标记)\n *\n * 当 MCP Server 返回特定错误码时调用,确保下次请求重新拉取配置并重建会话。\n *\n * @param category - MCP 品类名称\n * @param accountId - 账户 ID(可选,用于清理特定账户的缓存)\n */\nexport function clearCategoryCache(category: string, accountId?: string): void {\n if (accountId) {\n // 清理特定账户的缓存\n const cacheKey = `${accountId}:${category}`;\n console.log(`${LOG_TAG} 清理缓存 (category=\"${category}\", accountId=\"${accountId}\")`);\n mcpConfigCache.delete(cacheKey);\n mcpSessionCache.delete(cacheKey);\n statelessCategories.delete(cacheKey);\n inflightInitRequests.delete(cacheKey);\n } else {\n // 清理所有账户的该品类缓存\n console.log(`${LOG_TAG} 清理缓存 (category=\"${category}\", all accounts)\"`);\n for (const key of mcpConfigCache.keys()) {\n if (key.endsWith(`:${category}`)) {\n mcpConfigCache.delete(key);\n }\n }\n for (const key of mcpSessionCache.keys()) {\n if (key.endsWith(`:${category}`)) {\n mcpSessionCache.delete(key);\n }\n }\n for (const key of statelessCategories.keys()) {\n if (key.endsWith(`:${category}`)) {\n statelessCategories.delete(key);\n }\n }\n for (const key of inflightInitRequests.keys()) {\n if (key.endsWith(`:${category}`)) {\n inflightInitRequests.delete(key);\n }\n }\n }\n}\n\n/** tools/list 返回的工具描述 */\nexport interface McpToolInfo {\n name: string;\n description?: string;\n inputSchema?: Record<string, unknown>;\n}\n\n/**\n * 发送 JSON-RPC 请求到 MCP Server(Streamable HTTP 协议)\n *\n * 自动管理 session 生命周期:\n * - 无状态 Server:跳过 session 管理,直接发送请求\n * - 有状态 Server:首次调用先执行 initialize 握手,session 失效(404)时自动重建并重试\n *\n * @param category - MCP 品类名称\n * @param method - JSON-RPC 方法名\n * @param params - JSON-RPC 参数\n * @param accountId - 账户 ID(可选,默认使用 DEFAULT_ACCOUNT_ID)\n * @returns JSON-RPC result\n */\nexport async function sendJsonRpc(\n category: string,\n method: string,\n params?: Record<string, unknown>,\n accountId: string = DEFAULT_ACCOUNT_ID,\n): Promise<unknown> {\n const url = await getMcpUrl(category, accountId);\n\n // 使用 accountId + category 作为 session 缓存 key\n const sessionKey = `${accountId}:${category}`;\n\n const body: JsonRpcRequest = {\n jsonrpc: \"2.0\",\n id: generateReqId(\"mcp_rpc\"),\n method,\n ...(params !== undefined ? { params } : {}),\n };\n\n let session = await getOrCreateSession(url, sessionKey);\n\n try {\n const { rpcResult, newSessionId } = await sendRawJsonRpc(url, session, body);\n // 用最新的 sessionId 更新 session\n if (newSessionId) {\n session.sessionId = newSessionId;\n }\n return rpcResult;\n } catch (err) {\n // 特定 JSON-RPC 错误码触发缓存清理(统一在传输层处理,上层无需关心)\n if (err instanceof McpRpcError && CACHE_CLEAR_ERROR_CODES.has(err.code)) {\n clearCategoryCache(category, accountId);\n }\n\n // 无状态 Server 不存在 session 失效问题,直接抛出错误\n if (session.stateless) throw err;\n\n // 有状态 Server:session 失效时服务端返回 404,需要重新初始化并重试一次\n // 使用 McpHttpError.statusCode 精确匹配,避免字符串匹配 \"404\" 导致误判\n if (err instanceof McpHttpError && err.statusCode === 404) {\n console.log(`${LOG_TAG} Session 失效 (category=\"${category}\", accountId=\"${accountId}\"),开始重建...`);\n mcpSessionCache.delete(sessionKey);\n\n // 使用 rebuildSession 合并并发的 session 重建请求,避免竞态条件\n session = await rebuildSession(url, sessionKey);\n const { rpcResult, newSessionId } = await sendRawJsonRpc(url, session, body);\n if (newSessionId) {\n session.sessionId = newSessionId;\n }\n return rpcResult;\n }\n\n // 其他错误记录日志后抛出\n console.error(`${LOG_TAG} RPC 请求失败 (category=\"${category}\", accountId=\"${accountId}\", method=\"${method}\"): ${err instanceof Error ? err.message : String(err)}`);\n throw err;\n }\n}\n\n/**\n * 合并并发的 session 重建请求\n *\n * 与 getOrCreateSession 类似,使用 inflightInitRequests 防止\n * 多个并发请求同时遇到 404 时重复执行 initialize 握手。\n */\nasync function rebuildSession(url: string, sessionKey: string): Promise<McpSession> {\n const inflight = inflightInitRequests.get(sessionKey);\n if (inflight) return inflight;\n\n const promise = initializeSession(url, sessionKey).finally(() => {\n inflightInitRequests.delete(sessionKey);\n });\n inflightInitRequests.set(sessionKey, promise);\n return promise;\n}\n","/**\n * MCP Schema 清洗模块\n *\n * 负责内联 $ref/$defs 引用并移除 Gemini 不支持的 JSON Schema 关键词,\n * 防止 Gemini 模型解析 function response 时报 400 错误。\n */\n\n/** Gemini 不支持的 JSON Schema 关键词 */\nconst GEMINI_UNSUPPORTED_KEYWORDS = new Set([\n \"patternProperties\", \"additionalProperties\", \"$schema\", \"$id\", \"$ref\", \"$defs\",\n \"definitions\", \"examples\", \"minLength\", \"maxLength\", \"minimum\", \"maximum\",\n \"multipleOf\", \"pattern\", \"format\", \"minItems\", \"maxItems\", \"uniqueItems\",\n \"minProperties\", \"maxProperties\",\n]);\n\n/**\n * 清洗 JSON Schema,内联 $ref 引用并移除 Gemini 不支持的关键词,\n * 防止 Gemini 模型解析 function response 时报 400 错误。\n */\nexport function cleanSchemaForGemini(schema: unknown): unknown {\n if (!schema || typeof schema !== \"object\") return schema;\n if (Array.isArray(schema)) return schema.map(cleanSchemaForGemini);\n\n const obj = schema as Record<string, unknown>;\n\n // 收集 $defs/definitions 用于后续 $ref 内联解析\n const defs: Record<string, unknown> = {\n ...(obj.$defs && typeof obj.$defs === \"object\" ? obj.$defs as Record<string, unknown> : {}),\n ...(obj.definitions && typeof obj.definitions === \"object\" ? obj.definitions as Record<string, unknown> : {}),\n };\n\n return cleanWithDefs(obj, defs, new Set());\n}\n\nfunction cleanWithDefs(\n schema: unknown,\n defs: Record<string, unknown>,\n refStack: Set<string>,\n): unknown {\n if (!schema || typeof schema !== \"object\") return schema;\n if (Array.isArray(schema)) return schema.map((item) => cleanWithDefs(item, defs, refStack));\n\n const obj = schema as Record<string, unknown>;\n\n // 合并当前层级的 $defs/definitions 到 defs 中\n if (obj.$defs && typeof obj.$defs === \"object\") {\n Object.assign(defs, obj.$defs as Record<string, unknown>);\n }\n if (obj.definitions && typeof obj.definitions === \"object\") {\n Object.assign(defs, obj.definitions as Record<string, unknown>);\n }\n\n // 处理 $ref 引用:尝试内联解析\n if (typeof obj.$ref === \"string\") {\n const ref = obj.$ref;\n if (refStack.has(ref)) return {}; // 防止循环引用\n\n const match = ref.match(/^#\\/(?:\\$defs|definitions)\\/(.+)$/);\n if (match && match[1] && defs[match[1]]) {\n const nextStack = new Set(refStack);\n nextStack.add(ref);\n return cleanWithDefs(defs[match[1]], defs, nextStack);\n }\n return {}; // 无法解析的 $ref,返回空对象\n }\n\n const cleaned: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (GEMINI_UNSUPPORTED_KEYWORDS.has(key)) continue;\n\n if (key === \"const\") {\n cleaned.enum = [value];\n continue;\n }\n\n if (key === \"properties\" && value && typeof value === \"object\" && !Array.isArray(value)) {\n cleaned[key] = Object.fromEntries(\n Object.entries(value as Record<string, unknown>).map(([k, v]) => [\n k, cleanWithDefs(v, defs, refStack),\n ]),\n );\n } else if (key === \"items\" && value) {\n cleaned[key] = Array.isArray(value)\n ? value.map((item) => cleanWithDefs(item, defs, refStack))\n : cleanWithDefs(value, defs, refStack);\n } else if ((key === \"anyOf\" || key === \"oneOf\" || key === \"allOf\") && Array.isArray(value)) {\n // 过滤掉 null 类型的变体\n const nonNull = value.filter((v) => {\n if (!v || typeof v !== \"object\") return true;\n const r = v as Record<string, unknown>;\n return r.type !== \"null\";\n });\n if (nonNull.length === 1) {\n // 只剩一个变体时直接内联\n const single = cleanWithDefs(nonNull[0], defs, refStack);\n if (single && typeof single === \"object\" && !Array.isArray(single)) {\n Object.assign(cleaned, single as Record<string, unknown>);\n }\n } else {\n cleaned[key] = nonNull.map((v) => cleanWithDefs(v, defs, refStack));\n }\n } else {\n cleaned[key] = value;\n }\n }\n\n return cleaned;\n}\n","/**\n * wecom_mcp — 模拟 MCP 调用的 Agent Tool\n *\n * 通过 MCP Streamable HTTP 传输协议调用企业微信 MCP Server,\n * 提供 list(列出所有工具)和 call(调用工具)两个操作。\n *\n * 在 skills 中的使用方式:\n * wecom_mcp list <category>\n * wecom_mcp call <category> <method> '<jsonArgs>'\n *\n * 示例:\n * wecom_mcp list contact\n * wecom_mcp call contact getContact '{}'\n */\n\nimport { sendJsonRpc, clearCategoryCache, type McpToolInfo } from \"./transport.js\";\nimport { cleanSchemaForGemini } from \"./schema.js\";\n\n// ============================================================================\n// 类型定义\n// ============================================================================\n\n/** wecom_mcp 的入参 */\ninterface WeComToolsParams {\n /** 操作类型:list | call */\n action: \"list\" | \"call\";\n /** MCP 品类,对应 mcpConfig 中的 key,如 doc、contact */\n category: string;\n /** 账户 ID(可选,用于多账户场景) */\n accountId?: string;\n /** 调用的 MCP 方法名(action=call 时必填) */\n method?: string;\n /** 调用 MCP 方法的 JSON 参数(action=call 时使用) */\n args?: string | Record<string, unknown>;\n}\n\n// ============================================================================\n// 响应构造辅助\n// ============================================================================\n\n/** 构造统一的文本响应结构 */\nconst textResult = (data: unknown) => ({\n content: [{ type: \"text\" as const, text: JSON.stringify(data, null, 2) }],\n});\n\n/** 构造错误响应 */\nconst errorResult = (err: unknown) => {\n // 适配企业微信 API 返回的 { errcode, errmsg } 结构\n if (err && typeof err === \"object\" && \"errcode\" in err) {\n const { errcode, errmsg } = err as { errcode: number; errmsg?: string };\n return textResult({ error: errmsg ?? `错误码: ${errcode}`, errcode });\n }\n\n const message = err instanceof Error ? err.message : String(err);\n return textResult({ error: message });\n};\n\n// ============================================================================\n// list 操作:列出某品类的所有 MCP 工具\n// ============================================================================\n\nconst handleList = async (category: string, accountId?: string): Promise<unknown> => {\n const result = await sendJsonRpc(category, \"tools/list\", undefined, accountId) as { tools?: McpToolInfo[] } | undefined;\n\n const tools = result?.tools ?? [];\n if (tools.length === 0) {\n return { message: `品类 \"${category}\" 下暂无可用工具`, tools: [] };\n }\n\n return {\n category,\n accountId: accountId ?? \"default\",\n count: tools.length,\n tools: tools.map((t) => ({\n name: t.name,\n description: t.description ?? \"\",\n // 清洗 inputSchema,内联 $ref/$defs 引用并移除 Gemini 不支持的关键词,\n // 避免 Gemini 模型解析 function response 时报 400 错误\n inputSchema: t.inputSchema ? cleanSchemaForGemini(t.inputSchema) : undefined,\n })),\n };\n};\n\n// ============================================================================\n// call 操作:调用某品类的某个 MCP 工具\n// ============================================================================\n\n/**\n * 需要触发缓存清理的业务错误码集合\n *\n * 这些错误码出现在 MCP 工具调用返回的 content 文本中(业务层面),\n * 与 JSON-RPC 层面的错误码不同,需要在此处额外检测。\n *\n * - 850002: 机器人未被授权使用对应能力,需清理缓存以便下次重新拉取配置\n */\nconst BIZ_CACHE_CLEAR_ERROR_CODES = new Set([850002]);\n\n/**\n * 检查 tools/call 的返回结果中是否包含需要清理缓存的业务错误码\n *\n * MCP Server 可能在正常的 JSON-RPC 响应中返回业务层错误,\n * 这些错误被包裹在 result.content[].text 中,需要解析后判断。\n */\nconst checkBizErrorAndClearCache = (result: unknown, category: string, accountId?: string): void => {\n if (!result || typeof result !== \"object\") return;\n\n const { content } = result as { content?: Array<{ type: string; text?: string }> };\n if (!Array.isArray(content)) return;\n\n for (const item of content) {\n if (item.type !== \"text\" || !item.text) continue;\n try {\n const parsed = JSON.parse(item.text) as Record<string, unknown>;\n if (typeof parsed.errcode === \"number\" && BIZ_CACHE_CLEAR_ERROR_CODES.has(parsed.errcode)) {\n console.log(`[mcp] 检测到业务错误码 ${parsed.errcode} (category=\"${category}\", accountId=\"${accountId}\"),清理缓存`);\n clearCategoryCache(category, accountId);\n return;\n }\n } catch {\n // text 不是 JSON 格式,跳过\n }\n }\n};\n\nconst handleCall = async (\n category: string,\n method: string,\n args: Record<string, unknown>,\n accountId?: string,\n): Promise<unknown> => {\n const result = await sendJsonRpc(category, \"tools/call\", {\n name: method,\n arguments: args,\n }, accountId);\n\n // 检查业务层错误码,必要时清理缓存\n checkBizErrorAndClearCache(result, category, accountId);\n\n return result;\n};\n\n// ============================================================================\n// 参数解析\n// ============================================================================\n\n/**\n * 解析 args 参数:支持 JSON 字符串或直接的对象\n */\nconst parseArgs = (args: string | Record<string, unknown> | undefined): Record<string, unknown> => {\n if (!args) return {};\n if (typeof args === \"object\") return args;\n try {\n return JSON.parse(args) as Record<string, unknown>;\n } catch (err) {\n const detail = err instanceof SyntaxError ? err.message : String(err);\n throw new Error(`args 参数不是合法的 JSON: ${args} (${detail})`);\n }\n};\n\n// ============================================================================\n// 工具定义 & 导出\n// ============================================================================\n\n/**\n * 创建 wecom_mcp Agent Tool 定义\n */\nexport function createWeComMcpTool() {\n return {\n name: \"wecom_mcp\",\n label: \"企业微信 MCP 工具\",\n description: [\n \"通过 HTTP 直接调用企业微信 MCP Server。\",\n \"支持两种操作:\",\n \" - list: 列出指定品类的所有 MCP 工具\",\n \" - call: 调用指定品类的某个 MCP 工具\",\n \"\",\n \"使用方式:\",\n \" wecom_mcp list <category>\",\n \" wecom_mcp call <category> <method> '<jsonArgs>'\",\n \"\",\n \"示例:\",\n \" 列出 contact 品类所有工具:wecom_mcp list contact\",\n \" 调用 contact 的 getContact:wecom_mcp call contact getContact '{}'\",\n ].join(\"\\n\"),\n parameters: {\n type: \"object\" as const,\n properties: {\n action: {\n type: \"string\",\n enum: [\"list\", \"call\"],\n description: \"操作类型:list(列出工具)或 call(调用工具)\",\n },\n category: {\n type: \"string\",\n description: \"MCP 品类名称,如 doc、contact 等,对应 mcpConfig 中的 key\",\n },\n accountId: {\n type: \"string\",\n description: \"账户 ID(可选,用于多账户场景,指定使用哪个账户的 MCP 服务)\",\n },\n method: {\n type: \"string\",\n description: \"要调用的 MCP 方法名(action=call 时必填)\",\n },\n args: {\n type: [\"string\", \"object\"],\n description: \"调用 MCP 方法的参数,可以是 JSON 字符串或对象(action=call 时使用,默认 {})\",\n },\n },\n required: [\"action\", \"category\"],\n },\n async execute(_toolCallId: string, params: unknown) {\n const p = params as WeComToolsParams;\n try {\n switch (p.action) {\n case \"list\":\n return textResult(await handleList(p.category, p.accountId));\n case \"call\": {\n if (!p.method) {\n return textResult({ error: \"action 为 call 时必须提供 method 参数\" });\n }\n const args = parseArgs(p.args);\n return textResult(await handleCall(p.category, p.method, args, p.accountId));\n }\n default:\n return textResult({ error: `未知操作类型: ${String(p.action)},支持 list 和 call` });\n }\n } catch (err) {\n return errorResult(err);\n }\n },\n };\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { emptyPluginConfigSchema } from \"openclaw/plugin-sdk\";\n\nimport { wecomPlugin } from \"./src/channel.js\";\nimport { createWeComMcpTool } from \"./src/mcp\";\nimport { setWeComRuntime } from \"./src/runtime.js\";\nimport { PLUGIN_VERSION } from \"./src/version.js\";\n\nconsole.log(`[wecom] v${PLUGIN_VERSION} loaded`);\n\n// ============================================================================\n// 需要自动注入 tools.alsoAllow 的工具名列表\n// ============================================================================\n\nconst REQUIRED_ALSO_ALLOW_TOOLS = [\"wecom_mcp\"] as const;\n\n/**\n * 确保 tools.alsoAllow 中包含插件所需的工具名。\n *\n * 逻辑:\n * 1. 读取当前配置\n * 2. 检查 tools.alsoAllow 中是否已包含所需工具\n * 3. 如有缺失,合并写入配置文件\n *\n * 幂等操作——重复调用不会产生副作用。\n * 若 tools.allow 已显式设置(与 alsoAllow 互斥),则跳过注入并打印提示。\n */\nasync function ensureToolsAlsoAllow(api: OpenClawPluginApi): Promise<void> {\n try {\n const cfg = api.runtime.config.loadConfig();\n const tools = cfg.tools ?? {};\n\n // 如果用户显式配置了 tools.allow(全量白名单),则 alsoAllow 与之互斥,\n // 此时不应自动追加 alsoAllow,避免产生校验冲突\n if (tools.allow && tools.allow.length > 0) {\n const missing = REQUIRED_ALSO_ALLOW_TOOLS.filter(\n (t) => !tools.allow!.includes(t),\n );\n if (missing.length > 0) {\n console.warn(\n `[wecom] tools.allow 已显式设置,无法自动注入 alsoAllow。` +\n `请手动将 ${JSON.stringify(missing)} 加入 tools.allow。`,\n );\n }\n return;\n }\n\n const existing = tools.alsoAllow ?? [];\n const missing = REQUIRED_ALSO_ALLOW_TOOLS.filter(\n (t) => !existing.includes(t),\n );\n\n if (missing.length === 0) {\n // 所有工具已在白名单中,无需操作\n return;\n }\n\n const merged = [...existing, ...missing];\n const nextConfig = {\n ...cfg,\n tools: {\n ...tools,\n alsoAllow: merged,\n },\n };\n\n await api.runtime.config.writeConfigFile(nextConfig);\n console.log(\n `[wecom] 已自动将 ${JSON.stringify(missing)} 加入 tools.alsoAllow`,\n );\n } catch (err) {\n // 配置写入失败不应阻断 Gateway 启动\n console.error(\n `[wecom] 自动注入 tools.alsoAllow 失败:`,\n err instanceof Error ? err.message : String(err),\n );\n }\n}\n\nconst plugin = {\n id: \"wecom-openclaw-plugin\",\n name: \"企业微信\",\n description: \"企业微信 OpenClaw 插件\",\n configSchema: emptyPluginConfigSchema(),\n register(api: OpenClawPluginApi) {\n\n setWeComRuntime(api.runtime);\n api.registerChannel({ plugin: wecomPlugin });\n\n // 注册 wecom_mcp:通过 HTTP 直接调用企业微信 MCP Server\n api.registerTool(createWeComMcpTool(), { name: \"wecom_mcp\" });\n\n // ── Gateway 启动时自动确保 tools.alsoAllow 包含 wecom_mcp ──────────\n // 在 gateway_start 阶段检测并写入,保证插件安装/更新后首次启动即生效\n // api.on(\"gateway_start\", async () => {\n // await ensureToolsAlsoAllow(api);\n // });\n\n // 注入媒体发送指令和文件大小限制提示词\n api.on(\"before_prompt_build\", () => {\n return {\n appendSystemContext: [\n \"【发送文件/图片/视频/语音】\",\n \"当你需要向用户发送文件、图片、视频或语音时,必须在回复中单独一行使用 MEDIA: 指令,后面跟文件的本地路径。\",\n \"格式:MEDIA: /文件的绝对路径\",\n \"文件优先存放到 ~/.openclaw 目录下,确保路径可访问。\",\n \"示例:\",\n \" MEDIA: ~/.openclaw/output.png\",\n \" MEDIA: ~/.openclaw/report.pdf\",\n \"系统会自动识别文件类型并发送给用户。\",\n \"\",\n \"注意事项:\",\n \"- MEDIA: 必须在行首,后面紧跟文件路径(不是 URL)\",\n \"- 如果路径中包含空格,可以用反引号包裹:MEDIA: `/path/to/my file.png`\",\n \"- 每个文件单独一行 MEDIA: 指令\",\n \"- 可以在 MEDIA: 指令前后附带文字说明\",\n \"\",\n \"【文件大小限制】\",\n \"- 图片不超过 10MB,视频不超过 10MB,语音不超过 2MB(仅支持 AMR 格式),文件不超过 20MB\",\n \"- 语音消息仅支持 AMR 格式(.amr),如需发送语音请确保文件为 AMR 格式\",\n \"- 超过大小限制的图片/视频/语音会被自动转为文件格式发送\",\n \"- 如果文件超过 20MB,将无法发送,请提前告知用户并尝试缩减文件大小\",\n ].join(\"\\n\"),\n };\n });\n },\n};\n\nexport default plugin;\n"],"names":["exports","path","fs","os","fileURLToPath","resolveStateDir","generateReqId","fileTypeFromBuffer","withFileLock","readJsonFileWithFallback","writeJsonFileAtomically","WSClient","DEFAULT_ACCOUNT_ID","addWildcardAllowFrom","formatPairingApproveHint","dirname","resolve","readFileSync","emptyPluginConfigSchema"],"mappings":"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"}
|