@yanhaidao/wecom 2.4.160 → 2.5.110

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 (313) hide show
  1. package/dist/index.js +68 -0
  2. package/dist/src/accounts.js +20 -0
  3. package/dist/src/agent/handler.js +895 -0
  4. package/dist/src/agent/index.js +5 -0
  5. package/dist/src/app/account-runtime.js +216 -0
  6. package/dist/src/app/bootstrap.js +19 -0
  7. package/dist/src/app/index.js +118 -0
  8. package/dist/src/capability/agent/delivery-service.js +63 -0
  9. package/dist/src/capability/agent/fallback-policy.js +6 -0
  10. package/dist/src/capability/agent/ingress-service.js +33 -0
  11. package/dist/src/capability/agent/upstream-delivery-service.js +71 -0
  12. package/dist/src/capability/bot/dispatch-config.js +45 -0
  13. package/dist/src/capability/bot/fallback-delivery.js +147 -0
  14. package/dist/src/capability/bot/local-path-delivery.js +178 -0
  15. package/dist/src/capability/bot/sandbox-media.js +138 -0
  16. package/dist/src/capability/bot/service.js +49 -0
  17. package/dist/src/capability/bot/stream-delivery.js +321 -0
  18. package/dist/src/capability/bot/stream-finalizer.js +81 -0
  19. package/dist/src/capability/bot/stream-orchestrator.js +318 -0
  20. package/dist/src/capability/bot/types.js +1 -0
  21. package/{src/capability/calendar/client.ts → dist/src/capability/calendar/client.js} +118 -241
  22. package/{src/capability/calendar/schema.ts → dist/src/capability/calendar/schema.js} +0 -38
  23. package/dist/src/capability/calendar/tool.js +365 -0
  24. package/dist/src/capability/calendar/types.js +12 -0
  25. package/{src/capability/doc/client.ts → dist/src/capability/doc/client.js} +370 -605
  26. package/{src/capability/doc/schema.ts → dist/src/capability/doc/schema.js} +345 -394
  27. package/dist/src/capability/doc/tool.js +1556 -0
  28. package/dist/src/capability/doc/types.js +113 -0
  29. package/dist/src/capability/mcp/index.js +3 -0
  30. package/dist/src/capability/mcp/schema.js +102 -0
  31. package/dist/src/capability/mcp/tool.js +146 -0
  32. package/dist/src/capability/mcp/transport.js +293 -0
  33. package/dist/src/channel.js +224 -0
  34. package/dist/src/config/accounts.js +236 -0
  35. package/dist/src/config/derived-paths.js +31 -0
  36. package/dist/src/config/index.js +7 -0
  37. package/dist/src/config/media.js +110 -0
  38. package/dist/src/config/network.js +32 -0
  39. package/dist/src/config/routing.js +20 -0
  40. package/dist/src/config/runtime-config.js +25 -0
  41. package/dist/src/config/schema.js +4 -0
  42. package/{src/config-schema.ts → dist/src/config-schema.js} +1 -1
  43. package/dist/src/context-store.js +219 -0
  44. package/{src/crypto/aes.ts → dist/src/crypto/aes.js} +11 -28
  45. package/dist/src/crypto/index.js +9 -0
  46. package/{src/crypto/signature.ts → dist/src/crypto/signature.js} +3 -18
  47. package/{src/crypto/xml.ts → dist/src/crypto/xml.js} +3 -11
  48. package/dist/src/crypto.js +145 -0
  49. package/dist/src/domain/models.js +1 -0
  50. package/dist/src/domain/policies.js +32 -0
  51. package/{src/dynamic-agent.ts → dist/src/dynamic-agent.js} +36 -73
  52. package/dist/src/gateway-monitor.js +139 -0
  53. package/dist/src/http.js +114 -0
  54. package/{src/media.ts → dist/src/media.js} +21 -40
  55. package/dist/src/monitor/limits.js +7 -0
  56. package/dist/src/monitor/state.js +28 -0
  57. package/dist/src/monitor.js +84 -0
  58. package/dist/src/observability/audit-log.js +30 -0
  59. package/dist/src/observability/legacy-operational-event-store.js +22 -0
  60. package/dist/src/observability/raw-envelope-log.js +24 -0
  61. package/dist/src/observability/status-registry.js +9 -0
  62. package/dist/src/observability/transport-session-view.js +14 -0
  63. package/dist/src/onboarding.js +546 -0
  64. package/dist/src/outbound.js +557 -0
  65. package/dist/src/runtime/dispatcher.js +57 -0
  66. package/{src/runtime/index.ts → dist/src/runtime/index.js} +0 -1
  67. package/dist/src/runtime/outbound-intent.js +1 -0
  68. package/dist/src/runtime/reply-orchestrator.js +38 -0
  69. package/dist/src/runtime/routing-bridge.js +26 -0
  70. package/dist/src/runtime/session-manager.js +112 -0
  71. package/dist/src/runtime/source-registry.js +174 -0
  72. package/dist/src/runtime.js +1 -0
  73. package/dist/src/shared/command-auth.js +57 -0
  74. package/{src/shared/index.ts → dist/src/shared/index.js} +0 -1
  75. package/dist/src/shared/media-asset.js +65 -0
  76. package/dist/src/shared/media-service.js +59 -0
  77. package/dist/src/shared/media-types.js +1 -0
  78. package/{src/shared/xml-parser.ts → dist/src/shared/xml-parser.js} +72 -63
  79. package/dist/src/store/active-reply-store.js +41 -0
  80. package/dist/src/store/interfaces.js +1 -0
  81. package/dist/src/store/memory-store.js +33 -0
  82. package/dist/src/store/stream-batch-store.js +319 -0
  83. package/{src/target.ts → dist/src/target.js} +15 -48
  84. package/dist/src/transport/agent-api/client.js +168 -0
  85. package/dist/src/transport/agent-api/core.js +337 -0
  86. package/dist/src/transport/agent-api/delivery.js +28 -0
  87. package/dist/src/transport/agent-api/media-upload.js +4 -0
  88. package/dist/src/transport/agent-api/reply.js +24 -0
  89. package/dist/src/transport/agent-api/upstream-delivery.js +30 -0
  90. package/dist/src/transport/agent-api/upstream-media-upload.js +46 -0
  91. package/dist/src/transport/agent-api/upstream-reply.js +26 -0
  92. package/dist/src/transport/agent-callback/http-handler.js +30 -0
  93. package/dist/src/transport/agent-callback/inbound.js +4 -0
  94. package/dist/src/transport/agent-callback/reply.js +8 -0
  95. package/dist/src/transport/agent-callback/request-handler.js +189 -0
  96. package/dist/src/transport/agent-callback/session.js +15 -0
  97. package/dist/src/transport/bot-webhook/active-reply.js +27 -0
  98. package/dist/src/transport/bot-webhook/http-handler.js +31 -0
  99. package/dist/src/transport/bot-webhook/inbound-normalizer.js +496 -0
  100. package/dist/src/transport/bot-webhook/inbound.js +4 -0
  101. package/dist/src/transport/bot-webhook/message-shape.js +98 -0
  102. package/dist/src/transport/bot-webhook/protocol.js +124 -0
  103. package/dist/src/transport/bot-webhook/reply.js +9 -0
  104. package/dist/src/transport/bot-webhook/request-handler.js +285 -0
  105. package/dist/src/transport/bot-webhook/session.js +15 -0
  106. package/dist/src/transport/bot-ws/inbound.js +147 -0
  107. package/dist/src/transport/bot-ws/media.js +236 -0
  108. package/dist/src/transport/bot-ws/reply.js +310 -0
  109. package/dist/src/transport/bot-ws/sdk-adapter.js +257 -0
  110. package/dist/src/transport/bot-ws/session.js +15 -0
  111. package/dist/src/transport/http/common.js +78 -0
  112. package/dist/src/transport/http/registry.js +71 -0
  113. package/dist/src/transport/http/request-handler.js +51 -0
  114. package/{src/transport/index.ts → dist/src/transport/index.js} +2 -10
  115. package/dist/src/types/account.js +1 -0
  116. package/dist/src/types/config.js +1 -0
  117. package/dist/src/types/constants.js +28 -0
  118. package/dist/src/types/events.js +1 -0
  119. package/dist/src/types/index.js +1 -0
  120. package/dist/src/types/legacy-stream.js +1 -0
  121. package/dist/src/types/message.js +5 -0
  122. package/dist/src/types/runtime-context.js +1 -0
  123. package/dist/src/types/runtime.js +1 -0
  124. package/dist/src/types.js +1 -0
  125. package/dist/src/upstream/index.js +111 -0
  126. package/dist/src/wecom_msg_adapter/markdown_adapter.js +280 -0
  127. package/openclaw.plugin.json +15 -0
  128. package/package.json +18 -1
  129. package/.github/workflows/release.yml +0 -143
  130. package/GOVERNANCE.md +0 -26
  131. package/SKILLS_CAL.md +0 -895
  132. package/SKILLS_DOC.md +0 -2288
  133. package/UPSTREAM_CONFIG.md +0 -170
  134. package/UPSTREAM_PLAN.md +0 -175
  135. package/assets/01.bot-add.png +0 -0
  136. package/assets/01.bot-setp2.png +0 -0
  137. package/assets/01.image.jpg +0 -0
  138. package/assets/02.agent.add.png +0 -0
  139. package/assets/02.agent.api-set.png +0 -0
  140. package/assets/02.image.jpg +0 -0
  141. package/assets/03.agent.page.png +0 -0
  142. package/assets/03.bot.page.png +0 -0
  143. package/assets/link-me.jpg +0 -0
  144. package/assets/register.png +0 -0
  145. package/changelog/v2.2.28.md +0 -70
  146. package/changelog/v2.3.10.md +0 -17
  147. package/changelog/v2.3.11.md +0 -19
  148. package/changelog/v2.3.12.md +0 -25
  149. package/changelog/v2.3.13.md +0 -19
  150. package/changelog/v2.3.14.md +0 -48
  151. package/changelog/v2.3.15.md +0 -15
  152. package/changelog/v2.3.16.md +0 -11
  153. package/changelog/v2.3.18.md +0 -22
  154. package/changelog/v2.3.19.md +0 -73
  155. package/changelog/v2.3.2.md +0 -28
  156. package/changelog/v2.3.26.md +0 -21
  157. package/changelog/v2.3.27.md +0 -33
  158. package/changelog/v2.3.4.md +0 -20
  159. package/changelog/v2.3.9.md +0 -22
  160. package/changelog/v2.4.12.md +0 -37
  161. package/changelog/v2.4.16.md +0 -19
  162. package/compat-single-account.md +0 -148
  163. package/index.test.ts +0 -38
  164. package/scripts/test-proxy.ts +0 -70
  165. package/src/accounts.ts +0 -34
  166. package/src/agent/api-client.upload.test.ts +0 -109
  167. package/src/agent/handler.event-filter.test.ts +0 -100
  168. package/src/agent/handler.ts +0 -1105
  169. package/src/agent/index.ts +0 -12
  170. package/src/app/account-runtime.ts +0 -276
  171. package/src/app/bootstrap.ts +0 -29
  172. package/src/app/index.ts +0 -192
  173. package/src/capability/agent/delivery-service.ts +0 -87
  174. package/src/capability/agent/fallback-policy.ts +0 -13
  175. package/src/capability/agent/ingress-service.ts +0 -38
  176. package/src/capability/agent/upstream-delivery-service.ts +0 -96
  177. package/src/capability/bot/dispatch-config.ts +0 -47
  178. package/src/capability/bot/fallback-delivery.ts +0 -178
  179. package/src/capability/bot/local-path-delivery.ts +0 -215
  180. package/src/capability/bot/sandbox-media.test.ts +0 -221
  181. package/src/capability/bot/sandbox-media.ts +0 -176
  182. package/src/capability/bot/service.ts +0 -56
  183. package/src/capability/bot/stream-delivery.ts +0 -379
  184. package/src/capability/bot/stream-finalizer.ts +0 -120
  185. package/src/capability/bot/stream-orchestrator.ts +0 -371
  186. package/src/capability/bot/types.ts +0 -8
  187. package/src/capability/calendar/SKILLS_CHECKLIST.md +0 -251
  188. package/src/capability/calendar/tool.ts +0 -417
  189. package/src/capability/calendar/types.ts +0 -309
  190. package/src/capability/doc/tool.ts +0 -1629
  191. package/src/capability/doc/types.ts +0 -792
  192. package/src/capability/mcp/index.ts +0 -10
  193. package/src/capability/mcp/schema.ts +0 -107
  194. package/src/capability/mcp/tool.ts +0 -174
  195. package/src/capability/mcp/transport.ts +0 -394
  196. package/src/channel.config.test.ts +0 -147
  197. package/src/channel.lifecycle.test.ts +0 -255
  198. package/src/channel.meta.test.ts +0 -26
  199. package/src/channel.ts +0 -256
  200. package/src/config/accounts.resolve.test.ts +0 -75
  201. package/src/config/accounts.ts +0 -296
  202. package/src/config/derived-paths.test.ts +0 -111
  203. package/src/config/derived-paths.ts +0 -41
  204. package/src/config/index.ts +0 -26
  205. package/src/config/media.test.ts +0 -113
  206. package/src/config/media.ts +0 -139
  207. package/src/config/network.ts +0 -53
  208. package/src/config/routing.test.ts +0 -88
  209. package/src/config/routing.ts +0 -26
  210. package/src/config/runtime-config.ts +0 -46
  211. package/src/config/schema.ts +0 -90
  212. package/src/context-store.ts +0 -297
  213. package/src/crypto/index.ts +0 -24
  214. package/src/crypto.test.ts +0 -32
  215. package/src/crypto.ts +0 -176
  216. package/src/domain/models.ts +0 -7
  217. package/src/domain/policies.ts +0 -36
  218. package/src/dynamic-agent.account-scope.test.ts +0 -17
  219. package/src/gateway-monitor.ts +0 -181
  220. package/src/http.ts +0 -145
  221. package/src/media.test.ts +0 -82
  222. package/src/monitor/limits.ts +0 -7
  223. package/src/monitor/state.queue.test.ts +0 -185
  224. package/src/monitor/state.ts +0 -34
  225. package/src/monitor.active.test.ts +0 -245
  226. package/src/monitor.inbound-filter.test.ts +0 -63
  227. package/src/monitor.integration.test.ts +0 -208
  228. package/src/monitor.ts +0 -121
  229. package/src/monitor.webhook.test.ts +0 -774
  230. package/src/observability/audit-log.ts +0 -48
  231. package/src/observability/legacy-operational-event-store.ts +0 -36
  232. package/src/observability/raw-envelope-log.ts +0 -28
  233. package/src/observability/status-registry.ts +0 -13
  234. package/src/observability/transport-session-view.ts +0 -14
  235. package/src/onboarding.test.ts +0 -336
  236. package/src/onboarding.ts +0 -704
  237. package/src/outbound.test.ts +0 -1271
  238. package/src/outbound.ts +0 -746
  239. package/src/runtime/dispatcher.ts +0 -71
  240. package/src/runtime/outbound-intent.ts +0 -4
  241. package/src/runtime/reply-orchestrator.test.ts +0 -71
  242. package/src/runtime/reply-orchestrator.ts +0 -67
  243. package/src/runtime/routing-bridge.test.ts +0 -115
  244. package/src/runtime/routing-bridge.ts +0 -44
  245. package/src/runtime/session-manager.test.ts +0 -174
  246. package/src/runtime/session-manager.ts +0 -139
  247. package/src/runtime/source-registry.ts +0 -249
  248. package/src/runtime.ts +0 -14
  249. package/src/shared/command-auth.ts +0 -87
  250. package/src/shared/media-asset.ts +0 -78
  251. package/src/shared/media-service.test.ts +0 -111
  252. package/src/shared/media-service.ts +0 -84
  253. package/src/shared/media-types.ts +0 -5
  254. package/src/shared/xml-parser.test.ts +0 -50
  255. package/src/store/active-reply-store.ts +0 -42
  256. package/src/store/interfaces.ts +0 -11
  257. package/src/store/memory-store.ts +0 -43
  258. package/src/store/stream-batch-store.ts +0 -350
  259. package/src/transport/agent-api/client.ts +0 -277
  260. package/src/transport/agent-api/core.ts +0 -463
  261. package/src/transport/agent-api/delivery.ts +0 -41
  262. package/src/transport/agent-api/media-upload.ts +0 -11
  263. package/src/transport/agent-api/reply.ts +0 -39
  264. package/src/transport/agent-api/upstream-delivery.ts +0 -45
  265. package/src/transport/agent-api/upstream-media-upload.ts +0 -70
  266. package/src/transport/agent-api/upstream-reply.ts +0 -43
  267. package/src/transport/agent-callback/http-handler.ts +0 -47
  268. package/src/transport/agent-callback/inbound.ts +0 -5
  269. package/src/transport/agent-callback/reply.ts +0 -13
  270. package/src/transport/agent-callback/request-handler.ts +0 -244
  271. package/src/transport/agent-callback/session.ts +0 -23
  272. package/src/transport/bot-webhook/active-reply.ts +0 -39
  273. package/src/transport/bot-webhook/http-handler.ts +0 -48
  274. package/src/transport/bot-webhook/inbound-normalizer.test.ts +0 -433
  275. package/src/transport/bot-webhook/inbound-normalizer.ts +0 -558
  276. package/src/transport/bot-webhook/inbound.ts +0 -5
  277. package/src/transport/bot-webhook/message-shape.ts +0 -92
  278. package/src/transport/bot-webhook/protocol.ts +0 -148
  279. package/src/transport/bot-webhook/reply.ts +0 -15
  280. package/src/transport/bot-webhook/request-handler.ts +0 -394
  281. package/src/transport/bot-webhook/session.ts +0 -23
  282. package/src/transport/bot-ws/inbound.test.ts +0 -290
  283. package/src/transport/bot-ws/inbound.ts +0 -163
  284. package/src/transport/bot-ws/media.test.ts +0 -44
  285. package/src/transport/bot-ws/media.ts +0 -321
  286. package/src/transport/bot-ws/reply.test.ts +0 -450
  287. package/src/transport/bot-ws/reply.ts +0 -365
  288. package/src/transport/bot-ws/sdk-adapter.test.ts +0 -187
  289. package/src/transport/bot-ws/sdk-adapter.ts +0 -314
  290. package/src/transport/bot-ws/session.ts +0 -28
  291. package/src/transport/http/common.ts +0 -109
  292. package/src/transport/http/registry.ts +0 -92
  293. package/src/transport/http/request-handler.ts +0 -84
  294. package/src/types/account.ts +0 -70
  295. package/src/types/config.ts +0 -114
  296. package/src/types/constants.ts +0 -31
  297. package/src/types/events.ts +0 -21
  298. package/src/types/global.d.ts +0 -9
  299. package/src/types/index.ts +0 -17
  300. package/src/types/legacy-stream.ts +0 -50
  301. package/src/types/message.ts +0 -189
  302. package/src/types/runtime-context.ts +0 -28
  303. package/src/types/runtime.ts +0 -165
  304. package/src/types.ts +0 -41
  305. package/src/upstream/index.ts +0 -150
  306. package/src/upstream.test.ts +0 -84
  307. package/src/wecom_msg_adapter/markdown_adapter.ts +0 -331
  308. package/tsconfig.json +0 -22
  309. package/vitest.config.ts +0 -26
  310. /package/{src/capability/agent/index.ts → dist/src/capability/agent/index.js} +0 -0
  311. /package/{src/capability/bot/index.ts → dist/src/capability/bot/index.js} +0 -0
  312. /package/{src/capability/calendar/index.ts → dist/src/capability/calendar/index.js} +0 -0
  313. /package/{src/capability/index.ts → dist/src/capability/index.js} +0 -0
