@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.
Files changed (209) hide show
  1. package/README.md +4 -251
  2. package/dist/cjs/index.js +45 -0
  3. package/dist/cjs/index.js.map +1 -0
  4. package/dist/cjs/src/channel.js +339 -0
  5. package/dist/cjs/src/channel.js.map +1 -0
  6. package/dist/cjs/src/const.js +137 -0
  7. package/dist/cjs/src/const.js.map +1 -0
  8. package/dist/cjs/src/dm-policy.js +89 -0
  9. package/dist/cjs/src/dm-policy.js.map +1 -0
  10. package/dist/cjs/src/group-policy.js +133 -0
  11. package/dist/cjs/src/group-policy.js.map +1 -0
  12. package/dist/cjs/src/mcp/interceptors/biz-error.js +70 -0
  13. package/dist/cjs/src/mcp/interceptors/biz-error.js.map +1 -0
  14. package/dist/cjs/src/mcp/interceptors/index.js +73 -0
  15. package/dist/cjs/src/mcp/interceptors/index.js.map +1 -0
  16. package/dist/cjs/src/mcp/interceptors/msg-media.js +159 -0
  17. package/dist/cjs/src/mcp/interceptors/msg-media.js.map +1 -0
  18. package/dist/cjs/src/mcp/interceptors/smartpage-create.js +157 -0
  19. package/dist/cjs/src/mcp/interceptors/smartpage-create.js.map +1 -0
  20. package/dist/cjs/src/mcp/interceptors/smartpage-export.js +93 -0
  21. package/dist/cjs/src/mcp/interceptors/smartpage-export.js.map +1 -0
  22. package/dist/cjs/src/mcp/schema.js +104 -0
  23. package/dist/cjs/src/mcp/schema.js.map +1 -0
  24. package/dist/cjs/src/mcp/tool.js +208 -0
  25. package/dist/cjs/src/mcp/tool.js.map +1 -0
  26. package/dist/cjs/src/mcp/transport.js +417 -0
  27. package/dist/cjs/src/mcp/transport.js.map +1 -0
  28. package/dist/cjs/src/media-handler.js +129 -0
  29. package/dist/cjs/src/media-handler.js.map +1 -0
  30. package/dist/cjs/src/media-uploader.js +284 -0
  31. package/dist/cjs/src/media-uploader.js.map +1 -0
  32. package/dist/cjs/src/message-parser.js +134 -0
  33. package/dist/cjs/src/message-parser.js.map +1 -0
  34. package/dist/cjs/src/message-sender.js +89 -0
  35. package/dist/cjs/src/message-sender.js.map +1 -0
  36. package/dist/cjs/src/monitor.js +991 -0
  37. package/dist/cjs/src/monitor.js.map +1 -0
  38. package/dist/cjs/src/onboarding.js +182 -0
  39. package/dist/cjs/src/onboarding.js.map +1 -0
  40. package/dist/cjs/src/openclaw-compat.js +400 -0
  41. package/dist/cjs/src/openclaw-compat.js.map +1 -0
  42. package/dist/cjs/src/reqid-store.js +88 -0
  43. package/dist/cjs/src/reqid-store.js.map +1 -0
  44. package/dist/cjs/src/runtime.js +16 -0
  45. package/dist/cjs/src/runtime.js.map +1 -0
  46. package/dist/cjs/src/state-dir-resolve.js +35 -0
  47. package/dist/cjs/src/state-dir-resolve.js.map +1 -0
  48. package/dist/cjs/src/state-manager.js +158 -0
  49. package/dist/cjs/src/state-manager.js.map +1 -0
  50. package/dist/cjs/src/template-card-parser.js +641 -0
  51. package/dist/cjs/src/template-card-parser.js.map +1 -0
  52. package/dist/cjs/src/timeout.js +42 -0
  53. package/dist/cjs/src/timeout.js.map +1 -0
  54. package/dist/cjs/src/utils.js +60 -0
  55. package/dist/cjs/src/utils.js.map +1 -0
  56. package/dist/cjs/src/version.js +26 -0
  57. package/dist/cjs/src/version.js.map +1 -0
  58. package/dist/esm/index.js +41 -0
  59. package/dist/esm/index.js.map +1 -0
  60. package/dist/esm/src/channel.js +337 -0
  61. package/dist/esm/src/channel.js.map +1 -0
  62. package/dist/{src → esm/src}/const.js +30 -77
  63. package/dist/esm/src/const.js.map +1 -0
  64. package/dist/{src → esm/src}/dm-policy.js +9 -6
  65. package/dist/esm/src/dm-policy.js.map +1 -0
  66. package/dist/{src → esm/src}/group-policy.js +7 -3
  67. package/dist/esm/src/group-policy.js.map +1 -0
  68. package/dist/{src → esm/src}/mcp/interceptors/biz-error.js +6 -2
  69. package/dist/esm/src/mcp/interceptors/biz-error.js.map +1 -0
  70. package/dist/{src → esm/src}/mcp/interceptors/index.js +10 -6
  71. package/dist/esm/src/mcp/interceptors/index.js.map +1 -0
  72. package/dist/{src → esm/src}/mcp/interceptors/msg-media.js +10 -6
  73. package/dist/esm/src/mcp/interceptors/msg-media.js.map +1 -0
  74. package/dist/{src → esm/src}/mcp/interceptors/smartpage-create.js +6 -2
  75. package/dist/esm/src/mcp/interceptors/smartpage-create.js.map +1 -0
  76. package/dist/{src → esm/src}/mcp/interceptors/smartpage-export.js +6 -2
  77. package/dist/esm/src/mcp/interceptors/smartpage-export.js.map +1 -0
  78. package/dist/{src → esm/src}/mcp/schema.js +4 -1
  79. package/dist/esm/src/mcp/schema.js.map +1 -0
  80. package/dist/{src → esm/src}/mcp/tool.js +8 -4
  81. package/dist/esm/src/mcp/tool.js.map +1 -0
  82. package/dist/{src → esm/src}/mcp/transport.js +16 -15
  83. package/dist/esm/src/mcp/transport.js.map +1 -0
  84. package/dist/{src → esm/src}/media-handler.js +10 -6
  85. package/dist/esm/src/media-handler.js.map +1 -0
  86. package/dist/{src → esm/src}/media-uploader.js +10 -64
  87. package/dist/esm/src/media-uploader.js.map +1 -0
  88. package/dist/{src → esm/src}/message-parser.js +4 -1
  89. package/dist/esm/src/message-parser.js.map +1 -0
  90. package/dist/{src → esm/src}/message-sender.js +11 -46
  91. package/dist/esm/src/message-sender.js.map +1 -0
  92. package/dist/{src → esm/src}/monitor.js +282 -151
  93. package/dist/esm/src/monitor.js.map +1 -0
  94. package/dist/{src → esm/src}/onboarding.js +26 -22
  95. package/dist/esm/src/onboarding.js.map +1 -0
  96. package/dist/{src → esm/src}/openclaw-compat.js +27 -143
  97. package/dist/esm/src/openclaw-compat.js.map +1 -0
  98. package/dist/{src → esm/src}/reqid-store.js +7 -4
  99. package/dist/esm/src/reqid-store.js.map +1 -0
  100. package/dist/{src → esm/src}/runtime.js +5 -2
  101. package/dist/esm/src/runtime.js.map +1 -0
  102. package/dist/esm/src/state-dir-resolve.js +13 -0
  103. package/dist/esm/src/state-dir-resolve.js.map +1 -0
  104. package/dist/{src → esm/src}/state-manager.js +16 -84
  105. package/dist/esm/src/state-manager.js.map +1 -0
  106. package/dist/{src → esm/src}/template-card-parser.js +8 -17
  107. package/dist/esm/src/template-card-parser.js.map +1 -0
  108. package/dist/{src → esm/src}/timeout.js +5 -2
  109. package/dist/esm/src/timeout.js.map +1 -0
  110. package/dist/{src → esm/src}/utils.js +10 -24
  111. package/dist/esm/src/utils.js.map +1 -0
  112. package/dist/esm/src/version.js +23 -0
  113. package/dist/esm/src/version.js.map +1 -0
  114. package/dist/esm/types/index.d.ts +9 -0
  115. package/dist/{src → esm/types/src}/const.d.ts +0 -46
  116. package/dist/{src → esm/types/src}/interface.d.ts +2 -0
  117. package/dist/{src → esm/types/src}/message-sender.d.ts +0 -18
  118. package/dist/{src → esm/types/src}/openclaw-compat.d.ts +0 -49
  119. package/dist/esm/types/src/state-dir-resolve.d.ts +2 -0
  120. package/dist/{src → esm/types/src}/utils.d.ts +0 -39
  121. package/dist/esm/types/src/version.d.ts +2 -0
  122. package/dist/index.d.ts +4 -2
  123. package/package.json +7 -15
  124. package/dist/index.js +0 -113
  125. package/dist/src/accounts.d.ts +0 -57
  126. package/dist/src/accounts.js +0 -222
  127. package/dist/src/agent/api-client.d.ts +0 -94
  128. package/dist/src/agent/api-client.js +0 -292
  129. package/dist/src/agent/handler.d.ts +0 -63
  130. package/dist/src/agent/handler.js +0 -532
  131. package/dist/src/agent/index.d.ts +0 -5
  132. package/dist/src/agent/index.js +0 -5
  133. package/dist/src/agent/webhook.d.ts +0 -23
  134. package/dist/src/agent/webhook.js +0 -226
  135. package/dist/src/agent/xml.d.ts +0 -21
  136. package/dist/src/agent/xml.js +0 -41
  137. package/dist/src/channel.js +0 -564
  138. package/dist/src/chat-queue.d.ts +0 -31
  139. package/dist/src/chat-queue.js +0 -45
  140. package/dist/src/http.d.ts +0 -26
  141. package/dist/src/http.js +0 -93
  142. package/dist/src/interface.js +0 -4
  143. package/dist/src/mcp/index.js +0 -6
  144. package/dist/src/mcp/interceptors/types.js +0 -7
  145. package/dist/src/shared/command-auth.d.ts +0 -23
  146. package/dist/src/shared/command-auth.js +0 -73
  147. package/dist/src/shared/xml-parser.d.ts +0 -46
  148. package/dist/src/shared/xml-parser.js +0 -210
  149. package/dist/src/target.d.ts +0 -35
  150. package/dist/src/target.js +0 -67
  151. package/dist/src/template-card-manager.d.ts +0 -55
  152. package/dist/src/template-card-manager.js +0 -205
  153. package/dist/src/types/account.d.ts +0 -29
  154. package/dist/src/types/account.js +0 -4
  155. package/dist/src/types/config.d.ts +0 -80
  156. package/dist/src/types/config.js +0 -7
  157. package/dist/src/types/constants.d.ts +0 -42
  158. package/dist/src/types/constants.js +0 -42
  159. package/dist/src/types/index.d.ts +0 -7
  160. package/dist/src/types/index.js +0 -5
  161. package/dist/src/types/message.d.ts +0 -238
  162. package/dist/src/types/message.js +0 -5
  163. package/dist/src/version.d.ts +0 -2
  164. package/dist/src/version.js +0 -24
  165. package/dist/src/webhook/command-auth.d.ts +0 -47
  166. package/dist/src/webhook/command-auth.js +0 -96
  167. package/dist/src/webhook/gateway.d.ts +0 -36
  168. package/dist/src/webhook/gateway.js +0 -227
  169. package/dist/src/webhook/handler.d.ts +0 -18
  170. package/dist/src/webhook/handler.js +0 -420
  171. package/dist/src/webhook/helpers.d.ts +0 -156
  172. package/dist/src/webhook/helpers.js +0 -833
  173. package/dist/src/webhook/http.d.ts +0 -26
  174. package/dist/src/webhook/http.js +0 -94
  175. package/dist/src/webhook/index.d.ts +0 -11
  176. package/dist/src/webhook/index.js +0 -14
  177. package/dist/src/webhook/media.d.ts +0 -29
  178. package/dist/src/webhook/media.js +0 -88
  179. package/dist/src/webhook/monitor.d.ts +0 -59
  180. package/dist/src/webhook/monitor.js +0 -1147
  181. package/dist/src/webhook/state.d.ts +0 -220
  182. package/dist/src/webhook/state.js +0 -491
  183. package/dist/src/webhook/target.d.ts +0 -41
  184. package/dist/src/webhook/target.js +0 -132
  185. package/dist/src/webhook/types.d.ts +0 -347
  186. package/dist/src/webhook/types.js +0 -33
  187. /package/dist/{src → esm/types/src}/channel.d.ts +0 -0
  188. /package/dist/{src → esm/types/src}/dm-policy.d.ts +0 -0
  189. /package/dist/{src → esm/types/src}/group-policy.d.ts +0 -0
  190. /package/dist/{src → esm/types/src}/mcp/index.d.ts +0 -0
  191. /package/dist/{src → esm/types/src}/mcp/interceptors/biz-error.d.ts +0 -0
  192. /package/dist/{src → esm/types/src}/mcp/interceptors/index.d.ts +0 -0
  193. /package/dist/{src → esm/types/src}/mcp/interceptors/msg-media.d.ts +0 -0
  194. /package/dist/{src → esm/types/src}/mcp/interceptors/smartpage-create.d.ts +0 -0
  195. /package/dist/{src → esm/types/src}/mcp/interceptors/smartpage-export.d.ts +0 -0
  196. /package/dist/{src → esm/types/src}/mcp/interceptors/types.d.ts +0 -0
  197. /package/dist/{src → esm/types/src}/mcp/schema.d.ts +0 -0
  198. /package/dist/{src → esm/types/src}/mcp/tool.d.ts +0 -0
  199. /package/dist/{src → esm/types/src}/mcp/transport.d.ts +0 -0
  200. /package/dist/{src → esm/types/src}/media-handler.d.ts +0 -0
  201. /package/dist/{src → esm/types/src}/media-uploader.d.ts +0 -0
  202. /package/dist/{src → esm/types/src}/message-parser.d.ts +0 -0
  203. /package/dist/{src → esm/types/src}/monitor.d.ts +0 -0
  204. /package/dist/{src → esm/types/src}/onboarding.d.ts +0 -0
  205. /package/dist/{src → esm/types/src}/reqid-store.d.ts +0 -0
  206. /package/dist/{src → esm/types/src}/runtime.d.ts +0 -0
  207. /package/dist/{src → esm/types/src}/state-manager.d.ts +0 -0
  208. /package/dist/{src → esm/types/src}/template-card-parser.d.ts +0 -0
  209. /package/dist/{src → esm/types/src}/timeout.d.ts +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"monitor.js","sources":["../../../../../src/monitor.ts"],"sourcesContent":["/**\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"],"names":["path","os","getDefaultMediaLocalRoots","getWeComRuntime","CHANNEL_ID","MEDIA_IMAGE_PLACEHOLDER","MEDIA_DOCUMENT_PLACEHOLDER","sendWeComReply","THINKING_MESSAGE","StreamExpiredError","uploadAndSendMedia","extractTemplateCards","runtime","maskTemplateCardBlocks","parseMessageContent","checkGroupPolicy","checkDmPolicy","downloadAndSaveImages","downloadAndSaveFiles","setReqIdForChat","generateReqId","setMessageState","deleteMessageState","PLUGIN_VERSION","startMessageStateCleanup","WSClient","WS_HEARTBEAT_INTERVAL_MS","WS_MAX_RECONNECT_ATTEMPTS","WS_MAX_AUTH_FAILURE_ATTEMPTS","SCENE_WECOM_OPENCLAW","stopMessageStateCleanup","cleanupAccount","setWeComWebSocket","WSAuthFailureError","WSReconnectExhaustedError","EVENT_ENTER_CHECK_UPDATE","CMD_ENTER_EVENT_REPLY","warmupReqIdStore"],"mappings":"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"}
