ylib-wecom-openclaw-plugin 2026.4.29

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 (180) hide show
  1. package/README.md +596 -0
  2. package/dist/index.d.ts +10 -0
  3. package/dist/index.js +99 -0
  4. package/dist/src/accounts.d.ts +57 -0
  5. package/dist/src/accounts.js +247 -0
  6. package/dist/src/agent/api-client.d.ts +95 -0
  7. package/dist/src/agent/api-client.js +425 -0
  8. package/dist/src/agent/handler.d.ts +64 -0
  9. package/dist/src/agent/handler.js +731 -0
  10. package/dist/src/agent/index.d.ts +5 -0
  11. package/dist/src/agent/index.js +21 -0
  12. package/dist/src/agent/webhook.d.ts +25 -0
  13. package/dist/src/agent/webhook.js +294 -0
  14. package/dist/src/agent/xml.d.ts +21 -0
  15. package/dist/src/agent/xml.js +43 -0
  16. package/dist/src/channel.d.ts +5 -0
  17. package/dist/src/channel.js +815 -0
  18. package/dist/src/chat-queue.d.ts +31 -0
  19. package/dist/src/chat-queue.js +53 -0
  20. package/dist/src/config-schema.d.ts +587 -0
  21. package/dist/src/config-schema.js +146 -0
  22. package/dist/src/const.d.ts +128 -0
  23. package/dist/src/const.js +168 -0
  24. package/dist/src/dm-policy.d.ts +29 -0
  25. package/dist/src/dm-policy.js +146 -0
  26. package/dist/src/dynamic-agent.d.ts +37 -0
  27. package/dist/src/dynamic-agent.js +67 -0
  28. package/dist/src/dynamic-routing.d.ts +65 -0
  29. package/dist/src/dynamic-routing.js +62 -0
  30. package/dist/src/endpoint-dispatch.d.ts +54 -0
  31. package/dist/src/endpoint-dispatch.js +967 -0
  32. package/dist/src/endpoint-event-adapter.d.ts +15 -0
  33. package/dist/src/endpoint-event-adapter.js +427 -0
  34. package/dist/src/group-policy.d.ts +30 -0
  35. package/dist/src/group-policy.js +126 -0
  36. package/dist/src/http.d.ts +27 -0
  37. package/dist/src/http.js +168 -0
  38. package/dist/src/im-runtime-telemetry.d.ts +25 -0
  39. package/dist/src/im-runtime-telemetry.js +68 -0
  40. package/dist/src/interface.d.ts +192 -0
  41. package/dist/src/interface.js +5 -0
  42. package/dist/src/markdown-chunk.d.ts +1 -0
  43. package/dist/src/markdown-chunk.js +396 -0
  44. package/dist/src/mcp/index.d.ts +6 -0
  45. package/dist/src/mcp/index.js +28 -0
  46. package/dist/src/mcp/interceptors/biz-error.d.ts +11 -0
  47. package/dist/src/mcp/interceptors/biz-error.js +73 -0
  48. package/dist/src/mcp/interceptors/doc-auth-error.d.ts +10 -0
  49. package/dist/src/mcp/interceptors/doc-auth-error.js +235 -0
  50. package/dist/src/mcp/interceptors/index.d.ts +35 -0
  51. package/dist/src/mcp/interceptors/index.js +143 -0
  52. package/dist/src/mcp/interceptors/msg-media.d.ts +11 -0
  53. package/dist/src/mcp/interceptors/msg-media.js +201 -0
  54. package/dist/src/mcp/interceptors/smartpage-create.d.ts +30 -0
  55. package/dist/src/mcp/interceptors/smartpage-create.js +252 -0
  56. package/dist/src/mcp/interceptors/smartpage-export.d.ts +17 -0
  57. package/dist/src/mcp/interceptors/smartpage-export.js +135 -0
  58. package/dist/src/mcp/interceptors/smartsheet-upload.d.ts +22 -0
  59. package/dist/src/mcp/interceptors/smartsheet-upload.js +388 -0
  60. package/dist/src/mcp/interceptors/types.d.ts +64 -0
  61. package/dist/src/mcp/interceptors/types.js +8 -0
  62. package/dist/src/mcp/schema.d.ts +11 -0
  63. package/dist/src/mcp/schema.js +115 -0
  64. package/dist/src/mcp/tool.d.ts +63 -0
  65. package/dist/src/mcp/tool.js +318 -0
  66. package/dist/src/mcp/transport.d.ts +94 -0
  67. package/dist/src/mcp/transport.js +702 -0
  68. package/dist/src/media-handler.d.ts +55 -0
  69. package/dist/src/media-handler.js +306 -0
  70. package/dist/src/media-uploader.d.ts +142 -0
  71. package/dist/src/media-uploader.js +446 -0
  72. package/dist/src/message-parser.d.ts +104 -0
  73. package/dist/src/message-parser.js +232 -0
  74. package/dist/src/message-sender.d.ts +54 -0
  75. package/dist/src/message-sender.js +210 -0
  76. package/dist/src/monitor.d.ts +69 -0
  77. package/dist/src/monitor.js +1846 -0
  78. package/dist/src/onboarding.d.ts +8 -0
  79. package/dist/src/onboarding.js +248 -0
  80. package/dist/src/openclaw-compat.d.ts +148 -0
  81. package/dist/src/openclaw-compat.js +839 -0
  82. package/dist/src/proactive-markdown-send.d.ts +14 -0
  83. package/dist/src/proactive-markdown-send.js +205 -0
  84. package/dist/src/reqid-store.d.ts +23 -0
  85. package/dist/src/reqid-store.js +136 -0
  86. package/dist/src/runtime.d.ts +2 -0
  87. package/dist/src/runtime.js +7 -0
  88. package/dist/src/shared/command-auth.d.ts +23 -0
  89. package/dist/src/shared/command-auth.js +112 -0
  90. package/dist/src/shared/xml-parser.d.ts +46 -0
  91. package/dist/src/shared/xml-parser.js +228 -0
  92. package/dist/src/state-dir-resolve.d.ts +2 -0
  93. package/dist/src/state-dir-resolve.js +33 -0
  94. package/dist/src/state-manager.d.ts +115 -0
  95. package/dist/src/state-manager.js +413 -0
  96. package/dist/src/target.d.ts +35 -0
  97. package/dist/src/target.js +71 -0
  98. package/dist/src/template-card-manager.d.ts +55 -0
  99. package/dist/src/template-card-manager.js +316 -0
  100. package/dist/src/template-card-parser.d.ts +37 -0
  101. package/dist/src/template-card-parser.js +672 -0
  102. package/dist/src/timeout.d.ts +20 -0
  103. package/dist/src/timeout.js +57 -0
  104. package/dist/src/types/account.d.ts +29 -0
  105. package/dist/src/types/account.js +5 -0
  106. package/dist/src/types/config.d.ts +98 -0
  107. package/dist/src/types/config.js +8 -0
  108. package/dist/src/types/constants.d.ts +42 -0
  109. package/dist/src/types/constants.js +45 -0
  110. package/dist/src/types/index.d.ts +7 -0
  111. package/dist/src/types/index.js +17 -0
  112. package/dist/src/types/message.d.ts +238 -0
  113. package/dist/src/types/message.js +6 -0
  114. package/dist/src/utils.d.ts +148 -0
  115. package/dist/src/utils.js +92 -0
  116. package/dist/src/version.d.ts +2 -0
  117. package/dist/src/version.js +28 -0
  118. package/dist/src/webhook/command-auth.d.ts +47 -0
  119. package/dist/src/webhook/command-auth.js +137 -0
  120. package/dist/src/webhook/gateway.d.ts +36 -0
  121. package/dist/src/webhook/gateway.js +297 -0
  122. package/dist/src/webhook/handler.d.ts +19 -0
  123. package/dist/src/webhook/handler.js +481 -0
  124. package/dist/src/webhook/helpers.d.ts +157 -0
  125. package/dist/src/webhook/helpers.js +936 -0
  126. package/dist/src/webhook/http.d.ts +27 -0
  127. package/dist/src/webhook/http.js +168 -0
  128. package/dist/src/webhook/index.d.ts +11 -0
  129. package/dist/src/webhook/index.js +43 -0
  130. package/dist/src/webhook/media.d.ts +30 -0
  131. package/dist/src/webhook/media.js +152 -0
  132. package/dist/src/webhook/monitor.d.ts +59 -0
  133. package/dist/src/webhook/monitor.js +1672 -0
  134. package/dist/src/webhook/state.d.ts +220 -0
  135. package/dist/src/webhook/state.js +568 -0
  136. package/dist/src/webhook/target.d.ts +41 -0
  137. package/dist/src/webhook/target.js +165 -0
  138. package/dist/src/webhook/types.d.ts +348 -0
  139. package/dist/src/webhook/types.js +36 -0
  140. package/dist/src/webhook/video-frame.d.ts +13 -0
  141. package/dist/src/webhook/video-frame.js +108 -0
  142. package/openclaw.plugin.json +19 -0
  143. package/package.json +96 -0
  144. package/schema.json +534 -0
  145. package/scripts/generate-schema.mjs +33 -0
  146. package/skills/wecom-contact/SKILL.md +162 -0
  147. package/skills/wecom-doc/SKILL.md +162 -0
  148. package/skills/wecom-doc/references/create-doc.md +56 -0
  149. package/skills/wecom-doc/references/edit-doc-content.md +68 -0
  150. package/skills/wecom-doc/references/get-doc-content.md +88 -0
  151. package/skills/wecom-doc/references/smartpage-create.md +125 -0
  152. package/skills/wecom-doc/references/smartpage-export.md +160 -0
  153. package/skills/wecom-meeting/SKILL.md +441 -0
  154. package/skills/wecom-meeting/references/example-full.md +30 -0
  155. package/skills/wecom-meeting/references/example-reminder.md +46 -0
  156. package/skills/wecom-meeting/references/example-security.md +22 -0
  157. package/skills/wecom-meeting/references/response-get-meeting-info.md +148 -0
  158. package/skills/wecom-msg/SKILL.md +157 -0
  159. package/skills/wecom-msg/references/api-get-messages.md +93 -0
  160. package/skills/wecom-msg/references/api-get-msg-chat-list.md +58 -0
  161. package/skills/wecom-msg/references/api-get-msg-media.md +44 -0
  162. package/skills/wecom-msg/references/api-send-message.md +39 -0
  163. package/skills/wecom-preflight/SKILL.md +141 -0
  164. package/skills/wecom-schedule/SKILL.md +161 -0
  165. package/skills/wecom-schedule/references/api-check-availability.md +56 -0
  166. package/skills/wecom-schedule/references/api-create-schedule.md +38 -0
  167. package/skills/wecom-schedule/references/api-get-schedule-detail.md +81 -0
  168. package/skills/wecom-schedule/references/api-update-schedule.md +32 -0
  169. package/skills/wecom-schedule/references/ref-reminders.md +24 -0
  170. package/skills/wecom-send-media/SKILL.md +68 -0
  171. package/skills/wecom-send-template-card/SKILL.md +157 -0
  172. package/skills/wecom-send-template-card/references/api-template-card-types.md +358 -0
  173. package/skills/wecom-smartsheet/SKILL.md +164 -0
  174. package/skills/wecom-smartsheet/references/smartsheet-cell-value-formats.md +163 -0
  175. package/skills/wecom-smartsheet/references/smartsheet-field-types.md +44 -0
  176. package/skills/wecom-smartsheet/references/smartsheet-get-records.md +96 -0
  177. package/skills/wecom-smartsheet/references/webhook-examples.md +185 -0
  178. package/skills/wecom-smartsheet/references/webhook-fallback.md +184 -0
  179. package/skills/wecom-todo/SKILL.md +392 -0
  180. package/skills/wecom-todo/examples/workflows.md +163 -0
