@wecom/wecom-openclaw-plugin 2026.3.31-beta.0 → 2026.4.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -251
- package/dist/cjs/index.js +45 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/src/channel.js +339 -0
- package/dist/cjs/src/channel.js.map +1 -0
- package/dist/cjs/src/const.js +137 -0
- package/dist/cjs/src/const.js.map +1 -0
- package/dist/cjs/src/dm-policy.js +89 -0
- package/dist/cjs/src/dm-policy.js.map +1 -0
- package/dist/cjs/src/group-policy.js +133 -0
- package/dist/cjs/src/group-policy.js.map +1 -0
- package/dist/cjs/src/mcp/interceptors/biz-error.js +70 -0
- package/dist/cjs/src/mcp/interceptors/biz-error.js.map +1 -0
- package/dist/cjs/src/mcp/interceptors/index.js +73 -0
- package/dist/cjs/src/mcp/interceptors/index.js.map +1 -0
- package/dist/cjs/src/mcp/interceptors/msg-media.js +159 -0
- package/dist/cjs/src/mcp/interceptors/msg-media.js.map +1 -0
- package/dist/cjs/src/mcp/interceptors/smartpage-create.js +157 -0
- package/dist/cjs/src/mcp/interceptors/smartpage-create.js.map +1 -0
- package/dist/cjs/src/mcp/interceptors/smartpage-export.js +93 -0
- package/dist/cjs/src/mcp/interceptors/smartpage-export.js.map +1 -0
- package/dist/cjs/src/mcp/schema.js +104 -0
- package/dist/cjs/src/mcp/schema.js.map +1 -0
- package/dist/cjs/src/mcp/tool.js +208 -0
- package/dist/cjs/src/mcp/tool.js.map +1 -0
- package/dist/cjs/src/mcp/transport.js +417 -0
- package/dist/cjs/src/mcp/transport.js.map +1 -0
- package/dist/cjs/src/media-handler.js +129 -0
- package/dist/cjs/src/media-handler.js.map +1 -0
- package/dist/cjs/src/media-uploader.js +284 -0
- package/dist/cjs/src/media-uploader.js.map +1 -0
- package/dist/cjs/src/message-parser.js +134 -0
- package/dist/cjs/src/message-parser.js.map +1 -0
- package/dist/cjs/src/message-sender.js +89 -0
- package/dist/cjs/src/message-sender.js.map +1 -0
- package/dist/cjs/src/monitor.js +991 -0
- package/dist/cjs/src/monitor.js.map +1 -0
- package/dist/cjs/src/onboarding.js +182 -0
- package/dist/cjs/src/onboarding.js.map +1 -0
- package/dist/cjs/src/openclaw-compat.js +400 -0
- package/dist/cjs/src/openclaw-compat.js.map +1 -0
- package/dist/cjs/src/reqid-store.js +88 -0
- package/dist/cjs/src/reqid-store.js.map +1 -0
- package/dist/cjs/src/runtime.js +16 -0
- package/dist/cjs/src/runtime.js.map +1 -0
- package/dist/cjs/src/state-dir-resolve.js +35 -0
- package/dist/cjs/src/state-dir-resolve.js.map +1 -0
- package/dist/cjs/src/state-manager.js +158 -0
- package/dist/cjs/src/state-manager.js.map +1 -0
- package/dist/cjs/src/template-card-parser.js +641 -0
- package/dist/cjs/src/template-card-parser.js.map +1 -0
- package/dist/cjs/src/timeout.js +42 -0
- package/dist/cjs/src/timeout.js.map +1 -0
- package/dist/cjs/src/utils.js +60 -0
- package/dist/cjs/src/utils.js.map +1 -0
- package/dist/cjs/src/version.js +26 -0
- package/dist/cjs/src/version.js.map +1 -0
- package/dist/esm/index.js +41 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/src/channel.js +337 -0
- package/dist/esm/src/channel.js.map +1 -0
- package/dist/{src → esm/src}/const.js +30 -77
- package/dist/esm/src/const.js.map +1 -0
- package/dist/{src → esm/src}/dm-policy.js +9 -6
- package/dist/esm/src/dm-policy.js.map +1 -0
- package/dist/{src → esm/src}/group-policy.js +7 -3
- package/dist/esm/src/group-policy.js.map +1 -0
- package/dist/{src → esm/src}/mcp/interceptors/biz-error.js +6 -2
- package/dist/esm/src/mcp/interceptors/biz-error.js.map +1 -0
- package/dist/{src → esm/src}/mcp/interceptors/index.js +10 -6
- package/dist/esm/src/mcp/interceptors/index.js.map +1 -0
- package/dist/{src → esm/src}/mcp/interceptors/msg-media.js +10 -6
- package/dist/esm/src/mcp/interceptors/msg-media.js.map +1 -0
- package/dist/{src → esm/src}/mcp/interceptors/smartpage-create.js +6 -2
- package/dist/esm/src/mcp/interceptors/smartpage-create.js.map +1 -0
- package/dist/{src → esm/src}/mcp/interceptors/smartpage-export.js +6 -2
- package/dist/esm/src/mcp/interceptors/smartpage-export.js.map +1 -0
- package/dist/{src → esm/src}/mcp/schema.js +4 -1
- package/dist/esm/src/mcp/schema.js.map +1 -0
- package/dist/{src → esm/src}/mcp/tool.js +8 -4
- package/dist/esm/src/mcp/tool.js.map +1 -0
- package/dist/{src → esm/src}/mcp/transport.js +16 -15
- package/dist/esm/src/mcp/transport.js.map +1 -0
- package/dist/{src → esm/src}/media-handler.js +10 -6
- package/dist/esm/src/media-handler.js.map +1 -0
- package/dist/{src → esm/src}/media-uploader.js +10 -64
- package/dist/esm/src/media-uploader.js.map +1 -0
- package/dist/{src → esm/src}/message-parser.js +4 -1
- package/dist/esm/src/message-parser.js.map +1 -0
- package/dist/{src → esm/src}/message-sender.js +11 -46
- package/dist/esm/src/message-sender.js.map +1 -0
- package/dist/{src → esm/src}/monitor.js +282 -151
- package/dist/esm/src/monitor.js.map +1 -0
- package/dist/{src → esm/src}/onboarding.js +26 -22
- package/dist/esm/src/onboarding.js.map +1 -0
- package/dist/{src → esm/src}/openclaw-compat.js +27 -143
- package/dist/esm/src/openclaw-compat.js.map +1 -0
- package/dist/{src → esm/src}/reqid-store.js +7 -4
- package/dist/esm/src/reqid-store.js.map +1 -0
- package/dist/{src → esm/src}/runtime.js +5 -2
- package/dist/esm/src/runtime.js.map +1 -0
- package/dist/esm/src/state-dir-resolve.js +13 -0
- package/dist/esm/src/state-dir-resolve.js.map +1 -0
- package/dist/{src → esm/src}/state-manager.js +16 -84
- package/dist/esm/src/state-manager.js.map +1 -0
- package/dist/{src → esm/src}/template-card-parser.js +8 -17
- package/dist/esm/src/template-card-parser.js.map +1 -0
- package/dist/{src → esm/src}/timeout.js +5 -2
- package/dist/esm/src/timeout.js.map +1 -0
- package/dist/{src → esm/src}/utils.js +10 -24
- package/dist/esm/src/utils.js.map +1 -0
- package/dist/esm/src/version.js +23 -0
- package/dist/esm/src/version.js.map +1 -0
- package/dist/esm/types/index.d.ts +9 -0
- package/dist/{src → esm/types/src}/const.d.ts +0 -46
- package/dist/{src → esm/types/src}/interface.d.ts +2 -0
- package/dist/{src → esm/types/src}/message-sender.d.ts +0 -18
- package/dist/{src → esm/types/src}/openclaw-compat.d.ts +0 -49
- package/dist/esm/types/src/state-dir-resolve.d.ts +2 -0
- package/dist/{src → esm/types/src}/utils.d.ts +0 -39
- package/dist/esm/types/src/version.d.ts +2 -0
- package/dist/index.d.ts +4 -2
- package/package.json +7 -15
- package/dist/index.js +0 -113
- package/dist/src/accounts.d.ts +0 -57
- package/dist/src/accounts.js +0 -222
- package/dist/src/agent/api-client.d.ts +0 -94
- package/dist/src/agent/api-client.js +0 -292
- package/dist/src/agent/handler.d.ts +0 -63
- package/dist/src/agent/handler.js +0 -532
- package/dist/src/agent/index.d.ts +0 -5
- package/dist/src/agent/index.js +0 -5
- package/dist/src/agent/webhook.d.ts +0 -23
- package/dist/src/agent/webhook.js +0 -226
- package/dist/src/agent/xml.d.ts +0 -21
- package/dist/src/agent/xml.js +0 -41
- package/dist/src/channel.js +0 -564
- package/dist/src/chat-queue.d.ts +0 -31
- package/dist/src/chat-queue.js +0 -45
- package/dist/src/http.d.ts +0 -26
- package/dist/src/http.js +0 -93
- package/dist/src/interface.js +0 -4
- package/dist/src/mcp/index.js +0 -6
- package/dist/src/mcp/interceptors/types.js +0 -7
- package/dist/src/shared/command-auth.d.ts +0 -23
- package/dist/src/shared/command-auth.js +0 -73
- package/dist/src/shared/xml-parser.d.ts +0 -46
- package/dist/src/shared/xml-parser.js +0 -210
- package/dist/src/target.d.ts +0 -35
- package/dist/src/target.js +0 -67
- package/dist/src/template-card-manager.d.ts +0 -55
- package/dist/src/template-card-manager.js +0 -205
- package/dist/src/types/account.d.ts +0 -29
- package/dist/src/types/account.js +0 -4
- package/dist/src/types/config.d.ts +0 -80
- package/dist/src/types/config.js +0 -7
- package/dist/src/types/constants.d.ts +0 -42
- package/dist/src/types/constants.js +0 -42
- package/dist/src/types/index.d.ts +0 -7
- package/dist/src/types/index.js +0 -5
- package/dist/src/types/message.d.ts +0 -238
- package/dist/src/types/message.js +0 -5
- package/dist/src/version.d.ts +0 -2
- package/dist/src/version.js +0 -24
- package/dist/src/webhook/command-auth.d.ts +0 -47
- package/dist/src/webhook/command-auth.js +0 -96
- package/dist/src/webhook/gateway.d.ts +0 -36
- package/dist/src/webhook/gateway.js +0 -227
- package/dist/src/webhook/handler.d.ts +0 -18
- package/dist/src/webhook/handler.js +0 -420
- package/dist/src/webhook/helpers.d.ts +0 -156
- package/dist/src/webhook/helpers.js +0 -833
- package/dist/src/webhook/http.d.ts +0 -26
- package/dist/src/webhook/http.js +0 -94
- package/dist/src/webhook/index.d.ts +0 -11
- package/dist/src/webhook/index.js +0 -14
- package/dist/src/webhook/media.d.ts +0 -29
- package/dist/src/webhook/media.js +0 -88
- package/dist/src/webhook/monitor.d.ts +0 -59
- package/dist/src/webhook/monitor.js +0 -1147
- package/dist/src/webhook/state.d.ts +0 -220
- package/dist/src/webhook/state.js +0 -491
- package/dist/src/webhook/target.d.ts +0 -41
- package/dist/src/webhook/target.js +0 -132
- package/dist/src/webhook/types.d.ts +0 -347
- package/dist/src/webhook/types.js +0 -33
- /package/dist/{src → esm/types/src}/channel.d.ts +0 -0
- /package/dist/{src → esm/types/src}/dm-policy.d.ts +0 -0
- /package/dist/{src → esm/types/src}/group-policy.d.ts +0 -0
- /package/dist/{src → esm/types/src}/mcp/index.d.ts +0 -0
- /package/dist/{src → esm/types/src}/mcp/interceptors/biz-error.d.ts +0 -0
- /package/dist/{src → esm/types/src}/mcp/interceptors/index.d.ts +0 -0
- /package/dist/{src → esm/types/src}/mcp/interceptors/msg-media.d.ts +0 -0
- /package/dist/{src → esm/types/src}/mcp/interceptors/smartpage-create.d.ts +0 -0
- /package/dist/{src → esm/types/src}/mcp/interceptors/smartpage-export.d.ts +0 -0
- /package/dist/{src → esm/types/src}/mcp/interceptors/types.d.ts +0 -0
- /package/dist/{src → esm/types/src}/mcp/schema.d.ts +0 -0
- /package/dist/{src → esm/types/src}/mcp/tool.d.ts +0 -0
- /package/dist/{src → esm/types/src}/mcp/transport.d.ts +0 -0
- /package/dist/{src → esm/types/src}/media-handler.d.ts +0 -0
- /package/dist/{src → esm/types/src}/media-uploader.d.ts +0 -0
- /package/dist/{src → esm/types/src}/message-parser.d.ts +0 -0
- /package/dist/{src → esm/types/src}/monitor.d.ts +0 -0
- /package/dist/{src → esm/types/src}/onboarding.d.ts +0 -0
- /package/dist/{src → esm/types/src}/reqid-store.d.ts +0 -0
- /package/dist/{src → esm/types/src}/runtime.d.ts +0 -0
- /package/dist/{src → esm/types/src}/state-manager.d.ts +0 -0
- /package/dist/{src → esm/types/src}/template-card-parser.d.ts +0 -0
- /package/dist/{src → esm/types/src}/timeout.d.ts +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.js","sources":["../../../../../src/channel.ts"],"sourcesContent":["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"],"names":["DEFAULT_ACCOUNT_ID","CHANNEL_ID","getWeComWebSocket","wecomSetupWizard","wecomSetupAdapter","resolveWeComAccount","formatPairingApproveHint","getWeComRuntime","TEXT_CHUNK_LIMIT","uploadAndSendMedia","monitorWeComProvider"],"mappings":"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"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 企业微信渠道常量定义
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* 企业微信渠道 ID
|
|
8
|
+
*/
|
|
9
|
+
const CHANNEL_ID = "wecom";
|
|
10
|
+
/**
|
|
11
|
+
* 企业微信 WebSocket 命令枚举
|
|
12
|
+
*/
|
|
13
|
+
exports.WeComCommand = void 0;
|
|
14
|
+
(function (WeComCommand) {
|
|
15
|
+
/** 认证订阅 */
|
|
16
|
+
WeComCommand["SUBSCRIBE"] = "aibot_subscribe";
|
|
17
|
+
/** 心跳 */
|
|
18
|
+
WeComCommand["PING"] = "ping";
|
|
19
|
+
/** 企业微信推送消息 */
|
|
20
|
+
WeComCommand["AIBOT_CALLBACK"] = "aibot_callback";
|
|
21
|
+
/** clawdbot 响应消息 */
|
|
22
|
+
WeComCommand["AIBOT_RESPONSE"] = "aibot_response";
|
|
23
|
+
})(exports.WeComCommand || (exports.WeComCommand = {}));
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// 超时和重试配置
|
|
26
|
+
// ============================================================================
|
|
27
|
+
/** 图片下载超时时间(毫秒) */
|
|
28
|
+
const IMAGE_DOWNLOAD_TIMEOUT_MS = 30000;
|
|
29
|
+
/** 文件下载超时时间(毫秒) */
|
|
30
|
+
const FILE_DOWNLOAD_TIMEOUT_MS = 60000;
|
|
31
|
+
/** 消息发送超时时间(毫秒) */
|
|
32
|
+
const REPLY_SEND_TIMEOUT_MS = 15000;
|
|
33
|
+
/** WebSocket 心跳间隔(毫秒) */
|
|
34
|
+
const WS_HEARTBEAT_INTERVAL_MS = 30000;
|
|
35
|
+
/** WebSocket 连接断开时的最大重连次数 */
|
|
36
|
+
const WS_MAX_RECONNECT_ATTEMPTS = 10;
|
|
37
|
+
/** WebSocket 认证失败时的最大重试次数 */
|
|
38
|
+
const WS_MAX_AUTH_FAILURE_ATTEMPTS = 5;
|
|
39
|
+
// ============================================================================
|
|
40
|
+
// 消息状态管理配置
|
|
41
|
+
// ============================================================================
|
|
42
|
+
/** messageStates Map 条目的最大 TTL(毫秒),防止内存泄漏 */
|
|
43
|
+
const MESSAGE_STATE_TTL_MS = 10 * 60 * 1000;
|
|
44
|
+
/** messageStates Map 清理间隔(毫秒) */
|
|
45
|
+
const MESSAGE_STATE_CLEANUP_INTERVAL_MS = 60000;
|
|
46
|
+
/** messageStates Map 最大条目数 */
|
|
47
|
+
const MESSAGE_STATE_MAX_SIZE = 500;
|
|
48
|
+
// ============================================================================
|
|
49
|
+
// 消息模板
|
|
50
|
+
// ============================================================================
|
|
51
|
+
/** "思考中"流式消息占位内容 */
|
|
52
|
+
const THINKING_MESSAGE = "<think></think>";
|
|
53
|
+
/** 仅包含图片时的消息占位符 */
|
|
54
|
+
const MEDIA_IMAGE_PLACEHOLDER = "<media:image>";
|
|
55
|
+
/** 仅包含文件时的消息占位符 */
|
|
56
|
+
const MEDIA_DOCUMENT_PLACEHOLDER = "<media:document>";
|
|
57
|
+
// ============================================================================
|
|
58
|
+
// 默认值
|
|
59
|
+
// ============================================================================
|
|
60
|
+
// ============================================================================
|
|
61
|
+
// MCP 配置
|
|
62
|
+
// ============================================================================
|
|
63
|
+
/** 获取 MCP 配置的 WebSocket 命令 */
|
|
64
|
+
const MCP_GET_CONFIG_CMD = "aibot_get_mcp_config";
|
|
65
|
+
/** MCP 配置拉取超时时间(毫秒) */
|
|
66
|
+
const MCP_CONFIG_FETCH_TIMEOUT_MS = 15000;
|
|
67
|
+
// ============================================================================
|
|
68
|
+
// 默认值
|
|
69
|
+
// ============================================================================
|
|
70
|
+
/** 默认媒体大小上限(MB) */
|
|
71
|
+
const DEFAULT_MEDIA_MAX_MB = 5;
|
|
72
|
+
/** 文本分块大小上限 */
|
|
73
|
+
const TEXT_CHUNK_LIMIT = 4000;
|
|
74
|
+
// ============================================================================
|
|
75
|
+
// 媒体上传相关常量
|
|
76
|
+
// ============================================================================
|
|
77
|
+
/** 图片大小上限(字节):10MB */
|
|
78
|
+
const IMAGE_MAX_BYTES = 10 * 1024 * 1024;
|
|
79
|
+
/** 视频大小上限(字节):10MB */
|
|
80
|
+
const VIDEO_MAX_BYTES = 10 * 1024 * 1024;
|
|
81
|
+
/** 语音大小上限(字节):2MB */
|
|
82
|
+
const VOICE_MAX_BYTES = 2 * 1024 * 1024;
|
|
83
|
+
/** 文件大小上限(字节):20MB */
|
|
84
|
+
const FILE_MAX_BYTES = 20 * 1024 * 1024;
|
|
85
|
+
/** 文件绝对上限(字节):超过此值无法发送,等于 FILE_MAX_BYTES */
|
|
86
|
+
const ABSOLUTE_MAX_BYTES = FILE_MAX_BYTES;
|
|
87
|
+
// ============================================================================
|
|
88
|
+
// 事件/命令名称常量
|
|
89
|
+
// ============================================================================
|
|
90
|
+
/** 版本检查事件名称(SDK 事件监听用) */
|
|
91
|
+
const EVENT_ENTER_CHECK_UPDATE = "event.enter_check_update";
|
|
92
|
+
/** 版本检查事件回复命令名称 */
|
|
93
|
+
const CMD_ENTER_EVENT_REPLY = "ww_ai_robot_enter_event";
|
|
94
|
+
// ============================================================================
|
|
95
|
+
// SDK 连接配置
|
|
96
|
+
// ============================================================================
|
|
97
|
+
/** WSClient scene 参数:企微 OpenClaw 场景 */
|
|
98
|
+
const SCENE_WECOM_OPENCLAW = 1;
|
|
99
|
+
// ============================================================================
|
|
100
|
+
// 模板卡片配置
|
|
101
|
+
// ============================================================================
|
|
102
|
+
/** 合法的模板卡片 card_type 列表 */
|
|
103
|
+
const VALID_CARD_TYPES = [
|
|
104
|
+
"text_notice",
|
|
105
|
+
"news_notice",
|
|
106
|
+
"button_interaction",
|
|
107
|
+
"vote_interaction",
|
|
108
|
+
"multiple_interaction",
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
exports.ABSOLUTE_MAX_BYTES = ABSOLUTE_MAX_BYTES;
|
|
112
|
+
exports.CHANNEL_ID = CHANNEL_ID;
|
|
113
|
+
exports.CMD_ENTER_EVENT_REPLY = CMD_ENTER_EVENT_REPLY;
|
|
114
|
+
exports.DEFAULT_MEDIA_MAX_MB = DEFAULT_MEDIA_MAX_MB;
|
|
115
|
+
exports.EVENT_ENTER_CHECK_UPDATE = EVENT_ENTER_CHECK_UPDATE;
|
|
116
|
+
exports.FILE_DOWNLOAD_TIMEOUT_MS = FILE_DOWNLOAD_TIMEOUT_MS;
|
|
117
|
+
exports.FILE_MAX_BYTES = FILE_MAX_BYTES;
|
|
118
|
+
exports.IMAGE_DOWNLOAD_TIMEOUT_MS = IMAGE_DOWNLOAD_TIMEOUT_MS;
|
|
119
|
+
exports.IMAGE_MAX_BYTES = IMAGE_MAX_BYTES;
|
|
120
|
+
exports.MCP_CONFIG_FETCH_TIMEOUT_MS = MCP_CONFIG_FETCH_TIMEOUT_MS;
|
|
121
|
+
exports.MCP_GET_CONFIG_CMD = MCP_GET_CONFIG_CMD;
|
|
122
|
+
exports.MEDIA_DOCUMENT_PLACEHOLDER = MEDIA_DOCUMENT_PLACEHOLDER;
|
|
123
|
+
exports.MEDIA_IMAGE_PLACEHOLDER = MEDIA_IMAGE_PLACEHOLDER;
|
|
124
|
+
exports.MESSAGE_STATE_CLEANUP_INTERVAL_MS = MESSAGE_STATE_CLEANUP_INTERVAL_MS;
|
|
125
|
+
exports.MESSAGE_STATE_MAX_SIZE = MESSAGE_STATE_MAX_SIZE;
|
|
126
|
+
exports.MESSAGE_STATE_TTL_MS = MESSAGE_STATE_TTL_MS;
|
|
127
|
+
exports.REPLY_SEND_TIMEOUT_MS = REPLY_SEND_TIMEOUT_MS;
|
|
128
|
+
exports.SCENE_WECOM_OPENCLAW = SCENE_WECOM_OPENCLAW;
|
|
129
|
+
exports.TEXT_CHUNK_LIMIT = TEXT_CHUNK_LIMIT;
|
|
130
|
+
exports.THINKING_MESSAGE = THINKING_MESSAGE;
|
|
131
|
+
exports.VALID_CARD_TYPES = VALID_CARD_TYPES;
|
|
132
|
+
exports.VIDEO_MAX_BYTES = VIDEO_MAX_BYTES;
|
|
133
|
+
exports.VOICE_MAX_BYTES = VOICE_MAX_BYTES;
|
|
134
|
+
exports.WS_HEARTBEAT_INTERVAL_MS = WS_HEARTBEAT_INTERVAL_MS;
|
|
135
|
+
exports.WS_MAX_AUTH_FAILURE_ATTEMPTS = WS_MAX_AUTH_FAILURE_ATTEMPTS;
|
|
136
|
+
exports.WS_MAX_RECONNECT_ATTEMPTS = WS_MAX_RECONNECT_ATTEMPTS;
|
|
137
|
+
//# sourceMappingURL=const.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"const.js","sources":["../../../../../src/const.ts"],"sourcesContent":["/**\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"],"names":["WeComCommand"],"mappings":";;AAAA;;AAEG;AAEH;;AAEG;AACI,MAAM,UAAU,GAAG;AAE1B;;AAEG;AACSA;AAAZ,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,EATWA,oBAAY,KAAZA,oBAAY,GAAA,EAAA,CAAA,CAAA;AAWxB;AACA;AACA;AAEA;AACO,MAAM,yBAAyB,GAAG;AAEzC;AACO,MAAM,wBAAwB,GAAG;AAExC;AACO,MAAM,qBAAqB,GAAG;AAKrC;AACO,MAAM,wBAAwB,GAAG;AAExC;AACO,MAAM,yBAAyB,GAAG;AAEzC;AACO,MAAM,4BAA4B,GAAG;AAE5C;AACA;AACA;AAEA;MACa,oBAAoB,GAAG,EAAE,GAAG,EAAE,GAAG;AAE9C;AACO,MAAM,iCAAiC,GAAG;AAEjD;AACO,MAAM,sBAAsB,GAAG;AAEtC;AACA;AACA;AAEA;AACO,MAAM,gBAAgB,GAAG;AAEhC;AACO,MAAM,uBAAuB,GAAG;AAEvC;AACO,MAAM,0BAA0B,GAAG;AAC1C;AACA;AACA;AAEA;AACA;AACA;AAEA;AACO,MAAM,kBAAkB,GAAG;AAElC;AACO,MAAM,2BAA2B,GAAG;AAE3C;AACA;AACA;AAEA;AACO,MAAM,oBAAoB,GAAG;AAEpC;AACO,MAAM,gBAAgB,GAAG;AAEhC;AACA;AACA;AAEA;MACa,eAAe,GAAG,EAAE,GAAG,IAAI,GAAG;AAE3C;MACa,eAAe,GAAG,EAAE,GAAG,IAAI,GAAG;AAE3C;MACa,eAAe,GAAG,CAAC,GAAG,IAAI,GAAG;AAE1C;MACa,cAAc,GAAG,EAAE,GAAG,IAAI,GAAG;AAE1C;AACO,MAAM,kBAAkB,GAAG;AAKlC;AACA;AACA;AAEA;AACO,MAAM,wBAAwB,GAAG;AAExC;AACO,MAAM,qBAAqB,GAAG;AAErC;AACA;AACA;AAEA;AACO,MAAM,oBAAoB,GAAG;AAEpC;AACA;AACA;AAEA;AACO,MAAM,gBAAgB,GAAa;IACxC,aAAa;IACb,aAAa;IACb,oBAAoB;IACpB,kBAAkB;IAClB,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var runtime = require('./runtime.js');
|
|
4
|
+
var _const = require('./const.js');
|
|
5
|
+
var messageSender = require('./message-sender.js');
|
|
6
|
+
var groupPolicy = require('./group-policy.js');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 企业微信 DM(私聊)访问控制模块
|
|
10
|
+
*
|
|
11
|
+
* 负责私聊策略检查、配对流程
|
|
12
|
+
*/
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// 公开 API
|
|
15
|
+
// ============================================================================
|
|
16
|
+
/**
|
|
17
|
+
* 检查 DM Policy 访问控制
|
|
18
|
+
* @returns 检查结果,包含是否允许继续处理
|
|
19
|
+
*/
|
|
20
|
+
async function checkDmPolicy(params) {
|
|
21
|
+
const { senderId, isGroup, account, wsClient, frame, runtime: runtime$1 } = params;
|
|
22
|
+
const core = runtime.getWeComRuntime();
|
|
23
|
+
// 群聊消息不检查 DM Policy
|
|
24
|
+
if (isGroup) {
|
|
25
|
+
return { allowed: true };
|
|
26
|
+
}
|
|
27
|
+
const dmPolicy = account.config.dmPolicy ?? "open";
|
|
28
|
+
const configAllowFrom = (account.config.allowFrom ?? []).map((v) => String(v));
|
|
29
|
+
// 如果 dmPolicy 是 disabled,直接拒绝
|
|
30
|
+
if (dmPolicy === "disabled") {
|
|
31
|
+
runtime$1.log?.(`[WeCom] Blocked DM from ${senderId} (dmPolicy=disabled)`);
|
|
32
|
+
return { allowed: false };
|
|
33
|
+
}
|
|
34
|
+
// 如果是 open 模式,允许所有人
|
|
35
|
+
if (dmPolicy === "open") {
|
|
36
|
+
return { allowed: true };
|
|
37
|
+
}
|
|
38
|
+
// OpenClaw <= 2026.2.19 signature: readAllowFromStore(channel, env?, accountId?)
|
|
39
|
+
const oldStoreAllowFrom = await core.channel.pairing.readAllowFromStore('wecom', undefined, account.accountId).catch(() => []);
|
|
40
|
+
// Compatibility fallback for newer OpenClaw implementations.
|
|
41
|
+
const newStoreAllowFrom = await core.channel.pairing
|
|
42
|
+
.readAllowFromStore({ channel: _const.CHANNEL_ID, accountId: account.accountId })
|
|
43
|
+
.catch(() => []);
|
|
44
|
+
// 检查发送者是否在允许列表中
|
|
45
|
+
const storeAllowFrom = [...oldStoreAllowFrom, ...newStoreAllowFrom];
|
|
46
|
+
const effectiveAllowFrom = [...configAllowFrom, ...storeAllowFrom];
|
|
47
|
+
const senderAllowedResult = groupPolicy.isSenderAllowed(senderId, effectiveAllowFrom);
|
|
48
|
+
if (senderAllowedResult) {
|
|
49
|
+
return { allowed: true };
|
|
50
|
+
}
|
|
51
|
+
// 处理未授权用户
|
|
52
|
+
if (dmPolicy === "pairing") {
|
|
53
|
+
const { code, created } = await core.channel.pairing.upsertPairingRequest({
|
|
54
|
+
channel: _const.CHANNEL_ID,
|
|
55
|
+
id: senderId,
|
|
56
|
+
accountId: account.accountId,
|
|
57
|
+
meta: { name: senderId },
|
|
58
|
+
});
|
|
59
|
+
if (created) {
|
|
60
|
+
runtime$1.log?.(`[WeCom] Pairing request created for sender=${senderId}`);
|
|
61
|
+
try {
|
|
62
|
+
await messageSender.sendWeComReply({
|
|
63
|
+
wsClient,
|
|
64
|
+
frame,
|
|
65
|
+
text: core.channel.pairing.buildPairingReply({
|
|
66
|
+
channel: _const.CHANNEL_ID,
|
|
67
|
+
idLine: `您的企业微信用户ID: ${senderId}`,
|
|
68
|
+
code,
|
|
69
|
+
}),
|
|
70
|
+
runtime: runtime$1,
|
|
71
|
+
finish: true,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
runtime$1.error?.(`[WeCom] Failed to send pairing reply to ${senderId}: ${String(err)}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
runtime$1.log?.(`[WeCom] Pairing request already exists for sender=${senderId}`);
|
|
80
|
+
}
|
|
81
|
+
return { allowed: false, pairingSent: created };
|
|
82
|
+
}
|
|
83
|
+
// allowlist 模式:直接拒绝未授权用户
|
|
84
|
+
runtime$1.log?.(`[WeCom] Blocked unauthorized sender ${senderId} (dmPolicy=${dmPolicy})`);
|
|
85
|
+
return { allowed: false };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
exports.checkDmPolicy = checkDmPolicy;
|
|
89
|
+
//# sourceMappingURL=dm-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dm-policy.js","sources":["../../../../../src/dm-policy.ts"],"sourcesContent":["/**\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"],"names":["runtime","getWeComRuntime","CHANNEL_ID","isSenderAllowed","sendWeComReply"],"mappings":"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"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _const = require('./const.js');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 企业微信群组访问控制模块
|
|
7
|
+
*
|
|
8
|
+
* 负责群组策略检查(groupPolicy、群组白名单、群内发送者白名单)
|
|
9
|
+
*/
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// 内部辅助函数
|
|
12
|
+
// ============================================================================
|
|
13
|
+
/**
|
|
14
|
+
* 解析企业微信群组配置
|
|
15
|
+
*/
|
|
16
|
+
function resolveWeComGroupConfig(params) {
|
|
17
|
+
const groups = params.cfg?.groups ?? {};
|
|
18
|
+
const wildcard = groups["*"];
|
|
19
|
+
const groupId = params.groupId?.trim();
|
|
20
|
+
if (!groupId) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
const direct = groups[groupId];
|
|
24
|
+
if (direct) {
|
|
25
|
+
return direct;
|
|
26
|
+
}
|
|
27
|
+
const lowered = groupId.toLowerCase();
|
|
28
|
+
const matchKey = Object.keys(groups).find((key) => key.toLowerCase() === lowered);
|
|
29
|
+
if (matchKey) {
|
|
30
|
+
return groups[matchKey];
|
|
31
|
+
}
|
|
32
|
+
return wildcard;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 检查群组是否在允许列表中
|
|
36
|
+
*/
|
|
37
|
+
function isWeComGroupAllowed(params) {
|
|
38
|
+
const { groupPolicy } = params;
|
|
39
|
+
if (groupPolicy === "disabled") {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
if (groupPolicy === "open") {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
// allowlist 模式:检查群组是否在允许列表中
|
|
46
|
+
const normalizedAllowFrom = params.allowFrom.map((entry) => String(entry).replace(new RegExp(`^${_const.CHANNEL_ID}:`, "i"), "").trim());
|
|
47
|
+
if (normalizedAllowFrom.includes("*")) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
const normalizedGroupId = params.groupId.trim();
|
|
51
|
+
return normalizedAllowFrom.some((entry) => entry === normalizedGroupId || entry.toLowerCase() === normalizedGroupId.toLowerCase());
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 检查群组内发送者是否在允许列表中
|
|
55
|
+
*/
|
|
56
|
+
function isGroupSenderAllowed(params) {
|
|
57
|
+
const { senderId, groupId, wecomConfig } = params;
|
|
58
|
+
const groupConfig = resolveWeComGroupConfig({
|
|
59
|
+
cfg: wecomConfig,
|
|
60
|
+
groupId,
|
|
61
|
+
});
|
|
62
|
+
const perGroupSenderAllowFrom = (groupConfig?.allowFrom ?? []).map((v) => String(v));
|
|
63
|
+
if (perGroupSenderAllowFrom.length === 0) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
if (perGroupSenderAllowFrom.includes("*")) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
return perGroupSenderAllowFrom.some((entry) => {
|
|
70
|
+
const normalized = entry.replace(new RegExp(`^${_const.CHANNEL_ID}:`, "i"), "").trim();
|
|
71
|
+
return normalized === senderId || normalized === `user:${senderId}`;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
// ============================================================================
|
|
75
|
+
// 公开 API
|
|
76
|
+
// ============================================================================
|
|
77
|
+
/**
|
|
78
|
+
* 检查群组策略访问控制
|
|
79
|
+
* @returns 检查结果,包含是否允许继续处理
|
|
80
|
+
*/
|
|
81
|
+
function checkGroupPolicy(params) {
|
|
82
|
+
const { chatId, senderId, account, config, runtime } = params;
|
|
83
|
+
const wecomConfig = (config.channels?.[_const.CHANNEL_ID] ?? {});
|
|
84
|
+
const defaultGroupPolicy = config.channels?.[_const.CHANNEL_ID]?.groupPolicy;
|
|
85
|
+
const groupPolicy = account.config.groupPolicy ?? defaultGroupPolicy ?? "open";
|
|
86
|
+
// const { groupPolicy, providerMissingFallbackApplied } = resolveOpenProviderRuntimeGroupPolicy({
|
|
87
|
+
// providerConfigPresent: config.channels?.[CHANNEL_ID] !== undefined,
|
|
88
|
+
// groupPolicy: wecomConfig.groupPolicy,
|
|
89
|
+
// defaultGroupPolicy,
|
|
90
|
+
// });
|
|
91
|
+
// warnMissingProviderGroupPolicyFallbackOnce({
|
|
92
|
+
// providerMissingFallbackApplied,
|
|
93
|
+
// providerKey: CHANNEL_ID,
|
|
94
|
+
// accountId: account.accountId,
|
|
95
|
+
// log: (msg) => runtime.log?.(msg),
|
|
96
|
+
// });
|
|
97
|
+
const groupAllowFrom = wecomConfig.groupAllowFrom ?? [];
|
|
98
|
+
const groupAllowed = isWeComGroupAllowed({
|
|
99
|
+
groupPolicy,
|
|
100
|
+
allowFrom: groupAllowFrom,
|
|
101
|
+
groupId: chatId,
|
|
102
|
+
});
|
|
103
|
+
if (!groupAllowed) {
|
|
104
|
+
runtime.log?.(`[WeCom] Group ${chatId} not allowed (groupPolicy=${groupPolicy})`);
|
|
105
|
+
return { allowed: false };
|
|
106
|
+
}
|
|
107
|
+
const senderAllowed = isGroupSenderAllowed({
|
|
108
|
+
senderId,
|
|
109
|
+
groupId: chatId,
|
|
110
|
+
wecomConfig,
|
|
111
|
+
});
|
|
112
|
+
if (!senderAllowed) {
|
|
113
|
+
runtime.log?.(`[WeCom] Sender ${senderId} not in group ${chatId} sender allowlist`);
|
|
114
|
+
return { allowed: false };
|
|
115
|
+
}
|
|
116
|
+
return { allowed: true };
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 检查发送者是否在允许列表中(通用)
|
|
120
|
+
*/
|
|
121
|
+
function isSenderAllowed(senderId, allowFrom) {
|
|
122
|
+
if (allowFrom.includes("*")) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
return allowFrom.some((entry) => {
|
|
126
|
+
const normalized = entry.replace(new RegExp(`^${_const.CHANNEL_ID}:`, "i"), "").trim();
|
|
127
|
+
return normalized === senderId || normalized === `user:${senderId}`;
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
exports.checkGroupPolicy = checkGroupPolicy;
|
|
132
|
+
exports.isSenderAllowed = isSenderAllowed;
|
|
133
|
+
//# sourceMappingURL=group-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group-policy.js","sources":["../../../../../src/group-policy.ts"],"sourcesContent":["/**\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"],"names":["CHANNEL_ID"],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var transport = require('../transport.js');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 业务错误码检查拦截器
|
|
7
|
+
*
|
|
8
|
+
* 检查 tools/call 返回结果中是否包含需要清理缓存的业务错误码。
|
|
9
|
+
* MCP Server 可能在正常的 JSON-RPC 响应中返回业务层错误,
|
|
10
|
+
* 这些错误被包裹在 result.content[].text 中,需要解析后判断。
|
|
11
|
+
*
|
|
12
|
+
* 此拦截器对所有 call 调用生效。
|
|
13
|
+
*/
|
|
14
|
+
// ============================================================================
|
|
15
|
+
// 常量
|
|
16
|
+
// ============================================================================
|
|
17
|
+
/**
|
|
18
|
+
* 需要触发缓存清理的业务错误码集合
|
|
19
|
+
*
|
|
20
|
+
* 这些错误码出现在 MCP 工具调用返回的 content 文本中(业务层面),
|
|
21
|
+
* 与 JSON-RPC 层面的错误码不同,需要在此处额外检测。
|
|
22
|
+
*
|
|
23
|
+
* - 850002: 机器人未被授权使用对应能力,需清理缓存以便下次重新拉取配置
|
|
24
|
+
*/
|
|
25
|
+
const BIZ_CACHE_CLEAR_ERROR_CODES = new Set([850002]);
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// 拦截器实现
|
|
28
|
+
// ============================================================================
|
|
29
|
+
const bizErrorInterceptor = {
|
|
30
|
+
name: "biz-error",
|
|
31
|
+
/** 对所有 call 调用生效 */
|
|
32
|
+
match: () => true,
|
|
33
|
+
/** 检查返回结果中的业务错误码,必要时清理缓存 */
|
|
34
|
+
afterCall(ctx, result) {
|
|
35
|
+
checkBizErrorAndClearCache(result, ctx.category);
|
|
36
|
+
// 不修改 result,透传给下一个拦截器
|
|
37
|
+
return result;
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// 内部实现
|
|
42
|
+
// ============================================================================
|
|
43
|
+
/**
|
|
44
|
+
* 检查 tools/call 的返回结果中是否包含需要清理缓存的业务错误码
|
|
45
|
+
*/
|
|
46
|
+
function checkBizErrorAndClearCache(result, category) {
|
|
47
|
+
if (!result || typeof result !== "object")
|
|
48
|
+
return;
|
|
49
|
+
const { content } = result;
|
|
50
|
+
if (!Array.isArray(content))
|
|
51
|
+
return;
|
|
52
|
+
for (const item of content) {
|
|
53
|
+
if (item.type !== "text" || !item.text)
|
|
54
|
+
continue;
|
|
55
|
+
try {
|
|
56
|
+
const parsed = JSON.parse(item.text);
|
|
57
|
+
if (typeof parsed.errcode === "number" && BIZ_CACHE_CLEAR_ERROR_CODES.has(parsed.errcode)) {
|
|
58
|
+
console.log(`[mcp] 检测到业务错误码 ${parsed.errcode} (category="${category}"),清理缓存`);
|
|
59
|
+
transport.clearCategoryCache(category);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// text 不是 JSON 格式,跳过
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
exports.bizErrorInterceptor = bizErrorInterceptor;
|
|
70
|
+
//# sourceMappingURL=biz-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"biz-error.js","sources":["../../../../../../../src/mcp/interceptors/biz-error.ts"],"sourcesContent":["/**\n * 业务错误码检查拦截器\n *\n * 检查 tools/call 返回结果中是否包含需要清理缓存的业务错误码。\n * MCP Server 可能在正常的 JSON-RPC 响应中返回业务层错误,\n * 这些错误被包裹在 result.content[].text 中,需要解析后判断。\n *\n * 此拦截器对所有 call 调用生效。\n */\n\nimport { clearCategoryCache } from \"../transport.js\";\nimport type { CallInterceptor, CallContext } from \"./types.js\";\n\n// ============================================================================\n// 常量\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// 拦截器实现\n// ============================================================================\n\nexport const bizErrorInterceptor: CallInterceptor = {\n name: \"biz-error\",\n\n /** 对所有 call 调用生效 */\n match: () => true,\n\n /** 检查返回结果中的业务错误码,必要时清理缓存 */\n afterCall(ctx: CallContext, result: unknown): unknown {\n checkBizErrorAndClearCache(result, ctx.category);\n // 不修改 result,透传给下一个拦截器\n return result;\n },\n};\n\n// ============================================================================\n// 内部实现\n// ============================================================================\n\n/**\n * 检查 tools/call 的返回结果中是否包含需要清理缓存的业务错误码\n */\nfunction 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"],"names":["clearCategoryCache"],"mappings":";;;;AAAA;;;;;;;;AAQG;AAKH;AACA;AACA;AAEA;;;;;;;AAOG;AACH,MAAM,2BAA2B,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD;AACA;AACA;AAEO,MAAM,mBAAmB,GAAoB;AAClD,IAAA,IAAI,EAAE,WAAW;;AAGjB,IAAA,KAAK,EAAE,MAAM,IAAI;;IAGjB,SAAS,CAAC,GAAgB,EAAE,MAAe,EAAA;AACzC,QAAA,0BAA0B,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC;;AAEhD,QAAA,OAAO,MAAM;IACf,CAAC;;AAGH;AACA;AACA;AAEA;;AAEG;AACH,SAAS,0BAA0B,CAAC,MAAe,EAAE,QAAgB,EAAA;AACnE,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;gBAC7EA,4BAAkB,CAAC,QAAQ,CAAC;gBAC5B;YACF;QACF;AAAE,QAAA,MAAM;;QAER;IACF;AACF;;;;"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var bizError = require('./biz-error.js');
|
|
4
|
+
var msgMedia = require('./msg-media.js');
|
|
5
|
+
var smartpageCreate = require('./smartpage-create.js');
|
|
6
|
+
var smartpageExport = require('./smartpage-export.js');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* MCP call 拦截器注册表与调度入口
|
|
10
|
+
*
|
|
11
|
+
* 所有 call 拦截器在此注册,按注册顺序执行。
|
|
12
|
+
* 新增拦截器只需:
|
|
13
|
+
* 1. 在 interceptors/ 目录下新建文件,实现 CallInterceptor 接口
|
|
14
|
+
* 2. 在下方 interceptors 数组中注册
|
|
15
|
+
*
|
|
16
|
+
* tool.ts 的 handleCall 无需任何改动。
|
|
17
|
+
*/
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// 拦截器注册表(按注册顺序执行)
|
|
20
|
+
// ============================================================================
|
|
21
|
+
const interceptors = [
|
|
22
|
+
bizError.bizErrorInterceptor, // 业务错误码检查(所有 call 生效)
|
|
23
|
+
msgMedia.mediaInterceptor, // get_msg_media base64 拦截
|
|
24
|
+
smartpageCreate.smartpageCreateInterceptor, // smartpage_create 本地文件读取
|
|
25
|
+
smartpageExport.smartpageExportInterceptor, // smartpage_get_export_result content → 本地文件
|
|
26
|
+
];
|
|
27
|
+
/**
|
|
28
|
+
* 收集匹配的 beforeCall 配置,合并后返回
|
|
29
|
+
*
|
|
30
|
+
* 合并策略:
|
|
31
|
+
* - timeoutMs: 取所有拦截器返回值中的最大值
|
|
32
|
+
* - args: 后注册的拦截器覆盖前者(一般同一调用只有一个拦截器会返回 args)
|
|
33
|
+
*/
|
|
34
|
+
async function resolveBeforeCall(ctx) {
|
|
35
|
+
let mergedTimeoutMs;
|
|
36
|
+
let mergedArgs;
|
|
37
|
+
for (const interceptor of interceptors) {
|
|
38
|
+
if (!interceptor.match(ctx) || !interceptor.beforeCall)
|
|
39
|
+
continue;
|
|
40
|
+
const opts = await interceptor.beforeCall(ctx);
|
|
41
|
+
if (opts?.timeoutMs !== undefined) {
|
|
42
|
+
mergedTimeoutMs = mergedTimeoutMs === undefined
|
|
43
|
+
? opts.timeoutMs
|
|
44
|
+
: Math.max(mergedTimeoutMs, opts.timeoutMs);
|
|
45
|
+
}
|
|
46
|
+
if (opts?.args !== undefined) {
|
|
47
|
+
mergedArgs = opts.args;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
options: mergedTimeoutMs !== undefined ? { timeoutMs: mergedTimeoutMs } : undefined,
|
|
52
|
+
args: mergedArgs,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 依次执行匹配的 afterCall 拦截器,管道式传递 result
|
|
57
|
+
*
|
|
58
|
+
* 前一个拦截器的返回值作为下一个拦截器的输入。
|
|
59
|
+
* 拦截器若不需要修改 result,应原样返回。
|
|
60
|
+
*/
|
|
61
|
+
async function runAfterCall(ctx, result) {
|
|
62
|
+
let current = result;
|
|
63
|
+
for (const interceptor of interceptors) {
|
|
64
|
+
if (!interceptor.match(ctx) || !interceptor.afterCall)
|
|
65
|
+
continue;
|
|
66
|
+
current = await interceptor.afterCall(ctx, current);
|
|
67
|
+
}
|
|
68
|
+
return current;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
exports.resolveBeforeCall = resolveBeforeCall;
|
|
72
|
+
exports.runAfterCall = runAfterCall;
|
|
73
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../../../../src/mcp/interceptors/index.ts"],"sourcesContent":["/**\n * MCP call 拦截器注册表与调度入口\n *\n * 所有 call 拦截器在此注册,按注册顺序执行。\n * 新增拦截器只需:\n * 1. 在 interceptors/ 目录下新建文件,实现 CallInterceptor 接口\n * 2. 在下方 interceptors 数组中注册\n *\n * tool.ts 的 handleCall 无需任何改动。\n */\n\nimport { bizErrorInterceptor } from \"./biz-error.js\";\nimport { mediaInterceptor } from \"./msg-media.js\";\nimport { smartpageCreateInterceptor } from \"./smartpage-create.js\";\nimport { smartpageExportInterceptor } from \"./smartpage-export.js\";\nimport type { CallContext, CallInterceptor, BeforeCallOptions } from \"./types.js\";\nimport type { SendJsonRpcOptions } from \"../transport.js\";\n\nexport type { CallContext, CallInterceptor, BeforeCallOptions } from \"./types.js\";\n\n// ============================================================================\n// 拦截器注册表(按注册顺序执行)\n// ============================================================================\n\nconst interceptors: CallInterceptor[] = [\n bizErrorInterceptor, // 业务错误码检查(所有 call 生效)\n mediaInterceptor, // get_msg_media base64 拦截\n smartpageCreateInterceptor, // smartpage_create 本地文件读取\n smartpageExportInterceptor, // smartpage_get_export_result content → 本地文件\n];\n\n// ============================================================================\n// 调度 API\n// ============================================================================\n\n/** resolveBeforeCall 的返回值 */\nexport interface ResolvedBeforeCall {\n /** 合并后的 sendJsonRpc 选项(如超时时间) */\n options?: SendJsonRpcOptions;\n /** 替换后的 args(如从本地文件读取的请求体) */\n args?: Record<string, unknown>;\n}\n\n/**\n * 收集匹配的 beforeCall 配置,合并后返回\n *\n * 合并策略:\n * - timeoutMs: 取所有拦截器返回值中的最大值\n * - args: 后注册的拦截器覆盖前者(一般同一调用只有一个拦截器会返回 args)\n */\nexport async function resolveBeforeCall(ctx: CallContext): Promise<ResolvedBeforeCall> {\n let mergedTimeoutMs: number | undefined;\n let mergedArgs: Record<string, unknown> | undefined;\n\n for (const interceptor of interceptors) {\n if (!interceptor.match(ctx) || !interceptor.beforeCall) continue;\n\n const opts = await interceptor.beforeCall(ctx);\n if (opts?.timeoutMs !== undefined) {\n mergedTimeoutMs = mergedTimeoutMs === undefined\n ? opts.timeoutMs\n : Math.max(mergedTimeoutMs, opts.timeoutMs);\n }\n if (opts?.args !== undefined) {\n mergedArgs = opts.args;\n }\n }\n\n return {\n options: mergedTimeoutMs !== undefined ? { timeoutMs: mergedTimeoutMs } : undefined,\n args: mergedArgs,\n };\n}\n\n/**\n * 依次执行匹配的 afterCall 拦截器,管道式传递 result\n *\n * 前一个拦截器的返回值作为下一个拦截器的输入。\n * 拦截器若不需要修改 result,应原样返回。\n */\nexport async function runAfterCall(ctx: CallContext, result: unknown): Promise<unknown> {\n let current = result;\n\n for (const interceptor of interceptors) {\n if (!interceptor.match(ctx) || !interceptor.afterCall) continue;\n current = await interceptor.afterCall(ctx, current);\n }\n\n return current;\n}\n"],"names":["bizErrorInterceptor","mediaInterceptor","smartpageCreateInterceptor","smartpageExportInterceptor"],"mappings":";;;;;;;AAAA;;;;;;;;;AASG;AAWH;AACA;AACA;AAEA,MAAM,YAAY,GAAsB;AACtC,IAAAA,4BAAmB;AACnB,IAAAC,yBAAgB;AAChB,IAAAC,0CAA0B;AAC1B,IAAAC,0CAA0B;CAC3B;AAcD;;;;;;AAMG;AACI,eAAe,iBAAiB,CAAC,GAAgB,EAAA;AACtD,IAAA,IAAI,eAAmC;AACvC,IAAA,IAAI,UAA+C;AAEnD,IAAA,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE;QACtC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU;YAAE;QAExD,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC;AAC9C,QAAA,IAAI,IAAI,EAAE,SAAS,KAAK,SAAS,EAAE;YACjC,eAAe,GAAG,eAAe,KAAK;kBAClC,IAAI,CAAC;kBACL,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,SAAS,CAAC;QAC/C;AACA,QAAA,IAAI,IAAI,EAAE,IAAI,KAAK,SAAS,EAAE;AAC5B,YAAA,UAAU,GAAG,IAAI,CAAC,IAAI;QACxB;IACF;IAEA,OAAO;AACL,QAAA,OAAO,EAAE,eAAe,KAAK,SAAS,GAAG,EAAE,SAAS,EAAE,eAAe,EAAE,GAAG,SAAS;AACnF,QAAA,IAAI,EAAE,UAAU;KACjB;AACH;AAEA;;;;;AAKG;AACI,eAAe,YAAY,CAAC,GAAgB,EAAE,MAAe,EAAA;IAClE,IAAI,OAAO,GAAG,MAAM;AAEpB,IAAA,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE;QACtC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS;YAAE;QACvD,OAAO,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC;IACrD;AAEA,IAAA,OAAO,OAAO;AAChB;;;;;"}
|