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,388 @@
1
+ "use strict";
2
+ /**
3
+ * smartsheet_add_records / smartsheet_update_records 本地文件上传拦截器
4
+ *
5
+ * 核心逻辑:
6
+ * 大模型在调用 smartsheet_add_records / smartsheet_update_records 时,
7
+ * 可在 CellImageValue 中传入 image_path(本地图片路径)代替 image_url/title,
8
+ * 或在 CellAttachmentValue 中传入 file_path(本地文件路径)代替 file_id。
9
+ *
10
+ * 本拦截器在 beforeCall 阶段:
11
+ * 1. 深度扫描 records[].values 中的所有字段值,收集含 image_path / file_path 的单元格
12
+ * 2. 校验文件大小:单文件不超过 10MB,所有文件总计不超过 20MB
13
+ * 3. 并行读取本地文件 → base64 编码 → 调用 MCP 上传接口
14
+ * - image_path → upload_doc_image → 获取 image_url
15
+ * - file_path → upload_doc_file → 获取 file_id
16
+ * 4. 用上传结果替换原字段,移除 image_path / file_path
17
+ * 5. 返回修改后的完整 args
18
+ *
19
+ * 传给 MCP Server 的始终是标准协议格式(image_url / file_id),
20
+ * MCP Server 不需要感知 image_path / file_path 的存在。
21
+ */
22
+ var __assign = (this && this.__assign) || function () {
23
+ __assign = Object.assign || function(t) {
24
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
25
+ s = arguments[i];
26
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
27
+ t[p] = s[p];
28
+ }
29
+ return t;
30
+ };
31
+ return __assign.apply(this, arguments);
32
+ };
33
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
34
+ if (k2 === undefined) k2 = k;
35
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
36
+ }) : (function(o, m, k, k2) {
37
+ if (k2 === undefined) k2 = k;
38
+ o[k2] = m[k];
39
+ }));
40
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
41
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
42
+ }) : function(o, v) {
43
+ o["default"] = v;
44
+ });
45
+ var __importStar = (this && this.__importStar) || function (mod) {
46
+ if (mod && mod.__esModule) return mod;
47
+ var result = {};
48
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
49
+ __setModuleDefault(result, mod);
50
+ return result;
51
+ };
52
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
53
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
54
+ return new (P || (P = Promise))(function (resolve, reject) {
55
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
56
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
57
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
58
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
59
+ });
60
+ };
61
+ var __generator = (this && this.__generator) || function (thisArg, body) {
62
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
63
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
64
+ function verb(n) { return function (v) { return step([n, v]); }; }
65
+ function step(op) {
66
+ if (f) throw new TypeError("Generator is already executing.");
67
+ while (_) try {
68
+ 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;
69
+ if (y = 0, t) op = [op[0] & 2, t.value];
70
+ switch (op[0]) {
71
+ case 0: case 1: t = op; break;
72
+ case 4: _.label++; return { value: op[1], done: false };
73
+ case 5: _.label++; y = op[1]; op = [0]; continue;
74
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
75
+ default:
76
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
77
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
78
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
79
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
80
+ if (t[2]) _.ops.pop();
81
+ _.trys.pop(); continue;
82
+ }
83
+ op = body.call(thisArg, _);
84
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
85
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
86
+ }
87
+ };
88
+ exports.__esModule = true;
89
+ exports.smartsheetUploadInterceptor = void 0;
90
+ var fs = __importStar(require("node:fs/promises"));
91
+ var path = __importStar(require("node:path"));
92
+ var transport_js_1 = require("../transport.js");
93
+ // ============================================================================
94
+ // 常量
95
+ // ============================================================================
96
+ /** 单个文件大小上限:10MB */
97
+ var MAX_SINGLE_FILE_SIZE = 10 * 1024 * 1024;
98
+ /** 所有文件总大小上限:20MB */
99
+ var MAX_TOTAL_FILE_SIZE = 20 * 1024 * 1024;
100
+ /** 上传请求超时时间(毫秒):单次上传最大 10MB base64,给足时间 */
101
+ var UPLOAD_TIMEOUT_MS = 60000;
102
+ /** beforeCall 整体超时延长到 120s(可能有多个文件并行上传) */
103
+ var INTERCEPTOR_TIMEOUT_MS = 120000;
104
+ /** 日志前缀 */
105
+ var LOG_TAG = "[mcp] smartsheet-upload:";
106
+ // ============================================================================
107
+ // 内部辅助函数
108
+ // ============================================================================
109
+ /**
110
+ * 深度扫描 records 中所有含 image_path / file_path 的单元格值对象,
111
+ * 返回待上传任务列表。
112
+ *
113
+ * records 结构:
114
+ * [{ values: { "字段A": [{ image_path: "..." }], "字段B": [{ file_path: "..." }] } }]
115
+ *
116
+ * 字段值可能是数组(图片/附件/文本等)或标量(数字/布尔等),
117
+ * 仅对数组中的对象元素进行扫描。
118
+ */
119
+ function collectUploadTasks(records) {
120
+ var tasks = [];
121
+ for (var _i = 0, records_1 = records; _i < records_1.length; _i++) {
122
+ var record = records_1[_i];
123
+ var values = record.values;
124
+ if (!values || typeof values !== "object")
125
+ continue;
126
+ for (var _a = 0, _b = Object.keys(values); _a < _b.length; _a++) {
127
+ var fieldKey = _b[_a];
128
+ var fieldValue = values[fieldKey];
129
+ if (!Array.isArray(fieldValue))
130
+ continue;
131
+ for (var _c = 0, fieldValue_1 = fieldValue; _c < fieldValue_1.length; _c++) {
132
+ var cellValue = fieldValue_1[_c];
133
+ if (!cellValue || typeof cellValue !== "object")
134
+ continue;
135
+ var cell = cellValue;
136
+ if (typeof cell.image_path === "string" && cell.image_path) {
137
+ tasks.push({
138
+ kind: "image",
139
+ filePath: cell.image_path,
140
+ title: typeof cell.title === "string" ? cell.title : undefined,
141
+ cellValue: cell
142
+ });
143
+ }
144
+ else if (typeof cell.file_path === "string" && cell.file_path) {
145
+ tasks.push({
146
+ kind: "file",
147
+ filePath: cell.file_path,
148
+ cellValue: cell
149
+ });
150
+ }
151
+ }
152
+ }
153
+ }
154
+ return tasks;
155
+ }
156
+ /**
157
+ * 校验所有待上传文件的大小
158
+ *
159
+ * - 单文件 > 10MB → 报错
160
+ * - 所有文件累计 > 20MB → 报错
161
+ */
162
+ function validateFileSizes(tasks) {
163
+ return __awaiter(this, void 0, void 0, function () {
164
+ var totalSize, i, task, stat, err_1;
165
+ return __generator(this, function (_a) {
166
+ switch (_a.label) {
167
+ case 0:
168
+ totalSize = 0;
169
+ i = 0;
170
+ _a.label = 1;
171
+ case 1:
172
+ if (!(i < tasks.length)) return [3 /*break*/, 7];
173
+ task = tasks[i];
174
+ stat = void 0;
175
+ _a.label = 2;
176
+ case 2:
177
+ _a.trys.push([2, 4, , 5]);
178
+ return [4 /*yield*/, fs.stat(task.filePath)];
179
+ case 3:
180
+ stat = _a.sent();
181
+ return [3 /*break*/, 5];
182
+ case 4:
183
+ err_1 = _a.sent();
184
+ throw new Error(LOG_TAG + " \u65E0\u6CD5\u8BBF\u95EE\u6587\u4EF6 \"" + task.filePath + "\": " + (err_1 instanceof Error ? err_1.message : String(err_1)));
185
+ case 5:
186
+ if (!stat.isFile()) {
187
+ throw new Error(LOG_TAG + " \"" + task.filePath + "\" \u4E0D\u662F\u4E00\u4E2A\u6587\u4EF6");
188
+ }
189
+ if (stat.size > MAX_SINGLE_FILE_SIZE) {
190
+ throw new Error(LOG_TAG + " \u6587\u4EF6 \"" + task.filePath + "\" \u5927\u5C0F " + (stat.size / 1024 / 1024).toFixed(1) + "MB \u8D85\u8FC7\u5355\u6587\u4EF6\u4E0A\u9650 10MB");
191
+ }
192
+ totalSize += stat.size;
193
+ if (totalSize > MAX_TOTAL_FILE_SIZE) {
194
+ throw new Error(LOG_TAG + " \u7D2F\u8BA1\u6587\u4EF6\u5927\u5C0F " + (totalSize / 1024 / 1024).toFixed(1) + "MB \u8D85\u8FC7\u603B\u4E0A\u9650 20MB\uFF08\u5728\u6587\u4EF6 \"" + task.filePath + "\" \u5904\u8D85\u51FA\uFF09");
195
+ }
196
+ _a.label = 6;
197
+ case 6:
198
+ i++;
199
+ return [3 /*break*/, 1];
200
+ case 7:
201
+ if (totalSize > 0) {
202
+ console.log(LOG_TAG + " \u6587\u4EF6\u5927\u5C0F\u6821\u9A8C\u901A\u8FC7\uFF0C\u5171 " + tasks.length + " \u4E2A\u6587\u4EF6\uFF0C\u603B\u8BA1 " + (totalSize / 1024 / 1024).toFixed(2) + "MB");
203
+ }
204
+ return [2 /*return*/];
205
+ }
206
+ });
207
+ });
208
+ }
209
+ /**
210
+ * 执行单个图片上传任务
211
+ *
212
+ * 读取本地文件 → base64 → 调用 upload_doc_image → 替换 cellValue
213
+ */
214
+ function executeImageUpload(task, docLocator) {
215
+ return __awaiter(this, void 0, void 0, function () {
216
+ var buffer, base64Content, fileName, result, bizData, imageUrl;
217
+ return __generator(this, function (_a) {
218
+ switch (_a.label) {
219
+ case 0: return [4 /*yield*/, fs.readFile(task.filePath)];
220
+ case 1:
221
+ buffer = _a.sent();
222
+ base64Content = buffer.toString("base64");
223
+ fileName = path.basename(task.filePath);
224
+ console.log(LOG_TAG + " \u4E0A\u4F20\u56FE\u7247: \"" + task.filePath + "\" (" + (buffer.length / 1024).toFixed(0) + "KB)");
225
+ return [4 /*yield*/, transport_js_1.sendJsonRpc("doc", "tools/call", {
226
+ name: "upload_doc_image",
227
+ arguments: __assign(__assign({}, docLocator), { base64_content: base64Content })
228
+ }, { timeoutMs: UPLOAD_TIMEOUT_MS })];
229
+ case 2:
230
+ result = _a.sent();
231
+ bizData = extractBizData(result, "upload_doc_image");
232
+ imageUrl = bizData.url;
233
+ if (!imageUrl) {
234
+ throw new Error(LOG_TAG + " upload_doc_image \u672A\u8FD4\u56DE url\uFF0C\u6587\u4EF6: \"" + task.filePath + "\"");
235
+ }
236
+ // 替换 cellValue:设置 image_url + title,移除 image_path
237
+ task.cellValue.image_url = imageUrl;
238
+ task.cellValue.title = task.title || fileName;
239
+ delete task.cellValue.image_path;
240
+ console.log(LOG_TAG + " \u56FE\u7247\u4E0A\u4F20\u6210\u529F: \"" + task.filePath + "\" \u2192 image_url=\"" + imageUrl + "\"");
241
+ return [2 /*return*/];
242
+ }
243
+ });
244
+ });
245
+ }
246
+ /**
247
+ * 执行单个文件上传任务
248
+ *
249
+ * 读取本地文件 → base64 → 调用 upload_doc_file → 替换 cellValue
250
+ */
251
+ function executeFileUpload(task) {
252
+ return __awaiter(this, void 0, void 0, function () {
253
+ var buffer, base64Content, fileName, result, bizData, fileId;
254
+ return __generator(this, function (_a) {
255
+ switch (_a.label) {
256
+ case 0: return [4 /*yield*/, fs.readFile(task.filePath)];
257
+ case 1:
258
+ buffer = _a.sent();
259
+ base64Content = buffer.toString("base64");
260
+ fileName = path.basename(task.filePath);
261
+ console.log(LOG_TAG + " \u4E0A\u4F20\u6587\u4EF6: \"" + task.filePath + "\" (" + (buffer.length / 1024).toFixed(0) + "KB)");
262
+ return [4 /*yield*/, transport_js_1.sendJsonRpc("doc", "tools/call", {
263
+ name: "upload_doc_file",
264
+ arguments: {
265
+ file_name: fileName,
266
+ file_base64_content: base64Content
267
+ }
268
+ }, { timeoutMs: UPLOAD_TIMEOUT_MS })];
269
+ case 2:
270
+ result = _a.sent();
271
+ bizData = extractBizData(result, "upload_doc_file");
272
+ fileId = bizData.fileid;
273
+ if (!fileId) {
274
+ throw new Error(LOG_TAG + " upload_doc_file \u672A\u8FD4\u56DE fileid\uFF0C\u6587\u4EF6: \"" + task.filePath + "\"");
275
+ }
276
+ // 替换 cellValue:设置 file_id,移除 file_path
277
+ task.cellValue.file_id = fileId;
278
+ delete task.cellValue.file_path;
279
+ console.log(LOG_TAG + " \u6587\u4EF6\u4E0A\u4F20\u6210\u529F: \"" + task.filePath + "\" \u2192 file_id=\"" + fileId + "\"");
280
+ return [2 /*return*/];
281
+ }
282
+ });
283
+ });
284
+ }
285
+ /**
286
+ * 从 MCP tools/call 返回结构中提取业务 JSON 数据
287
+ *
288
+ * MCP result 格式:{ content: [{ type: "text", text: "{...json...}" }] }
289
+ */
290
+ function extractBizData(result, interfaceName) {
291
+ var _a, _b;
292
+ var content = (_a = result) === null || _a === void 0 ? void 0 : _a.content;
293
+ if (!Array.isArray(content)) {
294
+ throw new Error(LOG_TAG + " " + interfaceName + " \u54CD\u5E94\u683C\u5F0F\u5F02\u5E38\uFF1A\u7F3A\u5C11 content \u6570\u7EC4");
295
+ }
296
+ var textItem = content.find(function (c) { return c.type === "text" && typeof c.text === "string"; });
297
+ if (!textItem) {
298
+ throw new Error(LOG_TAG + " " + interfaceName + " \u54CD\u5E94\u683C\u5F0F\u5F02\u5E38\uFF1Acontent \u4E2D\u65E0 text \u7C7B\u578B\u6761\u76EE");
299
+ }
300
+ var bizData;
301
+ try {
302
+ bizData = JSON.parse(textItem.text);
303
+ }
304
+ catch (_c) {
305
+ throw new Error(LOG_TAG + " " + interfaceName + " \u54CD\u5E94\u975E JSON: " + textItem.text.slice(0, 200));
306
+ }
307
+ if (bizData.errcode !== 0) {
308
+ throw new Error(LOG_TAG + " " + interfaceName + " \u4E1A\u52A1\u9519\u8BEF: errcode=" + bizData.errcode + ", errmsg=" + ((_b = bizData.errmsg) !== null && _b !== void 0 ? _b : "unknown"));
309
+ }
310
+ return bizData;
311
+ }
312
+ /**
313
+ * 从 args 中提取文档定位参数(docid 或 url),用于 upload_doc_image
314
+ */
315
+ function extractDocLocator(args) {
316
+ if (typeof args.docid === "string" && args.docid) {
317
+ return { docid: args.docid };
318
+ }
319
+ if (typeof args.url === "string" && args.url) {
320
+ return { url: args.url };
321
+ }
322
+ throw new Error(LOG_TAG + " args \u4E2D\u7F3A\u5C11 docid \u6216 url\uFF0C\u65E0\u6CD5\u8C03\u7528 upload_doc_image");
323
+ }
324
+ // ============================================================================
325
+ // 拦截器实现
326
+ // ============================================================================
327
+ exports.smartsheetUploadInterceptor = {
328
+ name: "smartsheet-upload",
329
+ /** 对 doc 品类的 smartsheet_add_records / smartsheet_update_records 生效 */
330
+ match: function (ctx) {
331
+ return ctx.category === "doc" &&
332
+ (ctx.method === "smartsheet_add_records" || ctx.method === "smartsheet_update_records");
333
+ },
334
+ /** 扫描 records 中的 image_path / file_path,上传后替换为 image_url / file_id */
335
+ beforeCall: function (ctx) {
336
+ var records = ctx.args.records;
337
+ if (!Array.isArray(records) || records.length === 0) {
338
+ return undefined;
339
+ }
340
+ // 收集所有待上传任务
341
+ var tasks = collectUploadTasks(records);
342
+ if (tasks.length === 0) {
343
+ return undefined;
344
+ }
345
+ console.log(LOG_TAG + " \u68C0\u6D4B\u5230 " + tasks.length + " \u4E2A\u672C\u5730\u6587\u4EF6\u5F85\u4E0A\u4F20");
346
+ // 异步执行上传流程
347
+ return resolveUploads(ctx, tasks);
348
+ }
349
+ };
350
+ /**
351
+ * 执行文件校验和并行上传,返回替换后的 args
352
+ */
353
+ function resolveUploads(ctx, tasks) {
354
+ return __awaiter(this, void 0, void 0, function () {
355
+ var hasImageTasks, docLocator, uploadStart, uploadMs;
356
+ return __generator(this, function (_a) {
357
+ switch (_a.label) {
358
+ case 0:
359
+ // 阶段 1:文件大小校验
360
+ return [4 /*yield*/, validateFileSizes(tasks)];
361
+ case 1:
362
+ // 阶段 1:文件大小校验
363
+ _a.sent();
364
+ hasImageTasks = tasks.some(function (t) { return t.kind === "image"; });
365
+ docLocator = {};
366
+ if (hasImageTasks) {
367
+ docLocator = extractDocLocator(ctx.args);
368
+ }
369
+ uploadStart = performance.now();
370
+ return [4 /*yield*/, Promise.all(tasks.map(function (task) {
371
+ if (task.kind === "image") {
372
+ return executeImageUpload(task, docLocator);
373
+ }
374
+ return executeFileUpload(task);
375
+ }))];
376
+ case 2:
377
+ _a.sent();
378
+ uploadMs = (performance.now() - uploadStart).toFixed(1);
379
+ console.log(LOG_TAG + " \u5168\u90E8\u4E0A\u4F20\u5B8C\u6210\uFF0C\u5171 " + tasks.length + " \u4E2A\u6587\u4EF6\uFF0C\u8017\u65F6 " + uploadMs + "ms");
380
+ // args 中的 records 已被原地修改,返回完整 args + 延长超时
381
+ return [2 /*return*/, {
382
+ args: __assign({}, ctx.args),
383
+ timeoutMs: INTERCEPTOR_TIMEOUT_MS
384
+ }];
385
+ }
386
+ });
387
+ });
388
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * MCP call 拦截器类型定义
3
+ *
4
+ * 拦截器用于在 tools/call 调用前后注入特殊逻辑,
5
+ * 如修改超时配置、变换响应结果等,避免在 tool.ts 中堆积 if/else。
6
+ */
7
+ import type { SendJsonRpcOptions } from "../transport.js";
8
+ /** MCP call 调用的上下文 */
9
+ export interface CallContext {
10
+ /** MCP 品类,对应 mcpConfig 中的 key,如 doc、contact */
11
+ category: string;
12
+ /** 调用的 MCP 方法名 */
13
+ method: string;
14
+ /** 调用 MCP 方法的参数 */
15
+ args: Record<string, unknown>;
16
+ /** 当前会话对应的账户 ID(由工具工厂透传,用于精确清理缓存等场景) */
17
+ accountId?: string;
18
+ /** 当前会话的 chatId(群组 ID 或用户 ID),用于 aibot_send_biz_msg 等命令 */
19
+ chatId?: string;
20
+ /** 当前会话的聊天类型:single(单聊)或 group(群聊) */
21
+ chatType?: "single" | "group";
22
+ /** 当前会话可信的企业微信 userid */
23
+ requesterUserId?: string;
24
+ }
25
+ /**
26
+ * beforeCall 返回的选项
27
+ *
28
+ * 扩展 SendJsonRpcOptions,允许拦截器在调用前替换 args(如从本地文件读取请求体)。
29
+ */
30
+ export interface BeforeCallOptions extends SendJsonRpcOptions {
31
+ /** 替换后的 args(可选,不返回则使用原 args) */
32
+ args?: Record<string, unknown>;
33
+ }
34
+ /**
35
+ * call 拦截器接口
36
+ *
37
+ * 每个拦截器通过 match 判断是否对当前调用生效,
38
+ * 生效时可在调用前(beforeCall)和调用后(afterCall)注入逻辑。
39
+ */
40
+ export interface CallInterceptor {
41
+ /** 拦截器名称(用于日志) */
42
+ name: string;
43
+ /**
44
+ * 判断是否对当前调用生效
45
+ *
46
+ * 返回 true 时才会执行 beforeCall / afterCall
47
+ */
48
+ match(ctx: CallContext): boolean;
49
+ /**
50
+ * 在 sendJsonRpc 调用前修改请求选项和参数(可选)
51
+ *
52
+ * 如 get_msg_media 需要延长超时时间,
53
+ * 如 smartpage_create 需要从本地文件读取请求体替换 args。
54
+ * 返回的选项会与其他拦截器的结果合并(timeoutMs 取最大值,args 后者覆盖前者)。
55
+ */
56
+ beforeCall?(ctx: CallContext): BeforeCallOptions | Promise<BeforeCallOptions> | undefined;
57
+ /**
58
+ * 在 sendJsonRpc 返回后处理/变换结果(可选)
59
+ *
60
+ * 多个拦截器的 afterCall 按注册顺序管道式执行,
61
+ * 前一个的返回值作为下一个的输入。
62
+ */
63
+ afterCall?(ctx: CallContext, result: unknown): Promise<unknown> | unknown;
64
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /**
3
+ * MCP call 拦截器类型定义
4
+ *
5
+ * 拦截器用于在 tools/call 调用前后注入特殊逻辑,
6
+ * 如修改超时配置、变换响应结果等,避免在 tool.ts 中堆积 if/else。
7
+ */
8
+ exports.__esModule = true;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * MCP Schema 清洗模块
3
+ *
4
+ * 负责内联 $ref/$defs 引用并移除 Gemini 不支持的 JSON Schema 关键词,
5
+ * 防止 Gemini 模型解析 function response 时报 400 错误。
6
+ */
7
+ /**
8
+ * 清洗 JSON Schema,内联 $ref 引用并移除 Gemini 不支持的关键词,
9
+ * 防止 Gemini 模型解析 function response 时报 400 错误。
10
+ */
11
+ export declare function cleanSchemaForGemini(schema: unknown): unknown;
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ /**
3
+ * MCP Schema 清洗模块
4
+ *
5
+ * 负责内联 $ref/$defs 引用并移除 Gemini 不支持的 JSON Schema 关键词,
6
+ * 防止 Gemini 模型解析 function response 时报 400 错误。
7
+ */
8
+ var __assign = (this && this.__assign) || function () {
9
+ __assign = Object.assign || function(t) {
10
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
11
+ s = arguments[i];
12
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
13
+ t[p] = s[p];
14
+ }
15
+ return t;
16
+ };
17
+ return __assign.apply(this, arguments);
18
+ };
19
+ exports.__esModule = true;
20
+ exports.cleanSchemaForGemini = void 0;
21
+ /** Gemini 不支持的 JSON Schema 关键词 */
22
+ var GEMINI_UNSUPPORTED_KEYWORDS = new Set([
23
+ "patternProperties", "additionalProperties", "$schema", "$id", "$ref", "$defs",
24
+ "definitions", "examples", "minLength", "maxLength", "minimum", "maximum",
25
+ "multipleOf", "pattern", "format", "minItems", "maxItems", "uniqueItems",
26
+ "minProperties", "maxProperties",
27
+ ]);
28
+ /**
29
+ * 清洗 JSON Schema,内联 $ref 引用并移除 Gemini 不支持的关键词,
30
+ * 防止 Gemini 模型解析 function response 时报 400 错误。
31
+ */
32
+ function cleanSchemaForGemini(schema) {
33
+ if (!schema || typeof schema !== "object")
34
+ return schema;
35
+ if (Array.isArray(schema))
36
+ return schema.map(cleanSchemaForGemini);
37
+ var obj = schema;
38
+ // 收集 $defs/definitions 用于后续 $ref 内联解析
39
+ var defs = __assign(__assign({}, (obj.$defs && typeof obj.$defs === "object" ? obj.$defs : {})), (obj.definitions && typeof obj.definitions === "object" ? obj.definitions : {}));
40
+ return cleanWithDefs(obj, defs, new Set());
41
+ }
42
+ exports.cleanSchemaForGemini = cleanSchemaForGemini;
43
+ function cleanWithDefs(schema, defs, refStack) {
44
+ if (!schema || typeof schema !== "object")
45
+ return schema;
46
+ if (Array.isArray(schema))
47
+ return schema.map(function (item) { return cleanWithDefs(item, defs, refStack); });
48
+ var obj = schema;
49
+ // 合并当前层级的 $defs/definitions 到 defs 中
50
+ if (obj.$defs && typeof obj.$defs === "object") {
51
+ Object.assign(defs, obj.$defs);
52
+ }
53
+ if (obj.definitions && typeof obj.definitions === "object") {
54
+ Object.assign(defs, obj.definitions);
55
+ }
56
+ // 处理 $ref 引用:尝试内联解析
57
+ if (typeof obj.$ref === "string") {
58
+ var ref = obj.$ref;
59
+ if (refStack.has(ref))
60
+ return {}; // 防止循环引用
61
+ var match = ref.match(/^#\/(?:\$defs|definitions)\/(.+)$/);
62
+ if (match && match[1] && defs[match[1]]) {
63
+ var nextStack = new Set(refStack);
64
+ nextStack.add(ref);
65
+ return cleanWithDefs(defs[match[1]], defs, nextStack);
66
+ }
67
+ return {}; // 无法解析的 $ref,返回空对象
68
+ }
69
+ var cleaned = {};
70
+ for (var _i = 0, _a = Object.entries(obj); _i < _a.length; _i++) {
71
+ var _b = _a[_i], key = _b[0], value = _b[1];
72
+ if (GEMINI_UNSUPPORTED_KEYWORDS.has(key))
73
+ continue;
74
+ if (key === "const") {
75
+ cleaned["enum"] = [value];
76
+ continue;
77
+ }
78
+ if (key === "properties" && value && typeof value === "object" && !Array.isArray(value)) {
79
+ cleaned[key] = Object.fromEntries(Object.entries(value).map(function (_a) {
80
+ var k = _a[0], v = _a[1];
81
+ return [
82
+ k, cleanWithDefs(v, defs, refStack),
83
+ ];
84
+ }));
85
+ }
86
+ else if (key === "items" && value) {
87
+ cleaned[key] = Array.isArray(value)
88
+ ? value.map(function (item) { return cleanWithDefs(item, defs, refStack); })
89
+ : cleanWithDefs(value, defs, refStack);
90
+ }
91
+ else if ((key === "anyOf" || key === "oneOf" || key === "allOf") && Array.isArray(value)) {
92
+ // 过滤掉 null 类型的变体
93
+ var nonNull = value.filter(function (v) {
94
+ if (!v || typeof v !== "object")
95
+ return true;
96
+ var r = v;
97
+ return r.type !== "null";
98
+ });
99
+ if (nonNull.length === 1) {
100
+ // 只剩一个变体时直接内联
101
+ var single = cleanWithDefs(nonNull[0], defs, refStack);
102
+ if (single && typeof single === "object" && !Array.isArray(single)) {
103
+ Object.assign(cleaned, single);
104
+ }
105
+ }
106
+ else {
107
+ cleaned[key] = nonNull.map(function (v) { return cleanWithDefs(v, defs, refStack); });
108
+ }
109
+ }
110
+ else {
111
+ cleaned[key] = value;
112
+ }
113
+ }
114
+ return cleaned;
115
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * wecom_mcp — 模拟 MCP 调用的 Agent Tool
3
+ *
4
+ * 通过 MCP Streamable HTTP 传输协议调用企业微信 MCP Server,
5
+ * 提供 list(列出所有工具)和 call(调用工具)两个操作。
6
+ *
7
+ * 在 skills 中的使用方式:
8
+ * wecom_mcp list <category>
9
+ * wecom_mcp call <category> <method> '<jsonArgs>'
10
+ *
11
+ * 示例:
12
+ * wecom_mcp list contact
13
+ * wecom_mcp call contact getContact '{}'
14
+ */
15
+ interface CreateWeComMcpToolOptions {
16
+ /** 当前会话可信的企业微信 userid */
17
+ requesterUserId?: string;
18
+ /** 当前会话对应的账户 ID(来自 ctx.agentAccountId) */
19
+ accountId?: string;
20
+ /** 当前会话的 chatId(群组 ID 或用户 ID),用于 aibot_send_biz_msg 等命令 */
21
+ chatId?: string;
22
+ /** 当前会话的聊天类型:single(单聊)或 group(群聊) */
23
+ chatType?: "single" | "group";
24
+ }
25
+ /**
26
+ * 创建 wecom_mcp Agent Tool 定义
27
+ */
28
+ export declare function createWeComMcpTool(options?: CreateWeComMcpToolOptions): {
29
+ name: string;
30
+ label: string;
31
+ description: string;
32
+ parameters: {
33
+ type: "object";
34
+ properties: {
35
+ action: {
36
+ type: string;
37
+ enum: string[];
38
+ description: string;
39
+ };
40
+ category: {
41
+ type: string;
42
+ description: string;
43
+ };
44
+ method: {
45
+ type: string;
46
+ description: string;
47
+ };
48
+ args: {
49
+ type: string[];
50
+ description: string;
51
+ };
52
+ };
53
+ required: string[];
54
+ };
55
+ execute(_toolCallId: string, params: unknown): Promise<{
56
+ content: {
57
+ type: "text";
58
+ text: string;
59
+ }[];
60
+ details: unknown;
61
+ }>;
62
+ };
63
+ export {};