@@ -0,0 +1,1556 @@
1
+ import fs from "node:fs";
2
+ import { isWecomAgentSource } from "../../runtime/source-registry.js";
3
+ import { resolveAgentAccountOrUndefined } from "../bot/fallback-delivery.js";
4
+ import { WecomDocClient } from "./client.js";
5
+ import { wecomDocToolSchema } from "./schema.js";
6
+ function readString(value) {
7
+ const trimmed = String(value ?? "").trim();
8
+ return trimmed || "";
9
+ }
10
+ function mapDocTypeLabel(docType) {
11
+ if (docType === 10)
12
+ return "智能表格";
13
+ return docType === 4 ? "表格" : "文档";
14
+ }
15
+ function summarizeDocInfo(info = {}) {
16
+ const docName = readString(info.doc_name) || "未命名文档";
17
+ const docType = mapDocTypeLabel(Number(info.doc_type));
18
+ return `${docType}"${docName}"信息已获取`;
19
+ }
20
+ function summarizeDocAuth(result = {}) {
21
+ return `权限信息已获取:通知成员 ${result.docMembers?.length ?? 0},协作者 ${result.coAuthList?.length ?? 0}`;
22
+ }
23
+ function readBooleanFlag(value) {
24
+ return typeof value === "boolean" ? value : null;
25
+ }
26
+ function formatDocMemberRef(value) {
27
+ if (!value || typeof value !== "object" || Array.isArray(value))
28
+ return "";
29
+ const userid = readString(value.userid ?? value.userId);
30
+ if (userid)
31
+ return `userid:${userid}`;
32
+ const partyid = readString(value.partyid);
33
+ if (partyid)
34
+ return `partyid:${partyid}`;
35
+ const tagid = readString(value.tagid);
36
+ if (tagid)
37
+ return `tagid:${tagid}`;
38
+ return "";
39
+ }
40
+ function mapDocMemberList(values) {
41
+ return Array.isArray(values)
42
+ ? values.map((item) => formatDocMemberRef(item)).filter(Boolean)
43
+ : [];
44
+ }
45
+ function describeFlagState(value, enabledLabel, disabledLabel, unknownLabel = "未知") {
46
+ if (value === true)
47
+ return enabledLabel;
48
+ if (value === false)
49
+ return disabledLabel;
50
+ return unknownLabel;
51
+ }
52
+ function buildDocAuthDiagnosis(result = {}, requesterSenderId = "") {
53
+ const accessRule = result.accessRule && typeof result.accessRule === "object" ? result.accessRule : {};
54
+ const viewers = mapDocMemberList(result.docMembers);
55
+ const collaborators = mapDocMemberList(result.coAuthList);
56
+ const requester = readString(requesterSenderId);
57
+ const requesterViewerRef = requester ? `userid:${requester}` : "";
58
+ const requesterIsViewer = requesterViewerRef ? viewers.includes(requesterViewerRef) : false;
59
+ const requesterIsCollaborator = requesterViewerRef
60
+ ? collaborators.includes(requesterViewerRef)
61
+ : false;
62
+ const internalAccessEnabled = readBooleanFlag(accessRule.enable_corp_internal);
63
+ const externalAccessEnabled = readBooleanFlag(accessRule.enable_corp_external);
64
+ const externalShareAllowed = typeof accessRule.ban_share_external === "boolean" ? !accessRule.ban_share_external : null;
65
+ const likelyAnonymousLinkFailure = internalAccessEnabled === true && externalAccessEnabled === false;
66
+ const findings = [
67
+ `企业内访问:${describeFlagState(internalAccessEnabled, "开启", "关闭")}`,
68
+ `企业外访问:${describeFlagState(externalAccessEnabled, "开启", "关闭")}`,
69
+ `外部分享:${describeFlagState(externalShareAllowed, "允许", "禁止")}`,
70
+ `查看成员:${viewers.length}`,
71
+ `协作者:${collaborators.length}`,
72
+ ];
73
+ const recommendations = [];
74
+ if (likelyAnonymousLinkFailure) {
75
+ recommendations.push('当前更像是仅企业内可访问;匿名浏览器或未登录企业微信环境通常会显示"文档不存在"。');
76
+ }
77
+ if (requester) {
78
+ if (requesterIsCollaborator) {
79
+ recommendations.push(`当前请求人 ${requester} 已在协作者列表中。`);
80
+ }
81
+ else if (requesterIsViewer) {
82
+ recommendations.push(`当前请求人 ${requester} 已在查看成员列表中,但还不是协作者。`);
83
+ }
84
+ else {
85
+ recommendations.push(`当前请求人 ${requester} 不在查看成员或协作者列表中。`);
86
+ }
87
+ }
88
+ return {
89
+ internalAccessEnabled,
90
+ externalAccessEnabled,
91
+ externalShareAllowed,
92
+ viewerCount: viewers.length,
93
+ collaboratorCount: collaborators.length,
94
+ viewers,
95
+ collaborators,
96
+ requesterSenderId: requester || undefined,
97
+ requesterRole: requesterIsCollaborator
98
+ ? "collaborator"
99
+ : requesterIsViewer
100
+ ? "viewer"
101
+ : requester
102
+ ? "none"
103
+ : "unknown",
104
+ likelyAnonymousLinkFailure,
105
+ findings,
106
+ recommendations,
107
+ };
108
+ }
109
+ function summarizeDocAuthDiagnosis(diagnosis = {}) {
110
+ const parts = Array.isArray(diagnosis.findings) ? diagnosis.findings : [];
111
+ return parts.length > 0 ? `文档权限诊断:${parts.join(",")}` : "文档权限诊断已完成";
112
+ }
113
+ function buildDocIdUsageHint(docId) {
114
+ const normalizedDocId = readString(docId);
115
+ if (!normalizedDocId)
116
+ return "";
117
+ return `后续权限、分享和诊断操作请使用真实 docId:${normalizedDocId};不要直接使用分享链接路径中的片段。`;
118
+ }
119
+ function safeParseJson(text) {
120
+ try {
121
+ return JSON.parse(text);
122
+ }
123
+ catch {
124
+ return null;
125
+ }
126
+ }
127
+ function extractEmbeddedJson(html, variableName) {
128
+ const source = String(html ?? "");
129
+ if (!source)
130
+ return null;
131
+ const marker = `window.${variableName}=`;
132
+ const start = source.indexOf(marker);
133
+ if (start < 0)
134
+ return null;
135
+ const valueStart = start + marker.length;
136
+ const end = source.indexOf(";</script>", valueStart);
137
+ if (end < 0)
138
+ return null;
139
+ return safeParseJson(source.slice(valueStart, end));
140
+ }
141
+ function buildShareLinkDiagnosis(params) {
142
+ const { shareUrl, finalUrl, status, contentType, basicClientVars } = params;
143
+ const parsedUrl = new URL(finalUrl || shareUrl);
144
+ const pathSegments = parsedUrl.pathname.split("/").filter(Boolean);
145
+ const pathResourceType = readString(pathSegments[0]);
146
+ const pathResourceId = readString(pathSegments[1]);
147
+ const shareCode = readString(parsedUrl.searchParams.get("scode"));
148
+ const userInfo = basicClientVars?.userInfo && typeof basicClientVars.userInfo === "object"
149
+ ? basicClientVars.userInfo
150
+ : {};
151
+ const docInfo = basicClientVars?.docInfo && typeof basicClientVars.docInfo === "object"
152
+ ? basicClientVars.docInfo
153
+ : {};
154
+ const padInfo = docInfo?.padInfo && typeof docInfo.padInfo === "object" ? docInfo.padInfo : {};
155
+ const ownerInfo = docInfo?.ownerInfo && typeof docInfo.ownerInfo === "object" ? docInfo.ownerInfo : {};
156
+ const shareInfo = docInfo?.shareInfo && typeof docInfo.shareInfo === "object" ? docInfo.shareInfo : {};
157
+ const aclInfo = docInfo?.aclInfo && typeof docInfo.aclInfo === "object" ? docInfo.aclInfo : {};
158
+ const userType = readString(userInfo.userType);
159
+ const padType = readString(padInfo.padType);
160
+ const padId = readString(padInfo.padId);
161
+ const padTitle = readString(padInfo.padTitle);
162
+ const isGuest = userType === "guest" || Number(userInfo.loginType) === 0;
163
+ const isBlankPage = padType === "blankpage";
164
+ const likelyUnavailableToGuest = isGuest && isBlankPage && !padTitle;
165
+ const findings = [
166
+ `HTTP ${String(status || "")}`.trim(),
167
+ `内容类型:${readString(contentType) || "未知"}`,
168
+ `访问身份:${userType || "未知"}`,
169
+ `页面类型:${padType || "未知"}`,
170
+ `路径资源:${pathResourceType || "未知"} / ${pathResourceId || "未知"}`,
171
+ ];
172
+ const recommendations = [];
173
+ if (likelyUnavailableToGuest) {
174
+ recommendations.push('当前链接对 guest/未登录企业微信环境返回 blankpage,外部访问会表现为打不开或像"文档不存在"。');
175
+ }
176
+ if (shareCode) {
177
+ recommendations.push(`当前链接带有分享码 scode=${shareCode}。如分享码过期或未生效,外部访问会失败。`);
178
+ }
179
+ if (pathResourceId && padId && pathResourceId !== padId) {
180
+ recommendations.push(`链接路径中的资源标识与页面 padId 不一致:path=${pathResourceId},padId=${padId}。`);
181
+ }
182
+ if (pathResourceId && padId && pathResourceId === padId) {
183
+ recommendations.push("链接路径资源标识与页面 padId 一致,但这仍不等同于 Wedoc API 可用的真实 docId。");
184
+ }
185
+ return {
186
+ shareUrl,
187
+ finalUrl,
188
+ httpStatus: status,
189
+ contentType: readString(contentType) || undefined,
190
+ pathResourceType: pathResourceType || undefined,
191
+ pathResourceId: pathResourceId || undefined,
192
+ shareCode: shareCode || undefined,
193
+ userType: userType || undefined,
194
+ isGuest,
195
+ padId: padId || undefined,
196
+ padType: padType || undefined,
197
+ padTitle: padTitle || undefined,
198
+ ownerId: readString(ownerInfo.ownerId) || undefined,
199
+ hasShareInfo: Object.keys(shareInfo).length > 0,
200
+ hasAclInfo: Object.keys(aclInfo).length > 0,
201
+ likelyUnavailableToGuest,
202
+ findings,
203
+ recommendations,
204
+ };
205
+ }
206
+ async function inspectWecomShareLink(params) {
207
+ const { shareUrl } = params;
208
+ const normalizedUrl = readString(shareUrl);
209
+ if (!normalizedUrl)
210
+ throw new Error("shareUrl required");
211
+ let parsed;
212
+ try {
213
+ parsed = new URL(normalizedUrl);
214
+ }
215
+ catch {
216
+ throw new Error("shareUrl must be a valid URL");
217
+ }
218
+ // To protect URLs containing underscores from markdown italic corruption in output, we ensure we return exactly what we got or wrap it later.
219
+ const response = await fetch(parsed.toString(), {
220
+ headers: {
221
+ "user-agent": "OpenClaw-Wechat/1.0",
222
+ accept: "text/html,application/xhtml+xml",
223
+ },
224
+ });
225
+ const contentType = response.headers?.get("content-type") || "";
226
+ const html = await response.text();
227
+ const basicClientVars = extractEmbeddedJson(html, "basicClientVars");
228
+ const diagnosis = buildShareLinkDiagnosis({
229
+ shareUrl: normalizedUrl,
230
+ finalUrl: response.url || parsed.toString(),
231
+ status: response.status,
232
+ contentType,
233
+ basicClientVars,
234
+ });
235
+ return {
236
+ raw: {
237
+ httpStatus: response.status,
238
+ // Markdown italic protection for URLs
239
+ finalUrl: `\u00A0${response.url || parsed.toString()}\u00A0`.trim(),
240
+ contentType,
241
+ basicClientVars,
242
+ },
243
+ diagnosis,
244
+ };
245
+ }
246
+ function summarizeShareLinkDiagnosis(diagnosis = {}) {
247
+ const parts = Array.isArray(diagnosis.findings) ? diagnosis.findings : [];
248
+ return parts.length > 0 ? `分享链接校验:${parts.join(",")}` : "分享链接校验已完成";
249
+ }
250
+ function summarizeSheetProperties(result = {}) {
251
+ return `表格属性已获取:工作表 ${result.properties?.length ?? 0}`;
252
+ }
253
+ function summarizeDocAccess(result = {}) {
254
+ const parts = [];
255
+ if (result.addedViewerCount)
256
+ parts.push(`新增查看成员 ${result.addedViewerCount}`);
257
+ if (result.addedCollaboratorCount)
258
+ parts.push(`新增协作者 ${result.addedCollaboratorCount}`);
259
+ if (result.removedViewerCount)
260
+ parts.push(`移除查看成员 ${result.removedViewerCount}`);
261
+ if (result.removedCollaboratorCount)
262
+ parts.push(`移除协作者 ${result.removedCollaboratorCount}`);
263
+ return parts.length > 0 ? `文档权限已更新:${parts.join(",")}` : "文档权限已更新";
264
+ }
265
+ function summarizeFormInfo(result = {}) {
266
+ const title = readString(result.formInfo?.form_title) || "未命名收集表";
267
+ return `收集表"${title}"信息已获取`;
268
+ }
269
+ function summarizeFormAnswer(result = {}) {
270
+ return `收集表答案已获取:字段 ${result.answerList?.length ?? 0}`;
271
+ }
272
+ function summarizeFormStatistic(result = {}) {
273
+ return `收集表统计已获取:请求 ${result.items?.length ?? 0},成功 ${result.successCount ?? 0}`;
274
+ }
275
+ function summarizeAdvancedAccount(result = {}, action) {
276
+ if (action === "assign")
277
+ return `高级功能账号分配任务已提交,jobid: ${result.jobid || "未知"}`;
278
+ if (action === "cancel")
279
+ return `高级功能账号取消任务已提交,jobid: ${result.jobid || "未知"}`;
280
+ return `高级功能账号列表已获取:${result.userList?.length ?? 0} 个`;
281
+ }
282
+ function readMemberUserId(value) {
283
+ if (typeof value === "string" || typeof value === "number") {
284
+ return readString(value);
285
+ }
286
+ if (!value || typeof value !== "object" || Array.isArray(value))
287
+ return "";
288
+ return readString(value.userid ?? value.userId);
289
+ }
290
+ function hasMemberUserId(values, requesterSenderId) {
291
+ const normalizedRequesterSenderId = readString(requesterSenderId);
292
+ if (!normalizedRequesterSenderId)
293
+ return false;
294
+ return (Array.isArray(values) &&
295
+ values.some((item) => readMemberUserId(item) === normalizedRequesterSenderId));
296
+ }
297
+ function resolveCreateCollaborators(params) {
298
+ const { toolContext, requestParams } = params;
299
+ const explicitCollaborators = Array.isArray(requestParams?.collaborators)
300
+ ? [...requestParams.collaborators]
301
+ : [];
302
+ const requesterSenderId = readString(toolContext?.senderId || toolContext?.requesterSenderId); // align with OpenClaw standard `senderId`
303
+ if (!requesterSenderId)
304
+ return explicitCollaborators;
305
+ // By default, let's always auto-grant requester
306
+ if (hasMemberUserId(explicitCollaborators, requesterSenderId))
307
+ return explicitCollaborators;
308
+ if (hasMemberUserId(requestParams?.viewers, requesterSenderId))
309
+ return explicitCollaborators;
310
+ explicitCollaborators.push(requesterSenderId);
311
+ return explicitCollaborators;
312
+ }
313
+ function buildToolResult(payload) {
314
+ // To avoid formatting issues with URLs having underscores rendering as markdown Italics
315
+ if (payload.url)
316
+ payload.url = `<${payload.url}>`;
317
+ if (payload.diagnosis?.finalUrl)
318
+ payload.diagnosis.finalUrl = `<${payload.diagnosis.finalUrl}>`;
319
+ if (payload.diagnosis?.shareUrl)
320
+ payload.diagnosis.shareUrl = `<${payload.diagnosis.shareUrl}>`;
321
+ return {
322
+ content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
323
+ details: payload,
324
+ };
325
+ }
326
+ export function registerWecomDocTools(api) {
327
+ if (typeof api?.registerTool !== "function")
328
+ return;
329
+ const docClient = new WecomDocClient();
330
+ api.registerTool((toolContext) => {
331
+ if (toolContext?.messageChannel !== "wecom" ||
332
+ !isWecomAgentSource({
333
+ accountId: toolContext?.agentAccountId || toolContext?.accountId,
334
+ sessionKey: toolContext?.sessionKey,
335
+ sessionId: toolContext?.sessionId,
336
+ })) {
337
+ return null;
338
+ }
339
+ return {
340
+ name: "wecom_doc",
341
+ label: "WeCom Doc",
342
+ description: "企业微信文档工具。支持文档/表格/收集表完整CRUD操作、查看/协作者权限配置、属性查询以及分享打不开可用性诊断功能。",
343
+ parameters: wecomDocToolSchema,
344
+ async execute(_toolCallId, params) {
345
+ try {
346
+ let accountId = params.accountId || toolContext?.agentAccountId || toolContext?.accountId || "default";
347
+ const account = resolveAgentAccountOrUndefined(api.config, accountId);
348
+ if (!account || !account.configured) {
349
+ throw new Error(`WeCom account ${accountId} not configured for Doc API requirements`);
350
+ }
351
+ const action = params.action;
352
+ switch (action) {
353
+ case "create": {
354
+ const explicitCollaborators = Array.isArray(params.collaborators)
355
+ ? [...params.collaborators]
356
+ : [];
357
+ const result = await docClient.createDoc({
358
+ agent: account,
359
+ docName: params.docName,
360
+ docType: params.docType,
361
+ spaceId: params.spaceId,
362
+ fatherId: params.fatherId,
363
+ adminUsers: params.adminUsers,
364
+ });
365
+ // Auto-set security rules for better default permissions (internal users can edit)
366
+ try {
367
+ await docClient.setDocJoinRule({
368
+ agent: account,
369
+ docId: result.docId,
370
+ request: {
371
+ enable_corp_internal: true,
372
+ corp_internal_auth: 2, // 2 = edit permission
373
+ enable_corp_external: false,
374
+ ban_share_external: false,
375
+ },
376
+ });
377
+ }
378
+ catch (err) {
379
+ // Non-fatal: document created, just default permissions may be read-only
380
+ }
381
+ // Handle initial content (title/body separation) if provided
382
+ // Supports: string (text) or {type: "text"|"image", content/url: string}
383
+ let contentResult = null;
384
+ if (Array.isArray(params.init_content) && params.init_content.length > 0) {
385
+ try {
386
+ // Helper: check if content item is an image
387
+ const isImageItem = (item) => {
388
+ if (typeof item === "object" && item !== null) {
389
+ return item.type === "image" || (item.url && !item.content);
390
+ }
391
+ if (typeof item === "string") {
392
+ // Detect image URLs
393
+ return (item.startsWith("http") &&
394
+ (item.includes(".png") ||
395
+ item.includes(".jpg") ||
396
+ item.includes(".jpeg") ||
397
+ item.includes(".gif") ||
398
+ item.includes("qpic.cn") ||
399
+ item.includes("weixin.qq.com")));
400
+ }
401
+ return false;
402
+ };
403
+ // Helper: get image URL from content item
404
+ const getImageUrl = (item) => {
405
+ if (typeof item === "object" && item !== null) {
406
+ return item.url || item.content || "";
407
+ }
408
+ return String(item);
409
+ };
410
+ // Helper: get text from content item
411
+ const getText = (item) => {
412
+ if (typeof item === "object" && item !== null) {
413
+ return item.content || item.text || "";
414
+ }
415
+ return String(item);
416
+ };
417
+ // Helper: download image from URL or read local file and convert to base64
418
+ const getImageAsBase64 = async (imageSource) => {
419
+ // Check if it's a local file path or remote URL
420
+ const isLocalFile = !imageSource.startsWith("http") && !imageSource.startsWith("data:");
421
+ if (isLocalFile) {
422
+ // Local file path - read using Node.js fs
423
+ const fs = await import("fs");
424
+ const path = await import("path");
425
+ // Resolve to absolute path if relative
426
+ const absolutePath = path.isAbsolute(imageSource)
427
+ ? imageSource
428
+ : path.join(process.cwd(), imageSource);
429
+ if (!fs.existsSync(absolutePath)) {
430
+ throw new Error(`Local image file not found: ${absolutePath}`);
431
+ }
432
+ const fileBuffer = fs.readFileSync(absolutePath);
433
+ return fileBuffer.toString("base64");
434
+ }
435
+ else if (imageSource.startsWith("data:")) {
436
+ // Data URL (base64 already)
437
+ const matches = imageSource.match(/^data:image\/(?:png|jpeg|gif|webp);base64,(.*)$/);
438
+ if (matches && matches[1]) {
439
+ return matches[1];
440
+ }
441
+ throw new Error("Invalid data URL format");
442
+ }
443
+ else {
444
+ // Remote URL - download first
445
+ console.log(`[wecom-doc] Downloading remote image: ${imageSource.substring(0, 50)}...`);
446
+ const response = await fetch(imageSource);
447
+ if (!response.ok) {
448
+ throw new Error(`Failed to download image: ${response.status} ${response.statusText}`);
449
+ }
450
+ const arrayBuffer = await response.arrayBuffer();
451
+ return Buffer.from(arrayBuffer).toString("base64");
452
+ }
453
+ };
454
+ // Step 1: Insert first paragraph (title) at index 0
455
+ if (params.init_content[0]) {
456
+ const firstItem = params.init_content[0];
457
+ if (isImageItem(firstItem)) {
458
+ // First item is image - upload first, then insert at index 0
459
+ const imgUrl = getImageUrl(firstItem);
460
+ try {
461
+ // Upload image to WeCom to get proper image_id
462
+ const base64 = await getImageAsBase64(imgUrl);
463
+ const uploadResult = await docClient.uploadDocImage({
464
+ agent: account,
465
+ docId: result.docId,
466
+ base64_content: base64,
467
+ });
468
+ console.log(`[wecom-doc] Title image uploaded: ${uploadResult.width}x${uploadResult.height}`);
469
+ // Insert image using uploaded URL
470
+ // Note: version is optional, API handles concurrency
471
+ await docClient.updateDocContent({
472
+ agent: account,
473
+ docId: result.docId,
474
+ requests: [
475
+ {
476
+ insert_image: {
477
+ image_id: uploadResult.url,
478
+ location: { index: 0 },
479
+ width: uploadResult.width,
480
+ height: uploadResult.height,
481
+ },
482
+ },
483
+ ],
484
+ });
485
+ }
486
+ catch (uploadErr) {
487
+ console.error(`Failed to upload first image ${imgUrl}:`, uploadErr);
488
+ throw new Error(`First image upload failed: ${uploadErr instanceof Error ? uploadErr.message : String(uploadErr)}`);
489
+ }
490
+ }
491
+ else {
492
+ const titleText = getText(firstItem);
493
+ await docClient.updateDocContent({
494
+ agent: account,
495
+ docId: result.docId,
496
+ requests: [
497
+ {
498
+ insert_text: {
499
+ text: titleText,
500
+ location: { index: 0 },
501
+ },
502
+ },
503
+ ],
504
+ });
505
+ // Apply Title Styling (Bold)
506
+ if (titleText.length > 0) {
507
+ await docClient.updateDocContent({
508
+ agent: account,
509
+ docId: result.docId,
510
+ requests: [
511
+ {
512
+ update_text_property: {
513
+ text_property: { bold: true },
514
+ ranges: [{ start_index: 0, length: titleText.length }],
515
+ },
516
+ },
517
+ ],
518
+ });
519
+ }
520
+ }
521
+ }
522
+ // Step 2: For subsequent items, append with proper paragraph handling
523
+ // Per API spec: must get latest version and index before each batch_update
524
+ for (let i = 1; i < params.init_content.length; i++) {
525
+ const item = params.init_content[i];
526
+ // Refresh content to get latest document structure and version
527
+ // API requires: version difference ≤ 100 from latest
528
+ const currentContent = await docClient.getDocContent({
529
+ agent: account,
530
+ docId: result.docId,
531
+ });
532
+ // Get the end index of the document
533
+ const docEndIndex = currentContent.document.end;
534
+ const currentVersion = currentContent.version;
535
+ if (isImageItem(item)) {
536
+ // Insert image
537
+ const imgUrl = getImageUrl(item);
538
+ try {
539
+ // Upload image to WeCom
540
+ const base64 = await getImageAsBase64(imgUrl);
541
+ const uploadResult = await docClient.uploadDocImage({
542
+ agent: account,
543
+ docId: result.docId,
544
+ base64_content: base64,
545
+ });
546
+ console.log(`[wecom-doc] Item ${i} image uploaded: ${uploadResult.width}x${uploadResult.height}`);
547
+ // Step 2: Create new paragraph and insert image in one batch (2 operations ≤ 30)
548
+ // Per API spec: all indices are based on the same document snapshot
549
+ // insert_paragraph at docEndIndex creates a new paragraph
550
+ // insert_image at docEndIndex + 1 inserts into the newly created paragraph
551
+ await docClient.updateDocContent({
552
+ agent: account,
553
+ docId: result.docId,
554
+ version: currentVersion, // Pass version for concurrency control
555
+ requests: [
556
+ {
557
+ insert_paragraph: {
558
+ location: { index: docEndIndex },
559
+ },
560
+ },
561
+ {
562
+ insert_image: {
563
+ image_id: uploadResult.url,
564
+ location: { index: docEndIndex + 1 },
565
+ width: uploadResult.width,
566
+ height: uploadResult.height,
567
+ },
568
+ },
569
+ ],
570
+ });
571
+ }
572
+ catch (uploadErr) {
573
+ console.error(`Failed to upload image ${imgUrl}:`, uploadErr);
574
+ throw new Error(`Image upload failed: ${uploadErr instanceof Error ? uploadErr.message : String(uploadErr)}`);
575
+ }
576
+ }
577
+ else {
578
+ const text = getText(item);
579
+ if (!text)
580
+ continue;
581
+ // Insert text: create paragraph and insert text in one batch (2 operations ≤ 30)
582
+ // Per API spec: all indices are based on the same document snapshot
583
+ // insert_paragraph at docEndIndex creates a new paragraph
584
+ // insert_text at docEndIndex + 1 inserts into the newly created paragraph
585
+ await docClient.updateDocContent({
586
+ agent: account,
587
+ docId: result.docId,
588
+ version: currentVersion, // Pass version for concurrency control
589
+ requests: [
590
+ {
591
+ insert_paragraph: {
592
+ location: { index: docEndIndex },
593
+ },
594
+ },
595
+ {
596
+ insert_text: {
597
+ text: text,
598
+ location: { index: docEndIndex + 1 },
599
+ },
600
+ },
601
+ ],
602
+ });
603
+ }
604
+ }
605
+ contentResult = "init_content_populated";
606
+ }
607
+ catch (err) {
608
+ contentResult = `content_failed: ${err instanceof Error ? err.message : String(err)}`;
609
+ }
610
+ }
611
+ let accessResult = null;
612
+ if ((Array.isArray(params.viewers) && params.viewers.length > 0) ||
613
+ explicitCollaborators.length > 0) {
614
+ try {
615
+ accessResult = await docClient.grantDocAccess({
616
+ agent: account,
617
+ docId: result.docId,
618
+ viewers: params.viewers,
619
+ collaborators: explicitCollaborators,
620
+ });
621
+ }
622
+ catch (err) {
623
+ return buildToolResult({
624
+ ok: false,
625
+ partial: true,
626
+ action: "create",
627
+ accountId: account.accountId,
628
+ resourceType: result.docTypeLabel,
629
+ canonicalDocId: result.docId,
630
+ docId: result.docId,
631
+ title: readString(params.docName),
632
+ url: result.url || undefined,
633
+ summary: `已创建${mapDocTypeLabel(result.docType)}"${readString(params.docName)}"(docId: ${result.docId}),但权限授予失败`,
634
+ usageHint: buildDocIdUsageHint(result.docId) || undefined,
635
+ error: err instanceof Error ? err.message : String(err),
636
+ raw: { create: result.raw },
637
+ });
638
+ }
639
+ }
640
+ return buildToolResult({
641
+ ok: true,
642
+ action: "create",
643
+ accountId: account.accountId,
644
+ resourceType: result.docTypeLabel,
645
+ canonicalDocId: result.docId,
646
+ docId: result.docId,
647
+ title: readString(params.docName),
648
+ url: result.url || undefined,
649
+ summary: accessResult
650
+ ? `已创建${mapDocTypeLabel(result.docType)}"${readString(params.docName)}"(docId: ${result.docId});${summarizeDocAccess(accessResult)}` +
651
+ (contentResult ? `;内容填充: ${contentResult}` : "")
652
+ : `已创建${mapDocTypeLabel(result.docType)}"${readString(params.docName)}"(docId: ${result.docId})` +
653
+ (contentResult ? `;内容填充: ${contentResult}` : ""),
654
+ usageHint: buildDocIdUsageHint(result.docId) || undefined,
655
+ raw: accessResult ? { create: result.raw, access: accessResult.raw } : result.raw,
656
+ });
657
+ }
658
+ case "rename": {
659
+ const result = await docClient.renameDoc({
660
+ agent: account,
661
+ docId: params.docId,
662
+ newName: params.newName,
663
+ });
664
+ return buildToolResult({
665
+ ok: true,
666
+ action: "rename",
667
+ accountId: account.accountId,
668
+ docId: result.docId,
669
+ title: result.newName,
670
+ summary: `文档已重命名为"${result.newName}"`,
671
+ raw: result.raw,
672
+ });
673
+ }
674
+ case "copy": {
675
+ const result = await docClient.copyDoc({
676
+ agent: account,
677
+ docId: params.docId,
678
+ newName: params.newName,
679
+ spaceId: params.spaceId,
680
+ fatherId: params.fatherId,
681
+ });
682
+ return buildToolResult({
683
+ ok: true,
684
+ action: "copy",
685
+ accountId: account.accountId,
686
+ docId: result.docId,
687
+ summary: `文档已成功复制,新 docId: ${result.docId}`,
688
+ raw: result.raw,
689
+ });
690
+ }
691
+ case "get_info": {
692
+ const result = await docClient.getDocBaseInfo({
693
+ agent: account,
694
+ docId: params.docId,
695
+ });
696
+ return buildToolResult({
697
+ ok: true,
698
+ action: "get_info",
699
+ accountId: account.accountId,
700
+ docId: params.docId,
701
+ title: readString(result.info?.doc_name) || undefined,
702
+ resourceType: Number(result.info?.doc_type) === 10
703
+ ? "smart_table"
704
+ : Number(result.info?.doc_type) === 4
705
+ ? "spreadsheet"
706
+ : "doc",
707
+ summary: summarizeDocInfo(result.info),
708
+ raw: result.raw,
709
+ });
710
+ }
711
+ case "share": {
712
+ const result = await docClient.shareDoc({
713
+ agent: account,
714
+ docId: params.docId,
715
+ });
716
+ return buildToolResult({
717
+ ok: true,
718
+ action: "share",
719
+ accountId: account.accountId,
720
+ canonicalDocId: params.docId,
721
+ docId: params.docId,
722
+ url: result.shareUrl || undefined,
723
+ summary: result.shareUrl
724
+ ? `文档分享链接已获取(docId: ${params.docId})`
725
+ : `文档分享接口调用成功(docId: ${params.docId})`,
726
+ usageHint: buildDocIdUsageHint(params.docId) || undefined,
727
+ raw: result.raw,
728
+ });
729
+ }
730
+ case "get_auth": {
731
+ const result = await docClient.getDocAuth({
732
+ agent: account,
733
+ docId: params.docId,
734
+ });
735
+ const diagnosis = buildDocAuthDiagnosis(result, toolContext?.senderId);
736
+ return buildToolResult({
737
+ ok: true,
738
+ action: "get_auth",
739
+ accountId: account.accountId,
740
+ canonicalDocId: params.docId,
741
+ docId: params.docId,
742
+ summary: summarizeDocAuth(result),
743
+ diagnosis,
744
+ raw: result.raw,
745
+ });
746
+ }
747
+ case "diagnose_auth": {
748
+ const result = await docClient.getDocAuth({
749
+ agent: account,
750
+ docId: params.docId,
751
+ });
752
+ const diagnosis = buildDocAuthDiagnosis(result, toolContext?.senderId);
753
+ return buildToolResult({
754
+ ok: true,
755
+ action: "diagnose_auth",
756
+ accountId: account.accountId,
757
+ canonicalDocId: params.docId,
758
+ docId: params.docId,
759
+ summary: summarizeDocAuthDiagnosis(diagnosis),
760
+ diagnosis,
761
+ raw: result.raw,
762
+ });
763
+ }
764
+ case "validate_share_link": {
765
+ const result = await inspectWecomShareLink({
766
+ shareUrl: params.shareUrl,
767
+ });
768
+ return buildToolResult({
769
+ ok: true,
770
+ action: "validate_share_link",
771
+ accountId: account.accountId,
772
+ url: result.diagnosis.finalUrl || params.shareUrl,
773
+ summary: summarizeShareLinkDiagnosis(result.diagnosis),
774
+ diagnosis: result.diagnosis,
775
+ raw: result.raw,
776
+ });
777
+ }
778
+ case "delete": {
779
+ const result = await docClient.deleteDoc({
780
+ agent: account,
781
+ docId: params.docId,
782
+ formId: params.formId,
783
+ });
784
+ return buildToolResult({
785
+ ok: true,
786
+ action: "delete",
787
+ accountId: account.accountId,
788
+ docId: result.docId || undefined,
789
+ formId: result.formId || undefined,
790
+ summary: result.formId ? "收集表已删除" : "文档已删除",
791
+ raw: result.raw,
792
+ });
793
+ }
794
+ case "set_join_rule": {
795
+ const result = await docClient.setDocJoinRule({
796
+ agent: account,
797
+ docId: params.docId,
798
+ request: params.request,
799
+ });
800
+ return buildToolResult({
801
+ ok: true,
802
+ action: "set_join_rule",
803
+ accountId: account.accountId,
804
+ docId: result.docId,
805
+ summary: "文档查看规则已更新",
806
+ raw: result.raw,
807
+ });
808
+ }
809
+ case "set_member_auth": {
810
+ const result = await docClient.setDocMemberAuth({
811
+ agent: account,
812
+ docId: params.docId,
813
+ request: params.request,
814
+ });
815
+ return buildToolResult({
816
+ ok: true,
817
+ action: "set_member_auth",
818
+ accountId: account.accountId,
819
+ docId: result.docId,
820
+ summary: "文档通知范围及成员权限已更新",
821
+ raw: result.raw,
822
+ });
823
+ }
824
+ case "grant_access": {
825
+ const result = await docClient.grantDocAccess({
826
+ agent: account,
827
+ docId: params.docId,
828
+ viewers: params.viewers,
829
+ collaborators: params.collaborators,
830
+ removeViewers: params.removeViewers,
831
+ removeCollaborators: params.removeCollaborators,
832
+ authLevel: params.auth,
833
+ });
834
+ return buildToolResult({
835
+ ok: true,
836
+ action: "grant_access",
837
+ accountId: account.accountId,
838
+ docId: result.docId,
839
+ summary: summarizeDocAccess(result),
840
+ raw: result.raw,
841
+ });
842
+ }
843
+ case "add_collaborators": {
844
+ const result = await docClient.addDocCollaborators({
845
+ agent: account,
846
+ docId: params.docId,
847
+ collaborators: params.collaborators,
848
+ auth: params.auth,
849
+ });
850
+ return buildToolResult({
851
+ ok: true,
852
+ action: "add_collaborators",
853
+ accountId: account.accountId,
854
+ docId: result.docId,
855
+ summary: `协作者已添加:${result.addedCollaboratorCount ?? 0}`,
856
+ raw: result.raw,
857
+ });
858
+ }
859
+ case "get_content": {
860
+ const result = await docClient.getDocContent({
861
+ agent: account,
862
+ docId: params.docId,
863
+ });
864
+ return buildToolResult({
865
+ ok: true,
866
+ action: "get_content",
867
+ accountId: account.accountId,
868
+ docId: params.docId,
869
+ summary: "文档内容已获取",
870
+ raw: result.raw,
871
+ });
872
+ }
873
+ case "update_content": {
874
+ const result = await docClient.updateDocContent({
875
+ agent: account,
876
+ docId: params.docId,
877
+ requests: params.requests,
878
+ version: params.version,
879
+ });
880
+ const batchCount = result.batches ?? 1;
881
+ return buildToolResult({
882
+ ok: true,
883
+ action: "update_content",
884
+ accountId: account.accountId,
885
+ docId: params.docId,
886
+ summary: batchCount > 1
887
+ ? `文档内容已更新(自动分批,共${batchCount}批)`
888
+ : "文档内容已更新",
889
+ batches: batchCount,
890
+ raw: result.raw,
891
+ });
892
+ }
893
+ case "set_safety_setting": {
894
+ const result = await docClient.setDocSafetySetting({
895
+ agent: account,
896
+ docId: params.docId,
897
+ request: params.request,
898
+ });
899
+ return buildToolResult({
900
+ ok: true,
901
+ action: "set_safety_setting",
902
+ accountId: account.accountId,
903
+ docId: result.docId,
904
+ summary: "文档安全设置已更新",
905
+ raw: result.raw,
906
+ });
907
+ }
908
+ case "get_doc_security_setting": {
909
+ const result = await docClient.getDocAuth({
910
+ agent: account,
911
+ docId: params.docId,
912
+ });
913
+ return buildToolResult({
914
+ ok: true,
915
+ action: "get_doc_security_setting",
916
+ accountId: account.accountId,
917
+ docId: params.docId,
918
+ summary: "文档安全设置已获取",
919
+ details: result.secureSetting,
920
+ raw: result.raw,
921
+ });
922
+ }
923
+ case "mod_doc_security_setting": {
924
+ // Alias to setDocSafetySetting logic
925
+ const result = await docClient.setDocSafetySetting({
926
+ agent: account,
927
+ docId: params.docId,
928
+ request: params.setting,
929
+ });
930
+ return buildToolResult({
931
+ ok: true,
932
+ action: "mod_doc_security_setting",
933
+ accountId: account.accountId,
934
+ docId: result.docId,
935
+ summary: "文档安全设置已更新",
936
+ raw: result.raw,
937
+ });
938
+ }
939
+ case "mod_doc_member_notified_scope": {
940
+ const result = await docClient.modDocMemberNotifiedScope({
941
+ agent: account,
942
+ docId: params.docId,
943
+ notified_scope_type: params.notified_scope_type,
944
+ notified_member_list: params.notified_member_list,
945
+ });
946
+ return buildToolResult({
947
+ ok: true,
948
+ action: "mod_doc_member_notified_scope",
949
+ accountId: account.accountId,
950
+ docId: params.docId,
951
+ summary: "文档成员通知范围已更新",
952
+ raw: result,
953
+ });
954
+ }
955
+ case "create_form": {
956
+ // 创建收集表(表单)
957
+ try {
958
+ const result = await docClient.createCollect({
959
+ agent: account,
960
+ formInfo: params.formInfo,
961
+ spaceId: params.spaceId,
962
+ fatherId: params.fatherId,
963
+ });
964
+ const title = readString(result.title);
965
+ return buildToolResult({
966
+ ok: true,
967
+ action: "create_form",
968
+ accountId: account.accountId,
969
+ formId: result.formId,
970
+ title: title || undefined,
971
+ summary: title
972
+ ? `已创建收集表"${title}"(formId: ${result.formId})`
973
+ : `已创建收集表(formId: ${result.formId})`,
974
+ raw: result.raw,
975
+ });
976
+ }
977
+ catch (err) {
978
+ const errorMsg = err instanceof Error ? err.message : String(err);
979
+ return buildToolResult({
980
+ ok: false,
981
+ action: "create_form",
982
+ accountId: account.accountId,
983
+ error: errorMsg,
984
+ summary: "创建收集表失败",
985
+ raw: {},
986
+ });
987
+ }
988
+ }
989
+ case "modify_form": {
990
+ const result = await docClient.modifyCollect({
991
+ agent: account,
992
+ oper: params.oper,
993
+ formId: params.formId,
994
+ formInfo: params.formInfo,
995
+ });
996
+ const title = readString(result.title);
997
+ return buildToolResult({
998
+ ok: true,
999
+ action: "modify_form",
1000
+ accountId: account.accountId,
1001
+ formId: result.formId,
1002
+ title: title || undefined,
1003
+ summary: title
1004
+ ? `收集表已更新(${result.oper}):"${title}"`
1005
+ : `收集表已更新(${result.oper})`,
1006
+ raw: result.raw,
1007
+ });
1008
+ }
1009
+ case "get_form_info": {
1010
+ const result = await docClient.getFormInfo({
1011
+ agent: account,
1012
+ formId: params.formId,
1013
+ });
1014
+ return buildToolResult({
1015
+ ok: true,
1016
+ action: "get_form_info",
1017
+ accountId: account.accountId,
1018
+ formId: params.formId,
1019
+ title: readString(result.formInfo?.form_title) || undefined,
1020
+ summary: summarizeFormInfo(result),
1021
+ raw: result.raw,
1022
+ });
1023
+ }
1024
+ case "get_form_answer": {
1025
+ const result = await docClient.getFormAnswer({
1026
+ agent: account,
1027
+ repeatedId: params.repeatedId,
1028
+ answerIds: params.answerIds,
1029
+ });
1030
+ return buildToolResult({
1031
+ ok: true,
1032
+ action: "get_form_answer",
1033
+ accountId: account.accountId,
1034
+ repeatedId: params.repeatedId,
1035
+ summary: summarizeFormAnswer(result),
1036
+ raw: result.raw,
1037
+ });
1038
+ }
1039
+ case "get_form_statistic": {
1040
+ const result = await docClient.getFormStatistic({
1041
+ agent: account,
1042
+ requests: params.requests,
1043
+ });
1044
+ return buildToolResult({
1045
+ ok: true,
1046
+ action: "get_form_statistic",
1047
+ accountId: account.accountId,
1048
+ summary: summarizeFormStatistic(result),
1049
+ raw: result.raw,
1050
+ });
1051
+ }
1052
+ case "get_sheet_properties": {
1053
+ const result = await docClient.getSheetProperties({
1054
+ agent: account,
1055
+ docId: params.docId,
1056
+ });
1057
+ return buildToolResult({
1058
+ ok: true,
1059
+ action: "get_sheet_properties",
1060
+ accountId: account.accountId,
1061
+ docId: params.docId,
1062
+ summary: summarizeSheetProperties(result),
1063
+ raw: result.raw,
1064
+ });
1065
+ }
1066
+ case "edit_sheet_data": {
1067
+ const result = await docClient.editSheetData({
1068
+ agent: account,
1069
+ docId: params.docId,
1070
+ sheetId: params.sheetId,
1071
+ startRow: params.startRow ?? 0,
1072
+ startColumn: params.startColumn ?? 0,
1073
+ gridData: params.gridData,
1074
+ requests: params.requests, // Support direct requests for multiple operations
1075
+ });
1076
+ const summary = result.operations
1077
+ ? `在线表格已更新(${result.operations}个操作)`
1078
+ : "在线表格数据已编辑";
1079
+ return buildToolResult({
1080
+ ok: true,
1081
+ action: "edit_sheet_data",
1082
+ accountId: account.accountId,
1083
+ docId: result.docId,
1084
+ summary: summary,
1085
+ operations: result.operations,
1086
+ updatedCells: result.updatedCells,
1087
+ raw: result.raw,
1088
+ });
1089
+ }
1090
+ case "get_sheet_data": {
1091
+ const result = await docClient.getSheetData({
1092
+ agent: account,
1093
+ docId: params.docId,
1094
+ sheetId: params.sheetId,
1095
+ range: params.range,
1096
+ });
1097
+ return buildToolResult({
1098
+ ok: true,
1099
+ action: "get_sheet_data",
1100
+ accountId: account.accountId,
1101
+ docId: params.docId,
1102
+ summary: "在线表格数据已读取",
1103
+ data: result.data,
1104
+ raw: result.raw,
1105
+ });
1106
+ }
1107
+ case "modify_sheet_properties": {
1108
+ const result = await docClient.modifySheetProperties({
1109
+ agent: account,
1110
+ docId: params.docId,
1111
+ requests: params.requests,
1112
+ });
1113
+ return buildToolResult({
1114
+ ok: true,
1115
+ action: "modify_sheet_properties",
1116
+ accountId: account.accountId,
1117
+ docId: result.docId,
1118
+ summary: "在线表格属性已修改",
1119
+ raw: result.raw,
1120
+ });
1121
+ }
1122
+ case "smartsheet_add_records": {
1123
+ const result = await docClient.smartTableAddRecords({
1124
+ agent: account,
1125
+ docId: params.docId,
1126
+ sheetId: params.sheetId,
1127
+ records: params.records,
1128
+ key_type: params.key_type,
1129
+ });
1130
+ return buildToolResult({
1131
+ ok: true,
1132
+ action,
1133
+ accountId: account.accountId,
1134
+ docId: params.docId,
1135
+ summary: "智能表格记录已添加",
1136
+ raw: result.raw,
1137
+ });
1138
+ }
1139
+ case "smartsheet_update_records": {
1140
+ const result = await docClient.smartTableUpdateRecords({
1141
+ agent: account,
1142
+ docId: params.docId,
1143
+ sheetId: params.sheetId,
1144
+ records: params.records,
1145
+ });
1146
+ return buildToolResult({
1147
+ ok: true,
1148
+ action,
1149
+ accountId: account.accountId,
1150
+ docId: params.docId,
1151
+ summary: "智能表格记录已更新",
1152
+ raw: result.raw,
1153
+ });
1154
+ }
1155
+ case "smartsheet_del_records": {
1156
+ const result = await docClient.smartTableOperate({
1157
+ agent: account,
1158
+ docId: params.docId,
1159
+ operation: "del_records",
1160
+ bodyData: params,
1161
+ });
1162
+ return buildToolResult({
1163
+ ok: true,
1164
+ action,
1165
+ accountId: account.accountId,
1166
+ docId: params.docId,
1167
+ summary: "智能表格记录已删除",
1168
+ raw: result.raw,
1169
+ });
1170
+ }
1171
+ case "smartsheet_get_records": {
1172
+ const result = await docClient.smartTableGetRecords({ agent: account, ...params });
1173
+ return buildToolResult({
1174
+ ok: true,
1175
+ action,
1176
+ accountId: account.accountId,
1177
+ docId: params.docId,
1178
+ summary: result.records?.length
1179
+ ? `智能表格记录已获取:${result.records.length} 条`
1180
+ : "智能表格记录列表已获取",
1181
+ total: result.total,
1182
+ has_more: result.has_more,
1183
+ ver: result.ver,
1184
+ raw: result.raw,
1185
+ });
1186
+ }
1187
+ case "smartsheet_get_views": {
1188
+ const result = await docClient.smartTableGetViews({ agent: account, ...params });
1189
+ return buildToolResult({
1190
+ ok: true,
1191
+ action,
1192
+ accountId: account.accountId,
1193
+ docId: params.docId,
1194
+ summary: result.views?.length
1195
+ ? `智能表格视图已获取:${result.views.length} 个`
1196
+ : "智能表格视图列表已获取",
1197
+ total: result.total,
1198
+ has_more: result.has_more,
1199
+ raw: result.raw,
1200
+ });
1201
+ }
1202
+ case "smartsheet_get_sheets": {
1203
+ const result = await docClient.smartTableGetSheets({
1204
+ agent: account,
1205
+ docId: params.docId,
1206
+ sheet_id: params.sheet_id,
1207
+ need_all_type_sheet: params.need_all_type_sheet,
1208
+ });
1209
+ return buildToolResult({
1210
+ ok: true,
1211
+ action: "smartsheet_get_sheets",
1212
+ accountId: account.accountId,
1213
+ docId: params.docId,
1214
+ summary: `智能表格子表列表已获取:${result.sheets.length} 个`,
1215
+ raw: result.raw,
1216
+ });
1217
+ }
1218
+ case "smartsheet_add_sheet": {
1219
+ const result = await docClient.smartTableAddSheet({ agent: account, ...params });
1220
+ return buildToolResult({
1221
+ ok: true,
1222
+ action,
1223
+ accountId: account.accountId,
1224
+ docId: params.docId,
1225
+ summary: "智能表格子表已添加",
1226
+ raw: result.raw,
1227
+ });
1228
+ }
1229
+ case "smartsheet_del_sheet": {
1230
+ const result = await docClient.smartTableDelSheet({ agent: account, ...params });
1231
+ return buildToolResult({
1232
+ ok: true,
1233
+ action,
1234
+ accountId: account.accountId,
1235
+ docId: params.docId,
1236
+ summary: "智能表格子表已删除",
1237
+ raw: result.raw,
1238
+ });
1239
+ }
1240
+ case "smartsheet_update_sheet": {
1241
+ const result = await docClient.smartTableUpdateSheet({ agent: account, ...params });
1242
+ return buildToolResult({
1243
+ ok: true,
1244
+ action,
1245
+ accountId: account.accountId,
1246
+ docId: params.docId,
1247
+ summary: "智能表格子表已更新",
1248
+ raw: result.raw,
1249
+ });
1250
+ }
1251
+ case "smartsheet_add_view": {
1252
+ const result = await docClient.smartTableAddView({ agent: account, ...params });
1253
+ return buildToolResult({
1254
+ ok: true,
1255
+ action,
1256
+ accountId: account.accountId,
1257
+ docId: params.docId,
1258
+ summary: `智能表格视图已添加:${result.view?.view_title || "未知"}`,
1259
+ raw: result.raw,
1260
+ });
1261
+ }
1262
+ case "smartsheet_del_view": {
1263
+ const result = await docClient.smartTableDelView({ agent: account, ...params });
1264
+ return buildToolResult({
1265
+ ok: true,
1266
+ action,
1267
+ accountId: account.accountId,
1268
+ docId: params.docId,
1269
+ summary: `智能表格视图已删除:${params.view_ids?.length || 0} 个`,
1270
+ raw: result.raw,
1271
+ });
1272
+ }
1273
+ case "smartsheet_update_view": {
1274
+ const result = await docClient.smartTableUpdateView({ agent: account, ...params });
1275
+ return buildToolResult({
1276
+ ok: true,
1277
+ action,
1278
+ accountId: account.accountId,
1279
+ docId: params.docId,
1280
+ summary: `智能表格视图已更新:${result.view?.view_title || "未知"}`,
1281
+ raw: result.raw,
1282
+ });
1283
+ }
1284
+ case "smartsheet_add_fields": {
1285
+ const result = await docClient.smartTableAddFields({
1286
+ agent: account,
1287
+ docId: params.docId,
1288
+ sheetId: params.sheetId,
1289
+ fields: params.fields,
1290
+ autoCleanupDefaultField: params.autoCleanupDefaultField !== false, // Default true
1291
+ });
1292
+ return buildToolResult({
1293
+ ok: true,
1294
+ action,
1295
+ accountId: account.accountId,
1296
+ docId: params.docId,
1297
+ summary: `智能表格字段已添加:${result.fields?.length || 0} 个`,
1298
+ raw: result.raw,
1299
+ });
1300
+ }
1301
+ case "smartsheet_del_fields": {
1302
+ const result = await docClient.smartTableDelFields({ agent: account, ...params });
1303
+ return buildToolResult({
1304
+ ok: true,
1305
+ action,
1306
+ accountId: account.accountId,
1307
+ docId: params.docId,
1308
+ summary: `智能表格字段已删除:${params.field_ids?.length || 0} 个`,
1309
+ raw: result.raw,
1310
+ });
1311
+ }
1312
+ case "smartsheet_update_fields": {
1313
+ const result = await docClient.smartTableUpdateFields({ agent: account, ...params });
1314
+ return buildToolResult({
1315
+ ok: true,
1316
+ action,
1317
+ accountId: account.accountId,
1318
+ docId: params.docId,
1319
+ summary: `智能表格字段已更新:${result.fields?.length || 0} 个`,
1320
+ raw: result.raw,
1321
+ });
1322
+ }
1323
+ case "smartsheet_get_fields": {
1324
+ const result = await docClient.smartTableGetFields({ agent: account, ...params });
1325
+ return buildToolResult({
1326
+ ok: true,
1327
+ action,
1328
+ accountId: account.accountId,
1329
+ docId: params.docId,
1330
+ summary: result.fields?.length
1331
+ ? `智能表格字段已获取:${result.fields.length} 个`
1332
+ : "智能表格字段列表已获取",
1333
+ total: result.total,
1334
+ has_more: result.has_more,
1335
+ raw: result.raw,
1336
+ });
1337
+ }
1338
+ case "smartsheet_add_group": {
1339
+ const result = await docClient.smartTableAddGroup({ agent: account, ...params });
1340
+ return buildToolResult({
1341
+ ok: true,
1342
+ action,
1343
+ accountId: account.accountId,
1344
+ docId: params.docId,
1345
+ summary: "智能表格编组已添加",
1346
+ raw: result.raw,
1347
+ });
1348
+ }
1349
+ case "smartsheet_del_group": {
1350
+ const result = await docClient.smartTableDelGroup({ agent: account, ...params });
1351
+ return buildToolResult({
1352
+ ok: true,
1353
+ action,
1354
+ accountId: account.accountId,
1355
+ docId: params.docId,
1356
+ summary: "智能表格编组已删除",
1357
+ raw: result.raw,
1358
+ });
1359
+ }
1360
+ case "smartsheet_update_group": {
1361
+ const result = await docClient.smartTableUpdateGroup({ agent: account, ...params });
1362
+ return buildToolResult({
1363
+ ok: true,
1364
+ action,
1365
+ accountId: account.accountId,
1366
+ docId: params.docId,
1367
+ summary: "智能表格编组已更新",
1368
+ raw: result.raw,
1369
+ });
1370
+ }
1371
+ case "smartsheet_get_groups": {
1372
+ const result = await docClient.smartTableGetGroups({ agent: account, ...params });
1373
+ return buildToolResult({
1374
+ ok: true,
1375
+ action,
1376
+ accountId: account.accountId,
1377
+ docId: params.docId,
1378
+ summary: "智能表格编组列表已获取",
1379
+ raw: result.raw,
1380
+ });
1381
+ }
1382
+ case "smartsheet_add_external_records": {
1383
+ const result = await docClient.smartTableAddExternalRecords({
1384
+ agent: account,
1385
+ ...params,
1386
+ });
1387
+ return buildToolResult({
1388
+ ok: true,
1389
+ action,
1390
+ accountId: account.accountId,
1391
+ docId: params.docId,
1392
+ summary: "智能表格外部记录已添加",
1393
+ raw: result.raw,
1394
+ });
1395
+ }
1396
+ case "smartsheet_update_external_records": {
1397
+ const result = await docClient.smartTableUpdateExternalRecords({
1398
+ agent: account,
1399
+ ...params,
1400
+ });
1401
+ return buildToolResult({
1402
+ ok: true,
1403
+ action,
1404
+ accountId: account.accountId,
1405
+ docId: params.docId,
1406
+ summary: "智能表格外部记录已更新",
1407
+ raw: result.raw,
1408
+ });
1409
+ }
1410
+ case "smartsheet_get_sheet_priv": {
1411
+ const result = await docClient.smartTableGetSheetPriv({ agent: account, ...params });
1412
+ return buildToolResult({
1413
+ ok: true,
1414
+ action,
1415
+ accountId: account.accountId,
1416
+ docId: params.docId,
1417
+ summary: "智能表格子表权限已获取",
1418
+ raw: result.raw,
1419
+ });
1420
+ }
1421
+ case "smartsheet_update_sheet_priv": {
1422
+ const result = await docClient.smartTableUpdateSheetPriv({
1423
+ agent: account,
1424
+ ...params,
1425
+ });
1426
+ return buildToolResult({
1427
+ ok: true,
1428
+ action,
1429
+ accountId: account.accountId,
1430
+ docId: params.docId,
1431
+ summary: "智能表格子表权限已更新",
1432
+ raw: result.raw,
1433
+ });
1434
+ }
1435
+ case "smartsheet_create_rule": {
1436
+ const result = await docClient.smartTableCreateRule({ agent: account, ...params });
1437
+ return buildToolResult({
1438
+ ok: true,
1439
+ action,
1440
+ accountId: account.accountId,
1441
+ docId: params.docId,
1442
+ summary: `智能表格成员额外权限规则已创建 (rule_id: ${result.rule_id})`,
1443
+ raw: result.raw,
1444
+ });
1445
+ }
1446
+ case "smartsheet_mod_rule_member": {
1447
+ const result = await docClient.smartTableModRuleMember({ agent: account, ...params });
1448
+ return buildToolResult({
1449
+ ok: true,
1450
+ action,
1451
+ accountId: account.accountId,
1452
+ docId: params.docId,
1453
+ summary: "智能表格成员额外权限成员已更新",
1454
+ raw: result.raw,
1455
+ });
1456
+ }
1457
+ case "smartsheet_delete_rule": {
1458
+ const result = await docClient.smartTableDeleteRule({ agent: account, ...params });
1459
+ return buildToolResult({
1460
+ ok: true,
1461
+ action,
1462
+ accountId: account.accountId,
1463
+ docId: params.docId,
1464
+ summary: "智能表格成员额外权限规则已删除",
1465
+ raw: result.raw,
1466
+ });
1467
+ }
1468
+ case "doc_assign_advanced_account": {
1469
+ const result = await docClient.assignDocAdvancedAccount({
1470
+ agent: account,
1471
+ userid_list: params.userid_list,
1472
+ });
1473
+ return buildToolResult({
1474
+ ok: true,
1475
+ action,
1476
+ accountId: account.accountId,
1477
+ summary: summarizeAdvancedAccount(result.raw, "assign"),
1478
+ raw: result.raw,
1479
+ });
1480
+ }
1481
+ case "doc_cancel_advanced_account": {
1482
+ const result = await docClient.cancelDocAdvancedAccount({
1483
+ agent: account,
1484
+ userid_list: params.userid_list,
1485
+ });
1486
+ return buildToolResult({
1487
+ ok: true,
1488
+ action,
1489
+ accountId: account.accountId,
1490
+ summary: summarizeAdvancedAccount(result.raw, "cancel"),
1491
+ raw: result.raw,
1492
+ });
1493
+ }
1494
+ case "doc_get_advanced_account_list": {
1495
+ const result = await docClient.getDocAdvancedAccountList({
1496
+ agent: account,
1497
+ ...params,
1498
+ });
1499
+ return buildToolResult({
1500
+ ok: true,
1501
+ action,
1502
+ accountId: account.accountId,
1503
+ summary: summarizeAdvancedAccount(result, "list"),
1504
+ raw: result.raw,
1505
+ });
1506
+ }
1507
+ case "upload_doc_image": {
1508
+ const filePath = params.file_path;
1509
+ if (!fs.existsSync(filePath)) {
1510
+ throw new Error(`File not found: ${filePath}`);
1511
+ }
1512
+ const fileContent = fs.readFileSync(filePath);
1513
+ const base64Content = fileContent.toString("base64");
1514
+ const result = await docClient.uploadDocImage({
1515
+ agent: account,
1516
+ docId: params.docId,
1517
+ base64_content: base64Content,
1518
+ });
1519
+ return buildToolResult({
1520
+ ok: true,
1521
+ action,
1522
+ accountId: account.accountId,
1523
+ summary: "图片上传成功",
1524
+ details: {
1525
+ url: result.url,
1526
+ width: result.width,
1527
+ height: result.height,
1528
+ size: result.size,
1529
+ },
1530
+ raw: result.raw,
1531
+ });
1532
+ }
1533
+ default:
1534
+ throw new Error(`Unsupported action: ${String(action)}`);
1535
+ }
1536
+ }
1537
+ catch (err) {
1538
+ return {
1539
+ content: [
1540
+ {
1541
+ type: "text",
1542
+ text: JSON.stringify({
1543
+ ok: false,
1544
+ action: params?.action,
1545
+ error: err instanceof Error ? err.message : String(err),
1546
+ }, null, 2),
1547
+ },
1548
+ ],
1549
+ details: {},
1550
+ isError: true,
1551
+ };
1552
+ }
1553
+ },
1554
+ };
1555
+ });
1556
+ }