@@ -0,0 +1,731 @@
1
+ "use strict";
2
+ /**
3
+ * WeCom Agent Webhook 处理器
4
+ * 处理 XML 格式回调
5
+ */
6
+ var __assign = (this && this.__assign) || function () {
7
+ __assign = Object.assign || function(t) {
8
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
9
+ s = arguments[i];
10
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
11
+ t[p] = s[p];
12
+ }
13
+ return t;
14
+ };
15
+ return __assign.apply(this, arguments);
16
+ };
17
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || function (mod) {
30
+ if (mod && mod.__esModule) return mod;
31
+ var result = {};
32
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
33
+ __setModuleDefault(result, mod);
34
+ return result;
35
+ };
36
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
37
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
38
+ return new (P || (P = Promise))(function (resolve, reject) {
39
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
40
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
41
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
42
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
43
+ });
44
+ };
45
+ var __generator = (this && this.__generator) || function (thisArg, body) {
46
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
47
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
48
+ function verb(n) { return function (v) { return step([n, v]); }; }
49
+ function step(op) {
50
+ if (f) throw new TypeError("Generator is already executing.");
51
+ while (_) try {
52
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
53
+ if (y = 0, t) op = [op[0] & 2, t.value];
54
+ switch (op[0]) {
55
+ case 0: case 1: t = op; break;
56
+ case 4: _.label++; return { value: op[1], done: false };
57
+ case 5: _.label++; y = op[1]; op = [0]; continue;
58
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
59
+ default:
60
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
61
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
62
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
63
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
64
+ if (t[2]) _.ops.pop();
65
+ _.trys.pop(); continue;
66
+ }
67
+ op = body.call(thisArg, _);
68
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
69
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
70
+ }
71
+ };
72
+ var __spreadArrays = (this && this.__spreadArrays) || function () {
73
+ for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
74
+ for (var r = Array(s), k = 0, i = 0; i < il; i++)
75
+ for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
76
+ r[k] = a[j];
77
+ return r;
78
+ };
79
+ var __importDefault = (this && this.__importDefault) || function (mod) {
80
+ return (mod && mod.__esModule) ? mod : { "default": mod };
81
+ };
82
+ exports.__esModule = true;
83
+ exports.handleAgentWebhook = exports.shouldProcessAgentInboundMessage = void 0;
84
+ var node_url_1 = require("node:url");
85
+ var node_os_1 = __importDefault(require("node:os"));
86
+ var node_path_1 = __importDefault(require("node:path"));
87
+ var xml_parser_js_1 = require("../shared/xml-parser.js");
88
+ var api_client_js_1 = require("./api-client.js");
89
+ var command_auth_js_1 = require("../shared/command-auth.js");
90
+ var dynamic_routing_js_1 = require("../dynamic-routing.js");
91
+ var const_js_1 = require("../const.js");
92
+ var endpoint_event_adapter_js_1 = require("../endpoint-event-adapter.js");
93
+ var utils_js_1 = require("../utils.js");
94
+ function resolveWecomMediaMaxBytes(config) {
95
+ var _a, _b, _c, _d;
96
+ return (_d = (_c = (_b = (_a = config.channels) === null || _a === void 0 ? void 0 : _a.wecom) === null || _b === void 0 ? void 0 : _b.media) === null || _c === void 0 ? void 0 : _c.maxBytes) !== null && _d !== void 0 ? _d : const_js_1.DEFAULT_MEDIA_MAX_MB * 1024 * 1024;
97
+ }
98
+ /** 错误提示信息 */
99
+ var ERROR_HELP = "";
100
+ // Agent webhook 幂等去重池(防止企微回调重试导致重复回复)
101
+ // 注意:这是进程内内存去重,重启会清空;但足以覆盖企微的短周期重试。
102
+ var RECENT_MSGID_TTL_MS = 10 * 60 * 1000;
103
+ var recentAgentMsgIds = new Map();
104
+ function rememberAgentMsgId(msgId) {
105
+ var now = Date.now();
106
+ var existing = recentAgentMsgIds.get(msgId);
107
+ if (existing && now - existing < RECENT_MSGID_TTL_MS)
108
+ return false;
109
+ recentAgentMsgIds.set(msgId, now);
110
+ // 简单清理:只在写入时做一次线性 prune,避免无界增长
111
+ for (var _i = 0, recentAgentMsgIds_1 = recentAgentMsgIds; _i < recentAgentMsgIds_1.length; _i++) {
112
+ var _a = recentAgentMsgIds_1[_i], k = _a[0], ts = _a[1];
113
+ if (now - ts >= RECENT_MSGID_TTL_MS)
114
+ recentAgentMsgIds["delete"](k);
115
+ }
116
+ return true;
117
+ }
118
+ function looksLikeTextFile(buffer) {
119
+ var sampleSize = Math.min(buffer.length, 4096);
120
+ if (sampleSize === 0)
121
+ return true;
122
+ var bad = 0;
123
+ for (var i = 0; i < sampleSize; i++) {
124
+ var b = buffer[i];
125
+ var isWhitespace = b === 0x09 || b === 0x0a || b === 0x0d; // \t \n \r
126
+ var isPrintable = b >= 0x20 && b !== 0x7f;
127
+ if (!isWhitespace && !isPrintable)
128
+ bad++;
129
+ }
130
+ // 非可打印字符占比太高,基本可判断为二进制
131
+ return bad / sampleSize <= 0.02;
132
+ }
133
+ function analyzeTextHeuristic(buffer) {
134
+ var sampleSize = Math.min(buffer.length, 4096);
135
+ if (sampleSize === 0)
136
+ return { sampleSize: 0, badCount: 0, badRatio: 0 };
137
+ var badCount = 0;
138
+ for (var i = 0; i < sampleSize; i++) {
139
+ var b = buffer[i];
140
+ var isWhitespace = b === 0x09 || b === 0x0a || b === 0x0d;
141
+ var isPrintable = b >= 0x20 && b !== 0x7f;
142
+ if (!isWhitespace && !isPrintable)
143
+ badCount++;
144
+ }
145
+ return { sampleSize: sampleSize, badCount: badCount, badRatio: badCount / sampleSize };
146
+ }
147
+ function previewHex(buffer, maxBytes) {
148
+ if (maxBytes === void 0) { maxBytes = 32; }
149
+ var n = Math.min(buffer.length, maxBytes);
150
+ if (n <= 0)
151
+ return "";
152
+ return buffer
153
+ .subarray(0, n)
154
+ .toString("hex")
155
+ .replace(/(..)/g, "$1 ")
156
+ .trim();
157
+ }
158
+ function buildTextFilePreview(buffer, maxChars) {
159
+ if (!looksLikeTextFile(buffer))
160
+ return undefined;
161
+ var text = buffer.toString("utf8");
162
+ if (!text.trim())
163
+ return undefined;
164
+ var truncated = text.length > maxChars ? text.slice(0, maxChars) + "\n\u2026(\u5DF2\u622A\u65AD)" : text;
165
+ return truncated;
166
+ }
167
+ /**
168
+ * 仅允许“用户意图消息”进入 AI 会话。
169
+ * - event 回调(如 enter_agent/subscribe)不应触发会话与自动回复
170
+ * - 系统发送者(sys)不应触发会话与自动回复
171
+ * - 缺失发送者时默认丢弃,避免写入异常会话
172
+ */
173
+ function shouldProcessAgentInboundMessage(params) {
174
+ var _a, _b, _c;
175
+ var msgType = String((_a = params.msgType) !== null && _a !== void 0 ? _a : "").trim().toLowerCase();
176
+ var fromUser = String((_b = params.fromUser) !== null && _b !== void 0 ? _b : "").trim();
177
+ var normalizedFromUser = fromUser.toLowerCase();
178
+ var eventType = String((_c = params.eventType) !== null && _c !== void 0 ? _c : "").trim().toLowerCase();
179
+ if (msgType === "event") {
180
+ return {
181
+ shouldProcess: false,
182
+ reason: "event:" + (eventType || "unknown")
183
+ };
184
+ }
185
+ if (!fromUser) {
186
+ return {
187
+ shouldProcess: false,
188
+ reason: "missing_sender"
189
+ };
190
+ }
191
+ if (normalizedFromUser === "sys") {
192
+ return {
193
+ shouldProcess: false,
194
+ reason: "system_sender"
195
+ };
196
+ }
197
+ return {
198
+ shouldProcess: true,
199
+ reason: "user_message"
200
+ };
201
+ }
202
+ exports.shouldProcessAgentInboundMessage = shouldProcessAgentInboundMessage;
203
+ function normalizeAgentId(value) {
204
+ if (typeof value === "number" && Number.isFinite(value))
205
+ return value;
206
+ var raw = String(value !== null && value !== void 0 ? value : "").trim();
207
+ if (!raw)
208
+ return undefined;
209
+ var parsed = Number(raw);
210
+ return Number.isFinite(parsed) ? parsed : undefined;
211
+ }
212
+ /**
213
+ * **resolveQueryParams (解析查询参数)**
214
+ *
215
+ * 辅助函数:从 IncomingMessage 中解析 URL 查询字符串,用于获取签名、时间戳等参数。
216
+ */
217
+ function resolveQueryParams(req) {
218
+ var _a;
219
+ var url = new URL((_a = req.url) !== null && _a !== void 0 ? _a : "/", "http://localhost");
220
+ return url.searchParams;
221
+ }
222
+ /**
223
+ * 处理消息回调 (POST)
224
+ */
225
+ function handleMessageCallback(params) {
226
+ var _a, _b, _c, _d, _e, _f, _g;
227
+ return __awaiter(this, void 0, void 0, function () {
228
+ var req, res, verifiedPost, agent, config, core, log, error, query, querySignature, encrypted, decrypted, msg, timestamp, nonce, signature, inboundAgentId, msgType, fromUser, chatId, msgId, eventType, ok, content, preview, decision;
229
+ return __generator(this, function (_h) {
230
+ req = params.req, res = params.res, verifiedPost = params.verifiedPost, agent = params.agent, config = params.config, core = params.core, log = params.log, error = params.error;
231
+ try {
232
+ if (!verifiedPost) {
233
+ error === null || error === void 0 ? void 0 : error("[wecom-agent] inbound: missing preverified envelope");
234
+ res.statusCode = 400;
235
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
236
+ res.end("invalid request - \u7F3A\u5C11\u4E0A\u6E38\u9A8C\u7B7E\u7ED3\u679C" + ERROR_HELP);
237
+ return [2 /*return*/, true];
238
+ }
239
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] inbound: method=" + ((_a = req.method) !== null && _a !== void 0 ? _a : "UNKNOWN") + " remote=" + ((_c = (_b = req.socket) === null || _b === void 0 ? void 0 : _b.remoteAddress) !== null && _c !== void 0 ? _c : "unknown"));
240
+ query = resolveQueryParams(req);
241
+ querySignature = (_d = query.get("msg_signature")) !== null && _d !== void 0 ? _d : "";
242
+ encrypted = verifiedPost.encrypted;
243
+ decrypted = verifiedPost.decrypted;
244
+ msg = verifiedPost.parsed;
245
+ timestamp = verifiedPost.timestamp;
246
+ nonce = verifiedPost.nonce;
247
+ signature = verifiedPost.signature || querySignature;
248
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] inbound: using preverified envelope timestamp=" + (timestamp ? "yes" : "no") + " nonce=" + (nonce ? "yes" : "no") + " msg_signature=" + (signature ? "yes" : "no") + " encryptLen=" + encrypted.length);
249
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] inbound: decryptedBytes=" + Buffer.byteLength(decrypted, "utf8"));
250
+ inboundAgentId = normalizeAgentId(xml_parser_js_1.extractAgentId(msg));
251
+ if (inboundAgentId !== undefined &&
252
+ typeof agent.agentId === "number" &&
253
+ Number.isFinite(agent.agentId) &&
254
+ inboundAgentId !== agent.agentId) {
255
+ error === null || error === void 0 ? void 0 : error("[wecom-agent] inbound: agentId mismatch ignored expectedAgentId=" + agent.agentId + " actualAgentId=" + String((_e = xml_parser_js_1.extractAgentId(msg)) !== null && _e !== void 0 ? _e : ""));
256
+ }
257
+ msgType = xml_parser_js_1.extractMsgType(msg);
258
+ fromUser = xml_parser_js_1.extractFromUser(msg);
259
+ chatId = xml_parser_js_1.extractChatId(msg);
260
+ msgId = xml_parser_js_1.extractMsgId(msg);
261
+ eventType = String((_f = msg.Event) !== null && _f !== void 0 ? _f : "").trim().toLowerCase();
262
+ if (msgId) {
263
+ ok = rememberAgentMsgId(msgId);
264
+ if (!ok) {
265
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] duplicate msgId=" + msgId + " from=" + fromUser + " chatId=" + (chatId !== null && chatId !== void 0 ? chatId : "N/A") + " type=" + msgType + "; skipped");
266
+ res.statusCode = 200;
267
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
268
+ res.end("success");
269
+ return [2 /*return*/, true];
270
+ }
271
+ }
272
+ content = String((_g = xml_parser_js_1.extractContent(msg)) !== null && _g !== void 0 ? _g : "");
273
+ preview = content.length > 100 ? content.slice(0, 100) + "\u2026" : content;
274
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] " + msgType + " from=" + fromUser + " chatId=" + (chatId !== null && chatId !== void 0 ? chatId : "N/A") + " msgId=" + (msgId !== null && msgId !== void 0 ? msgId : "N/A") + " content=" + preview);
275
+ // 先返回 success (Agent 模式使用 API 发送回复,不用被动回复)
276
+ res.statusCode = 200;
277
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
278
+ res.end("success");
279
+ decision = shouldProcessAgentInboundMessage({
280
+ msgType: msgType,
281
+ fromUser: fromUser,
282
+ eventType: eventType
283
+ });
284
+ if (!decision.shouldProcess) {
285
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] skip processing: type=" + (msgType || "unknown") + " event=" + (eventType || "N/A") + " from=" + (fromUser || "N/A") + " reason=" + decision.reason);
286
+ return [2 /*return*/, true];
287
+ }
288
+ // 异步处理消息
289
+ processAgentMessage({
290
+ agent: agent,
291
+ config: config,
292
+ core: core,
293
+ fromUser: fromUser,
294
+ chatId: chatId,
295
+ msgType: msgType,
296
+ content: content,
297
+ msg: msg,
298
+ log: log,
299
+ error: error
300
+ })["catch"](function (err) {
301
+ error === null || error === void 0 ? void 0 : error("[wecom-agent] process failed: " + String(err));
302
+ });
303
+ return [2 /*return*/, true];
304
+ }
305
+ catch (err) {
306
+ error === null || error === void 0 ? void 0 : error("[wecom-agent] callback failed: " + String(err));
307
+ res.statusCode = 400;
308
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
309
+ res.end("error - \u56DE\u8C03\u5904\u7406\u5931\u8D25" + ERROR_HELP);
310
+ return [2 /*return*/, true];
311
+ }
312
+ return [2 /*return*/];
313
+ });
314
+ });
315
+ }
316
+ /**
317
+ * **processAgentMessage (处理 Agent 消息)**
318
+ *
319
+ * 异步处理解密后的消息内容,并触发 OpenClaw Agent。
320
+ * 流程:
321
+ * 1. 路由解析:根据 userid或群ID 确定 Agent 路由。
322
+ * 2. 媒体处理:如果是图片/文件等,下载资源。
323
+ * 3. 上下文构建:创建 Inbound Context。
324
+ * 4. 会话记录:更新 Session 状态。
325
+ * 5. 调度回复:将 Agent 的响应通过 `api-client` 发送回企业微信。
326
+ */
327
+ function processAgentMessage(params) {
328
+ var _a, _b, _c, _d;
329
+ return __awaiter(this, void 0, void 0, function () {
330
+ var agent, config, core, fromUser, chatId, content, msg, msgType, log, error, isGroup, rawChatId, peerId, mediaMaxBytes, attachments, finalContent, mediaPath, mediaType, mediaId, _e, buffer, contentType, headerFileName, xmlFileName, originalFileName, heuristic, extMap, textPreview, looksText, originalExt, normalizedContentType, ext, filename, saved, err_1, keys, route, routingResult, fromLabel, storePath, envelopeOptions, previousTimestamp, body, authz, prompt, err_2, ctxPayload, handledConfirmationKeys, ignoredSubAgentRunIds;
331
+ var _this = this;
332
+ return __generator(this, function (_f) {
333
+ switch (_f.label) {
334
+ case 0:
335
+ agent = params.agent, config = params.config, core = params.core, fromUser = params.fromUser, chatId = params.chatId, content = params.content, msg = params.msg, msgType = params.msgType, log = params.log, error = params.error;
336
+ isGroup = Boolean(chatId);
337
+ rawChatId = isGroup ? chatId : fromUser;
338
+ peerId = isGroup
339
+ ? utils_js_1.resolveWecomSessionPeerId({
340
+ chatType: "group",
341
+ chatId: rawChatId,
342
+ senderId: fromUser
343
+ })
344
+ : fromUser;
345
+ mediaMaxBytes = resolveWecomMediaMaxBytes(config);
346
+ attachments = [];
347
+ finalContent = content;
348
+ if (!["image", "voice", "video", "file"].includes(msgType)) return [3 /*break*/, 7];
349
+ mediaId = xml_parser_js_1.extractMediaId(msg);
350
+ if (!mediaId) return [3 /*break*/, 6];
351
+ _f.label = 1;
352
+ case 1:
353
+ _f.trys.push([1, 4, , 5]);
354
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] downloading media: " + mediaId + " (" + msgType + ")");
355
+ return [4 /*yield*/, api_client_js_1.downloadMedia({ agent: agent, mediaId: mediaId, maxBytes: mediaMaxBytes })];
356
+ case 2:
357
+ _e = _f.sent(), buffer = _e.buffer, contentType = _e.contentType, headerFileName = _e.filename;
358
+ xmlFileName = xml_parser_js_1.extractFileName(msg);
359
+ originalFileName = (xmlFileName || headerFileName || mediaId + ".bin").trim();
360
+ heuristic = analyzeTextHeuristic(buffer);
361
+ extMap = {
362
+ "image/jpeg": "jpg", "image/png": "png", "image/gif": "gif",
363
+ "audio/amr": "amr", "audio/speex": "speex", "video/mp4": "mp4"
364
+ };
365
+ textPreview = msgType === "file" ? buildTextFilePreview(buffer, 12000) : undefined;
366
+ looksText = Boolean(textPreview);
367
+ originalExt = node_path_1["default"].extname(originalFileName).toLowerCase();
368
+ normalizedContentType = looksText && originalExt === ".md" ? "text/markdown" :
369
+ looksText && (!contentType || contentType === "application/octet-stream")
370
+ ? "text/plain; charset=utf-8"
371
+ : contentType;
372
+ ext = extMap[normalizedContentType] || (looksText ? "txt" : "bin");
373
+ filename = mediaId + "." + ext;
374
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] file meta: msgType=" + msgType + " mediaId=" + mediaId + " size=" + buffer.length + " maxBytes=" + mediaMaxBytes + " " +
375
+ ("contentType=" + contentType + " normalizedContentType=" + normalizedContentType + " originalFileName=" + originalFileName + " ") +
376
+ ("xmlFileName=" + (xmlFileName !== null && xmlFileName !== void 0 ? xmlFileName : "N/A") + " headerFileName=" + (headerFileName !== null && headerFileName !== void 0 ? headerFileName : "N/A") + " ") +
377
+ ("textHeuristic(sample=" + heuristic.sampleSize + ", bad=" + heuristic.badCount + ", ratio=" + heuristic.badRatio.toFixed(4) + ") ") +
378
+ ("headHex=\"" + previewHex(buffer) + "\""));
379
+ return [4 /*yield*/, core.channel.media.saveMediaBuffer(buffer, normalizedContentType, "inbound", // context/scope
380
+ mediaMaxBytes, // limit
381
+ originalFileName)];
382
+ case 3:
383
+ saved = _f.sent();
384
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] media saved to: " + saved.path);
385
+ mediaPath = saved.path;
386
+ mediaType = normalizedContentType;
387
+ // 构建附件
388
+ attachments.push({
389
+ name: originalFileName,
390
+ mimeType: normalizedContentType,
391
+ url: node_url_1.pathToFileURL(saved.path).href
392
+ });
393
+ // 更新文本提示
394
+ if (textPreview) {
395
+ finalContent = [
396
+ content,
397
+ "",
398
+ "文件内容预览:",
399
+ "```",
400
+ textPreview,
401
+ "```",
402
+ "(\u5DF2\u4E0B\u8F7D " + buffer.length + " \u5B57\u8282)",
403
+ ].join("\n");
404
+ }
405
+ else {
406
+ if (msgType === "file") {
407
+ finalContent = [
408
+ content,
409
+ "",
410
+ "\u5DF2\u6536\u5230\u6587\u4EF6\uFF1A" + originalFileName,
411
+ "\u6587\u4EF6\u7C7B\u578B\uFF1A" + (normalizedContentType || contentType || "未知"),
412
+ "提示:当前仅对文本/Markdown/JSON/CSV/HTML/PDF(可选)做内容抽取;其他二进制格式请转为 PDF 或复制文本内容。",
413
+ "(\u5DF2\u4E0B\u8F7D " + buffer.length + " \u5B57\u8282)",
414
+ ].join("\n");
415
+ }
416
+ else {
417
+ finalContent = content + " (\u5DF2\u4E0B\u8F7D " + buffer.length + " \u5B57\u8282)";
418
+ }
419
+ }
420
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] file preview: enabled=" + looksText + " finalContentLen=" + finalContent.length + " attachments=" + attachments.length);
421
+ return [3 /*break*/, 5];
422
+ case 4:
423
+ err_1 = _f.sent();
424
+ error === null || error === void 0 ? void 0 : error("[wecom-agent] media processing failed: " + String(err_1));
425
+ finalContent = [
426
+ content,
427
+ "",
428
+ "\u5A92\u4F53\u5904\u7406\u5931\u8D25\uFF1A" + String(err_1),
429
+ "\u63D0\u793A\uFF1A\u53EF\u5728 OpenClaw \u914D\u7F6E\u4E2D\u63D0\u9AD8 channels.wecom.media.maxBytes\uFF08\u5F53\u524D=" + mediaMaxBytes + "\uFF09",
430
+ "\u4F8B\u5982\uFF1Aopenclaw config set channels.wecom.media.maxBytes " + 50 * 1024 * 1024,
431
+ ].join("\n");
432
+ return [3 /*break*/, 5];
433
+ case 5: return [3 /*break*/, 7];
434
+ case 6:
435
+ keys = Object.keys((_a = msg) !== null && _a !== void 0 ? _a : {}).slice(0, 50).join(",");
436
+ error === null || error === void 0 ? void 0 : error("[wecom-agent] mediaId not found for " + msgType + "; keys=" + keys);
437
+ _f.label = 7;
438
+ case 7:
439
+ route = core.channel.routing.resolveAgentRoute({
440
+ cfg: config,
441
+ channel: "wecom",
442
+ accountId: agent.accountId,
443
+ peer: { kind: isGroup ? "group" : "direct", id: peerId }
444
+ });
445
+ routingResult = dynamic_routing_js_1.processDynamicRouting({
446
+ route: route,
447
+ config: config,
448
+ core: core,
449
+ accountId: agent.accountId,
450
+ chatType: isGroup ? "group" : "dm",
451
+ chatId: rawChatId,
452
+ senderId: fromUser,
453
+ log: function (msg) { return log === null || log === void 0 ? void 0 : log(msg.replace(/^\[dynamic-routing\]/, "[wecom-agent]")); },
454
+ error: function (msg) { return error === null || error === void 0 ? void 0 : error(msg.replace(/^\[dynamic-routing\]/, "[wecom-agent]")); }
455
+ });
456
+ // 应用动态路由结果
457
+ if (routingResult.routeModified) {
458
+ route.agentId = routingResult.finalAgentId;
459
+ route.sessionKey = routingResult.finalSessionKey;
460
+ }
461
+ fromLabel = isGroup ? "group:" + rawChatId : "user:" + fromUser;
462
+ storePath = core.channel.session.resolveStorePath((_b = config.session) === null || _b === void 0 ? void 0 : _b.store, {
463
+ agentId: route.agentId
464
+ });
465
+ envelopeOptions = core.channel.reply.resolveEnvelopeFormatOptions(config);
466
+ previousTimestamp = core.channel.session.readSessionUpdatedAt({
467
+ storePath: storePath,
468
+ sessionKey: route.sessionKey
469
+ });
470
+ body = core.channel.reply.formatAgentEnvelope({
471
+ channel: "WeCom",
472
+ from: fromLabel,
473
+ previousTimestamp: previousTimestamp,
474
+ envelope: envelopeOptions,
475
+ body: finalContent
476
+ });
477
+ return [4 /*yield*/, command_auth_js_1.resolveWecomCommandAuthorization({
478
+ core: core,
479
+ cfg: config,
480
+ // Agent 门禁应读取 channels.wecom.agent.dm(即 agent.config.dm),而不是 channels.wecom.dm(不存在)
481
+ accountConfig: agent.config,
482
+ rawBody: finalContent,
483
+ senderUserId: fromUser
484
+ })];
485
+ case 8:
486
+ authz = _f.sent();
487
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] authz: dmPolicy=" + authz.dmPolicy + " shouldCompute=" + authz.shouldComputeAuth + " sender=" + fromUser.toLowerCase() + " senderAllowed=" + authz.senderAllowed + " authorizerConfigured=" + authz.authorizerConfigured + " commandAuthorized=" + String(authz.commandAuthorized));
488
+ if (!(authz.shouldComputeAuth && authz.commandAuthorized !== true)) return [3 /*break*/, 13];
489
+ prompt = command_auth_js_1.buildWecomUnauthorizedCommandPrompt({ senderUserId: fromUser, dmPolicy: authz.dmPolicy, scope: "agent" });
490
+ _f.label = 9;
491
+ case 9:
492
+ _f.trys.push([9, 11, , 12]);
493
+ return [4 /*yield*/, api_client_js_1.sendText({ agent: agent, toUser: fromUser, chatId: undefined, text: prompt })];
494
+ case 10:
495
+ _f.sent();
496
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] unauthorized command: replied via DM to " + fromUser);
497
+ return [3 /*break*/, 12];
498
+ case 11:
499
+ err_2 = _f.sent();
500
+ error === null || error === void 0 ? void 0 : error("[wecom-agent] unauthorized command reply failed: " + String(err_2));
501
+ return [3 /*break*/, 12];
502
+ case 12: return [2 /*return*/];
503
+ case 13:
504
+ ctxPayload = core.channel.reply.finalizeInboundContext({
505
+ Body: body,
506
+ RawBody: finalContent,
507
+ CommandBody: finalContent,
508
+ Attachments: attachments.length > 0 ? attachments : undefined,
509
+ From: isGroup ? "wecom:group:" + rawChatId : "wecom:" + fromUser,
510
+ // 使用 wecom-agent: 前缀标记 Agent 会话,确保 outbound 路由不会混入 Bot WS 发送路径。
511
+ // resolveWecomTarget 已支持剥离 wecom-agent: 前缀(target.ts L41),解析结果不变。
512
+ To: "wecom-agent:" + fromUser,
513
+ SessionKey: route.sessionKey,
514
+ AccountId: route.accountId,
515
+ ChatType: isGroup ? "group" : "direct",
516
+ ConversationLabel: fromLabel,
517
+ SenderName: fromUser,
518
+ SenderId: fromUser,
519
+ Provider: const_js_1.CHANNEL_ID,
520
+ Surface: "webchat",
521
+ OriginatingChannel: const_js_1.CHANNEL_ID,
522
+ // 标记为 Agent 会话的回复路由目标,避免与 Bot 会话混淆:
523
+ // - 用于让 /new /reset 这类命令回执不被 Bot 侧策略拦截
524
+ // - 群聊场景也统一路由为私信触发者(与 deliver 策略一致)
525
+ OriginatingTo: "wecom-agent:" + fromUser,
526
+ CommandAuthorized: (_c = authz.commandAuthorized) !== null && _c !== void 0 ? _c : true,
527
+ MediaPath: mediaPath,
528
+ MediaType: mediaType,
529
+ MediaUrl: mediaPath
530
+ });
531
+ // 记录会话
532
+ return [4 /*yield*/, core.channel.session.recordInboundSession({
533
+ storePath: storePath,
534
+ sessionKey: (_d = ctxPayload.SessionKey) !== null && _d !== void 0 ? _d : route.sessionKey,
535
+ ctx: ctxPayload,
536
+ onRecordError: function (err) {
537
+ error === null || error === void 0 ? void 0 : error("[wecom-agent] session record failed: " + String(err));
538
+ }
539
+ })];
540
+ case 14:
541
+ // 记录会话
542
+ _f.sent();
543
+ handledConfirmationKeys = new Set();
544
+ ignoredSubAgentRunIds = new Set();
545
+ return [4 /*yield*/, core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
546
+ ctx: ctxPayload,
547
+ cfg: config,
548
+ dispatcherOptions: {
549
+ deliver: function (payload, info) { return __awaiter(_this, void 0, void 0, function () {
550
+ var text, adapted, mediaDirectivePaths, mediaDirectiveRe, _mdMatch, p, home, mediaUrls, err_3, message, _i, mediaUrls_1, mediaPath_1, isRemoteUrl, buf, contentType, filename, res, _a, _b, fs, pathModule, ext, MIME_MAP, mediaType_1, mediaId, err_4, message, _c;
551
+ var _d, _e, _f;
552
+ return __generator(this, function (_g) {
553
+ switch (_g.label) {
554
+ case 0:
555
+ text = (_d = payload.text) !== null && _d !== void 0 ? _d : "";
556
+ adapted = endpoint_event_adapter_js_1.adaptEndpointEvent({
557
+ rawText: text,
558
+ currentEventType: info.kind
559
+ });
560
+ if (adapted.subAgentStartLine) {
561
+ if (adapted.subAgentRunId)
562
+ ignoredSubAgentRunIds.add(adapted.subAgentRunId);
563
+ text = adapted.subAgentStartLine.trim();
564
+ }
565
+ else if (adapted.subAgentRunId && ignoredSubAgentRunIds.has(adapted.subAgentRunId)) {
566
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] ignore sub-agent event: agent_run_id=" + adapted.subAgentRunId + " event=" + (adapted.eventType || info.kind));
567
+ return [2 /*return*/];
568
+ }
569
+ if (adapted.confirmationText) {
570
+ if (adapted.confirmationDedupKey && handledConfirmationKeys.has(adapted.confirmationDedupKey)) {
571
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] confirmation duplicate skipped: " + adapted.confirmationDedupKey);
572
+ return [2 /*return*/];
573
+ }
574
+ if (adapted.confirmationDedupKey)
575
+ handledConfirmationKeys.add(adapted.confirmationDedupKey);
576
+ text = adapted.confirmationText.trim();
577
+ }
578
+ else if (adapted.ignoreAsNoise) {
579
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] passthrough event ignored for outbound: " + (adapted.eventType || info.kind));
580
+ return [2 /*return*/];
581
+ }
582
+ mediaDirectivePaths = [];
583
+ mediaDirectiveRe = /^MEDIA:\s*`?([^\n`]+?)`?\s*$/gm;
584
+ while ((_mdMatch = mediaDirectiveRe.exec(text)) !== null) {
585
+ p = ((_e = _mdMatch[1]) !== null && _e !== void 0 ? _e : "").trim();
586
+ if (!p)
587
+ continue;
588
+ if (p.startsWith("~/") || p === "~") {
589
+ home = node_os_1["default"].homedir() || "/root";
590
+ p = p.replace(/^~/, home);
591
+ }
592
+ if (!mediaDirectivePaths.includes(p))
593
+ mediaDirectivePaths.push(p);
594
+ }
595
+ // 从回复文本中移除 MEDIA: 指令行
596
+ if (mediaDirectivePaths.length > 0) {
597
+ text = text.replace(/^MEDIA:\s*`?[^\n`]+?`?\s*$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
598
+ }
599
+ mediaUrls = Array.from(new Set(__spreadArrays((payload.mediaUrls || []), (payload.mediaUrl ? [payload.mediaUrl] : []), mediaDirectivePaths)));
600
+ if (!text.trim()) return [3 /*break*/, 4];
601
+ _g.label = 1;
602
+ case 1:
603
+ _g.trys.push([1, 3, , 4]);
604
+ return [4 /*yield*/, api_client_js_1.sendText({ agent: agent, toUser: fromUser, chatId: undefined, text: text })];
605
+ case 2:
606
+ _g.sent();
607
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] reply delivered (" + info.kind + ") to " + fromUser + " (textLen=" + text.length + ")");
608
+ return [3 /*break*/, 4];
609
+ case 3:
610
+ err_3 = _g.sent();
611
+ message = err_3 instanceof Error ? "" + err_3.message + (err_3.cause ? " (cause: " + String(err_3.cause) + ")" : "") : String(err_3);
612
+ error === null || error === void 0 ? void 0 : error("[wecom-agent] reply failed: " + message);
613
+ return [3 /*break*/, 4];
614
+ case 4:
615
+ _i = 0, mediaUrls_1 = mediaUrls;
616
+ _g.label = 5;
617
+ case 5:
618
+ if (!(_i < mediaUrls_1.length)) return [3 /*break*/, 22];
619
+ mediaPath_1 = mediaUrls_1[_i];
620
+ _g.label = 6;
621
+ case 6:
622
+ _g.trys.push([6, 16, , 21]);
623
+ isRemoteUrl = /^https?:\/\//i.test(mediaPath_1);
624
+ buf = void 0;
625
+ contentType = void 0;
626
+ filename = void 0;
627
+ if (!isRemoteUrl) return [3 /*break*/, 9];
628
+ return [4 /*yield*/, fetch(mediaPath_1, { signal: AbortSignal.timeout(30000) })];
629
+ case 7:
630
+ res = _g.sent();
631
+ if (!res.ok)
632
+ throw new Error("download failed: " + res.status);
633
+ _b = (_a = Buffer).from;
634
+ return [4 /*yield*/, res.arrayBuffer()];
635
+ case 8:
636
+ buf = _b.apply(_a, [_g.sent()]);
637
+ contentType = res.headers.get("content-type") || "application/octet-stream";
638
+ filename = new URL(mediaPath_1).pathname.split("/").pop() || "media";
639
+ return [3 /*break*/, 13];
640
+ case 9: return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("node:fs/promises")); })];
641
+ case 10:
642
+ fs = _g.sent();
643
+ return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("node:path")); })];
644
+ case 11:
645
+ pathModule = _g.sent();
646
+ return [4 /*yield*/, fs.readFile(mediaPath_1)];
647
+ case 12:
648
+ buf = _g.sent();
649
+ filename = pathModule.basename(mediaPath_1);
650
+ ext = pathModule.extname(mediaPath_1).slice(1).toLowerCase();
651
+ MIME_MAP = {
652
+ jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", gif: "image/gif",
653
+ webp: "image/webp", mp3: "audio/mpeg", wav: "audio/wav", amr: "audio/amr",
654
+ mp4: "video/mp4", mov: "video/quicktime", pdf: "application/pdf",
655
+ doc: "application/msword", docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
656
+ xls: "application/vnd.ms-excel", xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
657
+ txt: "text/plain", csv: "text/csv", json: "application/json", zip: "application/zip"
658
+ };
659
+ contentType = (_f = MIME_MAP[ext]) !== null && _f !== void 0 ? _f : "application/octet-stream";
660
+ _g.label = 13;
661
+ case 13:
662
+ mediaType_1 = "file";
663
+ if (contentType.startsWith("image/"))
664
+ mediaType_1 = "image";
665
+ else if (contentType.startsWith("audio/"))
666
+ mediaType_1 = "voice";
667
+ else if (contentType.startsWith("video/"))
668
+ mediaType_1 = "video";
669
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] uploading media: " + filename + " (" + mediaType_1 + ", " + contentType + ", " + buf.length + " bytes)");
670
+ return [4 /*yield*/, api_client_js_1.uploadMedia({ agent: agent, type: mediaType_1, buffer: buf, filename: filename })];
671
+ case 14:
672
+ mediaId = _g.sent();
673
+ return [4 /*yield*/, api_client_js_1.sendMedia(__assign({ agent: agent, toUser: fromUser, mediaId: mediaId,
674
+ mediaType: mediaType_1 }, (mediaType_1 === "video" ? { title: filename, description: "" } : {})))];
675
+ case 15:
676
+ _g.sent();
677
+ log === null || log === void 0 ? void 0 : log("[wecom-agent] media sent (" + info.kind + ") to " + fromUser + ": " + filename + " (" + mediaType_1 + ")");
678
+ return [3 /*break*/, 21];
679
+ case 16:
680
+ err_4 = _g.sent();
681
+ message = err_4 instanceof Error ? "" + err_4.message + (err_4.cause ? " (cause: " + String(err_4.cause) + ")" : "") : String(err_4);
682
+ error === null || error === void 0 ? void 0 : error("[wecom-agent] media send failed: " + mediaPath_1 + ": " + message);
683
+ _g.label = 17;
684
+ case 17:
685
+ _g.trys.push([17, 19, , 20]);
686
+ return [4 /*yield*/, api_client_js_1.sendText({ agent: agent, toUser: fromUser, chatId: undefined, text: "\u26A0\uFE0F \u6587\u4EF6\u53D1\u9001\u5931\u8D25: " + (mediaPath_1.split("/").pop() || mediaPath_1) + "\n" + message })];
687
+ case 18:
688
+ _g.sent();
689
+ return [3 /*break*/, 20];
690
+ case 19:
691
+ _c = _g.sent();
692
+ return [3 /*break*/, 20];
693
+ case 20: return [3 /*break*/, 21];
694
+ case 21:
695
+ _i++;
696
+ return [3 /*break*/, 5];
697
+ case 22: return [2 /*return*/];
698
+ }
699
+ });
700
+ }); },
701
+ onError: function (err, info) {
702
+ error === null || error === void 0 ? void 0 : error("[wecom-agent] " + info.kind + " reply error: " + String(err));
703
+ }
704
+ }
705
+ })];
706
+ case 15:
707
+ _f.sent();
708
+ return [2 /*return*/];
709
+ }
710
+ });
711
+ });
712
+ }
713
+ /**
714
+ * **handleAgentWebhook (Agent Webhook 入口)**
715
+ *
716
+ * 统一处理 Agent 模式的 POST 消息回调请求。
717
+ * URL 验证与验签/解密由 monitor 层统一处理后再调用本函数。
718
+ */
719
+ function handleAgentWebhook(params) {
720
+ return __awaiter(this, void 0, void 0, function () {
721
+ var req;
722
+ return __generator(this, function (_a) {
723
+ req = params.req;
724
+ if (req.method === "POST") {
725
+ return [2 /*return*/, handleMessageCallback(params)];
726
+ }
727
+ return [2 /*return*/, false];
728
+ });
729
+ });
730
+ }
731
+ exports.handleAgentWebhook = handleAgentWebhook;