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,936 @@
1
+ "use strict";
2
+ /**
3
+ * Webhook 辅助函数
4
+ *
5
+ * 从 @mocrane/wecom monitor.ts 迁移的辅助工具函数集合。
6
+ * 包含:文本截断、兜底提示构建、本机路径提取、MIME 推断等。
7
+ */
8
+ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
9
+ if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
10
+ return cooked;
11
+ };
12
+ var __assign = (this && this.__assign) || function () {
13
+ __assign = Object.assign || function(t) {
14
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
15
+ s = arguments[i];
16
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
17
+ t[p] = s[p];
18
+ }
19
+ return t;
20
+ };
21
+ return __assign.apply(this, arguments);
22
+ };
23
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
26
+ }) : (function(o, m, k, k2) {
27
+ if (k2 === undefined) k2 = k;
28
+ o[k2] = m[k];
29
+ }));
30
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
31
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
32
+ }) : function(o, v) {
33
+ o["default"] = v;
34
+ });
35
+ var __importStar = (this && this.__importStar) || function (mod) {
36
+ if (mod && mod.__esModule) return mod;
37
+ var result = {};
38
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
39
+ __setModuleDefault(result, mod);
40
+ return result;
41
+ };
42
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
43
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
44
+ return new (P || (P = Promise))(function (resolve, reject) {
45
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
46
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
47
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
48
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
49
+ });
50
+ };
51
+ var __generator = (this && this.__generator) || function (thisArg, body) {
52
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
53
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
54
+ function verb(n) { return function (v) { return step([n, v]); }; }
55
+ function step(op) {
56
+ if (f) throw new TypeError("Generator is already executing.");
57
+ while (_) try {
58
+ 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;
59
+ if (y = 0, t) op = [op[0] & 2, t.value];
60
+ switch (op[0]) {
61
+ case 0: case 1: t = op; break;
62
+ case 4: _.label++; return { value: op[1], done: false };
63
+ case 5: _.label++; y = op[1]; op = [0]; continue;
64
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
65
+ default:
66
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
67
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
68
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
69
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
70
+ if (t[2]) _.ops.pop();
71
+ _.trys.pop(); continue;
72
+ }
73
+ op = body.call(thisArg, _);
74
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
75
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
76
+ }
77
+ };
78
+ var __spreadArrays = (this && this.__spreadArrays) || function () {
79
+ for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
80
+ for (var r = Array(s), k = 0, i = 0; i < il; i++)
81
+ for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
82
+ r[k] = a[j];
83
+ return r;
84
+ };
85
+ var __importDefault = (this && this.__importDefault) || function (mod) {
86
+ return (mod && mod.__esModule) ? mod : { "default": mod };
87
+ };
88
+ exports.__esModule = true;
89
+ exports.buildStreamResponse = exports.buildStreamTextPlaceholderReply = exports.buildStreamPlaceholderReply = exports.hasMedia = exports.formatQuote = exports.buildInboundBody = exports.resolveWecomSenderUserId = exports.buildCfgForDispatch = exports.processInboundMessage = exports.resolveWecomMediaMaxBytes = exports.computeMd5 = exports.buildStreamReplyFromState = exports.guessContentTypeFromPath = exports.isAgentConfigured = exports.computeTaskKey = exports.looksLikeSendLocalFileIntent = exports.extractLocalImagePathsFromText = exports.extractLocalFilePathsFromText = exports.buildFallbackPrompt = exports.appendDmContent = exports.truncateUtf8Bytes = exports.MIME_BY_EXT = exports.STREAM_MAX_DM_BYTES = void 0;
90
+ var node_crypto_1 = __importDefault(require("node:crypto"));
91
+ // ============================================================================
92
+ // 常量
93
+ // ============================================================================
94
+ /** DM 文本最大字节数上限 */
95
+ exports.STREAM_MAX_DM_BYTES = 200000;
96
+ /** MIME 扩展名映射表 */
97
+ exports.MIME_BY_EXT = {
98
+ png: "image/png",
99
+ jpg: "image/jpeg",
100
+ jpeg: "image/jpeg",
101
+ gif: "image/gif",
102
+ webp: "image/webp",
103
+ bmp: "image/bmp",
104
+ pdf: "application/pdf",
105
+ txt: "text/plain",
106
+ csv: "text/csv",
107
+ tsv: "text/tab-separated-values",
108
+ md: "text/markdown",
109
+ json: "application/json",
110
+ xml: "application/xml",
111
+ yaml: "application/yaml",
112
+ yml: "application/yaml",
113
+ zip: "application/zip",
114
+ rar: "application/vnd.rar",
115
+ "7z": "application/x-7z-compressed",
116
+ tar: "application/x-tar",
117
+ gz: "application/gzip",
118
+ tgz: "application/gzip",
119
+ doc: "application/msword",
120
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
121
+ xls: "application/vnd.ms-excel",
122
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
123
+ ppt: "application/vnd.ms-powerpoint",
124
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
125
+ rtf: "application/rtf",
126
+ odt: "application/vnd.oasis.opendocument.text",
127
+ mp3: "audio/mpeg",
128
+ wav: "audio/wav",
129
+ ogg: "audio/ogg",
130
+ amr: "voice/amr",
131
+ m4a: "audio/mp4",
132
+ mp4: "video/mp4",
133
+ mov: "video/quicktime"
134
+ };
135
+ // ============================================================================
136
+ // 文本处理
137
+ // ============================================================================
138
+ /**
139
+ * UTF-8 字节截断(保留尾部,截断头部)
140
+ *
141
+ * 对齐原版 truncateUtf8Bytes:保留最后 maxBytes 字节。
142
+ */
143
+ function truncateUtf8Bytes(text, maxBytes) {
144
+ var buf = Buffer.from(text, "utf8");
145
+ if (buf.length <= maxBytes)
146
+ return text;
147
+ var slice = buf.subarray(buf.length - maxBytes);
148
+ return slice.toString("utf8");
149
+ }
150
+ exports.truncateUtf8Bytes = truncateUtf8Bytes;
151
+ /**
152
+ * 追加 DM 兜底内容(对齐原版 appendDmContent)
153
+ *
154
+ * 每次 deliver 时都追加到 dmContent(不受 STREAM_MAX_BYTES 限制,有 DM 上限保护)
155
+ */
156
+ function appendDmContent(state, text) {
157
+ var next = state.dmContent ? (state.dmContent + "\n\n" + text).trim() : text.trim();
158
+ state.dmContent = truncateUtf8Bytes(next, exports.STREAM_MAX_DM_BYTES);
159
+ }
160
+ exports.appendDmContent = appendDmContent;
161
+ // ============================================================================
162
+ // 兜底提示
163
+ // ============================================================================
164
+ /**
165
+ * 构建兜底提示文本(对齐原版 buildFallbackPrompt)
166
+ */
167
+ function buildFallbackPrompt(params) {
168
+ var who = params.userId ? "\uFF08" + params.userId + "\uFF09" : "";
169
+ var scope = params.chatType === "group" ? "群聊" : params.chatType === "direct" ? "私聊" : "会话";
170
+ if (!params.agentConfigured) {
171
+ return (scope + "\u4E2D\u9700\u8981\u901A\u8FC7\u5E94\u7528\u79C1\u4FE1\u53D1\u9001" + (params.filename ? "\uFF08" + params.filename + "\uFF09" : "") + "\uFF0C\u4F46\u7BA1\u7406\u5458\u5C1A\u672A\u914D\u7F6E\u4F01\u4E1A\u5FAE\u4FE1\u81EA\u5EFA\u5E94\u7528\uFF08Agent\uFF09\u901A\u9053\u3002\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u914D\u7F6E\u540E\u518D\u8BD5\u3002" + who).trim();
172
+ }
173
+ if (!params.userId) {
174
+ return (scope + "\u4E2D\u9700\u8981\u901A\u8FC7\u5E94\u7528\u79C1\u4FE1\u515C\u5E95\u53D1\u9001" + (params.filename ? "\uFF08" + params.filename + "\uFF09" : "") + "\uFF0C\u4F46\u672C\u6B21\u56DE\u8C03\u672A\u80FD\u8BC6\u522B\u89E6\u53D1\u8005 userid\uFF08\u8BF7\u68C0\u67E5\u4F01\u5FAE\u56DE\u8C03\u5B57\u6BB5 from.userid / fromuserid\uFF09\u3002\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6392\u67E5\u914D\u7F6E\u3002").trim();
175
+ }
176
+ if (params.kind === "media") {
177
+ return ("\u5DF2\u751F\u6210\u6587\u4EF6" + (params.filename ? "\uFF08" + params.filename + "\uFF09" : "") + "\uFF0C\u5C06\u901A\u8FC7\u5E94\u7528\u79C1\u4FE1\u53D1\u9001\u7ED9\u4F60\u3002" + who).trim();
178
+ }
179
+ if (params.kind === "timeout") {
180
+ return ("\u5185\u5BB9\u8F83\u957F\uFF0C\u4E3A\u907F\u514D\u8D85\u65F6\uFF0C\u540E\u7EED\u5185\u5BB9\u5C06\u901A\u8FC7\u5E94\u7528\u79C1\u4FE1\u53D1\u9001\u7ED9\u4F60\u3002" + who).trim();
181
+ }
182
+ return ("\u4EA4\u4ED8\u51FA\u73B0\u5F02\u5E38\uFF0C\u5DF2\u5C1D\u8BD5\u901A\u8FC7\u5E94\u7528\u79C1\u4FE1\u53D1\u9001\u7ED9\u4F60\u3002" + who).trim();
183
+ }
184
+ exports.buildFallbackPrompt = buildFallbackPrompt;
185
+ // ============================================================================
186
+ // 本机路径提取
187
+ // ============================================================================
188
+ /**
189
+ * 从文本中提取本机文件路径(对齐原版 extractLocalFilePathsFromText)
190
+ */
191
+ function extractLocalFilePathsFromText(text) {
192
+ if (!text.trim())
193
+ return [];
194
+ var re = new RegExp(String.raw(templateObject_1 || (templateObject_1 = __makeTemplateObject(["(/(?:Users|tmp|root|home)/[^s\"'<>\u3000-\u303F\uFF00-\uFFEF\u4E00-\u9FFF\u3400-\u4DBF]+)"], ["(\\/(?:Users|tmp|root|home)\\/[^\\s\"'<>\\u3000-\\u303F\\uFF00-\\uFFEF\\u4E00-\\u9FFF\\u3400-\\u4DBF]+)"]))), "g");
195
+ var found = new Set();
196
+ var m;
197
+ while ((m = re.exec(text))) {
198
+ var p = m[1];
199
+ if (p)
200
+ found.add(p);
201
+ }
202
+ return Array.from(found);
203
+ }
204
+ exports.extractLocalFilePathsFromText = extractLocalFilePathsFromText;
205
+ /**
206
+ * 从文本中提取本机图片路径(对齐原版 extractLocalImagePathsFromText)
207
+ *
208
+ * 仅提取 text 中存在且也出现在 mustAlsoAppearIn 中的路径(安全:防止泄漏)
209
+ */
210
+ function extractLocalImagePathsFromText(params) {
211
+ var text = params.text, mustAlsoAppearIn = params.mustAlsoAppearIn;
212
+ if (!text.trim())
213
+ return [];
214
+ var exts = "(png|jpg|jpeg|gif|webp|bmp)";
215
+ var re = new RegExp(String.raw(templateObject_2 || (templateObject_2 = __makeTemplateObject(["(/(?:Users|tmp|root|home)/[^s\"'<>]+?.", ")"], ["(\\/(?:Users|tmp|root|home)\\/[^\\s\"'<>]+?\\.", ")"])), exts), "gi");
216
+ var found = new Set();
217
+ var m;
218
+ while ((m = re.exec(text))) {
219
+ var p = m[1];
220
+ if (!p)
221
+ continue;
222
+ if (!mustAlsoAppearIn.includes(p))
223
+ continue;
224
+ found.add(p);
225
+ }
226
+ return Array.from(found);
227
+ }
228
+ exports.extractLocalImagePathsFromText = extractLocalImagePathsFromText;
229
+ /**
230
+ * 判断文本是否包含"发送本机文件"的意图(对齐原版 looksLikeSendLocalFileIntent)
231
+ */
232
+ function looksLikeSendLocalFileIntent(rawBody) {
233
+ var t = rawBody.trim();
234
+ if (!t)
235
+ return false;
236
+ return /(发送|发给|发到|转发|把.*发|把.*发送|帮我发|给我发)/.test(t);
237
+ }
238
+ exports.looksLikeSendLocalFileIntent = looksLikeSendLocalFileIntent;
239
+ // ============================================================================
240
+ // taskKey 与 Agent 配置
241
+ // ============================================================================
242
+ /**
243
+ * 计算 taskKey(对齐原版 computeTaskKey)
244
+ */
245
+ function computeTaskKey(target, msg) {
246
+ var _a;
247
+ var msgid = msg.msgid ? String(msg.msgid) : "";
248
+ if (!msgid)
249
+ return undefined;
250
+ var aibotid = String((_a = msg.aibotid) !== null && _a !== void 0 ? _a : "unknown").trim() || "unknown";
251
+ return "bot:" + target.account.accountId + ":" + aibotid + ":" + msgid;
252
+ }
253
+ exports.computeTaskKey = computeTaskKey;
254
+ /**
255
+ * 检查 Agent 凭证是否已配置(对齐原版 resolveAgentAccountOrUndefined 的简化版)
256
+ *
257
+ * 在 webhook 模式下,Agent 凭证直接来自 target.account,不需要复杂的解析
258
+ */
259
+ function isAgentConfigured(target) {
260
+ var _a;
261
+ return Boolean((_a = target.account.agent) === null || _a === void 0 ? void 0 : _a.configured);
262
+ }
263
+ exports.isAgentConfigured = isAgentConfigured;
264
+ /**
265
+ * 从路径猜测 content-type
266
+ */
267
+ function guessContentTypeFromPath(filePath) {
268
+ var _a;
269
+ var ext = (_a = filePath.split(".").pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
270
+ if (!ext)
271
+ return undefined;
272
+ return exports.MIME_BY_EXT[ext];
273
+ }
274
+ exports.guessContentTypeFromPath = guessContentTypeFromPath;
275
+ // ============================================================================
276
+ // Stream Reply 构建
277
+ // ============================================================================
278
+ /**
279
+ * 从 StreamState 构建最终流式回复(对齐原版 buildStreamReplyFromState)
280
+ *
281
+ * 包含 images/msg_item,对 content 做 truncateUtf8Bytes。
282
+ */
283
+ function buildStreamReplyFromState(state, maxBytes) {
284
+ var _a;
285
+ var content = truncateUtf8Bytes(state.content, maxBytes);
286
+ var result = {
287
+ msgtype: "stream",
288
+ stream: __assign({ id: state.streamId, finish: state.finished, content: content }, (state.finished && ((_a = state.images) === null || _a === void 0 ? void 0 : _a.length) ? {
289
+ msg_item: state.images.map(function (img) { return ({
290
+ msgtype: "image",
291
+ image: { base64: img.base64, md5: img.md5 }
292
+ }); })
293
+ } : {}))
294
+ };
295
+ return result;
296
+ }
297
+ exports.buildStreamReplyFromState = buildStreamReplyFromState;
298
+ /**
299
+ * 计算 MD5
300
+ */
301
+ function computeMd5(data) {
302
+ return node_crypto_1["default"].createHash("md5").update(data).digest("hex");
303
+ }
304
+ exports.computeMd5 = computeMd5;
305
+ // ============================================================================
306
+ // 配置解析
307
+ // ============================================================================
308
+ /**
309
+ * 解析媒体最大字节数(对齐原版 resolveWecomMediaMaxBytes)
310
+ */
311
+ function resolveWecomMediaMaxBytes(cfg) {
312
+ var _a, _b, _c;
313
+ var val = (_c = (_b = (_a = cfg.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;
314
+ if (typeof val === "number" && Number.isFinite(val) && val > 0)
315
+ return val;
316
+ return 20 * 1024 * 1024; // 默认 20MB
317
+ }
318
+ exports.resolveWecomMediaMaxBytes = resolveWecomMediaMaxBytes;
319
+ /**
320
+ * 处理接收消息(对齐原版 processInboundMessage)
321
+ *
322
+ * 解析企业微信传入的消息体:
323
+ * 1. 识别媒体消息(Image/File/Video/Mixed)
324
+ * 2. 如果存在媒体文件,调用 media.ts 进行解密和下载
325
+ * 3. 通过 inferInboundMediaMeta 精确推断 MIME 和文件名
326
+ * 4. 构造统一的 InboundResult 供后续 Agent 处理
327
+ *
328
+ * @param target Webhook 目标配置
329
+ * @param msg 企业微信原始消息对象
330
+ */
331
+ function processInboundMessage(target, msg) {
332
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2;
333
+ return __awaiter(this, void 0, void 0, function () {
334
+ var decryptWecomMediaWithMeta, resolveWecomEgressProxyUrl, msgtype, globalAesKey, maxBytes, proxyUrl, url, aesKey, decrypted, inferred, err_1, errorMessage, url, aesKey, decrypted, inferred, err_2, errorMessage, url, aesKey, decrypted, inferred, err_3, errorMessage, items, foundMedia, bodyParts, _i, items_1, item, t, content, itemAesKey, url, decrypted, inferred, err_4, errorMessage;
335
+ return __generator(this, function (_3) {
336
+ switch (_3.label) {
337
+ case 0: return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("./media.js")); })];
338
+ case 1:
339
+ decryptWecomMediaWithMeta = (_3.sent()).decryptWecomMediaWithMeta;
340
+ return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("../utils.js")); })];
341
+ case 2:
342
+ resolveWecomEgressProxyUrl = (_3.sent()).resolveWecomEgressProxyUrl;
343
+ msgtype = String((_a = msg.msgtype) !== null && _a !== void 0 ? _a : "").toLowerCase();
344
+ globalAesKey = target.account.encodingAESKey;
345
+ maxBytes = resolveWecomMediaMaxBytes(target.config);
346
+ proxyUrl = resolveWecomEgressProxyUrl(target.config);
347
+ if (!(msgtype === "image")) return [3 /*break*/, 6];
348
+ url = String((_c = (_b = msg.image) === null || _b === void 0 ? void 0 : _b.url) !== null && _c !== void 0 ? _c : "").trim();
349
+ aesKey = globalAesKey || ((_d = msg.image) === null || _d === void 0 ? void 0 : _d.aeskey) || "";
350
+ if (!(url && aesKey)) return [3 /*break*/, 6];
351
+ _3.label = 3;
352
+ case 3:
353
+ _3.trys.push([3, 5, , 6]);
354
+ return [4 /*yield*/, decryptWecomMediaWithMeta(url, aesKey, { maxBytes: maxBytes, http: { proxyUrl: proxyUrl } })];
355
+ case 4:
356
+ decrypted = _3.sent();
357
+ inferred = inferInboundMediaMeta({
358
+ kind: "image",
359
+ buffer: decrypted.buffer,
360
+ sourceUrl: decrypted.sourceUrl || url,
361
+ sourceContentType: decrypted.sourceContentType,
362
+ sourceFilename: decrypted.sourceFilename,
363
+ explicitFilename: pickBotFileName(msg)
364
+ });
365
+ return [2 /*return*/, {
366
+ body: "[image]",
367
+ media: {
368
+ buffer: decrypted.buffer,
369
+ contentType: inferred.contentType,
370
+ filename: inferred.filename
371
+ }
372
+ }];
373
+ case 5:
374
+ err_1 = _3.sent();
375
+ (_f = (_e = target.runtime).error) === null || _f === void 0 ? void 0 : _f.call(_e, "Failed to decrypt inbound image: " + String(err_1));
376
+ (_h = (_g = target.runtime).error) === null || _h === void 0 ? void 0 : _h.call(_g, "\u56FE\u7247\u89E3\u5BC6\u5931\u8D25: " + String(err_1) + "; \u53EF\u8C03\u5927 channels.wecom.media.maxBytes\uFF08\u5F53\u524D=" + maxBytes + "\uFF09\u4F8B\u5982\uFF1Aopenclaw config set channels.wecom.media.maxBytes " + 50 * 1024 * 1024);
377
+ errorMessage = formatDecryptError(err_1);
378
+ return [2 /*return*/, { body: "[image] (decryption failed: " + errorMessage + ")" }];
379
+ case 6:
380
+ if (!(msgtype === "file")) return [3 /*break*/, 10];
381
+ url = String((_k = (_j = msg.file) === null || _j === void 0 ? void 0 : _j.url) !== null && _k !== void 0 ? _k : "").trim();
382
+ aesKey = globalAesKey || ((_l = msg.file) === null || _l === void 0 ? void 0 : _l.aeskey) || "";
383
+ if (!(url && aesKey)) return [3 /*break*/, 10];
384
+ _3.label = 7;
385
+ case 7:
386
+ _3.trys.push([7, 9, , 10]);
387
+ return [4 /*yield*/, decryptWecomMediaWithMeta(url, aesKey, { maxBytes: maxBytes, http: { proxyUrl: proxyUrl } })];
388
+ case 8:
389
+ decrypted = _3.sent();
390
+ inferred = inferInboundMediaMeta({
391
+ kind: "file",
392
+ buffer: decrypted.buffer,
393
+ sourceUrl: decrypted.sourceUrl || url,
394
+ sourceContentType: decrypted.sourceContentType,
395
+ sourceFilename: decrypted.sourceFilename,
396
+ explicitFilename: pickBotFileName(msg)
397
+ });
398
+ return [2 /*return*/, {
399
+ body: "[file]",
400
+ media: {
401
+ buffer: decrypted.buffer,
402
+ contentType: inferred.contentType,
403
+ filename: inferred.filename
404
+ }
405
+ }];
406
+ case 9:
407
+ err_2 = _3.sent();
408
+ (_o = (_m = target.runtime).error) === null || _o === void 0 ? void 0 : _o.call(_m, "Failed to decrypt inbound file: " + String(err_2) + "; \u53EF\u8C03\u5927 channels.wecom.media.maxBytes\uFF08\u5F53\u524D=" + maxBytes + "\uFF09\u4F8B\u5982\uFF1Aopenclaw config set channels.wecom.media.maxBytes " + 50 * 1024 * 1024);
409
+ errorMessage = formatDecryptError(err_2);
410
+ return [2 /*return*/, { body: "[file] (decryption failed: " + errorMessage + ")" }];
411
+ case 10:
412
+ if (!(msgtype === "video")) return [3 /*break*/, 14];
413
+ url = String((_q = (_p = msg.video) === null || _p === void 0 ? void 0 : _p.url) !== null && _q !== void 0 ? _q : "").trim();
414
+ aesKey = globalAesKey || ((_r = msg.video) === null || _r === void 0 ? void 0 : _r.aeskey) || "";
415
+ if (!(url && aesKey)) return [3 /*break*/, 14];
416
+ _3.label = 11;
417
+ case 11:
418
+ _3.trys.push([11, 13, , 14]);
419
+ return [4 /*yield*/, decryptWecomMediaWithMeta(url, aesKey, { maxBytes: maxBytes, http: { proxyUrl: proxyUrl } })];
420
+ case 12:
421
+ decrypted = _3.sent();
422
+ inferred = inferInboundMediaMeta({
423
+ kind: "file",
424
+ buffer: decrypted.buffer,
425
+ sourceUrl: decrypted.sourceUrl || url,
426
+ sourceContentType: decrypted.sourceContentType,
427
+ sourceFilename: decrypted.sourceFilename,
428
+ explicitFilename: pickBotFileName(msg)
429
+ });
430
+ return [2 /*return*/, {
431
+ body: "[video] \u89C6\u9891\u6587\u4EF6\u5DF2\u4FDD\u5B58\uFF0C\u6587\u4EF6\u540D: " + inferred.filename,
432
+ media: {
433
+ buffer: decrypted.buffer,
434
+ contentType: inferred.contentType,
435
+ filename: inferred.filename
436
+ }
437
+ }];
438
+ case 13:
439
+ err_3 = _3.sent();
440
+ (_t = (_s = target.runtime).error) === null || _t === void 0 ? void 0 : _t.call(_s, "Failed to decrypt inbound video: " + String(err_3) + "; \u53EF\u8C03\u5927 channels.wecom.media.maxBytes\uFF08\u5F53\u524D=" + maxBytes + "\uFF09\u4F8B\u5982\uFF1Aopenclaw config set channels.wecom.media.maxBytes " + 50 * 1024 * 1024);
441
+ errorMessage = formatDecryptError(err_3);
442
+ return [2 /*return*/, { body: "[video] (decryption failed: " + errorMessage + ")" }];
443
+ case 14:
444
+ if (!(msgtype === "mixed")) return [3 /*break*/, 27];
445
+ items = (_u = msg.mixed) === null || _u === void 0 ? void 0 : _u.msg_item;
446
+ if (!Array.isArray(items)) return [3 /*break*/, 27];
447
+ foundMedia = undefined;
448
+ bodyParts = [];
449
+ _i = 0, items_1 = items;
450
+ _3.label = 15;
451
+ case 15:
452
+ if (!(_i < items_1.length)) return [3 /*break*/, 26];
453
+ item = items_1[_i];
454
+ t = String((_v = item.msgtype) !== null && _v !== void 0 ? _v : "").toLowerCase();
455
+ if (!(t === "text")) return [3 /*break*/, 16];
456
+ content = String((_x = (_w = item.text) === null || _w === void 0 ? void 0 : _w.content) !== null && _x !== void 0 ? _x : "").trim();
457
+ if (content)
458
+ bodyParts.push(content);
459
+ return [3 /*break*/, 25];
460
+ case 16:
461
+ if (!((t === "image" || t === "file") && !foundMedia)) return [3 /*break*/, 24];
462
+ itemAesKey = globalAesKey || ((_y = item[t]) === null || _y === void 0 ? void 0 : _y.aeskey) || "";
463
+ url = String((_0 = (_z = item[t]) === null || _z === void 0 ? void 0 : _z.url) !== null && _0 !== void 0 ? _0 : "").trim();
464
+ if (!!itemAesKey) return [3 /*break*/, 17];
465
+ bodyParts.push("[" + t + "]");
466
+ return [3 /*break*/, 23];
467
+ case 17:
468
+ if (!url) return [3 /*break*/, 22];
469
+ _3.label = 18;
470
+ case 18:
471
+ _3.trys.push([18, 20, , 21]);
472
+ return [4 /*yield*/, decryptWecomMediaWithMeta(url, itemAesKey, { maxBytes: maxBytes, http: { proxyUrl: proxyUrl } })];
473
+ case 19:
474
+ decrypted = _3.sent();
475
+ inferred = inferInboundMediaMeta({
476
+ kind: t,
477
+ buffer: decrypted.buffer,
478
+ sourceUrl: decrypted.sourceUrl || url,
479
+ sourceContentType: decrypted.sourceContentType,
480
+ sourceFilename: decrypted.sourceFilename,
481
+ explicitFilename: pickBotFileName(msg, item === null || item === void 0 ? void 0 : item[t])
482
+ });
483
+ foundMedia = {
484
+ buffer: decrypted.buffer,
485
+ contentType: inferred.contentType,
486
+ filename: inferred.filename
487
+ };
488
+ bodyParts.push("[" + t + "]");
489
+ return [3 /*break*/, 21];
490
+ case 20:
491
+ err_4 = _3.sent();
492
+ (_2 = (_1 = target.runtime).error) === null || _2 === void 0 ? void 0 : _2.call(_1, "Failed to decrypt mixed " + t + ": " + String(err_4) + "; \u53EF\u8C03\u5927 channels.wecom.media.maxBytes\uFF08\u5F53\u524D=" + maxBytes + "\uFF09\u4F8B\u5982\uFF1Aopenclaw config set channels.wecom.media.maxBytes " + 50 * 1024 * 1024);
493
+ errorMessage = formatDecryptError(err_4);
494
+ bodyParts.push("[" + t + "] (decryption failed: " + errorMessage + ")");
495
+ return [3 /*break*/, 21];
496
+ case 21: return [3 /*break*/, 23];
497
+ case 22:
498
+ bodyParts.push("[" + t + "]");
499
+ _3.label = 23;
500
+ case 23: return [3 /*break*/, 25];
501
+ case 24:
502
+ bodyParts.push("[" + t + "]");
503
+ _3.label = 25;
504
+ case 25:
505
+ _i++;
506
+ return [3 /*break*/, 15];
507
+ case 26: return [2 /*return*/, {
508
+ body: bodyParts.join("\n"),
509
+ media: foundMedia
510
+ }];
511
+ case 27:
512
+ // 其他消息类型:使用 buildInboundBody 构建文本表示
513
+ return [2 /*return*/, { body: buildInboundBody(msg) }];
514
+ }
515
+ });
516
+ });
517
+ }
518
+ exports.processInboundMessage = processInboundMessage;
519
+ // ============================================================================
520
+ // processInboundMessage 依赖的辅助函数
521
+ // ============================================================================
522
+ /** 格式化解密错误信息(对齐原版格式:message + cause) */
523
+ function formatDecryptError(err) {
524
+ var _a;
525
+ if (typeof err === "object" && err) {
526
+ var msg = (_a = err.message) !== null && _a !== void 0 ? _a : String(err);
527
+ var cause = err.cause;
528
+ return cause ? msg + " (cause: " + String(cause) + ")" : String(msg);
529
+ }
530
+ return String(err);
531
+ }
532
+ /** 从消息中提取显式文件名(对齐原版 pickBotFileName) */
533
+ function pickBotFileName(msg, item) {
534
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
535
+ var fromItem = item
536
+ ? resolveInlineFileName((_d = (_c = (_b = (_a = item === null || item === void 0 ? void 0 : item.filename) !== null && _a !== void 0 ? _a : item === null || item === void 0 ? void 0 : item.file_name) !== null && _b !== void 0 ? _b : item === null || item === void 0 ? void 0 : item.fileName) !== null && _c !== void 0 ? _c : item === null || item === void 0 ? void 0 : item.name) !== null && _d !== void 0 ? _d : item === null || item === void 0 ? void 0 : item.title)
537
+ : undefined;
538
+ if (fromItem)
539
+ return fromItem;
540
+ var fromFile = resolveInlineFileName((_y = (_w = (_u = (_r = (_o = (_k = (_g = (_f = (_e = msg) === null || _e === void 0 ? void 0 : _e.file) === null || _f === void 0 ? void 0 : _f.filename) !== null && _g !== void 0 ? _g : (_j = (_h = msg) === null || _h === void 0 ? void 0 : _h.file) === null || _j === void 0 ? void 0 : _j.file_name) !== null && _k !== void 0 ? _k : (_m = (_l = msg) === null || _l === void 0 ? void 0 : _l.file) === null || _m === void 0 ? void 0 : _m.fileName) !== null && _o !== void 0 ? _o : (_q = (_p = msg) === null || _p === void 0 ? void 0 : _p.file) === null || _q === void 0 ? void 0 : _q.name) !== null && _r !== void 0 ? _r : (_t = (_s = msg) === null || _s === void 0 ? void 0 : _s.file) === null || _t === void 0 ? void 0 : _t.title) !== null && _u !== void 0 ? _u : (_v = msg) === null || _v === void 0 ? void 0 : _v.filename) !== null && _w !== void 0 ? _w : (_x = msg) === null || _x === void 0 ? void 0 : _x.fileName) !== null && _y !== void 0 ? _y : (_z = msg) === null || _z === void 0 ? void 0 : _z.FileName);
541
+ return fromFile;
542
+ }
543
+ function resolveInlineFileName(input) {
544
+ var raw = String(input !== null && input !== void 0 ? input : "").trim();
545
+ return sanitizeInboundFilename(raw);
546
+ }
547
+ /** 清理文件名(移除非法字符) */
548
+ function sanitizeInboundFilename(raw) {
549
+ var _a, _b;
550
+ var s = String(raw !== null && raw !== void 0 ? raw : "").trim();
551
+ if (!s)
552
+ return undefined;
553
+ var base = (_b = (_a = s.split(/[\\/]/).pop()) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : "";
554
+ if (!base)
555
+ return undefined;
556
+ var sanitized = base.replace(/[\u0000-\u001f<>:"|?*]/g, "_").trim();
557
+ return sanitized || undefined;
558
+ }
559
+ /** 从 URL 中提取文件名 */
560
+ function extractFileNameFromUrl(rawUrl) {
561
+ var _a;
562
+ var s = String(rawUrl !== null && rawUrl !== void 0 ? rawUrl : "").trim();
563
+ if (!s)
564
+ return undefined;
565
+ try {
566
+ var u = new URL(s);
567
+ var name = decodeURIComponent((_a = u.pathname.split("/").pop()) !== null && _a !== void 0 ? _a : "").trim();
568
+ return name || undefined;
569
+ }
570
+ catch (_b) {
571
+ return undefined;
572
+ }
573
+ }
574
+ /** 检查文件名是否有常见扩展名 */
575
+ function hasLikelyExtension(name) {
576
+ if (!name)
577
+ return false;
578
+ return /\.[a-z0-9]{1,16}$/i.test(name);
579
+ }
580
+ /** 归一化 Content-Type */
581
+ function normalizeContentType(raw) {
582
+ var _a;
583
+ var normalized = (_a = String(raw !== null && raw !== void 0 ? raw : "").trim().split(";")[0]) === null || _a === void 0 ? void 0 : _a.trim().toLowerCase();
584
+ return normalized || undefined;
585
+ }
586
+ var GENERIC_CONTENT_TYPES = new Set([
587
+ "application/octet-stream",
588
+ "binary/octet-stream",
589
+ "application/download",
590
+ ]);
591
+ function isGenericContentType(raw) {
592
+ var normalized = normalizeContentType(raw);
593
+ if (!normalized)
594
+ return true;
595
+ return GENERIC_CONTENT_TYPES.has(normalized);
596
+ }
597
+ var EXT_BY_MIME = __assign(__assign({}, Object.fromEntries(Object.entries(exports.MIME_BY_EXT).map(function (_a) {
598
+ var ext = _a[0], mime = _a[1];
599
+ return [mime, ext];
600
+ }))), { "application/octet-stream": "bin" });
601
+ /** 从 Content-Type 反推扩展名 */
602
+ function guessExtensionFromContentType(contentType) {
603
+ var normalized = normalizeContentType(contentType);
604
+ if (!normalized)
605
+ return undefined;
606
+ if (normalized === "image/jpeg")
607
+ return "jpg";
608
+ return EXT_BY_MIME[normalized];
609
+ }
610
+ /**
611
+ * 从 Buffer magic bytes 检测 MIME(对齐原版 detectMimeFromBuffer)
612
+ *
613
+ * 注意:这是同步版本,用于 inferInboundMediaMeta 中的快速检测。
614
+ * 与 media.ts 中的 async detectMimeFromBuffer 不同,不使用 file-type 库。
615
+ */
616
+ function detectMimeFromBufferSync(buffer) {
617
+ var _a;
618
+ if (!buffer || buffer.length < 4)
619
+ return undefined;
620
+ // PNG
621
+ if (buffer.length >= 8 &&
622
+ buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4e && buffer[3] === 0x47 &&
623
+ buffer[4] === 0x0d && buffer[5] === 0x0a && buffer[6] === 0x1a && buffer[7] === 0x0a)
624
+ return "image/png";
625
+ // JPEG
626
+ if (buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff)
627
+ return "image/jpeg";
628
+ // GIF
629
+ if (buffer.subarray(0, 6).toString("ascii") === "GIF87a" || buffer.subarray(0, 6).toString("ascii") === "GIF89a")
630
+ return "image/gif";
631
+ // WEBP
632
+ if (buffer.length >= 12 && buffer.subarray(0, 4).toString("ascii") === "RIFF" && buffer.subarray(8, 12).toString("ascii") === "WEBP")
633
+ return "image/webp";
634
+ // BMP
635
+ if (buffer[0] === 0x42 && buffer[1] === 0x4d)
636
+ return "image/bmp";
637
+ // PDF
638
+ if (buffer.subarray(0, 5).toString("ascii") === "%PDF-")
639
+ return "application/pdf";
640
+ // OGG
641
+ if (buffer.subarray(0, 4).toString("ascii") === "OggS")
642
+ return "audio/ogg";
643
+ // WAV
644
+ if (buffer.length >= 12 && buffer.subarray(0, 4).toString("ascii") === "RIFF" && buffer.subarray(8, 12).toString("ascii") === "WAVE")
645
+ return "audio/wav";
646
+ // MP3
647
+ if (buffer.subarray(0, 3).toString("ascii") === "ID3" || (buffer[0] === 0xff && (((_a = buffer[1]) !== null && _a !== void 0 ? _a : 0) & 0xe0) === 0xe0))
648
+ return "audio/mpeg";
649
+ // MP4/MOV family
650
+ if (buffer.length >= 12 && buffer.subarray(4, 8).toString("ascii") === "ftyp")
651
+ return "video/mp4";
652
+ // Legacy Office (OLE Compound File)
653
+ if (buffer.length >= 8 &&
654
+ buffer[0] === 0xd0 && buffer[1] === 0xcf && buffer[2] === 0x11 && buffer[3] === 0xe0 &&
655
+ buffer[4] === 0xa1 && buffer[5] === 0xb1 && buffer[6] === 0x1a && buffer[7] === 0xe1)
656
+ return "application/msword";
657
+ // ZIP / OOXML
658
+ var zipMagic = (buffer[0] === 0x50 && buffer[1] === 0x4b && buffer[2] === 0x03 && buffer[3] === 0x04) ||
659
+ (buffer[0] === 0x50 && buffer[1] === 0x4b && buffer[2] === 0x05 && buffer[3] === 0x06) ||
660
+ (buffer[0] === 0x50 && buffer[1] === 0x4b && buffer[2] === 0x07 && buffer[3] === 0x08);
661
+ if (zipMagic) {
662
+ var probe = buffer.subarray(0, Math.min(buffer.length, 512 * 1024));
663
+ if (probe.includes(Buffer.from("word/")))
664
+ return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
665
+ if (probe.includes(Buffer.from("xl/")))
666
+ return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
667
+ if (probe.includes(Buffer.from("ppt/")))
668
+ return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
669
+ return "application/zip";
670
+ }
671
+ // Plain text heuristic
672
+ var sample = buffer.subarray(0, Math.min(buffer.length, 4096));
673
+ var printable = 0;
674
+ for (var _i = 0, sample_1 = sample; _i < sample_1.length; _i++) {
675
+ var b = sample_1[_i];
676
+ if (b === 0x00)
677
+ return undefined;
678
+ if (b === 0x09 || b === 0x0a || b === 0x0d || (b >= 0x20 && b <= 0x7e)) {
679
+ printable += 1;
680
+ }
681
+ }
682
+ if (sample.length > 0 && printable / sample.length > 0.95)
683
+ return "text/plain";
684
+ return undefined;
685
+ }
686
+ /**
687
+ * 推断入站媒体的 MIME 和文件名(对齐原版 inferInboundMediaMeta)
688
+ *
689
+ * 优先级链:magic bytes > HTTP header > URL 路径 > 文件名扩展 > 默认值
690
+ */
691
+ function inferInboundMediaMeta(params) {
692
+ var headerType = normalizeContentType(params.sourceContentType);
693
+ var magicType = detectMimeFromBufferSync(params.buffer);
694
+ var rawUrlName = sanitizeInboundFilename(extractFileNameFromUrl(params.sourceUrl));
695
+ var guessedByUrl = hasLikelyExtension(rawUrlName) ? rawUrlName : undefined;
696
+ var explicitName = sanitizeInboundFilename(params.explicitFilename);
697
+ var sourceName = sanitizeInboundFilename(params.sourceFilename);
698
+ var chosenName = explicitName || sourceName || guessedByUrl;
699
+ var typeByName = chosenName ? guessContentTypeFromPath(chosenName) : undefined;
700
+ var contentType;
701
+ if (params.kind === "image") {
702
+ if (magicType === null || magicType === void 0 ? void 0 : magicType.startsWith("image/"))
703
+ contentType = magicType;
704
+ else if (headerType === null || headerType === void 0 ? void 0 : headerType.startsWith("image/"))
705
+ contentType = headerType;
706
+ else if (typeByName === null || typeByName === void 0 ? void 0 : typeByName.startsWith("image/"))
707
+ contentType = typeByName;
708
+ else
709
+ contentType = "image/jpeg";
710
+ }
711
+ else {
712
+ contentType =
713
+ magicType ||
714
+ (!isGenericContentType(headerType) ? headerType : undefined) ||
715
+ typeByName ||
716
+ "application/octet-stream";
717
+ }
718
+ var hasExt = Boolean(chosenName && /\.[a-z0-9]{1,16}$/i.test(chosenName));
719
+ var ext = guessExtensionFromContentType(contentType) || (params.kind === "image" ? "jpg" : "bin");
720
+ var filename = chosenName
721
+ ? (hasExt ? chosenName : chosenName + "." + ext)
722
+ : params.kind + "." + ext;
723
+ return { contentType: contentType, filename: filename };
724
+ }
725
+ // ============================================================================
726
+ // 配置解析
727
+ // ============================================================================
728
+ /**
729
+ * 构建 Agent 调度所需的 config(对齐原版 cfgForDispatch 逻辑)
730
+ *
731
+ * 关键修改:
732
+ * - tools.deny += "message"(防止 Agent 绕过 Bot 交付)
733
+ * - blockStreamingChunk / blockStreamingCoalesce 使用更小的阈值
734
+ */
735
+ function buildCfgForDispatch(config) {
736
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
737
+ var baseAgents = (_b = (_a = config) === null || _a === void 0 ? void 0 : _a.agents) !== null && _b !== void 0 ? _b : {};
738
+ var baseAgentDefaults = (_d = (_c = baseAgents) === null || _c === void 0 ? void 0 : _c.defaults) !== null && _d !== void 0 ? _d : {};
739
+ var baseBlockChunk = (_f = (_e = baseAgentDefaults) === null || _e === void 0 ? void 0 : _e.blockStreamingChunk) !== null && _f !== void 0 ? _f : {};
740
+ var baseBlockCoalesce = (_h = (_g = baseAgentDefaults) === null || _g === void 0 ? void 0 : _g.blockStreamingCoalesce) !== null && _h !== void 0 ? _h : {};
741
+ var baseTools = (_k = (_j = config) === null || _j === void 0 ? void 0 : _j.tools) !== null && _k !== void 0 ? _k : {};
742
+ var baseSandbox = (_m = (_l = baseTools) === null || _l === void 0 ? void 0 : _l.sandbox) !== null && _m !== void 0 ? _m : {};
743
+ var baseSandboxTools = (_p = (_o = baseSandbox) === null || _o === void 0 ? void 0 : _o.tools) !== null && _p !== void 0 ? _p : {};
744
+ var existingTopLevelDeny = Array.isArray(baseTools.deny) ? baseTools.deny : [];
745
+ var existingSandboxDeny = Array.isArray(baseSandboxTools.deny) ? baseSandboxTools.deny : [];
746
+ var topLevelDeny = Array.from(new Set(__spreadArrays(existingTopLevelDeny, ["message"])));
747
+ var sandboxDeny = Array.from(new Set(__spreadArrays(existingSandboxDeny, ["message"])));
748
+ return __assign(__assign({}, config), { agents: __assign(__assign({}, baseAgents), { defaults: __assign(__assign({}, baseAgentDefaults), { blockStreamingChunk: __assign(__assign({}, baseBlockChunk), { minChars: (_q = baseBlockChunk.minChars) !== null && _q !== void 0 ? _q : 120, maxChars: (_r = baseBlockChunk.maxChars) !== null && _r !== void 0 ? _r : 360, breakPreference: (_s = baseBlockChunk.breakPreference) !== null && _s !== void 0 ? _s : "sentence" }), blockStreamingCoalesce: __assign(__assign({}, baseBlockCoalesce), { minChars: (_t = baseBlockCoalesce.minChars) !== null && _t !== void 0 ? _t : 120, maxChars: (_u = baseBlockCoalesce.maxChars) !== null && _u !== void 0 ? _u : 360, idleMs: (_v = baseBlockCoalesce.idleMs) !== null && _v !== void 0 ? _v : 250 }) }) }), tools: __assign(__assign({}, baseTools), { deny: topLevelDeny, sandbox: __assign(__assign({}, baseSandbox), { tools: __assign(__assign({}, baseSandboxTools), { deny: sandboxDeny }) }) }) });
749
+ }
750
+ exports.buildCfgForDispatch = buildCfgForDispatch;
751
+ /**
752
+ * 解析企微 Bot 回调中的发送者 userid(对齐原版 resolveWecomSenderUserId)
753
+ *
754
+ * 优先级:from.userid → fromuserid → from_userid → fromUserId
755
+ */
756
+ function resolveWecomSenderUserId(msg) {
757
+ var _a, _b, _c, _d, _e;
758
+ var direct = (_b = (_a = msg.from) === null || _a === void 0 ? void 0 : _a.userid) === null || _b === void 0 ? void 0 : _b.trim();
759
+ if (direct)
760
+ return direct;
761
+ var rawMsg = msg;
762
+ var legacy = String((_e = (_d = (_c = rawMsg.fromuserid) !== null && _c !== void 0 ? _c : rawMsg.from_userid) !== null && _d !== void 0 ? _d : rawMsg.fromUserId) !== null && _e !== void 0 ? _e : "").trim();
763
+ return legacy || undefined;
764
+ }
765
+ exports.resolveWecomSenderUserId = resolveWecomSenderUserId;
766
+ // ============================================================================
767
+ // 辅助函数
768
+ // ============================================================================
769
+ /**
770
+ * 构造入站消息文本内容(对齐原版 buildInboundBody)
771
+ *
772
+ * 根据消息类型提取文本表示:
773
+ * - text → text.content
774
+ * - voice → voice.content 或 "[voice]"
775
+ * - image → "[image] {url}"
776
+ * - file → "[file] {url}"
777
+ * - video → "[video] {url}"
778
+ * - mixed → 逐项提取拼接
779
+ * - event → "[event] {eventtype}"
780
+ * - stream → "[stream_refresh] {id}"
781
+ *
782
+ * 如果消息包含 quote(引用),追加引用内容。
783
+ */
784
+ function buildInboundBody(msg) {
785
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
786
+ var body = "";
787
+ var msgtype = String((_a = msg.msgtype) !== null && _a !== void 0 ? _a : "").toLowerCase();
788
+ if (msgtype === "text") {
789
+ body = ((_b = msg.text) === null || _b === void 0 ? void 0 : _b.content) || "";
790
+ }
791
+ else if (msgtype === "voice") {
792
+ body = ((_c = msg.voice) === null || _c === void 0 ? void 0 : _c.content) || "[voice]";
793
+ }
794
+ else if (msgtype === "mixed") {
795
+ var items = (_d = msg.mixed) === null || _d === void 0 ? void 0 : _d.msg_item;
796
+ if (Array.isArray(items)) {
797
+ body = items.map(function (item) {
798
+ var _a, _b, _c;
799
+ var t = String((_a = item === null || item === void 0 ? void 0 : item.msgtype) !== null && _a !== void 0 ? _a : "").toLowerCase();
800
+ if (t === "text")
801
+ return ((_b = item === null || item === void 0 ? void 0 : item.text) === null || _b === void 0 ? void 0 : _b.content) || "";
802
+ if (t === "image")
803
+ return "[image] " + (((_c = item === null || item === void 0 ? void 0 : item.image) === null || _c === void 0 ? void 0 : _c.url) || "");
804
+ return "[" + (t || "item") + "]";
805
+ }).filter(Boolean).join("\n");
806
+ }
807
+ else {
808
+ body = "[mixed]";
809
+ }
810
+ }
811
+ else if (msgtype === "image") {
812
+ body = "[image] " + (((_e = msg.image) === null || _e === void 0 ? void 0 : _e.url) || "");
813
+ }
814
+ else if (msgtype === "file") {
815
+ body = "[file] " + (((_f = msg.file) === null || _f === void 0 ? void 0 : _f.url) || "");
816
+ }
817
+ else if (msgtype === "video") {
818
+ body = "[video] " + (((_g = msg.video) === null || _g === void 0 ? void 0 : _g.url) || "");
819
+ }
820
+ else if (msgtype === "event") {
821
+ body = "[event] " + (((_h = msg.event) === null || _h === void 0 ? void 0 : _h.eventtype) || "");
822
+ }
823
+ else if (msgtype === "stream") {
824
+ body = "[stream_refresh] " + (((_j = msg.stream) === null || _j === void 0 ? void 0 : _j.id) || "");
825
+ }
826
+ else {
827
+ body = msgtype ? "[" + msgtype + "]" : "";
828
+ }
829
+ // 引用消息处理
830
+ var quote = msg.quote;
831
+ if (quote) {
832
+ var quoteText = formatQuote(quote).trim();
833
+ if (quoteText)
834
+ body += "\n\n> " + quoteText;
835
+ }
836
+ return body;
837
+ }
838
+ exports.buildInboundBody = buildInboundBody;
839
+ /**
840
+ * 格式化引用消息文本(对齐原版 formatQuote)
841
+ */
842
+ function formatQuote(quote) {
843
+ var _a, _b, _c, _d, _e, _f, _g;
844
+ var type = (_a = quote.msgtype) !== null && _a !== void 0 ? _a : "";
845
+ if (type === "text")
846
+ return ((_b = quote.text) === null || _b === void 0 ? void 0 : _b.content) || "";
847
+ if (type === "image")
848
+ return "[\u5F15\u7528: \u56FE\u7247] " + (((_c = quote.image) === null || _c === void 0 ? void 0 : _c.url) || "");
849
+ if (type === "mixed" && ((_d = quote.mixed) === null || _d === void 0 ? void 0 : _d.msg_item)) {
850
+ var items = quote.mixed.msg_item.map(function (item) {
851
+ var _a, _b;
852
+ if (item.msgtype === "text")
853
+ return (_a = item.text) === null || _a === void 0 ? void 0 : _a.content;
854
+ if (item.msgtype === "image")
855
+ return "[\u56FE\u7247] " + (((_b = item.image) === null || _b === void 0 ? void 0 : _b.url) || "");
856
+ return "";
857
+ }).filter(Boolean).join(" ");
858
+ return "[\u5F15\u7528: \u56FE\u6587] " + items;
859
+ }
860
+ if (type === "voice")
861
+ return "[\u5F15\u7528: \u8BED\u97F3] " + (((_e = quote.voice) === null || _e === void 0 ? void 0 : _e.content) || "");
862
+ if (type === "file")
863
+ return "[\u5F15\u7528: \u6587\u4EF6] " + (((_f = quote.file) === null || _f === void 0 ? void 0 : _f.url) || "");
864
+ if (type === "video")
865
+ return "[\u5F15\u7528: \u89C6\u9891] " + (((_g = quote.video) === null || _g === void 0 ? void 0 : _g.url) || "");
866
+ return "";
867
+ }
868
+ exports.formatQuote = formatQuote;
869
+ /** 检查消息是否有媒体内容 */
870
+ function hasMedia(message) {
871
+ var _a, _b;
872
+ var type = message.msgtype;
873
+ return ["image", "file", "voice", "video"].includes(type) ||
874
+ (type === "mixed" && ((_b = (_a = message.mixed) === null || _a === void 0 ? void 0 : _a.msg_item) === null || _b === void 0 ? void 0 : _b.some(function (item) { return item.msgtype !== "text"; })) === true);
875
+ }
876
+ exports.hasMedia = hasMedia;
877
+ /**
878
+ * 构造占位符响应(对齐原版 buildStreamPlaceholderReply)
879
+ *
880
+ * 用于 active_new / queued_new 场景:finish=false,显示占位符文本。
881
+ * 原版规范:第一次回复内容为 "1" 作为最小占位符。
882
+ */
883
+ function buildStreamPlaceholderReply(streamId, placeholderContent) {
884
+ var content = (placeholderContent === null || placeholderContent === void 0 ? void 0 : placeholderContent.trim()) || "1";
885
+ return {
886
+ msgtype: "stream",
887
+ stream: {
888
+ id: streamId,
889
+ finish: false,
890
+ content: content
891
+ }
892
+ };
893
+ }
894
+ exports.buildStreamPlaceholderReply = buildStreamPlaceholderReply;
895
+ /**
896
+ * 构造文本占位符响应(对齐原版 buildStreamTextPlaceholderReply)
897
+ *
898
+ * 用于 merged 场景:finish=false,显示自定义提示(如"已合并排队处理中...")。
899
+ */
900
+ function buildStreamTextPlaceholderReply(streamId, content) {
901
+ return {
902
+ msgtype: "stream",
903
+ stream: {
904
+ id: streamId,
905
+ finish: false,
906
+ content: content.trim() || "1"
907
+ }
908
+ };
909
+ }
910
+ exports.buildStreamTextPlaceholderReply = buildStreamTextPlaceholderReply;
911
+ /**
912
+ * 构造流式响应(从 StreamState 构建)
913
+ *
914
+ * 用于 stream_refresh 和 msgid 去重场景:返回当前累积内容 + finish 标记。
915
+ */
916
+ function buildStreamResponse(stream) {
917
+ var response = {
918
+ msgtype: "stream",
919
+ stream: {
920
+ id: stream.streamId,
921
+ finish: stream.finished,
922
+ content: stream.content
923
+ }
924
+ };
925
+ // 添加图片附件
926
+ if (stream.images && stream.images.length > 0) {
927
+ var streamObj = response.stream;
928
+ streamObj.msg_item = stream.images.map(function (img) { return ({
929
+ msgtype: "image",
930
+ image: { base64: img.base64, md5: img.md5 }
931
+ }); });
932
+ }
933
+ return response;
934
+ }
935
+ exports.buildStreamResponse = buildStreamResponse;
936
+ var templateObject_1, templateObject_2;