@wecom/wecom-openclaw-plugin 2026.3.25 → 2026.3.26

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../../src/openclaw-compat.ts","../../src/runtime.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/version.ts","../../src/monitor.ts","../../src/utils.ts","../../src/onboarding.ts","../../src/channel.ts","../../src/mcp/transport.ts","../../src/mcp/schema.ts","../../src/mcp/tool.ts","../../index.ts"],"sourcesContent":["/**\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\nexport const DEFAULT_ACCOUNT_ID = \"default\";\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 addWildcardAllowFrom?: (allowFrom: string[]) => string[];\n}\n\nconst _sdkReady: Promise<SdkExports> = import(\"openclaw/plugin-sdk/core\")\n .then((sdk: any) => {\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 if (typeof sdk.addWildcardAllowFrom === \"function\") {\n exports.addWildcardAllowFrom = sdk.addWildcardAllowFrom;\n }\n return exports;\n })\n .catch(() => {\n // openclaw/plugin-sdk 不可用或版本过低,全部使用 fallback\n return {} as SdkExports;\n });\n\n// 同时尝试从 plugin-sdk/setup 模块探测(缓存同步可用的引用)\nlet _cachedAddWildcardAllowFrom: ((allowFrom: string[]) => string[]) | undefined;\n\nconst _setupSdkReady: Promise<void> = import(\"openclaw/plugin-sdk/setup\")\n .then((sdk: any) => {\n if (typeof sdk.addWildcardAllowFrom === \"function\") {\n _cachedAddWildcardAllowFrom = sdk.addWildcardAllowFrom;\n }\n })\n .catch(() => { /* plugin-sdk/setup 不可用 */ });\n\n// 同时也从 core 模块的结果中缓存\n_sdkReady.then((sdk) => {\n if (!_cachedAddWildcardAllowFrom && sdk.addWildcardAllowFrom) {\n _cachedAddWildcardAllowFrom = sdk.addWildcardAllowFrom;\n }\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// addWildcardAllowFrom —— 向 allowFrom 列表添加通配符 \"*\"\n// ============================================================================\n\n/** fallback 版 addWildcardAllowFrom:确保列表中包含 \"*\" 通配符 */\nfunction addWildcardAllowFromFallback(allowFrom: string[]): string[] {\n if (allowFrom.includes(\"*\")) {\n return allowFrom;\n }\n return [...allowFrom, \"*\"];\n}\n\n/**\n * 向 allowFrom 列表添加通配符 \"*\"(兼容入口)\n *\n * 当 dmPolicy 为 \"open\" 时,需要确保 allowFrom 中包含 \"*\" 以允许所有来源。\n * 优先使用 SDK 版本(plugin-sdk/setup 或 plugin-sdk/core),不可用时使用 fallback。\n *\n * 注意:此函数为同步函数,与 SDK 原始签名一致。\n * SDK 引用在模块加载时异步探测并缓存,调用时同步读取缓存。\n */\nexport function addWildcardAllowFrom(allowFrom: string[]): string[] {\n if (_cachedAddWildcardAllowFrom) {\n try {\n return _cachedAddWildcardAllowFrom(allowFrom);\n } catch {\n // SDK 版本异常,降级到 fallback\n }\n }\n return addWildcardAllowFromFallback(allowFrom);\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\nexport function emptyPluginConfigSchema(): Record<string, unknown> {\n return {\n type: 'object',\n additionalProperties: false,\n properties: {},\n };\n}\n\n// ============================================================================\n// 辅助函数(参考 moltbot 实现)\n// ============================================================================\n\n/**\n * 解析可选的分隔条目\n * @param value 输入字符串,支持逗号、分号、换行符分隔\n * @returns 解析后的字符串数组,如果输入为空则返回 undefined\n */\nexport function parseOptionalDelimitedEntries(value?: string): string[] | undefined {\n if (!value?.trim()) {\n return undefined;\n }\n const parsed = value\n .split(/[\\n,;]+/g)\n .map((entry) => entry.trim())\n .filter(Boolean);\n return parsed.length > 0 ? parsed : undefined;\n}\n\n/**\n * 构建账户范围的 DM 安全策略\n */\nexport function buildAccountScopedDmSecurityPolicy(params: {\n cfg: Record<string, unknown>;\n channelKey: string;\n accountId?: string | null;\n fallbackAccountId?: string | null;\n policy?: string | null;\n allowFrom?: Array<string | number> | null;\n defaultPolicy?: string;\n allowFromPathSuffix?: string;\n policyPathSuffix?: string;\n approveChannelId?: string;\n approveHint?: string;\n normalizeEntry?: (raw: string) => string;\n}): {\n policy: string;\n allowFrom: Array<string | number>;\n policyPath?: string;\n allowFromPath: string;\n approveHint: string;\n normalizeEntry?: (raw: string) => string;\n} {\n const DEFAULT_ACCOUNT_ID = \"default\";\n const resolvedAccountId = params.accountId ?? params.fallbackAccountId ?? DEFAULT_ACCOUNT_ID;\n const channelConfig = (params.cfg.channels as Record<string, unknown> | undefined)?.[\n params.channelKey\n ] as { accounts?: Record<string, unknown> } | undefined;\n const useAccountPath = Boolean(channelConfig?.accounts?.[resolvedAccountId]);\n const basePath = useAccountPath\n ? `channels.${params.channelKey}.accounts.${resolvedAccountId}.`\n : `channels.${params.channelKey}.`;\n const allowFromPath = `${basePath}${params.allowFromPathSuffix ?? \"\"}`;\n const policyPath =\n params.policyPathSuffix != null ? `${basePath}${params.policyPathSuffix}` : undefined;\n\n return {\n policy: params.policy ?? params.defaultPolicy ?? \"pairing\",\n allowFrom: params.allowFrom ?? [],\n policyPath,\n allowFromPath,\n approveHint:\n params.approveHint ?? formatPairingApproveHint(params.approveChannelId ?? params.channelKey),\n normalizeEntry: params.normalizeEntry,\n };\n}\n\n/**\n * 格式化配对审批提示信息(参考 moltbot 实现)\n * @param channelId 频道ID\n * @returns 配对审批提示字符串\n */\nexport function formatPairingApproveHint(channelId: string): string {\n const listCmd = `openclaw pairing list ${channelId}`;\n const approveCmd = `openclaw pairing approve ${channelId} <code>`;\n return `向 ${channelId} 机器人发送消息以完成配对审批(命令行:${listCmd} / ${approveCmd})`;\n}\n","import type { PluginRuntime } from \"openclaw/plugin-sdk/core\";\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 * 企业微信渠道常量定义\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 = 10;\n\n/** WebSocket 认证失败时的最大重试次数 */\nexport const WS_MAX_AUTH_FAILURE_ATTEMPTS = 5;\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// ============================================================================\n\n/** 版本检查事件名称(SDK 事件监听用) */\nexport const EVENT_ENTER_CHECK_UPDATE = \"event.enter_check_update\";\n\n/** 版本检查事件回复命令名称 */\nexport const CMD_ENTER_EVENT_REPLY = \"ww_ai_robot_enter_event\";\n\n// ============================================================================\n// SDK 连接配置\n// ============================================================================\n\n/** WSClient scene 参数:企微 OpenClaw 场景 */\nexport const SCENE_WECOM_OPENCLAW = 1;\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/runtime-env\";\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// 流式过期错误(errcode 846608)\n// ============================================================================\n\n/** 流式回复超时错误码(>6分钟未更新,服务端拒绝继续流式更新) */\nexport const STREAM_EXPIRED_ERRCODE = 846608;\n\n/**\n * 流式回复过期错误\n * 当服务端返回 errcode=846608 时抛出,表示流式消息已超过6分钟无法更新,\n * 调用方需降级为主动发送(sendMessage)方式回复。\n */\nexport class StreamExpiredError extends Error {\n readonly errcode = STREAM_EXPIRED_ERRCODE;\n constructor(message?: string) {\n super(message ?? `Stream message update expired (errcode=${STREAM_EXPIRED_ERRCODE})`);\n this.name = \"StreamExpiredError\";\n }\n}\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 try {\n await withTimeout(\n wsClient.replyStream(frame, streamId, text, finish),\n REPLY_SEND_TIMEOUT_MS,\n `Reply send timed out (streamId=${streamId})`,\n );\n } catch (err: any) {\n // 服务端返回 846608:流式消息超过6分钟无法更新,需降级为主动发送\n const errMsg = err?.errmsg || err?.message || String(err);\n if (\n err?.errcode === STREAM_EXPIRED_ERRCODE ||\n errMsg.includes(String(STREAM_EXPIRED_ERRCODE))\n ) {\n throw new StreamExpiredError(errMsg);\n }\n throw err;\n }\n runtime.log?.(`[plugin -> server] streamId=${streamId}, finish=${finish}`);\n\n return streamId;\n}\n","/**\n * 企业微信媒体(图片)下载和保存模块\n *\n * 负责下载、检测格式、保存图片到本地,包含超时保护\n */\n\nimport type { OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport type { RuntimeEnv } from \"openclaw/plugin-sdk/runtime-env\";\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 } from \"openclaw/plugin-sdk/core\";\nimport type { RuntimeEnv } from \"openclaw/plugin-sdk/runtime-env\";\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/runtime-env\";\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","// ============================================================================\n// 类型定义\n// ============================================================================\n\n/** 单条 reqId 记录 */\ninterface ReqIdEntry {\n /** 请求 ID */\n reqId: string;\n /** 记录时间戳(毫秒) */\n ts: number;\n}\n\n/** Store 配置 */\ninterface ReqIdStoreOptions {\n /** TTL 毫秒数,超时的 reqId 视为过期(默认 7 天) */\n ttlMs?: number;\n /** 内存最大条目数(默认 200) */\n memoryMaxSize?: number;\n}\n\n// ============================================================================\n// 常量\n// ============================================================================\n\nconst DEFAULT_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 天\nconst DEFAULT_MEMORY_MAX_SIZE = 200;\n\n// ============================================================================\n// 公开接口\n// ============================================================================\n\nexport interface PersistentReqIdStore {\n /** 设置 chatId 对应的 reqId(仅写入内存) */\n set(chatId: string, reqId: string): void;\n /** 获取 chatId 对应的 reqId(仅内存) */\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 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\n // 内存层:chatId → ReqIdEntry\n const memory = new Map<string, ReqIdEntry>();\n\n // ========== 内部辅助函数 ==========\n\n /** 检查条目是否过期 */\n function isExpired(entry: ReqIdEntry, now: number): boolean {\n return ttlMs > 0 && now - entry.ts >= ttlMs;\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 // ========== 公开 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 }\n\n async function get(chatId: string): Promise<string | undefined> {\n const now = Date.now();\n\n // 仅查内存\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 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 }\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 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 * \n * 注意:由于移除了磁盘存储,此函数现在只返回 0(无预热条目)\n */\nexport async function warmupReqIdStore(\n accountId = \"default\",\n log?: (...args: unknown[]) => void,\n): Promise<number> {\n // 由于移除了磁盘存储,不再需要预热过程\n log?.(\"[WeCom] reqid-store warmup: no-op (disk storage removed)\");\n return 0;\n}\n\n/**\n * 立即将 reqId 数据刷写到磁盘(用于优雅退出)\n * \n * 注意:由于移除了磁盘存储,此函数现在是无操作\n */\nexport async function flushReqIdStore(accountId = \"default\"): Promise<void> {\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 // 注意:不删除 store,因为重连后可能还需要\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\n // 清空消息状态\n clearAllMessageStates();\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 * 企业微信 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 } from \"openclaw/plugin-sdk/core\";\nimport type { RuntimeEnv } from \"openclaw/plugin-sdk/runtime-env\";\nimport { WSClient, generateReqId, WSAuthFailureError, WSReconnectExhaustedError } 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 WS_HEARTBEAT_INTERVAL_MS,\n WS_MAX_RECONNECT_ATTEMPTS,\n WS_MAX_AUTH_FAILURE_ATTEMPTS,\n EVENT_ENTER_CHECK_UPDATE,\n CMD_ENTER_EVENT_REPLY,\n SCENE_WECOM_OPENCLAW,\n} from \"./const.js\";\nimport type { WeComMonitorOptions, MessageState } from \"./interface.js\";\nimport { parseMessageContent, type MessageBody } from \"./message-parser.js\";\nimport { sendWeComReply, StreamExpiredError } 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\";\n\nimport { PLUGIN_VERSION } from \"./version.js\";\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 state?: MessageState;\n}): Promise<void> {\n const { wsClient, frame, streamId, runtime, state } = 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 if (err instanceof StreamExpiredError && state) {\n state.streamExpired = true;\n runtime.log?.(`[wecom] Stream expired during thinking reply, will fallback to proactive send`);\n } else {\n runtime.error?.(`[wecom] Failed to send thinking message: ${String(err)}`);\n }\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)}`);\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 *\n * 降级策略:\n * - 当 streamExpired=true(errcode 846608)时,流式通道已不可用(>6分钟),\n * 改用 wsClient.sendMessage 主动发送完整文本。\n */\nasync function finishThinkingStream(ctx: DeliverContext): 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 let finishText: string = state.accumulatedText;\n\n if (state.hasMedia) {\n if (state.hasMediaFailed && state.mediaErrorSummary) {\n // 媒体成功发送:用友好提示告知用户\n finishText = finishText ? `${finishText}\\n\\n${state.mediaErrorSummary}` : state.mediaErrorSummary;\n } else if (!finishText) {\n finishText = \"📎 文件已发送,请查收。\";\n }\n }\n\n // if (!finishText) {\n // finishText = \"✅ 处理完成。\";\n // }\n\n if (finishText) {\n // 尝试流式发送;若已知过期或发送时发现过期,统一降级为主动发送\n let expired = state.streamExpired;\n if (!expired) {\n try {\n await sendWeComReply({wsClient, frame, text: finishText, runtime, finish: true, streamId: state.streamId});\n } catch (err) {\n if (err instanceof StreamExpiredError) {\n expired = true;\n } else {\n throw err;\n }\n }\n }\n if (expired) {\n runtime.log?.(`[wecom] Stream expired, sending final text via sendMessage (proactive)`);\n await wsClient.sendMessage(chatId, {\n msgtype: \"markdown\",\n markdown: { content: finishText },\n });\n }\n }\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 let isShowThink = !(account.sendThinkingMessage ?? true);\n\n try {\n await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({\n ctx: ctxPayload,\n cfg: config,\n // replyResolver: async (ctx, opts) => {\n // const startTime = Date.now();\n // const TEN_MINUTES = 7 * 60 * 1000;\n //\n // console.log('开始输出内容');\n //\n // while (Date.now() - startTime < TEN_MINUTES) {\n // // 每隔一段时间发送一个 block reply\n // await opts?.onBlockReply?.({ text: `输出内容 ${new Date().toISOString()}` });\n // await new Promise(resolve => setTimeout(resolve, 30 * 1000)); // 每5秒输出一次\n // }\n //\n // return { text: \"10分钟输出完成\" }; // 最终回复\n // },\n dispatcherOptions: {\n onReplyStart: async () => {\n if (!isShowThink && state.streamId && !state.accumulatedText) {\n try {\n await sendThinkingReply({wsClient, frame, streamId: state.streamId, runtime, state})\n } catch (e) {\n runtime.error?.(`[wecom] sendThinkingReply threw err: ${String(e)}`);\n }\n isShowThink = true;\n }\n },\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 state.accumulatedText += (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 // 中间帧:有可见文本时流式更新(流式过期后跳过,等 deliver 完成后主动发送)\n if (info.kind !== \"final\" && state.accumulatedText && !state.streamExpired) {\n try {\n await sendWeComReply({ wsClient, frame, text: state.accumulatedText, runtime, finish: false, streamId: state.streamId });\n } catch (err) {\n if (err instanceof StreamExpiredError) {\n state.streamExpired = true;\n runtime.log?.(`[wecom] Stream expired during intermediate reply, will fallback to proactive send`);\n } else {\n throw err;\n }\n }\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 routeAndDispatchMessage({\n ctxPayload,\n config,\n account,\n wsClient,\n frame,\n state,\n runtime,\n onCleanup: cleanupState,\n });\n } catch (err) {\n runtime.error?.(`[wecom][plugin] Message processing failed: ${String(err)}`);\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, setStatus } = options;\n\n runtime.log?.(`[${account.accountId}] [${PLUGIN_VERSION}] 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 maxAuthFailureAttempts: WS_MAX_AUTH_FAILURE_ATTEMPTS,\n scene: SCENE_WECOM_OPENCLAW,\n plug_version: PLUGIN_VERSION,\n });\n\n // 防止 cleanup 被多次调用(abort handler、error handler、disconnected_event 可能竞态触发)\n let cleanedUp = false;\n\n // 清理函数:确保所有资源被释放(幂等)\n const cleanup = async () => {\n if (cleanedUp) return;\n cleanedUp = true;\n stopMessageStateCleanup();\n await cleanupAccount(account.accountId);\n };\n\n // 处理中止信号(框架 stopChannel 会触发 abort)\n // resolve() 让 Promise settle → 框架清理 store.tasks/store.aborts\n if (abortSignal) {\n abortSignal.addEventListener(\"abort\", async () => {\n runtime.log?.(`[${account.accountId}] Connection aborted`);\n wsClient.disconnect();\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 //\n // SDK 内部已设置 isManualClose=true 阻止 SDK 层自动重连,连接不会自行恢复。\n // **不 reject/resolve Promise**——保持 pending 以阻止框架层 auto-restart。\n //\n // 为什么不能 reject/resolve:\n // - reject → 框架 auto-restart 介入 → 新连接建立 → 又被踢 → 两个实例互踢无限循环\n // - resolve → 同上,框架 .then() 中的 auto-restart 也会触发\n //\n // Promise pending 的安全性:\n // - store.tasks.has(id) = true → 阻止 Health Monitor 直接 startChannel(startChannel 检查 tasks.has)\n // - 框架 stopChannel → abort() → abort handler 中 resolve() → tasks 正常清理\n // - 用户修改配置 → config reload → stopChannel + startChannel → 正常恢复\n //\n // 显式调用 wsClient.disconnect() 确保 SDK 内部资源(定时器、队列等)完全释放。\n wsClient.on(\"event.disconnected_event\", async () => {\n const errorMsg = `Kicked by server: a new connection was established elsewhere. Auto-restart is suppressed to avoid mutual kicking. Please check for duplicate instances.`;\n runtime.error?.(`[${account.accountId}] ${errorMsg}`);\n wsClient.disconnect();\n await cleanup();\n setStatus?.({\n accountId: account.accountId,\n running: false,\n lastError: errorMsg,\n lastStopAt: Date.now(),\n });\n // Promise 保持 pending,不触发 auto-restart\n });\n\n // 监听重连事件\n wsClient.on(\"reconnecting\", (attempt) => {\n runtime.log?.(`[${account.accountId}] Reconnecting attempt ${attempt}...`);\n });\n\n // 监听错误事件\n wsClient.on(\"error\", async (error) => {\n runtime.error?.(`[${account.accountId}] WebSocket error: ${error.message}`);\n\n if (error instanceof WSAuthFailureError) {\n // 认证失败重试次数用尽(SDK 层已重试 WS_MAX_AUTH_FAILURE_ATTEMPTS 次)。\n // 配置错误(如 botId/secret 无效),框架 auto-restart 也无法恢复。\n //\n // **不 reject/resolve Promise**——保持 pending 以阻止框架层 auto-restart。\n //\n // 为什么不能 reject/resolve:\n // - reject/resolve → 框架 auto-restart(最多 10 次)× SDK 重试(5 次)= 60 次无意义尝试\n // - 且 Health Monitor 每小时还会 resetRestartAttempts 再来一轮\n //\n // Promise pending 的安全性:同被踢下线场景\n // - store.tasks.has(id) = true → 阻止 Health Monitor 直接 startChannel\n // - 框架 stopChannel / config reload → abort handler 中 resolve() → 正常清理\n // - 用户修改配置后框架通过 reload 机制重新启动\n const errorMsg = `Auth failure attempts exhausted (${WS_MAX_AUTH_FAILURE_ATTEMPTS} attempts). Please check botId/secret configuration.`;\n runtime.error?.(`[${account.accountId}] ${errorMsg}`);\n wsClient.disconnect();\n await cleanup();\n setStatus?.({\n accountId: account.accountId,\n running: false,\n lastError: errorMsg,\n lastStopAt: Date.now(),\n });\n return;\n }\n\n if (error instanceof WSReconnectExhaustedError) {\n // 网络断线重连次数用尽(SDK 层已重试 WS_MAX_RECONNECT_ATTEMPTS 次)。\n // 通常是网络/服务端问题,框架 auto-restart 可能恢复。\n //\n // reject Promise → 框架 auto-restart 介入(最多 MAX_RESTART_ATTEMPTS=10 次)\n // 总连接尝试次数 = (1 首次 + WS_MAX_RECONNECT_ATTEMPTS 重连) × (1 首轮 + 10 auto-restart)\n // = 11 × 11 = 121 次\n //\n // 如果 Health Monitor 介入(每 5 分钟检查),会 resetRestartAttempts 重新计数,\n // 受限于 DEFAULT_MAX_RESTARTS_PER_HOUR=10,每小时最多额外 10 × 121 = 1210 次。\n // 但因网络断线通常是暂时性的,auto-restart + Health Monitor 的兜底机制是合理的。\n //\n // 显式调用 wsClient.disconnect() 确保 SDK 内部资源完全释放,\n // 避免旧实例的定时器/队列残留。\n wsClient.disconnect();\n cleanup().finally(() => reject(error));\n return;\n }\n });\n\n // 监听版本检查事件:收到 enter_check_update 时回复当前插件版本\n wsClient.on(EVENT_ENTER_CHECK_UPDATE as any, async (frame: WsFrame) => {\n try {\n // runtime.log?.(`[${account.accountId}] Received enter_check_update, replying with version=${PLUGIN_VERSION}`);\n await wsClient.reply(frame, { version: PLUGIN_VERSION }, CMD_ENTER_EVENT_REPLY);\n } catch (err) {\n // runtime.error?.(`[${account.accountId}] Failed to reply enter_check_update: ${String(err)}`);\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 type { OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport { DEFAULT_ACCOUNT_ID } from \"./openclaw-compat.js\";\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 WeComConfig {\n enabled?: boolean;\n websocketUrl?: string;\n botId?: string;\n secret?: string;\n name?: string;\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 * 解析企业微信账户配置\n */\nexport function resolveWeComAccount(cfg: OpenClawConfig): ResolvedWeComAccount {\n const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {}) as WeComConfig;\n\n return {\n accountId: DEFAULT_ACCOUNT_ID,\n name: wecomConfig.name ?? \"企业微信\",\n enabled: wecomConfig.enabled ?? false,\n websocketUrl: wecomConfig.websocketUrl || DefaultWsUrl,\n botId: wecomConfig.botId ?? \"\",\n secret: wecomConfig.secret ?? \"\",\n sendThinkingMessage: wecomConfig.sendThinkingMessage ?? true,\n config: wecomConfig,\n };\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\nreturn {\n ...cfg,\n channels: {\n ...cfg.channels,\n [CHANNEL_ID]: merged,\n },\n };\n}\n","/**\n * 企业微信 setupWizard — 声明式 CLI setup wizard 配置。\n *\n * 框架通过 plugin.setupWizard 字段识别并驱动 channel 的引导配置流程。\n */\n\nimport type { ChannelSetupWizard, ChannelSetupDmPolicy } from \"openclaw/plugin-sdk/setup\";\nimport type { ChannelSetupAdapter } from \"openclaw/plugin-sdk/setup\";\nimport type { OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport { addWildcardAllowFrom } from \"./openclaw-compat.js\";\nimport type { WeComConfig } from \"./utils.js\";\nimport { resolveWeComAccount, setWeComAccount } from \"./utils.js\";\nimport { CHANNEL_ID } from \"./const.js\";\n\n// ============================================================================\n// ChannelSetupAdapter — 框架用于应用配置输入的适配器\n// ============================================================================\n\nexport const wecomSetupAdapter: ChannelSetupAdapter = {\n applyAccountConfig: ({ cfg, input }) => {\n const patch: Partial<WeComConfig> = {};\n\n if (input.token !== undefined) {\n patch.botId = String(input.token).trim();\n }\n if (input.privateKey !== undefined) {\n patch.secret = String(input.privateKey).trim();\n }\n\n // 如果是首次配置,默认启用\n const account = resolveWeComAccount(cfg);\n if (!account.botId && !account.secret) {\n patch.enabled = true;\n }\n\n return setWeComAccount(cfg, patch);\n },\n};\n\n// ============================================================================\n// DM Policy 配置\n// ============================================================================\n\n/**\n * 设置企业微信 dmPolicy\n */\nfunction setWeComDmPolicy(\n cfg: OpenClawConfig,\n dmPolicy: \"pairing\" | \"allowlist\" | \"open\" | \"disabled\",\n): OpenClawConfig {\n const account = resolveWeComAccount(cfg);\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 setWeComAccount(cfg, {\n dmPolicy,\n allowFrom,\n });\n}\n\nconst dmPolicy: ChannelSetupDmPolicy = {\n label: \"企业微信\",\n channel: CHANNEL_ID,\n policyKey: `channels.${CHANNEL_ID}.dmPolicy`,\n allowFromKey: `channels.${CHANNEL_ID}.allowFrom`,\n getCurrent: (cfg) => {\n const account = resolveWeComAccount(cfg);\n return account.config.dmPolicy ?? \"open\";\n },\n setPolicy: (cfg, policy) => {\n return setWeComDmPolicy(cfg, policy);\n },\n promptAllowFrom: async ({ cfg, prompter }) => {\n const account = resolveWeComAccount(cfg);\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 setWeComAccount(cfg, { allowFrom });\n },\n};\n\n// ============================================================================\n// ChannelSetupWizard — 声明式 setup wizard 配置\n// ============================================================================\n\nexport const wecomSetupWizard: ChannelSetupWizard = {\n channel: CHANNEL_ID,\n\n // ── 状态 ──────────────────────────────────────────────────────────────\n status: {\n configuredLabel: \"已配置 ✓\",\n unconfiguredLabel: \"需要 Bot ID 和 Secret\",\n configuredHint: \"已配置\",\n unconfiguredHint: \"需要设置\",\n resolveConfigured: ({ cfg }) => {\n const account = resolveWeComAccount(cfg);\n return Boolean(account.botId?.trim() && account.secret?.trim());\n },\n resolveStatusLines: ({ cfg, configured }) => {\n return [`企业微信: ${configured ? \"已配置\" : \"需要 Bot ID 和 Secret\"}`];\n },\n },\n\n // ── 引导说明 ──────────────────────────────────────────────────────────\n introNote: {\n title: \"企业微信设置\",\n lines: [\n \"企业微信机器人需要以下配置信息:\",\n \"1. Bot ID: 企业微信机器人 ID\",\n \"2. Secret: 企业微信机器人密钥\",\n ],\n shouldShow: ({ cfg }) => {\n const account = resolveWeComAccount(cfg);\n return !account.botId?.trim() || !account.secret?.trim();\n },\n },\n\n // ── 凭据输入 ──────────────────────────────────────────────────────────\n credentials: [\n {\n inputKey: \"token\",\n providerHint: \"企业微信\",\n credentialLabel: \"Bot ID\",\n envPrompt: \"使用环境变量中的 Bot ID?\",\n keepPrompt: \"Bot ID 已配置,保留当前值?\",\n inputPrompt: \"企业微信机器人 Bot ID\",\n inspect: ({ cfg }) => {\n const account = resolveWeComAccount(cfg);\n const hasValue = Boolean(account.botId?.trim());\n return {\n accountConfigured: hasValue,\n hasConfiguredValue: hasValue,\n resolvedValue: account.botId || undefined,\n };\n },\n applySet: ({ cfg, resolvedValue }) => {\n return setWeComAccount(cfg, { botId: resolvedValue });\n },\n },\n {\n inputKey: \"privateKey\",\n providerHint: \"企业微信\",\n credentialLabel: \"Secret\",\n envPrompt: \"使用环境变量中的 Secret?\",\n keepPrompt: \"Secret 已配置,保留当前值?\",\n inputPrompt: \"企业微信机器人 Secret\",\n inspect: ({ cfg }) => {\n const account = resolveWeComAccount(cfg);\n const hasValue = Boolean(account.secret?.trim());\n return {\n accountConfigured: hasValue,\n hasConfiguredValue: hasValue,\n resolvedValue: account.secret || undefined,\n };\n },\n applySet: ({ cfg, resolvedValue }) => {\n return setWeComAccount(cfg, { secret: resolvedValue });\n },\n },\n ],\n\n // ── 完成后的最终处理 ──────────────────────────────────────────────────\n finalize: async ({ cfg }) => {\n // 确保配置完成后 channel 处于启用状态\n const account = resolveWeComAccount(cfg);\n if (account.botId?.trim() && account.secret?.trim() && !account.enabled) {\n return { cfg: setWeComAccount(cfg, { enabled: true }) };\n }\n return undefined;\n },\n\n // ── 完成提示 ──────────────────────────────────────────────────────────\n completionNote: {\n title: \"企业微信配置完成\",\n lines: [\n \"企业微信机器人已配置完成。\",\n \"运行 `openclaw start` 启动服务。\",\n ],\n shouldShow: ({ cfg }) => {\n const account = resolveWeComAccount(cfg);\n return Boolean(account.botId?.trim() && account.secret?.trim());\n },\n },\n\n // ── DM 策略 ──────────────────────────────────────────────────────────\n dmPolicy,\n\n // ── 禁用 ─────────────────────────────────────────────────────────────\n disable: (cfg) => {\n return setWeComAccount(cfg, { enabled: false });\n },\n};\n","import {\n type ChannelPlugin,\n type OpenClawConfig,\n} from \"openclaw/plugin-sdk/core\";\nimport type { ChannelStatusIssue } from \"openclaw/plugin-sdk/channel-contract\";\n\nimport { formatPairingApproveHint, DEFAULT_ACCOUNT_ID } from './openclaw-compat.js'\nimport { getWeComRuntime } from \"./runtime.js\";\nimport { monitorWeComProvider } from \"./monitor.js\";\nimport { getWeComWebSocket } from \"./state-manager.js\";\nimport { wecomSetupWizard, wecomSetupAdapter } from \"./onboarding.js\";\nimport type { WeComConfig, ResolvedWeComAccount } from \"./utils.js\";\nimport { resolveWeComAccount } 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 setupWizard: wecomSetupWizard,\n setup: wecomSetupAdapter,\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: () => [DEFAULT_ACCOUNT_ID],\n\n // 解析账户配置\n resolveAccount: (cfg) => resolveWeComAccount(cfg),\n\n // 获取默认账户 ID\n defaultAccountId: () => DEFAULT_ACCOUNT_ID,\n\n // 设置账户启用状态\n setAccountEnabled: ({cfg, enabled}) => {\n const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {}) as WeComConfig;\n return {\n ...cfg,\n channels: {\n ...cfg.channels,\n [CHANNEL_ID]: {\n ...wecomConfig,\n enabled,\n },\n },\n };\n },\n\n // 删除账户\n deleteAccount: ({cfg}) => {\n const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {}) as WeComConfig;\n const {botId, secret, ...rest} = wecomConfig;\n return {\n ...cfg,\n channels: {\n ...cfg.channels,\n [CHANNEL_ID]: rest,\n },\n };\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}) => {\n const account = resolveWeComAccount(cfg);\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 // 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 // const { groupPolicy } = resolveOpenProviderRuntimeGroupPolicy({\n // providerConfigPresent: true,\n // groupPolicy: account.config.groupPolicy,\n // defaultGroupPolicy,\n // });\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 --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,\n name: account.name,\n enabled: account.enabled,\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 setStatus: ctx.setStatus,\n });\n },\n logoutAccount: async ({cfg}) => {\n const nextCfg = {...cfg} as OpenClawConfig;\n const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {}) as WeComConfig;\n const nextWecom = {...wecomConfig};\n let cleared = false;\n let changed = false;\n\n if (nextWecom.botId || nextWecom.secret) {\n delete nextWecom.botId;\n delete nextWecom.secret;\n cleared = true;\n changed = true;\n }\n\n if (changed) {\n if (Object.keys(nextWecom).length > 0) {\n nextCfg.channels = {...nextCfg.channels, [CHANNEL_ID]: nextWecom};\n } else {\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 }\n await getWeComRuntime().config.writeConfigFile(nextCfg);\n }\n\n const resolved = resolveWeComAccount(changed ? nextCfg : cfg);\n const loggedOut = !resolved.botId && !resolved.secret;\n\n return {cleared, envToken: false, loggedOut};\n },\n },\n};\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-compat.js\";\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/** 媒体下载请求超时时间(毫秒),base64 编码的媒体文件最大可达 ~27MB */\nexport const MEDIA_DOWNLOAD_TIMEOUT_MS = 120_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 * @returns 完整的 response.body 配置对象(至少包含 url 字段)\n */\nasync function fetchMcpConfig(category: string): Promise<Record<string, unknown>> {\n const wsClient = getWeComWebSocket(DEFAULT_ACCOUNT_ID);\n if (!wsClient) {\n throw new Error(\"WSClient 未连接,无法拉取 MCP 配置\");\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}\")`);\n return body as Record<string, unknown>;\n}\n\n/**\n * 获取指定品类的 MCP Server URL\n *\n * 优先从内存缓存中读取,未命中时通过 WSClient 拉取并缓存。\n *\n * @param category - MCP 品类名称\n * @returns MCP Server URL\n */\nasync function getMcpUrl(category: string): Promise<string> {\n // 查内存缓存\n const cached = mcpConfigCache.get(category);\n if (cached) return cached.url as string;\n\n // 缓存未命中,通过 WSClient 拉取\n const body = await fetchMcpConfig(category);\n\n // 写入缓存\n mcpConfigCache.set(category, body);\n\n console.log(`${LOG_TAG} getMcpUrl ${category}: ${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 timeoutMs: number = HTTP_REQUEST_TIMEOUT_MS,\n): Promise<{ response: Response; rpcResult: unknown; newSessionId: string | null }> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\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 请求超时 (${timeoutMs}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, category: string): Promise<McpSession> {\n const session: McpSession = { sessionId: null, initialized: false, stateless: false };\n\n console.log(`${LOG_TAG} 开始 initialize 握手 (category=\"${category}\")`);\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(category);\n mcpSessionCache.set(category, session);\n console.log(`${LOG_TAG} 无状态 Server 确认 (category=\"${category}\")`);\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(category, session);\n console.log(`${LOG_TAG} 有状态 Session 建立成功 (category=\"${category}\", 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, category: string): Promise<McpSession> {\n // 已确认为无状态的 Server,直接返回空 session 跳过握手\n if (statelessCategories.has(category)) {\n const cached = mcpSessionCache.get(category);\n if (cached) return cached;\n // 首次发现被清除(理论上不会走到这里),重新走握手探测\n }\n\n const cached = mcpSessionCache.get(category);\n if (cached?.initialized) return cached;\n\n // 防止并发重复初始化\n const inflight = inflightInitRequests.get(category);\n if (inflight) return inflight;\n\n const promise = initializeSession(url, category).finally(() => {\n inflightInitRequests.delete(category);\n });\n inflightInitRequests.set(category, 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 */\nexport function clearCategoryCache(category: string): void {\n console.log(`${LOG_TAG} 清理缓存 (category=\"${category}\")`);\n mcpConfigCache.delete(category);\n mcpSessionCache.delete(category);\n statelessCategories.delete(category);\n inflightInitRequests.delete(category);\n}\n\n/** tools/list 返回的工具描述 */\nexport interface McpToolInfo {\n name: string;\n description?: string;\n inputSchema?: Record<string, unknown>;\n}\n\n/** sendJsonRpc 的可选配置 */\nexport interface SendJsonRpcOptions {\n /** 自定义 HTTP 请求超时时间(毫秒),默认使用 HTTP_REQUEST_TIMEOUT_MS */\n timeoutMs?: number;\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 options - 可选配置(如自定义超时)\n * @returns JSON-RPC result\n */\nexport async function sendJsonRpc(\n category: string,\n method: string,\n params?: Record<string, unknown>,\n options?: SendJsonRpcOptions,\n): Promise<unknown> {\n const url = await getMcpUrl(category);\n const timeoutMs = options?.timeoutMs;\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, category);\n\n try {\n const { rpcResult, newSessionId } = await sendRawJsonRpc(url, session, body, timeoutMs);\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);\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}\"),开始重建...`);\n mcpSessionCache.delete(category);\n\n // 使用 rebuildSession 合并并发的 session 重建请求,避免竞态条件\n session = await rebuildSession(url, category);\n const { rpcResult, newSessionId } = await sendRawJsonRpc(url, session, body, timeoutMs);\n if (newSessionId) {\n session.sessionId = newSessionId;\n }\n return rpcResult;\n }\n\n // 其他错误记录日志后抛出\n console.error(`${LOG_TAG} RPC 请求失败 (category=\"${category}\", 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, category: string): Promise<McpSession> {\n const inflight = inflightInitRequests.get(category);\n if (inflight) return inflight;\n\n const promise = initializeSession(url, category).finally(() => {\n inflightInitRequests.delete(category);\n });\n inflightInitRequests.set(category, 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 * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { sendJsonRpc, clearCategoryCache, MEDIA_DOWNLOAD_TIMEOUT_MS, type McpToolInfo } from \"./transport.js\";\nimport { cleanSchemaForGemini } from \"./schema.js\";\nimport { getWeComRuntime } from \"../runtime.js\";\nimport { detectMime } from \"../openclaw-compat.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 /** 调用的 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): Promise<unknown> => {\n const result = await sendJsonRpc(category, \"tools/list\") 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 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): 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}\"),清理缓存`);\n clearCategoryCache(category);\n return;\n }\n } catch {\n // text 不是 JSON 格式,跳过\n }\n }\n};\n\n// ============================================================================\n// get_msg_media 响应拦截:base64 → 本地文件\n// ============================================================================\n\n/**\n * 拦截 get_msg_media 的 MCP 响应\n *\n * 核心逻辑:\n * 1. 从 MCP result 的 content[].text 中提取业务 JSON\n * 2. 提取 media_item.base64_data,解码为 Buffer\n * 3. 通过 openclaw SDK 的 saveMediaBuffer 保存到本地媒体目录\n * 4. 替换响应:移除 base64_data,加入 local_path\n *\n * 这样大模型只看到轻量的文件路径信息,不会被 base64 数据消耗 token。\n */\nasync function interceptMediaResponse(result: unknown): Promise<unknown> {\n const t0 = performance.now();\n\n // 1. 提取 MCP result 中的 content 数组\n const content = (result as Record<string, unknown>)?.content;\n if (!Array.isArray(content)) return result;\n\n const textItem = content.find(\n (c: Record<string, unknown>) => c.type === \"text\" && typeof c.text === \"string\",\n ) as { type: string; text: string } | undefined;\n if (!textItem) return result;\n\n // 2. 解析业务 JSON\n let bizData: Record<string, unknown>;\n try {\n bizData = JSON.parse(textItem.text) as Record<string, unknown>;\n } catch {\n // 非 JSON 格式,原样返回\n return result;\n }\n\n // 3. 校验业务响应:errcode !== 0 或无 media_item 时原样返回\n if (bizData.errcode !== 0) return result;\n\n const mediaItem = bizData.media_item as Record<string, unknown> | undefined;\n if (!mediaItem || typeof mediaItem.base64_data !== \"string\") return result;\n\n const base64Data = mediaItem.base64_data as string;\n const mediaName = mediaItem.name as string | undefined;\n const mediaType = mediaItem.type as string | undefined;\n const mediaId = mediaItem.media_id as string | undefined;\n\n const tParsed = performance.now();\n\n // 4. 解码 base64 → Buffer\n const buffer = Buffer.from(base64Data, \"base64\");\n const tDecoded = performance.now();\n\n // 5. 检测 contentType,并通过 saveMediaBuffer 保存到本地媒体目录\n const contentType = await detectMime({ buffer, filePath: mediaName }) ?? \"application/octet-stream\";\n const tMimeDetected = performance.now();\n\n // 企业微信聊天记录附件可达 20MB(文件消息上限),\n // 而 saveMediaBuffer 默认 maxBytes 为 5MB(针对 outbound 场景),\n // 此处显式放宽到 20MB 以支持大文件下载。\n const INBOUND_MAX_BYTES = 20 * 1024 * 1024; // 20MB\n\n const core = getWeComRuntime();\n const saved = await core.channel.media.saveMediaBuffer(\n buffer,\n contentType,\n \"inbound\",\n INBOUND_MAX_BYTES, // maxBytes: 放宽到 20MB,匹配企业微信文件消息上限\n mediaName, // originalFilename: 保留原始文件名\n );\n\n // 5.1 补偿:核心库 EXT_BY_MIME 可能缺少某些格式映射(如 audio/amr),\n // 导致保存的文件没有后缀。此处检测并修复。\n const MIME_EXT_PATCH: Record<string, string> = {\n \"audio/amr\": \".amr\",\n };\n const patchExt = MIME_EXT_PATCH[contentType];\n if (patchExt && !path.extname(saved.path)) {\n const newPath = saved.path + patchExt;\n try {\n await fs.rename(saved.path, newPath);\n saved.path = newPath;\n } catch {\n // rename 失败不影响主流程,文件仍可用\n }\n }\n\n const tSaved = performance.now();\n\n // 6. 构造精简响应,移除 base64_data,加入本地路径\n const newBizData = {\n errcode: 0,\n errmsg: \"ok\",\n media_item: {\n media_id: mediaId,\n name: mediaName ?? saved.path.split(\"/\").pop(),\n type: mediaType,\n local_path: saved.path,\n size: buffer.length,\n content_type: saved.contentType,\n },\n };\n\n const tEnd = performance.now();\n\n // 耗时日志:各环节耗时(ms)\n console.log(\n `[mcp] get_msg_media 拦截成功: media_id=${mediaId ?? \"unknown\"}, ` +\n `type=${mediaType ?? \"unknown\"}, size=${buffer.length}, saved=${saved.path}\\n` +\n ` ⏱ 耗时明细 (总 ${(tEnd - t0).toFixed(1)}ms):\\n` +\n ` 解析响应 JSON: ${(tParsed - t0).toFixed(1)}ms\\n` +\n ` base64 解码: ${(tDecoded - tParsed).toFixed(1)}ms (${(base64Data.length / 1024).toFixed(0)}KB base64 → ${(buffer.length / 1024).toFixed(0)}KB buffer)\\n` +\n ` MIME 检测: ${(tMimeDetected - tDecoded).toFixed(1)}ms (${contentType})\\n` +\n ` saveMediaBuffer: ${(tSaved - tMimeDetected).toFixed(1)}ms\\n` +\n ` 构造响应: ${(tEnd - tSaved).toFixed(1)}ms`,\n );\n\n // 7. 返回修改后的 MCP result 结构\n return {\n content: [{\n type: \"text\" as const,\n text: JSON.stringify(newBizData),\n }],\n };\n}\n\n// ============================================================================\n// call 操作:调用某品类的某个 MCP 工具\n// ============================================================================\n\nconst handleCall = async (\n category: string,\n method: string,\n args: Record<string, unknown>,\n): Promise<unknown> => {\n const callStart = performance.now();\n\n // get_msg_media 使用延长的超时时间(120s),因为返回的 base64 数据可达 ~27MB\n const options = method === \"get_msg_media\" ? { timeoutMs: MEDIA_DOWNLOAD_TIMEOUT_MS } : undefined;\n\n const result = await sendJsonRpc(category, \"tools/call\", {\n name: method,\n arguments: args,\n }, options);\n\n const rpcDone = performance.now();\n const rpcMs = (rpcDone - callStart).toFixed(1);\n\n // 检查业务层错误码,必要时清理缓存\n checkBizErrorAndClearCache(result, category);\n\n // 对 get_msg_media 响应进行 base64 拦截:解码存本地,只返回路径给大模型\n if (method === \"get_msg_media\") {\n const intercepted = await interceptMediaResponse(result);\n const totalMs = (performance.now() - callStart).toFixed(1);\n console.log(\n `[mcp] handleCall ${category}/${method} 总耗时: ${totalMs}ms` +\n ` (MCP请求: ${rpcMs}ms, 拦截处理: ${(performance.now() - rpcDone).toFixed(1)}ms)`,\n );\n return intercepted;\n }\n\n console.log(`[mcp] handleCall ${category}/${method} 耗时: ${rpcMs}ms`);\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 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));\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));\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/core\";\nimport { emptyPluginConfigSchema } from \"./src/openclaw-compat.js\";\nimport { wecomPlugin } from \"./src/channel.js\";\nimport { createWeComMcpTool } from \"./src/mcp\";\nimport { setWeComRuntime } from \"./src/runtime.js\";\nimport { CHANNEL_ID } from \"./src/const.js\";\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 // 注入媒体发送指令和文件大小限制提示词(仅对企业微信 channel 生效)\n api.on(\"before_prompt_build\", (_event, ctx) => {\n // 只在企业微信 channel 的会话中注入,避免影响其他 channel 插件\n if (ctx?.channelId !== CHANNEL_ID) {\n return;\n }\n return {\n appendSystemContext: [\n \"重要:涉及发送图片/视频/语音/文件给用户时,请务必使用 `MEDIA:` 指令。详见 wecom-send-media 这个 skill(技能)。\"\n ].join(\"\\n\"),\n };\n });\n },\n};\n\nexport default plugin;\n"],"names":["exports","path","fs","os","fileURLToPath","resolveStateDir","generateReqId","fileTypeFromBuffer","dirname","resolve","readFileSync","WSClient","WSAuthFailureError","WSReconnectExhaustedError"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../../src/openclaw-compat.ts","../../src/runtime.ts","../../src/const.ts","../../src/message-parser.ts","../../src/timeout.ts","../../src/message-sender.ts","../../src/media-handler.ts","../../src/media-uploader.ts","../../src/template-card-parser.ts","../../src/group-policy.ts","../../src/dm-policy.ts","../../src/reqid-store.ts","../../src/state-manager.ts","../../src/version.ts","../../src/monitor.ts","../../src/utils.ts","../../src/onboarding.ts","../../src/channel.ts","../../src/mcp/transport.ts","../../src/mcp/schema.ts","../../src/mcp/tool.ts","../../index.ts"],"sourcesContent":["/**\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\nexport const DEFAULT_ACCOUNT_ID = \"default\";\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 addWildcardAllowFrom?: (allowFrom: string[]) => string[];\n}\n\nconst _sdkReady: Promise<SdkExports> = import(\"openclaw/plugin-sdk/core\")\n .then((sdk: any) => {\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 if (typeof sdk.addWildcardAllowFrom === \"function\") {\n exports.addWildcardAllowFrom = sdk.addWildcardAllowFrom;\n }\n return exports;\n })\n .catch(() => {\n // openclaw/plugin-sdk 不可用或版本过低,全部使用 fallback\n return {} as SdkExports;\n });\n\n// 同时尝试从 plugin-sdk/setup 模块探测(缓存同步可用的引用)\nlet _cachedAddWildcardAllowFrom: ((allowFrom: string[]) => string[]) | undefined;\n\nconst _setupSdkReady: Promise<void> = import(\"openclaw/plugin-sdk/setup\")\n .then((sdk: any) => {\n if (typeof sdk.addWildcardAllowFrom === \"function\") {\n _cachedAddWildcardAllowFrom = sdk.addWildcardAllowFrom;\n }\n })\n .catch(() => { /* plugin-sdk/setup 不可用 */ });\n\n// 同时也从 core 模块的结果中缓存\n_sdkReady.then((sdk) => {\n if (!_cachedAddWildcardAllowFrom && sdk.addWildcardAllowFrom) {\n _cachedAddWildcardAllowFrom = sdk.addWildcardAllowFrom;\n }\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// addWildcardAllowFrom —— 向 allowFrom 列表添加通配符 \"*\"\n// ============================================================================\n\n/** fallback 版 addWildcardAllowFrom:确保列表中包含 \"*\" 通配符 */\nfunction addWildcardAllowFromFallback(allowFrom: string[]): string[] {\n if (allowFrom.includes(\"*\")) {\n return allowFrom;\n }\n return [...allowFrom, \"*\"];\n}\n\n/**\n * 向 allowFrom 列表添加通配符 \"*\"(兼容入口)\n *\n * 当 dmPolicy 为 \"open\" 时,需要确保 allowFrom 中包含 \"*\" 以允许所有来源。\n * 优先使用 SDK 版本(plugin-sdk/setup 或 plugin-sdk/core),不可用时使用 fallback。\n *\n * 注意:此函数为同步函数,与 SDK 原始签名一致。\n * SDK 引用在模块加载时异步探测并缓存,调用时同步读取缓存。\n */\nexport function addWildcardAllowFrom(allowFrom: string[]): string[] {\n if (_cachedAddWildcardAllowFrom) {\n try {\n return _cachedAddWildcardAllowFrom(allowFrom);\n } catch {\n // SDK 版本异常,降级到 fallback\n }\n }\n return addWildcardAllowFromFallback(allowFrom);\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\nexport function emptyPluginConfigSchema(): Record<string, unknown> {\n return {\n type: 'object',\n additionalProperties: false,\n properties: {},\n };\n}\n\n// ============================================================================\n// 辅助函数(参考 moltbot 实现)\n// ============================================================================\n\n/**\n * 解析可选的分隔条目\n * @param value 输入字符串,支持逗号、分号、换行符分隔\n * @returns 解析后的字符串数组,如果输入为空则返回 undefined\n */\nexport function parseOptionalDelimitedEntries(value?: string): string[] | undefined {\n if (!value?.trim()) {\n return undefined;\n }\n const parsed = value\n .split(/[\\n,;]+/g)\n .map((entry) => entry.trim())\n .filter(Boolean);\n return parsed.length > 0 ? parsed : undefined;\n}\n\n/**\n * 构建账户范围的 DM 安全策略\n */\nexport function buildAccountScopedDmSecurityPolicy(params: {\n cfg: Record<string, unknown>;\n channelKey: string;\n accountId?: string | null;\n fallbackAccountId?: string | null;\n policy?: string | null;\n allowFrom?: Array<string | number> | null;\n defaultPolicy?: string;\n allowFromPathSuffix?: string;\n policyPathSuffix?: string;\n approveChannelId?: string;\n approveHint?: string;\n normalizeEntry?: (raw: string) => string;\n}): {\n policy: string;\n allowFrom: Array<string | number>;\n policyPath?: string;\n allowFromPath: string;\n approveHint: string;\n normalizeEntry?: (raw: string) => string;\n} {\n const DEFAULT_ACCOUNT_ID = \"default\";\n const resolvedAccountId = params.accountId ?? params.fallbackAccountId ?? DEFAULT_ACCOUNT_ID;\n const channelConfig = (params.cfg.channels as Record<string, unknown> | undefined)?.[\n params.channelKey\n ] as { accounts?: Record<string, unknown> } | undefined;\n const useAccountPath = Boolean(channelConfig?.accounts?.[resolvedAccountId]);\n const basePath = useAccountPath\n ? `channels.${params.channelKey}.accounts.${resolvedAccountId}.`\n : `channels.${params.channelKey}.`;\n const allowFromPath = `${basePath}${params.allowFromPathSuffix ?? \"\"}`;\n const policyPath =\n params.policyPathSuffix != null ? `${basePath}${params.policyPathSuffix}` : undefined;\n\n return {\n policy: params.policy ?? params.defaultPolicy ?? \"pairing\",\n allowFrom: params.allowFrom ?? [],\n policyPath,\n allowFromPath,\n approveHint:\n params.approveHint ?? formatPairingApproveHint(params.approveChannelId ?? params.channelKey),\n normalizeEntry: params.normalizeEntry,\n };\n}\n\n/**\n * 格式化配对审批提示信息(参考 moltbot 实现)\n * @param channelId 频道ID\n * @returns 配对审批提示字符串\n */\nexport function formatPairingApproveHint(channelId: string): string {\n const listCmd = `openclaw pairing list ${channelId}`;\n const approveCmd = `openclaw pairing approve ${channelId} <code>`;\n return `向 ${channelId} 机器人发送消息以完成配对审批(命令行:${listCmd} / ${approveCmd})`;\n}\n","import type { PluginRuntime } from \"openclaw/plugin-sdk/core\";\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 * 企业微信渠道常量定义\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 = 10;\n\n/** WebSocket 认证失败时的最大重试次数 */\nexport const WS_MAX_AUTH_FAILURE_ATTEMPTS = 5;\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// ============================================================================\n\n/** 版本检查事件名称(SDK 事件监听用) */\nexport const EVENT_ENTER_CHECK_UPDATE = \"event.enter_check_update\";\n\n/** 版本检查事件回复命令名称 */\nexport const CMD_ENTER_EVENT_REPLY = \"ww_ai_robot_enter_event\";\n\n// ============================================================================\n// SDK 连接配置\n// ============================================================================\n\n/** WSClient scene 参数:企微 OpenClaw 场景 */\nexport const SCENE_WECOM_OPENCLAW = 1;\n\n// ============================================================================\n// 模板卡片配置\n// ============================================================================\n\n/** 合法的模板卡片 card_type 列表 */\nexport const VALID_CARD_TYPES: string[] = [\n \"text_notice\",\n \"news_notice\",\n \"button_interaction\",\n \"vote_interaction\",\n \"multiple_interaction\",\n];\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 corpid?: string;\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 event?: {\n eventtype?: string;\n template_card_event?: {\n card_type?: string;\n event_key?: string;\n task_id?: string;\n selected_items?: {\n selected_item?: Array<{\n question_key?: string;\n option_ids?: {\n option_id?: string[];\n };\n }>;\n };\n };\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 *\n * 这样后续 Agent 可以直接从 question_key / option_id 中理解用户的真实选择。\n */\nfunction buildTemplateCardEventText(body: MessageBody): string | undefined {\n const templateCardEvent = body.event?.template_card_event;\n if (\n body.msgtype !== \"event\" ||\n body.event?.eventtype !== \"template_card_event\" ||\n !templateCardEvent\n ) {\n return undefined;\n }\n\n const selectedItems = templateCardEvent.selected_items?.selected_item ?? [];\n const selectedLines = selectedItems.map((item) => {\n const questionKey = item.question_key?.trim() || \"unknown_question\";\n const optionIds = item.option_ids?.option_id?.filter(Boolean) ?? [];\n return `- ${questionKey}: ${optionIds.length > 0 ? optionIds.join(\", \") : \"(未选择)\"}`;\n });\n\n const senderUserId = body.from?.userid || \"\";\n const senderCorpId = body.from?.corpid || \"\";\n const chatId = body.chatid || senderUserId;\n\n return [\n \"[企业微信模板卡片回调]\",\n `event_type(事件类型): template_card_event`,\n body.msgid ? `msgid(消息 id): ${body.msgid}` : undefined,\n body.aibotid ? `aibotid(机器人 id): ${body.aibotid}` : undefined,\n body.chattype ? `chat_type(会话类型): ${body.chattype}` : undefined,\n chatId ? `chat_id(会话 id): ${chatId}` : undefined,\n senderCorpId ? `from.corpid(企业 id): ${senderCorpId}` : undefined,\n senderUserId ? `from.userid(发送人 id): ${senderUserId}` : undefined,\n senderUserId ? `sender_userid(发送人 id): ${senderUserId}` : undefined,\n templateCardEvent.card_type ? `card_type(卡片类型): ${templateCardEvent.card_type}` : undefined,\n templateCardEvent.event_key ? `event_key(事件 key): ${templateCardEvent.event_key}` : undefined,\n templateCardEvent.task_id ? `task_id(任务 id): ${templateCardEvent.task_id}` : undefined,\n selectedLines.length > 0 ? \"selected_items(选择项):\" : \"selected_items(选择项): []\",\n ...selectedLines,\n ]\n .filter((line): line is string => Boolean(line))\n .join(\"\\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 \n if (body.msgtype === \"event\") {\n const eventText = buildTemplateCardEventText(body);\n if (eventText) {\n textParts.push(eventText);\n }\n return { textParts, imageUrls, imageAesKeys, fileUrls, fileAesKeys, quoteContent };\n }\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/runtime-env\";\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// 流式过期错误(errcode 846608)\n// ============================================================================\n\n/** 流式回复超时错误码(>6分钟未更新,服务端拒绝继续流式更新) */\nexport const STREAM_EXPIRED_ERRCODE = 846608;\n\n/**\n * 流式回复过期错误\n * 当服务端返回 errcode=846608 时抛出,表示流式消息已超过6分钟无法更新,\n * 调用方需降级为主动发送(sendMessage)方式回复。\n */\nexport class StreamExpiredError extends Error {\n readonly errcode = STREAM_EXPIRED_ERRCODE;\n constructor(message?: string) {\n super(message ?? `Stream message update expired (errcode=${STREAM_EXPIRED_ERRCODE})`);\n this.name = \"StreamExpiredError\";\n }\n}\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 const body = frame.body as {\n msgtype?: string;\n chatid?: string;\n from?: {\n userid?: string;\n };\n };\n\n // 事件回调(aibot_event_callback)没有可用于 replyStream 的有效 req_id,\n // 对该场景改用主动发送 sendMessage,避免 846605 invalid req_id。\n if (body.msgtype === \"event\") {\n // 中间帧(thinking / 流式增量)直接跳过,仅在最终帧主动发一次文本。\n if (!finish) {\n runtime.log?.(`[plugin -> server] skip non-final stream for event callback, streamId=${streamId}`);\n return streamId;\n }\n\n const chatId = body.chatid || body.from?.userid;\n if (!chatId) {\n throw new Error(\"Missing chatId for event callback reply\");\n }\n\n await withTimeout(\n wsClient.sendMessage(chatId, {\n msgtype: \"markdown\",\n markdown: { content: text },\n }),\n REPLY_SEND_TIMEOUT_MS,\n `Event reply send timed out (streamId=${streamId})`,\n );\n runtime.log?.(`[plugin -> server] event-active-send chatId=${chatId}, finish=${finish}`);\n return streamId;\n }\n\n // 非事件消息,继续使用 replyStream(被动回复)\n // 使用 SDK 的 replyStream 方法发送消息,带超时保护\n try {\n await withTimeout(\n wsClient.replyStream(frame, streamId, text, finish),\n REPLY_SEND_TIMEOUT_MS,\n `Reply send timed out (streamId=${streamId})`,\n );\n } catch (err: any) {\n // 服务端返回 846608:流式消息超过6分钟无法更新,需降级为主动发送\n const errMsg = err?.errmsg || err?.message || String(err);\n if (\n err?.errcode === STREAM_EXPIRED_ERRCODE ||\n errMsg.includes(String(STREAM_EXPIRED_ERRCODE))\n ) {\n throw new StreamExpiredError(errMsg);\n }\n throw err;\n }\n runtime.log?.(`[plugin -> server] streamId=${streamId}, finish=${finish}`);\n\n return streamId;\n}\n","/**\n * 企业微信媒体(图片)下载和保存模块\n *\n * 负责下载、检测格式、保存图片到本地,包含超时保护\n */\n\nimport type { OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport type { RuntimeEnv } from \"openclaw/plugin-sdk/runtime-env\";\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 * 从 LLM 回复文本中提取 markdown JSON 代码块,验证其是否为合法的企业微信模板卡片,\n * 返回提取到的卡片列表和剩余文本。\n *\n * 同时提供 maskTemplateCardBlocks 函数,用于在流式中间帧中隐藏正在构建的卡片代码块,\n * 避免 JSON 源码暴露给终端用户。\n */\n\nimport { VALID_CARD_TYPES } from \"./const.js\";\nimport type { ExtractedTemplateCard, TemplateCardExtractionResult } from \"./interface.js\";\n\n// ============================================================================\n// LLM 输出字段类型修正\n// ============================================================================\n\n/**\n * 将 LLM 可能输出的字符串/非法值修正为企业微信 API 要求的整数。\n * 返回修正后的整数,若无法识别则返回 undefined(由调用方决定是否删除该字段)。\n */\nfunction coerceToInt(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return Math.round(value);\n }\n if (typeof value === \"string\") {\n const trimmed = value.trim().toLowerCase();\n // 纯数字字符串\n const num = Number(trimmed);\n if (!Number.isNaN(num) && Number.isFinite(num)) {\n return Math.round(num);\n }\n }\n return undefined;\n}\n\n/** 将 LLM 可能输出的字符串/非法值修正为布尔值 */\nfunction coerceToBool(value: unknown): boolean | undefined {\n if (typeof value === \"boolean\") return value;\n if (typeof value === \"string\") {\n const t = value.trim().toLowerCase();\n if (t === \"true\" || t === \"1\" || t === \"yes\") return true;\n if (t === \"false\" || t === \"0\" || t === \"no\") return false;\n }\n if (typeof value === \"number\") return value !== 0;\n return undefined;\n}\n\n/** checkbox.mode 的语义别名映射 */\nconst MODE_ALIASES: Record<string, number> = {\n single: 0,\n radio: 0,\n \"单选\": 0,\n multi: 1,\n multiple: 1,\n \"多选\": 1,\n};\n\n/**\n * 修正 checkbox.mode:\n * - 0 → 单选,1 → 多选,仅允许这两个值\n * - 字符串数字 \"0\"/\"1\" → 整数\n * - 语义别名 \"multi\"/\"single\" 等 → 对应整数\n * - 其他正整数(如 2)→ clamp 到 1(多选)\n * - 无法识别 → 删除(让服务端使用默认值 0)\n */\nfunction coerceCheckboxMode(value: unknown): number | undefined {\n let num: number | undefined;\n if (typeof value === \"number\" && Number.isFinite(value)) {\n num = Math.round(value);\n } else if (typeof value === \"string\") {\n const trimmed = value.trim().toLowerCase();\n if (trimmed in MODE_ALIASES) return MODE_ALIASES[trimmed];\n const parsed = Number(trimmed);\n if (!Number.isNaN(parsed)) num = Math.round(parsed);\n }\n if (num === undefined) return undefined;\n // mode 只允许 0(单选)或 1(多选),超出范围 clamp\n if (num <= 0) return 0;\n return 1;\n}\n\n/**\n * 对 LLM 生成的模板卡片 JSON 做字段类型修正,确保符合企业微信 API 的类型要求。\n *\n * 修正范围:\n * - checkbox.mode: uint32(0=单选,1=多选)\n * - checkbox.disable: bool\n * - checkbox.option_list[].is_checked: bool\n * - source.desc_color: int\n * - quote_area.type: int\n * - card_action.type: int\n * - image_text_area.type: int\n * - horizontal_content_list[].type: int\n * - jump_list[].type: int\n * - button_list[].style: int\n * - button_selection.disable: bool\n * - select_list[].disable: bool\n *\n * 原则:能修就修,修不了就删(让服务端走默认值),绝不阻塞发送。\n */\nfunction normalizeTemplateCardFields(\n card: Record<string, unknown>,\n log?: (...args: any[]) => void,\n): Record<string, unknown> {\n const fixes: string[] = [];\n\n // ── checkbox ──────────────────────────────────────────────────────────\n const checkbox = card.checkbox as Record<string, unknown> | undefined;\n if (checkbox && typeof checkbox === \"object\") {\n // mode\n if (\"mode\" in checkbox) {\n const fixed = coerceCheckboxMode(checkbox.mode);\n if (fixed !== undefined) {\n if (checkbox.mode !== fixed) {\n fixes.push(`checkbox.mode: ${JSON.stringify(checkbox.mode)} → ${fixed}`);\n }\n checkbox.mode = fixed;\n } else {\n fixes.push(`checkbox.mode: ${JSON.stringify(checkbox.mode)} → (deleted, invalid)`);\n delete checkbox.mode;\n }\n }\n // disable\n if (\"disable\" in checkbox) {\n const fixed = coerceToBool(checkbox.disable);\n if (fixed !== undefined && checkbox.disable !== fixed) {\n fixes.push(`checkbox.disable: ${JSON.stringify(checkbox.disable)} → ${fixed}`);\n checkbox.disable = fixed;\n }\n }\n // option_list[].is_checked\n if (Array.isArray(checkbox.option_list)) {\n for (const opt of checkbox.option_list as Record<string, unknown>[]) {\n if (opt && typeof opt === \"object\" && \"is_checked\" in opt) {\n const fixed = coerceToBool(opt.is_checked);\n if (fixed !== undefined && opt.is_checked !== fixed) {\n fixes.push(`checkbox.option_list.is_checked: ${JSON.stringify(opt.is_checked)} → ${fixed}`);\n opt.is_checked = fixed;\n }\n }\n }\n }\n }\n\n // ── source.desc_color ────────────────────────────────────────────────\n const source = card.source as Record<string, unknown> | undefined;\n if (source && typeof source === \"object\" && \"desc_color\" in source) {\n const fixed = coerceToInt(source.desc_color);\n if (fixed !== undefined && source.desc_color !== fixed) {\n fixes.push(`source.desc_color: ${JSON.stringify(source.desc_color)} → ${fixed}`);\n source.desc_color = fixed;\n }\n }\n\n // ── card_action.type ─────────────────────────────────────────────────\n const cardAction = card.card_action as Record<string, unknown> | undefined;\n if (cardAction && typeof cardAction === \"object\" && \"type\" in cardAction) {\n const fixed = coerceToInt(cardAction.type);\n if (fixed !== undefined && cardAction.type !== fixed) {\n fixes.push(`card_action.type: ${JSON.stringify(cardAction.type)} → ${fixed}`);\n cardAction.type = fixed;\n }\n }\n\n // ── quote_area.type ──────────────────────────────────────────────────\n const quoteArea = card.quote_area as Record<string, unknown> | undefined;\n if (quoteArea && typeof quoteArea === \"object\" && \"type\" in quoteArea) {\n const fixed = coerceToInt(quoteArea.type);\n if (fixed !== undefined && quoteArea.type !== fixed) {\n fixes.push(`quote_area.type: ${JSON.stringify(quoteArea.type)} → ${fixed}`);\n quoteArea.type = fixed;\n }\n }\n\n // ── image_text_area.type ─────────────────────────────────────────────\n const imageTextArea = card.image_text_area as Record<string, unknown> | undefined;\n if (imageTextArea && typeof imageTextArea === \"object\" && \"type\" in imageTextArea) {\n const fixed = coerceToInt(imageTextArea.type);\n if (fixed !== undefined && imageTextArea.type !== fixed) {\n fixes.push(`image_text_area.type: ${JSON.stringify(imageTextArea.type)} → ${fixed}`);\n imageTextArea.type = fixed;\n }\n }\n\n // ── horizontal_content_list[].type ───────────────────────────────────\n if (Array.isArray(card.horizontal_content_list)) {\n for (const item of card.horizontal_content_list as Record<string, unknown>[]) {\n if (item && typeof item === \"object\" && \"type\" in item) {\n const fixed = coerceToInt(item.type);\n if (fixed !== undefined && item.type !== fixed) {\n fixes.push(`horizontal_content_list.type: ${JSON.stringify(item.type)} → ${fixed}`);\n item.type = fixed;\n }\n }\n }\n }\n\n // ── jump_list[].type ─────────────────────────────────────────────────\n if (Array.isArray(card.jump_list)) {\n for (const item of card.jump_list as Record<string, unknown>[]) {\n if (item && typeof item === \"object\" && \"type\" in item) {\n const fixed = coerceToInt(item.type);\n if (fixed !== undefined && item.type !== fixed) {\n fixes.push(`jump_list.type: ${JSON.stringify(item.type)} → ${fixed}`);\n item.type = fixed;\n }\n }\n }\n }\n\n // ── button_list[].style ──────────────────────────────────────────────\n if (Array.isArray(card.button_list)) {\n for (const btn of card.button_list as Record<string, unknown>[]) {\n if (btn && typeof btn === \"object\" && \"style\" in btn) {\n const fixed = coerceToInt(btn.style);\n if (fixed !== undefined && btn.style !== fixed) {\n fixes.push(`button_list.style: ${JSON.stringify(btn.style)} → ${fixed}`);\n btn.style = fixed;\n }\n }\n }\n }\n\n // ── button_selection.disable ─────────────────────────────────────────\n const buttonSelection = card.button_selection as Record<string, unknown> | undefined;\n if (buttonSelection && typeof buttonSelection === \"object\" && \"disable\" in buttonSelection) {\n const fixed = coerceToBool(buttonSelection.disable);\n if (fixed !== undefined && buttonSelection.disable !== fixed) {\n fixes.push(`button_selection.disable: ${JSON.stringify(buttonSelection.disable)} → ${fixed}`);\n buttonSelection.disable = fixed;\n }\n }\n\n // ── select_list[].disable ────────────────────────────────────────────\n if (Array.isArray(card.select_list)) {\n for (const sel of card.select_list as Record<string, unknown>[]) {\n if (sel && typeof sel === \"object\" && \"disable\" in sel) {\n const fixed = coerceToBool(sel.disable);\n if (fixed !== undefined && sel.disable !== fixed) {\n fixes.push(`select_list.disable: ${JSON.stringify(sel.disable)} → ${fixed}`);\n sel.disable = fixed;\n }\n }\n }\n }\n\n if (fixes.length > 0) {\n log?.(`[template-card-parser] normalizeTemplateCardFields: ${fixes.length} fix(es) applied: ${fixes.join(\"; \")}`);\n }\n\n return card;\n}\n\n// ============================================================================\n// 必填字段校验与自动补全\n// ============================================================================\n\n/** task_id 合法字符:数字、字母、_-@ */\nconst TASK_ID_RE = /^[a-zA-Z0-9_\\-@]+$/;\n\n/**\n * 生成一个合法的 task_id。\n * 格式:task_{cardType}_{timestamp}_{随机4位},确保唯一且符合 API 要求。\n */\nfunction generateTaskId(cardType: string): string {\n const rand = Math.random().toString(36).slice(2, 6);\n return `task_${cardType}_${Date.now()}_${rand}`;\n}\n\n/**\n * 校验并补全模板卡片的必填字段。\n *\n * 在 normalizeTemplateCardFields(类型修正)之后调用,确保卡片结构满足企业微信 API 的必填要求。\n *\n * 补全策略:\n * - task_id:所有卡片统一自动补全(交互型 API 必填,通知型插件也需要用于缓存回写)\n * - main_title:除 text_notice 外的 4 种卡片 API 必填,自动补 { title: \"通知\" }\n * text_notice 要求 main_title.title 与 sub_title_text 至少填一个,缺两个时补 sub_title_text\n * - card_action:text_notice / news_notice API 必填,自动补 { type: 1, url: \"https://work.weixin.qq.com\" }\n * - checkbox:vote_interaction API 必填,无法凭空补全,仅记告警\n * - submit_button:vote_interaction / multiple_interaction API 必填,自动补 { text: \"提交\", key: \"submit_default\" }\n * - button_list:button_interaction API 必填,无法凭空补全,仅记告警\n * - select_list:multiple_interaction API 必填,无法凭空补全,仅记告警\n */\nfunction validateAndFixRequiredFields(\n card: Record<string, unknown>,\n log?: (...args: any[]) => void,\n): Record<string, unknown> {\n const cardType = card.card_type as string;\n const fixes: string[] = [];\n const warnings: string[] = [];\n\n // ── task_id(所有卡片:始终确保唯一性) ─────────────────────────────\n // LLM 可能编造时间戳导致重复,因此无论是否提供了 task_id,\n // 都提取语义前缀 + 代码追加真实时间戳和随机后缀来保证唯一。\n const rawTid = (typeof card.task_id === \"string\" && card.task_id.trim()) ? card.task_id.trim() : \"\";\n const rand = Math.random().toString(36).slice(2, 6);\n const ts = Date.now();\n\n let finalTid: string;\n if (rawTid) {\n // 提取 LLM 的语义前缀:去掉尾部的数字串(LLM 编造的假时间戳)\n const prefix = rawTid.replace(/_\\d{8,}$/, \"\").replace(/[^a-zA-Z0-9_\\-@]/g, \"_\").slice(0, 80);\n finalTid = prefix ? `${prefix}_${ts}_${rand}` : `task_${cardType}_${ts}_${rand}`;\n } else {\n finalTid = `task_${cardType}_${ts}_${rand}`;\n }\n\n if (finalTid !== rawTid) {\n fixes.push(`task_id: \"${rawTid || \"(missing)\"}\" → \"${finalTid}\"`);\n }\n card.task_id = finalTid;\n\n // ── main_title ────────────────────────────────────────────────────────\n const mainTitle = card.main_title as Record<string, unknown> | undefined;\n const hasMainTitle = mainTitle && typeof mainTitle === \"object\" &&\n (typeof mainTitle.title === \"string\" && mainTitle.title.trim());\n const hasSubTitleText = typeof card.sub_title_text === \"string\" && (card.sub_title_text as string).trim();\n\n switch (cardType) {\n case \"text_notice\":\n // text_notice: main_title.title 和 sub_title_text 至少一个\n if (!hasMainTitle && !hasSubTitleText) {\n card.sub_title_text = card.sub_title_text || \"通知\";\n fixes.push(`sub_title_text: (missing, no main_title either) → fallback \"通知\"`);\n }\n break;\n\n case \"news_notice\":\n case \"button_interaction\":\n case \"vote_interaction\":\n case \"multiple_interaction\":\n // 这四种 main_title 为必填\n if (!mainTitle || typeof mainTitle !== \"object\") {\n card.main_title = { title: \"通知\" };\n fixes.push(`main_title: (missing) → { title: \"通知\" }`);\n } else if (!hasMainTitle) {\n (mainTitle as Record<string, unknown>).title = \"通知\";\n fixes.push(`main_title.title: (empty) → \"通知\"`);\n }\n break;\n }\n\n // ── card_action(text_notice / news_notice 必填) ──────────────────\n if (cardType === \"text_notice\" || cardType === \"news_notice\") {\n if (!card.card_action || typeof card.card_action !== \"object\") {\n card.card_action = { type: 1, url: \"https://work.weixin.qq.com\" };\n fixes.push(`card_action: (missing) → { type: 1, url: \"https://work.weixin.qq.com\" }`);\n }\n }\n\n // ── submit_button(vote_interaction / multiple_interaction 必填) ──\n if (cardType === \"vote_interaction\" || cardType === \"multiple_interaction\") {\n if (!card.submit_button || typeof card.submit_button !== \"object\") {\n card.submit_button = { text: \"提交\", key: `submit_${cardType}_${Date.now()}` };\n fixes.push(`submit_button: (missing) → auto-generated`);\n }\n }\n\n // ── 核心业务字段(无法凭空补全,仅告警) ────────────────────────────\n if (cardType === \"button_interaction\") {\n if (!Array.isArray(card.button_list) || card.button_list.length === 0) {\n warnings.push(`button_list is missing or empty (required for button_interaction)`);\n }\n }\n\n if (cardType === \"vote_interaction\") {\n if (!card.checkbox || typeof card.checkbox !== \"object\") {\n warnings.push(`checkbox is missing (required for vote_interaction)`);\n }\n }\n\n if (cardType === \"multiple_interaction\") {\n if (!Array.isArray(card.select_list) || card.select_list.length === 0) {\n warnings.push(`select_list is missing or empty (required for multiple_interaction)`);\n }\n }\n\n if (fixes.length > 0) {\n log?.(`[template-card-parser] validateAndFixRequiredFields: ${fixes.length} fix(es): ${fixes.join(\"; \")}`);\n }\n if (warnings.length > 0) {\n log?.(`[template-card-parser] validateAndFixRequiredFields: ${warnings.length} warning(s): ${warnings.join(\"; \")}`);\n }\n\n return card;\n}\n\n// ============================================================================\n// 简化格式 → 企微 API 格式转换(vote_interaction / multiple_interaction)\n// ============================================================================\n\n/**\n * 生成唯一的 question_key / submit_button.key。\n */\nfunction generateKey(prefix: string): string {\n const rand = Math.random().toString(36).slice(2, 6);\n return `${prefix}_${Date.now()}_${rand}`;\n}\n\n/**\n * 将 vote_interaction 的简化格式转换为企微 API 格式。\n *\n * 简化格式字段:\n * title → main_title.title\n * description → main_title.desc\n * options → checkbox.option_list(每个 {id, text} 直接透传)\n * mode → checkbox.mode(0=单选 1=多选)\n * submit_text → submit_button.text\n *\n * 代码自动生成:checkbox.question_key, submit_button.key\n *\n * 如果 LLM 已输出了合法的 API 原始格式(有 checkbox.option_list),则跳过转换直接透传。\n */\nfunction transformVoteInteraction(\n card: Record<string, unknown>,\n log?: (...args: any[]) => void,\n): Record<string, unknown> {\n // 防御性:如果已经是合法 API 格式,跳过\n const existingCheckbox = card.checkbox as Record<string, unknown> | undefined;\n if (existingCheckbox && typeof existingCheckbox === \"object\" && Array.isArray(existingCheckbox.option_list)) {\n log?.(`[template-card-parser] transformVoteInteraction: already has checkbox.option_list, skipping transform`);\n return card;\n }\n\n // 提取 options(简化格式的核心字段)\n const options = card.options as Array<Record<string, unknown>> | undefined;\n if (!Array.isArray(options) || options.length === 0) {\n log?.(`[template-card-parser] transformVoteInteraction: no \"options\" array found, skipping transform`);\n return card;\n }\n\n log?.(`[template-card-parser] transformVoteInteraction: transforming simplified format → API format`);\n log?.(`[template-card-parser] transformVoteInteraction: input=${JSON.stringify(card)}`);\n\n // ── 构建 main_title ──\n const title = card.title as string | undefined;\n const description = card.description as string | undefined;\n if (title || description) {\n card.main_title = {\n ...(title ? { title } : {}),\n ...(description ? { desc: description } : {}),\n };\n delete card.title;\n delete card.description;\n }\n\n // ── 构建 checkbox(最多 20 个选项) ──\n const mode = coerceCheckboxMode(card.mode) ?? 0;\n const questionKey = generateKey(\"vote\");\n const clampedOptions = options.slice(0, 20);\n if (options.length > 20) {\n log?.(`[template-card-parser] transformVoteInteraction: options count ${options.length} exceeds max 20, clamped to 20`);\n }\n card.checkbox = {\n question_key: questionKey,\n mode,\n option_list: clampedOptions.map((opt) => ({\n id: String(opt.id ?? opt.value ?? `opt_${Math.random().toString(36).slice(2, 6)}`),\n text: String(opt.text ?? opt.label ?? opt.name ?? \"\"),\n })),\n };\n delete card.options;\n delete card.mode;\n\n // ── 构建 submit_button ──\n const submitText = (card.submit_text as string) || \"提交\";\n card.submit_button = {\n text: submitText,\n key: generateKey(\"submit_vote\"),\n };\n delete card.submit_text;\n\n // ── 清理 LLM 可能杜撰的无效字段 ──\n delete card.vote_question;\n delete card.vote_option;\n delete card.vote_options;\n\n log?.(`[template-card-parser] transformVoteInteraction: output=${JSON.stringify(card)}`);\n\n return card;\n}\n\n/**\n * 将 multiple_interaction 的简化格式转换为企微 API 格式。\n *\n * 简化格式字段:\n * title → main_title.title\n * description → main_title.desc\n * selectors → select_list(每个 {title, options: [{id, text}]} → {question_key, title, option_list})\n * submit_text → submit_button.text\n *\n * 代码自动生成:select_list[].question_key, submit_button.key\n *\n * 如果 LLM 已输出了合法的 API 原始格式(有 select_list[0].option_list),则跳过转换直接透传。\n */\nfunction transformMultipleInteraction(\n card: Record<string, unknown>,\n log?: (...args: any[]) => void,\n): Record<string, unknown> {\n // 防御性:如果已经是合法 API 格式,跳过\n const existingSelectList = card.select_list as Array<Record<string, unknown>> | undefined;\n if (\n Array.isArray(existingSelectList) &&\n existingSelectList.length > 0 &&\n Array.isArray(existingSelectList[0]?.option_list)\n ) {\n log?.(`[template-card-parser] transformMultipleInteraction: already has select_list[].option_list, skipping transform`);\n return card;\n }\n\n // 提取 selectors(简化格式的核心字段)\n const selectors = card.selectors as Array<Record<string, unknown>> | undefined;\n if (!Array.isArray(selectors) || selectors.length === 0) {\n log?.(`[template-card-parser] transformMultipleInteraction: no \"selectors\" array found, skipping transform`);\n return card;\n }\n\n log?.(`[template-card-parser] transformMultipleInteraction: transforming simplified format → API format`);\n log?.(`[template-card-parser] transformMultipleInteraction: input=${JSON.stringify(card)}`);\n\n // ── 构建 main_title ──\n const title = card.title as string | undefined;\n const description = card.description as string | undefined;\n if (title || description) {\n card.main_title = {\n ...(title ? { title } : {}),\n ...(description ? { desc: description } : {}),\n };\n delete card.title;\n delete card.description;\n }\n\n // ── 构建 select_list(最多 3 个选择器,每个最多 10 个选项) ──\n const clampedSelectors = selectors.slice(0, 3);\n if (selectors.length > 3) {\n log?.(`[template-card-parser] transformMultipleInteraction: selectors count ${selectors.length} exceeds max 3, clamped to 3`);\n }\n card.select_list = clampedSelectors.map((sel, idx) => {\n const selectorOptions = ((sel.options as Array<Record<string, unknown>>) ?? []).slice(0, 10);\n return {\n question_key: generateKey(`sel_${idx}`),\n title: String(sel.title ?? sel.label ?? `选择${idx + 1}`),\n option_list: selectorOptions.map((opt) => ({\n id: String(opt.id ?? opt.value ?? `opt_${Math.random().toString(36).slice(2, 6)}`),\n text: String(opt.text ?? opt.label ?? opt.name ?? \"\"),\n })),\n };\n });\n delete card.selectors;\n\n // ── 构建 submit_button ──\n const submitText = (card.submit_text as string) || \"提交\";\n card.submit_button = {\n text: submitText,\n key: generateKey(\"submit_multi\"),\n };\n delete card.submit_text;\n\n log?.(`[template-card-parser] transformMultipleInteraction: output=${JSON.stringify(card)}`);\n\n return card;\n}\n\n/**\n * 对 vote_interaction / multiple_interaction 执行简化格式转换。\n * 其他 card_type 直接跳过。\n */\nfunction transformSimplifiedCard(\n card: Record<string, unknown>,\n log?: (...args: any[]) => void,\n): Record<string, unknown> {\n const cardType = card.card_type as string;\n if (cardType === \"vote_interaction\") {\n return transformVoteInteraction(card, log);\n }\n if (cardType === \"multiple_interaction\") {\n return transformMultipleInteraction(card, log);\n }\n return card;\n}\n\n/**\n * 匹配 markdown 代码块的正则表达式\n * 支持 ```json ... ``` 和 ``` ... ``` 两种格式\n */\nconst CODE_BLOCK_RE = /```(?:json)?\\s*\\n([\\s\\S]*?)\\n```/g;\n\n/**\n * 匹配已闭合的代码块(含 card_type 关键词,用于中间帧遮罩)\n * 与 CODE_BLOCK_RE 相同,但用于 maskTemplateCardBlocks 中单独实例化\n */\nconst CLOSED_BLOCK_RE = /```(?:json)?\\s*\\n([\\s\\S]*?)\\n```/g;\n\n/**\n * 匹配未闭合的代码块尾部(LLM 正在输出中的代码块)\n * 以 ```json 或 ``` 开头,后面有内容但没有闭合的 ```\n */\nconst UNCLOSED_BLOCK_RE = /```(?:json)?\\s*\\n[\\s\\S]*$/;\n\n/**\n * 从文本中提取模板卡片 JSON 代码块\n *\n * 匹配规则:\n * 1. 匹配所有 ```json ... ``` 或 ``` ... ``` 格式的代码块\n * 2. 尝试 JSON.parse 解析代码块内容\n * 3. 检查解析结果中是否包含合法的 card_type 字段\n * 4. 合法的卡片从原文中移除,不合法的保留\n *\n * @param text - LLM 回复的完整文本\n * @returns 提取结果,包含卡片列表和剩余文本\n */\nexport function extractTemplateCards(text: string, log?: (...args: any[]) => void): TemplateCardExtractionResult {\n const cards: ExtractedTemplateCard[] = [];\n /** 需要从原文中移除的代码块(记录完整匹配内容) */\n const blocksToRemove: string[] = [];\n\n log?.(`[template-card-parser] extractTemplateCards called, textLength=${text.length}`);\n\n let match: RegExpExecArray | null;\n // 重置正则的 lastIndex,确保从头匹配\n CODE_BLOCK_RE.lastIndex = 0;\n\n let blockIndex = 0;\n while ((match = CODE_BLOCK_RE.exec(text)) !== null) {\n const fullMatch = match[0];\n const jsonContent = match[1].trim();\n blockIndex++;\n\n log?.(`[template-card-parser] Found code block #${blockIndex}, length=${fullMatch.length}, preview=${jsonContent.slice(0, 1000)}...`);\n\n // 尝试解析 JSON\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(jsonContent) as Record<string, unknown>;\n } catch (e) {\n // JSON 解析失败,保留在原文中\n log?.(`[template-card-parser] Code block #${blockIndex} JSON parse failed: ${String(e)}`);\n continue;\n }\n\n // 检查是否包含合法的 card_type\n const cardType = parsed.card_type;\n if (typeof cardType !== \"string\" || !VALID_CARD_TYPES.includes(cardType)) {\n // card_type 不合法,保留在原文中\n log?.(`[template-card-parser] Code block #${blockIndex} has invalid card_type=\"${String(cardType)}\", skipping`);\n continue;\n }\n\n log?.(`[template-card-parser] Code block #${blockIndex} is valid template card, card_type=\"${cardType}\"`);\n\n // vote_interaction / multiple_interaction:简化格式 → API 格式转换\n transformSimplifiedCard(parsed, log);\n\n // 修正 LLM 可能输出的错误字段类型(如 checkbox.mode: \"multi\" → 1)\n normalizeTemplateCardFields(parsed, log);\n\n // 校验并补全必填字段(如缺失的 task_id、main_title、card_action)\n validateAndFixRequiredFields(parsed, log);\n\n // 合法的模板卡片,收集并标记移除\n cards.push({\n cardJson: parsed,\n cardType,\n });\n blocksToRemove.push(fullMatch);\n }\n\n // 从原文中移除已提取的代码块,生成剩余文本\n let remainingText = text;\n for (const block of blocksToRemove) {\n remainingText = remainingText.replace(block, \"\");\n }\n // 清理多余空行(连续 3 个以上换行合并为 2 个)\n remainingText = remainingText.replace(/\\n{3,}/g, \"\\n\\n\").trim();\n\n log?.(`[template-card-parser] Extraction done: ${cards.length} card(s) found, remainingTextLength=${remainingText.length}`);\n\n return { cards, remainingText };\n}\n\n/**\n * 遮罩文本中的模板卡片代码块(用于流式中间帧展示)\n *\n * 在 LLM 流式输出过程中,累积文本可能包含:\n * 1. 已闭合的模板卡片 JSON 代码块 → 替换为友好提示文本\n * 2. 正在构建中的未闭合代码块 → 截断隐藏,避免 JSON 源码暴露\n *\n * 此函数仅做文本替换,不做 JSON 解析验证(中间帧性能优先)。\n * 只要代码块内容中出现 \"card_type\" 关键词就认为是模板卡片并遮罩。\n *\n * @param text - 当前累积文本\n * @returns 遮罩后的展示文本\n */\nexport function maskTemplateCardBlocks(text: string, log?: (...args: any[]) => void): string {\n let masked = text;\n let closedMaskCount = 0;\n let unclosedMasked = false;\n\n // 步骤一:处理已闭合的代码块\n CLOSED_BLOCK_RE.lastIndex = 0;\n masked = masked.replace(CLOSED_BLOCK_RE, (fullMatch, content: string) => {\n // 检查代码块内容是否包含 card_type 关键词\n if (/[\"']card_type[\"']/.test(content)) {\n closedMaskCount++;\n return \"\\n\\n📋 *正在生成卡片消息...*\\n\\n\";\n }\n // 非模板卡片代码块,保留原样\n return fullMatch;\n });\n\n // 步骤二:处理未闭合的代码块尾部(LLM 仍在输出中)\n // 检查是否有以 ``` 开头但没有闭合的代码块\n const unclosedMatch = UNCLOSED_BLOCK_RE.exec(masked);\n if (unclosedMatch) {\n const unclosedContent = unclosedMatch[0];\n // 如果未闭合部分包含 card_type 关键词,说明正在构建模板卡片 → 截断\n if (/[\"']card_type[\"']/.test(unclosedContent)) {\n unclosedMasked = true;\n masked = masked.slice(0, unclosedMatch.index) + \"\\n\\n📋 *正在生成卡片消息...*\";\n }\n }\n\n // 有遮罩行为时才打日志,避免每帧都刷屏\n if (closedMaskCount > 0 || unclosedMasked) {\n log?.(`[template-card-parser] maskTemplateCardBlocks: closedMasked=${closedMaskCount}, unclosedMasked=${unclosedMasked}, textLength=${text.length}, maskedLength=${masked.length}`);\n }\n\n return masked;\n}\n","/**\n * 企业微信群组访问控制模块\n *\n * 负责群组策略检查(groupPolicy、群组白名单、群内发送者白名单)\n */\n\nimport type { OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport type { RuntimeEnv } from \"openclaw/plugin-sdk/runtime-env\";\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/runtime-env\";\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","// ============================================================================\n// 类型定义\n// ============================================================================\n\n/** 单条 reqId 记录 */\ninterface ReqIdEntry {\n /** 请求 ID */\n reqId: string;\n /** 记录时间戳(毫秒) */\n ts: number;\n}\n\n/** Store 配置 */\ninterface ReqIdStoreOptions {\n /** TTL 毫秒数,超时的 reqId 视为过期(默认 7 天) */\n ttlMs?: number;\n /** 内存最大条目数(默认 200) */\n memoryMaxSize?: number;\n}\n\n// ============================================================================\n// 常量\n// ============================================================================\n\nconst DEFAULT_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 天\nconst DEFAULT_MEMORY_MAX_SIZE = 200;\n\n// ============================================================================\n// 公开接口\n// ============================================================================\n\nexport interface PersistentReqIdStore {\n /** 设置 chatId 对应的 reqId(仅写入内存) */\n set(chatId: string, reqId: string): void;\n /** 获取 chatId 对应的 reqId(仅内存) */\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 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\n // 内存层:chatId → ReqIdEntry\n const memory = new Map<string, ReqIdEntry>();\n\n // ========== 内部辅助函数 ==========\n\n /** 检查条目是否过期 */\n function isExpired(entry: ReqIdEntry, now: number): boolean {\n return ttlMs > 0 && now - entry.ts >= ttlMs;\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 // ========== 公开 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 }\n\n async function get(chatId: string): Promise<string | undefined> {\n const now = Date.now();\n\n // 仅查内存\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 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 }\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 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 * \n * 注意:由于移除了磁盘存储,此函数现在只返回 0(无预热条目)\n */\nexport async function warmupReqIdStore(\n accountId = \"default\",\n log?: (...args: unknown[]) => void,\n): Promise<number> {\n // 由于移除了磁盘存储,不再需要预热过程\n log?.(\"[WeCom] reqid-store warmup: no-op (disk storage removed)\");\n return 0;\n}\n\n/**\n * 立即将 reqId 数据刷写到磁盘(用于优雅退出)\n * \n * 注意:由于移除了磁盘存储,此函数现在是无操作\n */\nexport async function flushReqIdStore(accountId = \"default\"): Promise<void> {\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 // 注意:不删除 store,因为重连后可能还需要\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\n // 清空消息状态\n clearAllMessageStates();\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 * 企业微信 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 } from \"openclaw/plugin-sdk/core\";\nimport type { RuntimeEnv } from \"openclaw/plugin-sdk/runtime-env\";\nimport { WSClient, generateReqId, WSAuthFailureError, WSReconnectExhaustedError } from \"@wecom/aibot-node-sdk\";\nimport type { WsFrame, Logger, TemplateCard } 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 WS_HEARTBEAT_INTERVAL_MS,\n WS_MAX_RECONNECT_ATTEMPTS,\n WS_MAX_AUTH_FAILURE_ATTEMPTS,\n EVENT_ENTER_CHECK_UPDATE,\n CMD_ENTER_EVENT_REPLY,\n SCENE_WECOM_OPENCLAW,\n} from \"./const.js\";\nimport type { WeComMonitorOptions, MessageState } from \"./interface.js\";\nimport { parseMessageContent, type MessageBody } from \"./message-parser.js\";\nimport { sendWeComReply, StreamExpiredError } from \"./message-sender.js\";\nimport { downloadAndSaveImages, downloadAndSaveFiles } from \"./media-handler.js\";\nimport { uploadAndSendMedia } from \"./media-uploader.js\";\nimport { extractTemplateCards, maskTemplateCardBlocks } from \"./template-card-parser.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\";\n\nimport { PLUGIN_VERSION } from \"./version.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\ninterface SentTemplateCardCacheEntry {\n templateCard: TemplateCard;\n createdAt: number;\n}\n\nconst sentTemplateCardByTaskId = new Map<string, SentTemplateCardCacheEntry>();\nconst TEMPLATE_CARD_CACHE_TTL_MS = 24 * 60 * 60 * 1000;\nconst TEMPLATE_CARD_CACHE_MAX_SIZE = 300;\n\nfunction getTemplateCardCacheKey(accountId: string, taskId: string): string {\n return `${accountId}:${taskId}`;\n}\n\nfunction pruneTemplateCardCache(): void {\n const now = Date.now();\n\n for (const [key, entry] of sentTemplateCardByTaskId) {\n if (now - entry.createdAt >= TEMPLATE_CARD_CACHE_TTL_MS) {\n sentTemplateCardByTaskId.delete(key);\n }\n }\n\n if (sentTemplateCardByTaskId.size <= TEMPLATE_CARD_CACHE_MAX_SIZE) {\n return;\n }\n\n const sortedEntries = [...sentTemplateCardByTaskId.entries()].sort(\n (a, b) => a[1].createdAt - b[1].createdAt,\n );\n const removeCount = sentTemplateCardByTaskId.size - TEMPLATE_CARD_CACHE_MAX_SIZE;\n for (const [key] of sortedEntries.slice(0, removeCount)) {\n sentTemplateCardByTaskId.delete(key);\n }\n}\n\nfunction cloneTemplateCard(card: TemplateCard): TemplateCard {\n return JSON.parse(JSON.stringify(card)) as TemplateCard;\n}\n\nfunction saveTemplateCardToCache(params: {\n accountId: string;\n templateCard: TemplateCard;\n runtime: RuntimeEnv;\n}): void {\n const { accountId, templateCard, runtime } = params;\n const taskId = templateCard.task_id;\n if (!taskId) {\n runtime.log?.(\"[wecom][template-card] Skip cache: template card has no task_id\");\n return;\n }\n\n sentTemplateCardByTaskId.set(getTemplateCardCacheKey(accountId, taskId), {\n templateCard: cloneTemplateCard(templateCard),\n createdAt: Date.now(),\n });\n pruneTemplateCardCache();\n}\n\nfunction getTemplateCardFromCache(accountId: string, taskId: string): TemplateCard | undefined {\n pruneTemplateCardCache();\n const cached = sentTemplateCardByTaskId.get(getTemplateCardCacheKey(accountId, taskId));\n if (!cached) {\n return undefined;\n }\n return cloneTemplateCard(cached.templateCard);\n}\n\ntype TemplateCardEventPayload = NonNullable<NonNullable<MessageBody[\"event\"]>[\"template_card_event\"]>;\n\nfunction buildSelectedOptionMap(templateCardEvent?: TemplateCardEventPayload): Map<string, string[]> {\n const selectedMap = new Map<string, string[]>();\n const selectedItems = templateCardEvent?.selected_items?.selected_item ?? [];\n\n for (const item of selectedItems) {\n const questionKey = item.question_key?.trim();\n if (!questionKey) {\n continue;\n }\n const optionIds = item.option_ids?.option_id?.filter(Boolean) ?? [];\n selectedMap.set(questionKey, optionIds);\n }\n\n return selectedMap;\n}\n\nfunction applySelectedStateToTemplateCard(params: {\n templateCard: TemplateCard;\n selectedMap: Map<string, string[]>;\n templateCardEvent?: TemplateCardEventPayload;\n}): TemplateCard {\n const { templateCard, selectedMap, templateCardEvent } = params;\n const nextCard = cloneTemplateCard(templateCard);\n\n if (templateCardEvent?.task_id) {\n nextCard.task_id = templateCardEvent.task_id;\n }\n if (templateCardEvent?.card_type) {\n nextCard.card_type = templateCardEvent.card_type;\n }\n\n // 交互完成后将提交按钮文案更新为已提交,提升用户感知\n if (nextCard.submit_button?.text) {\n nextCard.submit_button.text = \"已提交\";\n }\n\n if (nextCard.checkbox?.question_key) {\n const selectedIds = selectedMap.get(nextCard.checkbox.question_key) ?? [];\n nextCard.checkbox.disable = true;\n if (Array.isArray(nextCard.checkbox.option_list)) {\n nextCard.checkbox.option_list = nextCard.checkbox.option_list.map((option) => ({\n ...option,\n is_checked: selectedIds.includes(option.id),\n }));\n }\n }\n\n if (Array.isArray(nextCard.select_list)) {\n nextCard.select_list = nextCard.select_list.map((selection) => {\n const selectedIds = selectedMap.get(selection.question_key) ?? [];\n return {\n ...selection,\n disable: true,\n selected_id: selectedIds[0] ?? selection.selected_id,\n };\n });\n }\n\n if (nextCard.button_selection?.question_key) {\n const selectedIds = selectedMap.get(nextCard.button_selection.question_key) ?? [];\n nextCard.button_selection.disable = true;\n if (selectedIds[0]) {\n nextCard.button_selection.selected_id = selectedIds[0];\n }\n }\n\n return nextCard;\n}\n\nasync function updateTemplateCardOnEvent(params: {\n frame: WsFrame;\n accountId: string;\n runtime: RuntimeEnv;\n wsClient: WSClient;\n}): Promise<void> {\n const { frame, accountId, runtime, wsClient } = params;\n const body = frame.body as MessageBody;\n const templateCardEvent = body.event?.template_card_event;\n const taskId = templateCardEvent?.task_id;\n\n if (!taskId) {\n runtime.log?.(`[${accountId}] [template-card-update] Skip update: missing task_id in callback`);\n return;\n }\n\n const cachedCard = getTemplateCardFromCache(accountId, taskId);\n if (!cachedCard) {\n runtime.log?.(`[${accountId}] [template-card-update] Skip update: task_id=${taskId} not found in cache`);\n return;\n }\n\n const selectedMap = buildSelectedOptionMap(templateCardEvent);\n const updatedCard = applySelectedStateToTemplateCard({\n templateCard: cachedCard,\n selectedMap,\n templateCardEvent,\n });\n\n await wsClient.updateTemplateCard(frame, updatedCard, [body.from.userid]);\n runtime.log?.(`[${accountId}] [template-card-update] Updated card by task_id=${taskId}`);\n\n // 将更新后的卡片写回缓存,后续多次点击时状态保持一致\n saveTemplateCardToCache({\n accountId,\n templateCard: updatedCard,\n runtime,\n });\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 state?: MessageState;\n}): Promise<void> {\n const { wsClient, frame, streamId, runtime, state } = 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 if (err instanceof StreamExpiredError && state) {\n state.streamExpired = true;\n runtime.log?.(`[wecom] Stream expired during thinking reply, will fallback to proactive send`);\n } else {\n runtime.error?.(`[wecom] Failed to send thinking message: ${String(err)}`);\n }\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)}`);\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 * 0. [新增] 有模板卡片代码块 → 提取卡片并主动发送,用剩余文本关闭流\n * 1. 有可见文本 → 用完整文本关闭\n * 2. 有媒体成功发送(通过 deliver 回调) → 用友好提示\"文件已发送\"\n * 3. 媒体发送失败 → 直接用错误摘要替换 thinking\n * 4. 其他 → 用通用\"处理完成\"提示\n * (agent 可能已通过内置 message 工具直接发送了文件,\n * 该路径走 outbound.sendMedia 完全绕过 deliver 回调,\n * 所以 state 中无记录,但文件已实际送达)\n *\n * 降级策略:\n * - 当 streamExpired=true(errcode 846608)时,流式通道已不可用(>6分钟),\n * 改用 wsClient.sendMessage 主动发送完整文本。\n */\nasync function finishThinkingStream(ctx: DeliverContext): 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 visibleText = stripThinkTags(state.accumulatedText);\n\n // ── 模板卡片检测与发送 ──────────────────────────────────────────────\n // 在确定 finishText 之前,先检查累积文本中是否包含模板卡片 JSON 代码块。\n // 若检测到合法卡片,通过 sendMessage 主动发送后,用剩余文本关闭流。\n if (visibleText) {\n runtime.log?.(`[wecom][template-card] finishThinkingStream: visibleText exists, length=${visibleText.length}, running extractTemplateCards...`);\n const logFn = (...args: any[]): void => {\n runtime.log?.(...args);\n };\n const { cards, remainingText } = extractTemplateCards(state.accumulatedText, logFn);\n\n runtime.log?.(`[wecom][template-card] finishThinkingStream: extractTemplateCards result — cards=${cards.length}, remainingTextLength=${remainingText.length}`);\n\n if (cards.length > 0) {\n runtime.log?.(`[wecom][template-card] finishThinkingStream: ${cards.length} card(s) detected, card_types=[${cards.map(c => c.cardType).join(\", \")}]`);\n await sendTemplateCards(ctx, cards);\n\n // 用剩余文本关闭流(可能为空)\n const trimmedRemaining = stripThinkTags(remainingText);\n const finishText = trimmedRemaining\n ? remainingText\n : (state.hasTemplateCard ? \"📋 卡片消息已发送。\" : \"✅ 处理完成。\");\n runtime.log?.(`[wecom][template-card] finishThinkingStream: closing stream with finishText=\"${finishText.slice(0, 100)}...\", hasTemplateCard=${state.hasTemplateCard}`);\n await sendWeComReply({ wsClient, frame, text: finishText, runtime, finish: true, streamId: state.streamId });\n return;\n }\n } else {\n runtime.log?.(`[wecom][template-card] finishThinkingStream: no visibleText, skipping template card extraction`);\n }\n // ── 模板卡片检测结束 ────────────────────────────────────────────────\n\n let finishText: string = state.accumulatedText;\n if (visibleText) {\n // 有可见文本:用完整文本关闭流(覆盖 thinking 为真实内容)\n finishText = state.accumulatedText;\n } else if (state.hasMedia) {\n if (state.hasMediaFailed && state.mediaErrorSummary) {\n // 媒体成功发送:用友好提示告知用户\n finishText = finishText ? `${finishText}\\n\\n${state.mediaErrorSummary}` : state.mediaErrorSummary;\n } else if (!finishText) {\n finishText = \"📎 文件已发送,请查收。\";\n }\n }\n\n // if (!finishText) {\n // finishText = \"✅ 处理完成。\";\n // }\n\n if (finishText) {\n // 尝试流式发送;若已知过期或发送时发现过期,统一降级为主动发送\n let expired = state.streamExpired;\n if (!expired) {\n try {\n await sendWeComReply({wsClient, frame, text: finishText, runtime, finish: true, streamId: state.streamId});\n } catch (err) {\n if (err instanceof StreamExpiredError) {\n expired = true;\n } else {\n throw err;\n }\n }\n }\n if (expired) {\n runtime.log?.(`[wecom] Stream expired, sending final text via sendMessage (proactive)`);\n await wsClient.sendMessage(chatId, {\n msgtype: \"markdown\",\n markdown: { content: finishText },\n });\n }\n }\n}\n\n/**\n * 逐个发送已提取的模板卡片(通过 wsClient.sendMessage 主动推送)\n *\n * 发送失败不阻塞流程,仅记录错误日志。\n */\nasync function sendTemplateCards(\n ctx: DeliverContext,\n cards: import(\"./interface.js\").ExtractedTemplateCard[],\n): Promise<void> {\n const { wsClient, frame, state, runtime, account } = ctx;\n const body = frame.body as MessageBody;\n const chatId = body.chatid || body.from.userid;\n\n for (const card of cards) {\n try {\n runtime.log?.(`[wecom][template-card] Sending card_type=${card.cardType} to chatId=${chatId}`);\n\n const rawTemplateCard = card.cardJson as Record<string, unknown>;\n if (typeof rawTemplateCard.card_type !== \"string\") {\n runtime.error?.(\"[wecom][template-card] Skip sending invalid card: missing card_type\");\n continue;\n }\n\n const templateCard = rawTemplateCard as unknown as TemplateCard;\n await wsClient.sendMessage(chatId, {\n msgtype: \"template_card\",\n template_card: templateCard,\n });\n state.hasTemplateCard = true;\n saveTemplateCardToCache({\n accountId: account.accountId,\n templateCard,\n runtime,\n });\n runtime.log?.(`[wecom][template-card] Card sent successfully: card_type=${card.cardType}`);\n } catch (err) {\n runtime.error?.(`[wecom][template-card] Failed to send card: card_type=${card.cardType}, error=${JSON.stringify(err)}`);\n }\n }\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 let isShowThink = !(account.sendThinkingMessage ?? true);\n\n try {\n await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({\n ctx: ctxPayload,\n cfg: config,\n // replyResolver: async (ctx, opts) => {\n // const startTime = Date.now();\n // const TEN_MINUTES = 7 * 60 * 1000;\n //\n // console.log('开始输出内容');\n //\n // while (Date.now() - startTime < TEN_MINUTES) {\n // // 每隔一段时间发送一个 block reply\n // await opts?.onBlockReply?.({ text: `输出内容 ${new Date().toISOString()}` });\n // await new Promise(resolve => setTimeout(resolve, 30 * 1000)); // 每5秒输出一次\n // }\n //\n // return { text: \"10分钟输出完成\" }; // 最终回复\n // },\n dispatcherOptions: {\n onReplyStart: async () => {\n if (!isShowThink && state.streamId && !state.accumulatedText) {\n try {\n await sendThinkingReply({wsClient, frame, streamId: state.streamId, runtime, state})\n } catch (e) {\n runtime.error?.(`[wecom] sendThinkingReply threw err: ${String(e)}`);\n }\n isShowThink = true;\n }\n },\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 state.accumulatedText += (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 // 中间帧:有可见文本时流式更新(流式过期后跳过,等 deliver 完成后主动发送)\n // 使用 maskTemplateCardBlocks 遮罩正在构建中的模板卡片代码块,\n // 避免 JSON 源码在流式输出过程中暴露给终端用户\n if (info.kind !== \"final\" && state.accumulatedText && !state.streamExpired) {\n try {\n const displayText = maskTemplateCardBlocks(state.accumulatedText, (...args: any[]) => runtime.log?.(...args));\n if (displayText !== state.accumulatedText) {\n runtime.log?.(`[wecom][template-card] Mid-frame masked: original=${state.accumulatedText.length}chars, masked=${displayText.length}chars`);\n }\n await sendWeComReply({ wsClient, frame, text: displayText, runtime, finish: false, streamId: state.streamId });\n } catch (err) {\n if (err instanceof StreamExpiredError) {\n state.streamExpired = true;\n runtime.log?.(`[wecom] Stream expired during intermediate reply, will fallback to proactive send`);\n } else {\n throw err;\n }\n }\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 routeAndDispatchMessage({\n ctxPayload,\n config,\n account,\n wsClient,\n frame,\n state,\n runtime,\n onCleanup: cleanupState,\n });\n } catch (err) {\n runtime.error?.(`[wecom][plugin] Message processing failed: ${String(err)}`);\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, setStatus } = options;\n\n runtime.log?.(`[${account.accountId}] [${PLUGIN_VERSION}] Initializing WSClient with SDK...`);\n runtime.error?.(`[${account.accountId}] [diag] monitor boot marker: build=20260325-event-debug-1`);\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 maxAuthFailureAttempts: WS_MAX_AUTH_FAILURE_ATTEMPTS,\n scene: SCENE_WECOM_OPENCLAW,\n plug_version: PLUGIN_VERSION,\n });\n\n // 防止 cleanup 被多次调用(abort handler、error handler、disconnected_event 可能竞态触发)\n let cleanedUp = false;\n\n // 清理函数:确保所有资源被释放(幂等)\n const cleanup = async () => {\n if (cleanedUp) return;\n cleanedUp = true;\n stopMessageStateCleanup();\n await cleanupAccount(account.accountId);\n };\n\n // 处理中止信号(框架 stopChannel 会触发 abort)\n // resolve() 让 Promise settle → 框架清理 store.tasks/store.aborts\n if (abortSignal) {\n abortSignal.addEventListener(\"abort\", async () => {\n runtime.log?.(`[${account.accountId}] Connection aborted`);\n wsClient.disconnect();\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 // 监听被踢下线事件(服务端因新连接建立而主动断开旧连接)\n //\n // SDK 内部已设置 isManualClose=true 阻止 SDK 层自动重连,连接不会自行恢复。\n // **不 reject/resolve Promise**——保持 pending 以阻止框架层 auto-restart。\n //\n // 为什么不能 reject/resolve:\n // - reject → 框架 auto-restart 介入 → 新连接建立 → 又被踢 → 两个实例互踢无限循环\n // - resolve → 同上,框架 .then() 中的 auto-restart 也会触发\n //\n // Promise pending 的安全性:\n // - store.tasks.has(id) = true → 阻止 Health Monitor 直接 startChannel(startChannel 检查 tasks.has)\n // - 框架 stopChannel → abort() → abort handler 中 resolve() → tasks 正常清理\n // - 用户修改配置 → config reload → stopChannel + startChannel → 正常恢复\n //\n // 显式调用 wsClient.disconnect() 确保 SDK 内部资源(定时器、队列等)完全释放。\n wsClient.on(\"event.disconnected_event\", async () => {\n const errorMsg = `Kicked by server: a new connection was established elsewhere. Auto-restart is suppressed to avoid mutual kicking. Please check for duplicate instances.`;\n runtime.error?.(`[${account.accountId}] ${errorMsg}`);\n wsClient.disconnect();\n await cleanup();\n setStatus?.({\n accountId: account.accountId,\n running: false,\n lastError: errorMsg,\n lastStopAt: Date.now(),\n });\n // Promise 保持 pending,不触发 auto-restart\n });\n\n // 监听重连事件\n wsClient.on(\"reconnecting\", (attempt) => {\n runtime.log?.(`[${account.accountId}] Reconnecting attempt ${attempt}...`);\n });\n\n // 监听错误事件\n wsClient.on(\"error\", async (error) => {\n runtime.error?.(`[${account.accountId}] WebSocket error: ${error.message}`);\n\n if (error instanceof WSAuthFailureError) {\n // 认证失败重试次数用尽(SDK 层已重试 WS_MAX_AUTH_FAILURE_ATTEMPTS 次)。\n // 配置错误(如 botId/secret 无效),框架 auto-restart 也无法恢复。\n //\n // **不 reject/resolve Promise**——保持 pending 以阻止框架层 auto-restart。\n //\n // 为什么不能 reject/resolve:\n // - reject/resolve → 框架 auto-restart(最多 10 次)× SDK 重试(5 次)= 60 次无意义尝试\n // - 且 Health Monitor 每小时还会 resetRestartAttempts 再来一轮\n //\n // Promise pending 的安全性:同被踢下线场景\n // - store.tasks.has(id) = true → 阻止 Health Monitor 直接 startChannel\n // - 框架 stopChannel / config reload → abort handler 中 resolve() → 正常清理\n // - 用户修改配置后框架通过 reload 机制重新启动\n const errorMsg = `Auth failure attempts exhausted (${WS_MAX_AUTH_FAILURE_ATTEMPTS} attempts). Please check botId/secret configuration.`;\n runtime.error?.(`[${account.accountId}] ${errorMsg}`);\n wsClient.disconnect();\n await cleanup();\n setStatus?.({\n accountId: account.accountId,\n running: false,\n lastError: errorMsg,\n lastStopAt: Date.now(),\n });\n return;\n }\n\n if (error instanceof WSReconnectExhaustedError) {\n // 网络断线重连次数用尽(SDK 层已重试 WS_MAX_RECONNECT_ATTEMPTS 次)。\n // 通常是网络/服务端问题,框架 auto-restart 可能恢复。\n //\n // reject Promise → 框架 auto-restart 介入(最多 MAX_RESTART_ATTEMPTS=10 次)\n // 总连接尝试次数 = (1 首次 + WS_MAX_RECONNECT_ATTEMPTS 重连) × (1 首轮 + 10 auto-restart)\n // = 11 × 11 = 121 次\n //\n // 如果 Health Monitor 介入(每 5 分钟检查),会 resetRestartAttempts 重新计数,\n // 受限于 DEFAULT_MAX_RESTARTS_PER_HOUR=10,每小时最多额外 10 × 121 = 1210 次。\n // 但因网络断线通常是暂时性的,auto-restart + Health Monitor 的兜底机制是合理的。\n //\n // 显式调用 wsClient.disconnect() 确保 SDK 内部资源完全释放,\n // 避免旧实例的定时器/队列残留。\n wsClient.disconnect();\n cleanup().finally(() => reject(error));\n return;\n }\n });\n\n // 监听版本检查事件:收到 enter_check_update 时回复当前插件版本\n wsClient.on(EVENT_ENTER_CHECK_UPDATE as any, async (frame: WsFrame) => {\n try {\n // runtime.log?.(`[${account.accountId}] Received enter_check_update, replying with version=${PLUGIN_VERSION}`);\n await wsClient.reply(frame, { version: PLUGIN_VERSION }, CMD_ENTER_EVENT_REPLY);\n } catch (err) {\n // runtime.error?.(`[${account.accountId}] Failed to reply enter_check_update: ${String(err)}`);\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 // 监听所有事件回调(aibot_event_callback)。\n // 这里使用通用 event 监听,再按 eventtype 分发,兼容不同 SDK 版本在细分事件名上的差异。\n wsClient.on(\"event\", async (frame: WsFrame) => {\n try {\n const eventBody = frame.body as MessageBody;\n const eventType = eventBody.event?.eventtype;\n runtime.log?.(\n `[${account.accountId}] Received event callback: eventtype=${eventType ?? \"\"}, msgid=${eventBody.msgid ?? \"\"}`,\n );\n runtime.error?.(\n `[${account.accountId}] [diag] event-listener fired: eventtype=${eventType ?? \"\"}, msgid=${eventBody.msgid ?? \"\"}`,\n );\n\n if (eventType !== \"template_card_event\") {\n return;\n }\n\n const templateCardEvent = eventBody.event?.template_card_event;\n runtime.log?.(\n `[${account.accountId}] Received template_card_event: event_key=${templateCardEvent?.event_key ?? \"\"}, task_id=${templateCardEvent?.task_id ?? \"\"}`,\n );\n\n try {\n await updateTemplateCardOnEvent({\n frame,\n accountId: account.accountId,\n runtime,\n wsClient,\n });\n } catch (updateErr) {\n runtime.error?.(\n `[${account.accountId}] [template-card-update] Failed to update template card: ${String(updateErr)}`,\n );\n }\n\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 template_card_event: ${String(err)}`);\n }\n });\n\n runtime.log?.(`[${account.accountId}] Event listeners attached: message + event(template_card_event)`);\n runtime.error?.(`[${account.accountId}] [diag] listeners-ready marker`);\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 type { OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport { DEFAULT_ACCOUNT_ID } from \"./openclaw-compat.js\";\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 WeComConfig {\n enabled?: boolean;\n websocketUrl?: string;\n botId?: string;\n secret?: string;\n name?: string;\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 * 解析企业微信账户配置\n */\nexport function resolveWeComAccount(cfg: OpenClawConfig): ResolvedWeComAccount {\n const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {}) as WeComConfig;\n\n return {\n accountId: DEFAULT_ACCOUNT_ID,\n name: wecomConfig.name ?? \"企业微信\",\n enabled: wecomConfig.enabled ?? false,\n websocketUrl: wecomConfig.websocketUrl || DefaultWsUrl,\n botId: wecomConfig.botId ?? \"\",\n secret: wecomConfig.secret ?? \"\",\n sendThinkingMessage: wecomConfig.sendThinkingMessage ?? true,\n config: wecomConfig,\n };\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\nreturn {\n ...cfg,\n channels: {\n ...cfg.channels,\n [CHANNEL_ID]: merged,\n },\n };\n}\n","/**\n * 企业微信 setupWizard — 声明式 CLI setup wizard 配置。\n *\n * 框架通过 plugin.setupWizard 字段识别并驱动 channel 的引导配置流程。\n */\n\nimport type { ChannelSetupWizard, ChannelSetupDmPolicy } from \"openclaw/plugin-sdk/setup\";\nimport type { ChannelSetupAdapter } from \"openclaw/plugin-sdk/setup\";\nimport type { OpenClawConfig } from \"openclaw/plugin-sdk/core\";\nimport { addWildcardAllowFrom } from \"./openclaw-compat.js\";\nimport type { WeComConfig } from \"./utils.js\";\nimport { resolveWeComAccount, setWeComAccount } from \"./utils.js\";\nimport { CHANNEL_ID } from \"./const.js\";\n\n// ============================================================================\n// ChannelSetupAdapter — 框架用于应用配置输入的适配器\n// ============================================================================\n\nexport const wecomSetupAdapter: ChannelSetupAdapter = {\n applyAccountConfig: ({ cfg, input }) => {\n const patch: Partial<WeComConfig> = {};\n\n if (input.token !== undefined) {\n patch.botId = String(input.token).trim();\n }\n if (input.privateKey !== undefined) {\n patch.secret = String(input.privateKey).trim();\n }\n\n // 如果是首次配置,默认启用\n const account = resolveWeComAccount(cfg);\n if (!account.botId && !account.secret) {\n patch.enabled = true;\n }\n\n return setWeComAccount(cfg, patch);\n },\n};\n\n// ============================================================================\n// DM Policy 配置\n// ============================================================================\n\n/**\n * 设置企业微信 dmPolicy\n */\nfunction setWeComDmPolicy(\n cfg: OpenClawConfig,\n dmPolicy: \"pairing\" | \"allowlist\" | \"open\" | \"disabled\",\n): OpenClawConfig {\n const account = resolveWeComAccount(cfg);\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 setWeComAccount(cfg, {\n dmPolicy,\n allowFrom,\n });\n}\n\nconst dmPolicy: ChannelSetupDmPolicy = {\n label: \"企业微信\",\n channel: CHANNEL_ID,\n policyKey: `channels.${CHANNEL_ID}.dmPolicy`,\n allowFromKey: `channels.${CHANNEL_ID}.allowFrom`,\n getCurrent: (cfg) => {\n const account = resolveWeComAccount(cfg);\n return account.config.dmPolicy ?? \"open\";\n },\n setPolicy: (cfg, policy) => {\n return setWeComDmPolicy(cfg, policy);\n },\n promptAllowFrom: async ({ cfg, prompter }) => {\n const account = resolveWeComAccount(cfg);\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 setWeComAccount(cfg, { allowFrom });\n },\n};\n\n// ============================================================================\n// ChannelSetupWizard — 声明式 setup wizard 配置\n// ============================================================================\n\nexport const wecomSetupWizard: ChannelSetupWizard = {\n channel: CHANNEL_ID,\n\n // ── 状态 ──────────────────────────────────────────────────────────────\n status: {\n configuredLabel: \"已配置 ✓\",\n unconfiguredLabel: \"需要 Bot ID 和 Secret\",\n configuredHint: \"已配置\",\n unconfiguredHint: \"需要设置\",\n resolveConfigured: ({ cfg }) => {\n const account = resolveWeComAccount(cfg);\n return Boolean(account.botId?.trim() && account.secret?.trim());\n },\n resolveStatusLines: ({ cfg, configured }) => {\n return [`企业微信: ${configured ? \"已配置\" : \"需要 Bot ID 和 Secret\"}`];\n },\n },\n\n // ── 引导说明 ──────────────────────────────────────────────────────────\n introNote: {\n title: \"企业微信设置\",\n lines: [\n \"企业微信机器人需要以下配置信息:\",\n \"1. Bot ID: 企业微信机器人 ID\",\n \"2. Secret: 企业微信机器人密钥\",\n ],\n shouldShow: ({ cfg }) => {\n const account = resolveWeComAccount(cfg);\n return !account.botId?.trim() || !account.secret?.trim();\n },\n },\n\n // ── 凭据输入 ──────────────────────────────────────────────────────────\n credentials: [\n {\n inputKey: \"token\",\n providerHint: \"企业微信\",\n credentialLabel: \"Bot ID\",\n envPrompt: \"使用环境变量中的 Bot ID?\",\n keepPrompt: \"Bot ID 已配置,保留当前值?\",\n inputPrompt: \"企业微信机器人 Bot ID\",\n inspect: ({ cfg }) => {\n const account = resolveWeComAccount(cfg);\n const hasValue = Boolean(account.botId?.trim());\n return {\n accountConfigured: hasValue,\n hasConfiguredValue: hasValue,\n resolvedValue: account.botId || undefined,\n };\n },\n applySet: ({ cfg, resolvedValue }) => {\n return setWeComAccount(cfg, { botId: resolvedValue });\n },\n },\n {\n inputKey: \"privateKey\",\n providerHint: \"企业微信\",\n credentialLabel: \"Secret\",\n envPrompt: \"使用环境变量中的 Secret?\",\n keepPrompt: \"Secret 已配置,保留当前值?\",\n inputPrompt: \"企业微信机器人 Secret\",\n inspect: ({ cfg }) => {\n const account = resolveWeComAccount(cfg);\n const hasValue = Boolean(account.secret?.trim());\n return {\n accountConfigured: hasValue,\n hasConfiguredValue: hasValue,\n resolvedValue: account.secret || undefined,\n };\n },\n applySet: ({ cfg, resolvedValue }) => {\n return setWeComAccount(cfg, { secret: resolvedValue });\n },\n },\n ],\n\n // ── 完成后的最终处理 ──────────────────────────────────────────────────\n finalize: async ({ cfg }) => {\n // 确保配置完成后 channel 处于启用状态\n const account = resolveWeComAccount(cfg);\n if (account.botId?.trim() && account.secret?.trim() && !account.enabled) {\n return { cfg: setWeComAccount(cfg, { enabled: true }) };\n }\n return undefined;\n },\n\n // ── 完成提示 ──────────────────────────────────────────────────────────\n completionNote: {\n title: \"企业微信配置完成\",\n lines: [\n \"企业微信机器人已配置完成。\",\n \"运行 `openclaw start` 启动服务。\",\n ],\n shouldShow: ({ cfg }) => {\n const account = resolveWeComAccount(cfg);\n return Boolean(account.botId?.trim() && account.secret?.trim());\n },\n },\n\n // ── DM 策略 ──────────────────────────────────────────────────────────\n dmPolicy,\n\n // ── 禁用 ─────────────────────────────────────────────────────────────\n disable: (cfg) => {\n return setWeComAccount(cfg, { enabled: false });\n },\n};\n","import {\n type ChannelPlugin,\n type OpenClawConfig,\n} from \"openclaw/plugin-sdk/core\";\nimport type { ChannelStatusIssue } from \"openclaw/plugin-sdk/channel-contract\";\n\nimport { formatPairingApproveHint, DEFAULT_ACCOUNT_ID } from './openclaw-compat.js'\nimport { getWeComRuntime } from \"./runtime.js\";\nimport { monitorWeComProvider } from \"./monitor.js\";\nimport { getWeComWebSocket } from \"./state-manager.js\";\nimport { wecomSetupWizard, wecomSetupAdapter } from \"./onboarding.js\";\nimport type { WeComConfig, ResolvedWeComAccount } from \"./utils.js\";\nimport { resolveWeComAccount } 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 setupWizard: wecomSetupWizard,\n setup: wecomSetupAdapter,\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: () => [DEFAULT_ACCOUNT_ID],\n\n // 解析账户配置\n resolveAccount: (cfg) => resolveWeComAccount(cfg),\n\n // 获取默认账户 ID\n defaultAccountId: () => DEFAULT_ACCOUNT_ID,\n\n // 设置账户启用状态\n setAccountEnabled: ({cfg, enabled}) => {\n const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {}) as WeComConfig;\n return {\n ...cfg,\n channels: {\n ...cfg.channels,\n [CHANNEL_ID]: {\n ...wecomConfig,\n enabled,\n },\n },\n };\n },\n\n // 删除账户\n deleteAccount: ({cfg}) => {\n const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {}) as WeComConfig;\n const {botId, secret, ...rest} = wecomConfig;\n return {\n ...cfg,\n channels: {\n ...cfg.channels,\n [CHANNEL_ID]: rest,\n },\n };\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}) => {\n const account = resolveWeComAccount(cfg);\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 // 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 // const { groupPolicy } = resolveOpenProviderRuntimeGroupPolicy({\n // providerConfigPresent: true,\n // groupPolicy: account.config.groupPolicy,\n // defaultGroupPolicy,\n // });\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 --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,\n name: account.name,\n enabled: account.enabled,\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 setStatus: ctx.setStatus,\n });\n },\n logoutAccount: async ({cfg}) => {\n const nextCfg = {...cfg} as OpenClawConfig;\n const wecomConfig = (cfg.channels?.[CHANNEL_ID] ?? {}) as WeComConfig;\n const nextWecom = {...wecomConfig};\n let cleared = false;\n let changed = false;\n\n if (nextWecom.botId || nextWecom.secret) {\n delete nextWecom.botId;\n delete nextWecom.secret;\n cleared = true;\n changed = true;\n }\n\n if (changed) {\n if (Object.keys(nextWecom).length > 0) {\n nextCfg.channels = {...nextCfg.channels, [CHANNEL_ID]: nextWecom};\n } else {\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 }\n await getWeComRuntime().config.writeConfigFile(nextCfg);\n }\n\n const resolved = resolveWeComAccount(changed ? nextCfg : cfg);\n const loggedOut = !resolved.botId && !resolved.secret;\n\n return {cleared, envToken: false, loggedOut};\n },\n },\n};\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-compat.js\";\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/** 媒体下载请求超时时间(毫秒),base64 编码的媒体文件最大可达 ~27MB */\nexport const MEDIA_DOWNLOAD_TIMEOUT_MS = 120_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 * @returns 完整的 response.body 配置对象(至少包含 url 字段)\n */\nasync function fetchMcpConfig(category: string): Promise<Record<string, unknown>> {\n const wsClient = getWeComWebSocket(DEFAULT_ACCOUNT_ID);\n if (!wsClient) {\n throw new Error(\"WSClient 未连接,无法拉取 MCP 配置\");\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}\")`);\n return body as Record<string, unknown>;\n}\n\n/**\n * 获取指定品类的 MCP Server URL\n *\n * 优先从内存缓存中读取,未命中时通过 WSClient 拉取并缓存。\n *\n * @param category - MCP 品类名称\n * @returns MCP Server URL\n */\nasync function getMcpUrl(category: string): Promise<string> {\n // 查内存缓存\n const cached = mcpConfigCache.get(category);\n if (cached) return cached.url as string;\n\n // 缓存未命中,通过 WSClient 拉取\n const body = await fetchMcpConfig(category);\n\n // 写入缓存\n mcpConfigCache.set(category, body);\n\n console.log(`${LOG_TAG} getMcpUrl ${category}: ${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 timeoutMs: number = HTTP_REQUEST_TIMEOUT_MS,\n): Promise<{ response: Response; rpcResult: unknown; newSessionId: string | null }> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\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 请求超时 (${timeoutMs}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, category: string): Promise<McpSession> {\n const session: McpSession = { sessionId: null, initialized: false, stateless: false };\n\n console.log(`${LOG_TAG} 开始 initialize 握手 (category=\"${category}\")`);\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(category);\n mcpSessionCache.set(category, session);\n console.log(`${LOG_TAG} 无状态 Server 确认 (category=\"${category}\")`);\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(category, session);\n console.log(`${LOG_TAG} 有状态 Session 建立成功 (category=\"${category}\", 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, category: string): Promise<McpSession> {\n // 已确认为无状态的 Server,直接返回空 session 跳过握手\n if (statelessCategories.has(category)) {\n const cached = mcpSessionCache.get(category);\n if (cached) return cached;\n // 首次发现被清除(理论上不会走到这里),重新走握手探测\n }\n\n const cached = mcpSessionCache.get(category);\n if (cached?.initialized) return cached;\n\n // 防止并发重复初始化\n const inflight = inflightInitRequests.get(category);\n if (inflight) return inflight;\n\n const promise = initializeSession(url, category).finally(() => {\n inflightInitRequests.delete(category);\n });\n inflightInitRequests.set(category, 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 */\nexport function clearCategoryCache(category: string): void {\n console.log(`${LOG_TAG} 清理缓存 (category=\"${category}\")`);\n mcpConfigCache.delete(category);\n mcpSessionCache.delete(category);\n statelessCategories.delete(category);\n inflightInitRequests.delete(category);\n}\n\n/** tools/list 返回的工具描述 */\nexport interface McpToolInfo {\n name: string;\n description?: string;\n inputSchema?: Record<string, unknown>;\n}\n\n/** sendJsonRpc 的可选配置 */\nexport interface SendJsonRpcOptions {\n /** 自定义 HTTP 请求超时时间(毫秒),默认使用 HTTP_REQUEST_TIMEOUT_MS */\n timeoutMs?: number;\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 options - 可选配置(如自定义超时)\n * @returns JSON-RPC result\n */\nexport async function sendJsonRpc(\n category: string,\n method: string,\n params?: Record<string, unknown>,\n options?: SendJsonRpcOptions,\n): Promise<unknown> {\n const url = await getMcpUrl(category);\n const timeoutMs = options?.timeoutMs;\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, category);\n\n try {\n const { rpcResult, newSessionId } = await sendRawJsonRpc(url, session, body, timeoutMs);\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);\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}\"),开始重建...`);\n mcpSessionCache.delete(category);\n\n // 使用 rebuildSession 合并并发的 session 重建请求,避免竞态条件\n session = await rebuildSession(url, category);\n const { rpcResult, newSessionId } = await sendRawJsonRpc(url, session, body, timeoutMs);\n if (newSessionId) {\n session.sessionId = newSessionId;\n }\n return rpcResult;\n }\n\n // 其他错误记录日志后抛出\n console.error(`${LOG_TAG} RPC 请求失败 (category=\"${category}\", 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, category: string): Promise<McpSession> {\n const inflight = inflightInitRequests.get(category);\n if (inflight) return inflight;\n\n const promise = initializeSession(url, category).finally(() => {\n inflightInitRequests.delete(category);\n });\n inflightInitRequests.set(category, 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 * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { sendJsonRpc, clearCategoryCache, MEDIA_DOWNLOAD_TIMEOUT_MS, type McpToolInfo } from \"./transport.js\";\nimport { cleanSchemaForGemini } from \"./schema.js\";\nimport { getWeComRuntime } from \"../runtime.js\";\nimport { detectMime } from \"../openclaw-compat.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 /** 调用的 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): Promise<unknown> => {\n const result = await sendJsonRpc(category, \"tools/list\") 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 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): 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}\"),清理缓存`);\n clearCategoryCache(category);\n return;\n }\n } catch {\n // text 不是 JSON 格式,跳过\n }\n }\n};\n\n// ============================================================================\n// get_msg_media 响应拦截:base64 → 本地文件\n// ============================================================================\n\n/**\n * 拦截 get_msg_media 的 MCP 响应\n *\n * 核心逻辑:\n * 1. 从 MCP result 的 content[].text 中提取业务 JSON\n * 2. 提取 media_item.base64_data,解码为 Buffer\n * 3. 通过 openclaw SDK 的 saveMediaBuffer 保存到本地媒体目录\n * 4. 替换响应:移除 base64_data,加入 local_path\n *\n * 这样大模型只看到轻量的文件路径信息,不会被 base64 数据消耗 token。\n */\nasync function interceptMediaResponse(result: unknown): Promise<unknown> {\n const t0 = performance.now();\n\n // 1. 提取 MCP result 中的 content 数组\n const content = (result as Record<string, unknown>)?.content;\n if (!Array.isArray(content)) return result;\n\n const textItem = content.find(\n (c: Record<string, unknown>) => c.type === \"text\" && typeof c.text === \"string\",\n ) as { type: string; text: string } | undefined;\n if (!textItem) return result;\n\n // 2. 解析业务 JSON\n let bizData: Record<string, unknown>;\n try {\n bizData = JSON.parse(textItem.text) as Record<string, unknown>;\n } catch {\n // 非 JSON 格式,原样返回\n return result;\n }\n\n // 3. 校验业务响应:errcode !== 0 或无 media_item 时原样返回\n if (bizData.errcode !== 0) return result;\n\n const mediaItem = bizData.media_item as Record<string, unknown> | undefined;\n if (!mediaItem || typeof mediaItem.base64_data !== \"string\") return result;\n\n const base64Data = mediaItem.base64_data as string;\n const mediaName = mediaItem.name as string | undefined;\n const mediaType = mediaItem.type as string | undefined;\n const mediaId = mediaItem.media_id as string | undefined;\n\n const tParsed = performance.now();\n\n // 4. 解码 base64 → Buffer\n const buffer = Buffer.from(base64Data, \"base64\");\n const tDecoded = performance.now();\n\n // 5. 检测 contentType,并通过 saveMediaBuffer 保存到本地媒体目录\n const contentType = await detectMime({ buffer, filePath: mediaName }) ?? \"application/octet-stream\";\n const tMimeDetected = performance.now();\n\n // 企业微信聊天记录附件可达 20MB(文件消息上限),\n // 而 saveMediaBuffer 默认 maxBytes 为 5MB(针对 outbound 场景),\n // 此处显式放宽到 20MB 以支持大文件下载。\n const INBOUND_MAX_BYTES = 20 * 1024 * 1024; // 20MB\n\n const core = getWeComRuntime();\n const saved = await core.channel.media.saveMediaBuffer(\n buffer,\n contentType,\n \"inbound\",\n INBOUND_MAX_BYTES, // maxBytes: 放宽到 20MB,匹配企业微信文件消息上限\n mediaName, // originalFilename: 保留原始文件名\n );\n\n // 5.1 补偿:核心库 EXT_BY_MIME 可能缺少某些格式映射(如 audio/amr),\n // 导致保存的文件没有后缀。此处检测并修复。\n const MIME_EXT_PATCH: Record<string, string> = {\n \"audio/amr\": \".amr\",\n };\n const patchExt = MIME_EXT_PATCH[contentType];\n if (patchExt && !path.extname(saved.path)) {\n const newPath = saved.path + patchExt;\n try {\n await fs.rename(saved.path, newPath);\n saved.path = newPath;\n } catch {\n // rename 失败不影响主流程,文件仍可用\n }\n }\n\n const tSaved = performance.now();\n\n // 6. 构造精简响应,移除 base64_data,加入本地路径\n const newBizData = {\n errcode: 0,\n errmsg: \"ok\",\n media_item: {\n media_id: mediaId,\n name: mediaName ?? saved.path.split(\"/\").pop(),\n type: mediaType,\n local_path: saved.path,\n size: buffer.length,\n content_type: saved.contentType,\n },\n };\n\n const tEnd = performance.now();\n\n // 耗时日志:各环节耗时(ms)\n console.log(\n `[mcp] get_msg_media 拦截成功: media_id=${mediaId ?? \"unknown\"}, ` +\n `type=${mediaType ?? \"unknown\"}, size=${buffer.length}, saved=${saved.path}\\n` +\n ` ⏱ 耗时明细 (总 ${(tEnd - t0).toFixed(1)}ms):\\n` +\n ` 解析响应 JSON: ${(tParsed - t0).toFixed(1)}ms\\n` +\n ` base64 解码: ${(tDecoded - tParsed).toFixed(1)}ms (${(base64Data.length / 1024).toFixed(0)}KB base64 → ${(buffer.length / 1024).toFixed(0)}KB buffer)\\n` +\n ` MIME 检测: ${(tMimeDetected - tDecoded).toFixed(1)}ms (${contentType})\\n` +\n ` saveMediaBuffer: ${(tSaved - tMimeDetected).toFixed(1)}ms\\n` +\n ` 构造响应: ${(tEnd - tSaved).toFixed(1)}ms`,\n );\n\n // 7. 返回修改后的 MCP result 结构\n return {\n content: [{\n type: \"text\" as const,\n text: JSON.stringify(newBizData),\n }],\n };\n}\n\n// ============================================================================\n// call 操作:调用某品类的某个 MCP 工具\n// ============================================================================\n\nconst handleCall = async (\n category: string,\n method: string,\n args: Record<string, unknown>,\n): Promise<unknown> => {\n const callStart = performance.now();\n\n // get_msg_media 使用延长的超时时间(120s),因为返回的 base64 数据可达 ~27MB\n const options = method === \"get_msg_media\" ? { timeoutMs: MEDIA_DOWNLOAD_TIMEOUT_MS } : undefined;\n\n const result = await sendJsonRpc(category, \"tools/call\", {\n name: method,\n arguments: args,\n }, options);\n\n const rpcDone = performance.now();\n const rpcMs = (rpcDone - callStart).toFixed(1);\n\n // 检查业务层错误码,必要时清理缓存\n checkBizErrorAndClearCache(result, category);\n\n // 对 get_msg_media 响应进行 base64 拦截:解码存本地,只返回路径给大模型\n if (method === \"get_msg_media\") {\n const intercepted = await interceptMediaResponse(result);\n const totalMs = (performance.now() - callStart).toFixed(1);\n console.log(\n `[mcp] handleCall ${category}/${method} 总耗时: ${totalMs}ms` +\n ` (MCP请求: ${rpcMs}ms, 拦截处理: ${(performance.now() - rpcDone).toFixed(1)}ms)`,\n );\n return intercepted;\n }\n\n console.log(`[mcp] handleCall ${category}/${method} 耗时: ${rpcMs}ms`);\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 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));\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));\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/core\";\nimport { emptyPluginConfigSchema } from \"./src/openclaw-compat.js\";\nimport { wecomPlugin } from \"./src/channel.js\";\nimport { createWeComMcpTool } from \"./src/mcp\";\nimport { setWeComRuntime } from \"./src/runtime.js\";\nimport { CHANNEL_ID } from \"./src/const.js\";\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 // 注入媒体发送指令和文件大小限制提示词(仅对企业微信 channel 生效)\n api.on(\"before_prompt_build\", (_event, ctx) => {\n // 只在企业微信 channel 的会话中注入,避免影响其他 channel 插件\n if (ctx?.channelId !== CHANNEL_ID) {\n return;\n }\n return {\n appendSystemContext: [\n \"重要:涉及发送图片/视频/语音/文件给用户时,请务必使用 `MEDIA:` 指令。详见 wecom-send-media 这个 skill(技能)。\",\n \"重要:当需要向用户发送结构化卡片消息(如通知、投票、按钮选择等)时,请在回复中直接输出 JSON 代码块(```json ... ```),其中 card_type 字段标明卡片类型。详见 wecom-send-template-card 技能。\"\n ].join(\"\\n\"),\n };\n });\n },\n};\n\nexport default plugin;\n"],"names":["exports","path","fs","os","fileURLToPath","resolveStateDir","generateReqId","fileTypeFromBuffer","dirname","resolve","readFileSync","WSClient","WSAuthFailureError","WSReconnectExhaustedError"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;AAQG;AAOI,MAAM,kBAAkB,GAAG,SAAS;AAoC3C,MAAM,SAAS,GAAwB,OAAO,0BAA0B;AACrE,KAAA,IAAI,CAAC,CAAC,GAAQ,KAAI;IACjB,MAAMA,SAAO,GAAe,EAAE;AAC9B,IAAA,IAAI,OAAO,GAAG,CAAC,wBAAwB,KAAK,UAAU,EAAE;AACtD,QAAAA,SAAO,CAAC,wBAAwB,GAAG,GAAG,CAAC,wBAAwB;IACjE;AACA,IAAA,IAAI,OAAO,GAAG,CAAC,UAAU,KAAK,UAAU,EAAE;AACxC,QAAAA,SAAO,CAAC,UAAU,GAAG,GAAG,CAAC,UAAU;IACrC;AACA,IAAA,IAAI,OAAO,GAAG,CAAC,yBAAyB,KAAK,UAAU,EAAE;AACvD,QAAAA,SAAO,CAAC,yBAAyB,GAAG,GAAG,CAAC,yBAAyB;IACnE;AACA,IAAA,IAAI,OAAO,GAAG,CAAC,oBAAoB,KAAK,UAAU,EAAE;AAClD,QAAAA,SAAO,CAAC,oBAAoB,GAAG,GAAG,CAAC,oBAAoB;IACzD;AACA,IAAA,OAAOA,SAAO;AAChB,CAAC;KACA,KAAK,CAAC,MAAK;;AAEV,IAAA,OAAO,EAAgB;AACzB,CAAC,CAAC;AAEJ;AACA,IAAI,2BAA4E;AAE1C,OAAO,2BAA2B;AACrE,KAAA,IAAI,CAAC,CAAC,GAAQ,KAAI;AACjB,IAAA,IAAI,OAAO,GAAG,CAAC,oBAAoB,KAAK,UAAU,EAAE;AAClD,QAAA,2BAA2B,GAAG,GAAG,CAAC,oBAAoB;IACxD;AACF,CAAC;AACA,KAAA,KAAK,CAAC,MAAK,EAA8B,CAAC;AAE7C;AACA,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,KAAI;AACrB,IAAA,IAAI,CAAC,2BAA2B,IAAI,GAAG,CAAC,oBAAoB,EAAE;AAC5D,QAAA,2BAA2B,GAAG,GAAG,CAAC,oBAAoB;IACxD;AACF,CAAC,CAAC;AAEF;AACA;AACA;AAEA,MAAM,WAAW,GAA2B;AAC1C,IAAA,OAAO,EAAE,YAAY;AACrB,IAAA,OAAO,EAAE,YAAY;AACrB,IAAA,MAAM,EAAE,YAAY;AACpB,IAAA,OAAO,EAAE,YAAY;AACrB,IAAA,MAAM,EAAE,WAAW;AACnB,IAAA,OAAO,EAAE,YAAY;AACrB,IAAA,MAAM,EAAE,WAAW;AACnB,IAAA,MAAM,EAAE,WAAW;AACnB,IAAA,MAAM,EAAE,YAAY;AACpB,IAAA,MAAM,EAAE,aAAa;AACrB,IAAA,MAAM,EAAE,WAAW;AACnB,IAAA,MAAM,EAAE,iBAAiB;AACzB,IAAA,MAAM,EAAE,iBAAiB;AACzB,IAAA,OAAO,EAAE,kBAAkB;AAC3B,IAAA,MAAM,EAAE,iBAAiB;AACzB,IAAA,KAAK,EAAE,kBAAkB;AACzB,IAAA,MAAM,EAAE,mBAAmB;AAC3B,IAAA,KAAK,EAAE,6BAA6B;AACpC,IAAA,MAAM,EAAE,qBAAqB;AAC7B,IAAA,MAAM,EAAE,oBAAoB;AAC5B,IAAA,MAAM,EAAE,0BAA0B;AAClC,IAAA,MAAM,EAAE,+BAA+B;AACvC,IAAA,OAAO,EAAE,yEAAyE;AAClF,IAAA,OAAO,EAAE,mEAAmE;AAC5E,IAAA,OAAO,EAAE,2EAA2E;AACpF,IAAA,MAAM,EAAE,UAAU;AAClB,IAAA,MAAM,EAAE,YAAY;AACpB,IAAA,KAAK,EAAE,eAAe;AACtB,IAAA,MAAM,EAAE,WAAW;AACnB,IAAA,MAAM,EAAE,WAAW;AACnB,IAAA,MAAM,EAAE,WAAW;AACnB,IAAA,OAAO,EAAE,YAAY;AACrB,IAAA,MAAM,EAAE,iBAAiB;AACzB,IAAA,MAAM,EAAE,WAAW;AACnB,IAAA,MAAM,EAAE,eAAe;CACxB;AAED;AACA,eAAe,mBAAmB,CAAC,MAAc,EAAA;AAC/C,IAAA,IAAI;QACF,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,OAAO,WAAW,CAAC;AACxD,QAAA,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC;AAC7C,QAAA,OAAO,IAAI,EAAE,IAAI,IAAI,SAAS;IAChC;AAAE,IAAA,MAAM;AACN,QAAA,OAAO,SAAS;IAClB;AACF;AAEA;AACA,eAAe,kBAAkB,CAAC,IAAuB,EAAA;IACvD,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,GAAGC,eAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,GAAG,SAAS;AACjF,IAAA,MAAM,OAAO,GAAG,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,SAAS;AAElD,IAAA,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,SAAS;AAEhF,IAAA,MAAM,SAAS,GAAG,CAAC,CAAU,KAC3B,CAAC,CAAC,IAAI,CAAC,KAAK,0BAA0B,IAAI,CAAC,KAAK,iBAAiB;AAEnE,IAAA,IAAI,OAAO,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AAChD,QAAA,OAAO,OAAO;IAChB;IACA,IAAI,OAAO,EAAE;AACX,QAAA,OAAO,OAAO;IAChB;IACA,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE;IACzE,IAAI,UAAU,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE;AACxC,QAAA,OAAO,UAAU;IACnB;IACA,IAAI,OAAO,EAAE;AACX,QAAA,OAAO,OAAO;IAChB;IACA,IAAI,UAAU,EAAE;AACd,QAAA,OAAO,UAAU;IACnB;AACA,IAAA,OAAO,SAAS;AAClB;AAEA;;;;;;;;AAQG;AACI,eAAe,UAAU,CAC9B,YAAwC,EAAA;AAExC,IAAA,MAAM,GAAG,GAAG,MAAM,SAAS;AAE3B,IAAA,MAAM,IAAI,GAAsB,MAAM,CAAC,QAAQ,CAAC,YAAY;AAC1D,UAAE,EAAE,MAAM,EAAE,YAAY;UACtB,YAAY;AAEhB,IAAA,IAAI,GAAG,CAAC,UAAU,EAAE;AAClB,QAAA,IAAI;AACF,YAAA,OAAO,MAAM,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;QACnC;AAAE,QAAA,MAAM;;QAER;IACF;AACA,IAAA,OAAO,kBAAkB,CAAC,IAAI,CAAC;AACjC;AAEA;AACA;AACA;AAEA;AACA,eAAe,uBAAuB,CACpC,SAAiB,EACjB,UAAyC,EAAA;IAEzC,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE;AAC1C,QAAA,MAAM,IAAI,KAAK,CAAC,uDAAuD,SAAS,CAAA,CAAE,CAAC;IACrF;AAEA,IAAA,IAAI,QAAgB;AACpB,IAAA,IAAI;QACF,QAAQ,GAAG,MAAMC,aAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;IACzC;AAAE,IAAA,MAAM;AACN,QAAA,QAAQ,GAAGD,eAAI,CAAC,OAAO,CAAC,SAAS,CAAC;IACpC;AAEA,IAAA,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE;AAC7B,QAAA,IAAI,YAAoB;AACxB,QAAA,IAAI;YACF,YAAY,GAAG,MAAMC,aAAE,CAAC,QAAQ,CAAC,IAAI,CAAC;QACxC;AAAE,QAAA,MAAM;AACN,YAAA,YAAY,GAAGD,eAAI,CAAC,OAAO,CAAC,IAAI,CAAC;QACnC;QACA,IAAI,YAAY,KAAKA,eAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE;YAClD;QACF;AACA,QAAA,IAAI,QAAQ,KAAK,YAAY,IAAI,QAAQ,CAAC,UAAU,CAAC,YAAY,GAAGA,eAAI,CAAC,GAAG,CAAC,EAAE;YAC7E;QACF;IACF;AAEA,IAAA,MAAM,IAAI,KAAK,CAAC,uDAAuD,SAAS,CAAA,CAAE,CAAC;AACrF;AAEA;AACA,eAAe,gBAAgB,CAC7B,GAAW,EACX,QAAiB,EAAA;AAEjB,IAAA,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AACpD,IAAA,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE;AACX,QAAA,MAAM,IAAI,KAAK,CAAC,CAAA,2BAAA,EAA8B,GAAG,CAAA,OAAA,EAAU,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,CAAA,CAAE,CAAC;IAC5F;AAEA,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC;IACnD,IAAI,QAAQ,IAAI,MAAM,CAAC,MAAM,GAAG,QAAQ,EAAE;AACxC,QAAA,MAAM,IAAI,KAAK,CAAC,CAAA,WAAA,EAAc,GAAG,CAAA,mBAAA,EAAsB,MAAM,CAAC,MAAM,CAAA,GAAA,EAAM,QAAQ,CAAA,CAAA,CAAG,CAAC;IACxF;IAEA,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE;AAE3E,IAAA,IAAI,QAA4B;IAChC,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;IAC1D,IAAI,WAAW,EAAE;QACf,MAAM,KAAK,GAAG,2CAA2C,CAAC,IAAI,CAAC,WAAW,CAAC;AAC3E,QAAA,IAAI,KAAK,GAAG,CAAC,CAAC,EAAE;AACd,YAAA,IAAI;gBACF,QAAQ,GAAGA,eAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACpF;AAAE,YAAA,MAAM;gBACN,QAAQ,GAAGA,eAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YAChE;QACF;IACF;IACA,IAAI,CAAC,QAAQ,EAAE;AACb,QAAA,IAAI;AACF,YAAA,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC;YAC3B,MAAM,IAAI,GAAGA,eAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC;AAC3C,YAAA,IAAI,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,QAAQ,GAAG,IAAI;QACjD;AAAE,QAAA,MAAM,eAAe;IACzB;AAEA,IAAA,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,IAAI,GAAG,EAAE,CAAC;AAE/F,IAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE;AAC1C;AAEA;AACA,SAAS,eAAe,CAAC,CAAS,EAAA;AAChC,IAAA,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;AACrB,QAAA,OAAOA,eAAI,CAAC,IAAI,CAACE,aAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5C;AACA,IAAA,OAAO,CAAC;AACV;AAEA;AACA,eAAe,gCAAgC,CAC7C,QAAgB,EAChB,UAAoC,EAAE,EAAA;AAEtC,IAAA,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,OAAO;;IAG7C,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;;AAGpD,IAAA,IAAI,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE;AAClC,QAAA,IAAI;AACF,YAAA,QAAQ,GAAGC,sBAAa,CAAC,QAAQ,CAAC;QACpC;AAAE,QAAA,MAAM;AACN,YAAA,MAAM,IAAI,KAAK,CAAC,wBAAwB,QAAQ,CAAA,CAAE,CAAC;QACrD;IACF;;AAGA,IAAA,IAAI,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;QAClC,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC;QAC1D,OAAO;YACL,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B;IACH;;AAGA,IAAA,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;AAC5B,QAAA,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC;IACtC;;AAGA,IAAA,MAAM,uBAAuB,CAAC,QAAQ,EAAE,eAAe,CAAC;;AAGxD,IAAA,IAAI,IAAY;AAChB,IAAA,IAAI;QACF,MAAM,IAAI,GAAG,MAAMF,aAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;AACpC,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE;AAClB,YAAA,MAAM,IAAI,KAAK,CAAC,mCAAmC,QAAQ,CAAA,CAAE,CAAC;QAChE;QACA,IAAI,GAAG,MAAMA,aAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;IACpC;IAAE,OAAO,GAAQ,EAAE;AACjB,QAAA,IAAI,GAAG,EAAE,IAAI,KAAK,QAAQ,EAAE;AAC1B,YAAA,MAAM,IAAI,KAAK,CAAC,+BAA+B,QAAQ,CAAA,CAAE,CAAC;QAC5D;AACA,QAAA,MAAM,GAAG;IACX;IAEA,IAAI,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,QAAQ,EAAE;QACtC,MAAM,IAAI,KAAK,CAAC,CAAA,8BAAA,EAAiC,IAAI,CAAC,MAAM,CAAA,GAAA,EAAM,QAAQ,CAAA,CAAA,CAAG,CAAC;IAChF;AAEA,IAAA,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;IAC3E,MAAM,QAAQ,GAAGD,eAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,SAAS;IAErD,OAAO;AACL,QAAA,MAAM,EAAE,IAAI;AACZ,QAAA,WAAW,EAAE,IAAI;QACjB,QAAQ;KACT;AACH;AAEA;;;;;AAKG;AACI,eAAe,wBAAwB,CAC5C,QAAgB,EAChB,UAAoC,EAAE,EAAA;AAEtC,IAAA,MAAM,GAAG,GAAG,MAAM,SAAS;AAE3B,IAAA,IAAI,GAAG,CAAC,wBAAwB,EAAE;QAChC,OAAO,GAAG,CAAC,wBAAwB,CAAC,QAAQ,EAAE,OAAO,CAAC;IACxD;AACA,IAAA,OAAO,gCAAgC,CAAC,QAAQ,EAAE,OAAO,CAAC;AAC5D;AAEA;AACA;AACA;AAEA;AACA,SAAS,4BAA4B,CAAC,SAAmB,EAAA;AACvD,IAAA,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AAC3B,QAAA,OAAO,SAAS;IAClB;AACA,IAAA,OAAO,CAAC,GAAG,SAAS,EAAE,GAAG,CAAC;AAC5B;AAEA;;;;;;;;AAQG;AACG,SAAU,oBAAoB,CAAC,SAAmB,EAAA;IACtD,IAAI,2BAA2B,EAAE;AAC/B,QAAA,IAAI;AACF,YAAA,OAAO,2BAA2B,CAAC,SAAS,CAAC;QAC/C;AAAE,QAAA,MAAM;;QAER;IACF;AACA,IAAA,OAAO,4BAA4B,CAAC,SAAS,CAAC;AAChD;AAEA;AACA;AACA;AAEA;AACA,SAASI,iBAAe,GAAA;AACtB,IAAA,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE;AACtG,IAAA,IAAI,aAAa;AAAE,QAAA,OAAO,aAAa;IACvC,OAAOJ,eAAI,CAAC,IAAI,CAACE,aAAE,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC;AAC7C;AAEA;;;;AAIG;AACI,eAAe,yBAAyB,GAAA;AAC7C,IAAA,MAAM,GAAG,GAAG,MAAM,SAAS;AAE3B,IAAA,IAAI,GAAG,CAAC,yBAAyB,EAAE;AACjC,QAAA,IAAI;AACF,YAAA,OAAO,GAAG,CAAC,yBAAyB,EAAE;QACxC;AAAE,QAAA,MAAM;;QAER;IACF;;IAGA,MAAM,QAAQ,GAAGF,eAAI,CAAC,OAAO,CAACI,iBAAe,EAAE,CAAC;IAChD,OAAO;AACL,QAAAJ,eAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC;AAC5B,QAAAA,eAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC;AAC7B,QAAAA,eAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC;AAChC,QAAAA,eAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC;KACjC;AACH;SAEgB,uBAAuB,GAAA;IACrC,OAAO;AACL,QAAA,IAAI,EAAE,QAAQ;AACd,QAAA,oBAAoB,EAAE,KAAK;AAC3B,QAAA,UAAU,EAAE,EAAE;KACf;AACH;AAsEA;;;;AAIG;AACG,SAAU,wBAAwB,CAAC,SAAiB,EAAA;AACxD,IAAA,MAAM,OAAO,GAAG,CAAA,sBAAA,EAAyB,SAAS,EAAE;AACpD,IAAA,MAAM,UAAU,GAAG,CAAA,yBAAA,EAA4B,SAAS,SAAS;AACjE,IAAA,OAAO,KAAK,SAAS,CAAA,oBAAA,EAAuB,OAAO,CAAA,GAAA,EAAM,UAAU,GAAG;AACxE;;AC7gBA,IAAI,OAAO,GAAyB,IAAI;AAElC,SAAU,eAAe,CAAC,CAAgB,EAAA;IAC9C,OAAO,GAAG,CAAC;AACb;SAEgB,eAAe,GAAA;IAC7B,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC;IAC1E;AACA,IAAA,OAAO,OAAO;AAChB;;ACbA;;AAEG;AAEH;;AAEG;AACI,MAAM,UAAU,GAAG,OAAgB;AAE1C;;AAEG;AACH,IAAY,YASX;AATD,CAAA,UAAY,YAAY,EAAA;;AAEtB,IAAA,YAAA,CAAA,WAAA,CAAA,GAAA,iBAA6B;;AAE7B,IAAA,YAAA,CAAA,MAAA,CAAA,GAAA,MAAa;;AAEb,IAAA,YAAA,CAAA,gBAAA,CAAA,GAAA,gBAAiC;;AAEjC,IAAA,YAAA,CAAA,gBAAA,CAAA,GAAA,gBAAiC;AACnC,CAAC,EATW,YAAY,KAAZ,YAAY,GAAA,EAAA,CAAA,CAAA;AAWxB;AACA;AACA;AAEA;AACO,MAAM,yBAAyB,GAAG,KAAM;AAE/C;AACO,MAAM,wBAAwB,GAAG,KAAM;AAE9C;AACO,MAAM,qBAAqB,GAAG,KAAM;AAK3C;AACO,MAAM,wBAAwB,GAAG,KAAM;AAE9C;AACO,MAAM,yBAAyB,GAAG,EAAE;AAE3C;AACO,MAAM,4BAA4B,GAAG,CAAC;AAE7C;AACA;AACA;AAEA;AACO,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;AAElD;AACO,MAAM,iCAAiC,GAAG,KAAM;AAEvD;AACO,MAAM,sBAAsB,GAAG,GAAG;AAEzC;AACA;AACA;AAEA;AACO,MAAM,gBAAgB,GAAG,iBAAiB;AAEjD;AACO,MAAM,uBAAuB,GAAG,eAAe;AAEtD;AACO,MAAM,0BAA0B,GAAG,kBAAkB;AAC5D;AACA;AACA;AAEA;AACA;AACA;AAEA;AACO,MAAM,kBAAkB,GAAG,sBAAsB;AAExD;AACO,MAAM,2BAA2B,GAAG,KAAM;AAEjD;AACA;AACA;AAEA;AACO,MAAM,oBAAoB,GAAG,CAAC;AAErC;AACO,MAAM,gBAAgB,GAAG,IAAI;AAEpC;AACA;AACA;AAEA;AACO,MAAM,eAAe,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI;AAE/C;AACO,MAAM,eAAe,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI;AAE/C;AACO,MAAM,eAAe,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI;AAE9C;AACO,MAAM,cAAc,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI;AAE9C;AACO,MAAM,kBAAkB,GAAG,cAAc;AAKhD;AACA;AACA;AAEA;AACO,MAAM,wBAAwB,GAAG,0BAA0B;AAElE;AACO,MAAM,qBAAqB,GAAG,yBAAyB;AAE9D;AACA;AACA;AAEA;AACO,MAAM,oBAAoB,GAAG,CAAC;AAErC;AACA;AACA;AAEA;AACO,MAAM,gBAAgB,GAAa;IACxC,aAAa;IACb,aAAa;IACb,oBAAoB;IACpB,kBAAkB;IAClB,sBAAsB;CACvB;;ACnJD;;;;AAIG;AA4EH;AACA;AACA;AAEA;;;;AAIG;AACH,SAAS,0BAA0B,CAAC,IAAiB,EAAA;AACnD,IAAA,MAAM,iBAAiB,GAAG,IAAI,CAAC,KAAK,EAAE,mBAAmB;AACzD,IAAA,IACE,IAAI,CAAC,OAAO,KAAK,OAAO;AACxB,QAAA,IAAI,CAAC,KAAK,EAAE,SAAS,KAAK,qBAAqB;QAC/C,CAAC,iBAAiB,EAClB;AACA,QAAA,OAAO,SAAS;IAClB;IAEA,MAAM,aAAa,GAAG,iBAAiB,CAAC,cAAc,EAAE,aAAa,IAAI,EAAE;IAC3E,MAAM,aAAa,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,KAAI;QAC/C,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,kBAAkB;AACnE,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE;QACnE,OAAO,CAAA,EAAA,EAAK,WAAW,CAAA,EAAA,EAAK,SAAS,CAAC,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,CAAA,CAAE;AACrF,IAAA,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,EAAE;IAC5C,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,EAAE;AAC5C,IAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,YAAY;IAE1C,OAAO;QACL,cAAc;QACd,CAAA,qCAAA,CAAuC;AACvC,QAAA,IAAI,CAAC,KAAK,GAAG,CAAA,cAAA,EAAiB,IAAI,CAAC,KAAK,CAAA,CAAE,GAAG,SAAS;AACtD,QAAA,IAAI,CAAC,OAAO,GAAG,CAAA,iBAAA,EAAoB,IAAI,CAAC,OAAO,CAAA,CAAE,GAAG,SAAS;AAC7D,QAAA,IAAI,CAAC,QAAQ,GAAG,CAAA,iBAAA,EAAoB,IAAI,CAAC,QAAQ,CAAA,CAAE,GAAG,SAAS;QAC/D,MAAM,GAAG,CAAA,gBAAA,EAAmB,MAAM,CAAA,CAAE,GAAG,SAAS;QAChD,YAAY,GAAG,CAAA,oBAAA,EAAuB,YAAY,CAAA,CAAE,GAAG,SAAS;QAChE,YAAY,GAAG,CAAA,qBAAA,EAAwB,YAAY,CAAA,CAAE,GAAG,SAAS;QACjE,YAAY,GAAG,CAAA,uBAAA,EAA0B,YAAY,CAAA,CAAE,GAAG,SAAS;AACnE,QAAA,iBAAiB,CAAC,SAAS,GAAG,CAAA,iBAAA,EAAoB,iBAAiB,CAAC,SAAS,CAAA,CAAE,GAAG,SAAS;AAC3F,QAAA,iBAAiB,CAAC,SAAS,GAAG,CAAA,mBAAA,EAAsB,iBAAiB,CAAC,SAAS,CAAA,CAAE,GAAG,SAAS;AAC7F,QAAA,iBAAiB,CAAC,OAAO,GAAG,CAAA,gBAAA,EAAmB,iBAAiB,CAAC,OAAO,CAAA,CAAE,GAAG,SAAS;QACtF,aAAa,CAAC,MAAM,GAAG,CAAC,GAAG,sBAAsB,GAAG,yBAAyB;AAC7E,QAAA,GAAG,aAAa;AACjB;SACE,MAAM,CAAC,CAAC,IAAI,KAAqB,OAAO,CAAC,IAAI,CAAC;SAC9C,IAAI,CAAC,IAAI,CAAC;AACf;AAEA;;;AAGG;AACG,SAAU,mBAAmB,CAAC,IAAiB,EAAA;IACnD,MAAM,SAAS,GAAa,EAAE;IAC9B,MAAM,SAAS,GAAa,EAAE;AAC9B,IAAA,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB;IAC9C,MAAM,QAAQ,GAAa,EAAE;AAC7B,IAAA,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB;AAC7C,IAAA,IAAI,YAAgC;;AAIpC,IAAA,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO,EAAE;AAC5B,QAAA,MAAM,SAAS,GAAG,0BAA0B,CAAC,IAAI,CAAC;QAClD,IAAI,SAAS,EAAE;AACb,YAAA,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC;QAC3B;AACA,QAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE;IACpF;;AAGA,IAAA,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO,IAAI,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE;QACpD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE;AACtC,YAAA,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE;gBACjD,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;YACnC;AAAO,iBAAA,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO,IAAI,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE;gBACtD,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;AAC9B,gBAAA,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;AACrB,oBAAA,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;gBACrD;YACF;QACF;IACF;SAAO;;AAEL,QAAA,IAAI,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE;YACtB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;QACnC;;AAEA,QAAA,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE;YACnD,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;QACpC;AACA,QAAA,IAAI,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE;YACnB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;AAC9B,YAAA,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;AACrB,gBAAA,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YACrD;QACF;;AAEA,QAAA,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE;YAC7C,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AAC5B,YAAA,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;AACpB,gBAAA,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;YAClD;QACF;IACF;;AAGA,IAAA,IAAI,IAAI,CAAC,KAAK,EAAE;AACd,QAAA,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE;YAC7D,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO;QACxC;AAAO,aAAA,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,KAAK,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE;YACtE,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO;QACzC;AAAO,aAAA,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,KAAK,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE;;YAElE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;YACpC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE;AAC3B,gBAAA,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC;YACjE;QACF;AAAO,aAAA,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE;;YAEhE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;YAClC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE;AAC1B,gBAAA,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;YAC9D;QACF;IACF;AAEA,IAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE;AACpF;;AClNA;;;;AAIG;AAEH;;;;;;;AAOG;SACa,WAAW,CACzB,OAAmB,EACnB,SAAiB,EACjB,OAAgB,EAAA;AAEhB,IAAA,IAAI,SAAS,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE;AACjD,QAAA,OAAO,OAAO;IAChB;AAEA,IAAA,IAAI,SAAwC;IAE5C,MAAM,cAAc,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,KAAI;AACtD,QAAA,SAAS,GAAG,UAAU,CAAC,MAAK;YAC1B,MAAM,CAAC,IAAI,YAAY,CAAC,OAAO,IAAI,CAAA,0BAAA,EAA6B,SAAS,CAAA,EAAA,CAAI,CAAC,CAAC;QACjF,CAAC,EAAE,SAAS,CAAC;AACf,IAAA,CAAC,CAAC;AAEF,IAAA,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,MAAK;QAC1D,YAAY,CAAC,SAAS,CAAC;AACzB,IAAA,CAAC,CAAC;AACJ;AAEA;;AAEG;AACG,MAAO,YAAa,SAAQ,KAAK,CAAA;AACrC,IAAA,WAAA,CAAY,OAAe,EAAA;QACzB,KAAK,CAAC,OAAO,CAAC;AACd,QAAA,IAAI,CAAC,IAAI,GAAG,cAAc;IAC5B;AACD;;AC5CD;;;;AAIG;AAOH;AACA;AACA;AAEA;AACO,MAAM,sBAAsB,GAAG,MAAM;AAE5C;;;;AAIG;AACG,MAAO,kBAAmB,SAAQ,KAAK,CAAA;AAE3C,IAAA,WAAA,CAAY,OAAgB,EAAA;AAC1B,QAAA,KAAK,CAAC,OAAO,IAAI,0CAA0C,sBAAsB,CAAA,CAAA,CAAG,CAAC;QAF9E,IAAA,CAAA,OAAO,GAAG,sBAAsB;AAGvC,QAAA,IAAI,CAAC,IAAI,GAAG,oBAAoB;IAClC;AACD;AAED;AACA;AACA;AAEA;;;;;AAKG;AACI,eAAe,cAAc,CAAC,MASpC,EAAA;AACC,IAAA,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,MAAM;IAE5F,IAAI,CAAC,IAAI,EAAE;AACT,QAAA,OAAO,EAAE;IACX;IAEA,MAAM,QAAQ,GAAG,gBAAgB,IAAIK,0BAAa,CAAC,QAAQ,CAAC;AAE5D,IAAA,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE;AACzB,QAAA,OAAO,CAAC,KAAK,GAAG,CAAA,iDAAA,CAAmD,CAAC;AACpE,QAAA,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC;IAC3C;AAEA,IAAA,MAAM,IAAI,GAAG,KAAK,CAAC,IAMlB;;;AAID,IAAA,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO,EAAE;;QAE5B,IAAI,CAAC,MAAM,EAAE;YACX,OAAO,CAAC,GAAG,GAAG,yEAAyE,QAAQ,CAAA,CAAE,CAAC;AAClG,YAAA,OAAO,QAAQ;QACjB;QAEA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM;QAC/C,IAAI,CAAC,MAAM,EAAE;AACX,YAAA,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC;QAC5D;AAEA,QAAA,MAAM,WAAW,CACf,QAAQ,CAAC,WAAW,CAAC,MAAM,EAAE;AAC3B,YAAA,OAAO,EAAE,UAAU;AACnB,YAAA,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;AAC5B,SAAA,CAAC,EACF,qBAAqB,EACrB,wCAAwC,QAAQ,CAAA,CAAA,CAAG,CACpD;QACD,OAAO,CAAC,GAAG,GAAG,CAAA,4CAAA,EAA+C,MAAM,CAAA,SAAA,EAAY,MAAM,CAAA,CAAE,CAAC;AACxF,QAAA,OAAO,QAAQ;IACjB;;;AAIA,IAAA,IAAI;QACF,MAAM,WAAW,CACf,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,EACnD,qBAAqB,EACrB,CAAA,+BAAA,EAAkC,QAAQ,CAAA,CAAA,CAAG,CAC9C;IACH;IAAE,OAAO,GAAQ,EAAE;;AAEjB,QAAA,MAAM,MAAM,GAAG,GAAG,EAAE,MAAM,IAAI,GAAG,EAAE,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC;AACzD,QAAA,IACE,GAAG,EAAE,OAAO,KAAK,sBAAsB;YACvC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,EAC/C;AACA,YAAA,MAAM,IAAI,kBAAkB,CAAC,MAAM,CAAC;QACtC;AACA,QAAA,MAAM,GAAG;IACX;IACA,OAAO,CAAC,GAAG,GAAG,CAAA,4BAAA,EAA+B,QAAQ,CAAA,SAAA,EAAY,MAAM,CAAA,CAAE,CAAC;AAE1E,IAAA,OAAO,QAAQ;AACjB;;ACxHA;;;;AAIG;AAWH;AACA;AACA;AAEA;;AAEG;AACH,eAAe,aAAa,CAAC,IAAY,EAAA;AACvC,IAAA,MAAM,IAAI,GAAG,MAAMC,2BAAkB,CAAC,IAAI,CAAC;IAC3C,OAAO,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,KAAK;AACjD;AAEA;;AAEG;AACH,eAAe,sBAAsB,CAAC,IAAY,EAAA;AAChD,IAAA,MAAM,IAAI,GAAG,MAAMA,2BAAkB,CAAC,IAAI,CAAC;IAC3C,IAAI,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;QACnC,OAAO,IAAI,CAAC,IAAI;IAClB;AACA,IAAA,OAAO,0BAA0B;AACnC;AAEA;AACA;AACA;AAEA;;AAEG;AACI,eAAe,qBAAqB,CAAC,MAO3C,EAAA;IACC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM;AACvD,IAAA,MAAM,IAAI,GAAG,eAAe,EAAE;IAC9B,MAAM,SAAS,GAAkD,EAAE;AAEnE,IAAA,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;AAChC,QAAA,IAAI;YACF,OAAO,CAAC,GAAG,GAAG,kCAAkC,QAAQ,CAAA,CAAE,CAAC;YAC3D,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,IAAI,oBAAoB;AAC9E,YAAA,MAAM,QAAQ,GAAG,UAAU,GAAG,IAAI,GAAG,IAAI;AAEzC,YAAA,IAAI,WAAmB;AACvB,YAAA,IAAI,gBAAwB;AAC5B,YAAA,IAAI,gBAAoC;YACxC,MAAM,WAAW,GAAG,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,QAAQ,CAAC;AAEtD,YAAA,IAAI;;gBAEF,MAAM,MAAM,GAAG,MAAM,WAAW,CAC9B,QAAQ,CAAC,YAAY,CAAC,QAAQ,EAAE,WAAW,CAAC,EAC5C,yBAAyB,EACzB,6BAA6B,QAAQ,CAAA,CAAE,CACxC;AACD,gBAAA,WAAW,GAAG,MAAM,CAAC,MAAM;AAC3B,gBAAA,gBAAgB,GAAG,MAAM,CAAC,QAAQ;AAClC,gBAAA,gBAAgB,GAAG,MAAM,sBAAsB,CAAC,WAAW,CAAC;AAC5D,gBAAA,OAAO,CAAC,GAAG,GAAG,CAAA,+BAAA,EAAkC,WAAW,CAAC,MAAM,CAAA,cAAA,EAAiB,gBAAgB,cAAc,gBAAgB,IAAI,QAAQ,CAAA,CAAE,CAAC;YAClJ;YAAE,OAAO,QAAQ,EAAE;;gBAEjB,OAAO,CAAC,GAAG,GAAG,CAAA,uCAAA,EAA0C,MAAM,CAAC,QAAQ,CAAC,CAAA,CAAE,CAAC;gBAC3E,MAAM,OAAO,GAAG,MAAM,WAAW,CAC/B,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,EACtD,yBAAyB,EACzB,CAAA,iCAAA,EAAoC,QAAQ,CAAA,CAAE,CACH;AAC7C,gBAAA,OAAO,CAAC,GAAG,GAAG,CAAA,mCAAA,EAAsC,OAAO,CAAC,WAAW,CAAA,OAAA,EAAU,OAAO,CAAC,MAAM,CAAC,MAAM,CAAA,CAAE,CAAC;AAEzG,gBAAA,WAAW,GAAG,OAAO,CAAC,MAAM;AAC5B,gBAAA,gBAAgB,GAAG,OAAO,CAAC,WAAW,IAAI,0BAA0B;gBACpE,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC;gBAExD,IAAI,CAAC,YAAY,EAAE;AACjB,oBAAA,OAAO,CAAC,GAAG,GAAG,CAAA,yDAAA,CAA2D,CAAC;gBAC5E;YACF;YAEA,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,eAAe,CACpD,WAAW,EACX,gBAAgB,EAChB,SAAS,EACT,QAAQ,EACR,gBAAgB,CACjB;AACD,YAAA,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;AACpE,YAAA,OAAO,CAAC,GAAG,GAAG,qCAAqC,KAAK,CAAC,IAAI,CAAA,cAAA,EAAiB,KAAK,CAAC,WAAW,CAAA,CAAE,CAAC;QACpG;QAAE,OAAO,GAAG,EAAE;YACZ,OAAO,CAAC,KAAK,GAAG,CAAA,kCAAA,EAAqC,MAAM,CAAC,GAAG,CAAC,CAAA,CAAE,CAAC;QACrE;IACF;AAEA,IAAA,OAAO,SAAS;AAClB;AAEA;;AAEG;AACI,eAAe,oBAAoB,CAAC,MAO1C,EAAA;IACC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM;AACtD,IAAA,MAAM,IAAI,GAAG,eAAe,EAAE;IAC9B,MAAM,SAAS,GAAkD,EAAE;AAEnE,IAAA,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;AAC9B,QAAA,IAAI;YACF,OAAO,CAAC,GAAG,GAAG,iCAAiC,OAAO,CAAA,CAAE,CAAC;YACzD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,IAAI,oBAAoB;AAC9E,YAAA,MAAM,QAAQ,GAAG,UAAU,GAAG,IAAI,GAAG,IAAI;AAEzC,YAAA,IAAI,UAAkB;AACtB,YAAA,IAAI,eAAuB;AAC3B,YAAA,IAAI,gBAAoC;YACxC,MAAM,UAAU,GAAG,MAAM,CAAC,WAAW,EAAE,GAAG,CAAC,OAAO,CAAC;AAEnD,YAAA,IAAI;;gBAEF,MAAM,MAAM,GAAG,MAAM,WAAW,CAC9B,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE,UAAU,CAAC,EAC1C,wBAAwB,EACxB,4BAA4B,OAAO,CAAA,CAAE,CACtC;AACD,gBAAA,UAAU,GAAG,MAAM,CAAC,MAAM;AAC1B,gBAAA,gBAAgB,GAAG,MAAM,CAAC,QAAQ;;AAGlC,gBAAA,MAAM,IAAI,GAAG,MAAMA,2BAAkB,CAAC,UAAU,CAAC;AACjD,gBAAA,eAAe,GAAG,IAAI,EAAE,IAAI,IAAI,0BAA0B;AAC1D,gBAAA,OAAO,CAAC,GAAG,GAAG,CAAA,8BAAA,EAAiC,UAAU,CAAC,MAAM,CAAA,cAAA,EAAiB,eAAe,cAAc,gBAAgB,IAAI,QAAQ,CAAA,CAAE,CAAC;YAC/I;YAAE,OAAO,QAAQ,EAAE;;gBAEjB,OAAO,CAAC,GAAG,GAAG,CAAA,4CAAA,EAA+C,MAAM,CAAC,QAAQ,CAAC,CAAA,CAAE,CAAC;gBAChF,MAAM,OAAO,GAAG,MAAM,WAAW,CAC/B,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,EACrD,wBAAwB,EACxB,CAAA,gCAAA,EAAmC,OAAO,CAAA,CAAE,CACD;AAC7C,gBAAA,OAAO,CAAC,GAAG,GAAG,CAAA,kCAAA,EAAqC,OAAO,CAAC,WAAW,CAAA,OAAA,EAAU,OAAO,CAAC,MAAM,CAAC,MAAM,CAAA,CAAE,CAAC;AAExG,gBAAA,UAAU,GAAG,OAAO,CAAC,MAAM;AAC3B,gBAAA,eAAe,GAAG,OAAO,CAAC,WAAW,IAAI,0BAA0B;YACrE;YAEA,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,eAAe,CACpD,UAAU,EACV,eAAe,EACf,SAAS,EACT,QAAQ,EACR,gBAAgB,CACjB;AACD,YAAA,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;AACpE,YAAA,OAAO,CAAC,GAAG,GAAG,oCAAoC,KAAK,CAAC,IAAI,CAAA,cAAA,EAAiB,KAAK,CAAC,WAAW,CAAA,CAAE,CAAC;QACnG;QAAE,OAAO,GAAG,EAAE;YACZ,OAAO,CAAC,KAAK,GAAG,CAAA,iCAAA,EAAoC,MAAM,CAAC,GAAG,CAAC,CAAA,CAAE,CAAC;QACpE;IACF;AAEA,IAAA,OAAO,SAAS;AAClB;;ACxLA;;;;;;;AAOG;AA4CH;AACA;AACA;AAEA;;;;;AAKG;AACG,SAAU,oBAAoB,CAAC,QAAgB,EAAA;AACnD,IAAA,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,EAAE;;AAGnC,IAAA,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;AAC7B,QAAA,OAAO,OAAO;IAChB;;AAGA,IAAA,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;AAC7B,QAAA,OAAO,OAAO;IAChB;;AAGA,IAAA,IACE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QACzB,IAAI,KAAK,iBAAiB;MAC1B;AACA,QAAA,OAAO,OAAO;IAChB;;AAGA,IAAA,OAAO,MAAM;AACf;AAEA;AACA;AACA;AAEA;;;;;;;;;AASG;AACI,eAAe,gBAAgB,CACpC,QAAgB,EAChB,eAAmC,EAAA;;;AAInC,IAAA,MAAM,MAAM,GAAmB,MAAM,wBAAwB,CAAC,QAAQ,EAAE;AACtE,QAAA,QAAQ,EAAE,kBAAkB;QAC5B,eAAe;AAChB,KAAA,CAAC;AAEF,IAAA,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE;AAChD,QAAA,MAAM,IAAI,KAAK,CAAC,6BAA6B,QAAQ,CAAA,cAAA,CAAgB,CAAC;IACxE;;AAGA,IAAA,IAAI,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,0BAA0B;;IAGlE,IACE,WAAW,KAAK,0BAA0B;QAC1C,WAAW,KAAK,YAAY,EAC5B;QACA,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC;QAChD,IAAI,QAAQ,EAAE;YACZ,WAAW,GAAG,QAAQ;QACxB;IACF;;AAGA,IAAA,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC;IAExE,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,WAAW;QACX,QAAQ;KACT;AACH;AAEA;AACA;AACA;AAEA;AACA,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC;AAEpD;;;;;;;;;;;;;;AAcG;SACa,mBAAmB,CACjC,QAAgB,EAChB,YAA4B,EAC5B,WAAoB,EAAA;AAEpB,IAAA,MAAM,UAAU,GAAG,CAAC,QAAQ,IAAI,IAAI,GAAG,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;;AAGxD,IAAA,IAAI,QAAQ,GAAG,kBAAkB,EAAE;QACjC,OAAO;AACL,YAAA,SAAS,EAAE,YAAY;AACvB,YAAA,YAAY,EAAE,IAAI;YAClB,YAAY,EAAE,CAAA,KAAA,EAAQ,UAAU,CAAA,2CAAA,CAA6C;AAC7E,YAAA,UAAU,EAAE,KAAK;SAClB;IACH;;IAGA,QAAQ,YAAY;AAClB,QAAA,KAAK,OAAO;AACV,YAAA,IAAI,QAAQ,GAAG,eAAe,EAAE;gBAC9B,OAAO;AACL,oBAAA,SAAS,EAAE,MAAM;AACjB,oBAAA,YAAY,EAAE,KAAK;AACnB,oBAAA,UAAU,EAAE,IAAI;oBAChB,aAAa,EAAE,CAAA,KAAA,EAAQ,UAAU,CAAA,uBAAA,CAAyB;iBAC3D;YACH;YACA;AAEF,QAAA,KAAK,OAAO;AACV,YAAA,IAAI,QAAQ,GAAG,eAAe,EAAE;gBAC9B,OAAO;AACL,oBAAA,SAAS,EAAE,MAAM;AACjB,oBAAA,YAAY,EAAE,KAAK;AACnB,oBAAA,UAAU,EAAE,IAAI;oBAChB,aAAa,EAAE,CAAA,KAAA,EAAQ,UAAU,CAAA,uBAAA,CAAyB;iBAC3D;YACH;YACA;AAEF,QAAA,KAAK,OAAO;;AAEV,YAAA,IAAI,WAAW,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,EAAE;gBACxE,OAAO;AACL,oBAAA,SAAS,EAAE,MAAM;AACjB,oBAAA,YAAY,EAAE,KAAK;AACnB,oBAAA,UAAU,EAAE,IAAI;oBAChB,aAAa,EAAE,CAAA,KAAA,EAAQ,WAAW,CAAA,2BAAA,CAA6B;iBAChE;YACH;AACA,YAAA,IAAI,QAAQ,GAAG,eAAe,EAAE;gBAC9B,OAAO;AACL,oBAAA,SAAS,EAAE,MAAM;AACjB,oBAAA,YAAY,EAAE,KAAK;AACnB,oBAAA,UAAU,EAAE,IAAI;oBAChB,aAAa,EAAE,CAAA,KAAA,EAAQ,UAAU,CAAA,sBAAA,CAAwB;iBAC1D;YACH;YACA;;;IAQJ,OAAO;AACL,QAAA,SAAS,EAAE,YAAY;AACvB,QAAA,YAAY,EAAE,KAAK;AACnB,QAAA,UAAU,EAAE,KAAK;KAClB;AACH;AAEA;AACA;AACA;AAEA;;AAEG;AACH,SAAS,eAAe,CACtB,QAAgB,EAChB,gBAAyB,EACzB,WAAoB,EAAA;;IAGpB,IAAI,gBAAgB,EAAE;AACpB,QAAA,OAAO,gBAAgB;IACzB;;AAGA,IAAA,IAAI;QACF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC;QAC3C,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC;QAC5C,MAAM,QAAQ,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;QAChD,IAAI,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AACtC,YAAA,OAAO,kBAAkB,CAAC,QAAQ,CAAC;QACrC;IACF;AAAE,IAAA,MAAM;;QAEN,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC;QACjC,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QACxC,IAAI,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AACtC,YAAA,OAAO,QAAQ;QACjB;IACF;;IAGA,MAAM,GAAG,GAAG,eAAe,CAAC,WAAW,IAAI,0BAA0B,CAAC;IACtE,OAAO,CAAA,MAAA,EAAS,IAAI,CAAC,GAAG,EAAE,CAAA,EAAG,GAAG,EAAE;AACpC;AAEA;;AAEG;AACH,SAAS,eAAe,CAAC,IAAY,EAAA;AACnC,IAAA,MAAM,GAAG,GAA2B;AAClC,QAAA,YAAY,EAAE,MAAM;AACpB,QAAA,WAAW,EAAE,MAAM;AACnB,QAAA,WAAW,EAAE,MAAM;AACnB,QAAA,YAAY,EAAE,OAAO;AACrB,QAAA,WAAW,EAAE,MAAM;AACnB,QAAA,eAAe,EAAE,MAAM;AACvB,QAAA,WAAW,EAAE,MAAM;AACnB,QAAA,iBAAiB,EAAE,MAAM;AACzB,QAAA,iBAAiB,EAAE,MAAM;AACzB,QAAA,YAAY,EAAE,OAAO;AACrB,QAAA,YAAY,EAAE,MAAM;AACpB,QAAA,WAAW,EAAE,MAAM;AACnB,QAAA,WAAW,EAAE,MAAM;AACnB,QAAA,WAAW,EAAE,MAAM;AACnB,QAAA,WAAW,EAAE,MAAM;AACnB,QAAA,iBAAiB,EAAE,MAAM;AACzB,QAAA,iBAAiB,EAAE,MAAM;AACzB,QAAA,oBAAoB,EAAE,MAAM;AAC5B,QAAA,yEAAyE,EACvE,OAAO;AACT,QAAA,0BAA0B,EAAE,MAAM;AAClC,QAAA,mEAAmE,EACjE,OAAO;AACT,QAAA,YAAY,EAAE,MAAM;KACrB;AACD,IAAA,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,MAAM;AAC5B;AA0CA;;;;;;AAMG;AACI,eAAe,kBAAkB,CACtC,OAAkC,EAAA;AAElC,IAAA,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,OAAO;AAE9E,IAAA,IAAI;;AAEF,QAAA,GAAG,GAAG,CAAA,6BAAA,EAAgC,QAAQ,CAAA,CAAE,CAAC;QACjD,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,QAAQ,EAAE,eAAe,CAAC;;QAG/D,MAAM,YAAY,GAAG,oBAAoB,CAAC,KAAK,CAAC,WAAW,CAAC;;AAG5D,QAAA,MAAM,SAAS,GAAG,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC;AAE3F,QAAA,IAAI,SAAS,CAAC,YAAY,EAAE;YAC1B,QAAQ,GAAG,CAAA,wBAAA,EAA2B,SAAS,CAAC,YAAY,CAAA,CAAE,CAAC;YAC/D,OAAO;AACL,gBAAA,EAAE,EAAE,KAAK;AACT,gBAAA,QAAQ,EAAE,IAAI;gBACd,YAAY,EAAE,SAAS,CAAC,YAAY;gBACpC,SAAS,EAAE,SAAS,CAAC,SAAS;aAC/B;QACH;AAEA,QAAA,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS;;QAGrC,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE;AAC5D,YAAA,IAAI,EAAE,SAAS;YACf,QAAQ,EAAE,KAAK,CAAC,QAAQ;AACzB,SAAA,CAAC;QACF,GAAG,GAAG,CAAA,iCAAA,EAAoC,YAAY,CAAC,QAAQ,CAAA,OAAA,EAAU,SAAS,CAAA,CAAE,CAAC;;AAGrF,QAAA,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,CAAC,QAAQ,CAAC;AACxF,QAAA,MAAM,SAAS,GAAG,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,CAAA,YAAA,EAAe,IAAI,CAAC,GAAG,EAAE,EAAE;QACxE,GAAG,GAAG,CAAA,gDAAA,EAAmD,MAAM,UAAU,SAAS,CAAA,CAAE,CAAC;QAErF,OAAO;AACL,YAAA,EAAE,EAAE,IAAI;YACR,SAAS;YACT,SAAS;YACT,UAAU,EAAE,SAAS,CAAC,UAAU;YAChC,aAAa,EAAE,SAAS,CAAC,aAAa;SACvC;IACH;IAAE,OAAO,GAAG,EAAE;AACZ,QAAA,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC;QAC1B,QAAQ,GAAG,CAAA,yCAAA,EAA4C,QAAQ,WAAW,MAAM,CAAA,CAAE,CAAC;QACnF,OAAO;AACL,YAAA,EAAE,EAAE,KAAK;AACT,YAAA,KAAK,EAAE,MAAM;SACd;IACH;AACF;;ACzZA;;;;;;;;AAQG;AAKH;AACA;AACA;AAEA;;;AAGG;AACH,SAAS,WAAW,CAAC,KAAc,EAAA;AACjC,IAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;AACvD,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;IAC1B;AACA,IAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QAC7B,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;;AAE1C,QAAA,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC;AAC3B,QAAA,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AAC9C,YAAA,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;QACxB;IACF;AACA,IAAA,OAAO,SAAS;AAClB;AAEA;AACA,SAAS,YAAY,CAAC,KAAc,EAAA;IAClC,IAAI,OAAO,KAAK,KAAK,SAAS;AAAE,QAAA,OAAO,KAAK;AAC5C,IAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QAC7B,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK;AAAE,YAAA,OAAO,IAAI;QACzD,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI;AAAE,YAAA,OAAO,KAAK;IAC5D;IACA,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,KAAK,CAAC;AACjD,IAAA,OAAO,SAAS;AAClB;AAEA;AACA,MAAM,YAAY,GAA2B;AAC3C,IAAA,MAAM,EAAE,CAAC;AACT,IAAA,KAAK,EAAE,CAAC;AACR,IAAA,IAAI,EAAE,CAAC;AACP,IAAA,KAAK,EAAE,CAAC;AACR,IAAA,QAAQ,EAAE,CAAC;AACX,IAAA,IAAI,EAAE,CAAC;CACR;AAED;;;;;;;AAOG;AACH,SAAS,kBAAkB,CAAC,KAAc,EAAA;AACxC,IAAA,IAAI,GAAuB;AAC3B,IAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;AACvD,QAAA,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;IACzB;AAAO,SAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QACpC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;QAC1C,IAAI,OAAO,IAAI,YAAY;AAAE,YAAA,OAAO,YAAY,CAAC,OAAO,CAAC;AACzD,QAAA,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;AAC9B,QAAA,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;AAAE,YAAA,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IACrD;IACA,IAAI,GAAG,KAAK,SAAS;AAAE,QAAA,OAAO,SAAS;;IAEvC,IAAI,GAAG,IAAI,CAAC;AAAE,QAAA,OAAO,CAAC;AACtB,IAAA,OAAO,CAAC;AACV;AAEA;;;;;;;;;;;;;;;;;;AAkBG;AACH,SAAS,2BAA2B,CAClC,IAA6B,EAC7B,GAA8B,EAAA;IAE9B,MAAM,KAAK,GAAa,EAAE;;AAG1B,IAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,QAA+C;AACrE,IAAA,IAAI,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE;;AAE5C,QAAA,IAAI,MAAM,IAAI,QAAQ,EAAE;YACtB,MAAM,KAAK,GAAG,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC;AAC/C,YAAA,IAAI,KAAK,KAAK,SAAS,EAAE;AACvB,gBAAA,IAAI,QAAQ,CAAC,IAAI,KAAK,KAAK,EAAE;AAC3B,oBAAA,KAAK,CAAC,IAAI,CAAC,CAAA,eAAA,EAAkB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,CAAC;gBAC1E;AACA,gBAAA,QAAQ,CAAC,IAAI,GAAG,KAAK;YACvB;iBAAO;AACL,gBAAA,KAAK,CAAC,IAAI,CAAC,CAAA,eAAA,EAAkB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA,qBAAA,CAAuB,CAAC;gBAClF,OAAO,QAAQ,CAAC,IAAI;YACtB;QACF;;AAEA,QAAA,IAAI,SAAS,IAAI,QAAQ,EAAE;YACzB,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC;YAC5C,IAAI,KAAK,KAAK,SAAS,IAAI,QAAQ,CAAC,OAAO,KAAK,KAAK,EAAE;AACrD,gBAAA,KAAK,CAAC,IAAI,CAAC,CAAA,kBAAA,EAAqB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,CAAC;AAC9E,gBAAA,QAAQ,CAAC,OAAO,GAAG,KAAK;YAC1B;QACF;;QAEA,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE;AACvC,YAAA,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,WAAwC,EAAE;gBACnE,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,YAAY,IAAI,GAAG,EAAE;oBACzD,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC;oBAC1C,IAAI,KAAK,KAAK,SAAS,IAAI,GAAG,CAAC,UAAU,KAAK,KAAK,EAAE;AACnD,wBAAA,KAAK,CAAC,IAAI,CAAC,CAAA,iCAAA,EAAoC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,CAAC;AAC3F,wBAAA,GAAG,CAAC,UAAU,GAAG,KAAK;oBACxB;gBACF;YACF;QACF;IACF;;AAGA,IAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAA6C;IACjE,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,YAAY,IAAI,MAAM,EAAE;QAClE,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC;QAC5C,IAAI,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,UAAU,KAAK,KAAK,EAAE;AACtD,YAAA,KAAK,CAAC,IAAI,CAAC,CAAA,mBAAA,EAAsB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,CAAC;AAChF,YAAA,MAAM,CAAC,UAAU,GAAG,KAAK;QAC3B;IACF;;AAGA,IAAA,MAAM,UAAU,GAAG,IAAI,CAAC,WAAkD;IAC1E,IAAI,UAAU,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,MAAM,IAAI,UAAU,EAAE;QACxE,MAAM,KAAK,GAAG,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC;QAC1C,IAAI,KAAK,KAAK,SAAS,IAAI,UAAU,CAAC,IAAI,KAAK,KAAK,EAAE;AACpD,YAAA,KAAK,CAAC,IAAI,CAAC,CAAA,kBAAA,EAAqB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,CAAC;AAC7E,YAAA,UAAU,CAAC,IAAI,GAAG,KAAK;QACzB;IACF;;AAGA,IAAA,MAAM,SAAS,GAAG,IAAI,CAAC,UAAiD;IACxE,IAAI,SAAS,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,MAAM,IAAI,SAAS,EAAE;QACrE,MAAM,KAAK,GAAG,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC;QACzC,IAAI,KAAK,KAAK,SAAS,IAAI,SAAS,CAAC,IAAI,KAAK,KAAK,EAAE;AACnD,YAAA,KAAK,CAAC,IAAI,CAAC,CAAA,iBAAA,EAAoB,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,CAAC;AAC3E,YAAA,SAAS,CAAC,IAAI,GAAG,KAAK;QACxB;IACF;;AAGA,IAAA,MAAM,aAAa,GAAG,IAAI,CAAC,eAAsD;IACjF,IAAI,aAAa,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,MAAM,IAAI,aAAa,EAAE;QACjF,MAAM,KAAK,GAAG,WAAW,CAAC,aAAa,CAAC,IAAI,CAAC;QAC7C,IAAI,KAAK,KAAK,SAAS,IAAI,aAAa,CAAC,IAAI,KAAK,KAAK,EAAE;AACvD,YAAA,KAAK,CAAC,IAAI,CAAC,CAAA,sBAAA,EAAyB,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,CAAC;AACpF,YAAA,aAAa,CAAC,IAAI,GAAG,KAAK;QAC5B;IACF;;IAGA,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,uBAAuB,CAAC,EAAE;AAC/C,QAAA,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,uBAAoD,EAAE;YAC5E,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,MAAM,IAAI,IAAI,EAAE;gBACtD,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;gBACpC,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE;AAC9C,oBAAA,KAAK,CAAC,IAAI,CAAC,CAAA,8BAAA,EAAiC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,CAAC;AACnF,oBAAA,IAAI,CAAC,IAAI,GAAG,KAAK;gBACnB;YACF;QACF;IACF;;IAGA,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;AACjC,QAAA,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,SAAsC,EAAE;YAC9D,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,MAAM,IAAI,IAAI,EAAE;gBACtD,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;gBACpC,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE;AAC9C,oBAAA,KAAK,CAAC,IAAI,CAAC,CAAA,gBAAA,EAAmB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,CAAC;AACrE,oBAAA,IAAI,CAAC,IAAI,GAAG,KAAK;gBACnB;YACF;QACF;IACF;;IAGA,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AACnC,QAAA,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,WAAwC,EAAE;YAC/D,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,IAAI,GAAG,EAAE;gBACpD,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;gBACpC,IAAI,KAAK,KAAK,SAAS,IAAI,GAAG,CAAC,KAAK,KAAK,KAAK,EAAE;AAC9C,oBAAA,KAAK,CAAC,IAAI,CAAC,CAAA,mBAAA,EAAsB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,CAAC;AACxE,oBAAA,GAAG,CAAC,KAAK,GAAG,KAAK;gBACnB;YACF;QACF;IACF;;AAGA,IAAA,MAAM,eAAe,GAAG,IAAI,CAAC,gBAAuD;IACpF,IAAI,eAAe,IAAI,OAAO,eAAe,KAAK,QAAQ,IAAI,SAAS,IAAI,eAAe,EAAE;QAC1F,MAAM,KAAK,GAAG,YAAY,CAAC,eAAe,CAAC,OAAO,CAAC;QACnD,IAAI,KAAK,KAAK,SAAS,IAAI,eAAe,CAAC,OAAO,KAAK,KAAK,EAAE;AAC5D,YAAA,KAAK,CAAC,IAAI,CAAC,CAAA,0BAAA,EAA6B,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,CAAC;AAC7F,YAAA,eAAe,CAAC,OAAO,GAAG,KAAK;QACjC;IACF;;IAGA,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AACnC,QAAA,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,WAAwC,EAAE;YAC/D,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,SAAS,IAAI,GAAG,EAAE;gBACtD,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC;gBACvC,IAAI,KAAK,KAAK,SAAS,IAAI,GAAG,CAAC,OAAO,KAAK,KAAK,EAAE;AAChD,oBAAA,KAAK,CAAC,IAAI,CAAC,CAAA,qBAAA,EAAwB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,CAAC;AAC5E,oBAAA,GAAG,CAAC,OAAO,GAAG,KAAK;gBACrB;YACF;QACF;IACF;AAEA,IAAA,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;AACpB,QAAA,GAAG,GAAG,CAAA,oDAAA,EAAuD,KAAK,CAAC,MAAM,CAAA,kBAAA,EAAqB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA,CAAE,CAAC;IACnH;AAEA,IAAA,OAAO,IAAI;AACb;AAkBA;;;;;;;;;;;;;;AAcG;AACH,SAAS,4BAA4B,CACnC,IAA6B,EAC7B,GAA8B,EAAA;AAE9B,IAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAmB;IACzC,MAAM,KAAK,GAAa,EAAE;IAC1B,MAAM,QAAQ,GAAa,EAAE;;;;AAK7B,IAAA,MAAM,MAAM,GAAG,CAAC,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE;AACnG,IAAA,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACnD,IAAA,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE;AAErB,IAAA,IAAI,QAAgB;IACpB,IAAI,MAAM,EAAE;;QAEV,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAC5F,QAAQ,GAAG,MAAM,GAAG,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA,EAAI,IAAI,EAAE,GAAG,CAAA,KAAA,EAAQ,QAAQ,IAAI,EAAE,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE;IAClF;SAAO;QACL,QAAQ,GAAG,QAAQ,QAAQ,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA,EAAI,IAAI,EAAE;IAC7C;AAEA,IAAA,IAAI,QAAQ,KAAK,MAAM,EAAE;QACvB,KAAK,CAAC,IAAI,CAAC,CAAA,UAAA,EAAa,MAAM,IAAI,WAAW,CAAA,KAAA,EAAQ,QAAQ,CAAA,CAAA,CAAG,CAAC;IACnE;AACA,IAAA,IAAI,CAAC,OAAO,GAAG,QAAQ;;AAGvB,IAAA,MAAM,SAAS,GAAG,IAAI,CAAC,UAAiD;AACxE,IAAA,MAAM,YAAY,GAAG,SAAS,IAAI,OAAO,SAAS,KAAK,QAAQ;AAC7D,SAAC,OAAO,SAAS,CAAC,KAAK,KAAK,QAAQ,IAAI,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;AACjE,IAAA,MAAM,eAAe,GAAG,OAAO,IAAI,CAAC,cAAc,KAAK,QAAQ,IAAK,IAAI,CAAC,cAAyB,CAAC,IAAI,EAAE;IAEzG,QAAQ,QAAQ;AACd,QAAA,KAAK,aAAa;;AAEhB,YAAA,IAAI,CAAC,YAAY,IAAI,CAAC,eAAe,EAAE;gBACrC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,IAAI,IAAI;AACjD,gBAAA,KAAK,CAAC,IAAI,CAAC,CAAA,+DAAA,CAAiE,CAAC;YAC/E;YACA;AAEF,QAAA,KAAK,aAAa;AAClB,QAAA,KAAK,oBAAoB;AACzB,QAAA,KAAK,kBAAkB;AACvB,QAAA,KAAK,sBAAsB;;YAEzB,IAAI,CAAC,SAAS,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE;gBAC/C,IAAI,CAAC,UAAU,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;AACjC,gBAAA,KAAK,CAAC,IAAI,CAAC,CAAA,uCAAA,CAAyC,CAAC;YACvD;iBAAO,IAAI,CAAC,YAAY,EAAE;AACvB,gBAAA,SAAqC,CAAC,KAAK,GAAG,IAAI;AACnD,gBAAA,KAAK,CAAC,IAAI,CAAC,CAAA,gCAAA,CAAkC,CAAC;YAChD;YACA;;;IAIJ,IAAI,QAAQ,KAAK,aAAa,IAAI,QAAQ,KAAK,aAAa,EAAE;AAC5D,QAAA,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,EAAE;AAC7D,YAAA,IAAI,CAAC,WAAW,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,4BAA4B,EAAE;AACjE,YAAA,KAAK,CAAC,IAAI,CAAC,CAAA,uEAAA,CAAyE,CAAC;QACvF;IACF;;IAGA,IAAI,QAAQ,KAAK,kBAAkB,IAAI,QAAQ,KAAK,sBAAsB,EAAE;AAC1E,QAAA,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,OAAO,IAAI,CAAC,aAAa,KAAK,QAAQ,EAAE;AACjE,YAAA,IAAI,CAAC,aAAa,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAA,OAAA,EAAU,QAAQ,IAAI,IAAI,CAAC,GAAG,EAAE,CAAA,CAAE,EAAE;AAC5E,YAAA,KAAK,CAAC,IAAI,CAAC,CAAA,yCAAA,CAA2C,CAAC;QACzD;IACF;;AAGA,IAAA,IAAI,QAAQ,KAAK,oBAAoB,EAAE;AACrC,QAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE;AACrE,YAAA,QAAQ,CAAC,IAAI,CAAC,CAAA,iEAAA,CAAmE,CAAC;QACpF;IACF;AAEA,IAAA,IAAI,QAAQ,KAAK,kBAAkB,EAAE;AACnC,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE;AACvD,YAAA,QAAQ,CAAC,IAAI,CAAC,CAAA,mDAAA,CAAqD,CAAC;QACtE;IACF;AAEA,IAAA,IAAI,QAAQ,KAAK,sBAAsB,EAAE;AACvC,QAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE;AACrE,YAAA,QAAQ,CAAC,IAAI,CAAC,CAAA,mEAAA,CAAqE,CAAC;QACtF;IACF;AAEA,IAAA,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;AACpB,QAAA,GAAG,GAAG,CAAA,qDAAA,EAAwD,KAAK,CAAC,MAAM,CAAA,UAAA,EAAa,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA,CAAE,CAAC;IAC5G;AACA,IAAA,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;AACvB,QAAA,GAAG,GAAG,CAAA,qDAAA,EAAwD,QAAQ,CAAC,MAAM,CAAA,aAAA,EAAgB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA,CAAE,CAAC;IACrH;AAEA,IAAA,OAAO,IAAI;AACb;AAEA;AACA;AACA;AAEA;;AAEG;AACH,SAAS,WAAW,CAAC,MAAc,EAAA;AACjC,IAAA,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;IACnD,OAAO,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,IAAI,CAAC,GAAG,EAAE,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE;AAC1C;AAEA;;;;;;;;;;;;;AAaG;AACH,SAAS,wBAAwB,CAC/B,IAA6B,EAC7B,GAA8B,EAAA;;AAG9B,IAAA,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAA+C;AAC7E,IAAA,IAAI,gBAAgB,IAAI,OAAO,gBAAgB,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,WAAW,CAAC,EAAE;AAC3G,QAAA,GAAG,GAAG,CAAA,qGAAA,CAAuG,CAAC;AAC9G,QAAA,OAAO,IAAI;IACb;;AAGA,IAAA,MAAM,OAAO,GAAG,IAAI,CAAC,OAAqD;AAC1E,IAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;AACnD,QAAA,GAAG,GAAG,CAAA,6FAAA,CAA+F,CAAC;AACtG,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,GAAG,GAAG,CAAA,4FAAA,CAA8F,CAAC;IACrG,GAAG,GAAG,CAAA,uDAAA,EAA0D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,CAAE,CAAC;;AAGvF,IAAA,MAAM,KAAK,GAAG,IAAI,CAAC,KAA2B;AAC9C,IAAA,MAAM,WAAW,GAAG,IAAI,CAAC,WAAiC;AAC1D,IAAA,IAAI,KAAK,IAAI,WAAW,EAAE;QACxB,IAAI,CAAC,UAAU,GAAG;AAChB,YAAA,IAAI,KAAK,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AAC3B,YAAA,IAAI,WAAW,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC;SAC9C;QACD,OAAO,IAAI,CAAC,KAAK;QACjB,OAAO,IAAI,CAAC,WAAW;IACzB;;IAGA,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AAC/C,IAAA,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC;IACvC,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;AAC3C,IAAA,IAAI,OAAO,CAAC,MAAM,GAAG,EAAE,EAAE;QACvB,GAAG,GAAG,CAAA,+DAAA,EAAkE,OAAO,CAAC,MAAM,CAAA,8BAAA,CAAgC,CAAC;IACzH;IACA,IAAI,CAAC,QAAQ,GAAG;AACd,QAAA,YAAY,EAAE,WAAW;QACzB,IAAI;QACJ,WAAW,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM;AACxC,YAAA,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,KAAK,IAAI,CAAA,IAAA,EAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AAClF,YAAA,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;AACtD,SAAA,CAAC,CAAC;KACJ;IACD,OAAO,IAAI,CAAC,OAAO;IACnB,OAAO,IAAI,CAAC,IAAI;;AAGhB,IAAA,MAAM,UAAU,GAAI,IAAI,CAAC,WAAsB,IAAI,IAAI;IACvD,IAAI,CAAC,aAAa,GAAG;AACnB,QAAA,IAAI,EAAE,UAAU;AAChB,QAAA,GAAG,EAAE,WAAW,CAAC,aAAa,CAAC;KAChC;IACD,OAAO,IAAI,CAAC,WAAW;;IAGvB,OAAO,IAAI,CAAC,aAAa;IACzB,OAAO,IAAI,CAAC,WAAW;IACvB,OAAO,IAAI,CAAC,YAAY;IAExB,GAAG,GAAG,CAAA,wDAAA,EAA2D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,CAAE,CAAC;AAExF,IAAA,OAAO,IAAI;AACb;AAEA;;;;;;;;;;;;AAYG;AACH,SAAS,4BAA4B,CACnC,IAA6B,EAC7B,GAA8B,EAAA;;AAG9B,IAAA,MAAM,kBAAkB,GAAG,IAAI,CAAC,WAAyD;AACzF,IAAA,IACE,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC;QACjC,kBAAkB,CAAC,MAAM,GAAG,CAAC;QAC7B,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,EACjD;AACA,QAAA,GAAG,GAAG,CAAA,8GAAA,CAAgH,CAAC;AACvH,QAAA,OAAO,IAAI;IACb;;AAGA,IAAA,MAAM,SAAS,GAAG,IAAI,CAAC,SAAuD;AAC9E,IAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;AACvD,QAAA,GAAG,GAAG,CAAA,mGAAA,CAAqG,CAAC;AAC5G,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,GAAG,GAAG,CAAA,gGAAA,CAAkG,CAAC;IACzG,GAAG,GAAG,CAAA,2DAAA,EAA8D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,CAAE,CAAC;;AAG3F,IAAA,MAAM,KAAK,GAAG,IAAI,CAAC,KAA2B;AAC9C,IAAA,MAAM,WAAW,GAAG,IAAI,CAAC,WAAiC;AAC1D,IAAA,IAAI,KAAK,IAAI,WAAW,EAAE;QACxB,IAAI,CAAC,UAAU,GAAG;AAChB,YAAA,IAAI,KAAK,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AAC3B,YAAA,IAAI,WAAW,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC;SAC9C;QACD,OAAO,IAAI,CAAC,KAAK;QACjB,OAAO,IAAI,CAAC,WAAW;IACzB;;IAGA,MAAM,gBAAgB,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC9C,IAAA,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;QACxB,GAAG,GAAG,CAAA,qEAAA,EAAwE,SAAS,CAAC,MAAM,CAAA,4BAAA,CAA8B,CAAC;IAC/H;AACA,IAAA,IAAI,CAAC,WAAW,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,KAAI;AACnD,QAAA,MAAM,eAAe,GAAG,CAAE,GAAG,CAAC,OAA0C,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAC5F,OAAO;AACL,YAAA,YAAY,EAAE,WAAW,CAAC,CAAA,IAAA,EAAO,GAAG,EAAE,CAAC;AACvC,YAAA,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,IAAI,CAAA,EAAA,EAAK,GAAG,GAAG,CAAC,EAAE,CAAC;YACvD,WAAW,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM;AACzC,gBAAA,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,KAAK,IAAI,CAAA,IAAA,EAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AAClF,gBAAA,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;AACtD,aAAA,CAAC,CAAC;SACJ;AACH,IAAA,CAAC,CAAC;IACF,OAAO,IAAI,CAAC,SAAS;;AAGrB,IAAA,MAAM,UAAU,GAAI,IAAI,CAAC,WAAsB,IAAI,IAAI;IACvD,IAAI,CAAC,aAAa,GAAG;AACnB,QAAA,IAAI,EAAE,UAAU;AAChB,QAAA,GAAG,EAAE,WAAW,CAAC,cAAc,CAAC;KACjC;IACD,OAAO,IAAI,CAAC,WAAW;IAEvB,GAAG,GAAG,CAAA,4DAAA,EAA+D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,CAAE,CAAC;AAE5F,IAAA,OAAO,IAAI;AACb;AAEA;;;AAGG;AACH,SAAS,uBAAuB,CAC9B,IAA6B,EAC7B,GAA8B,EAAA;AAE9B,IAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAmB;AACzC,IAAA,IAAI,QAAQ,KAAK,kBAAkB,EAAE;AACnC,QAAA,OAAO,wBAAwB,CAAC,IAAI,EAAE,GAAG,CAAC;IAC5C;AACA,IAAA,IAAI,QAAQ,KAAK,sBAAsB,EAAE;AACvC,QAAA,OAAO,4BAA4B,CAAC,IAAI,EAAE,GAAG,CAAC;IAChD;AACA,IAAA,OAAO,IAAI;AACb;AAEA;;;AAGG;AACH,MAAM,aAAa,GAAG,mCAAmC;AAEzD;;;AAGG;AACH,MAAM,eAAe,GAAG,mCAAmC;AAE3D;;;AAGG;AACH,MAAM,iBAAiB,GAAG,2BAA2B;AAErD;;;;;;;;;;;AAWG;AACG,SAAU,oBAAoB,CAAC,IAAY,EAAE,GAA8B,EAAA;IAC/E,MAAM,KAAK,GAA4B,EAAE;;IAEzC,MAAM,cAAc,GAAa,EAAE;IAEnC,GAAG,GAAG,CAAA,+DAAA,EAAkE,IAAI,CAAC,MAAM,CAAA,CAAE,CAAC;AAEtF,IAAA,IAAI,KAA6B;;AAEjC,IAAA,aAAa,CAAC,SAAS,GAAG,CAAC;IAE3B,IAAI,UAAU,GAAG,CAAC;AAClB,IAAA,OAAO,CAAC,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE;AAClD,QAAA,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC;QAC1B,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AACnC,QAAA,UAAU,EAAE;AAEZ,QAAA,GAAG,GAAG,CAAA,yCAAA,EAA4C,UAAU,CAAA,SAAA,EAAY,SAAS,CAAC,MAAM,CAAA,UAAA,EAAa,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA,GAAA,CAAK,CAAC;;AAGrI,QAAA,IAAI,MAA+B;AACnC,QAAA,IAAI;AACF,YAAA,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAA4B;QAC7D;QAAE,OAAO,CAAC,EAAE;;YAEV,GAAG,GAAG,CAAA,mCAAA,EAAsC,UAAU,CAAA,oBAAA,EAAuB,MAAM,CAAC,CAAC,CAAC,CAAA,CAAE,CAAC;YACzF;QACF;;AAGA,QAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS;AACjC,QAAA,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;;YAExE,GAAG,GAAG,CAAA,mCAAA,EAAsC,UAAU,CAAA,wBAAA,EAA2B,MAAM,CAAC,QAAQ,CAAC,CAAA,WAAA,CAAa,CAAC;YAC/G;QACF;QAEA,GAAG,GAAG,CAAA,mCAAA,EAAsC,UAAU,uCAAuC,QAAQ,CAAA,CAAA,CAAG,CAAC;;AAGzG,QAAA,uBAAuB,CAAC,MAAM,EAAE,GAAG,CAAC;;AAGpC,QAAA,2BAA2B,CAAC,MAAM,EAAE,GAAG,CAAC;;AAGxC,QAAA,4BAA4B,CAAC,MAAM,EAAE,GAAG,CAAC;;QAGzC,KAAK,CAAC,IAAI,CAAC;AACT,YAAA,QAAQ,EAAE,MAAM;YAChB,QAAQ;AACT,SAAA,CAAC;AACF,QAAA,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC;IAChC;;IAGA,IAAI,aAAa,GAAG,IAAI;AACxB,IAAA,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE;QAClC,aAAa,GAAG,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;IAClD;;AAEA,IAAA,aAAa,GAAG,aAAa,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE;AAE/D,IAAA,GAAG,GAAG,CAAA,wCAAA,EAA2C,KAAK,CAAC,MAAM,CAAA,oCAAA,EAAuC,aAAa,CAAC,MAAM,CAAA,CAAE,CAAC;AAE3H,IAAA,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE;AACjC;AAEA;;;;;;;;;;;;AAYG;AACG,SAAU,sBAAsB,CAAC,IAAY,EAAE,GAA8B,EAAA;IACjF,IAAI,MAAM,GAAG,IAAI;IACjB,IAAI,eAAe,GAAG,CAAC;IACvB,IAAI,cAAc,GAAG,KAAK;;AAG1B,IAAA,eAAe,CAAC,SAAS,GAAG,CAAC;AAC7B,IAAA,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC,SAAS,EAAE,OAAe,KAAI;;AAEtE,QAAA,IAAI,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AACrC,YAAA,eAAe,EAAE;AACjB,YAAA,OAAO,0BAA0B;QACnC;;AAEA,QAAA,OAAO,SAAS;AAClB,IAAA,CAAC,CAAC;;;IAIF,MAAM,aAAa,GAAG,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC;IACpD,IAAI,aAAa,EAAE;AACjB,QAAA,MAAM,eAAe,GAAG,aAAa,CAAC,CAAC,CAAC;;AAExC,QAAA,IAAI,mBAAmB,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE;YAC7C,cAAc,GAAG,IAAI;AACrB,YAAA,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,sBAAsB;QACxE;IACF;;AAGA,IAAA,IAAI,eAAe,GAAG,CAAC,IAAI,cAAc,EAAE;AACzC,QAAA,GAAG,GAAG,CAAA,4DAAA,EAA+D,eAAe,CAAA,iBAAA,EAAoB,cAAc,CAAA,aAAA,EAAgB,IAAI,CAAC,MAAM,kBAAkB,MAAM,CAAC,MAAM,CAAA,CAAE,CAAC;IACrL;AAEA,IAAA,OAAO,MAAM;AACf;;AC1tBA;;;;AAIG;AAmBH;AACA;AACA;AAEA;;AAEG;AACH,SAAS,uBAAuB,CAAC,MAGhC,EAAA;IACC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,EAAE,MAAM,IAAI,EAAE;AACvC,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC;IAC5B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE;IACtC,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,OAAO,SAAS;IAClB;AAEA,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;IAC9B,IAAI,MAAM,EAAE;AACV,QAAA,OAAO,MAAM;IACf;AAEA,IAAA,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,EAAE;IACrC,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC;IACjF,IAAI,QAAQ,EAAE;AACZ,QAAA,OAAO,MAAM,CAAC,QAAQ,CAAC;IACzB;AACA,IAAA,OAAO,QAAQ;AACjB;AAEA;;AAEG;AACH,SAAS,mBAAmB,CAAC,MAI5B,EAAA;AACC,IAAA,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM;AAC9B,IAAA,IAAI,WAAW,KAAK,UAAU,EAAE;AAC9B,QAAA,OAAO,KAAK;IACd;AACA,IAAA,IAAI,WAAW,KAAK,MAAM,EAAE;AAC1B,QAAA,OAAO,IAAI;IACb;;AAEA,IAAA,MAAM,mBAAmB,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,KACrD,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,CAAA,CAAA,EAAI,UAAU,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CACrE;AACD,IAAA,IAAI,mBAAmB,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AACrC,QAAA,OAAO,IAAI;IACb;IACA,MAAM,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE;IAC/C,OAAO,mBAAmB,CAAC,IAAI,CAC7B,CAAC,KAAK,KAAK,KAAK,KAAK,iBAAiB,IAAI,KAAK,CAAC,WAAW,EAAE,KAAK,iBAAiB,CAAC,WAAW,EAAE,CAClG;AACH;AAEA;;AAEG;AACH,SAAS,oBAAoB,CAAC,MAI7B,EAAA;IACC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM;IAEjD,MAAM,WAAW,GAAG,uBAAuB,CAAC;AAC1C,QAAA,GAAG,EAAE,WAAW;QAChB,OAAO;AACR,KAAA,CAAC;IAEF,MAAM,uBAAuB,GAAG,CAAC,WAAW,EAAE,SAAS,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC;AAEpF,IAAA,IAAI,uBAAuB,CAAC,MAAM,KAAK,CAAC,EAAE;AACxC,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,IAAI,uBAAuB,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AACzC,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,OAAO,uBAAuB,CAAC,IAAI,CAAC,CAAC,KAAK,KAAI;QAC5C,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA,CAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE;QAC/E,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,CAAA,KAAA,EAAQ,QAAQ,CAAA,CAAE;AACrE,IAAA,CAAC,CAAC;AACJ;AAEA;AACA;AACA;AAEA;;;AAGG;AACG,SAAU,gBAAgB,CAAC,MAMhC,EAAA;AACC,IAAA,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM;AAC7D,IAAA,MAAM,WAAW,IAAI,MAAM,CAAC,QAAQ,GAAG,UAAU,CAAC,IAAI,EAAE,CAAgB;IAExE,MAAM,kBAAkB,GAAG,MAAM,CAAC,QAAQ,GAAG,UAAU,CAAC,EAAE,WAAW;IACrE,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,IAAI,kBAAkB,IAAI,MAAM;;;;;;;;;;;;AAc9E,IAAA,MAAM,cAAc,GAAG,WAAW,CAAC,cAAc,IAAI,EAAE;IACvD,MAAM,YAAY,GAAG,mBAAmB,CAAC;QACvC,WAAW;AACX,QAAA,SAAS,EAAE,cAAc;AACzB,QAAA,OAAO,EAAE,MAAM;AAChB,KAAA,CAAC;IAEF,IAAI,CAAC,YAAY,EAAE;QACjB,OAAO,CAAC,GAAG,GACT,CAAA,cAAA,EAAiB,MAAM,CAAA,0BAAA,EAA6B,WAAW,CAAA,CAAA,CAAG,CACnE;AACD,QAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE;IAC3B;IAEA,MAAM,aAAa,GAAG,oBAAoB,CAAC;QACzC,QAAQ;AACR,QAAA,OAAO,EAAE,MAAM;QACf,WAAW;AACZ,KAAA,CAAC;IAEF,IAAI,CAAC,aAAa,EAAE;QAClB,OAAO,CAAC,GAAG,GACT,CAAA,eAAA,EAAkB,QAAQ,CAAA,cAAA,EAAiB,MAAM,CAAA,iBAAA,CAAmB,CACrE;AACD,QAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE;IAC3B;AAEA,IAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;AAC1B;AAEA;;AAEG;AACG,SAAU,eAAe,CAAC,QAAgB,EAAE,SAAmB,EAAA;AACnE,IAAA,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AAC3B,QAAA,OAAO,IAAI;IACb;AACA,IAAA,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,KAAI;QAC9B,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA,CAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE;QAC/E,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,CAAA,KAAA,EAAQ,QAAQ,CAAA,CAAE;AACrE,IAAA,CAAC,CAAC;AACJ;;AC3LA;;;;AAIG;AAwBH;AACA;AACA;AAEA;;;AAGG;AACI,eAAe,aAAa,CAAC,MAOnC,EAAA;AACC,IAAA,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM;AACvE,IAAA,MAAM,IAAI,GAAG,eAAe,EAAE;;IAG9B,IAAI,OAAO,EAAE;AACX,QAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;IAC1B;IAEA,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM;IAClD,MAAM,eAAe,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC;;AAG9E,IAAA,IAAI,QAAQ,KAAK,UAAU,EAAE;QAC3B,OAAO,CAAC,GAAG,GAAG,2BAA2B,QAAQ,CAAA,oBAAA,CAAsB,CAAC;AACxE,QAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE;IAC3B;;AAGA,IAAA,IAAI,QAAQ,KAAK,MAAM,EAAE;AACvB,QAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;IAC1B;;IAGA,MAAM,iBAAiB,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;;AAE9H,IAAA,MAAM,iBAAiB,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC;AACxC,SAAA,kBAAkB,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE;AACxE,SAAA,KAAK,CAAC,MAAM,EAAE,CAAC;;IAGpB,MAAM,cAAc,GAAG,CAAC,GAAG,iBAAiB,EAAE,GAAG,iBAAiB,CAAC;IAEnE,MAAM,kBAAkB,GAAG,CAAC,GAAG,eAAe,EAAE,GAAG,cAAc,CAAC;IAClE,MAAM,mBAAmB,GAAG,eAAe,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IAEzE,IAAI,mBAAmB,EAAE;AACvB,QAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;IAC1B;;AAGA,IAAA,IAAI,QAAQ,KAAK,SAAS,EAAE;AAC1B,QAAA,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC;AACxE,YAAA,OAAO,EAAE,UAAU;AACnB,YAAA,EAAE,EAAE,QAAQ;YACZ,SAAS,EAAE,OAAO,CAAC,SAAS;AAC5B,YAAA,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;AACzB,SAAA,CAAC;QAEF,IAAI,OAAO,EAAE;YACX,OAAO,CAAC,GAAG,GAAG,8CAA8C,QAAQ,CAAA,CAAE,CAAC;AACvE,YAAA,IAAI;AACF,gBAAA,MAAM,cAAc,CAAC;oBACnB,QAAQ;oBACR,KAAK;oBACL,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC;AAC3C,wBAAA,OAAO,EAAE,UAAU;wBACnB,MAAM,EAAE,CAAA,YAAA,EAAe,QAAQ,CAAA,CAAE;wBACjC,IAAI;qBACL,CAAC;oBACF,OAAO;AACP,oBAAA,MAAM,EAAE,IAAI;AACb,iBAAA,CAAC;YACJ;YAAE,OAAO,GAAG,EAAE;AACZ,gBAAA,OAAO,CAAC,KAAK,GAAG,CAAA,wCAAA,EAA2C,QAAQ,CAAA,EAAA,EAAK,MAAM,CAAC,GAAG,CAAC,CAAA,CAAE,CAAC;YACxF;QACF;aAAO;YACL,OAAO,CAAC,GAAG,GAAG,qDAAqD,QAAQ,CAAA,CAAE,CAAC;QAChF;QACA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE;IACjD;;IAGA,OAAO,CAAC,GAAG,GAAG,CAAA,oCAAA,EAAuC,QAAQ,CAAA,WAAA,EAAc,QAAQ,CAAA,CAAA,CAAG,CAAC;AACvF,IAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE;AAC3B;;ACtHA;AACA;AACA;AAkBA;AACA;AACA;AAEA,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAC/C,MAAM,uBAAuB,GAAG,GAAG;AAqBnC;AACA;AACA;AAEM,SAAU,0BAA0B,CACxC,SAAiB,EACjB,OAA2B,EAAA;AAE3B,IAAA,MAAM,KAAK,GAAqB,cAAc;AAC9C,IAAA,MAAM,aAAa,GAA6B,uBAAuB;;AAGvE,IAAA,MAAM,MAAM,GAAG,IAAI,GAAG,EAAsB;;;AAK5C,IAAA,SAAS,SAAS,CAAC,KAAiB,EAAE,GAAW,EAAA;QAC/C,OAAoB,GAAG,GAAG,KAAK,CAAC,EAAE,IAAI,KAAK;IAC7C;AAEA;;;AAGG;AACH,IAAA,SAAS,WAAW,GAAA;AAClB,QAAA,IAAI,MAAM,CAAC,IAAI,IAAI,aAAa;YAAE;AAClC,QAAA,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACtE,QAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,GAAG,aAAa,CAAC;AAC7D,QAAA,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,QAAQ,EAAE;AAC5B,YAAA,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC;QACpB;IACF;;AAIA,IAAA,SAAS,GAAG,CAAC,MAAc,EAAE,KAAa,EAAA;AACxC,QAAA,MAAM,KAAK,GAAe,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE;;AAEnD,QAAA,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;AACrB,QAAA,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC;AACzB,QAAA,WAAW,EAAE;IACf;IAEA,eAAe,GAAG,CAAC,MAAc,EAAA;AAC/B,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;;QAGtB,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;QACnC,IAAI,QAAQ,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE;YACzC,OAAO,QAAQ,CAAC,KAAK;QACvB;QACA,IAAI,QAAQ,EAAE;AACZ,YAAA,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACxB;AAEA,QAAA,OAAO,SAAS;IAClB;IAEA,SAAS,OAAO,CAAC,MAAc,EAAA;AAC7B,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;QACtB,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;QAChC,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE;YACnC,OAAO,KAAK,CAAC,KAAK;QACpB;QACA,IAAI,KAAK,EAAE;AACT,YAAA,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;QACvB;AACA,QAAA,OAAO,SAAS;IAClB;IAEA,SAAS,GAAG,CAAC,MAAc,EAAA;AACzB,QAAA,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;IACvB;AAEA,IAAA,SAAS,WAAW,GAAA;QAClB,MAAM,CAAC,KAAK,EAAE;IAChB;AAEA,IAAA,SAAS,UAAU,GAAA;QACjB,OAAO,MAAM,CAAC,IAAI;IACpB;IAEA,OAAO;QACL,GAAG;QACH,GAAG;QACH,OAAO;AACP,QAAA,MAAM,EAAE,GAAG;QACX,WAAW;QACX,UAAU;KACX;AACH;;ACzIA;;;;;AAKG;AAWH;AACA;AACA;AAEA;AACA,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAoB;AAErD;;AAEG;AACG,SAAU,iBAAiB,CAAC,SAAiB,EAAA;IACjD,OAAO,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI;AACjD;AAEA;;AAEG;AACG,SAAU,iBAAiB,CAAC,SAAiB,EAAE,MAAgB,EAAA;AACnE,IAAA,iBAAiB,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC;AAC1C;AAmBA;AACA,MAAM,aAAa,GAAG,IAAI,GAAG,EAA6B;AAE1D;AACA,IAAI,YAAY,GAA0C,IAAI;AAE9D;;AAEG;SACa,wBAAwB,GAAA;AACtC,IAAA,IAAI,YAAY;QAAE;AAElB,IAAA,YAAY,GAAG,WAAW,CAAC,MAAK;AAC9B,QAAA,kBAAkB,EAAE;IACtB,CAAC,EAAE,iCAAiC,CAAC;;IAGrC,IAAI,YAAY,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,OAAO,IAAI,YAAY,EAAE;QAC/E,YAAY,CAAC,KAAK,EAAE;IACtB;AACF;AAEA;;AAEG;SACa,uBAAuB,GAAA;IACrC,IAAI,YAAY,EAAE;QAChB,aAAa,CAAC,YAAY,CAAC;QAC3B,YAAY,GAAG,IAAI;IACrB;AACF;AAEA;;AAEG;AACH,SAAS,kBAAkB,GAAA;AACzB,IAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;;IAGtB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,aAAa,EAAE;QACxC,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,IAAI,oBAAoB,EAAE;AACjD,YAAA,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC;QAC3B;IACF;;AAGA,IAAA,IAAI,aAAa,CAAC,IAAI,GAAG,sBAAsB,EAAE;AAC/C,QAAA,MAAM,MAAM,GAAG,CAAC,GAAG,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3F,QAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,sBAAsB,CAAC;AAC7E,QAAA,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,QAAQ,EAAE;AAC5B,YAAA,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC;QAC3B;IACF;AACF;AAEA;;AAEG;AACG,SAAU,eAAe,CAAC,SAAiB,EAAE,KAAmB,EAAA;AACpE,IAAA,aAAa,CAAC,GAAG,CAAC,SAAS,EAAE;QAC3B,KAAK;AACL,QAAA,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;AACtB,KAAA,CAAC;AACJ;AAiBA;;AAEG;AACG,SAAU,kBAAkB,CAAC,SAAiB,EAAA;AAClD,IAAA,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC;AACjC;AASA;AACA;AACA;AAEA;;;;AAIG;AACH,MAAM,WAAW,GAAG,IAAI,GAAG,EAAgC;AAE3D,SAAS,qBAAqB,CAAC,SAAiB,EAAA;IAC9C,IAAI,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC;IACtC,IAAI,CAAC,KAAK,EAAE;AACV,QAAA,KAAK,GAAG,0BAA0B,CAAU,CAAC;AAC7C,QAAA,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC;IACnC;AACA,IAAA,OAAO,KAAK;AACd;AAEA;AACA;AACA;AAEA;;AAEG;AACG,SAAU,eAAe,CAAC,MAAc,EAAE,KAAa,EAAE,SAAS,GAAG,SAAS,EAAA;IAClF,qBAAqB,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC;AACrD;AAuBA;;;;AAIG;AACI,eAAe,gBAAgB,CACpC,SAAS,GAAG,SAAS,EACrB,GAAkC,EAAA;;AAGlC,IAAA,GAAG,GAAG,0DAA0D,CAAC;AACjE,IAAA,OAAO,CAAC;AACV;AAWA;AACA;AACA;AAEA;;AAEG;AACI,eAAe,cAAc,CAAC,SAAiB,EAAA;;IAEpD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC;IACjD,IAAI,QAAQ,EAAE;AACZ,QAAA,IAAI;YACF,QAAQ,CAAC,UAAU,EAAE;QACvB;AAAE,QAAA,MAAM;;QAER;AACA,QAAA,iBAAiB,CAAC,MAAM,CAAC,SAAS,CAAC;IACrC;;;AAIF;;AChPA;AACA,MAAM,UAAU,GAAG,MAAa;AAC9B,IAAA,IAAI;;AAEF,QAAA,MAAM,UAAU,GAAGC,YAAO,CAACJ,sBAAa,CAAC,8PAAe,CAAC,CAAC;;QAG1D,MAAM,OAAO,GAAGK,YAAO,CAAC,UAAU,EAAE,IAAI,EAAE,cAAc,CAAC;AACzD,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAACC,oBAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AACtD,QAAA,OAAO,GAAG,CAAC,OAAO,IAAI,EAAE;IAC1B;AAAE,IAAA,MAAM;AACN,QAAA,OAAO,EAAE;IACX;AACF,CAAC;AAED;AACO,MAAM,cAAc,GAAW,UAAU,EAAE;;ACpBlD;;;;;;;;;;;;;;;;AAgBG;AA4CH;;;AAGG;AACH,SAAS,cAAc,CAAC,IAAY,EAAA;AAClC,IAAA,OAAO,IAAI;;AAEb;AAWA,MAAM,wBAAwB,GAAG,IAAI,GAAG,EAAsC;AAC9E,MAAM,0BAA0B,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;AACtD,MAAM,4BAA4B,GAAG,GAAG;AAExC,SAAS,uBAAuB,CAAC,SAAiB,EAAE,MAAc,EAAA;AAChE,IAAA,OAAO,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,MAAM,EAAE;AACjC;AAEA,SAAS,sBAAsB,GAAA;AAC7B,IAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAEtB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,wBAAwB,EAAE;QACnD,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,IAAI,0BAA0B,EAAE;AACvD,YAAA,wBAAwB,CAAC,MAAM,CAAC,GAAG,CAAC;QACtC;IACF;AAEA,IAAA,IAAI,wBAAwB,CAAC,IAAI,IAAI,4BAA4B,EAAE;QACjE;IACF;AAEA,IAAA,MAAM,aAAa,GAAG,CAAC,GAAG,wBAAwB,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAChE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAC1C;AACD,IAAA,MAAM,WAAW,GAAG,wBAAwB,CAAC,IAAI,GAAG,4BAA4B;AAChF,IAAA,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,EAAE;AACvD,QAAA,wBAAwB,CAAC,MAAM,CAAC,GAAG,CAAC;IACtC;AACF;AAEA,SAAS,iBAAiB,CAAC,IAAkB,EAAA;IAC3C,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAiB;AACzD;AAEA,SAAS,uBAAuB,CAAC,MAIhC,EAAA;IACC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,MAAM;AACnD,IAAA,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO;IACnC,IAAI,CAAC,MAAM,EAAE;AACX,QAAA,OAAO,CAAC,GAAG,GAAG,iEAAiE,CAAC;QAChF;IACF;IAEA,wBAAwB,CAAC,GAAG,CAAC,uBAAuB,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE;AACvE,QAAA,YAAY,EAAE,iBAAiB,CAAC,YAAY,CAAC;AAC7C,QAAA,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;AACtB,KAAA,CAAC;AACF,IAAA,sBAAsB,EAAE;AAC1B;AAEA,SAAS,wBAAwB,CAAC,SAAiB,EAAE,MAAc,EAAA;AACjE,IAAA,sBAAsB,EAAE;AACxB,IAAA,MAAM,MAAM,GAAG,wBAAwB,CAAC,GAAG,CAAC,uBAAuB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACvF,IAAI,CAAC,MAAM,EAAE;AACX,QAAA,OAAO,SAAS;IAClB;AACA,IAAA,OAAO,iBAAiB,CAAC,MAAM,CAAC,YAAY,CAAC;AAC/C;AAIA,SAAS,sBAAsB,CAAC,iBAA4C,EAAA;AAC1E,IAAA,MAAM,WAAW,GAAG,IAAI,GAAG,EAAoB;IAC/C,MAAM,aAAa,GAAG,iBAAiB,EAAE,cAAc,EAAE,aAAa,IAAI,EAAE;AAE5E,IAAA,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE;QAChC,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,EAAE;QAC7C,IAAI,CAAC,WAAW,EAAE;YAChB;QACF;AACA,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE;AACnE,QAAA,WAAW,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC;IACzC;AAEA,IAAA,OAAO,WAAW;AACpB;AAEA,SAAS,gCAAgC,CAAC,MAIzC,EAAA;IACC,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,GAAG,MAAM;AAC/D,IAAA,MAAM,QAAQ,GAAG,iBAAiB,CAAC,YAAY,CAAC;AAEhD,IAAA,IAAI,iBAAiB,EAAE,OAAO,EAAE;AAC9B,QAAA,QAAQ,CAAC,OAAO,GAAG,iBAAiB,CAAC,OAAO;IAC9C;AACA,IAAA,IAAI,iBAAiB,EAAE,SAAS,EAAE;AAChC,QAAA,QAAQ,CAAC,SAAS,GAAG,iBAAiB,CAAC,SAAS;IAClD;;AAGA,IAAA,IAAI,QAAQ,CAAC,aAAa,EAAE,IAAI,EAAE;AAChC,QAAA,QAAQ,CAAC,aAAa,CAAC,IAAI,GAAG,KAAK;IACrC;AAEA,IAAA,IAAI,QAAQ,CAAC,QAAQ,EAAE,YAAY,EAAE;AACnC,QAAA,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,EAAE;AACzE,QAAA,QAAQ,CAAC,QAAQ,CAAC,OAAO,GAAG,IAAI;QAChC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE;AAChD,YAAA,QAAQ,CAAC,QAAQ,CAAC,WAAW,GAAG,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,MAAM;AAC7E,gBAAA,GAAG,MAAM;gBACT,UAAU,EAAE,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;AAC5C,aAAA,CAAC,CAAC;QACL;IACF;IAEA,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE;AACvC,QAAA,QAAQ,CAAC,WAAW,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,SAAS,KAAI;AAC5D,YAAA,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE;YACjE,OAAO;AACL,gBAAA,GAAG,SAAS;AACZ,gBAAA,OAAO,EAAE,IAAI;gBACb,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,WAAW;aACrD;AACH,QAAA,CAAC,CAAC;IACJ;AAEA,IAAA,IAAI,QAAQ,CAAC,gBAAgB,EAAE,YAAY,EAAE;AAC3C,QAAA,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CAAC,YAAY,CAAC,IAAI,EAAE;AACjF,QAAA,QAAQ,CAAC,gBAAgB,CAAC,OAAO,GAAG,IAAI;AACxC,QAAA,IAAI,WAAW,CAAC,CAAC,CAAC,EAAE;YAClB,QAAQ,CAAC,gBAAgB,CAAC,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC;QACxD;IACF;AAEA,IAAA,OAAO,QAAQ;AACjB;AAEA,eAAe,yBAAyB,CAAC,MAKxC,EAAA;IACC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM;AACtD,IAAA,MAAM,IAAI,GAAG,KAAK,CAAC,IAAmB;AACtC,IAAA,MAAM,iBAAiB,GAAG,IAAI,CAAC,KAAK,EAAE,mBAAmB;AACzD,IAAA,MAAM,MAAM,GAAG,iBAAiB,EAAE,OAAO;IAEzC,IAAI,CAAC,MAAM,EAAE;QACX,OAAO,CAAC,GAAG,GAAG,IAAI,SAAS,CAAA,iEAAA,CAAmE,CAAC;QAC/F;IACF;IAEA,MAAM,UAAU,GAAG,wBAAwB,CAAC,SAAS,EAAE,MAAM,CAAC;IAC9D,IAAI,CAAC,UAAU,EAAE;QACf,OAAO,CAAC,GAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,8CAAA,EAAiD,MAAM,CAAA,mBAAA,CAAqB,CAAC;QACxG;IACF;AAEA,IAAA,MAAM,WAAW,GAAG,sBAAsB,CAAC,iBAAiB,CAAC;IAC7D,MAAM,WAAW,GAAG,gCAAgC,CAAC;AACnD,QAAA,YAAY,EAAE,UAAU;QACxB,WAAW;QACX,iBAAiB;AAClB,KAAA,CAAC;AAEF,IAAA,MAAM,QAAQ,CAAC,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzE,OAAO,CAAC,GAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,iDAAA,EAAoD,MAAM,CAAA,CAAE,CAAC;;AAGxF,IAAA,uBAAuB,CAAC;QACtB,SAAS;AACT,QAAA,YAAY,EAAE,WAAW;QACzB,OAAO;AACR,KAAA,CAAC;AACJ;AAEA;AACA;AACA;AAEA;;AAEG;AACH,SAAS,eAAe,GAAA;AACtB,IAAA,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE;AACtG,IAAA,IAAI,aAAa;AAAE,QAAA,OAAO,aAAa;IACvC,OAAOT,iBAAI,CAAC,IAAI,CAACE,eAAE,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC;AAC7C;AAEA;;;;;;;;;;;;;;;;AAgBG;AACH,eAAe,0BAA0B,CAAC,MAAoB,EAAA;;AAE5D,IAAA,MAAM,QAAQ,GAAG,MAAM,yBAAyB,EAAE;AAClD,IAAA,MAAM,KAAK,GAAa,CAAC,GAAG,QAAQ,CAAC;IAErC,MAAM,QAAQ,GAAGF,iBAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;IAChD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;AAC7B,QAAA,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;IACtB;;AAEA,IAAA,IAAI,MAAM,EAAE,eAAe,EAAE;AAC3B,QAAA,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,eAAe,EAAE;AACtC,YAAA,MAAM,QAAQ,GAAGA,iBAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,EAAEE,eAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YACpE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;AAC7B,gBAAA,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;YACtB;QACF;IACF;AACA,IAAA,OAAO,KAAK;AACd;AAEA;AACA;AACA;AAEA;;;;AAIG;AACH,SAAS,sBAAsB,CAC7B,QAAgB,EAChB,MAAiD,EAAA;IAEjD,IAAI,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,uBAAuB,CAAC,EAAE;QACnD,OAAO,CAAA,mBAAA,EAAsB,QAAQ,CAAA,qDAAA,CAAuD;IAC9F;AACA,IAAA,IAAI,MAAM,CAAC,YAAY,EAAE;AACvB,QAAA,OAAO,CAAA,UAAA,EAAa,MAAM,CAAC,YAAY,EAAE;IAC3C;IACA,OAAO,CAAA,iBAAA,EAAoB,QAAQ,CAAA,OAAA,CAAS;AAC9C;AAmBA;AACA;AACA;AAEA;;AAEG;AACH,SAAS,mBAAmB,CAC1B,KAAc,EACd,OAA6B,EAC7B,MAAsB,EACtB,IAAY,EACZ,SAAwD,EACxD,YAAqB,EAAA;AAErB,IAAA,MAAM,IAAI,GAAG,eAAe,EAAE;AAC9B,IAAA,MAAM,IAAI,GAAG,KAAK,CAAC,IAAmB;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM;AAC9C,IAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,KAAK,OAAO,GAAG,OAAO,GAAG,QAAQ;;IAG/D,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC;AACnD,QAAA,GAAG,EAAE,MAAM;AACX,QAAA,OAAO,EAAE,UAAU;QACnB,SAAS,EAAE,OAAO,CAAC,SAAS;AAC5B,QAAA,IAAI,EAAE;AACJ,YAAA,IAAI,EAAE,QAAQ;AACd,YAAA,EAAE,EAAE,MAAM;AACX,SAAA;AACF,KAAA,CAAC;;IAGF,MAAM,SAAS,GAAG,QAAQ,KAAK,OAAO,GAAG,CAAA,MAAA,EAAS,MAAM,EAAE,GAAG,CAAA,KAAA,EAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,CAAA,CAAE;;IAGvF,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;AAC5E,IAAA,MAAM,WAAW,GAAG,IAAI,KAAK,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,GAAG,uBAAuB,GAAG,0BAA0B,IAAI,EAAE,CAAC;;IAG5H,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,SAAS;AAClF,IAAA,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,GAAG;AACpC,UAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,OAAO;UACnD,SAAS;;AAGb,IAAA,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC;AAC/C,QAAA,IAAI,EAAE,WAAW;AACjB,QAAA,OAAO,EAAE,WAAW;AACpB,QAAA,WAAW,EAAE,WAAW;QAExB,UAAU,EAAE,IAAI,CAAC,KAAK;QAEtB,IAAI,EAAE,QAAQ,KAAK,OAAO,GAAG,CAAA,EAAG,UAAU,CAAA,OAAA,EAAU,MAAM,EAAE,GAAG,CAAA,EAAG,UAAU,CAAA,CAAA,EAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAA,CAAE;AAClG,QAAA,EAAE,EAAE,CAAA,EAAG,UAAU,CAAA,CAAA,EAAI,MAAM,CAAA,CAAE;AAC7B,QAAA,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;QAE1B,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,SAAS,EAAE,OAAO,CAAC,SAAS;AAE5B,QAAA,QAAQ,EAAE,QAAQ;AAClB,QAAA,iBAAiB,EAAE,SAAS;AAE5B,QAAA,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;AAErB,QAAA,QAAQ,EAAE,UAAU;AACpB,QAAA,OAAO,EAAE,UAAU;AAEnB,QAAA,kBAAkB,EAAE,UAAU;AAC9B,QAAA,aAAa,EAAE,CAAA,EAAG,UAAU,CAAA,CAAA,EAAI,MAAM,CAAA,CAAE;AAExC,QAAA,iBAAiB,EAAE,IAAI;QAEvB,WAAW,EAAE,IAAI,CAAC,YAAY;AAC9B,QAAA,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM;AAC3B,QAAA,UAAU,EAAE,KAAK;AAEjB,QAAA,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI;AAC7B,QAAA,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW;AACpC,QAAA,UAAU,EAAE,UAAU;AACtB,QAAA,UAAU,EAAE,UAAU;AACtB,QAAA,SAAS,EAAE,UAAU;AAErB,QAAA,WAAW,EAAE,YAAY;AAC1B,KAAA,CAAC;AACJ;AAeA;;AAEG;AACH,eAAe,iBAAiB,CAAC,MAMhC,EAAA;AACC,IAAA,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM;AAC5D,IAAA,IAAI;AACF,QAAA,MAAM,cAAc,CAAC;YACnB,QAAQ;YACR,KAAK;AACL,YAAA,IAAI,EAAE,gBAAgB;YACtB,OAAO;AACP,YAAA,MAAM,EAAE,KAAK;YACb,QAAQ;AACT,SAAA,CAAC;IACJ;IAAE,OAAO,GAAG,EAAE;AACZ,QAAA,IAAI,GAAG,YAAY,kBAAkB,IAAI,KAAK,EAAE;AAC9C,YAAA,KAAK,CAAC,aAAa,GAAG,IAAI;AAC1B,YAAA,OAAO,CAAC,GAAG,GAAG,CAAA,6EAAA,CAA+E,CAAC;QAChG;aAAO;YACL,OAAO,CAAC,KAAK,GAAG,CAAA,yCAAA,EAA4C,MAAM,CAAC,GAAG,CAAC,CAAA,CAAE,CAAC;QAC5E;IACF;AACF;AAEA;;;;;AAKG;AACH,eAAe,cAAc,CAC3B,GAAmB,EACnB,SAAmB,EAAA;AAEnB,IAAA,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,GAAG;AACxD,IAAA,MAAM,IAAI,GAAG,KAAK,CAAC,IAAmB;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM;IAC9C,MAAM,eAAe,GAAG,MAAM,0BAA0B,CAAC,OAAO,CAAC,MAAM,CAAC;IAExE,OAAO,CAAC,GAAG,GAAG,kCAAkC,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,CAAA,YAAA,EAAe,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAA,CAAE,CAAC;AAE1H,IAAA,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;AAChC,QAAA,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC;YACtC,QAAQ;YACR,QAAQ;YACR,MAAM;YACN,eAAe;AACf,YAAA,GAAG,EAAE,CAAC,GAAG,IAAW,KAAK,OAAO,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC;AAC/C,YAAA,QAAQ,EAAE,CAAC,GAAG,IAAW,KAAK,OAAO,CAAC,KAAK,GAAG,GAAG,IAAI,CAAC;AACvD,SAAA,CAAC;AAEF,QAAA,IAAI,MAAM,CAAC,EAAE,EAAE;AACb,YAAA,KAAK,CAAC,QAAQ,GAAG,IAAI;QACvB;aAAO;AACL,YAAA,KAAK,CAAC,cAAc,GAAG,IAAI;AAC3B,YAAA,OAAO,CAAC,KAAK,GAAG,CAAA,+BAAA,EAAkC,QAAQ,CAAA,SAAA,EAAY,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,KAAK,CAAA,CAAE,CAAC;;YAE5G,MAAM,OAAO,GAAG,sBAAsB,CAAC,QAAQ,EAAE,MAAM,CAAC;AACxD,YAAA,KAAK,CAAC,iBAAiB,GAAG,KAAK,CAAC;AAC9B,kBAAE,CAAA,EAAG,KAAK,CAAC,iBAAiB,CAAA,IAAA,EAAO,OAAO,CAAA;kBACxC,OAAO;QACb;IACF;AACF;AAEA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACH,eAAe,oBAAoB,CAAC,GAAmB,EAAA;AACrD,IAAA,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAW,OAAO,EAAE,GAAG,GAAG;AACxD,IAAA,MAAM,IAAI,GAAG,KAAK,CAAC,IAAmB;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM;IAC9C,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,CAAC,eAAe,CAAC;;;;IAKzD,IAAI,WAAW,EAAE;QACf,OAAO,CAAC,GAAG,GAAG,CAAA,wEAAA,EAA2E,WAAW,CAAC,MAAM,CAAA,iCAAA,CAAmC,CAAC;AAC/I,QAAA,MAAM,KAAK,GAAG,CAAC,GAAG,IAAW,KAAU;AACrC,YAAA,OAAO,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC;AACxB,QAAA,CAAC;AACD,QAAA,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,oBAAoB,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC;AAEnF,QAAA,OAAO,CAAC,GAAG,GAAG,oFAAoF,KAAK,CAAC,MAAM,CAAA,sBAAA,EAAyB,aAAa,CAAC,MAAM,CAAA,CAAE,CAAC;AAE9J,QAAA,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;AACpB,YAAA,OAAO,CAAC,GAAG,GAAG,CAAA,6CAAA,EAAgD,KAAK,CAAC,MAAM,CAAA,+BAAA,EAAkC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA,CAAA,CAAG,CAAC;AACrJ,YAAA,MAAM,iBAAiB,CAAC,GAAG,EAAE,KAAK,CAAC;;AAGnC,YAAA,MAAM,gBAAgB,GAAG,cAAc,CAAC,aAAa,CAAC;YACtD,MAAM,UAAU,GAAG;AACjB,kBAAE;AACF,mBAAG,KAAK,CAAC,eAAe,GAAG,aAAa,GAAG,SAAS,CAAC;AACvD,YAAA,OAAO,CAAC,GAAG,GAAG,CAAA,6EAAA,EAAgF,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA,sBAAA,EAAyB,KAAK,CAAC,eAAe,CAAA,CAAE,CAAC;YACvK,MAAM,cAAc,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC5G;QACF;IACF;SAAO;AACL,QAAA,OAAO,CAAC,GAAG,GAAG,CAAA,8FAAA,CAAgG,CAAC;IACjH;;AAGA,IAAA,IAAI,UAAU,GAAW,KAAK,CAAC,eAAe;IAC9C,IAAI,WAAW,EAAE;;AAEf,QAAA,UAAU,GAAG,KAAK,CAAC,eAAe;IACpC;AAAO,SAAA,IAAI,KAAK,CAAC,QAAQ,EAAE;QACzB,IAAI,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,iBAAiB,EAAE;;AAEnD,YAAA,UAAU,GAAG,UAAU,GAAG,CAAA,EAAG,UAAU,CAAA,IAAA,EAAO,KAAK,CAAC,iBAAiB,EAAE,GAAG,KAAK,CAAC,iBAAiB;QACnG;aAAO,IAAI,CAAC,UAAU,EAAE;YACtB,UAAU,GAAG,eAAe;QAC9B;IACF;;;;IAMA,IAAI,UAAU,EAAE;;AAEd,QAAA,IAAI,OAAO,GAAG,KAAK,CAAC,aAAa;QACjC,IAAI,CAAC,OAAO,EAAE;AACZ,YAAA,IAAI;gBACF,MAAM,cAAc,CAAC,EAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAC,CAAC;YAC5G;YAAE,OAAO,GAAG,EAAE;AACZ,gBAAA,IAAI,GAAG,YAAY,kBAAkB,EAAE;oBACrC,OAAO,GAAG,IAAI;gBAChB;qBAAO;AACL,oBAAA,MAAM,GAAG;gBACX;YACF;QACF;QACA,IAAI,OAAO,EAAE;AACX,YAAA,OAAO,CAAC,GAAG,GAAG,CAAA,sEAAA,CAAwE,CAAC;AACvF,YAAA,MAAM,QAAQ,CAAC,WAAW,CAAC,MAAM,EAAE;AACjC,gBAAA,OAAO,EAAE,UAAU;AACnB,gBAAA,QAAQ,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE;AAClC,aAAA,CAAC;QACJ;IACF;AACF;AAEA;;;;AAIG;AACH,eAAe,iBAAiB,CAC9B,GAAmB,EACnB,KAAuD,EAAA;AAEvD,IAAA,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,GAAG;AACxD,IAAA,MAAM,IAAI,GAAG,KAAK,CAAC,IAAmB;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM;AAE9C,IAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;AACxB,QAAA,IAAI;AACF,YAAA,OAAO,CAAC,GAAG,GAAG,CAAA,yCAAA,EAA4C,IAAI,CAAC,QAAQ,CAAA,WAAA,EAAc,MAAM,CAAA,CAAE,CAAC;AAE9F,YAAA,MAAM,eAAe,GAAG,IAAI,CAAC,QAAmC;AAChE,YAAA,IAAI,OAAO,eAAe,CAAC,SAAS,KAAK,QAAQ,EAAE;AACjD,gBAAA,OAAO,CAAC,KAAK,GAAG,qEAAqE,CAAC;gBACtF;YACF;YAEA,MAAM,YAAY,GAAG,eAA0C;AAC/D,YAAA,MAAM,QAAQ,CAAC,WAAW,CAAC,MAAM,EAAE;AACjC,gBAAA,OAAO,EAAE,eAAe;AACxB,gBAAA,aAAa,EAAE,YAAY;AAC5B,aAAA,CAAC;AACF,YAAA,KAAK,CAAC,eAAe,GAAG,IAAI;AAC5B,YAAA,uBAAuB,CAAC;gBACtB,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,YAAY;gBACZ,OAAO;AACR,aAAA,CAAC;YACF,OAAO,CAAC,GAAG,GAAG,CAAA,yDAAA,EAA4D,IAAI,CAAC,QAAQ,CAAA,CAAE,CAAC;QAC5F;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,OAAO,CAAC,KAAK,GAAG,CAAA,sDAAA,EAAyD,IAAI,CAAC,QAAQ,CAAA,QAAA,EAAW,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA,CAAE,CAAC;QACzH;IACF;AACF;AAEA;;AAEG;AACH,eAAe,uBAAuB,CAAC,MAStC,EAAA;AACC,IAAA,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM;AAC1F,IAAA,MAAM,IAAI,GAAG,eAAe,EAAE;AAC9B,IAAA,MAAM,GAAG,GAAmB,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE;;IAGxE,IAAI,SAAS,GAAG,KAAK;IACrB,MAAM,WAAW,GAAG,MAAK;QACvB,IAAI,CAAC,SAAS,EAAE;YAAE,SAAS,GAAG,IAAI;AAAE,YAAA,SAAS,EAAE;QAAE;AACnD,IAAA,CAAC;IAED,IAAI,WAAW,GAAG,EAAE,OAAO,CAAC,mBAAmB,IAAI,IAAI,CAAC;AAExD,IAAA,IAAI;AACF,QAAA,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC;AAChE,YAAA,GAAG,EAAE,UAAU;AACf,YAAA,GAAG,EAAE,MAAM;;;;;;;;;;;;;;;AAeX,YAAA,iBAAiB,EAAE;gBACjB,YAAY,EAAE,YAAW;AACvB,oBAAA,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE;AAC5D,wBAAA,IAAI;AACF,4BAAA,MAAM,iBAAiB,CAAC,EAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAC,CAAC;wBACtF;wBAAE,OAAO,CAAC,EAAE;4BACV,OAAO,CAAC,KAAK,GAAG,CAAA,qCAAA,EAAwC,MAAM,CAAC,CAAC,CAAC,CAAA,CAAE,CAAC;wBACtE;wBACA,WAAW,GAAG,IAAI;oBACpB;gBACF,CAAC;AACD,gBAAA,OAAO,EAAE,OAAO,OAAO,EAAE,IAAI,KAAI;AAC/B,oBAAA,KAAK,CAAC,aAAa,GAAG,IAAI;;;AAI1B,oBAAA,IAAI,OAAO,CAAC,IAAI,EAAE;wBAChB,KAAK,CAAC,eAAe,KAAK,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;oBAC/C;;AAGA,oBAAA,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC,QAAQ,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE;AAC5G,oBAAA,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;AACxB,wBAAA,IAAI;AACF,4BAAA,MAAM,cAAc,CAAC,GAAG,EAAE,SAAS,CAAC;wBACtC;wBAAE,OAAO,QAAQ,EAAE;;;AAGjB,4BAAA,KAAK,CAAC,cAAc,GAAG,IAAI;AAC3B,4BAAA,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC;AAC/B,4BAAA,MAAM,OAAO,GAAG,CAAA,8CAAA,EAAiD,MAAM,EAAE;AACzE,4BAAA,KAAK,CAAC,iBAAiB,GAAG,KAAK,CAAC;AAC9B,kCAAE,CAAA,EAAG,KAAK,CAAC,iBAAiB,CAAA,IAAA,EAAO,OAAO,CAAA;kCACxC,OAAO;4BACX,OAAO,CAAC,KAAK,GAAG,iCAAiC,MAAM,CAAA,CAAE,CAAC;wBAC5D;oBACF;;;;AAKA,oBAAA,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,eAAe,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE;AAC1E,wBAAA,IAAI;4BACF,MAAM,WAAW,GAAG,sBAAsB,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC,GAAG,IAAW,KAAK,OAAO,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC;AAC7G,4BAAA,IAAI,WAAW,KAAK,KAAK,CAAC,eAAe,EAAE;AACzC,gCAAA,OAAO,CAAC,GAAG,GAAG,CAAA,kDAAA,EAAqD,KAAK,CAAC,eAAe,CAAC,MAAM,iBAAiB,WAAW,CAAC,MAAM,CAAA,KAAA,CAAO,CAAC;4BAC5I;4BACA,MAAM,cAAc,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;wBAChH;wBAAE,OAAO,GAAG,EAAE;AACZ,4BAAA,IAAI,GAAG,YAAY,kBAAkB,EAAE;AACrC,gCAAA,KAAK,CAAC,aAAa,GAAG,IAAI;AAC1B,gCAAA,OAAO,CAAC,GAAG,GAAG,CAAA,iFAAA,CAAmF,CAAC;4BACpG;iCAAO;AACL,gCAAA,MAAM,GAAG;4BACX;wBACF;oBACF;gBACF,CAAC;AACD,gBAAA,OAAO,EAAE,CAAC,GAAG,EAAE,IAAI,KAAI;AACrB,oBAAA,OAAO,CAAC,KAAK,GAAG,WAAW,IAAI,CAAC,IAAI,CAAA,eAAA,EAAkB,MAAM,CAAC,GAAG,CAAC,CAAA,CAAE,CAAC;gBACtE,CAAC;AACF,aAAA;AACF,SAAA,CAAC;;AAGF,QAAA,MAAM,oBAAoB,CAAC,GAAG,CAAC;AAC/B,QAAA,WAAW,EAAE;IACf;IAAE,OAAO,GAAG,EAAE;QACZ,OAAO,CAAC,KAAK,GAAG,CAAA,2CAAA,EAA8C,MAAM,CAAC,GAAG,CAAC,CAAA,CAAE,CAAC;;;AAG5E,QAAA,IAAI;AACF,YAAA,MAAM,oBAAoB,CAAC,GAAG,CAAC;QACjC;QAAE,OAAO,SAAS,EAAE;YAClB,OAAO,CAAC,KAAK,GAAG,CAAA,+DAAA,EAAkE,MAAM,CAAC,SAAS,CAAC,CAAA,CAAE,CAAC;QACxG;AACA,QAAA,WAAW,EAAE;IACf;AACF;AAEA;;;;;;;;;;;;;AAaG;AACH,eAAe,mBAAmB,CAAC,MAMlC,EAAA;AACC,IAAA,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM;AAC5D,IAAA,MAAM,IAAI,GAAG,KAAK,CAAC,IAAmB;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM;AAC9C,IAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,KAAK,OAAO,GAAG,OAAO,GAAG,QAAQ;AAC/D,IAAA,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK;AAC5B,IAAA,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM;;AAGlC,IAAA,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,mBAAmB,CAAC,IAAI,CAAC;IAC7G,IAAI,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE;;;;;;AAQtC,IAAA,IAAI,CAAC,IAAI,IAAI,YAAY,EAAE;QACzB,IAAI,GAAG,YAAY;AACnB,QAAA,OAAO,CAAC,GAAG,GAAG,+EAA+E,CAAC;IAChG;;AAGA,IAAA,IAAI,CAAC,IAAI,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;AAC5D,QAAA,OAAO,CAAC,GAAG,GAAG,wEAAwE,CAAC;QACvF;IACF;;AAGA,IAAA,IAAI,QAAQ,KAAK,OAAO,EAAE;QACxB,MAAM,iBAAiB,GAAG,gBAAgB,CAAC;YACzC,MAAM;AACN,YAAA,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;YAC1B,OAAO;YACP,MAAM;YACN,OAAO;AACR,SAAA,CAAC;AAEF,QAAA,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE;YAC9B;QACF;IACF;;AAGA,IAAA,MAAM,cAAc,GAAG,MAAM,aAAa,CAAC;AACzC,QAAA,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;QAC1B,OAAO,EAAE,QAAQ,KAAK,OAAO;QAC7B,OAAO;QACP,QAAQ;QACR,KAAK;QACL,OAAO;AACR,KAAA,CAAC;AAEF,IAAA,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;QAC3B;IACF;;IAGA,MAAM,CAAC,cAAc,EAAE,aAAa,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;AACxD,QAAA,qBAAqB,CAAC;YACpB,SAAS;YACT,YAAY;YACZ,OAAO;YACP,MAAM;YACN,OAAO;YACP,QAAQ;SACT,CAAC;AACF,QAAA,oBAAoB,CAAC;YACnB,QAAQ;YACR,WAAW;YACX,OAAO;YACP,MAAM;YACN,OAAO;YACP,QAAQ;SACT,CAAC;AACH,KAAA,CAAC;IACF,MAAM,SAAS,GAAG,CAAC,GAAG,cAAc,EAAE,GAAG,aAAa,CAAC;;IAGvD,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC;AAEjD,IAAA,MAAM,QAAQ,GAAGG,0BAAa,CAAC,QAAQ,CAAC;IACxC,MAAM,KAAK,GAAiB,EAAE,eAAe,EAAE,EAAE,EAAE,QAAQ,EAAE;AAC7D,IAAA,eAAe,CAAC,SAAS,EAAE,KAAK,CAAC;IAEjC,MAAM,YAAY,GAAG,MAAK;QACxB,kBAAkB,CAAC,SAAS,CAAC;AAC/B,IAAA,CAAC;;;;;;;AASD,IAAA,MAAM,UAAU,GAAG,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,CAAC;;AAG7F,IAAA,IAAI;AACF,QAAA,MAAM,uBAAuB,CAAC;YAC5B,UAAU;YACV,MAAM;YACN,OAAO;YACP,QAAQ;YACR,KAAK;YACL,KAAK;YACL,OAAO;AACP,YAAA,SAAS,EAAE,YAAY;AACxB,SAAA,CAAC;IACJ;IAAE,OAAO,GAAG,EAAE;QACZ,OAAO,CAAC,KAAK,GAAG,CAAA,2CAAA,EAA8C,MAAM,CAAC,GAAG,CAAC,CAAA,CAAE,CAAC;AAC5E,QAAA,YAAY,EAAE;IAChB;AACF;AAEA;AACA;AACA;AAEA;;AAEG;AACH,SAAS,eAAe,CAAC,OAAmB,EAAE,SAAiB,EAAA;IAC7D,OAAO;AACL,QAAA,KAAK,EAAE,CAAC,OAAe,EAAE,GAAG,IAAW,KAAI;AACzC,YAAA,OAAO,CAAC,GAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,EAAA,EAAK,OAAO,CAAA,CAAE,EAAE,GAAG,IAAI,CAAC;QACrD,CAAC;AACD,QAAA,IAAI,EAAE,CAAC,OAAe,EAAE,GAAG,IAAW,KAAI;AACxC,YAAA,OAAO,CAAC,GAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,EAAA,EAAK,OAAO,CAAA,CAAE,EAAE,GAAG,IAAI,CAAC;QACrD,CAAC;AACD,QAAA,IAAI,EAAE,CAAC,OAAe,EAAE,GAAG,IAAW,KAAI;AACxC,YAAA,OAAO,CAAC,GAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,QAAA,EAAW,OAAO,CAAA,CAAE,EAAE,GAAG,IAAI,CAAC;QAC3D,CAAC;AACD,QAAA,KAAK,EAAE,CAAC,OAAe,EAAE,GAAG,IAAW,KAAI;AACzC,YAAA,OAAO,CAAC,KAAK,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,EAAA,EAAK,OAAO,CAAA,CAAE,EAAE,GAAG,IAAI,CAAC;QACvD,CAAC;KACF;AACH;AAEA;AACA;AACA;AAEA;;;AAGG;AACI,eAAe,oBAAoB,CAAC,OAA4B,EAAA;AACrE,IAAA,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,OAAO;AAEpE,IAAA,OAAO,CAAC,GAAG,GAAG,CAAA,CAAA,EAAI,OAAO,CAAC,SAAS,CAAA,GAAA,EAAM,cAAc,CAAA,mCAAA,CAAqC,CAAC;IAC7F,OAAO,CAAC,KAAK,GAAG,CAAA,CAAA,EAAI,OAAO,CAAC,SAAS,CAAA,0DAAA,CAA4D,CAAC;;AAGlG,IAAA,wBAAwB,EAAE;IAE1B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAI;QACrC,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC;AAE1D,QAAA,MAAM,QAAQ,GAAG,IAAIK,qBAAQ,CAAC;YAC5B,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,KAAK,EAAE,OAAO,CAAC,YAAY;YAC3B,MAAM;AACN,YAAA,iBAAiB,EAAE,wBAAwB;AAC3C,YAAA,oBAAoB,EAAE,yBAAyB;AAC/C,YAAA,sBAAsB,EAAE,4BAA4B;AACpD,YAAA,KAAK,EAAE,oBAAoB;AAC3B,YAAA,YAAY,EAAE,cAAc;AAC7B,SAAA,CAAC;;QAGF,IAAI,SAAS,GAAG,KAAK;;AAGrB,QAAA,MAAM,OAAO,GAAG,YAAW;AACzB,YAAA,IAAI,SAAS;gBAAE;YACf,SAAS,GAAG,IAAI;AAChB,YAAA,uBAAuB,EAAE;AACzB,YAAA,MAAM,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC;AACzC,QAAA,CAAC;;;QAID,IAAI,WAAW,EAAE;AACf,YAAA,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE,YAAW;gBAC/C,OAAO,CAAC,GAAG,GAAG,CAAA,CAAA,EAAI,OAAO,CAAC,SAAS,CAAA,oBAAA,CAAsB,CAAC;gBAC1D,QAAQ,CAAC,UAAU,EAAE;gBACrB,MAAM,OAAO,EAAE;AACf,gBAAA,OAAO,EAAE;AACX,YAAA,CAAC,CAAC;QACJ;;AAGA,QAAA,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,MAAK;YAC5B,OAAO,CAAC,GAAG,GAAG,CAAA,CAAA,EAAI,OAAO,CAAC,SAAS,CAAA,qBAAA,CAAuB,CAAC;AAC7D,QAAA,CAAC,CAAC;;AAGF,QAAA,QAAQ,CAAC,EAAE,CAAC,eAAe,EAAE,MAAK;YAChC,OAAO,CAAC,GAAG,GAAG,CAAA,CAAA,EAAI,OAAO,CAAC,SAAS,CAAA,2BAAA,CAA6B,CAAC;AACjE,YAAA,iBAAiB,CAAC,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC;AAChD,QAAA,CAAC,CAAC;;QAGF,QAAQ,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,MAAM,KAAI;AACrC,YAAA,OAAO,CAAC,GAAG,GAAG,CAAA,CAAA,EAAI,OAAO,CAAC,SAAS,CAAA,0BAAA,EAA6B,MAAM,CAAA,CAAE,CAAC;AAC3E,QAAA,CAAC,CAAC;;;;;;;;;;;;;;;;AAkBF,QAAA,QAAQ,CAAC,EAAE,CAAC,0BAA0B,EAAE,YAAW;YACjD,MAAM,QAAQ,GAAG,CAAA,uJAAA,CAAyJ;AAC1K,YAAA,OAAO,CAAC,KAAK,GAAG,CAAA,CAAA,EAAI,OAAO,CAAC,SAAS,CAAA,EAAA,EAAK,QAAQ,CAAA,CAAE,CAAC;YACrD,QAAQ,CAAC,UAAU,EAAE;YACrB,MAAM,OAAO,EAAE;AACf,YAAA,SAAS,GAAG;gBACV,SAAS,EAAE,OAAO,CAAC,SAAS;AAC5B,gBAAA,OAAO,EAAE,KAAK;AACd,gBAAA,SAAS,EAAE,QAAQ;AACnB,gBAAA,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;AACvB,aAAA,CAAC;;AAEJ,QAAA,CAAC,CAAC;;QAGF,QAAQ,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,OAAO,KAAI;AACtC,YAAA,OAAO,CAAC,GAAG,GAAG,CAAA,CAAA,EAAI,OAAO,CAAC,SAAS,CAAA,uBAAA,EAA0B,OAAO,CAAA,GAAA,CAAK,CAAC;AAC5E,QAAA,CAAC,CAAC;;QAGF,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,KAAI;AACnC,YAAA,OAAO,CAAC,KAAK,GAAG,IAAI,OAAO,CAAC,SAAS,CAAA,mBAAA,EAAsB,KAAK,CAAC,OAAO,CAAA,CAAE,CAAC;AAE3E,YAAA,IAAI,KAAK,YAAYC,+BAAkB,EAAE;;;;;;;;;;;;;;AAcvC,gBAAA,MAAM,QAAQ,GAAG,CAAA,iCAAA,EAAoC,4BAA4B,sDAAsD;AACvI,gBAAA,OAAO,CAAC,KAAK,GAAG,CAAA,CAAA,EAAI,OAAO,CAAC,SAAS,CAAA,EAAA,EAAK,QAAQ,CAAA,CAAE,CAAC;gBACrD,QAAQ,CAAC,UAAU,EAAE;gBACrB,MAAM,OAAO,EAAE;AACf,gBAAA,SAAS,GAAG;oBACV,SAAS,EAAE,OAAO,CAAC,SAAS;AAC5B,oBAAA,OAAO,EAAE,KAAK;AACd,oBAAA,SAAS,EAAE,QAAQ;AACnB,oBAAA,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;AACvB,iBAAA,CAAC;gBACF;YACF;AAEA,YAAA,IAAI,KAAK,YAAYC,sCAAyB,EAAE;;;;;;;;;;;;;;gBAc9C,QAAQ,CAAC,UAAU,EAAE;AACrB,gBAAA,OAAO,EAAE,CAAC,OAAO,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;gBACtC;YACF;AACF,QAAA,CAAC,CAAC;;QAGF,QAAQ,CAAC,EAAE,CAAC,wBAA+B,EAAE,OAAO,KAAc,KAAI;AACpE,YAAA,IAAI;;AAEF,gBAAA,MAAM,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,qBAAqB,CAAC;YACjF;YAAE,OAAO,GAAG,EAAE;;YAEd;AACF,QAAA,CAAC,CAAC;;QAGF,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAc,KAAI;AAC9C,YAAA,IAAI;AACF,gBAAA,MAAM,mBAAmB,CAAC;oBACxB,KAAK;oBACL,OAAO;oBACP,MAAM;oBACN,OAAO;oBACP,QAAQ;AACT,iBAAA,CAAC;YACJ;YAAE,OAAO,GAAG,EAAE;AACZ,gBAAA,OAAO,CAAC,KAAK,GAAG,IAAI,OAAO,CAAC,SAAS,CAAA,6BAAA,EAAgC,MAAM,CAAC,GAAG,CAAC,CAAA,CAAE,CAAC;YACrF;AACF,QAAA,CAAC,CAAC;;;QAIF,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAc,KAAI;AAC5C,YAAA,IAAI;AACF,gBAAA,MAAM,SAAS,GAAG,KAAK,CAAC,IAAmB;AAC3C,gBAAA,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,EAAE,SAAS;gBAC5C,OAAO,CAAC,GAAG,GACT,IAAI,OAAO,CAAC,SAAS,CAAA,qCAAA,EAAwC,SAAS,IAAI,EAAE,CAAA,QAAA,EAAW,SAAS,CAAC,KAAK,IAAI,EAAE,CAAA,CAAE,CAC/G;gBACD,OAAO,CAAC,KAAK,GACX,IAAI,OAAO,CAAC,SAAS,CAAA,yCAAA,EAA4C,SAAS,IAAI,EAAE,CAAA,QAAA,EAAW,SAAS,CAAC,KAAK,IAAI,EAAE,CAAA,CAAE,CACnH;AAED,gBAAA,IAAI,SAAS,KAAK,qBAAqB,EAAE;oBACvC;gBACF;AAEA,gBAAA,MAAM,iBAAiB,GAAG,SAAS,CAAC,KAAK,EAAE,mBAAmB;gBAC9D,OAAO,CAAC,GAAG,GACT,IAAI,OAAO,CAAC,SAAS,CAAA,0CAAA,EAA6C,iBAAiB,EAAE,SAAS,IAAI,EAAE,aAAa,iBAAiB,EAAE,OAAO,IAAI,EAAE,CAAA,CAAE,CACpJ;AAED,gBAAA,IAAI;AACF,oBAAA,MAAM,yBAAyB,CAAC;wBAC9B,KAAK;wBACL,SAAS,EAAE,OAAO,CAAC,SAAS;wBAC5B,OAAO;wBACP,QAAQ;AACT,qBAAA,CAAC;gBACJ;gBAAE,OAAO,SAAS,EAAE;AAClB,oBAAA,OAAO,CAAC,KAAK,GACX,IAAI,OAAO,CAAC,SAAS,CAAA,yDAAA,EAA4D,MAAM,CAAC,SAAS,CAAC,CAAA,CAAE,CACrG;gBACH;AAEA,gBAAA,MAAM,mBAAmB,CAAC;oBACxB,KAAK;oBACL,OAAO;oBACP,MAAM;oBACN,OAAO;oBACP,QAAQ;AACT,iBAAA,CAAC;YACJ;YAAE,OAAO,GAAG,EAAE;AACZ,gBAAA,OAAO,CAAC,KAAK,GAAG,IAAI,OAAO,CAAC,SAAS,CAAA,yCAAA,EAA4C,MAAM,CAAC,GAAG,CAAC,CAAA,CAAE,CAAC;YACjG;AACF,QAAA,CAAC,CAAC;QAEF,OAAO,CAAC,GAAG,GAAG,CAAA,CAAA,EAAI,OAAO,CAAC,SAAS,CAAA,gEAAA,CAAkE,CAAC;QACtG,OAAO,CAAC,KAAK,GAAG,CAAA,CAAA,EAAI,OAAO,CAAC,SAAS,CAAA,+BAAA,CAAiC,CAAC;;AAGvE,QAAA,gBAAgB,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,GAAG,IAAI,KAAK,OAAO,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC;AACpE,aAAA,IAAI,CAAC,CAAC,KAAK,KAAI;AACd,YAAA,OAAO,CAAC,GAAG,GAAG,CAAA,CAAA,EAAI,OAAO,CAAC,SAAS,CAAA,YAAA,EAAe,KAAK,CAAA,wBAAA,CAA0B,CAAC;AACpF,QAAA,CAAC;AACA,aAAA,KAAK,CAAC,CAAC,GAAG,KAAI;AACb,YAAA,OAAO,CAAC,KAAK,GAAG,IAAI,OAAO,CAAC,SAAS,CAAA,gCAAA,EAAmC,MAAM,CAAC,GAAG,CAAC,CAAA,CAAE,CAAC;AACxF,QAAA,CAAC;aACA,OAAO,CAAC,MAAK;;YAEZ,QAAQ,CAAC,OAAO,EAAE;AACpB,QAAA,CAAC,CAAC;AACN,IAAA,CAAC,CAAC;AACJ;;AC5pCA;;AAEG;AAyCI,MAAM,YAAY,GAAG,iCAAiC;AAc7D;;AAEG;AACG,SAAU,mBAAmB,CAAC,GAAmB,EAAA;AACrD,IAAA,MAAM,WAAW,IAAI,GAAG,CAAC,QAAQ,GAAG,UAAU,CAAC,IAAI,EAAE,CAAgB;IAErE,OAAO;AACL,QAAA,SAAS,EAAE,kBAAkB;AAC7B,QAAA,IAAI,EAAE,WAAW,CAAC,IAAI,IAAI,MAAM;AAChC,QAAA,OAAO,EAAE,WAAW,CAAC,OAAO,IAAI,KAAK;AACrC,QAAA,YAAY,EAAE,WAAW,CAAC,YAAY,IAAI,YAAY;AACtD,QAAA,KAAK,EAAE,WAAW,CAAC,KAAK,IAAI,EAAE;AAC9B,QAAA,MAAM,EAAE,WAAW,CAAC,MAAM,IAAI,EAAE;AAChC,QAAA,mBAAmB,EAAE,WAAW,CAAC,mBAAmB,IAAI,IAAI;AAC5D,QAAA,MAAM,EAAE,WAAW;KACpB;AACH;AAEA;;AAEG;AACG,SAAU,eAAe,CAC7B,GAAmB,EACnB,OAA6B,EAAA;AAE7B,IAAA,MAAM,QAAQ,IAAI,GAAG,CAAC,QAAQ,GAAG,UAAU,CAAC,IAAI,EAAE,CAAgB;AAClE,IAAA,MAAM,MAAM,GAAgB;QAC1B,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,QAAQ,EAAE,OAAO,IAAI,IAAI;QACrD,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,QAAQ,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,QAAQ,EAAE,MAAM,IAAI,EAAE;AAChD,QAAA,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,QAAQ,EAAE,SAAS;AACnD,QAAA,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,QAAQ,EAAE,QAAQ;;AAEhD,QAAA,IAAI,OAAO,CAAC,YAAY,IAAI,QAAQ,EAAE;cAClC,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,QAAQ,EAAE,YAAY;cAC9D,EAAE,CAAC;AACP,QAAA,IAAI,OAAO,CAAC,IAAI,IAAI,QAAQ,EAAE;cAC1B,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,QAAQ,EAAE,IAAI;cACtC,EAAE,CAAC;QACP,IAAI,OAAO,CAAC,mBAAmB,KAAK,SAAS,IAAI,QAAQ,EAAE,mBAAmB,KAAK;cAC/E,EAAE,mBAAmB,EAAE,OAAO,CAAC,mBAAmB,IAAI,QAAQ,EAAE,mBAAmB;cACnF,EAAE,CAAC;KACR;IAEH,OAAO;AACH,QAAA,GAAG,GAAG;AACN,QAAA,QAAQ,EAAE;YACR,GAAG,GAAG,CAAC,QAAQ;YACf,CAAC,UAAU,GAAG,MAAM;AACrB,SAAA;KACF;AACH;;AC5GA;;;;AAIG;AAUH;AACA;AACA;AAEO,MAAM,iBAAiB,GAAwB;IACpD,kBAAkB,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,KAAI;QACrC,MAAM,KAAK,GAAyB,EAAE;AAEtC,QAAA,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE;AAC7B,YAAA,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE;QAC1C;AACA,QAAA,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE;AAClC,YAAA,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE;QAChD;;AAGA,QAAA,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC;QACxC,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;AACrC,YAAA,KAAK,CAAC,OAAO,GAAG,IAAI;QACtB;AAEA,QAAA,OAAO,eAAe,CAAC,GAAG,EAAE,KAAK,CAAC;IACpC,CAAC;CACF;AAED;AACA;AACA;AAEA;;AAEG;AACH,SAAS,gBAAgB,CACvB,GAAmB,EACnB,QAAuD,EAAA;AAEvD,IAAA,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC;IACxC,MAAM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE;AACxD,IAAA,MAAM,SAAS,GACb,QAAQ,KAAK;AACX,UAAE,oBAAoB,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC;AAC9D,UAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC;IAE7C,OAAO,eAAe,CAAC,GAAG,EAAE;QAC1B,QAAQ;QACR,SAAS;AACV,KAAA,CAAC;AACJ;AAEA,MAAM,QAAQ,GAAyB;AACrC,IAAA,KAAK,EAAE,MAAM;AACb,IAAA,OAAO,EAAE,UAAU;IACnB,SAAS,EAAE,CAAA,SAAA,EAAY,UAAU,CAAA,SAAA,CAAW;IAC5C,YAAY,EAAE,CAAA,SAAA,EAAY,UAAU,CAAA,UAAA,CAAY;AAChD,IAAA,UAAU,EAAE,CAAC,GAAG,KAAI;AAClB,QAAA,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC;AACxC,QAAA,OAAO,OAAO,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM;IAC1C,CAAC;AACD,IAAA,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAI;AACzB,QAAA,OAAO,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC;IACtC,CAAC;IACD,eAAe,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAI;AAC3C,QAAA,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC;QACxC,MAAM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE;AAExD,QAAA,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC;AAChC,YAAA,OAAO,EAAE,0BAA0B;AACnC,YAAA,WAAW,EAAE,mBAAmB;AAChC,YAAA,YAAY,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS;AAC9E,SAAA,CAAC;AAEF,QAAA,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE;aACjC,KAAK,CAAC,UAAU;aAChB,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE;aACnB,MAAM,CAAC,OAAO,CAAC;QAElB,OAAO,eAAe,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC;IAC5C,CAAC;CACF;AAED;AACA;AACA;AAEO,MAAM,gBAAgB,GAAuB;AAClD,IAAA,OAAO,EAAE,UAAU;;AAGnB,IAAA,MAAM,EAAE;AACN,QAAA,eAAe,EAAE,OAAO;AACxB,QAAA,iBAAiB,EAAE,oBAAoB;AACvC,QAAA,cAAc,EAAE,KAAK;AACrB,QAAA,gBAAgB,EAAE,MAAM;AACxB,QAAA,iBAAiB,EAAE,CAAC,EAAE,GAAG,EAAE,KAAI;AAC7B,YAAA,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC;AACxC,YAAA,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;QACjE,CAAC;QACD,kBAAkB,EAAE,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,KAAI;AAC1C,YAAA,OAAO,CAAC,CAAA,MAAA,EAAS,UAAU,GAAG,KAAK,GAAG,oBAAoB,CAAA,CAAE,CAAC;QAC/D,CAAC;AACF,KAAA;;AAGD,IAAA,SAAS,EAAE;AACT,QAAA,KAAK,EAAE,QAAQ;AACf,QAAA,KAAK,EAAE;YACL,kBAAkB;YAClB,uBAAuB;YACvB,sBAAsB;AACvB,SAAA;AACD,QAAA,UAAU,EAAE,CAAC,EAAE,GAAG,EAAE,KAAI;AACtB,YAAA,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC;AACxC,YAAA,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE;QAC1D,CAAC;AACF,KAAA;;AAGD,IAAA,WAAW,EAAE;AACX,QAAA;AACE,YAAA,QAAQ,EAAE,OAAO;AACjB,YAAA,YAAY,EAAE,MAAM;AACpB,YAAA,eAAe,EAAE,QAAQ;AACzB,YAAA,SAAS,EAAE,kBAAkB;AAC7B,YAAA,UAAU,EAAE,mBAAmB;AAC/B,YAAA,WAAW,EAAE,gBAAgB;AAC7B,YAAA,OAAO,EAAE,CAAC,EAAE,GAAG,EAAE,KAAI;AACnB,gBAAA,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC;gBACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;gBAC/C,OAAO;AACL,oBAAA,iBAAiB,EAAE,QAAQ;AAC3B,oBAAA,kBAAkB,EAAE,QAAQ;AAC5B,oBAAA,aAAa,EAAE,OAAO,CAAC,KAAK,IAAI,SAAS;iBAC1C;YACH,CAAC;YACD,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,KAAI;gBACnC,OAAO,eAAe,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;YACvD,CAAC;AACF,SAAA;AACD,QAAA;AACE,YAAA,QAAQ,EAAE,YAAY;AACtB,YAAA,YAAY,EAAE,MAAM;AACpB,YAAA,eAAe,EAAE,QAAQ;AACzB,YAAA,SAAS,EAAE,kBAAkB;AAC7B,YAAA,UAAU,EAAE,mBAAmB;AAC/B,YAAA,WAAW,EAAE,gBAAgB;AAC7B,YAAA,OAAO,EAAE,CAAC,EAAE,GAAG,EAAE,KAAI;AACnB,gBAAA,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC;gBACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;gBAChD,OAAO;AACL,oBAAA,iBAAiB,EAAE,QAAQ;AAC3B,oBAAA,kBAAkB,EAAE,QAAQ;AAC5B,oBAAA,aAAa,EAAE,OAAO,CAAC,MAAM,IAAI,SAAS;iBAC3C;YACH,CAAC;YACD,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,KAAI;gBACnC,OAAO,eAAe,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;YACxD,CAAC;AACF,SAAA;AACF,KAAA;;AAGD,IAAA,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,KAAI;;AAE1B,QAAA,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC;AACxC,QAAA,IAAI,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;AACvE,YAAA,OAAO,EAAE,GAAG,EAAE,eAAe,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE;QACzD;AACA,QAAA,OAAO,SAAS;IAClB,CAAC;;AAGD,IAAA,cAAc,EAAE;AACd,QAAA,KAAK,EAAE,UAAU;AACjB,QAAA,KAAK,EAAE;YACL,eAAe;YACf,2BAA2B;AAC5B,SAAA;AACD,QAAA,UAAU,EAAE,CAAC,EAAE,GAAG,EAAE,KAAI;AACtB,YAAA,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC;AACxC,YAAA,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;QACjE,CAAC;AACF,KAAA;;IAGD,QAAQ;;AAGR,IAAA,OAAO,EAAE,CAAC,GAAG,KAAI;QACf,OAAO,eAAe,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACjD,CAAC;CACF;;AC5LD;;;AAGG;AACH,eAAe,gBAAgB,CAAC,EACE,EAAE,EACF,OAAO,EACP,SAAS,GAK1C,EAAA;AACC,IAAA,MAAM,iBAAiB,GAAG,SAAS,IAAI,kBAAkB;;IAGzD,MAAM,aAAa,GAAG,IAAI,MAAM,CAAC,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA,CAAG,EAAE,GAAG,CAAC;IACxD,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC;;AAG5C,IAAA,MAAM,QAAQ,GAAG,iBAAiB,CAAC,iBAAiB,CAAC;IACrD,IAAI,CAAC,QAAQ,EAAE;AACb,QAAA,MAAM,IAAI,KAAK,CAAC,sCAAsC,iBAAiB,CAAA,CAAE,CAAC;IAC5E;;IAGA,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,MAAM,EAAE;AAChD,QAAA,OAAO,EAAE,UAAU;QACnB,QAAQ,EAAE,EAAE,OAAO,EAAE;AACtB,KAAA,CAAC;AAEF,IAAA,MAAM,SAAS,GAAG,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,CAAA,MAAA,EAAS,IAAI,CAAC,GAAG,EAAE,EAAE;IAElE,OAAO;AACL,QAAA,OAAO,EAAE,UAAU;QACnB,SAAS;QACT,MAAM;KACP;AACH;AAEA;AACA,MAAM,IAAI,GAAG;AACX,IAAA,EAAE,EAAE,UAAU;AACd,IAAA,KAAK,EAAE,MAAM;AACb,IAAA,cAAc,EAAE,cAAc;AAC9B,IAAA,WAAW,EAAE,WAAW;IACxB,QAAQ,EAAE,CAAA,UAAA,EAAa,UAAU,CAAA,CAAE;AACnC,IAAA,SAAS,EAAE,UAAU;AACrB,IAAA,KAAK,EAAE,eAAe;AACtB,IAAA,WAAW,EAAE,cAAc;CAC5B;AACM,MAAM,WAAW,GAAwC;AAC9D,IAAA,EAAE,EAAE,UAAU;AACd,IAAA,IAAI,EAAE;AACJ,QAAA,GAAG,IAAI;AACP,QAAA,mBAAmB,EAAE,IAAI;AAC1B,KAAA;AACD,IAAA,OAAO,EAAE;AACP,QAAA,OAAO,EAAE,aAAa;QACtB,mBAAmB,EAAE,CAAC,KAAK,KAAK,KAAK,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,CAAA,EAAA,EAAK,UAAU,CAAA,OAAA,CAAS,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE;QACnG,cAAc,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,KAAI;;;;;;;QAOtC,CAAC;AACF,KAAA;AACD,IAAA,WAAW,EAAE,gBAAgB;AAC7B,IAAA,KAAK,EAAE,iBAAiB;AACxB,IAAA,YAAY,EAAE;AACZ,QAAA,SAAS,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;AAC9B,QAAA,SAAS,EAAE,KAAK;AAChB,QAAA,OAAO,EAAE,KAAK;AACd,QAAA,KAAK,EAAE,IAAI;AACX,QAAA,cAAc,EAAE,KAAK;AACrB,QAAA,cAAc,EAAE,IAAI;AACrB,KAAA;IACD,MAAM,EAAE,EAAC,cAAc,EAAE,CAAC,CAAA,SAAA,EAAY,UAAU,CAAA,CAAE,CAAC,EAAC;AACpD,IAAA,MAAM,EAAE;;AAEN,QAAA,cAAc,EAAE,MAAM,CAAC,kBAAkB,CAAC;;QAG1C,cAAc,EAAE,CAAC,GAAG,KAAK,mBAAmB,CAAC,GAAG,CAAC;;AAGjD,QAAA,gBAAgB,EAAE,MAAM,kBAAkB;;QAG1C,iBAAiB,EAAE,CAAC,EAAC,GAAG,EAAE,OAAO,EAAC,KAAI;AACpC,YAAA,MAAM,WAAW,IAAI,GAAG,CAAC,QAAQ,GAAG,UAAU,CAAC,IAAI,EAAE,CAAgB;YACrE,OAAO;AACL,gBAAA,GAAG,GAAG;AACN,gBAAA,QAAQ,EAAE;oBACR,GAAG,GAAG,CAAC,QAAQ;oBACf,CAAC,UAAU,GAAG;AACZ,wBAAA,GAAG,WAAW;wBACd,OAAO;AACR,qBAAA;AACF,iBAAA;aACF;QACH,CAAC;;AAGD,QAAA,aAAa,EAAE,CAAC,EAAC,GAAG,EAAC,KAAI;AACvB,YAAA,MAAM,WAAW,IAAI,GAAG,CAAC,QAAQ,GAAG,UAAU,CAAC,IAAI,EAAE,CAAgB;YACrE,MAAM,EAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAC,GAAG,WAAW;YAC5C,OAAO;AACL,gBAAA,GAAG,GAAG;AACN,gBAAA,QAAQ,EAAE;oBACR,GAAG,GAAG,CAAC,QAAQ;oBACf,CAAC,UAAU,GAAG,IAAI;AACnB,iBAAA;aACF;QACH,CAAC;;QAGD,YAAY,EAAE,CAAC,OAAO,KACpB,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;;AAG1D,QAAA,eAAe,EAAE,CAAC,OAAO,MAAM;YAC7B,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,OAAO,EAAE,OAAO,CAAC,OAAO;AACxB,YAAA,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;YACpE,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,YAAY,EAAE,OAAO,CAAC,YAAY;SACnC,CAAC;;AAGF,QAAA,gBAAgB,EAAE,CAAC,EAAC,GAAG,EAAC,KAAI;AAC1B,YAAA,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC;YACxC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,CAAC;;QAGD,eAAe,EAAE,CAAC,EAAC,SAAS,EAAC,KAC3B;AACG,aAAA,GAAG,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE;aACnC,MAAM,CAAC,OAAO,CAAC;AACrB,KAAA;AACD,IAAA,QAAQ,EAAE;AACR,QAAA,eAAe,EAAE,CAAC,EAAC,OAAO,EAAC,KAAI;AAC7B,YAAA,MAAM,QAAQ,GAAG,CAAA,SAAA,EAAY,UAAU,GAAG;YAC1C,OAAO;AACL,gBAAA,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM;AACzC,gBAAA,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE;gBACzC,UAAU,EAAE,CAAA,EAAG,QAAQ,CAAA,QAAA,CAAU;AACjC,gBAAA,aAAa,EAAE,QAAQ;AACvB,gBAAA,WAAW,EAAE,wBAAwB,CAAC,UAAU,CAAC;gBACjD,cAAc,EAAE,CAAC,GAAG,KAAK,GAAG,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA,CAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE;aACpF;QACH,CAAC;QACD,eAAe,EAAE,CAAC,EAAC,OAAO,EAAE,GAAG,EAAC,KAAI;YAClC,MAAM,QAAQ,GAAa,EAAE;;YAG7B,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM;AAClD,YAAA,IAAI,QAAQ,KAAK,MAAM,EAAE;AACvB,gBAAA,MAAM,WAAW,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,EAAE,IAAI,CACvD,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,GAAG,CACxC;gBACD,IAAI,CAAC,WAAW,EAAE;AAChB,oBAAA,QAAQ,CAAC,IAAI,CACX,wFAAwF,UAAU,CAAA,wCAAA,CAA0C,CAC7I;gBACH;YACF;;YAGA,MAAM,kBAAkB,GAAG,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW;YAC9D,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,IAAI,kBAAkB,IAAI,MAAM;;;;;;AAM9E,YAAA,IAAI,WAAW,KAAK,MAAM,EAAE;gBAC1B,QAAQ,CAAC,IAAI,CACX,CAAA,qDAAA,EAAwD,UAAU,CAAA,oCAAA,EAAuC,UAAU,CAAA,sBAAA,CAAwB,CAC5I;YACH;AAEA,YAAA,OAAO,QAAQ;QACjB,CAAC;AACF,KAAA;AACD,IAAA,SAAS,EAAE;AACT,QAAA,eAAe,EAAE,CAAC,MAAM,KAAI;AAC1B,YAAA,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE;AAC7B,YAAA,IAAI,CAAC,OAAO;AAAE,gBAAA,OAAO,SAAS;AAC9B,YAAA,OAAO,OAAO;QAChB,CAAC;AACD,QAAA,cAAc,EAAE;AACd,YAAA,WAAW,EAAE,CAAC,EAAE,KAAI;AAClB,gBAAA,MAAM,OAAO,GAAG,EAAE,EAAE,IAAI,EAAE;AAC1B,gBAAA,OAAO,OAAO,CAAC,OAAO,CAAC;YACzB,CAAC;AACD,YAAA,IAAI,EAAE,kBAAkB;AACzB,SAAA;AACF,KAAA;AACD,IAAA,SAAS,EAAE;AACT,QAAA,IAAI,EAAE,YAAY,IAAI;AACtB,QAAA,SAAS,EAAE,YAAY,EAAE;AACzB,QAAA,UAAU,EAAE,YAAY,EAAE;AAC3B,KAAA;AACD,IAAA,QAAQ,EAAE;AACR,QAAA,YAAY,EAAE,SAAS;QACvB,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,eAAe,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC;AACvF,QAAA,cAAc,EAAE,gBAAgB;QAChC,QAAQ,EAAE,OAAO,EAAC,EAAE,EAAE,IAAI,EAAE,SAAS,EAAC,KAAI;AACxC,YAAA,OAAO,gBAAgB,CAAC,EAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,IAAI,SAAS,EAAC,CAAC;QACjF,CAAC;AACD,QAAA,SAAS,EAAE,OAAO,EAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,SAAS,EAAC,KAAI;AACpE,YAAA,MAAM,iBAAiB,GAAG,SAAS,IAAI,kBAAkB;YACzD,MAAM,aAAa,GAAG,IAAI,MAAM,CAAC,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA,CAAG,EAAE,GAAG,CAAC;YACxD,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC;;AAG5C,YAAA,MAAM,QAAQ,GAAG,iBAAiB,CAAC,iBAAiB,CAAC;YACrD,IAAI,CAAC,QAAQ,EAAE;AACb,gBAAA,MAAM,IAAI,KAAK,CAAC,sCAAsC,iBAAiB,CAAA,CAAE,CAAC;YAC5E;;YAGA,IAAI,CAAC,QAAQ,EAAE;AACb,gBAAA,OAAO,gBAAgB,CAAC,EAAC,EAAE,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,EAAE,SAAS,EAAE,iBAAiB,EAAC,CAAC;YAClF;AAEA,YAAA,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC;gBACtC,QAAQ;gBACR,QAAQ;gBACR,MAAM;gBACN,eAAe;AAChB,aAAA,CAAC;AAEF,YAAA,IAAI,MAAM,CAAC,QAAQ,EAAE;AACnB,gBAAA,OAAO,gBAAgB,CAAC,EAAC,EAAE,EAAE,OAAO,EAAE,CAAA,GAAA,EAAM,MAAM,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,iBAAiB,EAAC,CAAC;YACnG;AAEA,YAAA,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE;;gBAEd,MAAM,eAAe,GAAG;AACtB,sBAAE,CAAA,EAAG,IAAI,CAAA,KAAA,EAAQ,QAAQ,CAAA;AACzB,sBAAE,CAAA,GAAA,EAAM,QAAQ,CAAA,CAAE;AACpB,gBAAA,OAAO,gBAAgB,CAAC,EAAC,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,iBAAiB,EAAC,CAAC;YACvF;;YAGA,IAAI,IAAI,EAAE;AACR,gBAAA,MAAM,gBAAgB,CAAC,EAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,iBAAiB,EAAC,CAAC;YAC3E;;AAGA,YAAA,IAAI,MAAM,CAAC,aAAa,EAAE;AACxB,gBAAA,MAAM,gBAAgB,CAAC,EAAC,EAAE,EAAE,OAAO,EAAE,CAAA,GAAA,EAAM,MAAM,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,iBAAiB,EAAC,CAAC;YACnG;YAEA,OAAO;AACL,gBAAA,OAAO,EAAE,UAAU;gBACnB,SAAS,EAAE,MAAM,CAAC,SAAU;gBAC5B,MAAM;aACP;QACH,CAAC;AACF,KAAA;AACD,IAAA,MAAM,EAAE;AACN,QAAA,cAAc,EAAE;AACd,YAAA,SAAS,EAAE,kBAAkB;AAC7B,YAAA,OAAO,EAAE,KAAK;AACd,YAAA,WAAW,EAAE,IAAI;AACjB,YAAA,UAAU,EAAE,IAAI;AAChB,YAAA,SAAS,EAAE,IAAI;AAChB,SAAA;AACD,QAAA,mBAAmB,EAAE,CAAC,QAAQ,KAC5B,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,KAAI;YACzB,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,IAAI,kBAAkB,CAAC;AAC/D,YAAA,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,KAAK,KAAK;AACvC,YAAA,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,KAAK,IAAI;YAC5C,IAAI,CAAC,OAAO,EAAE;AACZ,gBAAA,OAAO,EAAE;YACX;YACA,MAAM,MAAM,GAAyB,EAAE;YACvC,IAAI,CAAC,UAAU,EAAE;gBACf,MAAM,CAAC,IAAI,CAAC;AACV,oBAAA,OAAO,EAAE,UAAU;oBACnB,SAAS;AACT,oBAAA,IAAI,EAAE,QAAQ;AACd,oBAAA,OAAO,EAAE,yBAAyB;AAClC,oBAAA,GAAG,EAAE,kEAAkE;AACxE,iBAAA,CAAC;YACJ;AACA,YAAA,OAAO,MAAM;AACf,QAAA,CAAC,CAAC;QACJ,mBAAmB,EAAE,CAAC,EAAC,QAAQ,EAAC,MAAM;AACpC,YAAA,UAAU,EAAE,QAAQ,CAAC,UAAU,IAAI,KAAK;AACxC,YAAA,OAAO,EAAE,QAAQ,CAAC,OAAO,IAAI,KAAK;AAClC,YAAA,WAAW,EAAE,QAAQ,CAAC,WAAW,IAAI,IAAI;AACzC,YAAA,UAAU,EAAE,QAAQ,CAAC,UAAU,IAAI,IAAI;AACvC,YAAA,SAAS,EAAE,QAAQ,CAAC,SAAS,IAAI,IAAI;SACtC,CAAC;QACF,YAAY,EAAE,YAAW;YACvB,OAAO,EAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAC;QAChC,CAAC;QACD,oBAAoB,EAAE,CAAC,EAAC,OAAO,EAAE,OAAO,EAAC,KAAI;YAC3C,MAAM,UAAU,GAAG,OAAO,CACxB,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE;AACrB,gBAAA,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,CACvB;YACD,OAAO;gBACL,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,UAAU;AACV,gBAAA,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,KAAK;AAClC,gBAAA,WAAW,EAAE,OAAO,EAAE,WAAW,IAAI,IAAI;AACzC,gBAAA,UAAU,EAAE,OAAO,EAAE,UAAU,IAAI,IAAI;AACvC,gBAAA,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,IAAI;aACtC;QACH,CAAC;AACF,KAAA;AACD,IAAA,OAAO,EAAE;AACP,QAAA,YAAY,EAAE,OAAO,GAAG,KAAI;AAC1B,YAAA,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO;;AAG3B,YAAA,OAAO,oBAAoB,CAAC;gBAC1B,OAAO;gBACP,MAAM,EAAE,GAAG,CAAC,GAAG;gBACf,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,SAAS,EAAE,GAAG,CAAC,SAAS;AACzB,aAAA,CAAC;QACJ,CAAC;AACD,QAAA,aAAa,EAAE,OAAO,EAAC,GAAG,EAAC,KAAI;AAC7B,YAAA,MAAM,OAAO,GAAG,EAAC,GAAG,GAAG,EAAmB;AAC1C,YAAA,MAAM,WAAW,IAAI,GAAG,CAAC,QAAQ,GAAG,UAAU,CAAC,IAAI,EAAE,CAAgB;AACrE,YAAA,MAAM,SAAS,GAAG,EAAC,GAAG,WAAW,EAAC;YAClC,IAAI,OAAO,GAAG,KAAK;YACnB,IAAI,OAAO,GAAG,KAAK;YAEnB,IAAI,SAAS,CAAC,KAAK,IAAI,SAAS,CAAC,MAAM,EAAE;gBACvC,OAAO,SAAS,CAAC,KAAK;gBACtB,OAAO,SAAS,CAAC,MAAM;gBACvB,OAAO,GAAG,IAAI;gBACd,OAAO,GAAG,IAAI;YAChB;YAEA,IAAI,OAAO,EAAE;gBACX,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;AACrC,oBAAA,OAAO,CAAC,QAAQ,GAAG,EAAC,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,UAAU,GAAG,SAAS,EAAC;gBACnE;qBAAO;oBACL,MAAM,YAAY,GAAG,EAAC,GAAG,OAAO,CAAC,QAAQ,EAAC;AAC1C,oBAAA,OAAQ,YAAwC,CAAC,UAAU,CAAC;oBAC5D,IAAI,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;AACxC,wBAAA,OAAO,CAAC,QAAQ,GAAG,YAAY;oBACjC;yBAAO;wBACL,OAAO,OAAO,CAAC,QAAQ;oBACzB;gBACF;gBACA,MAAM,eAAe,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC;YACzD;AAEA,YAAA,MAAM,QAAQ,GAAG,mBAAmB,CAAC,OAAO,GAAG,OAAO,GAAG,GAAG,CAAC;YAC7D,MAAM,SAAS,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,MAAM;YAErD,OAAO,EAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAC;QAC9C,CAAC;AACF,KAAA;CACF;;AClYD;;;;;;;;;;AAUG;AA+CH;AACA;AACA;AAEA;AACA,MAAM,uBAAuB,GAAG,KAAM;AAEtC;AACO,MAAM,yBAAyB,GAAG,MAAO;AAEhD;AACA,MAAM,OAAO,GAAG,OAAO;AAEvB;;;;;AAKG;AACG,MAAO,WAAY,SAAQ,KAAK,CAAA;AACpC,IAAA,WAAA,CACkB,IAAY,EAC5B,OAAe,EACC,IAAc,EAAA;QAE9B,KAAK,CAAC,OAAO,CAAC;QAJE,IAAA,CAAA,IAAI,GAAJ,IAAI;QAEJ,IAAA,CAAA,IAAI,GAAJ,IAAI;AAGpB,QAAA,IAAI,CAAC,IAAI,GAAG,aAAa;IAC3B;AACD;AAED;;;;;AAKG;AACG,MAAO,YAAa,SAAQ,KAAK,CAAA;IACrC,WAAA,CACkB,UAAkB,EAClC,OAAe,EAAA;QAEf,KAAK,CAAC,OAAO,CAAC;QAHE,IAAA,CAAA,UAAU,GAAV,UAAU;AAI1B,QAAA,IAAI,CAAC,IAAI,GAAG,cAAc;IAC5B;AACD;AAED;;;;;;;;;;AAUG;AACH,MAAM,uBAAuB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAEjE;AACA,MAAM,cAAc,GAAG,IAAI,GAAG,EAAmC;AAEjE;AACA,MAAM,eAAe,GAAG,IAAI,GAAG,EAAsB;AAErD;AACA,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAAU;AAE7C;AACA,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAA+B;AAEnE;AACA;AACA;AAEA;;;;;AAKG;AACH,eAAe,cAAc,CAAC,QAAgB,EAAA;AAC5C,IAAA,MAAM,QAAQ,GAAG,iBAAiB,CAAC,kBAAkB,CAAC;IACtD,IAAI,CAAC,QAAQ,EAAE;AACb,QAAA,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC;IAC7C;AAEA,IAAA,MAAM,KAAK,GAAGP,0BAAa,CAAC,YAAY,CAAC;AAEzC,IAAA,MAAM,QAAQ,GAAG,MAAM,WAAW,CAChC,QAAQ,CAAC,KAAK,CACZ,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAC9B,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,cAAc,EAAG,EACvD,kBAAkB,CACnB,EACD,2BAA2B,EAC3B,CAAA,sBAAA,EAAyB,QAAQ,qBAAqB,2BAA2B,CAAA,EAAA,CAAI,CACtF;AAED,IAAA,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS,IAAI,QAAQ,CAAC,OAAO,KAAK,CAAC,EAAE;AAC5D,QAAA,MAAM,MAAM,GAAG,CAAA,oBAAA,EAAuB,QAAQ,CAAC,OAAO,CAAA,SAAA,EAAY,QAAQ,CAAC,MAAM,IAAI,SAAS,EAAE;QAChG,OAAO,CAAC,KAAK,CAAC,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,MAAM,CAAA,CAAE,CAAC;AACrC,QAAA,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC;IACzB;AAEA,IAAA,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAoC;AAC1D,IAAA,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE;AACd,QAAA,MAAM,IAAI,KAAK,CACb,gCAAgC,QAAQ,CAAA,EAAA,CAAI,CAC7C;IACH;IAEA,OAAO,CAAC,GAAG,CAAC,CAAA,EAAG,OAAO,CAAA,mBAAA,EAAsB,QAAQ,CAAA,EAAA,CAAI,CAAC;AACzD,IAAA,OAAO,IAA+B;AACxC;AAEA;;;;;;;AAOG;AACH,eAAe,SAAS,CAAC,QAAgB,EAAA;;IAEvC,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC3C,IAAA,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC,GAAa;;AAGvC,IAAA,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC;;AAG3C,IAAA,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC;AAElC,IAAA,OAAO,CAAC,GAAG,CAAC,CAAA,EAAG,OAAO,CAAA,WAAA,EAAc,QAAQ,CAAA,EAAA,EAAK,IAAI,CAAC,GAAG,CAAA,CAAE,CAAC;IAE5D,OAAO,IAAI,CAAC,GAAa;AAC3B;AAEA;AACA;AACA;AAEA;;;;;AAKG;AACH,eAAe,cAAc,CAC3B,GAAW,EACX,OAAmB,EACnB,IAAoB,EACpB,SAAA,GAAoB,uBAAuB,EAAA;AAE3C,IAAA,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE;AACxC,IAAA,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC;AAEjE,IAAA,MAAM,OAAO,GAA2B;AACtC,QAAA,cAAc,EAAE,kBAAkB;AAClC,QAAA,MAAM,EAAE,qCAAqC;KAC9C;;AAED,IAAA,IAAI,OAAO,CAAC,SAAS,EAAE;AACrB,QAAA,OAAO,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC,SAAS;IAC/C;AAEA,IAAA,IAAI,QAAkB;AACtB,IAAA,IAAI;AACF,QAAA,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;AAC1B,YAAA,MAAM,EAAE,MAAM;YACd,OAAO;AACP,YAAA,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YAC1B,MAAM,EAAE,UAAU,CAAC,MAAM;AAC1B,SAAA,CAAC;IACJ;IAAE,OAAO,GAAG,EAAE;QACZ,IAAI,GAAG,YAAY,YAAY,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE;AAC5D,YAAA,MAAM,IAAI,KAAK,CAAC,aAAa,SAAS,CAAA,GAAA,CAAK,CAAC;QAC9C;QACA,MAAM,IAAI,KAAK,CAAC,CAAA,YAAA,EAAe,GAAG,YAAY,KAAK,GAAG,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA,CAAE,CAAC;IACpF;YAAU;QACR,YAAY,CAAC,SAAS,CAAC;IACzB;;IAGA,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;AAE3D,IAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;AAChB,QAAA,MAAM,IAAI,YAAY,CACpB,QAAQ,CAAC,MAAM,EACf,CAAA,eAAA,EAAkB,QAAQ,CAAC,MAAM,CAAA,CAAA,EAAI,QAAQ,CAAC,UAAU,CAAA,CAAE,CAC3D;IACH;;IAGA,MAAM,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC5D,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,aAAa,KAAK,GAAG,EAAE;QACpD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE;IACzD;AAEA,IAAA,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE;;AAG9D,IAAA,IAAI,WAAW,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE;AAC7C,QAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC,QAAQ,CAAC,EAAE,YAAY,EAAE;IAChF;;AAGA,IAAA,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE;AAClC,IAAA,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE;QAChB,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE;IACzD;IAEA,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAoB;AAC/C,IAAA,IAAI,GAAG,CAAC,KAAK,EAAE;AACb,QAAA,MAAM,IAAI,WAAW,CACnB,GAAG,CAAC,KAAK,CAAC,IAAI,EACd,CAAA,UAAA,EAAa,GAAG,CAAC,KAAK,CAAC,IAAI,CAAA,GAAA,EAAM,GAAG,CAAC,KAAK,CAAC,OAAO,CAAA,CAAE,EACpD,GAAG,CAAC,KAAK,CAAC,IAAI,CACf;IACH;IACA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE;AAC1D;AAEA;AACA;AACA;AAEA;;;;;AAKG;AACH,eAAe,iBAAiB,CAAC,GAAW,EAAE,QAAgB,EAAA;AAC5D,IAAA,MAAM,OAAO,GAAe,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE;IAErF,OAAO,CAAC,GAAG,CAAC,CAAA,EAAG,OAAO,CAAA,6BAAA,EAAgC,QAAQ,CAAA,EAAA,CAAI,CAAC;;AAGnE,IAAA,MAAM,QAAQ,GAAmB;AAC/B,QAAA,OAAO,EAAE,KAAK;AACd,QAAA,EAAE,EAAEA,0BAAa,CAAC,UAAU,CAAC;AAC7B,QAAA,MAAM,EAAE,YAAY;AACpB,QAAA,MAAM,EAAE;AACN,YAAA,eAAe,EAAE,YAAY;AAC7B,YAAA,YAAY,EAAE,EAAE;YAChB,UAAU,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE;AACpD,SAAA;KACF;AAED,IAAA,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC;;IAGpF,IAAI,aAAa,EAAE;AACjB,QAAA,OAAO,CAAC,SAAS,GAAG,aAAa;IACnC;;;AAIA,IAAA,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;AACtB,QAAA,OAAO,CAAC,SAAS,GAAG,IAAI;AACxB,QAAA,OAAO,CAAC,WAAW,GAAG,IAAI;AAC1B,QAAA,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC;AACjC,QAAA,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,CAAA,EAAG,OAAO,CAAA,0BAAA,EAA6B,QAAQ,CAAA,EAAA,CAAI,CAAC;AAChE,QAAA,OAAO,OAAO;IAChB;;AAGA,IAAA,MAAM,UAAU,GAAmB;AACjC,QAAA,OAAO,EAAE,KAAK;AACd,QAAA,MAAM,EAAE,2BAA2B;KACpC;;AAED,IAAA,MAAM,EAAE,YAAY,EAAE,eAAe,EAAE,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,CAAC;;IAGxF,IAAI,eAAe,EAAE;AACnB,QAAA,OAAO,CAAC,SAAS,GAAG,eAAe;IACrC;AAEA,IAAA,OAAO,CAAC,WAAW,GAAG,IAAI;AAC1B,IAAA,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC;AACtC,IAAA,OAAO,CAAC,GAAG,CAAC,CAAA,EAAG,OAAO,CAAA,6BAAA,EAAgC,QAAQ,CAAA,cAAA,EAAiB,OAAO,CAAC,SAAS,CAAA,EAAA,CAAI,CAAC;AACrG,IAAA,OAAO,OAAO;AAChB;AAEA;;;;;;AAMG;AACH,eAAe,kBAAkB,CAAC,GAAW,EAAE,QAAgB,EAAA;;AAE7D,IAAA,IAAI,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;QACrC,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC5C,QAAA,IAAI,MAAM;AAAE,YAAA,OAAO,MAAM;;IAE3B;IAEA,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC5C,IAAI,MAAM,EAAE,WAAW;AAAE,QAAA,OAAO,MAAM;;IAGtC,MAAM,QAAQ,GAAG,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC;AACnD,IAAA,IAAI,QAAQ;AAAE,QAAA,OAAO,QAAQ;AAE7B,IAAA,MAAM,OAAO,GAAG,iBAAiB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,MAAK;AAC5D,QAAA,oBAAoB,CAAC,MAAM,CAAC,QAAQ,CAAC;AACvC,IAAA,CAAC,CAAC;AACF,IAAA,oBAAoB,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC;AAC3C,IAAA,OAAO,OAAO;AAChB;AAEA;AACA;AACA;AAEA;;;;;AAKG;AACH,eAAe,gBAAgB,CAAC,QAAkB,EAAA;AAChD,IAAA,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE;IAClC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;;IAG9B,IAAI,gBAAgB,GAAa,EAAE;IACnC,IAAI,aAAa,GAAG,EAAE;AAEtB,IAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;AACxB,QAAA,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;YAC7B,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACtC;AAAO,aAAA,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE;;YAEnC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACtC;AAAO,aAAA,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE;;YAE5D,aAAa,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE;YAClD,gBAAgB,GAAG,EAAE;QACvB;IACF;;AAGA,IAAA,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE;QAC/B,aAAa,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE;IACpD;IAEA,IAAI,CAAC,aAAa,EAAE;AAClB,QAAA,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC;IACnC;AAEA,IAAA,IAAI;QACF,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAoB;AACxD,QAAA,IAAI,GAAG,CAAC,KAAK,EAAE;AACb,YAAA,MAAM,IAAI,WAAW,CACnB,GAAG,CAAC,KAAK,CAAC,IAAI,EACd,CAAA,UAAA,EAAa,GAAG,CAAC,KAAK,CAAC,IAAI,CAAA,GAAA,EAAM,GAAG,CAAC,KAAK,CAAC,OAAO,CAAA,CAAE,EACpD,GAAG,CAAC,KAAK,CAAC,IAAI,CACf;QACH;QACA,OAAO,GAAG,CAAC,MAAM;IACnB;IAAE,OAAO,GAAG,EAAE;AACZ,QAAA,IAAI,GAAG,YAAY,WAAW,EAAE;AAC9B,YAAA,MAAM,IAAI,KAAK,CAAC,CAAA,YAAA,EAAe,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA,CAAE,CAAC;QAC/D;AACA,QAAA,MAAM,GAAG;IACX;AACF;AAEA;AACA;AACA;AAEA;;;;;;AAMG;AACG,SAAU,kBAAkB,CAAC,QAAgB,EAAA;IACjD,OAAO,CAAC,GAAG,CAAC,CAAA,EAAG,OAAO,CAAA,iBAAA,EAAoB,QAAQ,CAAA,EAAA,CAAI,CAAC;AACvD,IAAA,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC;AAC/B,IAAA,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC;AAChC,IAAA,mBAAmB,CAAC,MAAM,CAAC,QAAQ,CAAC;AACpC,IAAA,oBAAoB,CAAC,MAAM,CAAC,QAAQ,CAAC;AACvC;AAeA;;;;;;;;;;;;AAYG;AACI,eAAe,WAAW,CAC/B,QAAgB,EAChB,MAAc,EACd,MAAgC,EAChC,OAA4B,EAAA;AAE5B,IAAA,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC;AACrC,IAAA,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS;AAEpC,IAAA,MAAM,IAAI,GAAmB;AAC3B,QAAA,OAAO,EAAE,KAAK;AACd,QAAA,EAAE,EAAEA,0BAAa,CAAC,SAAS,CAAC;QAC5B,MAAM;AACN,QAAA,IAAI,MAAM,KAAK,SAAS,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;KAC5C;IAED,IAAI,OAAO,GAAG,MAAM,kBAAkB,CAAC,GAAG,EAAE,QAAQ,CAAC;AAErD,IAAA,IAAI;AACF,QAAA,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC;;QAEvF,IAAI,YAAY,EAAE;AAChB,YAAA,OAAO,CAAC,SAAS,GAAG,YAAY;QAClC;AACA,QAAA,OAAO,SAAS;IAClB;IAAE,OAAO,GAAG,EAAE;;AAEZ,QAAA,IAAI,GAAG,YAAY,WAAW,IAAI,uBAAuB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YACvE,kBAAkB,CAAC,QAAQ,CAAC;QAC9B;;QAGA,IAAI,OAAO,CAAC,SAAS;AAAE,YAAA,MAAM,GAAG;;;QAIhC,IAAI,GAAG,YAAY,YAAY,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,EAAE;YACzD,OAAO,CAAC,GAAG,CAAC,CAAA,EAAG,OAAO,CAAA,uBAAA,EAA0B,QAAQ,CAAA,UAAA,CAAY,CAAC;AACrE,YAAA,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC;;YAGhC,OAAO,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,QAAQ,CAAC;AAC7C,YAAA,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC;YACvF,IAAI,YAAY,EAAE;AAChB,gBAAA,OAAO,CAAC,SAAS,GAAG,YAAY;YAClC;AACA,YAAA,OAAO,SAAS;QAClB;;AAGA,QAAA,OAAO,CAAC,KAAK,CAAC,CAAA,EAAG,OAAO,CAAA,qBAAA,EAAwB,QAAQ,CAAA,WAAA,EAAc,MAAM,CAAA,IAAA,EAAO,GAAG,YAAY,KAAK,GAAG,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA,CAAE,CAAC;AACtI,QAAA,MAAM,GAAG;IACX;AACF;AAEA;;;;;AAKG;AACH,eAAe,cAAc,CAAC,GAAW,EAAE,QAAgB,EAAA;IACzD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC;AACnD,IAAA,IAAI,QAAQ;AAAE,QAAA,OAAO,QAAQ;AAE7B,IAAA,MAAM,OAAO,GAAG,iBAAiB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,MAAK;AAC5D,QAAA,oBAAoB,CAAC,MAAM,CAAC,QAAQ,CAAC;AACvC,IAAA,CAAC,CAAC;AACF,IAAA,oBAAoB,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC;AAC3C,IAAA,OAAO,OAAO;AAChB;;ACpiBA;;;;;AAKG;AAEH;AACA,MAAM,2BAA2B,GAAG,IAAI,GAAG,CAAC;IAC1C,mBAAmB,EAAE,sBAAsB,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO;IAC9E,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS;IACzE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa;AACxE,IAAA,eAAe,EAAE,eAAe;AACjC,CAAA,CAAC;AAEF;;;AAGG;AACG,SAAU,oBAAoB,CAAC,MAAe,EAAA;AAClD,IAAA,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;AAAE,QAAA,OAAO,MAAM;AACxD,IAAA,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;AAAE,QAAA,OAAO,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC;IAElE,MAAM,GAAG,GAAG,MAAiC;;AAG7C,IAAA,MAAM,IAAI,GAA4B;QACpC,IAAI,GAAG,CAAC,KAAK,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,GAAG,GAAG,CAAC,KAAgC,GAAG,EAAE,CAAC;QAC3F,IAAI,GAAG,CAAC,WAAW,IAAI,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ,GAAG,GAAG,CAAC,WAAsC,GAAG,EAAE,CAAC;KAC9G;IAED,OAAO,aAAa,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC;AAC5C;AAEA,SAAS,aAAa,CACpB,MAAe,EACf,IAA6B,EAC7B,QAAqB,EAAA;AAErB,IAAA,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;AAAE,QAAA,OAAO,MAAM;AACxD,IAAA,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;AAAE,QAAA,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAE3F,MAAM,GAAG,GAAG,MAAiC;;IAG7C,IAAI,GAAG,CAAC,KAAK,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,EAAE;QAC9C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,KAAgC,CAAC;IAC3D;IACA,IAAI,GAAG,CAAC,WAAW,IAAI,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ,EAAE;QAC1D,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,WAAsC,CAAC;IACjE;;AAGA,IAAA,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE;AAChC,QAAA,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI;AACpB,QAAA,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,EAAE,CAAC;QAEjC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,mCAAmC,CAAC;AAC5D,QAAA,IAAI,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AACvC,YAAA,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC;AACnC,YAAA,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;AAClB,YAAA,OAAO,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC;QACvD;QACA,OAAO,EAAE,CAAC;IACZ;IAEA,MAAM,OAAO,GAA4B,EAAE;AAC3C,IAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;AAC9C,QAAA,IAAI,2BAA2B,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE;AAE1C,QAAA,IAAI,GAAG,KAAK,OAAO,EAAE;AACnB,YAAA,OAAO,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC;YACtB;QACF;AAEA,QAAA,IAAI,GAAG,KAAK,YAAY,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACvF,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,WAAW,CAC/B,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK;gBAC/D,CAAC,EAAE,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC;AACpC,aAAA,CAAC,CACH;QACH;AAAO,aAAA,IAAI,GAAG,KAAK,OAAO,IAAI,KAAK,EAAE;YACnC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK;AAChC,kBAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC;kBACvD,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC;QAC1C;aAAO,IAAI,CAAC,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,OAAO,KAAK,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;;YAE1F,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAI;AACjC,gBAAA,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;AAAE,oBAAA,OAAO,IAAI;gBAC5C,MAAM,CAAC,GAAG,CAA4B;AACtC,gBAAA,OAAO,CAAC,CAAC,IAAI,KAAK,MAAM;AAC1B,YAAA,CAAC,CAAC;AACF,YAAA,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;;AAExB,gBAAA,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC;AACxD,gBAAA,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;AAClE,oBAAA,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAiC,CAAC;gBAC3D;YACF;iBAAO;gBACL,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;YACrE;QACF;aAAO;AACL,YAAA,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK;QACtB;IACF;AAEA,IAAA,OAAO,OAAO;AAChB;;AC3GA;;;;;;;;;;;;;AAaG;AAyBH;AACA;AACA;AAEA;AACA,MAAM,UAAU,GAAG,CAAC,IAAa,MAAM;IACrC,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;AAC1E,CAAA,CAAC;AAEF;AACA,MAAM,WAAW,GAAG,CAAC,GAAY,KAAI;;IAEnC,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,SAAS,IAAI,GAAG,EAAE;AACtD,QAAA,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,GAA2C;AACvE,QAAA,OAAO,UAAU,CAAC,EAAE,KAAK,EAAE,MAAM,IAAI,CAAA,KAAA,EAAQ,OAAO,CAAA,CAAE,EAAE,OAAO,EAAE,CAAC;IACpE;AAEA,IAAA,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC;IAChE,OAAO,UAAU,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACvC,CAAC;AAED;AACA;AACA;AAEA,MAAM,UAAU,GAAG,OAAO,QAAgB,KAAsB;IAC9D,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,YAAY,CAA0C;AAEjG,IAAA,MAAM,KAAK,GAAG,MAAM,EAAE,KAAK,IAAI,EAAE;AACjC,IAAA,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;QACtB,OAAO,EAAE,OAAO,EAAE,CAAA,IAAA,EAAO,QAAQ,CAAA,SAAA,CAAW,EAAE,KAAK,EAAE,EAAE,EAAE;IAC3D;IAEA,OAAO;QACL,QAAQ;QACR,KAAK,EAAE,KAAK,CAAC,MAAM;QACnB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM;YACvB,IAAI,EAAE,CAAC,CAAC,IAAI;AACZ,YAAA,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,EAAE;;;AAGhC,YAAA,WAAW,EAAE,CAAC,CAAC,WAAW,GAAG,oBAAoB,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,SAAS;AAC7E,SAAA,CAAC,CAAC;KACJ;AACH,CAAC;AAED;AACA;AACA;AAEA;;;;;;;AAOG;AACH,MAAM,2BAA2B,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD;;;;;AAKG;AACH,MAAM,0BAA0B,GAAG,CAAC,MAAe,EAAE,QAAgB,KAAU;AAC7E,IAAA,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE;AAE3C,IAAA,MAAM,EAAE,OAAO,EAAE,GAAG,MAA8D;AAClF,IAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE;AAE7B,IAAA,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE;QAC1B,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE;AACxC,QAAA,IAAI;YACF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAA4B;AAC/D,YAAA,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,2BAA2B,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;gBACzF,OAAO,CAAC,GAAG,CAAC,CAAA,eAAA,EAAkB,MAAM,CAAC,OAAO,CAAA,YAAA,EAAe,QAAQ,CAAA,OAAA,CAAS,CAAC;gBAC7E,kBAAkB,CAAC,QAAQ,CAAC;gBAC5B;YACF;QACF;AAAE,QAAA,MAAM;;QAER;IACF;AACF,CAAC;AAED;AACA;AACA;AAEA;;;;;;;;;;AAUG;AACH,eAAe,sBAAsB,CAAC,MAAe,EAAA;AACnD,IAAA,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE;;AAG5B,IAAA,MAAM,OAAO,GAAI,MAAkC,EAAE,OAAO;AAC5D,IAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;AAAE,QAAA,OAAO,MAAM;IAE1C,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAC3B,CAAC,CAA0B,KAAK,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAClC;AAC/C,IAAA,IAAI,CAAC,QAAQ;AAAE,QAAA,OAAO,MAAM;;AAG5B,IAAA,IAAI,OAAgC;AACpC,IAAA,IAAI;QACF,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAA4B;IAChE;AAAE,IAAA,MAAM;;AAEN,QAAA,OAAO,MAAM;IACf;;AAGA,IAAA,IAAI,OAAO,CAAC,OAAO,KAAK,CAAC;AAAE,QAAA,OAAO,MAAM;AAExC,IAAA,MAAM,SAAS,GAAG,OAAO,CAAC,UAAiD;IAC3E,IAAI,CAAC,SAAS,IAAI,OAAO,SAAS,CAAC,WAAW,KAAK,QAAQ;AAAE,QAAA,OAAO,MAAM;AAE1E,IAAA,MAAM,UAAU,GAAG,SAAS,CAAC,WAAqB;AAClD,IAAA,MAAM,SAAS,GAAG,SAAS,CAAC,IAA0B;AACtD,IAAA,MAAM,SAAS,GAAG,SAAS,CAAC,IAA0B;AACtD,IAAA,MAAM,OAAO,GAAG,SAAS,CAAC,QAA8B;AAExD,IAAA,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE;;IAGjC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC;AAChD,IAAA,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;;AAGlC,IAAA,MAAM,WAAW,GAAG,MAAM,UAAU,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,IAAI,0BAA0B;AACnG,IAAA,MAAM,aAAa,GAAG,WAAW,CAAC,GAAG,EAAE;;;;IAKvC,MAAM,iBAAiB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAE3C,IAAA,MAAM,IAAI,GAAG,eAAe,EAAE;AAC9B,IAAA,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,eAAe,CACpD,MAAM,EACN,WAAW,EACX,SAAS,EACT,iBAAiB;AACjB,IAAA,SAAS,CACV;;;AAID,IAAA,MAAM,cAAc,GAA2B;AAC7C,QAAA,WAAW,EAAE,MAAM;KACpB;AACD,IAAA,MAAM,QAAQ,GAAG,cAAc,CAAC,WAAW,CAAC;AAC5C,IAAA,IAAI,QAAQ,IAAI,CAACL,eAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;AACzC,QAAA,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,GAAG,QAAQ;AACrC,QAAA,IAAI;YACF,MAAMC,aAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC;AACpC,YAAA,KAAK,CAAC,IAAI,GAAG,OAAO;QACtB;AAAE,QAAA,MAAM;;QAER;IACF;AAEA,IAAA,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE;;AAGhC,IAAA,MAAM,UAAU,GAAG;AACjB,QAAA,OAAO,EAAE,CAAC;AACV,QAAA,MAAM,EAAE,IAAI;AACZ,QAAA,UAAU,EAAE;AACV,YAAA,QAAQ,EAAE,OAAO;AACjB,YAAA,IAAI,EAAE,SAAS,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE;AAC9C,YAAA,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,KAAK,CAAC,IAAI;YACtB,IAAI,EAAE,MAAM,CAAC,MAAM;YACnB,YAAY,EAAE,KAAK,CAAC,WAAW;AAChC,SAAA;KACF;AAED,IAAA,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE;;AAG9B,IAAA,OAAO,CAAC,GAAG,CACT,sCAAsC,OAAO,IAAI,SAAS,CAAA,EAAA,CAAI;QAC9D,CAAA,KAAA,EAAQ,SAAS,IAAI,SAAS,CAAA,OAAA,EAAU,MAAM,CAAC,MAAM,CAAA,QAAA,EAAW,KAAK,CAAC,IAAI,CAAA,EAAA,CAAI;QAC9E,CAAA,YAAA,EAAe,CAAC,IAAI,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA,MAAA,CAAQ;QAC7C,CAAA,iBAAA,EAAoB,CAAC,OAAO,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA,IAAA,CAAM;AACnD,QAAA,CAAA,mBAAA,EAAsB,CAAC,QAAQ,GAAG,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA,YAAA,EAAe,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA,YAAA,CAAc;AAChK,QAAA,CAAA,mBAAA,EAAsB,CAAC,aAAa,GAAG,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA,KAAA,EAAQ,WAAW,CAAA,GAAA,CAAK;QACnF,CAAA,qBAAA,EAAwB,CAAC,MAAM,GAAG,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA,IAAA,CAAM;AACjE,QAAA,CAAA,iBAAA,EAAoB,CAAC,IAAI,GAAG,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA,EAAA,CAAI,CACnD;;IAGD,OAAO;AACL,QAAA,OAAO,EAAE,CAAC;AACR,gBAAA,IAAI,EAAE,MAAe;AACrB,gBAAA,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;aACjC,CAAC;KACH;AACH;AAEA;AACA;AACA;AAEA,MAAM,UAAU,GAAG,OACjB,QAAgB,EAChB,MAAc,EACd,IAA6B,KACT;AACpB,IAAA,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;;AAGnC,IAAA,MAAM,OAAO,GAAG,MAAM,KAAK,eAAe,GAAG,EAAE,SAAS,EAAE,yBAAyB,EAAE,GAAG,SAAS;IAEjG,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,YAAY,EAAE;AACvD,QAAA,IAAI,EAAE,MAAM;AACZ,QAAA,SAAS,EAAE,IAAI;KAChB,EAAE,OAAO,CAAC;AAEX,IAAA,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE;AACjC,IAAA,MAAM,KAAK,GAAG,CAAC,OAAO,GAAG,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;;AAG9C,IAAA,0BAA0B,CAAC,MAAM,EAAE,QAAQ,CAAC;;AAG5C,IAAA,IAAI,MAAM,KAAK,eAAe,EAAE;AAC9B,QAAA,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAC,MAAM,CAAC;AACxD,QAAA,MAAM,OAAO,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CACT,CAAA,iBAAA,EAAoB,QAAQ,CAAA,CAAA,EAAI,MAAM,CAAA,MAAA,EAAS,OAAO,CAAA,EAAA,CAAI;AAC1D,YAAA,CAAA,SAAA,EAAY,KAAK,CAAA,UAAA,EAAa,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA,GAAA,CAAK,CAC5E;AACD,QAAA,OAAO,WAAW;IACpB;IAEA,OAAO,CAAC,GAAG,CAAC,CAAA,iBAAA,EAAoB,QAAQ,CAAA,CAAA,EAAI,MAAM,CAAA,KAAA,EAAQ,KAAK,CAAA,EAAA,CAAI,CAAC;AACpE,IAAA,OAAO,MAAM;AACf,CAAC;AAED;AACA;AACA;AAEA;;AAEG;AACH,MAAM,SAAS,GAAG,CAAC,IAAkD,KAA6B;AAChG,IAAA,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,EAAE;IACpB,IAAI,OAAO,IAAI,KAAK,QAAQ;AAAE,QAAA,OAAO,IAAI;AACzC,IAAA,IAAI;AACF,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAA4B;IACpD;IAAE,OAAO,GAAG,EAAE;AACZ,QAAA,MAAM,MAAM,GAAG,GAAG,YAAY,WAAW,GAAG,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,CAAA,mBAAA,EAAsB,IAAI,CAAA,EAAA,EAAK,MAAM,CAAA,CAAA,CAAG,CAAC;IAC3D;AACF,CAAC;AAED;AACA;AACA;AAEA;;AAEG;SACa,kBAAkB,GAAA;IAChC,OAAO;AACL,QAAA,IAAI,EAAE,WAAW;AACjB,QAAA,KAAK,EAAE,aAAa;AACpB,QAAA,WAAW,EAAE;YACX,8BAA8B;YAC9B,SAAS;YACT,4BAA4B;YAC5B,4BAA4B;YAC5B,EAAE;YACF,OAAO;YACP,6BAA6B;YAC7B,mDAAmD;YACnD,EAAE;YACF,KAAK;YACL,4CAA4C;YAC5C,kEAAkE;SACnE,CAAC,IAAI,CAAC,IAAI,CAAC;AACZ,QAAA,UAAU,EAAE;AACV,YAAA,IAAI,EAAE,QAAiB;AACvB,YAAA,UAAU,EAAE;AACV,gBAAA,MAAM,EAAE;AACN,oBAAA,IAAI,EAAE,QAAQ;AACd,oBAAA,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;AACtB,oBAAA,WAAW,EAAE,6BAA6B;AAC3C,iBAAA;AACD,gBAAA,QAAQ,EAAE;AACR,oBAAA,IAAI,EAAE,QAAQ;AACd,oBAAA,WAAW,EAAE,8CAA8C;AAC5D,iBAAA;AACD,gBAAA,MAAM,EAAE;AACN,oBAAA,IAAI,EAAE,QAAQ;AACd,oBAAA,WAAW,EAAE,+BAA+B;AAC7C,iBAAA;AACD,gBAAA,IAAI,EAAE;AACJ,oBAAA,IAAI,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC;AAC1B,oBAAA,WAAW,EAAE,qDAAqD;AACnE,iBAAA;AACF,aAAA;AACD,YAAA,QAAQ,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC;AACjC,SAAA;AACD,QAAA,MAAM,OAAO,CAAC,WAAmB,EAAE,MAAe,EAAA;YAChD,MAAM,CAAC,GAAG,MAA0B;AACpC,YAAA,IAAI;AACF,gBAAA,QAAQ,CAAC,CAAC,MAAM;AACd,oBAAA,KAAK,MAAM;wBACT,OAAO,UAAU,CAAC,MAAM,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;oBACjD,KAAK,MAAM,EAAE;AACX,wBAAA,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE;4BACb,OAAO,UAAU,CAAC,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAC;wBAC/D;wBACA,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9B,wBAAA,OAAO,UAAU,CAAC,MAAM,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;oBACjE;AACA,oBAAA;AACE,wBAAA,OAAO,UAAU,CAAC,EAAE,KAAK,EAAE,CAAA,QAAA,EAAW,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA,eAAA,CAAiB,EAAE,CAAC;;YAEhF;YAAE,OAAO,GAAG,EAAE;AACZ,gBAAA,OAAO,WAAW,CAAC,GAAG,CAAC;YACzB;QACF,CAAC;KACF;AACH;;AC9SA,MAAM,MAAM,GAAG;AACb,IAAA,EAAE,EAAE,uBAAuB;AAC3B,IAAA,IAAI,EAAE,MAAM;AACZ,IAAA,WAAW,EAAE,kBAAkB;IAC/B,YAAY,EAAE,uBAAuB,EAAE;AACvC,IAAA,QAAQ,CAAC,GAAsB,EAAA;AAE7B,QAAA,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC;QAC5B,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;;AAG5C,QAAA,GAAG,CAAC,YAAY,CAAC,kBAAkB,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;;;;;;;QAS7D,GAAG,CAAC,EAAE,CAAC,qBAAqB,EAAE,CAAC,MAAM,EAAE,GAAG,KAAI;;AAE5C,YAAA,IAAI,GAAG,EAAE,SAAS,KAAK,UAAU,EAAE;gBACjC;YACF;YACA,OAAO;AACL,gBAAA,mBAAmB,EAAE;oBACnB,6EAA6E;oBAC7E;iBACD,CAAC,IAAI,CAAC,IAAI,CAAC;aACb;AACH,QAAA,CAAC,CAAC;IACJ,CAAC;;;;;"}