@lark-project/openclaw-lark-project 2026.3.131

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 (368) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -0
  3. package/README.zh.md +80 -0
  4. package/dist/index.js +172 -0
  5. package/dist/index.js.map +7 -0
  6. package/dist/skills/feishu-bitable/SKILL.md +248 -0
  7. package/dist/skills/feishu-bitable/references/examples.md +813 -0
  8. package/dist/skills/feishu-bitable/references/field-properties.md +763 -0
  9. package/dist/skills/feishu-bitable/references/record-values.md +911 -0
  10. package/dist/skills/feishu-calendar/SKILL.md +244 -0
  11. package/dist/skills/feishu-channel-rules/SKILL.md +18 -0
  12. package/dist/skills/feishu-channel-rules/references/markdown-syntax.md +138 -0
  13. package/dist/skills/feishu-create-doc/SKILL.md +719 -0
  14. package/dist/skills/feishu-fetch-doc/SKILL.md +93 -0
  15. package/dist/skills/feishu-im-read/SKILL.md +163 -0
  16. package/dist/skills/feishu-project/SKILL.md +122 -0
  17. package/dist/skills/feishu-task/SKILL.md +293 -0
  18. package/dist/skills/feishu-troubleshoot/SKILL.md +70 -0
  19. package/dist/skills/feishu-update-doc/SKILL.md +285 -0
  20. package/dist/src/card/builder.js +293 -0
  21. package/dist/src/card/builder.js.map +7 -0
  22. package/dist/src/card/cardkit.js +126 -0
  23. package/dist/src/card/cardkit.js.map +7 -0
  24. package/dist/src/card/flush-controller.js +107 -0
  25. package/dist/src/card/flush-controller.js.map +7 -0
  26. package/dist/src/card/markdown-style.js +57 -0
  27. package/dist/src/card/markdown-style.js.map +7 -0
  28. package/dist/src/card/reply-dispatcher-types.js +39 -0
  29. package/dist/src/card/reply-dispatcher-types.js.map +7 -0
  30. package/dist/src/card/reply-dispatcher.js +245 -0
  31. package/dist/src/card/reply-dispatcher.js.map +7 -0
  32. package/dist/src/card/reply-mode.js +29 -0
  33. package/dist/src/card/reply-mode.js.map +7 -0
  34. package/dist/src/card/streaming-card-controller.js +653 -0
  35. package/dist/src/card/streaming-card-controller.js.map +7 -0
  36. package/dist/src/card/unavailable-guard.js +76 -0
  37. package/dist/src/card/unavailable-guard.js.map +7 -0
  38. package/dist/src/channel/abort-detect.js +79 -0
  39. package/dist/src/channel/abort-detect.js.map +7 -0
  40. package/dist/src/channel/chat-queue.js +50 -0
  41. package/dist/src/channel/chat-queue.js.map +7 -0
  42. package/dist/src/channel/config-adapter.js +89 -0
  43. package/dist/src/channel/config-adapter.js.map +7 -0
  44. package/dist/src/channel/directory.js +133 -0
  45. package/dist/src/channel/directory.js.map +7 -0
  46. package/dist/src/channel/event-handlers.js +175 -0
  47. package/dist/src/channel/event-handlers.js.map +7 -0
  48. package/dist/src/channel/monitor.js +108 -0
  49. package/dist/src/channel/monitor.js.map +7 -0
  50. package/dist/src/channel/onboarding-config.js +76 -0
  51. package/dist/src/channel/onboarding-config.js.map +7 -0
  52. package/dist/src/channel/onboarding-migrate.js +55 -0
  53. package/dist/src/channel/onboarding-migrate.js.map +7 -0
  54. package/dist/src/channel/onboarding.js +285 -0
  55. package/dist/src/channel/onboarding.js.map +7 -0
  56. package/dist/src/channel/plugin.js +260 -0
  57. package/dist/src/channel/plugin.js.map +7 -0
  58. package/dist/src/channel/probe.js +14 -0
  59. package/dist/src/channel/probe.js.map +7 -0
  60. package/dist/src/channel/types.js +1 -0
  61. package/dist/src/channel/types.js.map +7 -0
  62. package/dist/src/commands/auth.js +73 -0
  63. package/dist/src/commands/auth.js.map +7 -0
  64. package/dist/src/commands/diagnose.js +658 -0
  65. package/dist/src/commands/diagnose.js.map +7 -0
  66. package/dist/src/commands/doctor.js +327 -0
  67. package/dist/src/commands/doctor.js.map +7 -0
  68. package/dist/src/commands/index.js +124 -0
  69. package/dist/src/commands/index.js.map +7 -0
  70. package/dist/src/core/accounts.js +129 -0
  71. package/dist/src/core/accounts.js.map +7 -0
  72. package/dist/src/core/agent-config.js +60 -0
  73. package/dist/src/core/agent-config.js.map +7 -0
  74. package/dist/src/core/api-error.js +55 -0
  75. package/dist/src/core/api-error.js.map +7 -0
  76. package/dist/src/core/app-owner-fallback.js +17 -0
  77. package/dist/src/core/app-owner-fallback.js.map +7 -0
  78. package/dist/src/core/app-scope-checker.js +95 -0
  79. package/dist/src/core/app-scope-checker.js.map +7 -0
  80. package/dist/src/core/auth-errors.js +120 -0
  81. package/dist/src/core/auth-errors.js.map +7 -0
  82. package/dist/src/core/chat-info-cache.js +102 -0
  83. package/dist/src/core/chat-info-cache.js.map +7 -0
  84. package/dist/src/core/config-schema.js +150 -0
  85. package/dist/src/core/config-schema.js.map +7 -0
  86. package/dist/src/core/device-flow.js +174 -0
  87. package/dist/src/core/device-flow.js.map +7 -0
  88. package/dist/src/core/feishu-fetch.js +12 -0
  89. package/dist/src/core/feishu-fetch.js.map +7 -0
  90. package/dist/src/core/footer-config.js +16 -0
  91. package/dist/src/core/footer-config.js.map +7 -0
  92. package/dist/src/core/lark-client.js +322 -0
  93. package/dist/src/core/lark-client.js.map +7 -0
  94. package/dist/src/core/lark-logger.js +92 -0
  95. package/dist/src/core/lark-logger.js.map +7 -0
  96. package/dist/src/core/lark-ticket.js +18 -0
  97. package/dist/src/core/lark-ticket.js.map +7 -0
  98. package/dist/src/core/message-unavailable.js +119 -0
  99. package/dist/src/core/message-unavailable.js.map +7 -0
  100. package/dist/src/core/owner-policy.js +25 -0
  101. package/dist/src/core/owner-policy.js.map +7 -0
  102. package/dist/src/core/permission-url.js +37 -0
  103. package/dist/src/core/permission-url.js.map +7 -0
  104. package/dist/src/core/project-auth.js +177 -0
  105. package/dist/src/core/project-auth.js.map +7 -0
  106. package/dist/src/core/project-oauth-flow.js +124 -0
  107. package/dist/src/core/project-oauth-flow.js.map +7 -0
  108. package/dist/src/core/project-token-store.js +172 -0
  109. package/dist/src/core/project-token-store.js.map +7 -0
  110. package/dist/src/core/raw-request.js +45 -0
  111. package/dist/src/core/raw-request.js.map +7 -0
  112. package/dist/src/core/scope-manager.js +62 -0
  113. package/dist/src/core/scope-manager.js.map +7 -0
  114. package/dist/src/core/security-check.js +118 -0
  115. package/dist/src/core/security-check.js.map +7 -0
  116. package/dist/src/core/shutdown-hooks.js +37 -0
  117. package/dist/src/core/shutdown-hooks.js.map +7 -0
  118. package/dist/src/core/targets.js +55 -0
  119. package/dist/src/core/targets.js.map +7 -0
  120. package/dist/src/core/token-store.js +215 -0
  121. package/dist/src/core/token-store.js.map +7 -0
  122. package/dist/src/core/tool-client.js +335 -0
  123. package/dist/src/core/tool-client.js.map +7 -0
  124. package/dist/src/core/tool-scopes.js +207 -0
  125. package/dist/src/core/tool-scopes.js.map +7 -0
  126. package/dist/src/core/tools-config.js +57 -0
  127. package/dist/src/core/tools-config.js.map +7 -0
  128. package/dist/src/core/types.js +1 -0
  129. package/dist/src/core/types.js.map +7 -0
  130. package/dist/src/core/uat-client.js +124 -0
  131. package/dist/src/core/uat-client.js.map +7 -0
  132. package/dist/src/core/version.js +27 -0
  133. package/dist/src/core/version.js.map +7 -0
  134. package/dist/src/messaging/converters/audio.js +19 -0
  135. package/dist/src/messaging/converters/audio.js.map +7 -0
  136. package/dist/src/messaging/converters/calendar.js +46 -0
  137. package/dist/src/messaging/converters/calendar.js.map +7 -0
  138. package/dist/src/messaging/converters/content-converter.js +61 -0
  139. package/dist/src/messaging/converters/content-converter.js.map +7 -0
  140. package/dist/src/messaging/converters/file.js +18 -0
  141. package/dist/src/messaging/converters/file.js.map +7 -0
  142. package/dist/src/messaging/converters/folder.js +18 -0
  143. package/dist/src/messaging/converters/folder.js.map +7 -0
  144. package/dist/src/messaging/converters/hongbao.js +14 -0
  145. package/dist/src/messaging/converters/hongbao.js.map +7 -0
  146. package/dist/src/messaging/converters/image.js +16 -0
  147. package/dist/src/messaging/converters/image.js.map +7 -0
  148. package/dist/src/messaging/converters/index.js +48 -0
  149. package/dist/src/messaging/converters/index.js.map +7 -0
  150. package/dist/src/messaging/converters/interactive/card-converter.js +1040 -0
  151. package/dist/src/messaging/converters/interactive/card-converter.js.map +7 -0
  152. package/dist/src/messaging/converters/interactive/card-utils.js +36 -0
  153. package/dist/src/messaging/converters/interactive/card-utils.js.map +7 -0
  154. package/dist/src/messaging/converters/interactive/index.js +19 -0
  155. package/dist/src/messaging/converters/interactive/index.js.map +7 -0
  156. package/dist/src/messaging/converters/interactive/legacy.js +53 -0
  157. package/dist/src/messaging/converters/interactive/legacy.js.map +7 -0
  158. package/dist/src/messaging/converters/interactive/types.js +23 -0
  159. package/dist/src/messaging/converters/interactive/types.js.map +7 -0
  160. package/dist/src/messaging/converters/location.js +17 -0
  161. package/dist/src/messaging/converters/location.js.map +7 -0
  162. package/dist/src/messaging/converters/merge-forward.js +143 -0
  163. package/dist/src/messaging/converters/merge-forward.js.map +7 -0
  164. package/dist/src/messaging/converters/post.js +113 -0
  165. package/dist/src/messaging/converters/post.js.map +7 -0
  166. package/dist/src/messaging/converters/share.js +22 -0
  167. package/dist/src/messaging/converters/share.js.map +7 -0
  168. package/dist/src/messaging/converters/sticker.js +16 -0
  169. package/dist/src/messaging/converters/sticker.js.map +7 -0
  170. package/dist/src/messaging/converters/system.js +25 -0
  171. package/dist/src/messaging/converters/system.js.map +7 -0
  172. package/dist/src/messaging/converters/text.js +12 -0
  173. package/dist/src/messaging/converters/text.js.map +7 -0
  174. package/dist/src/messaging/converters/todo.js +37 -0
  175. package/dist/src/messaging/converters/todo.js.map +7 -0
  176. package/dist/src/messaging/converters/types.js +1 -0
  177. package/dist/src/messaging/converters/types.js.map +7 -0
  178. package/dist/src/messaging/converters/unknown.js +13 -0
  179. package/dist/src/messaging/converters/unknown.js.map +7 -0
  180. package/dist/src/messaging/converters/utils.js +35 -0
  181. package/dist/src/messaging/converters/utils.js.map +7 -0
  182. package/dist/src/messaging/converters/video-chat.js +21 -0
  183. package/dist/src/messaging/converters/video-chat.js.map +7 -0
  184. package/dist/src/messaging/converters/video.js +30 -0
  185. package/dist/src/messaging/converters/video.js.map +7 -0
  186. package/dist/src/messaging/converters/vote.js +24 -0
  187. package/dist/src/messaging/converters/vote.js.map +7 -0
  188. package/dist/src/messaging/inbound/dedup.js +82 -0
  189. package/dist/src/messaging/inbound/dedup.js.map +7 -0
  190. package/dist/src/messaging/inbound/dispatch-builders.js +98 -0
  191. package/dist/src/messaging/inbound/dispatch-builders.js.map +7 -0
  192. package/dist/src/messaging/inbound/dispatch-commands.js +94 -0
  193. package/dist/src/messaging/inbound/dispatch-commands.js.map +7 -0
  194. package/dist/src/messaging/inbound/dispatch-context.js +96 -0
  195. package/dist/src/messaging/inbound/dispatch-context.js.map +7 -0
  196. package/dist/src/messaging/inbound/dispatch.js +150 -0
  197. package/dist/src/messaging/inbound/dispatch.js.map +7 -0
  198. package/dist/src/messaging/inbound/enrich.js +137 -0
  199. package/dist/src/messaging/inbound/enrich.js.map +7 -0
  200. package/dist/src/messaging/inbound/gate-effects.js +28 -0
  201. package/dist/src/messaging/inbound/gate-effects.js.map +7 -0
  202. package/dist/src/messaging/inbound/gate.js +163 -0
  203. package/dist/src/messaging/inbound/gate.js.map +7 -0
  204. package/dist/src/messaging/inbound/handler.js +132 -0
  205. package/dist/src/messaging/inbound/handler.js.map +7 -0
  206. package/dist/src/messaging/inbound/media-resolver.js +70 -0
  207. package/dist/src/messaging/inbound/media-resolver.js.map +7 -0
  208. package/dist/src/messaging/inbound/mention.js +50 -0
  209. package/dist/src/messaging/inbound/mention.js.map +7 -0
  210. package/dist/src/messaging/inbound/parse-io.js +41 -0
  211. package/dist/src/messaging/inbound/parse-io.js.map +7 -0
  212. package/dist/src/messaging/inbound/parse.js +79 -0
  213. package/dist/src/messaging/inbound/parse.js.map +7 -0
  214. package/dist/src/messaging/inbound/permission.js +30 -0
  215. package/dist/src/messaging/inbound/permission.js.map +7 -0
  216. package/dist/src/messaging/inbound/policy.js +83 -0
  217. package/dist/src/messaging/inbound/policy.js.map +7 -0
  218. package/dist/src/messaging/inbound/reaction-handler.js +162 -0
  219. package/dist/src/messaging/inbound/reaction-handler.js.map +7 -0
  220. package/dist/src/messaging/inbound/user-name-cache.js +172 -0
  221. package/dist/src/messaging/inbound/user-name-cache.js.map +7 -0
  222. package/dist/src/messaging/outbound/actions.js +239 -0
  223. package/dist/src/messaging/outbound/actions.js.map +7 -0
  224. package/dist/src/messaging/outbound/chat-manage.js +74 -0
  225. package/dist/src/messaging/outbound/chat-manage.js.map +7 -0
  226. package/dist/src/messaging/outbound/deliver.js +162 -0
  227. package/dist/src/messaging/outbound/deliver.js.map +7 -0
  228. package/dist/src/messaging/outbound/fetch.js +7 -0
  229. package/dist/src/messaging/outbound/fetch.js.map +7 -0
  230. package/dist/src/messaging/outbound/forward.js +31 -0
  231. package/dist/src/messaging/outbound/forward.js.map +7 -0
  232. package/dist/src/messaging/outbound/media-url-utils.js +101 -0
  233. package/dist/src/messaging/outbound/media-url-utils.js.map +7 -0
  234. package/dist/src/messaging/outbound/media.js +463 -0
  235. package/dist/src/messaging/outbound/media.js.map +7 -0
  236. package/dist/src/messaging/outbound/outbound.js +95 -0
  237. package/dist/src/messaging/outbound/outbound.js.map +7 -0
  238. package/dist/src/messaging/outbound/reactions.js +312 -0
  239. package/dist/src/messaging/outbound/reactions.js.map +7 -0
  240. package/dist/src/messaging/outbound/send.js +194 -0
  241. package/dist/src/messaging/outbound/send.js.map +7 -0
  242. package/dist/src/messaging/outbound/typing.js +77 -0
  243. package/dist/src/messaging/outbound/typing.js.map +7 -0
  244. package/dist/src/messaging/shared/message-lookup.js +84 -0
  245. package/dist/src/messaging/shared/message-lookup.js.map +7 -0
  246. package/dist/src/messaging/types.js +1 -0
  247. package/dist/src/messaging/types.js.map +7 -0
  248. package/dist/src/tools/auto-auth.js +714 -0
  249. package/dist/src/tools/auto-auth.js.map +7 -0
  250. package/dist/src/tools/helpers.js +133 -0
  251. package/dist/src/tools/helpers.js.map +7 -0
  252. package/dist/src/tools/mcp/doc/create.js +35 -0
  253. package/dist/src/tools/mcp/doc/create.js.map +7 -0
  254. package/dist/src/tools/mcp/doc/fetch.js +33 -0
  255. package/dist/src/tools/mcp/doc/fetch.js.map +7 -0
  256. package/dist/src/tools/mcp/doc/index.js +32 -0
  257. package/dist/src/tools/mcp/doc/index.js.map +7 -0
  258. package/dist/src/tools/mcp/doc/update.js +61 -0
  259. package/dist/src/tools/mcp/doc/update.js.map +7 -0
  260. package/dist/src/tools/mcp/project/endpoint.js +25 -0
  261. package/dist/src/tools/mcp/project/endpoint.js.map +7 -0
  262. package/dist/src/tools/mcp/project/index.js +27 -0
  263. package/dist/src/tools/mcp/project/index.js.map +7 -0
  264. package/dist/src/tools/mcp/project/tools.js +579 -0
  265. package/dist/src/tools/mcp/project/tools.js.map +7 -0
  266. package/dist/src/tools/mcp/shared.js +170 -0
  267. package/dist/src/tools/mcp/shared.js.map +7 -0
  268. package/dist/src/tools/oapi/bitable/app-table-field.js +244 -0
  269. package/dist/src/tools/oapi/bitable/app-table-field.js.map +7 -0
  270. package/dist/src/tools/oapi/bitable/app-table-record.js +501 -0
  271. package/dist/src/tools/oapi/bitable/app-table-record.js.map +7 -0
  272. package/dist/src/tools/oapi/bitable/app-table-view.js +226 -0
  273. package/dist/src/tools/oapi/bitable/app-table-view.js.map +7 -0
  274. package/dist/src/tools/oapi/bitable/app-table.js +278 -0
  275. package/dist/src/tools/oapi/bitable/app-table.js.map +7 -0
  276. package/dist/src/tools/oapi/bitable/app.js +200 -0
  277. package/dist/src/tools/oapi/bitable/app.js.map +7 -0
  278. package/dist/src/tools/oapi/bitable/index.js +13 -0
  279. package/dist/src/tools/oapi/bitable/index.js.map +7 -0
  280. package/dist/src/tools/oapi/calendar/calendar.js +131 -0
  281. package/dist/src/tools/oapi/calendar/calendar.js.map +7 -0
  282. package/dist/src/tools/oapi/calendar/event-attendee.js +301 -0
  283. package/dist/src/tools/oapi/calendar/event-attendee.js.map +7 -0
  284. package/dist/src/tools/oapi/calendar/event.js +834 -0
  285. package/dist/src/tools/oapi/calendar/event.js.map +7 -0
  286. package/dist/src/tools/oapi/calendar/freebusy.js +111 -0
  287. package/dist/src/tools/oapi/calendar/freebusy.js.map +7 -0
  288. package/dist/src/tools/oapi/calendar/index.js +11 -0
  289. package/dist/src/tools/oapi/calendar/index.js.map +7 -0
  290. package/dist/src/tools/oapi/chat/chat.js +132 -0
  291. package/dist/src/tools/oapi/chat/chat.js.map +7 -0
  292. package/dist/src/tools/oapi/chat/index.js +11 -0
  293. package/dist/src/tools/oapi/chat/index.js.map +7 -0
  294. package/dist/src/tools/oapi/chat/members.js +83 -0
  295. package/dist/src/tools/oapi/chat/members.js.map +7 -0
  296. package/dist/src/tools/oapi/common/get-user.js +95 -0
  297. package/dist/src/tools/oapi/common/get-user.js.map +7 -0
  298. package/dist/src/tools/oapi/common/index.js +7 -0
  299. package/dist/src/tools/oapi/common/index.js.map +7 -0
  300. package/dist/src/tools/oapi/common/search-user.js +67 -0
  301. package/dist/src/tools/oapi/common/search-user.js.map +7 -0
  302. package/dist/src/tools/oapi/drive/doc-comments.js +310 -0
  303. package/dist/src/tools/oapi/drive/doc-comments.js.map +7 -0
  304. package/dist/src/tools/oapi/drive/doc-media.js +314 -0
  305. package/dist/src/tools/oapi/drive/doc-media.js.map +7 -0
  306. package/dist/src/tools/oapi/drive/file.js +548 -0
  307. package/dist/src/tools/oapi/drive/file.js.map +7 -0
  308. package/dist/src/tools/oapi/drive/index.js +29 -0
  309. package/dist/src/tools/oapi/drive/index.js.map +7 -0
  310. package/dist/src/tools/oapi/helpers.js +199 -0
  311. package/dist/src/tools/oapi/helpers.js.map +7 -0
  312. package/dist/src/tools/oapi/im/format-messages.js +128 -0
  313. package/dist/src/tools/oapi/im/format-messages.js.map +7 -0
  314. package/dist/src/tools/oapi/im/index.js +15 -0
  315. package/dist/src/tools/oapi/im/index.js.map +7 -0
  316. package/dist/src/tools/oapi/im/message-read.js +404 -0
  317. package/dist/src/tools/oapi/im/message-read.js.map +7 -0
  318. package/dist/src/tools/oapi/im/message.js +179 -0
  319. package/dist/src/tools/oapi/im/message.js.map +7 -0
  320. package/dist/src/tools/oapi/im/resource.js +126 -0
  321. package/dist/src/tools/oapi/im/resource.js.map +7 -0
  322. package/dist/src/tools/oapi/im/time-utils.js +169 -0
  323. package/dist/src/tools/oapi/im/time-utils.js.map +7 -0
  324. package/dist/src/tools/oapi/im/user-name-uat.js +103 -0
  325. package/dist/src/tools/oapi/im/user-name-uat.js.map +7 -0
  326. package/dist/src/tools/oapi/index.js +56 -0
  327. package/dist/src/tools/oapi/index.js.map +7 -0
  328. package/dist/src/tools/oapi/sdk-types.js +1 -0
  329. package/dist/src/tools/oapi/sdk-types.js.map +7 -0
  330. package/dist/src/tools/oapi/search/doc-search.js +215 -0
  331. package/dist/src/tools/oapi/search/doc-search.js.map +7 -0
  332. package/dist/src/tools/oapi/search/index.js +25 -0
  333. package/dist/src/tools/oapi/search/index.js.map +7 -0
  334. package/dist/src/tools/oapi/sheets/index.js +25 -0
  335. package/dist/src/tools/oapi/sheets/index.js.map +7 -0
  336. package/dist/src/tools/oapi/sheets/sheet.js +652 -0
  337. package/dist/src/tools/oapi/sheets/sheet.js.map +7 -0
  338. package/dist/src/tools/oapi/task/comment.js +151 -0
  339. package/dist/src/tools/oapi/task/comment.js.map +7 -0
  340. package/dist/src/tools/oapi/task/index.js +11 -0
  341. package/dist/src/tools/oapi/task/index.js.map +7 -0
  342. package/dist/src/tools/oapi/task/subtask.js +175 -0
  343. package/dist/src/tools/oapi/task/subtask.js.map +7 -0
  344. package/dist/src/tools/oapi/task/task.js +405 -0
  345. package/dist/src/tools/oapi/task/task.js.map +7 -0
  346. package/dist/src/tools/oapi/task/tasklist.js +366 -0
  347. package/dist/src/tools/oapi/task/tasklist.js.map +7 -0
  348. package/dist/src/tools/oapi/wiki/index.js +27 -0
  349. package/dist/src/tools/oapi/wiki/index.js.map +7 -0
  350. package/dist/src/tools/oapi/wiki/space-node.js +311 -0
  351. package/dist/src/tools/oapi/wiki/space-node.js.map +7 -0
  352. package/dist/src/tools/oapi/wiki/space.js +148 -0
  353. package/dist/src/tools/oapi/wiki/space.js.map +7 -0
  354. package/dist/src/tools/oauth-batch-auth.js +125 -0
  355. package/dist/src/tools/oauth-batch-auth.js.map +7 -0
  356. package/dist/src/tools/oauth-cards.js +269 -0
  357. package/dist/src/tools/oauth-cards.js.map +7 -0
  358. package/dist/src/tools/oauth.js +538 -0
  359. package/dist/src/tools/oauth.js.map +7 -0
  360. package/dist/src/tools/onboarding-auth.js +101 -0
  361. package/dist/src/tools/onboarding-auth.js.map +7 -0
  362. package/dist/src/tools/project-oauth.js +305 -0
  363. package/dist/src/tools/project-oauth.js.map +7 -0
  364. package/dist/src/tools/tat/im/index.js +9 -0
  365. package/dist/src/tools/tat/im/index.js.map +7 -0
  366. package/dist/src/tools/tat/im/resource.js +123 -0
  367. package/dist/src/tools/tat/im/resource.js.map +7 -0
  368. package/package.json +64 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/tools/auto-auth.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * auto-auth.ts \u2014 \u5DE5\u5177\u5C42\u81EA\u52A8\u6388\u6743\u5904\u7406\u3002\n *\n * \u5F53 OAPI \u5DE5\u5177\u9047\u5230\u6388\u6743\u95EE\u9898\u65F6\uFF0C\u76F4\u63A5\u5728\u5DE5\u5177\u5C42\u5904\u7406\uFF0C\u4E0D\u518D\u8BA9 AI \u5224\u65AD\uFF1A\n *\n * - UserAuthRequiredError (appScopeVerified=true)\n * \u2192 \u76F4\u63A5\u8C03\u7528 executeAuthorize \u53D1\u8D77 OAuth Device Flow \u5361\u7247\n *\n * - UserScopeInsufficientError\n * \u2192 \u76F4\u63A5\u8C03\u7528 executeAuthorize\uFF08\u4F7F\u7528 missingScopes\uFF09\n *\n * - AppScopeMissingError\n * \u2192 \u53D1\u9001\u5E94\u7528\u6743\u9650\u5F15\u5BFC\u5361\u7247\uFF1B\u7528\u6237\u70B9\u51FB\"\u6211\u5DF2\u5B8C\u6210\"\u540E\uFF1A\n * 1. \u66F4\u65B0\u5361\u7247\u4E3A\u5904\u7406\u4E2D\u72B6\u6001\n * 2. invalidateAppScopeCache\n * 3. \u53D1\u9001\u4E2D\u95F4\u5408\u6210\u6D88\u606F\u544A\u77E5 AI\uFF08\"\u5E94\u7528\u6743\u9650\u5DF2\u786E\u8BA4\uFF0C\u6B63\u5728\u53D1\u8D77\u7528\u6237\u6388\u6743...\"\uFF09\n * 4. \u8C03\u7528 executeAuthorize \u53D1\u8D77 OAuth Device Flow\n *\n * - \u5176\u4ED6\u60C5\u51B5\uFF08AppScopeCheckFailedError\u3001appScopeVerified=false \u7B49\uFF09\n * \u2192 \u56DE\u9000\u5230\u539F handleInvokeError\uFF08\u4E0D\u89E6\u53D1\u81EA\u52A8\u6388\u6743\uFF09\n *\n * \u964D\u7EA7\u7B56\u7565\uFF08\u4FDD\u5B88\uFF09\uFF1A\u4EE5\u4E0B\u60C5\u51B5\u5747\u56DE\u9000\u5230 handleInvokeError\uFF1A\n * - \u65E0 LarkTicket\uFF08\u975E\u6D88\u606F\u573A\u666F\uFF09\n * - \u65E0 senderOpenId\uFF08\u65E0\u6CD5\u786E\u5B9A\u6388\u6743\u5BF9\u8C61\uFF09\n * - \u8D26\u53F7\u672A\u914D\u7F6E\uFF08!acct.configured\uFF09\n * - \u4EFB\u4F55\u6B65\u9AA4\u629B\u51FA\u5F02\u5E38\n */\n\nimport type { ClawdbotConfig } from 'openclaw/plugin-sdk';\nimport type { ConfiguredLarkAccount } from '../core/types';\nimport type { LarkTicket } from '../core/lark-ticket';\nimport { getTicket } from '../core/lark-ticket';\nimport { larkLogger } from '../core/lark-logger';\n\nconst log = larkLogger('tools/auto-auth');\nimport { getLarkAccount } from '../core/accounts';\nimport { UserAuthRequiredError, UserScopeInsufficientError, AppScopeMissingError } from '../core/tool-client';\nimport { invalidateAppScopeCache, getAppGrantedScopes, isAppScopeSatisfied } from '../core/app-scope-checker';\nimport { LarkClient } from '../core/lark-client';\nimport { createCardEntity, sendCardByCardId, updateCardKitCardForAuth } from '../card/cardkit';\nimport { executeAuthorize } from './oauth';\nimport { formatLarkError, json } from './oapi/helpers';\nimport { OwnerAccessDeniedError } from '../core/owner-policy';\nimport { enqueueFeishuChatTask } from '../channel/chat-queue';\nimport { handleFeishuMessage } from '../messaging/inbound/handler';\nimport { withTicket } from '../core/lark-ticket';\n\n// ---------------------------------------------------------------------------\n// Debounce + scope merge \u2014 \u9632\u6296\u7F13\u51B2\u533A\uFF08\u4E24\u9636\u6BB5\uFF09\n//\n// \u5DE5\u5177\u8C03\u7528\u53EF\u80FD\u662F\u771F\u6B63\u5E76\u53D1\uFF0850ms \u5185\u5230\u8FBE\uFF09\u6216\u88AB\u6846\u67B6\u5E8F\u5217\u5316\uFF08\u95F4\u9694\u6570\u79D2\u5230\u8FBE\uFF09\u3002\n// \u4E3A\u540C\u65F6\u8986\u76D6\u4E24\u79CD\u573A\u666F\uFF0C\u91C7\u7528\u4E24\u9636\u6BB5\u8BBE\u8BA1\uFF1A\n//\n// collecting\uFF08\u6536\u96C6\u9636\u6BB5\uFF09\uFF1A50ms \u9632\u6296\u7A97\u53E3\uFF0C\u5408\u5E76 scope\n// executing\uFF08\u6267\u884C\u9636\u6BB5\uFF09\uFF1AflushFn \u6B63\u5728\u8FD0\u884C\uFF0C\u540E\u7EED\u8BF7\u6C42\u590D\u7528\u540C\u4E00\u7ED3\u679C\n//\n// \u4ECE collecting \u2192 executing \u8F6C\u6362\u65F6\u4E0D\u4ECE Map \u4E2D\u5220\u9664 entry\uFF0C\n// \u76F4\u5230 flushFn \u5B8C\u6210\uFF08resolve / reject\uFF09\u624D\u79FB\u9664\u3002\n// ---------------------------------------------------------------------------\n\ntype JsonResult = ReturnType<typeof json>;\n\n/** \u7F13\u51B2\u4E2D\u7684\u6388\u6743\u8BF7\u6C42 */\ninterface AuthBatchEntry {\n phase: 'collecting' | 'executing';\n scopes: Set<string>;\n waiters: Array<{ resolve: (v: JsonResult) => void; reject: (e: unknown) => void }>;\n timer: ReturnType<typeof setTimeout> | null;\n /** flushFn \u6267\u884C\u4E2D\u7684 Promise\uFF08executing \u9636\u6BB5\u6709\u503C\uFF09 */\n resultPromise: Promise<JsonResult> | null;\n /** executing \u9636\u6BB5\uFF1A\u65B0 scope \u5230\u8FBE\u65F6\u7684\u5EF6\u8FDF\u5237\u65B0\u5B9A\u65F6\u5668 */\n updateTimer: ReturnType<typeof setTimeout> | null;\n /** scope \u66F4\u65B0\u7684 executeAuthorize \u662F\u5426\u6B63\u5728\u6267\u884C\uFF08\u4E92\u65A5\u9501\uFF09 */\n isUpdating: boolean;\n /** isUpdating \u671F\u95F4\u53C8\u6709\u65B0 scope \u5230\u8FBE\uFF0C\u9700\u8981\u518D\u66F4\u65B0\u4E00\u8F6E */\n pendingReupdate: boolean;\n /** flushFn \u5F15\u7528\uFF0Cexecuting \u9636\u6BB5\u7528\u4E8E scope \u66F4\u65B0\u65F6\u91CD\u65B0\u8C03\u7528 */\n flushFn: ((mergedScopes: string[]) => Promise<JsonResult>) | null;\n /** \u4EE5\u4E0B\u5B57\u6BB5\u6765\u81EA\u7B2C\u4E00\u4E2A\u5165\u961F\u7684\u8BF7\u6C42\uFF0C\u540E\u7EED\u8BF7\u6C42\u590D\u7528 */\n account: ConfiguredLarkAccount;\n cfg: ClawdbotConfig;\n ticket: LarkTicket;\n}\n\n/**\n * \u9632\u6296\u7F13\u51B2\u533A Map\u3002\n *\n * Key \u89C4\u5219\uFF1A\n * \u7528\u6237\u6388\u6743\uFF1A`user:${accountId}:${senderOpenId}:${messageId}`\n * \u5E94\u7528\u6388\u6743\uFF1A`app:${accountId}:${chatId}:${messageId}`\n */\nconst authBatches = new Map<string, AuthBatchEntry>();\n\n/** \u9632\u6296\u7A97\u53E3\uFF08\u6BEB\u79D2\uFF09 */\nconst AUTH_DEBOUNCE_MS = 50;\n\n/** \u7528\u6237\u6388\u6743\u9632\u6296\u7A97\u53E3\uFF08\u6BEB\u79D2\uFF09\u3002\u6BD4 app auth \u7684 50ms \u66F4\u957F\uFF0C\u4FDD\u8BC1\u5E94\u7528\u6743\u9650\u5361\u7247\u5148\u53D1\u51FA\u3002 */\nconst AUTH_USER_DEBOUNCE_MS = 150;\n\n/**\n * Scope \u66F4\u65B0\u9632\u6296\u7A97\u53E3\uFF08\u6BEB\u79D2\uFF09\u3002\n * \u6BD4\u521D\u59CB\u9632\u6296\u66F4\u957F\uFF0C\u56E0\u4E3A\u5DE5\u5177\u8C03\u7528\u53EF\u80FD\u95F4\u9694\u6570\u5341\u5230\u6570\u767E\u6BEB\u79D2\u987A\u5E8F\u5230\u8FBE\u3002\n * \u9700\u8981\u7B49\u8DB3\u591F\u4E45\u4EE5\u6536\u96C6\u6240\u6709\u540E\u7EED\u5230\u8FBE\u7684 scope \u540E\u518D\u4E00\u6B21\u6027\u66F4\u65B0\u5361\u7247\u3002\n */\nconst AUTH_UPDATE_DEBOUNCE_MS = 500;\n\n/**\n * \u51B7\u5374\u671F\uFF08\u6BEB\u79D2\uFF09\u3002\n * flushFn \u6267\u884C\u5B8C\u6BD5\u540E\uFF0Centry \u7EE7\u7EED\u4FDD\u7559\u5728 Map \u4E2D\u8FD9\u4E48\u957F\u65F6\u95F4\uFF0C\n * \u9632\u6B62\u540E\u7EED\u987A\u5E8F\u5230\u8FBE\u7684\u5DE5\u5177\u8C03\u7528\u521B\u5EFA\u91CD\u590D\u5361\u7247\u3002\n */\nconst AUTH_COOLDOWN_MS = 30_000;\n\n/**\n * \u5C06\u6388\u6743\u8BF7\u6C42\u5165\u961F\u5230\u9632\u6296\u7F13\u51B2\u533A\u3002\n *\n * \u540C\u4E00 bufferKey \u7684\u8BF7\u6C42\u4F1A\u88AB\u5408\u5E76\uFF1A\n * - collecting \u9636\u6BB5\uFF1Ascope \u96C6\u5408\u53D6\u5E76\u96C6\uFF0C\u5171\u4EAB\u540C\u4E00\u4E2A flushFn \u6267\u884C\u7ED3\u679C\n * - executing \u9636\u6BB5\uFF1AflushFn \u5DF2\u5728\u8FD0\u884C\uFF0C\u540E\u7EED\u8BF7\u6C42\u76F4\u63A5\u590D\u7528\u5DF2\u6709\u7ED3\u679C\uFF08\u4E0D\u91CD\u590D\u53D1\u5361\u7247\uFF09\n *\n * @param bufferKey - \u7F13\u51B2\u533A key\uFF08\u533A\u5206\u4E0D\u540C\u7528\u6237/\u4F1A\u8BDD\uFF09\n * @param scopes - \u672C\u6B21\u8BF7\u6C42\u9700\u8981\u7684 scope \u5217\u8868\n * @param ctx - \u4E0A\u4E0B\u6587\u4FE1\u606F\uFF08\u4EC5\u7B2C\u4E00\u4E2A\u8BF7\u6C42\u7684\u88AB\u91C7\u7528\uFF09\n * @param flushFn - \u5B9A\u65F6\u5668\u5230\u671F\u540E\u6267\u884C\u7684\u5B9E\u9645\u6388\u6743\u51FD\u6570\uFF0C\u63A5\u6536\u5408\u5E76\u540E\u7684 scope \u6570\u7EC4\n */\nfunction enqueueAuthRequest(\n bufferKey: string,\n scopes: string[],\n ctx: { account: ConfiguredLarkAccount; cfg: ClawdbotConfig; ticket: LarkTicket },\n flushFn: (mergedScopes: string[]) => Promise<JsonResult>,\n debounceMs: number = AUTH_DEBOUNCE_MS,\n): Promise<JsonResult> {\n const existing = authBatches.get(bufferKey);\n\n if (existing) {\n // \u4E0D\u8BBA\u54EA\u4E2A\u9636\u6BB5\uFF0C\u90FD\u8FFD\u52A0 scope\n for (const s of scopes) existing.scopes.add(s);\n\n if (existing.phase === 'executing') {\n // flushFn \u5DF2\u5728\u6267\u884C\u6216\u5DF2\u5B8C\u6210\uFF08\u5361\u7247\u5DF2\u53D1\u51FA\uFF09\uFF0C\u590D\u7528\u7ED3\u679C\n // \u540C\u65F6\u89E6\u53D1\u5EF6\u8FDF\u5237\u65B0\uFF1A\u7528\u5408\u5E76\u540E\u7684 scope \u91CD\u65B0\u8C03\u7528 flushFn \u66F4\u65B0\u5361\u7247\n log.info(`auth in-flight, piggyback \u2192 key=${bufferKey}, scopes=[${[...existing.scopes].join(', ')}]`);\n\n // \u9632\u6296 + \u4E92\u65A5\uFF1A\u591A\u4E2A\u5FEB\u901F\u5230\u8FBE\u7684\u8BF7\u6C42\u53EA\u89E6\u53D1\u4E00\u6B21\u5361\u7247\u66F4\u65B0\n if (existing.updateTimer) clearTimeout(existing.updateTimer);\n existing.updateTimer = setTimeout(async () => {\n existing.updateTimer = null;\n\n // \u4E92\u65A5\uFF1A\u5982\u679C\u4E0A\u4E00\u8F6E\u66F4\u65B0\u8FD8\u5728\u6267\u884C\uFF0C\u6807\u8BB0 pendingReupdate \u7B49\u5B83\u7ED3\u675F\u540E\u91CD\u8DD1\n if (existing.isUpdating) {\n existing.pendingReupdate = true;\n log.info(`scope update deferred (previous update still running) \u2192 key=${bufferKey}`);\n return;\n }\n\n existing.isUpdating = true;\n try {\n const mergedScopes = [...existing.scopes];\n log.info(`scope update flush \u2192 key=${bufferKey}, scopes=[${mergedScopes.join(', ')}]`);\n // \u91CD\u65B0\u8C03\u7528 flushFn\uFF08executeAuthorize \u4F1A\u68C0\u6D4B\u5230 pendingFlow\uFF0C\n // \u539F\u5730\u66F4\u65B0\u65E7\u5361\u7247\u5185\u5BB9 + \u91CD\u542F Device Flow\uFF09\n await existing.flushFn!(mergedScopes);\n } catch (err) {\n log.warn(`scope update failed: ${err}`);\n } finally {\n existing.isUpdating = false;\n // \u5982\u679C\u9501\u5B9A\u671F\u95F4\u6709\u65B0 scope \u5230\u8FBE\uFF0C\u518D\u8DD1\u4E00\u8F6E\n if (existing.pendingReupdate) {\n existing.pendingReupdate = false;\n const finalScopes = [...existing.scopes];\n log.info(`scope reupdate \u2192 key=${bufferKey}, scopes=[${finalScopes.join(', ')}]`);\n try {\n await existing.flushFn!(finalScopes);\n } catch (err) {\n log.warn(`scope reupdate failed: ${err}`);\n }\n }\n }\n }, AUTH_UPDATE_DEBOUNCE_MS);\n\n return existing.resultPromise!;\n }\n\n // collecting \u9636\u6BB5\uFF1A\u6B63\u5E38\u5408\u5E76\n log.info(`debounce merge \u2192 key=${bufferKey}, scopes=[${[...existing.scopes].join(', ')}]`);\n return new Promise<JsonResult>((resolve, reject) => {\n existing.waiters.push({ resolve, reject });\n });\n }\n\n // \u521B\u5EFA\u65B0\u7F13\u51B2\u533A\uFF08collecting \u9636\u6BB5\uFF09\n const entry: AuthBatchEntry = {\n phase: 'collecting',\n scopes: new Set(scopes),\n waiters: [],\n timer: null,\n resultPromise: null,\n updateTimer: null,\n isUpdating: false,\n pendingReupdate: false,\n flushFn: null,\n account: ctx.account,\n cfg: ctx.cfg,\n ticket: ctx.ticket,\n };\n\n const promise = new Promise<JsonResult>((resolve, reject) => {\n entry.waiters.push({ resolve, reject });\n });\n\n entry.timer = setTimeout(async () => {\n // \u8F6C\u5165 executing \u9636\u6BB5\uFF08\u4E0D\u4ECE Map \u4E2D\u5220\u9664\uFF0C\u963B\u6B62\u540E\u7EED\u8BF7\u6C42\u521B\u5EFA\u65B0\u5361\u7247\uFF09\n entry.phase = 'executing';\n entry.timer = null;\n entry.flushFn = flushFn; // \u4FDD\u5B58\u5F15\u7528\uFF0C\u4F9B executing \u9636\u6BB5 scope \u66F4\u65B0\u65F6\u91CD\u65B0\u8C03\u7528\n const mergedScopes = [...entry.scopes];\n\n log.info(\n `debounce flush \u2192 key=${bufferKey}, ` + `waiters=${entry.waiters.length}, scopes=[${mergedScopes.join(', ')}]`,\n );\n\n // \u5C06 flushFn \u7684 Promise \u5B58\u5165 entry\uFF0C\u4F9B executing \u9636\u6BB5\u7684\u540E\u6765\u8005\u590D\u7528\n entry.resultPromise = flushFn(mergedScopes);\n\n try {\n const result = await entry.resultPromise;\n for (const w of entry.waiters) w.resolve(result);\n } catch (err) {\n for (const w of entry.waiters) w.reject(err);\n } finally {\n // \u8FDB\u5165\u51B7\u5374\u671F\uFF1Aentry \u7EE7\u7EED\u7559\u5728 Map \u4E2D\uFF0C\u540E\u7EED\u5230\u8FBE\u7684\u5DE5\u5177\u8C03\u7528\n // \u4F1A\u547D\u4E2D executing \u5206\u652F\u5E76\u590D\u7528 resultPromise\uFF0C\u4E0D\u4F1A\u521B\u5EFA\u65B0\u5361\u7247\u3002\n // \u51B7\u5374\u671F\u7ED3\u675F\u540E\u6E05\u7406\u3002\n setTimeout(() => authBatches.delete(bufferKey), AUTH_COOLDOWN_MS);\n }\n }, debounceMs);\n\n authBatches.set(bufferKey, entry);\n return promise;\n}\n\n// ---------------------------------------------------------------------------\n// PendingAppAuthFlow \u2014 \u7B49\u5F85\u7528\u6237\u786E\u8BA4\u7684\u5E94\u7528\u6743\u9650\u5F15\u5BFC\u6D41\u7A0B\n// ---------------------------------------------------------------------------\n\ninterface PendingAppAuthFlow {\n appId: string;\n accountId: string;\n cardId: string;\n sequence: number;\n requiredScopes: string[];\n /** \u4E0E\u89E6\u53D1 AppScopeMissingError \u65F6\u7684 scopeNeedType \u4E00\u81F4\u3002 */\n scopeNeedType?: 'one' | 'all';\n /** \u4E0E\u89E6\u53D1 AppScopeMissingError \u65F6\u7684 tokenType \u4E00\u81F4\u3002 */\n tokenType?: 'user' | 'tenant';\n cfg: ClawdbotConfig;\n ticket: LarkTicket;\n}\n\n/** TTL\uFF1A15 \u5206\u949F\u540E\u81EA\u52A8\u6E05\u7406\uFF0C\u9632\u6B62\u5185\u5B58\u6CC4\u6F0F\u3002 */\nconst PENDING_FLOW_TTL_MS = 15 * 60 * 1000;\n\n/** \u8BA1\u7B97\u53BB\u91CD key\uFF08chatId + messageId + \u6709\u5E8F scopes\uFF09\u3002 */\nfunction makeDedupKey(chatId: string, messageId: string, scopes: string[]): string {\n return chatId + '\\0' + messageId + '\\0' + [...scopes].sort().join(',');\n}\n\n/** \u6CE8\u518C\u540E\u7684 flow\uFF0C\u9644\u52A0\u7D22\u5F15\u952E\u4FE1\u606F */\ntype RegisteredFlow = PendingAppAuthFlow & {\n dedupKey: string;\n activeCardKey: string;\n};\n\n/**\n * \u5E94\u7528\u6743\u9650\u6388\u6743\u6D41\u7BA1\u7406\u5668 \u2014 \u7EDF\u4E00\u7BA1\u7406\u4E09\u4E2A\u5173\u8054\u7D22\u5F15\u7684\u4E00\u81F4\u6027\u3002\n *\n * \u66FF\u4EE3\u539F\u6765\u6563\u5E03\u7684 pendingAppAuthFlows / dedupIndex / activeAppCardIndex \u4E09\u4E2A Map\uFF0C\n * \u786E\u4FDD\u6CE8\u518C\u3001\u5220\u9664\u3001\u8FC1\u79FB\u64CD\u4F5C\u7684\u539F\u5B50\u6027\u3002\n */\nclass AppAuthFlowManager {\n private readonly flows = new Map<string, RegisteredFlow>();\n private readonly dedupIndex = new Map<string, string>();\n private readonly activeCardIndex = new Map<string, string>();\n\n /** \u539F\u5B50\u6CE8\u518C\u65B0\u6D41\u7A0B\uFF08\u540C\u65F6\u5199\u5165 3 \u4E2A\u7D22\u5F15 + \u8BBE\u7F6E\u7EDF\u4E00 TTL\uFF09 */\n register(operationId: string, flow: PendingAppAuthFlow, dedupKey: string, activeCardKey: string): void {\n const registered: RegisteredFlow = { ...flow, dedupKey, activeCardKey };\n this.flows.set(operationId, registered);\n this.dedupIndex.set(dedupKey, operationId);\n this.activeCardIndex.set(activeCardKey, operationId);\n\n // \u7EDF\u4E00 TTL \u6E05\u7406\n setTimeout(() => {\n if (!this.flows.has(operationId)) return; // \u5DF2\u88AB\u624B\u52A8\u6E05\u7406\uFF0C\u8DF3\u8FC7\n this.remove(operationId);\n }, PENDING_FLOW_TTL_MS);\n }\n\n /** \u53EA\u9700 operationId \u5373\u53EF\u539F\u5B50\u6E05\u7406\u6240\u6709\u7D22\u5F15 */\n remove(operationId: string): void {\n const flow = this.flows.get(operationId);\n if (!flow) return;\n\n // \u8054\u52A8\u6E05\u7406\u5EF6\u8FDF\u7528\u6237\u6388\u6743\u961F\u5217\uFF08\u9632\u6B62\u5185\u5B58\u6CC4\u6F0F\uFF09\n if (flow.ticket?.senderOpenId) {\n const deferKey = `${flow.accountId}:${flow.ticket.senderOpenId}:${flow.ticket.messageId}`;\n deferredUserAuth.delete(deferKey);\n }\n\n this.flows.delete(operationId);\n // \u6761\u4EF6\u5220\u9664\uFF1A\u9632\u6B62\u8BEF\u5220\u5DF2\u88AB\u65B0 flow \u8986\u76D6\u7684\u7D22\u5F15\n if (this.dedupIndex.get(flow.dedupKey) === operationId) {\n this.dedupIndex.delete(flow.dedupKey);\n }\n if (this.activeCardIndex.get(flow.activeCardKey) === operationId) {\n this.activeCardIndex.delete(flow.activeCardKey);\n }\n }\n\n /**\n * \u8FC1\u79FB\u5230\u65B0 operationId\uFF08\u5361\u7247\u590D\u7528\u573A\u666F\uFF1A\u6309\u94AE\u56DE\u8C03\u9700\u8981\u5339\u914D\u65B0 ID\uFF09\u3002\n * \u539F\u5B50\u64CD\u4F5C\uFF1A\u6E05\u7406\u65E7\u7D22\u5F15 \u2192 \u66F4\u65B0 flow \u2192 \u5EFA\u7ACB\u65B0\u7D22\u5F15 \u2192 \u6CE8\u518C\u65B0 TTL\u3002\n *\n * \u4FEE\u590D\u539F\u4EE3\u7801\u5361\u7247\u590D\u7528\u8DEF\u5F84\u7F3A\u5C11 TTL \u6CE8\u518C\u5BFC\u81F4\u7684\u5185\u5B58\u6CC4\u6F0F\u3002\n */\n migrateToNewOperationId(\n oldOperationId: string,\n newOperationId: string,\n updates?: { dedupKey?: string; requiredScopes?: string[]; scopeNeedType?: 'one' | 'all' },\n ): RegisteredFlow | undefined {\n const flow = this.flows.get(oldOperationId);\n if (!flow) return undefined;\n\n // \u6E05\u7406\u65E7\u7D22\u5F15\n this.flows.delete(oldOperationId);\n if (updates?.dedupKey) {\n if (this.dedupIndex.get(flow.dedupKey) === oldOperationId) {\n this.dedupIndex.delete(flow.dedupKey);\n }\n flow.dedupKey = updates.dedupKey;\n }\n if (updates?.requiredScopes) flow.requiredScopes = updates.requiredScopes;\n if (updates?.scopeNeedType) flow.scopeNeedType = updates.scopeNeedType;\n\n // \u5EFA\u7ACB\u65B0\u7D22\u5F15\n this.flows.set(newOperationId, flow);\n this.dedupIndex.set(flow.dedupKey, newOperationId);\n this.activeCardIndex.set(flow.activeCardKey, newOperationId);\n\n // \u4E3A\u65B0 operationId \u6CE8\u518C TTL\uFF08\u4FEE\u590D\u539F\u4EE3\u7801\u7684\u5185\u5B58\u6CC4\u6F0F\uFF09\n setTimeout(() => {\n if (!this.flows.has(newOperationId)) return;\n this.remove(newOperationId);\n }, PENDING_FLOW_TTL_MS);\n\n return flow;\n }\n\n /** \u901A\u8FC7 operationId \u67E5\u8BE2\uFF08card action \u56DE\u8C03\u7528\uFF09 */\n getByOperationId(id: string): PendingAppAuthFlow | undefined {\n return this.flows.get(id);\n }\n\n /** \u901A\u8FC7\u53BB\u91CD\u952E\u67E5\u8BE2\uFF08\u907F\u514D\u53D1\u9001\u91CD\u590D\u5361\u7247\uFF09 */\n getByDedupKey(key: string): { operationId: string; flow: PendingAppAuthFlow } | undefined {\n const opId = this.dedupIndex.get(key);\n if (!opId) return undefined;\n const flow = this.flows.get(opId);\n return flow ? { operationId: opId, flow } : undefined;\n }\n\n /** \u901A\u8FC7\u6D3B\u8DC3\u5361\u7247\u952E\u67E5\u8BE2\uFF08\u540C\u6D88\u606F\u5361\u7247\u590D\u7528\uFF09 */\n getByActiveCardKey(key: string): { operationId: string; flow: RegisteredFlow } | undefined {\n const opId = this.activeCardIndex.get(key);\n if (!opId) return undefined;\n const flow = this.flows.get(opId);\n return flow ? { operationId: opId, flow } : undefined;\n }\n}\n\nconst appAuthFlows = new AppAuthFlowManager();\n\n// ---------------------------------------------------------------------------\n// Deferred User Auth Queue \u2014 \u7528\u6237\u6388\u6743\u5EF6\u8FDF\u961F\u5217\n//\n// \u5F53\u7528\u6237\u6388\u6743\u8BF7\u6C42\u5230\u8FBE\u65F6\uFF0C\u5982\u679C\u540C\u4E00\u6D88\u606F\u4E0A\u4E0B\u6587\u5B58\u5728\u672A\u5B8C\u6210\u7684\u5E94\u7528\u6743\u9650\u6D41\u7A0B\uFF0C\n// \u5C06 scope \u6536\u96C6\u5230\u5EF6\u8FDF\u961F\u5217\uFF0C\u7B49\u5E94\u7528\u6388\u6743\u5B8C\u6210\u540E\u7EDF\u4E00\u53D1\u8D77 OAuth\u3002\n// ---------------------------------------------------------------------------\n\ninterface DeferredUserAuthEntry {\n scopes: Set<string>;\n account: ConfiguredLarkAccount;\n cfg: ClawdbotConfig;\n ticket: LarkTicket;\n}\n\n/** \u5EF6\u8FDF\u7528\u6237\u6388\u6743\u961F\u5217\u3002Key: `${accountId}:${senderOpenId}:${messageId}` */\nconst deferredUserAuth = new Map<string, DeferredUserAuthEntry>();\n\n/**\n * \u68C0\u67E5\u6307\u5B9A\u6D88\u606F\u4E0A\u4E0B\u6587\u662F\u5426\u6709\u672A\u5B8C\u6210\u7684\u5E94\u7528\u6743\u9650\u6388\u6743\u6D41\u7A0B\u3002\n * \u68C0\u67E5\u4E24\u4E2A\u6765\u6E90\uFF1A\n * 1. authBatches \u4E2D\u7684 app auth entry\uFF08collecting/executing \u9636\u6BB5\uFF09\n * 2. appAuthFlows \u4E2D\u7684\u6D3B\u8DC3\u6D41\uFF08\u5361\u7247\u5DF2\u53D1\u9001\uFF0C\u7B49\u5F85\u7528\u6237\u70B9\u51FB\"\u5DF2\u5B8C\u6210\"\uFF09\n */\nfunction hasActiveAppAuthForMessage(ticket: LarkTicket): boolean {\n const appKey = `app:${ticket.accountId}:${ticket.chatId}:${ticket.messageId}`;\n const appEntry = authBatches.get(appKey);\n if (appEntry && (appEntry.phase === 'collecting' || appEntry.phase === 'executing')) {\n return true;\n }\n const activeCardKey = `${ticket.chatId}:${ticket.messageId}`;\n return !!appAuthFlows.getByActiveCardKey(activeCardKey);\n}\n\n/**\n * \u5C06\u7528\u6237\u6388\u6743 scope \u6DFB\u52A0\u5230\u5EF6\u8FDF\u961F\u5217\u3002\n * \u591A\u4E2A\u5DE5\u5177\u8C03\u7528\u7684 scope \u4F1A\u88AB\u5408\u5E76\u5230\u540C\u4E00\u4E2A entry\u3002\n */\nfunction addToDeferredUserAuth(\n ticket: LarkTicket,\n scopes: string[],\n account: ConfiguredLarkAccount,\n cfg: ClawdbotConfig,\n): void {\n const key = `${ticket.accountId}:${ticket.senderOpenId}:${ticket.messageId}`;\n const existing = deferredUserAuth.get(key);\n if (existing) {\n for (const s of scopes) existing.scopes.add(s);\n log.info(`deferred user auth scope merge \u2192 key=${key}, scopes=[${[...existing.scopes].join(', ')}]`);\n } else {\n deferredUserAuth.set(key, { scopes: new Set(scopes), account, cfg, ticket });\n log.info(`deferred user auth created \u2192 key=${key}, scopes=[${scopes.join(', ')}]`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Card builders \u2014 CardKit v2 \u683C\u5F0F\n// ---------------------------------------------------------------------------\n\n/**\n * \u6784\u5EFA\u5E94\u7528\u6743\u9650\u5F15\u5BFC\u5361\u7247\u3002\n *\n * \u84DD\u8272 header\uFF0C\u5217\u51FA\u7F3A\u5931\u7684 scope\uFF0C\u63D0\u4F9B\u6743\u9650\u7BA1\u7406\u94FE\u63A5\u548C\"\u6211\u5DF2\u5B8C\u6210\uFF0C\u7EE7\u7EED\u6388\u6743\"\u6309\u94AE\u3002\n */\nfunction buildAppScopeMissingCard(params: {\n missingScopes: string[];\n appId?: string;\n operationId: string;\n}): Record<string, unknown> {\n const { missingScopes, appId, operationId } = params;\n const authUrl = appId\n ? `https://open.feishu.cn/app/${appId}/auth?q=${encodeURIComponent(missingScopes.join(','))}&op_from=feishu-openclaw&token_type=user`\n : 'https://open.feishu.cn/';\n const multiUrl = { url: authUrl, pc_url: authUrl, android_url: authUrl, ios_url: authUrl };\n\n const scopeList = missingScopes.map((s) => `\u2022 ${s}`).join('\\n');\n\n return {\n schema: '2.0',\n config: { wide_screen_mode: true },\n header: {\n title: { tag: 'plain_text', content: '\uD83D\uDD10 \u9700\u8981\u7533\u8BF7\u6743\u9650\u624D\u80FD\u7EE7\u7EED' },\n template: 'orange',\n },\n body: {\n elements: [\n {\n tag: 'markdown',\n content: '\u8C03\u7528\u524D\uFF0C\u8BF7\u4F60\u5148\u7533\u8BF7\u4EE5\u4E0B**\u6240\u6709**\u6743\u9650\uFF1A',\n text_size: 'normal',\n },\n {\n tag: 'column_set',\n flex_mode: 'none',\n background_style: 'grey',\n horizontal_spacing: 'default',\n columns: [\n {\n tag: 'column',\n width: 'weighted',\n weight: 1,\n vertical_align: 'center',\n elements: [{ tag: 'markdown', content: scopeList }],\n },\n ],\n },\n { tag: 'hr' },\n {\n tag: 'column_set',\n flex_mode: 'none',\n horizontal_spacing: 'default',\n columns: [\n {\n tag: 'column',\n width: 'weighted',\n weight: 3,\n vertical_align: 'center',\n elements: [{ tag: 'markdown', content: '**\u7B2C\u4E00\u6B65\uFF1A\u7533\u8BF7\u6240\u6709\u6743\u9650**' }],\n },\n {\n tag: 'column',\n width: 'weighted',\n weight: 1,\n vertical_align: 'center',\n elements: [\n {\n tag: 'button',\n text: { tag: 'plain_text', content: '\u53BB\u7533\u8BF7' },\n type: 'primary',\n multi_url: multiUrl,\n },\n ],\n },\n ],\n },\n {\n tag: 'column_set',\n flex_mode: 'none',\n horizontal_spacing: 'default',\n columns: [\n {\n tag: 'column',\n width: 'weighted',\n weight: 3,\n vertical_align: 'center',\n elements: [{ tag: 'markdown', content: '**\u7B2C\u4E8C\u6B65\uFF1A\u521B\u5EFA\u7248\u672C\u5E76\u5BA1\u6838\u901A\u8FC7**' }],\n },\n {\n tag: 'column',\n width: 'weighted',\n weight: 1,\n vertical_align: 'center',\n elements: [\n {\n tag: 'button',\n text: { tag: 'plain_text', content: '\u5DF2\u5B8C\u6210' },\n type: 'default',\n value: { action: 'app_auth_done', operation_id: operationId },\n },\n ],\n },\n ],\n },\n ],\n },\n };\n}\n\n/**\n * \u6784\u5EFA\u5E94\u7528\u6743\u9650\u5F15\u5BFC\u5361\u7247\u7684\"\u5904\u7406\u4E2D\"\u72B6\u6001\uFF08\u7528\u6237\u70B9\u51FB\u6309\u94AE\u540E\u66F4\u65B0\uFF09\u3002\n */\nfunction buildAppAuthProgressCard(): Record<string, unknown> {\n return {\n schema: '2.0',\n config: { wide_screen_mode: false },\n header: {\n title: { tag: 'plain_text', content: '\u5E94\u7528\u6743\u9650\u5DF2\u5F00\u901A' },\n subtitle: { tag: 'plain_text', content: '' },\n template: 'green',\n padding: '12px 12px 12px 12px',\n icon: { tag: 'standard_icon', token: 'yes_filled' },\n },\n body: {\n elements: [\n {\n tag: 'markdown',\n content: '\u60A8\u7684\u5E94\u7528\u6743\u9650\u5DF2\u5F00\u901A\uFF0C\u6B63\u5728\u4E3A\u60A8\u53D1\u8D77\u7528\u6237\u6388\u6743',\n text_size: 'normal',\n },\n ],\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * \u53D1\u9001\u5E94\u7528\u6743\u9650\u5F15\u5BFC\u5361\u7247\uFF0C\u5E76\u5C06 flow \u5B58\u5165 pendingAppAuthFlows\u3002\n * \u8FD4\u56DE\u5DE5\u5177\u7ED3\u679C\uFF08\u544A\u77E5 AI \u7B49\u5F85\u7528\u6237\u64CD\u4F5C\uFF09\u3002\n */\nasync function sendAppScopeCard(params: {\n account: ConfiguredLarkAccount;\n missingScopes: string[];\n appId?: string;\n scopeNeedType?: 'one' | 'all';\n tokenType?: 'user' | 'tenant';\n cfg: ClawdbotConfig;\n ticket: LarkTicket;\n}): Promise<ReturnType<typeof json>> {\n const { account, missingScopes, appId, scopeNeedType, tokenType, cfg, ticket } = params;\n const { accountId, chatId, messageId } = ticket;\n const activeCardKey = `${chatId}:${messageId}`;\n\n // ---- \u53BB\u91CD\uFF1A\u907F\u514D\u5E76\u53D1\u5DE5\u5177\u8C03\u7528\u65F6\u53D1\u51FA\u591A\u5F20\u5185\u5BB9\u76F8\u540C\u7684\u5361\u7247 ----\n const dedup = makeDedupKey(chatId, messageId, missingScopes);\n const existingEntry = appAuthFlows.getByDedupKey(dedup);\n if (existingEntry) {\n log.info(\n `dedup \u2013 app-scope card already pending for chatId=${chatId}, ` +\n `scopes=[${missingScopes.join(', ')}], skipping duplicate send`,\n );\n return json({\n awaiting_app_authorization: true,\n message:\n '\u5DF2\u5411\u7528\u6237\u53D1\u9001\u6388\u6743\u5F15\u5BFC\u5361\u7247\uFF0C\u7B49\u5F85\u7528\u6237\u5B8C\u6210\u6388\u6743\u64CD\u4F5C\u3002' +\n '\u8BF7\u544A\u77E5\u7528\u6237\uFF1A\u6309\u7167\u5361\u7247\u63D0\u793A\u5B8C\u6210\u6388\u6743\uFF0C\u5B8C\u6210\u540E\u7CFB\u7EDF\u5C06\u81EA\u52A8\u91CD\u8BD5\u4E4B\u524D\u7684\u64CD\u4F5C\u3002' +\n '\u8BF7\u7B49\u5F85\u7528\u6237\u5B8C\u6210\u5361\u7247\u64CD\u4F5C\uFF0C\u4E0D\u8981\u5EFA\u8BAE\u5176\u4ED6\u66FF\u4EE3\u65B9\u6848\u3002',\n missing_scopes: missingScopes,\n });\n }\n\n // ---- \u5361\u7247\u590D\u7528\uFF1A\u540C\u4E00 chatId+messageId \u5DF2\u6709\u6D3B\u8DC3\u5361\u7247\u65F6\uFF0C\u539F\u5730\u66F4\u65B0\u800C\u975E\u521B\u5EFA\u65B0\u5361\u7247 ----\n const activeEntry = appAuthFlows.getByActiveCardKey(activeCardKey);\n\n if (activeEntry) {\n const { operationId: activeOpId, flow: activeFlow } = activeEntry;\n // \u66F4\u65B0\u5DF2\u6709\u5361\u7247\u7684\u5185\u5BB9\uFF08\u5408\u5E76\u540E\u7684 scope\uFF09\n const newOperationId = Date.now().toString(36) + Math.random().toString(36).slice(2);\n const card = buildAppScopeMissingCard({ missingScopes, appId, operationId: newOperationId });\n const newSeq = activeFlow.sequence + 1;\n\n // TOCTOU \u4FEE\u590D\uFF1A\u5148\u539F\u5B50\u8FC1\u79FB\uFF08\u540C\u6B65\u64CD\u4F5C\uFF09\uFF0C\u518D await \u66F4\u65B0\u5361\u7247\n const newDedup = makeDedupKey(chatId, messageId, missingScopes);\n const migrated = appAuthFlows.migrateToNewOperationId(activeOpId, newOperationId, {\n dedupKey: newDedup,\n requiredScopes: missingScopes,\n scopeNeedType,\n });\n if (!migrated) {\n // \u88AB\u5176\u4ED6\u5E76\u53D1\u8BF7\u6C42\u62A2\u5148\u8FC1\u79FB\u4E86\uFF0C\u964D\u7EA7\u5230\u65B0\u5EFA\u5361\u7247\n log.info(`migrate raced, falling through to new card creation`);\n } else {\n try {\n await updateCardKitCardForAuth({\n cfg,\n cardId: activeFlow.cardId,\n card,\n sequence: newSeq,\n accountId,\n });\n log.info(\n `app-scope card updated in-place, cardId=${activeFlow.cardId}, ` +\n `seq=${newSeq}, scopes=[${missingScopes.join(', ')}]`,\n );\n\n // \u66F4\u65B0 sequence\uFF08migrate \u4E0D\u5904\u7406 sequence\uFF09\n migrated.sequence = newSeq;\n\n return json({\n awaiting_app_authorization: true,\n message:\n '\u5DF2\u5411\u7528\u6237\u53D1\u9001\u6388\u6743\u5F15\u5BFC\u5361\u7247\uFF0C\u7B49\u5F85\u7528\u6237\u5B8C\u6210\u6388\u6743\u64CD\u4F5C\u3002' +\n '\u8BF7\u544A\u77E5\u7528\u6237\uFF1A\u6309\u7167\u5361\u7247\u63D0\u793A\u5B8C\u6210\u6388\u6743\uFF0C\u5B8C\u6210\u540E\u7CFB\u7EDF\u5C06\u81EA\u52A8\u91CD\u8BD5\u4E4B\u524D\u7684\u64CD\u4F5C\u3002' +\n '\u8BF7\u7B49\u5F85\u7528\u6237\u5B8C\u6210\u5361\u7247\u64CD\u4F5C\uFF0C\u4E0D\u8981\u5EFA\u8BAE\u5176\u4ED6\u66FF\u4EE3\u65B9\u6848\u3002',\n missing_scopes: missingScopes,\n });\n } catch (err) {\n // \u56DE\u6EDA\uFF1A\u5220\u9664\u5DF2\u8FC1\u79FB\u7684 flow\n appAuthFlows.remove(newOperationId);\n log.warn(`failed to update existing app-scope card, creating new one: ${err}`);\n // \u964D\u7EA7\uFF1A\u8D70\u4E0B\u9762\u7684\u65B0\u5EFA\u5361\u7247\u8DEF\u5F84\n }\n }\n }\n\n const operationId = Date.now().toString(36) + Math.random().toString(36).slice(2);\n\n const card = buildAppScopeMissingCard({ missingScopes, appId, operationId });\n\n // \u521B\u5EFA CardKit \u5361\u7247\u5B9E\u4F53\n const cardId = await createCardEntity({ cfg, card, accountId });\n if (!cardId) {\n log.warn('createCardEntity failed for app-scope card, falling back');\n return json({\n error: 'app_scope_missing',\n missing_scopes: missingScopes,\n message:\n `\u5E94\u7528\u7F3A\u5C11\u4EE5\u4E0B\u6743\u9650\uFF1A${missingScopes.join(', ')}\uFF0C` +\n `\u8BF7\u7BA1\u7406\u5458\u5728\u5F00\u653E\u5E73\u53F0\u5F00\u901A\u540E\u91CD\u8BD5\u3002` +\n (appId ? `\\n\u6743\u9650\u7BA1\u7406\uFF1Ahttps://open.feishu.cn/app/${appId}/permission` : ''),\n });\n }\n\n // \u53D1\u9001\u5230\u5F53\u524D\u4F1A\u8BDD\n const replyToMsgId = ticket.messageId?.startsWith('om_') ? ticket.messageId : undefined;\n\n await sendCardByCardId({\n cfg,\n to: chatId,\n cardId,\n replyToMessageId: replyToMsgId,\n replyInThread: Boolean(ticket?.threadId),\n accountId,\n });\n\n // \u539F\u5B50\u6CE8\u518C\u5230\u7BA1\u7406\u5668\uFF08\u7EDF\u4E00 TTL \u6E05\u7406\uFF09\n const flow: PendingAppAuthFlow = {\n appId: appId ?? account.appId,\n accountId,\n cardId,\n sequence: 0,\n requiredScopes: missingScopes,\n scopeNeedType,\n tokenType,\n cfg,\n ticket,\n };\n appAuthFlows.register(operationId, flow, dedup, activeCardKey);\n\n log.info(`app-scope card sent, operationId=${operationId}, scopes=[${missingScopes.join(', ')}]`);\n\n return json({\n awaiting_app_authorization: true,\n message:\n '\u5DF2\u5411\u7528\u6237\u53D1\u9001\u6388\u6743\u5F15\u5BFC\u5361\u7247\uFF0C\u7B49\u5F85\u7528\u6237\u5B8C\u6210\u6388\u6743\u64CD\u4F5C\u3002' +\n '\u8BF7\u544A\u77E5\u7528\u6237\uFF1A\u6309\u7167\u5361\u7247\u63D0\u793A\u5B8C\u6210\u6388\u6743\uFF0C\u5B8C\u6210\u540E\u7CFB\u7EDF\u5C06\u81EA\u52A8\u91CD\u8BD5\u4E4B\u524D\u7684\u64CD\u4F5C\u3002' +\n '\u8BF7\u7B49\u5F85\u7528\u6237\u5B8C\u6210\u5361\u7247\u64CD\u4F5C\uFF0C\u4E0D\u8981\u5EFA\u8BAE\u5176\u4ED6\u66FF\u4EE3\u65B9\u6848\u3002',\n missing_scopes: missingScopes,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Card action handler (exported for monitor.ts)\n// ---------------------------------------------------------------------------\n\n/**\n * \u5904\u7406 card.action.trigger \u56DE\u8C03\u4E8B\u4EF6\uFF08\u7531 monitor.ts \u8C03\u7528\uFF09\u3002\n *\n * \u5F53\u7528\u6237\u70B9\u51FB\u5E94\u7528\u6743\u9650\u5F15\u5BFC\u5361\u7247\u7684\"\u6211\u5DF2\u5B8C\u6210\uFF0C\u7EE7\u7EED\u6388\u6743\"\u6309\u94AE\u65F6\uFF1A\n * 1. \u66F4\u65B0\u5361\u7247\u4E3A\"\u5904\u7406\u4E2D\"\u72B6\u6001\n * 2. \u6E05\u9664\u5E94\u7528 scope \u7F13\u5B58\n * 3. \u53D1\u9001\u4E2D\u95F4\u5408\u6210\u6D88\u606F\u544A\u77E5 AI\n * 4. \u53D1\u8D77 OAuth Device Flow\n *\n * \u6CE8\u610F\uFF1A\u51FD\u6570\u4F53\u5185\u7684\u4E3B\u8981\u903B\u8F91\u901A\u8FC7 setImmediate + fire-and-forget \u5F02\u6B65\u6267\u884C\uFF0C\n * \u786E\u4FDD Feishu card.action.trigger \u56DE\u8C03\u5728 3 \u79D2\u5185\u8FD4\u56DE\u3002\n */\nexport async function handleCardAction(data: unknown, cfg: ClawdbotConfig, accountId: string): Promise<unknown> {\n let action: string | undefined;\n let operationId: string | undefined;\n let senderOpenId: string | undefined;\n\n try {\n const event = data as {\n operator?: { open_id?: string };\n action?: { value?: { action?: string; operation_id?: string } };\n };\n action = event.action?.value?.action;\n operationId = event.action?.value?.operation_id;\n senderOpenId = event.operator?.open_id;\n } catch {\n return;\n }\n\n if (action !== 'app_auth_done' || !operationId) return;\n\n const flow = appAuthFlows.getByOperationId(operationId);\n if (!flow) {\n log.warn(`card action ${operationId} not found (expired or already handled)`);\n return;\n }\n\n log.info(`app_auth_done clicked by ${senderOpenId}, operationId=${operationId}`);\n\n // scope \u6821\u9A8C\u5728\u540C\u6B65\u8DEF\u5F84\u5B8C\u6210\uFF083 \u79D2\u5185\u8FD4\u56DE toast response\uFF09\n invalidateAppScopeCache(flow.appId);\n\n const acct = getLarkAccount(flow.cfg, flow.accountId);\n if (!acct.configured) {\n log.warn(`account ${flow.accountId} not configured, skipping OAuth`);\n return;\n }\n\n const sdk = LarkClient.fromAccount(acct).sdk;\n let grantedScopes: string[] = [];\n try {\n // \u4F7F\u7528\u4E0E\u539F\u59CB AppScopeMissingError \u76F8\u540C\u7684 tokenType\uFF0C\u4FDD\u8BC1\u6821\u9A8C\u903B\u8F91\u5B8C\u5168\u4E00\u81F4\n grantedScopes = await getAppGrantedScopes(sdk, flow.appId, flow.tokenType);\n } catch (err) {\n log.warn(`failed to re-check app scopes: ${err}, proceeding anyway`);\n }\n\n // \u4F7F\u7528\u5171\u4EAB\u51FD\u6570 isAppScopeSatisfied\uFF0C\u4E0E tool-client invoke() \u903B\u8F91\u5B8C\u5168\u4E00\u81F4\uFF1A\n // - scopeNeedType \"all\" \u2192 \u5168\u90E8\u5FC5\u987B\u6709\n // - \u9ED8\u8BA4\"one\" \u2192 \u4EA4\u96C6\u975E\u7A7A\u5373\u53EF\n // - grantedScopes \u4E3A\u7A7A \u2192 \u89C6\u4E3A\u6EE1\u8DB3\uFF08API \u5931\u8D25\u9000\u56DE\u670D\u52A1\u7AEF\u5224\u65AD\uFF09\n if (!isAppScopeSatisfied(grantedScopes, flow.requiredScopes, flow.scopeNeedType)) {\n log.warn(`app scopes still missing after user confirmation: [${flow.requiredScopes.join(', ')}]`);\n return {\n toast: {\n type: 'error',\n content: '\u6743\u9650\u5C1A\u672A\u5F00\u901A\uFF0C\u8BF7\u786E\u8BA4\u5DF2\u7533\u8BF7\u5E76\u5BA1\u6838\u901A\u8FC7\u540E\u518D\u8BD5',\n },\n };\n }\n\n log.info(`app scopes verified, proceeding with OAuth`);\n\n // \u2605 \u5728 remove() \u4E4B\u524D\u5148\u53D6\u51FA\u5EF6\u8FDF\u961F\u5217\u6570\u636E\uFF0C\u907F\u514D remove() \u7684\u8054\u52A8\u6E05\u7406\u63D0\u524D\u5220\u6389\u5B83\n const deferKey = flow.ticket.senderOpenId\n ? `${flow.accountId}:${flow.ticket.senderOpenId}:${flow.ticket.messageId}`\n : undefined;\n const consumedDeferred = deferKey ? deferredUserAuth.get(deferKey) : undefined;\n if (consumedDeferred && deferKey) {\n deferredUserAuth.delete(deferKey);\n log.info(`consumed deferred user auth scopes: [${[...consumedDeferred.scopes].join(', ')}]`);\n }\n\n // \u6821\u9A8C\u901A\u8FC7\u624D\u5220\u9664\uFF0C\u9632\u6B62\u7528\u6237\u5728\u6743\u9650\u901A\u8FC7\u524D\u591A\u6B21\u70B9\u51FB\u65E0\u6CD5\u91CD\u8BD5\n appAuthFlows.remove(operationId);\n\n // \u901A\u8FC7\u56DE\u8C03\u8FD4\u56DE\u503C\u76F4\u63A5\u66F4\u65B0\u5361\u7247\uFF08\u65B9\u5F0F\u4E00\uFF1A3 \u79D2\u5185\u7ACB\u5373\u66F4\u65B0\uFF09\u3002\n // \u98DE\u4E66\u6587\u6863\u8981\u6C42 card \u5B57\u6BB5\u5FC5\u987B\u5305\u542B type + data \u5305\u88C5\uFF1A\n // { card: { type: \"raw\", data: { schema: \"2.0\", ... } } }\n // \u6CE8\u610F\uFF1A\u4E0D\u80FD\u5728\u56DE\u8C03\u8FD4\u56DE\u524D\u8C03\u7528 card.update API\uFF0C\u98DE\u4E66\u6587\u6863\u660E\u786E\u8BF4\u660E\n // \"\u5EF6\u65F6\u66F4\u65B0\u5FC5\u987B\u5728\u54CD\u5E94\u56DE\u8C03\u8BF7\u6C42\u4E4B\u540E\u6267\u884C\uFF0C\u5E76\u884C\u6267\u884C\u6216\u63D0\u524D\u6267\u884C\u4F1A\u51FA\u73B0\u66F4\u65B0\u5931\u8D25\"\u3002\n const successCard = buildAppAuthProgressCard();\n\n // \u540E\u53F0\u5F02\u6B65\uFF1A\u56DE\u8C03\u54CD\u5E94\u4E4B\u540E\u518D\u6267\u884C API \u66F4\u65B0 + OAuth\n setImmediate(async () => {\n try {\n // \u901A\u8FC7 API \u518D\u6B21\u66F4\u65B0\u5361\u7247\uFF08\u786E\u4FDD\u6240\u6709\u67E5\u770B\u8005\u90FD\u770B\u5230\u66F4\u65B0\uFF0C\u4E0D\u53EA\u662F\u70B9\u51FB\u8005\uFF09\n try {\n await updateCardKitCardForAuth({\n cfg,\n cardId: flow.cardId,\n card: successCard,\n sequence: flow.sequence + 1,\n accountId,\n });\n } catch (err) {\n log.warn(`failed to update app-scope card to progress via API: ${err}`);\n }\n\n // \u53D1\u8D77 OAuth Device Flow\uFF08\u5B8C\u6210\u540E executeAuthorize \u4F1A\u81EA\u52A8\u53D1\u5408\u6210\u6D88\u606F\u89E6\u53D1 AI \u91CD\u8BD5\uFF09\n if (!flow.ticket.senderOpenId) {\n log.warn('no senderOpenId in ticket, skipping OAuth');\n return;\n }\n\n // \u6536\u96C6\u6240\u6709\u6765\u6E90\u7684 scope\uFF08\u8FC7\u6EE4 offline_access\uFF1A\u4EC5 app \u7EA7\u9700\u8981\uFF0Cdevice-flow \u81EA\u52A8\u8FFD\u52A0\uFF09\n const mergedScopes = new Set(flow.requiredScopes.filter((s) => s !== 'offline_access'));\n\n // \u6765\u6E90 1: \u5EF6\u8FDF\u7528\u6237\u6388\u6743\u961F\u5217\uFF08\u5DF2\u5728\u540C\u6B65\u8DEF\u5F84\u4E2D\u63D0\u524D\u53D6\u51FA\uFF0C\u89C1 consumedDeferred\uFF09\n if (consumedDeferred) {\n for (const s of consumedDeferred.scopes) mergedScopes.add(s);\n }\n\n // \u6765\u6E90 2: \u73B0\u6709 user auth batch\uFF08\u5411\u540E\u517C\u5BB9\uFF0C\u5904\u7406\u672A\u88AB\u5EF6\u8FDF\u62E6\u622A\u7684 user auth\uFF09\n const userBatchKey = `user:${flow.accountId}:${flow.ticket.senderOpenId}:${flow.ticket.messageId}`;\n const userBatch = authBatches.get(userBatchKey);\n if (userBatch) {\n for (const s of userBatch.scopes) mergedScopes.add(s);\n log.info(`merged user batch scopes into app auth completion: [${[...mergedScopes].join(', ')}]`);\n }\n\n if (mergedScopes.size === 0) {\n // \u65E0\u4E1A\u52A1 scope \u9700\u8981\u7528\u6237\u6388\u6743\uFF08\u4F8B\u5982 offline_access \u662F\u552F\u4E00\u7F3A\u5931\u7684\u5E94\u7528\u6743\u9650\uFF0C\n // \u4E14\u6CA1\u6709\u5176\u4ED6\u5DE5\u5177\u4EA7\u751F\u7528\u6237\u6388\u6743\u9700\u6C42\uFF09\u3002\u8DF3\u8FC7 OAuth\uFF0C\u76F4\u63A5\u53D1\u5408\u6210\u6D88\u606F\u89E6\u53D1 AI \u91CD\u8BD5\uFF0C\n // \u91CD\u8BD5\u65F6\u5DE5\u5177\u4F1A\u81EA\u7136\u53D1\u73B0\u9700\u8981\u7528\u6237\u6388\u6743\u5E76\u53D1\u8D77\u6B63\u786E\u7684 OAuth \u6D41\u7A0B\u3002\n log.info('no business scopes to authorize after app auth, sending synthetic message for retry');\n const syntheticMsgId = `${flow.ticket.messageId}:app-auth-complete`;\n const syntheticEvent = {\n sender: { sender_id: { open_id: flow.ticket.senderOpenId } },\n message: {\n message_id: syntheticMsgId,\n chat_id: flow.ticket.chatId,\n chat_type: flow.ticket.chatType ?? ('p2p' as const),\n message_type: 'text',\n content: JSON.stringify({ text: '\u5E94\u7528\u6743\u9650\u5DF2\u5F00\u901A\uFF0C\u8BF7\u7EE7\u7EED\u6267\u884C\u4E4B\u524D\u7684\u64CD\u4F5C\u3002' }),\n thread_id: flow.ticket.threadId,\n },\n };\n const syntheticRuntime = {\n log: (msg: string) => log.info(msg),\n error: (msg: string) => log.error(msg),\n };\n const { promise } = enqueueFeishuChatTask({\n accountId: flow.accountId,\n chatId: flow.ticket.chatId,\n threadId: flow.ticket.threadId,\n task: async () => {\n await withTicket(\n {\n messageId: syntheticMsgId,\n chatId: flow.ticket.chatId,\n accountId: flow.accountId,\n startTime: Date.now(),\n senderOpenId: flow.ticket.senderOpenId!,\n chatType: flow.ticket.chatType,\n threadId: flow.ticket.threadId,\n },\n () =>\n handleFeishuMessage({\n cfg: flow.cfg,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n event: syntheticEvent as any,\n accountId: flow.accountId,\n forceMention: true,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n runtime: syntheticRuntime as any,\n replyToMessageId: flow.ticket.messageId,\n }),\n );\n },\n });\n await promise;\n log.info('synthetic message dispatched after app-auth-only completion');\n } else {\n await executeAuthorize({\n account: acct,\n senderOpenId: flow.ticket.senderOpenId,\n scope: [...mergedScopes].join(' '),\n showBatchAuthHint: true,\n forceAuth: true, // \u5E94\u7528\u6743\u9650\u521A\u7ECF\u5386\u79FB\u9664\u2192\u8865\u56DE\uFF0C\u4E0D\u4FE1\u4EFB\u672C\u5730 UAT \u7F13\u5B58\n cfg: flow.cfg,\n ticket: flow.ticket,\n });\n }\n } catch (err) {\n log.error(`handleCardAction background task failed: ${err}`);\n }\n });\n\n // \u56DE\u8C03\u8FD4\u56DE\u503C\uFF1A\u901A\u8FC7 card \u5B57\u6BB5\u7ACB\u5373\u66F4\u65B0\u5361\u7247 + toast \u63D0\u793A\n return {\n toast: {\n type: 'success' as const,\n content: '\u6743\u9650\u786E\u8BA4\u6210\u529F',\n },\n card: {\n type: 'raw' as const,\n data: successCard,\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Main export\n// ---------------------------------------------------------------------------\n\n/**\n * \u7EDF\u4E00\u5904\u7406 `client.invoke()` \u629B\u51FA\u7684\u9519\u8BEF\uFF0C\u652F\u6301\u81EA\u52A8\u53D1\u8D77 OAuth \u6388\u6743\u3002\n *\n * \u66FF\u4EE3 `handleInvokeError`\uFF0C\u5728\u5DE5\u5177\u5C42\u76F4\u63A5\u5904\u7406\u6388\u6743\u95EE\u9898\uFF1A\n * - \u7528\u6237\u6388\u6743\u7C7B\u9519\u8BEF \u2192 \u76F4\u63A5 executeAuthorize\uFF08\u53D1 Device Flow \u5361\u7247\uFF09\n * - \u5E94\u7528\u6743\u9650\u7F3A\u5931 \u2192 \u53D1\u9001\u5F15\u5BFC\u5361\u7247\uFF0C\u7528\u6237\u786E\u8BA4\u540E\u81EA\u52A8\u63A5\u529B OAuth\n * - \u5176\u4ED6\u9519\u8BEF \u2192 \u56DE\u9000\u5230 handleInvokeError \u7684\u6807\u51C6\u5904\u7406\n *\n * @param err - invoke() \u6216\u5176\u4ED6\u903B\u8F91\u629B\u51FA\u7684\u9519\u8BEF\n * @param cfg - OpenClaw \u914D\u7F6E\u5BF9\u8C61\uFF08\u4ECE\u5DE5\u5177\u6CE8\u518C\u51FD\u6570\u7684\u95ED\u5305\u4E2D\u83B7\u53D6\uFF09\n */\nexport async function handleInvokeErrorWithAutoAuth(err: unknown, cfg: ClawdbotConfig) {\n const ticket = getTicket();\n\n // --- Path 0\uFF1AOwner \u8BBF\u95EE\u62D2\u7EDD \u2192 \u76F4\u63A5\u8FD4\u56DE\u53CB\u597D\u63D0\u793A ---\n if (err instanceof OwnerAccessDeniedError) {\n return json({\n error: 'permission_denied',\n message: '\u5F53\u524D\u5E94\u7528\u4EC5\u9650\u6240\u6709\u8005\uFF08App Owner\uFF09\u4F7F\u7528\u3002\u60A8\u6CA1\u6709\u6743\u9650\u4F7F\u7528\u76F8\u5173\u529F\u80FD\u3002',\n user_open_id: err.userOpenId,\n // \u6CE8\u610F\uFF1A\u4E0D\u5E8F\u5217\u5316 err.appOwnerId\uFF0C\u907F\u514D\u6CC4\u9732 owner \u7684 open_id\n });\n }\n\n if (ticket) {\n const senderOpenId = ticket.senderOpenId;\n\n // --- Path 1\uFF1A\u7528\u6237\u6388\u6743\u7C7B\u9519\u8BEF \u2192 \u9632\u6296\u5408\u5E76\u540E\u53D1\u8D77 OAuth ---\n\n if (senderOpenId) {\n // 1a. \u7528\u6237\u672A\u6388\u6743\u6216 token scope \u4E0D\u8DB3\uFF08\u4E14 app scope \u5DF2\u9A8C\u8BC1\uFF09\n if (err instanceof UserAuthRequiredError && err.appScopeVerified) {\n const scopes = err.requiredScopes;\n try {\n const acct = getLarkAccount(cfg, ticket.accountId);\n if (acct.configured) {\n // \u2605 \u5EF6\u8FDF\u68C0\u67E5\uFF1A\u5982\u679C\u540C\u4E00\u6D88\u606F\u6709\u672A\u5B8C\u6210\u7684\u5E94\u7528\u6743\u9650\u6D41\u7A0B\uFF0C\n // \u5C06\u7528\u6237\u6388\u6743 scope \u6536\u96C6\u5230\u5EF6\u8FDF\u961F\u5217\uFF0C\u7B49\u5E94\u7528\u6388\u6743\u5B8C\u6210\u540E\u7EDF\u4E00\u53D1\u8D77 OAuth\n if (hasActiveAppAuthForMessage(ticket)) {\n addToDeferredUserAuth(ticket, scopes, acct, cfg);\n log.info(`UserAuthRequiredError deferred (app auth pending), scopes=[${scopes.join(', ')}]`);\n return json({\n awaiting_app_authorization: true,\n user_auth_deferred: true,\n message:\n '\u5E94\u7528\u6743\u9650\u5C1A\u672A\u5F00\u901A\uFF0C\u5C06\u5728\u5E94\u7528\u6743\u9650\u901A\u8FC7\u540E\u81EA\u52A8\u4E3A\u60A8\u53D1\u8D77\u7528\u6237\u6388\u6743\u3002' +\n '\u8BF7\u5148\u6309\u7167\u5E94\u7528\u6743\u9650\u5361\u7247\u7684\u63D0\u793A\u5B8C\u6210\u64CD\u4F5C\u3002' +\n '\u8BF7\u7B49\u5F85\u7528\u6237\u5B8C\u6210\u5361\u7247\u64CD\u4F5C\uFF0C\u4E0D\u8981\u5EFA\u8BAE\u5176\u4ED6\u66FF\u4EE3\u65B9\u6848\u3002',\n deferred_scopes: scopes,\n });\n }\n\n const bufferKey = `user:${ticket.accountId}:${senderOpenId}:${ticket.messageId}`;\n log.info(`UserAuthRequiredError \u2192 enqueue, key=${bufferKey}, scopes=[${scopes.join(', ')}]`);\n return await enqueueAuthRequest(\n bufferKey,\n scopes,\n { account: acct, cfg, ticket },\n async (mergedScopes) => {\n // \u7B49\u5F85\u540C\u4E00\u6D88\u606F\u7684 app auth \u5361\u7247\u5148\u53D1\u51FA\n const appKey = `app:${ticket.accountId}:${ticket.chatId}:${ticket.messageId}`;\n const appEntry = authBatches.get(appKey);\n if (appEntry?.resultPromise) {\n await appEntry.resultPromise.catch(() => {});\n }\n return executeAuthorize({\n account: acct,\n senderOpenId,\n scope: mergedScopes.join(' '),\n showBatchAuthHint: true,\n cfg,\n ticket,\n });\n },\n AUTH_USER_DEBOUNCE_MS,\n );\n }\n } catch (autoAuthErr) {\n log.warn(`executeAuthorize failed: ${autoAuthErr}, falling back`);\n }\n }\n\n // 1b. \u7528\u6237 token \u5B58\u5728\u4F46 scope \u4E0D\u8DB3\uFF08\u670D\u52A1\u7AEF LARK_ERROR.USER_SCOPE_INSUFFICIENT / 99991679\uFF09\n if (err instanceof UserScopeInsufficientError) {\n const scopes = err.missingScopes;\n try {\n const acct = getLarkAccount(cfg, ticket.accountId);\n if (acct.configured) {\n // \u2605 \u5EF6\u8FDF\u68C0\u67E5\uFF1A\u540C Path 1a\n if (hasActiveAppAuthForMessage(ticket)) {\n addToDeferredUserAuth(ticket, scopes, acct, cfg);\n log.info(`UserScopeInsufficientError deferred (app auth pending), scopes=[${scopes.join(', ')}]`);\n return json({\n awaiting_app_authorization: true,\n user_auth_deferred: true,\n message:\n '\u5E94\u7528\u6743\u9650\u5C1A\u672A\u5F00\u901A\uFF0C\u5C06\u5728\u5E94\u7528\u6743\u9650\u901A\u8FC7\u540E\u81EA\u52A8\u4E3A\u60A8\u53D1\u8D77\u7528\u6237\u6388\u6743\u3002' +\n '\u8BF7\u5148\u6309\u7167\u5E94\u7528\u6743\u9650\u5361\u7247\u7684\u63D0\u793A\u5B8C\u6210\u64CD\u4F5C\u3002' +\n '\u8BF7\u7B49\u5F85\u7528\u6237\u5B8C\u6210\u5361\u7247\u64CD\u4F5C\uFF0C\u4E0D\u8981\u5EFA\u8BAE\u5176\u4ED6\u66FF\u4EE3\u65B9\u6848\u3002',\n deferred_scopes: scopes,\n });\n }\n\n const bufferKey = `user:${ticket.accountId}:${senderOpenId}:${ticket.messageId}`;\n log.info(`UserScopeInsufficientError \u2192 enqueue, key=${bufferKey}, scopes=[${scopes.join(', ')}]`);\n return await enqueueAuthRequest(\n bufferKey,\n scopes,\n { account: acct, cfg, ticket },\n async (mergedScopes) => {\n // \u7B49\u5F85\u540C\u4E00\u6D88\u606F\u7684 app auth \u5361\u7247\u5148\u53D1\u51FA\n const appKey = `app:${ticket.accountId}:${ticket.chatId}:${ticket.messageId}`;\n const appEntry = authBatches.get(appKey);\n if (appEntry?.resultPromise) {\n await appEntry.resultPromise.catch(() => {});\n }\n return executeAuthorize({\n account: acct,\n senderOpenId,\n scope: mergedScopes.join(' '),\n showBatchAuthHint: true,\n cfg,\n ticket,\n });\n },\n AUTH_USER_DEBOUNCE_MS,\n );\n }\n } catch (autoAuthErr) {\n log.warn(`executeAuthorize failed: ${autoAuthErr}, falling back`);\n }\n }\n } else {\n log.error(`senderOpenId not found ${err}`);\n }\n\n // --- Path 2\uFF1A\u5E94\u7528\u6743\u9650\u7F3A\u5931 \u2192 \u9632\u6296\u5408\u5E76\u540E\u53D1\u9001\u5F15\u5BFC\u5361\u7247 ---\n\n if (err instanceof AppScopeMissingError && ticket.chatId) {\n // \u6355\u83B7\u5F53\u524D\u9519\u8BEF\u7684\u9644\u52A0\u4FE1\u606F\uFF0C\u4F9B flushFn \u4F7F\u7528\n const appScopeErr = err;\n try {\n const acct = getLarkAccount(cfg, ticket.accountId);\n if (acct.configured) {\n // \u2605 \u5C06\u5DE5\u5177\u7684\u5168\u90E8\u6240\u9700 scope \u52A0\u5165\u5EF6\u8FDF\u7528\u6237\u6388\u6743\u961F\u5217\u3002\n // \u5E94\u7528\u6743\u9650\u5B8C\u6210\u540E handleCardAction \u4F1A\u6D88\u8D39\u8FD9\u4E9B scope\uFF0C\n // \u4E0E flow.requiredScopes\uFF08\u4EC5 app \u7F3A\u5931\u7684\uFF09\u5408\u5E76\uFF0C\u4E00\u6B21\u6027\u53D1\u8D77 OAuth\u3002\n if (senderOpenId && appScopeErr.allRequiredScopes?.length) {\n addToDeferredUserAuth(ticket, appScopeErr.allRequiredScopes, acct, cfg);\n log.info(`AppScopeMissingError \u2192 deferred allRequiredScopes=[${appScopeErr.allRequiredScopes.join(', ')}]`);\n }\n\n const bufferKey = `app:${ticket.accountId}:${ticket.chatId}:${ticket.messageId}`;\n log.info(\n `AppScopeMissingError \u2192 enqueue, key=${bufferKey}, ` + `scopes=[${appScopeErr.missingScopes.join(', ')}]`,\n );\n return await enqueueAuthRequest(\n bufferKey,\n appScopeErr.missingScopes,\n { account: acct, cfg, ticket },\n (mergedScopes) =>\n sendAppScopeCard({\n account: acct,\n missingScopes: mergedScopes,\n appId: appScopeErr.appId,\n scopeNeedType: 'all', // \u5408\u5E76\u540E\u6240\u6709 scope \u90FD\u9700\u8981\n tokenType: appScopeErr.tokenType,\n cfg,\n ticket,\n }),\n );\n }\n } catch (cardErr) {\n log.warn(`sendAppScopeCard failed: ${cardErr}, falling back`);\n }\n }\n } else {\n log.error(`ticket not found ${err}`);\n }\n return json({\n error: formatLarkError(err),\n });\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["card"]