@@ -0,0 +1,182 @@
1
+ 'use strict';
2
+
3
+ var openclawCompat = require('./openclaw-compat.js');
4
+ var utils = require('./utils.js');
5
+ var _const = require('./const.js');
6
+
7
+ /**
8
+ * 企业微信 setupWizard — 声明式 CLI setup wizard 配置。
9
+ *
10
+ * 框架通过 plugin.setupWizard 字段识别并驱动 channel 的引导配置流程。
11
+ */
12
+ // ============================================================================
13
+ // ChannelSetupAdapter — 框架用于应用配置输入的适配器
14
+ // ============================================================================
15
+ const wecomSetupAdapter = {
16
+ applyAccountConfig: ({ cfg, input }) => {
17
+ const patch = {};
18
+ if (input.token !== undefined) {
19
+ patch.botId = String(input.token).trim();
20
+ }
21
+ if (input.privateKey !== undefined) {
22
+ patch.secret = String(input.privateKey).trim();
23
+ }
24
+ // 如果是首次配置,默认启用
25
+ const account = utils.resolveWeComAccount(cfg);
26
+ if (!account.botId && !account.secret) {
27
+ patch.enabled = true;
28
+ }
29
+ return utils.setWeComAccount(cfg, patch);
30
+ },
31
+ };
32
+ // ============================================================================
33
+ // DM Policy 配置
34
+ // ============================================================================
35
+ /**
36
+ * 设置企业微信 dmPolicy
37
+ */
38
+ function setWeComDmPolicy(cfg, dmPolicy) {
39
+ const account = utils.resolveWeComAccount(cfg);
40
+ const existingAllowFrom = account.config.allowFrom ?? [];
41
+ const allowFrom = dmPolicy === "open"
42
+ ? openclawCompat.addWildcardAllowFrom(existingAllowFrom.map((x) => String(x)))
43
+ : existingAllowFrom.map((x) => String(x));
44
+ return utils.setWeComAccount(cfg, {
45
+ dmPolicy,
46
+ allowFrom,
47
+ });
48
+ }
49
+ const dmPolicy = {
50
+ label: "企业微信",
51
+ channel: _const.CHANNEL_ID,
52
+ policyKey: `channels.${_const.CHANNEL_ID}.dmPolicy`,
53
+ allowFromKey: `channels.${_const.CHANNEL_ID}.allowFrom`,
54
+ getCurrent: (cfg) => {
55
+ const account = utils.resolveWeComAccount(cfg);
56
+ return account.config.dmPolicy ?? "open";
57
+ },
58
+ setPolicy: (cfg, policy) => {
59
+ return setWeComDmPolicy(cfg, policy);
60
+ },
61
+ promptAllowFrom: async ({ cfg, prompter }) => {
62
+ const account = utils.resolveWeComAccount(cfg);
63
+ const existingAllowFrom = account.config.allowFrom ?? [];
64
+ const entry = await prompter.text({
65
+ message: "企业微信允许来源(用户ID或群组ID,逗号分隔)",
66
+ placeholder: "user123, group456",
67
+ initialValue: existingAllowFrom[0] ? String(existingAllowFrom[0]) : undefined,
68
+ });
69
+ const allowFrom = String(entry ?? "")
70
+ .split(/[\n,;]+/g)
71
+ .map((s) => s.trim())
72
+ .filter(Boolean);
73
+ return utils.setWeComAccount(cfg, { allowFrom });
74
+ },
75
+ };
76
+ // ============================================================================
77
+ // ChannelSetupWizard — 声明式 setup wizard 配置
78
+ // ============================================================================
79
+ const wecomSetupWizard = {
80
+ channel: _const.CHANNEL_ID,
81
+ // ── 状态 ──────────────────────────────────────────────────────────────
82
+ status: {
83
+ configuredLabel: "已配置 ✓",
84
+ unconfiguredLabel: "需要 Bot ID 和 Secret",
85
+ configuredHint: "已配置",
86
+ unconfiguredHint: "需要设置",
87
+ resolveConfigured: ({ cfg }) => {
88
+ const account = utils.resolveWeComAccount(cfg);
89
+ return Boolean(account.botId?.trim() && account.secret?.trim());
90
+ },
91
+ resolveStatusLines: ({ cfg, configured }) => {
92
+ return [`企业微信: ${configured ? "已配置" : "需要 Bot ID 和 Secret"}`];
93
+ },
94
+ },
95
+ // ── 引导说明 ──────────────────────────────────────────────────────────
96
+ introNote: {
97
+ title: "企业微信设置",
98
+ lines: [
99
+ "企业微信机器人需要以下配置信息:",
100
+ "1. Bot ID: 企业微信机器人 ID",
101
+ "2. Secret: 企业微信机器人密钥",
102
+ ],
103
+ shouldShow: ({ cfg }) => {
104
+ const account = utils.resolveWeComAccount(cfg);
105
+ return !account.botId?.trim() || !account.secret?.trim();
106
+ },
107
+ },
108
+ // ── 凭据输入 ──────────────────────────────────────────────────────────
109
+ credentials: [
110
+ {
111
+ inputKey: "token",
112
+ providerHint: "企业微信",
113
+ credentialLabel: "Bot ID",
114
+ envPrompt: "使用环境变量中的 Bot ID?",
115
+ keepPrompt: "Bot ID 已配置,保留当前值?",
116
+ inputPrompt: "企业微信机器人 Bot ID",
117
+ inspect: ({ cfg }) => {
118
+ const account = utils.resolveWeComAccount(cfg);
119
+ const hasValue = Boolean(account.botId?.trim());
120
+ return {
121
+ accountConfigured: hasValue,
122
+ hasConfiguredValue: hasValue,
123
+ resolvedValue: account.botId || undefined,
124
+ };
125
+ },
126
+ applySet: ({ cfg, resolvedValue }) => {
127
+ return utils.setWeComAccount(cfg, { botId: resolvedValue });
128
+ },
129
+ },
130
+ {
131
+ inputKey: "privateKey",
132
+ providerHint: "企业微信",
133
+ credentialLabel: "Secret",
134
+ envPrompt: "使用环境变量中的 Secret?",
135
+ keepPrompt: "Secret 已配置,保留当前值?",
136
+ inputPrompt: "企业微信机器人 Secret",
137
+ inspect: ({ cfg }) => {
138
+ const account = utils.resolveWeComAccount(cfg);
139
+ const hasValue = Boolean(account.secret?.trim());
140
+ return {
141
+ accountConfigured: hasValue,
142
+ hasConfiguredValue: hasValue,
143
+ resolvedValue: account.secret || undefined,
144
+ };
145
+ },
146
+ applySet: ({ cfg, resolvedValue }) => {
147
+ return utils.setWeComAccount(cfg, { secret: resolvedValue });
148
+ },
149
+ },
150
+ ],
151
+ // ── 完成后的最终处理 ──────────────────────────────────────────────────
152
+ finalize: async ({ cfg }) => {
153
+ // 确保配置完成后 channel 处于启用状态
154
+ const account = utils.resolveWeComAccount(cfg);
155
+ if (account.botId?.trim() && account.secret?.trim() && !account.enabled) {
156
+ return { cfg: utils.setWeComAccount(cfg, { enabled: true }) };
157
+ }
158
+ return undefined;
159
+ },
160
+ // ── 完成提示 ──────────────────────────────────────────────────────────
161
+ completionNote: {
162
+ title: "企业微信配置完成",
163
+ lines: [
164
+ "企业微信机器人已配置完成。",
165
+ "运行 `openclaw start` 启动服务。",
166
+ ],
167
+ shouldShow: ({ cfg }) => {
168
+ const account = utils.resolveWeComAccount(cfg);
169
+ return Boolean(account.botId?.trim() && account.secret?.trim());
170
+ },
171
+ },
172
+ // ── DM 策略 ──────────────────────────────────────────────────────────
173
+ dmPolicy,
174
+ // ── 禁用 ─────────────────────────────────────────────────────────────
175
+ disable: (cfg) => {
176
+ return utils.setWeComAccount(cfg, { enabled: false });
177
+ },
178
+ };
179
+
180
+ exports.wecomSetupAdapter = wecomSetupAdapter;
181
+ exports.wecomSetupWizard = wecomSetupWizard;
182
+ //# sourceMappingURL=onboarding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboarding.js","sources":["../../../../../src/onboarding.ts"],"sourcesContent":["/**\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"],"names":["resolveWeComAccount","setWeComAccount","addWildcardAllowFrom","CHANNEL_ID"],"mappings":";;;;;;AAAA;;;;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,GAAGA,yBAAmB,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,OAAOC,qBAAe,CAAC,GAAG,EAAE,KAAK,CAAC;IACpC,CAAC;;AAGH;AACA;AACA;AAEA;;AAEG;AACH,SAAS,gBAAgB,CACvB,GAAmB,EACnB,QAAuD,EAAA;AAEvD,IAAA,MAAM,OAAO,GAAGD,yBAAmB,CAAC,GAAG,CAAC;IACxC,MAAM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE;AACxD,IAAA,MAAM,SAAS,GACb,QAAQ,KAAK;AACX,UAAEE,mCAAoB,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,OAAOD,qBAAe,CAAC,GAAG,EAAE;QAC1B,QAAQ;QACR,SAAS;AACV,KAAA,CAAC;AACJ;AAEA,MAAM,QAAQ,GAAyB;AACrC,IAAA,KAAK,EAAE,MAAM;AACb,IAAA,OAAO,EAAEE,iBAAU;IACnB,SAAS,EAAE,CAAA,SAAA,EAAYA,iBAAU,CAAA,SAAA,CAAW;IAC5C,YAAY,EAAE,CAAA,SAAA,EAAYA,iBAAU,CAAA,UAAA,CAAY;AAChD,IAAA,UAAU,EAAE,CAAC,GAAG,KAAI;AAClB,QAAA,MAAM,OAAO,GAAGH,yBAAmB,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,GAAGA,yBAAmB,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,OAAOC,qBAAe,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC;IAC5C,CAAC;CACF;AAED;AACA;AACA;AAEO,MAAM,gBAAgB,GAAuB;AAClD,IAAA,OAAO,EAAEE,iBAAU;;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,GAAGH,yBAAmB,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,GAAGA,yBAAmB,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,GAAGA,yBAAmB,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,OAAOC,qBAAe,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,GAAGD,yBAAmB,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,OAAOC,qBAAe,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,GAAGD,yBAAmB,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,EAAEC,qBAAe,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,GAAGD,yBAAmB,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,OAAOC,qBAAe,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACjD,CAAC;;;;;;"}