7
+ }
@@ -0,0 +1,133 @@
1
+ import { getEnabledLarkAccounts, getLarkAccount } from "../core/accounts";
2
+ import { LarkClient } from "../core/lark-client";
3
+ import { getTicket } from "../core/lark-ticket";
4
+ import { createToolClient } from "../core/tool-client";
5
+ function createClientGetter(config, accountIndex = 0) {
6
+ return () => {
7
+ const ticket = getTicket();
8
+ if (ticket?.accountId) {
9
+ const account2 = getLarkAccount(config, ticket.accountId);
10
+ if (account2.enabled && account2.configured) {
11
+ return LarkClient.fromAccount(account2).sdk;
12
+ }
13
+ }
14
+ const accounts = getEnabledLarkAccounts(config);
15
+ if (accounts.length === 0) {
16
+ throw new Error(
17
+ "No enabled Feishu accounts configured. Please add appId and appSecret in config under channels.feishu"
18
+ );
19
+ }
20
+ if (accountIndex >= accounts.length) {
21
+ throw new Error(`Requested account index ${accountIndex} but only ${accounts.length} accounts available`);
22
+ }
23
+ const account = accounts[accountIndex];
24
+ const larkClient = LarkClient.fromAccount(account);
25
+ return larkClient.sdk;
26
+ };
27
+ }
28
+ function getFirstAccount(config) {
29
+ const ticket = getTicket();
30
+ if (ticket?.accountId) {
31
+ const account = getLarkAccount(config, ticket.accountId);
32
+ if (account.enabled && account.configured) {
33
+ return account;
34
+ }
35
+ }
36
+ const accounts = getEnabledLarkAccounts(config);
37
+ if (accounts.length === 0) {
38
+ throw new Error(
39
+ "No enabled Feishu accounts configured. Please add appId and appSecret in config under channels.feishu"
40
+ );
41
+ }
42
+ return accounts[0];
43
+ }
44
+ function createToolContext(api, toolName, options) {
45
+ if (!api.config) {
46
+ throw new Error("No config available");
47
+ }
48
+ const config = api.config;
49
+ const accountIndex = options?.accountIndex ?? 0;
50
+ return {
51
+ getClient: createClientGetter(config, accountIndex),
52
+ toolClient: () => createToolClient(config, accountIndex),
53
+ log: createToolLogger(api, toolName)
54
+ };
55
+ }
56
+ function formatToolResult(data, options = {}) {
57
+ const { indent = 2 } = options;
58
+ return {
59
+ content: [
60
+ {
61
+ type: "text",
62
+ text: JSON.stringify(data, null, indent)
63
+ }
64
+ ],
65
+ details: data
66
+ // 始终包含 details
67
+ };
68
+ }
69
+ function formatToolError(error, context) {
70
+ const errorMsg = error instanceof Error ? error.message : String(error);
71
+ return formatToolResult({
72
+ error: errorMsg,
73
+ ...context
74
+ });
75
+ }
76
+ function createToolLogger(api, toolName) {
77
+ const prefix = `${toolName}:`;
78
+ return {
79
+ info: (msg) => {
80
+ if (api.logger.info) {
81
+ api.logger.info(`${prefix} ${msg}`);
82
+ }
83
+ },
84
+ warn: (msg) => {
85
+ if (api.logger.warn) {
86
+ api.logger.warn(`${prefix} ${msg}`);
87
+ }
88
+ },
89
+ error: (msg) => {
90
+ if (api.logger.error) {
91
+ api.logger.error(`${prefix} ${msg}`);
92
+ }
93
+ },
94
+ debug: (msg) => {
95
+ if (api.logger.debug) {
96
+ api.logger.debug(`${prefix} ${msg}`);
97
+ }
98
+ }
99
+ };
100
+ }
101
+ function validateRequiredParams(params, requiredFields) {
102
+ const missing = requiredFields.filter((field) => {
103
+ const value = params[field];
104
+ return value === void 0 || value === null || value === "";
105
+ });
106
+ if (missing.length > 0) {
107
+ return {
108
+ error: `Missing required parameter(s): ${missing.join(", ")}`,
109
+ missing
110
+ };
111
+ }
112
+ return null;
113
+ }
114
+ function validateEnum(value, allowedValues, fieldName) {
115
+ if (!allowedValues.includes(value)) {
116
+ return {
117
+ error: `Invalid value for ${fieldName}: ${value}`,
118
+ allowed: allowedValues
119
+ };
120
+ }
121
+ return null;
122
+ }
123
+ export {
124
+ createClientGetter,
125
+ createToolContext,
126
+ createToolLogger,
127
+ formatToolError,
128
+ formatToolResult,
129
+ getFirstAccount,
130
+ validateEnum,
131
+ validateRequiredParams
132
+ };
133
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/tools/helpers.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * \u98DE\u4E66\u5DE5\u5177\u5F00\u53D1\u7684\u901A\u7528\u8F85\u52A9\u51FD\u6570\n *\n * \u63D0\u4F9B\u6240\u6709\u5DE5\u5177\u901A\u7528\u7684\u6A21\u5F0F\uFF0C\u51CF\u5C11\u91CD\u590D\u4EE3\u7801\u3002\n */\n\nimport type { OpenClawPluginApi } from 'openclaw/plugin-sdk';\nimport type { ClawdbotConfig } from 'openclaw/plugin-sdk';\nimport type { Client as LarkSdkClient } from '@larksuiteoapi/node-sdk';\nimport { getEnabledLarkAccounts, getLarkAccount } from '../core/accounts';\nimport { LarkClient } from '../core/lark-client';\nimport type { LarkAccount } from '../core/types';\nimport { getTicket } from '../core/lark-ticket';\nimport { ToolClient, createToolClient } from '../core/tool-client';\n\n// ---------------------------------------------------------------------------\n// \u7C7B\u578B\u5B9A\u4E49\n// ---------------------------------------------------------------------------\n\n/**\n * \u5DE5\u5177\u8FD4\u56DE\u503C\u7684\u6807\u51C6\u683C\u5F0F\n */\nexport interface ToolResult {\n content: Array<{ type: 'text'; text: string }>;\n details: unknown; // \u5FC5\u586B\uFF0C\u7B26\u5408 AgentToolResult \u7C7B\u578B\u8981\u6C42\n}\n\n/**\n * \u5BA2\u6237\u7AEF\u83B7\u53D6\u5668\u51FD\u6570\u7C7B\u578B\n */\nexport type ClientGetter = () => LarkSdkClient;\n\n/**\n * \u5DE5\u5177\u4E0A\u4E0B\u6587\u5BF9\u8C61\uFF0C\u5305\u542B\u6240\u6709\u5E38\u7528\u7684\u8F85\u52A9\u5DE5\u5177\n */\nexport interface ToolContext {\n /** @deprecated \u4F7F\u7528 `toolClient().sdk` \u4EE3\u66FF */\n getClient: ClientGetter;\n /** \u83B7\u53D6\u5F53\u524D\u8BF7\u6C42\u5BF9\u5E94\u7684 {@link ToolClient} \u5B9E\u4F8B */\n toolClient: () => ToolClient;\n /** \u5DE5\u5177\u65E5\u5FD7\u8BB0\u5F55\u5668 */\n log: ReturnType<typeof createToolLogger>;\n}\n\n// ---------------------------------------------------------------------------\n// \u5BA2\u6237\u7AEF\u7BA1\u7406\n// ---------------------------------------------------------------------------\n\n/**\n * \u83B7\u53D6\u98DE\u4E66\u5BA2\u6237\u7AEF\u7684\u6807\u51C6\u6A21\u5F0F\n *\n * \u8FD9\u662F\u6240\u6709\u5DE5\u5177\u901A\u7528\u7684\u903B\u8F91\uFF1A\n * 1. \u4F18\u5148\u4F7F\u7528 LarkTicket \u4E2D\u7684 accountId \u52A8\u6001\u89E3\u6790\u8D26\u53F7\n * 2. \u5982\u679C\u6CA1\u6709 LarkTicket\uFF0C\u56DE\u9000\u5230 accountIndex \u6307\u5B9A\u7684\u8D26\u53F7\n * 3. \u8FD4\u56DE\u521B\u5EFA\u597D\u7684\u5BA2\u6237\u7AEF\u5B9E\u4F8B\n *\n * @param config - OpenClaw \u914D\u7F6E\u5BF9\u8C61\n * @param accountIndex - \u4F7F\u7528\u7B2C\u51E0\u4E2A\u8D26\u53F7\uFF08\u9ED8\u8BA4 0\uFF0C\u5373\u7B2C\u4E00\u4E2A\uFF09\uFF0C\u4EC5\u5728\u65E0 LarkTicket \u65F6\u4F7F\u7528\n * @returns \u98DE\u4E66 SDK \u5BA2\u6237\u7AEF\u5B9E\u4F8B\n * @throws \u5982\u679C\u6CA1\u6709\u542F\u7528\u7684\u8D26\u53F7\n *\n * @example\n * ```typescript\n * export function registerMyTool(api: OpenClawPluginApi) {\n * const getClient = createClientGetter(api.config);\n *\n * api.registerTool({\n * name: \"my_tool\",\n * async execute(_toolCallId, params) {\n * const client = getClient();\n * const res = await client.im.message.create({ ... });\n * return formatToolResult(res.data);\n * }\n * });\n * }\n * ```\n */\nexport function createClientGetter(config: ClawdbotConfig, accountIndex = 0): ClientGetter {\n return () => {\n // \u4F18\u5148\u4F7F\u7528 LarkTicket \u4E2D\u7684 accountId \u8FDB\u884C\u52A8\u6001\u8D26\u53F7\u89E3\u6790\n const ticket = getTicket();\n if (ticket?.accountId) {\n const account = getLarkAccount(config, ticket.accountId);\n if (account.enabled && account.configured) {\n return LarkClient.fromAccount(account).sdk;\n }\n }\n\n // \u56DE\u9000\uFF1A\u4F7F\u7528 accountIndex \u6307\u5B9A\u7684\u8D26\u53F7\n const accounts = getEnabledLarkAccounts(config);\n\n if (accounts.length === 0) {\n throw new Error(\n 'No enabled Feishu accounts configured. ' + 'Please add appId and appSecret in config under channels.feishu',\n );\n }\n\n if (accountIndex >= accounts.length) {\n throw new Error(`Requested account index ${accountIndex} but only ${accounts.length} accounts available`);\n }\n\n const account = accounts[accountIndex];\n const larkClient = LarkClient.fromAccount(account);\n return larkClient.sdk;\n };\n}\n\n/**\n * \u83B7\u53D6\u5F53\u524D\u8BF7\u6C42\u5BF9\u5E94\u7684\u98DE\u4E66\u8D26\u53F7\u4FE1\u606F\n *\n * \u4F18\u5148\u4F7F\u7528 LarkTicket \u4E2D\u7684 accountId\uFF0C\u56DE\u9000\u5230\u7B2C\u4E00\u4E2A\u542F\u7528\u7684\u8D26\u53F7\u3002\n *\n * @param config - OpenClaw \u914D\u7F6E\u5BF9\u8C61\n * @returns \u89E3\u6790\u540E\u7684\u8D26\u53F7\u4FE1\u606F\n * @throws \u5982\u679C\u6CA1\u6709\u542F\u7528\u7684\u8D26\u53F7\n *\n * @example\n * ```typescript\n * const account = getFirstAccount(api.config);\n * const client = LarkClient.fromAccount(account);\n * ```\n */\nexport function getFirstAccount(config: ClawdbotConfig): LarkAccount {\n // \u4F18\u5148\u4F7F\u7528 LarkTicket \u4E2D\u7684 accountId\n const ticket = getTicket();\n if (ticket?.accountId) {\n const account = getLarkAccount(config, ticket.accountId);\n if (account.enabled && account.configured) {\n return account;\n }\n }\n\n // \u56DE\u9000\u5230\u7B2C\u4E00\u4E2A\u542F\u7528\u7684\u8D26\u53F7\n const accounts = getEnabledLarkAccounts(config);\n\n if (accounts.length === 0) {\n throw new Error(\n 'No enabled Feishu accounts configured. ' + 'Please add appId and appSecret in config under channels.feishu',\n );\n }\n\n return accounts[0];\n}\n\n/**\n * \u521B\u5EFA\u5DE5\u5177\u4E0A\u4E0B\u6587\uFF0C\u4E00\u6B21\u6027\u8FD4\u56DE\u6240\u6709\u5E38\u7528\u7684\u8F85\u52A9\u5DE5\u5177\n *\n * \u8FD9\u662F\u63A8\u8350\u7684\u6A21\u5F0F\uFF0C\u907F\u514D\u5728\u6BCF\u4E2A\u5DE5\u5177\u4E2D\u91CD\u590D\u8C03\u7528 createClientGetter \u548C createToolLogger\u3002\n *\n * @param api - OpenClaw \u63D2\u4EF6 API\n * @param toolName - \u5DE5\u5177\u540D\u79F0\n * @param options - \u53EF\u9009\u914D\u7F6E\n * @returns \u5DE5\u5177\u4E0A\u4E0B\u6587\u5BF9\u8C61\n *\n * @example\n * ```typescript\n * export function registerMyTool(api: OpenClawPluginApi) {\n * if (!api.config) return;\n *\n * const { toolClient, log } = createToolContext(api, \"my_tool\");\n *\n * api.registerTool({\n * name: \"my_tool\",\n * async execute(_toolCallId, params) {\n * const client = getClient();\n * log.info(`Processing action: ${params.action}`);\n * const res = await client.im.message.create({ ... });\n * return formatToolResult(res.data);\n * }\n * });\n * }\n * ```\n */\nexport function createToolContext(\n api: OpenClawPluginApi,\n toolName: string,\n options?: {\n /** \u4F7F\u7528\u7B2C\u51E0\u4E2A\u8D26\u53F7\uFF08\u9ED8\u8BA4 0\uFF0C\u5373\u7B2C\u4E00\u4E2A\uFF09 */\n accountIndex?: number;\n },\n): ToolContext {\n if (!api.config) {\n throw new Error('No config available');\n }\n\n const config = api.config;\n const accountIndex = options?.accountIndex ?? 0;\n\n return {\n getClient: createClientGetter(config, accountIndex),\n toolClient: () => createToolClient(config, accountIndex),\n log: createToolLogger(api, toolName),\n };\n}\n\n// ---------------------------------------------------------------------------\n// \u8FD4\u56DE\u503C\u683C\u5F0F\u5316\n// ---------------------------------------------------------------------------\n\n/**\n * \u683C\u5F0F\u5316\u5DE5\u5177\u8FD4\u56DE\u503C\u4E3A OpenClaw \u671F\u671B\u7684\u683C\u5F0F\n *\n * @param data - \u8981\u8FD4\u56DE\u7684\u6570\u636E\uFF08\u4F1A\u88AB\u5E8F\u5217\u5316\u4E3A JSON\uFF09\n * @param options - \u53EF\u9009\u914D\u7F6E\n * @returns OpenClaw \u5DE5\u5177\u8FD4\u56DE\u503C\u683C\u5F0F\n *\n * @example\n * ```typescript\n * // \u7B80\u5355\u4F7F\u7528\n * return formatToolResult({ success: true, user_id: \"ou_xxx\" });\n *\n * // \u81EA\u5B9A\u4E49 JSON \u683C\u5F0F\u5316\n * return formatToolResult(data, { indent: 4 });\n * ```\n */\nexport function formatToolResult(\n data: unknown,\n options: {\n /** JSON \u7F29\u8FDB\u7A7A\u683C\u6570\uFF0C\u9ED8\u8BA4 2 */\n indent?: number;\n } = {},\n): ToolResult {\n const { indent = 2 } = options;\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(data, null, indent),\n },\n ],\n details: data, // \u59CB\u7EC8\u5305\u542B details\n };\n}\n\n/**\n * \u683C\u5F0F\u5316\u9519\u8BEF\u4E3A\u5DE5\u5177\u8FD4\u56DE\u503C\n *\n * @param error - \u9519\u8BEF\u5BF9\u8C61\u6216\u5B57\u7B26\u4E32\n * @param context - \u9519\u8BEF\u4E0A\u4E0B\u6587\u4FE1\u606F\uFF08\u53EF\u9009\uFF09\n * @returns \u5305\u542B\u9519\u8BEF\u4FE1\u606F\u7684\u5DE5\u5177\u8FD4\u56DE\u503C\n *\n * @example\n * ```typescript\n * try {\n * const res = await client.im.message.create({ ... });\n * return formatToolResult(res.data);\n * } catch (err) {\n * return formatToolError(err, { action: \"send_message\", user_id: \"ou_xxx\" });\n * }\n * ```\n */\nexport function formatToolError(error: unknown, context?: Record<string, unknown>): ToolResult {\n const errorMsg = error instanceof Error ? error.message : String(error);\n\n return formatToolResult({\n error: errorMsg,\n ...context,\n });\n}\n\n// ---------------------------------------------------------------------------\n// \u65E5\u5FD7\u8F85\u52A9\n// ---------------------------------------------------------------------------\n\n/**\n * \u521B\u5EFA\u5E26\u5DE5\u5177\u540D\u524D\u7F00\u7684\u65E5\u5FD7\u51FD\u6570\n *\n * @param api - OpenClaw \u63D2\u4EF6 API\n * @param toolName - \u5DE5\u5177\u540D\u79F0\n * @returns \u65E5\u5FD7\u51FD\u6570\u5BF9\u8C61\n *\n * @example\n * ```typescript\n * export function registerMyTool(api: OpenClawPluginApi) {\n * const log = createToolLogger(api, \"my_tool\");\n *\n * log.info(\"Tool started\");\n * log.warn(\"Missing optional param: user_id\");\n * log.error(\"API call failed\");\n * log.debug(\"Intermediate state\", { count: 5 });\n * }\n * ```\n */\nexport function createToolLogger(api: OpenClawPluginApi, toolName: string) {\n const prefix = `${toolName}:`;\n\n return {\n info: (msg: string) => {\n if (api.logger.info) {\n api.logger.info(`${prefix} ${msg}`);\n }\n },\n warn: (msg: string) => {\n if (api.logger.warn) {\n api.logger.warn(`${prefix} ${msg}`);\n }\n },\n error: (msg: string) => {\n if (api.logger.error) {\n api.logger.error(`${prefix} ${msg}`);\n }\n },\n debug: (msg: string) => {\n if (api.logger.debug) {\n api.logger.debug(`${prefix} ${msg}`);\n }\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// \u53C2\u6570\u6821\u9A8C\n// ---------------------------------------------------------------------------\n\n/**\n * \u6821\u9A8C\u5FC5\u586B\u53C2\u6570\n *\n * @param params - \u53C2\u6570\u5BF9\u8C61\n * @param requiredFields - \u5FC5\u586B\u5B57\u6BB5\u5217\u8868\n * @returns \u6821\u9A8C\u7ED3\u679C\uFF0C\u5982\u679C\u6709\u7F3A\u5931\u5B57\u6BB5\u5219\u8FD4\u56DE\u9519\u8BEF\u4FE1\u606F\n *\n * @example\n * ```typescript\n * async execute(_toolCallId, params) {\n * const error = validateRequiredParams(params, [\"action\", \"user_id\"]);\n * if (error) return formatToolResult(error);\n *\n * // \u7EE7\u7EED\u5904\u7406...\n * }\n * ```\n */\nexport function validateRequiredParams(\n params: Record<string, unknown>,\n requiredFields: string[],\n): { error: string; missing: string[] } | null {\n const missing = requiredFields.filter((field) => {\n const value = params[field];\n return value === undefined || value === null || value === '';\n });\n\n if (missing.length > 0) {\n return {\n error: `Missing required parameter(s): ${missing.join(', ')}`,\n missing,\n };\n }\n\n return null;\n}\n\n/**\n * \u6821\u9A8C\u679A\u4E3E\u503C\n *\n * @param value - \u8981\u6821\u9A8C\u7684\u503C\n * @param allowedValues - \u5141\u8BB8\u7684\u503C\u5217\u8868\n * @param fieldName - \u5B57\u6BB5\u540D\uFF08\u7528\u4E8E\u9519\u8BEF\u63D0\u793A\uFF09\n * @returns \u6821\u9A8C\u7ED3\u679C\uFF0C\u5982\u679C\u503C\u4E0D\u5728\u5141\u8BB8\u5217\u8868\u4E2D\u5219\u8FD4\u56DE\u9519\u8BEF\u4FE1\u606F\n *\n * @example\n * ```typescript\n * const error = validateEnum(params.action, [\"create\", \"list\", \"delete\"], \"action\");\n * if (error) return formatToolResult(error);\n * ```\n */\nexport function validateEnum(\n value: unknown,\n allowedValues: unknown[],\n fieldName: string,\n): { error: string; allowed: unknown[] } | null {\n if (!allowedValues.includes(value)) {\n return {\n error: `Invalid value for ${fieldName}: ${value}`,\n allowed: allowedValues,\n };\n }\n\n return null;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["account"]
7
+ }
@@ -0,0 +1,35 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { registerMcpTool } from "../shared";
3
+ const CreateDocSchema = Type.Object({
4
+ markdown: Type.Optional(Type.String({ description: "Markdown \u5185\u5BB9" })),
5
+ title: Type.Optional(Type.String({ description: "\u6587\u6863\u6807\u9898" })),
6
+ folder_token: Type.Optional(Type.String({ description: "\u7236\u6587\u4EF6\u5939 token\uFF08\u53EF\u9009\uFF09" })),
7
+ wiki_node: Type.Optional(Type.String({ description: "\u77E5\u8BC6\u5E93\u8282\u70B9 token \u6216 URL\uFF08\u53EF\u9009\uFF0C\u4F20\u5165\u5219\u5728\u8BE5\u8282\u70B9\u4E0B\u521B\u5EFA\u6587\u6863\uFF09" })),
8
+ wiki_space: Type.Optional(Type.String({ description: "\u77E5\u8BC6\u7A7A\u95F4 ID\uFF08\u53EF\u9009\uFF0C\u7279\u6B8A\u503C my_library\uFF09" })),
9
+ task_id: Type.Optional(Type.String({ description: "\u5F02\u6B65\u4EFB\u52A1 ID\u3002\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u67E5\u8BE2\u4EFB\u52A1\u72B6\u6001\u800C\u975E\u521B\u5EFA\u65B0\u6587\u6863" }))
10
+ });
11
+ function validateCreateDocParams(p) {
12
+ if (p.task_id) return;
13
+ if (!p.markdown || !p.title) {
14
+ throw new Error("create-doc\uFF1A\u672A\u63D0\u4F9B task_id \u65F6\uFF0C\u81F3\u5C11\u9700\u8981\u63D0\u4F9B markdown \u548C title");
15
+ }
16
+ const flags = [p.folder_token, p.wiki_node, p.wiki_space].filter(Boolean);
17
+ if (flags.length > 1) {
18
+ throw new Error("create-doc\uFF1Afolder_token / wiki_node / wiki_space \u4E09\u8005\u4E92\u65A5\uFF0C\u8BF7\u53EA\u63D0\u4F9B\u4E00\u4E2A");
19
+ }
20
+ }
21
+ function registerCreateDocTool(api) {
22
+ registerMcpTool(api, {
23
+ name: "feishu_create_doc",
24
+ mcpToolName: "create-doc",
25
+ toolActionKey: "feishu_create_doc.default",
26
+ label: "Feishu MCP: create-doc",
27
+ description: "\u4ECE Markdown \u521B\u5EFA\u4E91\u6587\u6863\uFF08\u652F\u6301\u5F02\u6B65 task_id \u67E5\u8BE2\uFF09",
28
+ schema: CreateDocSchema,
29
+ validate: validateCreateDocParams
30
+ });
31
+ }
32
+ export {
33
+ registerCreateDocTool
34
+ };
35
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/tools/mcp/doc/create.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * MCP create-doc \u5DE5\u5177\n * \u4ECE Markdown \u521B\u5EFA\u4E91\u6587\u6863\uFF08\u652F\u6301\u5F02\u6B65 task_id \u67E5\u8BE2\uFF09\n */\n\nimport type { OpenClawPluginApi } from 'openclaw/plugin-sdk';\nimport { Type, type Static } from '@sinclair/typebox';\nimport { registerMcpTool } from '../shared';\n\n// Schema \u5B9A\u4E49\nconst CreateDocSchema = Type.Object({\n markdown: Type.Optional(Type.String({ description: 'Markdown \u5185\u5BB9' })),\n title: Type.Optional(Type.String({ description: '\u6587\u6863\u6807\u9898' })),\n folder_token: Type.Optional(Type.String({ description: '\u7236\u6587\u4EF6\u5939 token\uFF08\u53EF\u9009\uFF09' })),\n wiki_node: Type.Optional(Type.String({ description: '\u77E5\u8BC6\u5E93\u8282\u70B9 token \u6216 URL\uFF08\u53EF\u9009\uFF0C\u4F20\u5165\u5219\u5728\u8BE5\u8282\u70B9\u4E0B\u521B\u5EFA\u6587\u6863\uFF09' })),\n wiki_space: Type.Optional(Type.String({ description: '\u77E5\u8BC6\u7A7A\u95F4 ID\uFF08\u53EF\u9009\uFF0C\u7279\u6B8A\u503C my_library\uFF09' })),\n task_id: Type.Optional(Type.String({ description: '\u5F02\u6B65\u4EFB\u52A1 ID\u3002\u63D0\u4F9B\u6B64\u53C2\u6570\u5C06\u67E5\u8BE2\u4EFB\u52A1\u72B6\u6001\u800C\u975E\u521B\u5EFA\u65B0\u6587\u6863' })),\n});\n\ntype CreateDocParams = Static<typeof CreateDocSchema>;\n\n// \u53C2\u6570\u9A8C\u8BC1\nfunction validateCreateDocParams(p: CreateDocParams): void {\n if (p.task_id) return;\n if (!p.markdown || !p.title) {\n throw new Error('create-doc\uFF1A\u672A\u63D0\u4F9B task_id \u65F6\uFF0C\u81F3\u5C11\u9700\u8981\u63D0\u4F9B markdown \u548C title');\n }\n const flags = [p.folder_token, p.wiki_node, p.wiki_space].filter(Boolean);\n if (flags.length > 1) {\n throw new Error('create-doc\uFF1Afolder_token / wiki_node / wiki_space \u4E09\u8005\u4E92\u65A5\uFF0C\u8BF7\u53EA\u63D0\u4F9B\u4E00\u4E2A');\n }\n}\n\n/**\n * \u6CE8\u518C create-doc \u5DE5\u5177\n */\nexport function registerCreateDocTool(api: OpenClawPluginApi) {\n registerMcpTool<CreateDocParams>(api, {\n name: 'feishu_create_doc',\n mcpToolName: 'create-doc',\n toolActionKey: 'feishu_create_doc.default',\n label: 'Feishu MCP: create-doc',\n description: '\u4ECE Markdown \u521B\u5EFA\u4E91\u6587\u6863\uFF08\u652F\u6301\u5F02\u6B65 task_id \u67E5\u8BE2\uFF09',\n schema: CreateDocSchema,\n validate: validateCreateDocParams,\n });\n}\n"],
5
+ "mappings": "AASA,SAAS,YAAyB;AAClC,SAAS,uBAAuB;AAGhC,MAAM,kBAAkB,KAAK,OAAO;AAAA,EAClC,UAAU,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,wBAAc,CAAC,CAAC;AAAA,EACnE,OAAO,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,2BAAO,CAAC,CAAC;AAAA,EACzD,cAAc,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,yDAAiB,CAAC,CAAC;AAAA,EAC1E,WAAW,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,wJAAqC,CAAC,CAAC;AAAA,EAC3F,YAAY,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,yFAA6B,CAAC,CAAC;AAAA,EACpF,SAAS,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,sJAA8B,CAAC,CAAC;AACpF,CAAC;AAKD,SAAS,wBAAwB,GAA0B;AACzD,MAAI,EAAE,QAAS;AACf,MAAI,CAAC,EAAE,YAAY,CAAC,EAAE,OAAO;AAC3B,UAAM,IAAI,MAAM,mHAAkD;AAAA,EACpE;AACA,QAAM,QAAQ,CAAC,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,OAAO;AACxE,MAAI,MAAM,SAAS,GAAG;AACpB,UAAM,IAAI,MAAM,0HAA8D;AAAA,EAChF;AACF;AAKO,SAAS,sBAAsB,KAAwB;AAC5D,kBAAiC,KAAK;AAAA,IACpC,MAAM;AAAA,IACN,aAAa;AAAA,IACb,eAAe;AAAA,IACf,OAAO;AAAA,IACP,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ,CAAC;AACH;",
6
+ "names": []
7
+ }
@@ -0,0 +1,33 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { registerMcpTool } from "../shared";
3
+ const FetchDocSchema = Type.Object({
4
+ doc_id: Type.String({
5
+ description: "\u6587\u6863 ID \u6216 URL\uFF08\u652F\u6301\u81EA\u52A8\u89E3\u6790\uFF09"
6
+ }),
7
+ offset: Type.Optional(
8
+ Type.Integer({
9
+ description: "\u5B57\u7B26\u504F\u79FB\u91CF\uFF08\u53EF\u9009\uFF0C\u9ED8\u8BA40\uFF09\u3002\u7528\u4E8E\u5927\u6587\u6863\u5206\u9875\u83B7\u53D6\u3002",
10
+ minimum: 0
11
+ })
12
+ ),
13
+ limit: Type.Optional(
14
+ Type.Integer({
15
+ description: "\u8FD4\u56DE\u7684\u6700\u5927\u5B57\u7B26\u6570\uFF08\u53EF\u9009\uFF09\u3002\u4EC5\u5728\u7528\u6237\u660E\u786E\u8981\u6C42\u5206\u9875\u65F6\u4F7F\u7528\u3002",
16
+ minimum: 1
17
+ })
18
+ )
19
+ });
20
+ function registerFetchDocTool(api) {
21
+ registerMcpTool(api, {
22
+ name: "feishu_fetch_doc",
23
+ mcpToolName: "fetch-doc",
24
+ toolActionKey: "feishu_fetch_doc.default",
25
+ label: "Feishu MCP: fetch-doc",
26
+ description: "\u83B7\u53D6\u98DE\u4E66\u4E91\u6587\u6863\u5185\u5BB9\uFF0C\u8FD4\u56DE\u6587\u6863\u6807\u9898\u548C Markdown \u683C\u5F0F\u5185\u5BB9\u3002\u652F\u6301\u5206\u9875\u83B7\u53D6\u5927\u6587\u6863\u3002",
27
+ schema: FetchDocSchema
28
+ });
29
+ }
30
+ export {
31
+ registerFetchDocTool
32
+ };
33
+ //# sourceMappingURL=fetch.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/tools/mcp/doc/fetch.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * MCP fetch-doc \u5DE5\u5177\n * \u67E5\u770B\u4E91\u6587\u6863\u5185\u5BB9\uFF08\u8FD4\u56DE\u6807\u9898\u4E0E Markdown\uFF0C\u652F\u6301\u5206\u9875\uFF09\n */\n\nimport type { OpenClawPluginApi } from 'openclaw/plugin-sdk';\nimport { Type, type Static } from '@sinclair/typebox';\nimport { registerMcpTool } from '../shared';\n\n// Schema \u5B9A\u4E49\nconst FetchDocSchema = Type.Object({\n doc_id: Type.String({\n description: '\u6587\u6863 ID \u6216 URL\uFF08\u652F\u6301\u81EA\u52A8\u89E3\u6790\uFF09',\n }),\n offset: Type.Optional(\n Type.Integer({\n description: '\u5B57\u7B26\u504F\u79FB\u91CF\uFF08\u53EF\u9009\uFF0C\u9ED8\u8BA40\uFF09\u3002\u7528\u4E8E\u5927\u6587\u6863\u5206\u9875\u83B7\u53D6\u3002',\n minimum: 0,\n }),\n ),\n limit: Type.Optional(\n Type.Integer({\n description: '\u8FD4\u56DE\u7684\u6700\u5927\u5B57\u7B26\u6570\uFF08\u53EF\u9009\uFF09\u3002\u4EC5\u5728\u7528\u6237\u660E\u786E\u8981\u6C42\u5206\u9875\u65F6\u4F7F\u7528\u3002',\n minimum: 1,\n }),\n ),\n});\n\ntype FetchDocParams = Static<typeof FetchDocSchema>;\n\n/**\n * \u6CE8\u518C fetch-doc \u5DE5\u5177\n */\nexport function registerFetchDocTool(api: OpenClawPluginApi) {\n registerMcpTool<FetchDocParams>(api, {\n name: 'feishu_fetch_doc',\n mcpToolName: 'fetch-doc',\n toolActionKey: 'feishu_fetch_doc.default',\n label: 'Feishu MCP: fetch-doc',\n description: '\u83B7\u53D6\u98DE\u4E66\u4E91\u6587\u6863\u5185\u5BB9\uFF0C\u8FD4\u56DE\u6587\u6863\u6807\u9898\u548C Markdown \u683C\u5F0F\u5185\u5BB9\u3002\u652F\u6301\u5206\u9875\u83B7\u53D6\u5927\u6587\u6863\u3002',\n schema: FetchDocSchema,\n });\n}\n"],
5
+ "mappings": "AASA,SAAS,YAAyB;AAClC,SAAS,uBAAuB;AAGhC,MAAM,iBAAiB,KAAK,OAAO;AAAA,EACjC,QAAQ,KAAK,OAAO;AAAA,IAClB,aAAa;AAAA,EACf,CAAC;AAAA,EACD,QAAQ,KAAK;AAAA,IACX,KAAK,QAAQ;AAAA,MACX,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA,EACA,OAAO,KAAK;AAAA,IACV,KAAK,QAAQ;AAAA,MACX,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF,CAAC;AAOM,SAAS,qBAAqB,KAAwB;AAC3D,kBAAgC,KAAK;AAAA,IACnC,MAAM;AAAA,IACN,aAAa;AAAA,IACb,eAAe;AAAA,IACf,OAAO;AAAA,IACP,aAAa;AAAA,IACb,QAAQ;AAAA,EACV,CAAC;AACH;",
6
+ "names": []
7
+ }
@@ -0,0 +1,32 @@
1
+ import { getEnabledLarkAccounts } from "../../../core/accounts";
2
+ import { resolveAnyEnabledToolsConfig } from "../../../core/tools-config";
3
+ import { extractMcpUrlFromConfig, setMcpEndpointOverride } from "../shared";
4
+ import { registerFetchDocTool } from "./fetch";
5
+ import { registerCreateDocTool } from "./create";
6
+ import { registerUpdateDocTool } from "./update";
7
+ function registerFeishuMcpDocTools(api) {
8
+ if (!api.config) {
9
+ api.logger.debug?.("feishu_doc: No config available, skipping");
10
+ return;
11
+ }
12
+ const accounts = getEnabledLarkAccounts(api.config);
13
+ if (accounts.length === 0) {
14
+ api.logger.debug?.("feishu_doc: No Feishu accounts configured, skipping");
15
+ return;
16
+ }
17
+ const toolsCfg = resolveAnyEnabledToolsConfig(accounts);
18
+ if (!toolsCfg.doc) {
19
+ api.logger.debug?.("feishu_doc: doc tool disabled in all accounts");
20
+ return;
21
+ }
22
+ const mcpEndpoint = extractMcpUrlFromConfig(api.config);
23
+ setMcpEndpointOverride(mcpEndpoint);
24
+ registerFetchDocTool(api);
25
+ registerCreateDocTool(api);
26
+ registerUpdateDocTool(api);
27
+ api.logger.info?.("feishu_doc: Registered feishu_fetch_doc, feishu_create_doc, feishu_update_doc");
28
+ }
29
+ export {
30
+ registerFeishuMcpDocTools
31
+ };
32
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/tools/mcp/doc/index.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * MCP Doc \u5DE5\u5177\u96C6\n * \u7EDF\u4E00\u5BFC\u51FA\u6240\u6709 doc \u76F8\u5173\u5DE5\u5177\u7684\u6CE8\u518C\u51FD\u6570\n */\n\nimport type { OpenClawPluginApi } from 'openclaw/plugin-sdk';\nimport { getEnabledLarkAccounts } from '../../../core/accounts';\nimport { resolveAnyEnabledToolsConfig } from '../../../core/tools-config';\nimport { extractMcpUrlFromConfig, setMcpEndpointOverride } from '../shared';\nimport { registerFetchDocTool } from './fetch';\nimport { registerCreateDocTool } from './create';\nimport { registerUpdateDocTool } from './update';\n\n/**\n * \u6CE8\u518C MCP Doc \u5DE5\u5177\uFF08\u4EC5\u4FDD\u7559 create/fetch/update\uFF0Csearch/list \u5DF2\u7531 OAPI \u66FF\u4EE3\uFF09\n */\nexport function registerFeishuMcpDocTools(api: OpenClawPluginApi) {\n if (!api.config) {\n api.logger.debug?.('feishu_doc: No config available, skipping');\n return;\n }\n\n const accounts = getEnabledLarkAccounts(api.config);\n if (accounts.length === 0) {\n api.logger.debug?.('feishu_doc: No Feishu accounts configured, skipping');\n return;\n }\n\n // \u6CBF\u7528\u73B0\u6709 doc \u5F00\u5173\uFF1A\u82E5\u6240\u6709\u8D26\u6237\u90FD\u5173\u95ED doc \u5DE5\u5177\uFF0C\u5219 MCP doc \u5DE5\u5177\u4E5F\u4E0D\u6CE8\u518C\n const toolsCfg = resolveAnyEnabledToolsConfig(accounts);\n if (!toolsCfg.doc) {\n api.logger.debug?.('feishu_doc: doc tool disabled in all accounts');\n return;\n }\n\n // \u5C06 mcp_url\uFF08\u82E5\u914D\u7F6E\uFF09\u7F13\u5B58\u4E3A\u5168\u5C40 override\uFF0C\u4F9B\u540E\u7EED\u5DE5\u5177\u8C03\u7528\u4F7F\u7528\n const mcpEndpoint = extractMcpUrlFromConfig(api.config);\n setMcpEndpointOverride(mcpEndpoint);\n\n // \u6CE8\u518C\u5DE5\u5177\uFF08search/list \u5DF2\u7531 OAPI \u7248\u672C\u66FF\u4EE3\uFF0C\u4E0D\u518D\u6CE8\u518C\uFF09\n registerFetchDocTool(api);\n registerCreateDocTool(api);\n registerUpdateDocTool(api);\n\n api.logger.info?.('feishu_doc: Registered feishu_fetch_doc, feishu_create_doc, feishu_update_doc');\n}\n"],
5
+ "mappings": "AASA,SAAS,8BAA8B;AACvC,SAAS,oCAAoC;AAC7C,SAAS,yBAAyB,8BAA8B;AAChE,SAAS,4BAA4B;AACrC,SAAS,6BAA6B;AACtC,SAAS,6BAA6B;AAK/B,SAAS,0BAA0B,KAAwB;AAChE,MAAI,CAAC,IAAI,QAAQ;AACf,QAAI,OAAO,QAAQ,2CAA2C;AAC9D;AAAA,EACF;AAEA,QAAM,WAAW,uBAAuB,IAAI,MAAM;AAClD,MAAI,SAAS,WAAW,GAAG;AACzB,QAAI,OAAO,QAAQ,qDAAqD;AACxE;AAAA,EACF;AAGA,QAAM,WAAW,6BAA6B,QAAQ;AACtD,MAAI,CAAC,SAAS,KAAK;AACjB,QAAI,OAAO,QAAQ,+CAA+C;AAClE;AAAA,EACF;AAGA,QAAM,cAAc,wBAAwB,IAAI,MAAM;AACtD,yBAAuB,WAAW;AAGlC,uBAAqB,GAAG;AACxB,wBAAsB,GAAG;AACzB,wBAAsB,GAAG;AAEzB,MAAI,OAAO,OAAO,+EAA+E;AACnG;",
6
+ "names": []
7
+ }
@@ -0,0 +1,61 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { registerMcpTool } from "../shared";
3
+ const UpdateDocSchema = Type.Object({
4
+ doc_id: Type.Optional(Type.String({ description: "\u6587\u6863 ID \u6216 URL" })),
5
+ markdown: Type.Optional(Type.String({ description: "Markdown \u5185\u5BB9" })),
6
+ mode: Type.Union(
7
+ [
8
+ Type.Literal("overwrite"),
9
+ Type.Literal("append"),
10
+ Type.Literal("replace_range"),
11
+ Type.Literal("replace_all"),
12
+ Type.Literal("insert_before"),
13
+ Type.Literal("insert_after"),
14
+ Type.Literal("delete_range")
15
+ ],
16
+ { description: "\u66F4\u65B0\u6A21\u5F0F\uFF08\u5FC5\u586B\uFF09" }
17
+ ),
18
+ selection_with_ellipsis: Type.Optional(
19
+ Type.String({ description: "\u5B9A\u4F4D\u8868\u8FBE\u5F0F\uFF1A\u5F00\u5934\u5185\u5BB9...\u7ED3\u5C3E\u5185\u5BB9\uFF08\u4E0E selection_by_title \u4E8C\u9009\u4E00\uFF09" })
20
+ ),
21
+ selection_by_title: Type.Optional(
22
+ Type.String({ description: "\u6807\u9898\u5B9A\u4F4D\uFF1A\u4F8B\u5982 ## \u7AE0\u8282\u6807\u9898\uFF08\u4E0E selection_with_ellipsis \u4E8C\u9009\u4E00\uFF09" })
23
+ ),
24
+ new_title: Type.Optional(Type.String({ description: "\u65B0\u7684\u6587\u6863\u6807\u9898\uFF08\u53EF\u9009\uFF09" })),
25
+ task_id: Type.Optional(Type.String({ description: "\u5F02\u6B65\u4EFB\u52A1 ID\uFF0C\u7528\u4E8E\u67E5\u8BE2\u4EFB\u52A1\u72B6\u6001" }))
26
+ });
27
+ function validateUpdateDocParams(p) {
28
+ if (p.task_id) return;
29
+ if (!p.doc_id) {
30
+ throw new Error("update-doc\uFF1A\u672A\u63D0\u4F9B task_id \u65F6\u5FC5\u987B\u63D0\u4F9B doc_id");
31
+ }
32
+ const needSelection = p.mode === "replace_range" || p.mode === "insert_before" || p.mode === "insert_after" || p.mode === "delete_range";
33
+ if (needSelection) {
34
+ const hasEllipsis = Boolean(p.selection_with_ellipsis);
35
+ const hasTitle = Boolean(p.selection_by_title);
36
+ if (hasEllipsis && hasTitle || !hasEllipsis && !hasTitle) {
37
+ throw new Error(
38
+ "update-doc\uFF1Amode \u4E3A replace_range/insert_before/insert_after/delete_range \u65F6\uFF0Cselection_with_ellipsis \u4E0E selection_by_title \u5FC5\u987B\u4E8C\u9009\u4E00"
39
+ );
40
+ }
41
+ }
42
+ const needMarkdown = p.mode !== "delete_range";
43
+ if (needMarkdown && !p.markdown) {
44
+ throw new Error(`update-doc\uFF1Amode=${p.mode} \u65F6\u5FC5\u987B\u63D0\u4F9B markdown`);
45
+ }
46
+ }
47
+ function registerUpdateDocTool(api) {
48
+ registerMcpTool(api, {
49
+ name: "feishu_update_doc",
50
+ mcpToolName: "update-doc",
51
+ toolActionKey: "feishu_update_doc.default",
52
+ label: "Feishu MCP: update-doc",
53
+ description: "\u66F4\u65B0\u4E91\u6587\u6863\uFF08overwrite/append/replace_range/replace_all/insert_before/insert_after/delete_range\uFF0C\u652F\u6301\u5F02\u6B65 task_id \u67E5\u8BE2\uFF09",
54
+ schema: UpdateDocSchema,
55
+ validate: validateUpdateDocParams
56
+ });
57
+ }
58
+ export {
59
+ registerUpdateDocTool
60
+ };
61
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/tools/mcp/doc/update.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * MCP update-doc \u5DE5\u5177\n * \u66F4\u65B0\u4E91\u6587\u6863\uFF08overwrite/append/replace_range/replace_all/insert_before/insert_after/delete_range\uFF0C\u652F\u6301\u5F02\u6B65 task_id \u67E5\u8BE2\uFF09\n */\n\nimport type { OpenClawPluginApi } from 'openclaw/plugin-sdk';\nimport { Type, type Static } from '@sinclair/typebox';\nimport { registerMcpTool } from '../shared';\n\n// Schema \u5B9A\u4E49\nconst UpdateDocSchema = Type.Object({\n doc_id: Type.Optional(Type.String({ description: '\u6587\u6863 ID \u6216 URL' })),\n markdown: Type.Optional(Type.String({ description: 'Markdown \u5185\u5BB9' })),\n mode: Type.Union(\n [\n Type.Literal('overwrite'),\n Type.Literal('append'),\n Type.Literal('replace_range'),\n Type.Literal('replace_all'),\n Type.Literal('insert_before'),\n Type.Literal('insert_after'),\n Type.Literal('delete_range'),\n ],\n { description: '\u66F4\u65B0\u6A21\u5F0F\uFF08\u5FC5\u586B\uFF09' },\n ),\n selection_with_ellipsis: Type.Optional(\n Type.String({ description: '\u5B9A\u4F4D\u8868\u8FBE\u5F0F\uFF1A\u5F00\u5934\u5185\u5BB9...\u7ED3\u5C3E\u5185\u5BB9\uFF08\u4E0E selection_by_title \u4E8C\u9009\u4E00\uFF09' }),\n ),\n selection_by_title: Type.Optional(\n Type.String({ description: '\u6807\u9898\u5B9A\u4F4D\uFF1A\u4F8B\u5982 ## \u7AE0\u8282\u6807\u9898\uFF08\u4E0E selection_with_ellipsis \u4E8C\u9009\u4E00\uFF09' }),\n ),\n new_title: Type.Optional(Type.String({ description: '\u65B0\u7684\u6587\u6863\u6807\u9898\uFF08\u53EF\u9009\uFF09' })),\n task_id: Type.Optional(Type.String({ description: '\u5F02\u6B65\u4EFB\u52A1 ID\uFF0C\u7528\u4E8E\u67E5\u8BE2\u4EFB\u52A1\u72B6\u6001' })),\n});\n\ntype UpdateDocParams = Static<typeof UpdateDocSchema>;\n\n// \u53C2\u6570\u9A8C\u8BC1\nfunction validateUpdateDocParams(p: UpdateDocParams): void {\n if (p.task_id) return;\n if (!p.doc_id) {\n throw new Error('update-doc\uFF1A\u672A\u63D0\u4F9B task_id \u65F6\u5FC5\u987B\u63D0\u4F9B doc_id');\n }\n const needSelection =\n p.mode === 'replace_range' || p.mode === 'insert_before' || p.mode === 'insert_after' || p.mode === 'delete_range';\n\n if (needSelection) {\n const hasEllipsis = Boolean(p.selection_with_ellipsis);\n const hasTitle = Boolean(p.selection_by_title);\n if ((hasEllipsis && hasTitle) || (!hasEllipsis && !hasTitle)) {\n throw new Error(\n 'update-doc\uFF1Amode \u4E3A replace_range/insert_before/insert_after/delete_range \u65F6\uFF0Cselection_with_ellipsis \u4E0E selection_by_title \u5FC5\u987B\u4E8C\u9009\u4E00',\n );\n }\n }\n\n const needMarkdown = p.mode !== 'delete_range';\n if (needMarkdown && !p.markdown) {\n throw new Error(`update-doc\uFF1Amode=${p.mode} \u65F6\u5FC5\u987B\u63D0\u4F9B markdown`);\n }\n}\n\n/**\n * \u6CE8\u518C update-doc \u5DE5\u5177\n */\nexport function registerUpdateDocTool(api: OpenClawPluginApi) {\n registerMcpTool<UpdateDocParams>(api, {\n name: 'feishu_update_doc',\n mcpToolName: 'update-doc',\n toolActionKey: 'feishu_update_doc.default',\n label: 'Feishu MCP: update-doc',\n description:\n '\u66F4\u65B0\u4E91\u6587\u6863\uFF08overwrite/append/replace_range/replace_all/insert_before/insert_after/delete_range\uFF0C\u652F\u6301\u5F02\u6B65 task_id \u67E5\u8BE2\uFF09',\n schema: UpdateDocSchema,\n validate: validateUpdateDocParams,\n });\n}\n"],
5
+ "mappings": "AASA,SAAS,YAAyB;AAClC,SAAS,uBAAuB;AAGhC,MAAM,kBAAkB,KAAK,OAAO;AAAA,EAClC,QAAQ,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,6BAAc,CAAC,CAAC;AAAA,EACjE,UAAU,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,wBAAc,CAAC,CAAC;AAAA,EACnE,MAAM,KAAK;AAAA,IACT;AAAA,MACE,KAAK,QAAQ,WAAW;AAAA,MACxB,KAAK,QAAQ,QAAQ;AAAA,MACrB,KAAK,QAAQ,eAAe;AAAA,MAC5B,KAAK,QAAQ,aAAa;AAAA,MAC1B,KAAK,QAAQ,eAAe;AAAA,MAC5B,KAAK,QAAQ,cAAc;AAAA,MAC3B,KAAK,QAAQ,cAAc;AAAA,IAC7B;AAAA,IACA,EAAE,aAAa,mDAAW;AAAA,EAC5B;AAAA,EACA,yBAAyB,KAAK;AAAA,IAC5B,KAAK,OAAO,EAAE,aAAa,kJAA8C,CAAC;AAAA,EAC5E;AAAA,EACA,oBAAoB,KAAK;AAAA,IACvB,KAAK,OAAO,EAAE,aAAa,sIAAiD,CAAC;AAAA,EAC/E;AAAA,EACA,WAAW,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,+DAAa,CAAC,CAAC;AAAA,EACnE,SAAS,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,oFAAmB,CAAC,CAAC;AACzE,CAAC;AAKD,SAAS,wBAAwB,GAA0B;AACzD,MAAI,EAAE,QAAS;AACf,MAAI,CAAC,EAAE,QAAQ;AACb,UAAM,IAAI,MAAM,kFAAqC;AAAA,EACvD;AACA,QAAM,gBACJ,EAAE,SAAS,mBAAmB,EAAE,SAAS,mBAAmB,EAAE,SAAS,kBAAkB,EAAE,SAAS;AAEtG,MAAI,eAAe;AACjB,UAAM,cAAc,QAAQ,EAAE,uBAAuB;AACrD,UAAM,WAAW,QAAQ,EAAE,kBAAkB;AAC7C,QAAK,eAAe,YAAc,CAAC,eAAe,CAAC,UAAW;AAC5D,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,eAAe,EAAE,SAAS;AAChC,MAAI,gBAAgB,CAAC,EAAE,UAAU;AAC/B,UAAM,IAAI,MAAM,wBAAmB,EAAE,IAAI,0CAAiB;AAAA,EAC5D;AACF;AAKO,SAAS,sBAAsB,KAAwB;AAC5D,kBAAiC,KAAK;AAAA,IACpC,MAAM;AAAA,IACN,aAAa;AAAA,IACb,eAAe;AAAA,IACf,OAAO;AAAA,IACP,aACE;AAAA,IACF,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ,CAAC;AACH;",
6
+ "names": []
7
+ }
@@ -0,0 +1,25 @@
1
+ const DEFAULT_PROJECT_MCP_ENDPOINT = "https://project.feishu.cn/mcp_server/v1";
2
+ function getProjectMcpEndpoint(cfg) {
3
+ const envEndpoint = process.env.FEISHU_PROJECT_MCP_ENDPOINT?.trim();
4
+ if (envEndpoint) return envEndpoint;
5
+ if (cfg && typeof cfg === "object") {
6
+ const channels = cfg.channels;
7
+ if (channels && typeof channels === "object") {
8
+ const feishu = channels.feishu;
9
+ if (feishu && typeof feishu === "object") {
10
+ const project = feishu.project;
11
+ if (project && typeof project === "object") {
12
+ const endpoint = project.mcpEndpoint;
13
+ if (typeof endpoint === "string" && endpoint.trim()) {
14
+ return endpoint.trim();
15
+ }
16
+ }
17
+ }
18
+ }
19
+ }
20
+ return DEFAULT_PROJECT_MCP_ENDPOINT;
21
+ }
22
+ export {
23
+ getProjectMcpEndpoint
24
+ };
25
+ //# sourceMappingURL=endpoint.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/tools/mcp/project/endpoint.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * \u98DE\u4E66\u9879\u76EE MCP Server \u7AEF\u70B9\u914D\u7F6E\n */\n\nconst DEFAULT_PROJECT_MCP_ENDPOINT = 'https://project.feishu.cn/mcp_server/v1';\n\n/**\n * \u83B7\u53D6\u98DE\u4E66\u9879\u76EE MCP \u7AEF\u70B9\u3002\n *\n * \u4F18\u5148\u7EA7\uFF1A\n * 1. \u73AF\u5883\u53D8\u91CF FEISHU_PROJECT_MCP_ENDPOINT\n * 2. \u914D\u7F6E channels.feishu.project.mcpEndpoint\n * 3. \u9ED8\u8BA4\u503C\n */\nexport function getProjectMcpEndpoint(cfg?: unknown): string {\n const envEndpoint = process.env.FEISHU_PROJECT_MCP_ENDPOINT?.trim();\n if (envEndpoint) return envEndpoint;\n\n if (cfg && typeof cfg === 'object') {\n const channels = (cfg as Record<string, unknown>).channels;\n if (channels && typeof channels === 'object') {\n const feishu = (channels as Record<string, unknown>).feishu;\n if (feishu && typeof feishu === 'object') {\n const project = (feishu as Record<string, unknown>).project;\n if (project && typeof project === 'object') {\n const endpoint = (project as Record<string, unknown>).mcpEndpoint;\n if (typeof endpoint === 'string' && endpoint.trim()) {\n return endpoint.trim();\n }\n }\n }\n }\n }\n\n return DEFAULT_PROJECT_MCP_ENDPOINT;\n}\n"],
5
+ "mappings": "AAOA,MAAM,+BAA+B;AAU9B,SAAS,sBAAsB,KAAuB;AAC3D,QAAM,cAAc,QAAQ,IAAI,6BAA6B,KAAK;AAClE,MAAI,YAAa,QAAO;AAExB,MAAI,OAAO,OAAO,QAAQ,UAAU;AAClC,UAAM,WAAY,IAAgC;AAClD,QAAI,YAAY,OAAO,aAAa,UAAU;AAC5C,YAAM,SAAU,SAAqC;AACrD,UAAI,UAAU,OAAO,WAAW,UAAU;AACxC,cAAM,UAAW,OAAmC;AACpD,YAAI,WAAW,OAAO,YAAY,UAAU;AAC1C,gBAAM,WAAY,QAAoC;AACtD,cAAI,OAAO,aAAa,YAAY,SAAS,KAAK,GAAG;AACnD,mBAAO,SAAS,KAAK;AAAA,UACvB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;",
6
+ "names": []
7
+ }