@larksuite/openclaw-lark 2025.7.15-beta.0

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 (426) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +76 -0
  3. package/bin/openclaw-lark.js +39 -0
  4. package/index.d.ts +36 -0
  5. package/index.js +188 -0
  6. package/openclaw.plugin.json +64 -0
  7. package/package.json +63 -0
  8. package/secret-contract-api.d.ts +15 -0
  9. package/secret-contract-api.js +78 -0
  10. package/skills/feishu-bitable/SKILL.md +248 -0
  11. package/skills/feishu-bitable/references/examples.md +813 -0
  12. package/skills/feishu-bitable/references/field-properties.md +763 -0
  13. package/skills/feishu-bitable/references/record-values.md +911 -0
  14. package/skills/feishu-calendar/SKILL.md +242 -0
  15. package/skills/feishu-channel-rules/SKILL.md +18 -0
  16. package/skills/feishu-channel-rules/references/markdown-syntax.md +138 -0
  17. package/skills/feishu-create-doc/SKILL.md +719 -0
  18. package/skills/feishu-fetch-doc/SKILL.md +93 -0
  19. package/skills/feishu-im-read/SKILL.md +163 -0
  20. package/skills/feishu-task/SKILL.md +340 -0
  21. package/skills/feishu-troubleshoot/SKILL.md +70 -0
  22. package/skills/feishu-update-doc/SKILL.md +285 -0
  23. package/src/card/builder.d.ts +152 -0
  24. package/src/card/builder.js +794 -0
  25. package/src/card/card-error.d.ts +91 -0
  26. package/src/card/card-error.js +206 -0
  27. package/src/card/cardkit.d.ts +90 -0
  28. package/src/card/cardkit.js +203 -0
  29. package/src/card/flush-controller.d.ts +45 -0
  30. package/src/card/flush-controller.js +138 -0
  31. package/src/card/image-resolver.d.ts +45 -0
  32. package/src/card/image-resolver.js +116 -0
  33. package/src/card/markdown-style.d.ts +16 -0
  34. package/src/card/markdown-style.js +106 -0
  35. package/src/card/reasoning-utils.d.ts +14 -0
  36. package/src/card/reasoning-utils.js +64 -0
  37. package/src/card/reply-dispatcher-types.d.ts +132 -0
  38. package/src/card/reply-dispatcher-types.js +61 -0
  39. package/src/card/reply-dispatcher.d.ts +15 -0
  40. package/src/card/reply-dispatcher.js +447 -0
  41. package/src/card/reply-mode.d.ts +41 -0
  42. package/src/card/reply-mode.js +70 -0
  43. package/src/card/streaming-card-controller.d.ts +118 -0
  44. package/src/card/streaming-card-controller.js +1045 -0
  45. package/src/card/tool-use-config.d.ts +26 -0
  46. package/src/card/tool-use-config.js +76 -0
  47. package/src/card/tool-use-display.d.ts +37 -0
  48. package/src/card/tool-use-display.js +476 -0
  49. package/src/card/tool-use-trace-store.d.ts +51 -0
  50. package/src/card/tool-use-trace-store.js +271 -0
  51. package/src/card/unavailable-guard.d.ts +35 -0
  52. package/src/card/unavailable-guard.js +87 -0
  53. package/src/channel/abort-detect.d.ts +47 -0
  54. package/src/channel/abort-detect.js +219 -0
  55. package/src/channel/chat-queue.d.ts +41 -0
  56. package/src/channel/chat-queue.js +68 -0
  57. package/src/channel/config-adapter.d.ts +23 -0
  58. package/src/channel/config-adapter.js +107 -0
  59. package/src/channel/directory.d.ts +57 -0
  60. package/src/channel/directory.js +197 -0
  61. package/src/channel/event-handlers.d.ts +17 -0
  62. package/src/channel/event-handlers.js +380 -0
  63. package/src/channel/interactive-dispatch.d.ts +59 -0
  64. package/src/channel/interactive-dispatch.js +195 -0
  65. package/src/channel/monitor.d.ts +17 -0
  66. package/src/channel/monitor.js +140 -0
  67. package/src/channel/onboarding-config.d.ts +18 -0
  68. package/src/channel/onboarding-config.js +96 -0
  69. package/src/channel/onboarding-migrate.d.ts +25 -0
  70. package/src/channel/onboarding-migrate.js +70 -0
  71. package/src/channel/onboarding.d.ts +12 -0
  72. package/src/channel/onboarding.js +300 -0
  73. package/src/channel/plugin.d.ts +13 -0
  74. package/src/channel/plugin.js +310 -0
  75. package/src/channel/probe.d.ts +14 -0
  76. package/src/channel/probe.js +24 -0
  77. package/src/channel/types.d.ts +37 -0
  78. package/src/channel/types.js +8 -0
  79. package/src/commands/auth.d.ts +21 -0
  80. package/src/commands/auth.js +165 -0
  81. package/src/commands/diagnose.d.ts +69 -0
  82. package/src/commands/diagnose.js +848 -0
  83. package/src/commands/doctor.d.ts +27 -0
  84. package/src/commands/doctor.js +588 -0
  85. package/src/commands/index.d.ts +25 -0
  86. package/src/commands/index.js +219 -0
  87. package/src/commands/locale.d.ts +7 -0
  88. package/src/commands/locale.js +8 -0
  89. package/src/core/accounts.d.ts +51 -0
  90. package/src/core/accounts.js +219 -0
  91. package/src/core/agent-config.d.ts +100 -0
  92. package/src/core/agent-config.js +148 -0
  93. package/src/core/api-error.d.ts +48 -0
  94. package/src/core/api-error.js +117 -0
  95. package/src/core/app-owner-fallback.d.ts +22 -0
  96. package/src/core/app-owner-fallback.js +39 -0
  97. package/src/core/app-scope-checker.d.ts +87 -0
  98. package/src/core/app-scope-checker.js +198 -0
  99. package/src/core/auth-errors.d.ts +144 -0
  100. package/src/core/auth-errors.js +160 -0
  101. package/src/core/card-action-operator.d.ts +33 -0
  102. package/src/core/card-action-operator.js +30 -0
  103. package/src/core/chat-info-cache.d.ts +67 -0
  104. package/src/core/chat-info-cache.js +165 -0
  105. package/src/core/comment-target.d.ts +65 -0
  106. package/src/core/comment-target.js +100 -0
  107. package/src/core/config-schema.d.ts +490 -0
  108. package/src/core/config-schema.js +223 -0
  109. package/src/core/device-flow.d.ts +77 -0
  110. package/src/core/device-flow.js +217 -0
  111. package/src/core/domains.d.ts +18 -0
  112. package/src/core/domains.js +34 -0
  113. package/src/core/feishu-fetch.d.ts +18 -0
  114. package/src/core/feishu-fetch.js +28 -0
  115. package/src/core/footer-config.d.ts +24 -0
  116. package/src/core/footer-config.js +51 -0
  117. package/src/core/lark-client.d.ts +125 -0
  118. package/src/core/lark-client.js +468 -0
  119. package/src/core/lark-logger.d.ts +23 -0
  120. package/src/core/lark-logger.js +160 -0
  121. package/src/core/lark-ticket.d.ts +29 -0
  122. package/src/core/lark-ticket.js +40 -0
  123. package/src/core/message-unavailable.d.ts +53 -0
  124. package/src/core/message-unavailable.js +142 -0
  125. package/src/core/owner-policy.d.ts +32 -0
  126. package/src/core/owner-policy.js +55 -0
  127. package/src/core/permission-url.d.ts +22 -0
  128. package/src/core/permission-url.js +76 -0
  129. package/src/core/raw-request.d.ts +27 -0
  130. package/src/core/raw-request.js +90 -0
  131. package/src/core/runtime-store.d.ts +13 -0
  132. package/src/core/runtime-store.js +29 -0
  133. package/src/core/scope-manager.d.ts +168 -0
  134. package/src/core/scope-manager.js +224 -0
  135. package/src/core/sdk-compat.d.ts +20 -0
  136. package/src/core/sdk-compat.js +28 -0
  137. package/src/core/security-check.d.ts +72 -0
  138. package/src/core/security-check.js +184 -0
  139. package/src/core/shutdown-hooks.d.ts +22 -0
  140. package/src/core/shutdown-hooks.js +61 -0
  141. package/src/core/synthetic-target.d.ts +33 -0
  142. package/src/core/synthetic-target.js +40 -0
  143. package/src/core/targets.d.ts +60 -0
  144. package/src/core/targets.js +173 -0
  145. package/src/core/token-store.d.ts +54 -0
  146. package/src/core/token-store.js +326 -0
  147. package/src/core/tool-client.d.ts +176 -0
  148. package/src/core/tool-client.js +426 -0
  149. package/src/core/tool-scopes.d.ts +156 -0
  150. package/src/core/tool-scopes.js +344 -0
  151. package/src/core/tools-config.d.ts +55 -0
  152. package/src/core/tools-config.js +143 -0
  153. package/src/core/types.d.ts +91 -0
  154. package/src/core/types.js +12 -0
  155. package/src/core/uat-client.d.ts +46 -0
  156. package/src/core/uat-client.js +192 -0
  157. package/src/core/version.d.ts +31 -0
  158. package/src/core/version.js +69 -0
  159. package/src/messaging/converters/audio.d.ts +8 -0
  160. package/src/messaging/converters/audio.js +24 -0
  161. package/src/messaging/converters/calendar.d.ts +13 -0
  162. package/src/messaging/converters/calendar.js +56 -0
  163. package/src/messaging/converters/content-converter-helpers.d.ts +30 -0
  164. package/src/messaging/converters/content-converter-helpers.js +82 -0
  165. package/src/messaging/converters/content-converter.d.ts +24 -0
  166. package/src/messaging/converters/content-converter.js +40 -0
  167. package/src/messaging/converters/file.d.ts +8 -0
  168. package/src/messaging/converters/file.js +24 -0
  169. package/src/messaging/converters/folder.d.ts +8 -0
  170. package/src/messaging/converters/folder.js +24 -0
  171. package/src/messaging/converters/hongbao.d.ts +8 -0
  172. package/src/messaging/converters/hongbao.js +20 -0
  173. package/src/messaging/converters/image.d.ts +8 -0
  174. package/src/messaging/converters/image.js +22 -0
  175. package/src/messaging/converters/index.d.ts +8 -0
  176. package/src/messaging/converters/index.js +53 -0
  177. package/src/messaging/converters/interactive/card-converter.d.ts +76 -0
  178. package/src/messaging/converters/interactive/card-converter.js +1177 -0
  179. package/src/messaging/converters/interactive/card-utils.d.ts +9 -0
  180. package/src/messaging/converters/interactive/card-utils.js +47 -0
  181. package/src/messaging/converters/interactive/index.d.ts +8 -0
  182. package/src/messaging/converters/interactive/index.js +25 -0
  183. package/src/messaging/converters/interactive/legacy.d.ts +11 -0
  184. package/src/messaging/converters/interactive/legacy.js +60 -0
  185. package/src/messaging/converters/interactive/types.d.ts +23 -0
  186. package/src/messaging/converters/interactive/types.js +27 -0
  187. package/src/messaging/converters/location.d.ts +8 -0
  188. package/src/messaging/converters/location.js +23 -0
  189. package/src/messaging/converters/merge-forward.d.ts +32 -0
  190. package/src/messaging/converters/merge-forward.js +235 -0
  191. package/src/messaging/converters/post.d.ts +11 -0
  192. package/src/messaging/converters/post.js +235 -0
  193. package/src/messaging/converters/share.d.ts +9 -0
  194. package/src/messaging/converters/share.js +28 -0
  195. package/src/messaging/converters/sticker.d.ts +8 -0
  196. package/src/messaging/converters/sticker.js +22 -0
  197. package/src/messaging/converters/system.d.ts +12 -0
  198. package/src/messaging/converters/system.js +36 -0
  199. package/src/messaging/converters/text.d.ts +8 -0
  200. package/src/messaging/converters/text.js +18 -0
  201. package/src/messaging/converters/todo.d.ts +8 -0
  202. package/src/messaging/converters/todo.js +45 -0
  203. package/src/messaging/converters/types.d.ts +114 -0
  204. package/src/messaging/converters/types.js +8 -0
  205. package/src/messaging/converters/unknown.d.ts +8 -0
  206. package/src/messaging/converters/unknown.js +20 -0
  207. package/src/messaging/converters/utils.d.ts +22 -0
  208. package/src/messaging/converters/utils.js +57 -0
  209. package/src/messaging/converters/video-chat.d.ts +8 -0
  210. package/src/messaging/converters/video-chat.js +31 -0
  211. package/src/messaging/converters/video.d.ts +8 -0
  212. package/src/messaging/converters/video.js +35 -0
  213. package/src/messaging/converters/vote.d.ts +8 -0
  214. package/src/messaging/converters/vote.js +28 -0
  215. package/src/messaging/inbound/bot-content.d.ts +84 -0
  216. package/src/messaging/inbound/bot-content.js +117 -0
  217. package/src/messaging/inbound/bot-loop-guard.d.ts +48 -0
  218. package/src/messaging/inbound/bot-loop-guard.js +89 -0
  219. package/src/messaging/inbound/comment-context.d.ts +82 -0
  220. package/src/messaging/inbound/comment-context.js +353 -0
  221. package/src/messaging/inbound/comment-handler.d.ts +30 -0
  222. package/src/messaging/inbound/comment-handler.js +269 -0
  223. package/src/messaging/inbound/dedup.d.ts +59 -0
  224. package/src/messaging/inbound/dedup.js +121 -0
  225. package/src/messaging/inbound/dispatch-builders.d.ts +104 -0
  226. package/src/messaging/inbound/dispatch-builders.js +241 -0
  227. package/src/messaging/inbound/dispatch-commands.d.ts +22 -0
  228. package/src/messaging/inbound/dispatch-commands.js +131 -0
  229. package/src/messaging/inbound/dispatch-context.d.ts +67 -0
  230. package/src/messaging/inbound/dispatch-context.js +153 -0
  231. package/src/messaging/inbound/dispatch.d.ts +50 -0
  232. package/src/messaging/inbound/dispatch.js +477 -0
  233. package/src/messaging/inbound/enrich.d.ts +102 -0
  234. package/src/messaging/inbound/enrich.js +236 -0
  235. package/src/messaging/inbound/gate-effects.d.ts +23 -0
  236. package/src/messaging/inbound/gate-effects.js +46 -0
  237. package/src/messaging/inbound/gate.d.ts +91 -0
  238. package/src/messaging/inbound/gate.js +342 -0
  239. package/src/messaging/inbound/handler-registry.d.ts +25 -0
  240. package/src/messaging/inbound/handler-registry.js +23 -0
  241. package/src/messaging/inbound/handler.d.ts +37 -0
  242. package/src/messaging/inbound/handler.js +286 -0
  243. package/src/messaging/inbound/media-resolver.d.ts +32 -0
  244. package/src/messaging/inbound/media-resolver.js +91 -0
  245. package/src/messaging/inbound/mention-registry.d.ts +59 -0
  246. package/src/messaging/inbound/mention-registry.js +115 -0
  247. package/src/messaging/inbound/mention.d.ts +48 -0
  248. package/src/messaging/inbound/mention.js +102 -0
  249. package/src/messaging/inbound/parse-io.d.ts +50 -0
  250. package/src/messaging/inbound/parse-io.js +86 -0
  251. package/src/messaging/inbound/parse.d.ts +28 -0
  252. package/src/messaging/inbound/parse.js +128 -0
  253. package/src/messaging/inbound/permission.d.ts +17 -0
  254. package/src/messaging/inbound/permission.js +44 -0
  255. package/src/messaging/inbound/policy.d.ts +95 -0
  256. package/src/messaging/inbound/policy.js +168 -0
  257. package/src/messaging/inbound/reaction-handler.d.ts +62 -0
  258. package/src/messaging/inbound/reaction-handler.js +259 -0
  259. package/src/messaging/inbound/sentinel-store.d.ts +37 -0
  260. package/src/messaging/inbound/sentinel-store.js +98 -0
  261. package/src/messaging/inbound/synthetic-message.d.ts +26 -0
  262. package/src/messaging/inbound/synthetic-message.js +59 -0
  263. package/src/messaging/inbound/user-name-cache-store.d.ts +62 -0
  264. package/src/messaging/inbound/user-name-cache-store.js +236 -0
  265. package/src/messaging/inbound/user-name-cache.d.ts +78 -0
  266. package/src/messaging/inbound/user-name-cache.js +306 -0
  267. package/src/messaging/inbound/vc-meeting-invited-handler.d.ts +20 -0
  268. package/src/messaging/inbound/vc-meeting-invited-handler.js +236 -0
  269. package/src/messaging/inbound/vc-sender.d.ts +41 -0
  270. package/src/messaging/inbound/vc-sender.js +53 -0
  271. package/src/messaging/outbound/actions.d.ts +16 -0
  272. package/src/messaging/outbound/actions.js +329 -0
  273. package/src/messaging/outbound/bot-peer-context.d.ts +42 -0
  274. package/src/messaging/outbound/bot-peer-context.js +40 -0
  275. package/src/messaging/outbound/chat-manage.d.ts +64 -0
  276. package/src/messaging/outbound/chat-manage.js +117 -0
  277. package/src/messaging/outbound/deliver.d.ts +186 -0
  278. package/src/messaging/outbound/deliver.js +410 -0
  279. package/src/messaging/outbound/fetch.d.ts +12 -0
  280. package/src/messaging/outbound/fetch.js +17 -0
  281. package/src/messaging/outbound/forward.d.ts +26 -0
  282. package/src/messaging/outbound/forward.js +51 -0
  283. package/src/messaging/outbound/media-url-utils.d.ts +29 -0
  284. package/src/messaging/outbound/media-url-utils.js +172 -0
  285. package/src/messaging/outbound/media.d.ts +260 -0
  286. package/src/messaging/outbound/media.js +865 -0
  287. package/src/messaging/outbound/normalize-mentions.d.ts +50 -0
  288. package/src/messaging/outbound/normalize-mentions.js +166 -0
  289. package/src/messaging/outbound/outbound-mention.d.ts +41 -0
  290. package/src/messaging/outbound/outbound-mention.js +112 -0
  291. package/src/messaging/outbound/outbound.d.ts +79 -0
  292. package/src/messaging/outbound/outbound.js +195 -0
  293. package/src/messaging/outbound/reactions.d.ts +124 -0
  294. package/src/messaging/outbound/reactions.js +384 -0
  295. package/src/messaging/outbound/send.d.ts +153 -0
  296. package/src/messaging/outbound/send.js +417 -0
  297. package/src/messaging/outbound/typing.d.ts +60 -0
  298. package/src/messaging/outbound/typing.js +139 -0
  299. package/src/messaging/shared/message-lookup.d.ts +54 -0
  300. package/src/messaging/shared/message-lookup.js +120 -0
  301. package/src/messaging/types.d.ts +316 -0
  302. package/src/messaging/types.js +11 -0
  303. package/src/tools/ask-user-question.d.ts +32 -0
  304. package/src/tools/ask-user-question.js +922 -0
  305. package/src/tools/auto-auth.d.ts +57 -0
  306. package/src/tools/auto-auth.js +904 -0
  307. package/src/tools/helpers.d.ts +264 -0
  308. package/src/tools/helpers.js +389 -0
  309. package/src/tools/mcp/doc/create.d.ts +12 -0
  310. package/src/tools/mcp/doc/create.js +47 -0
  311. package/src/tools/mcp/doc/fetch.d.ts +12 -0
  312. package/src/tools/mcp/doc/fetch.js +39 -0
  313. package/src/tools/mcp/doc/index.d.ts +12 -0
  314. package/src/tools/mcp/doc/index.js +50 -0
  315. package/src/tools/mcp/doc/update.d.ts +12 -0
  316. package/src/tools/mcp/doc/update.js +64 -0
  317. package/src/tools/mcp/shared.d.ts +59 -0
  318. package/src/tools/mcp/shared.js +239 -0
  319. package/src/tools/oapi/bitable/app-table-field.d.ts +16 -0
  320. package/src/tools/oapi/bitable/app-table-field.js +225 -0
  321. package/src/tools/oapi/bitable/app-table-record.d.ts +20 -0
  322. package/src/tools/oapi/bitable/app-table-record.js +439 -0
  323. package/src/tools/oapi/bitable/app-table-view.d.ts +16 -0
  324. package/src/tools/oapi/bitable/app-table-view.js +172 -0
  325. package/src/tools/oapi/bitable/app-table.d.ts +17 -0
  326. package/src/tools/oapi/bitable/app-table.js +195 -0
  327. package/src/tools/oapi/bitable/app.d.ts +18 -0
  328. package/src/tools/oapi/bitable/app.js +189 -0
  329. package/src/tools/oapi/bitable/index.d.ts +9 -0
  330. package/src/tools/oapi/bitable/index.js +17 -0
  331. package/src/tools/oapi/calendar/calendar.d.ts +15 -0
  332. package/src/tools/oapi/calendar/calendar.js +125 -0
  333. package/src/tools/oapi/calendar/event-attendee.d.ts +14 -0
  334. package/src/tools/oapi/calendar/event-attendee.js +161 -0
  335. package/src/tools/oapi/calendar/event.d.ts +16 -0
  336. package/src/tools/oapi/calendar/event.js +712 -0
  337. package/src/tools/oapi/calendar/freebusy.d.ts +13 -0
  338. package/src/tools/oapi/calendar/freebusy.js +114 -0
  339. package/src/tools/oapi/calendar/index.d.ts +8 -0
  340. package/src/tools/oapi/calendar/index.js +15 -0
  341. package/src/tools/oapi/chat/chat.d.ts +16 -0
  342. package/src/tools/oapi/chat/chat.js +127 -0
  343. package/src/tools/oapi/chat/index.d.ts +10 -0
  344. package/src/tools/oapi/chat/index.js +23 -0
  345. package/src/tools/oapi/chat/members.d.ts +11 -0
  346. package/src/tools/oapi/chat/members.js +84 -0
  347. package/src/tools/oapi/common/get-user.d.ts +12 -0
  348. package/src/tools/oapi/common/get-user.js +109 -0
  349. package/src/tools/oapi/common/index.d.ts +6 -0
  350. package/src/tools/oapi/common/index.js +11 -0
  351. package/src/tools/oapi/common/search-user.d.ts +11 -0
  352. package/src/tools/oapi/common/search-user.js +76 -0
  353. package/src/tools/oapi/drive/doc-comments.d.ts +15 -0
  354. package/src/tools/oapi/drive/doc-comments.js +351 -0
  355. package/src/tools/oapi/drive/doc-media.d.ts +19 -0
  356. package/src/tools/oapi/drive/doc-media.js +371 -0
  357. package/src/tools/oapi/drive/file.d.ts +19 -0
  358. package/src/tools/oapi/drive/file.js +519 -0
  359. package/src/tools/oapi/drive/index.d.ts +12 -0
  360. package/src/tools/oapi/drive/index.js +45 -0
  361. package/src/tools/oapi/helpers.d.ts +183 -0
  362. package/src/tools/oapi/helpers.js +385 -0
  363. package/src/tools/oapi/im/format-messages.d.ts +50 -0
  364. package/src/tools/oapi/im/format-messages.js +169 -0
  365. package/src/tools/oapi/im/index.d.ts +10 -0
  366. package/src/tools/oapi/im/index.js +25 -0
  367. package/src/tools/oapi/im/message-read.d.ts +13 -0
  368. package/src/tools/oapi/im/message-read.js +419 -0
  369. package/src/tools/oapi/im/message.d.ts +16 -0
  370. package/src/tools/oapi/im/message.js +152 -0
  371. package/src/tools/oapi/im/resource.d.ts +13 -0
  372. package/src/tools/oapi/im/resource.js +186 -0
  373. package/src/tools/oapi/im/time-utils.d.ts +46 -0
  374. package/src/tools/oapi/im/time-utils.js +212 -0
  375. package/src/tools/oapi/im/user-name-uat.d.ts +26 -0
  376. package/src/tools/oapi/im/user-name-uat.js +143 -0
  377. package/src/tools/oapi/index.d.ts +11 -0
  378. package/src/tools/oapi/index.js +64 -0
  379. package/src/tools/oapi/sdk-types.d.ts +96 -0
  380. package/src/tools/oapi/sdk-types.js +13 -0
  381. package/src/tools/oapi/search/doc-search.d.ts +13 -0
  382. package/src/tools/oapi/search/doc-search.js +194 -0
  383. package/src/tools/oapi/search/index.d.ts +12 -0
  384. package/src/tools/oapi/search/index.js +37 -0
  385. package/src/tools/oapi/sheets/index.d.ts +12 -0
  386. package/src/tools/oapi/sheets/index.js +35 -0
  387. package/src/tools/oapi/sheets/sheet.d.ts +16 -0
  388. package/src/tools/oapi/sheets/sheet.js +688 -0
  389. package/src/tools/oapi/task/attachment.d.ts +18 -0
  390. package/src/tools/oapi/task/attachment.js +107 -0
  391. package/src/tools/oapi/task/comment.d.ts +15 -0
  392. package/src/tools/oapi/task/comment.js +149 -0
  393. package/src/tools/oapi/task/index.d.ts +11 -0
  394. package/src/tools/oapi/task/index.js +21 -0
  395. package/src/tools/oapi/task/section.d.ts +17 -0
  396. package/src/tools/oapi/task/section.js +293 -0
  397. package/src/tools/oapi/task/subtask.d.ts +14 -0
  398. package/src/tools/oapi/task/subtask.js +171 -0
  399. package/src/tools/oapi/task/task.d.ts +19 -0
  400. package/src/tools/oapi/task/task.js +512 -0
  401. package/src/tools/oapi/task/task_agent.d.ts +14 -0
  402. package/src/tools/oapi/task/task_agent.js +108 -0
  403. package/src/tools/oapi/task/tasklist.d.ts +19 -0
  404. package/src/tools/oapi/task/tasklist.js +276 -0
  405. package/src/tools/oapi/wiki/index.d.ts +12 -0
  406. package/src/tools/oapi/wiki/index.js +42 -0
  407. package/src/tools/oapi/wiki/space-node.d.ts +17 -0
  408. package/src/tools/oapi/wiki/space-node.js +233 -0
  409. package/src/tools/oapi/wiki/space.d.ts +15 -0
  410. package/src/tools/oapi/wiki/space.js +133 -0
  411. package/src/tools/oauth-batch-auth.d.ts +11 -0
  412. package/src/tools/oauth-batch-auth.js +150 -0
  413. package/src/tools/oauth-cards.d.ts +39 -0
  414. package/src/tools/oauth-cards.js +324 -0
  415. package/src/tools/oauth.d.ts +47 -0
  416. package/src/tools/oauth.js +592 -0
  417. package/src/tools/onboarding-auth.d.ts +27 -0
  418. package/src/tools/onboarding-auth.js +133 -0
  419. package/src/tools/tat/im/index.d.ts +15 -0
  420. package/src/tools/tat/im/index.js +22 -0
  421. package/src/tools/tat/im/resource.d.ts +15 -0
  422. package/src/tools/tat/im/resource.js +192 -0
  423. package/tsdown.config.d.ts +2 -0
  424. package/tsdown.config.js +25 -0
  425. package/vitest.config.d.ts +2 -0
  426. package/vitest.config.js +12 -0
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * Default values and resolution logic for the Feishu card footer configuration.
7
+ *
8
+ * Each boolean flag controls whether a particular metadata item is displayed
9
+ * in the card footer (e.g. elapsed time, model name).
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.DEFAULT_FOOTER_CONFIG = void 0;
13
+ exports.resolveFooterConfig = resolveFooterConfig;
14
+ // ---------------------------------------------------------------------------
15
+ // Defaults
16
+ // ---------------------------------------------------------------------------
17
+ /**
18
+ * The default footer configuration.
19
+ *
20
+ * By default all metadata items are hidden — neither status text
21
+ * ("已完成" / "出错" / "已停止") nor elapsed time are shown.
22
+ */
23
+ exports.DEFAULT_FOOTER_CONFIG = {
24
+ status: false,
25
+ elapsed: false,
26
+ tokens: false,
27
+ cache: false,
28
+ context: false,
29
+ model: false,
30
+ };
31
+ // ---------------------------------------------------------------------------
32
+ // Resolver
33
+ // ---------------------------------------------------------------------------
34
+ /**
35
+ * Merge a partial footer configuration with `DEFAULT_FOOTER_CONFIG`.
36
+ *
37
+ * Fields present in the input take precedence; anything absent falls back
38
+ * to the default value.
39
+ */
40
+ function resolveFooterConfig(cfg) {
41
+ if (!cfg)
42
+ return { ...exports.DEFAULT_FOOTER_CONFIG };
43
+ return {
44
+ status: cfg.status ?? exports.DEFAULT_FOOTER_CONFIG.status,
45
+ elapsed: cfg.elapsed ?? exports.DEFAULT_FOOTER_CONFIG.elapsed,
46
+ tokens: cfg.tokens ?? exports.DEFAULT_FOOTER_CONFIG.tokens,
47
+ cache: cfg.cache ?? exports.DEFAULT_FOOTER_CONFIG.cache,
48
+ context: cfg.context ?? exports.DEFAULT_FOOTER_CONFIG.context,
49
+ model: cfg.model ?? exports.DEFAULT_FOOTER_CONFIG.model,
50
+ };
51
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * Feishu / Lark SDK client management.
6
+ *
7
+ * Provides `LarkClient` — a unified manager for Lark SDK client instances,
8
+ * WebSocket connections, EventDispatcher lifecycle, and bot identity.
9
+ *
10
+ * Consumers obtain instances via factory methods:
11
+ * - `LarkClient.fromCfg(cfg, accountId)` — resolve account from config
12
+ * - `LarkClient.fromAccount(account)` — from a pre-resolved account
13
+ * - `LarkClient.fromCredentials(credentials)` — ephemeral instance (not cached)
14
+ */
15
+ import * as Lark from '@larksuiteoapi/node-sdk';
16
+ import type { ClawdbotConfig, PluginRuntime } from 'openclaw/plugin-sdk';
17
+ import type { MessageDedup } from '../messaging/inbound/dedup';
18
+ import type { FeishuProbeResult, LarkAccount, LarkBrand } from './types';
19
+ /** Credential set accepted by the ephemeral `fromCredentials` factory. */
20
+ export interface LarkClientCredentials {
21
+ accountId?: string;
22
+ appId?: string;
23
+ appSecret?: string;
24
+ brand?: LarkBrand;
25
+ }
26
+ export declare class LarkClient {
27
+ readonly account: LarkAccount;
28
+ private _sdk;
29
+ private _wsClient;
30
+ private _botOpenId;
31
+ private _botName;
32
+ private _lastProbeResult;
33
+ private _lastProbeAt;
34
+ /** Attached message deduplicator — disposed together with the client. */
35
+ messageDedup: MessageDedup | null;
36
+ /** Persist the runtime instance for later retrieval (activate 阶段调用一次). */
37
+ static setRuntime(runtime: PluginRuntime): void;
38
+ /** Retrieve the stored runtime instance. Throws if not yet initialised. */
39
+ static get runtime(): PluginRuntime;
40
+ private static _globalConfig;
41
+ /** Store the original global config (called during monitor startup). */
42
+ static setGlobalConfig(cfg: ClawdbotConfig): void;
43
+ /** Retrieve the stored global config, or `null` if not yet set. */
44
+ static get globalConfig(): ClawdbotConfig | null;
45
+ private constructor();
46
+ /** Shorthand for `this.account.accountId`. */
47
+ get accountId(): string;
48
+ /** Resolve account from config and return a cached `LarkClient`. */
49
+ static fromCfg(cfg: ClawdbotConfig, accountId?: string): LarkClient;
50
+ /**
51
+ * Get (or create) a cached `LarkClient` for the given account.
52
+ * If the cached instance has stale credentials it is replaced.
53
+ */
54
+ static fromAccount(account: LarkAccount): LarkClient;
55
+ /**
56
+ * Create an ephemeral `LarkClient` from bare credentials.
57
+ * The instance is **not** added to the global cache — suitable for
58
+ * one-off probe / diagnose calls that should not pollute account state.
59
+ */
60
+ static fromCredentials(credentials: LarkClientCredentials): LarkClient;
61
+ /** Look up a cached instance by accountId. */
62
+ static get(accountId: string): LarkClient | null;
63
+ /**
64
+ * Dispose one or all cached instances.
65
+ * With `accountId` — dispose that single instance.
66
+ * Without — dispose every cached instance and clear the cache.
67
+ */
68
+ static clearCache(accountId?: string): Promise<void>;
69
+ /** Lazily-created Lark SDK client. */
70
+ get sdk(): Lark.Client;
71
+ /**
72
+ * Probe bot identity via the `bot/v1/openclaw_bot/ping` API.
73
+ * Results are cached on the instance for subsequent access via
74
+ * `botOpenId` / `botName`.
75
+ */
76
+ probe(opts?: {
77
+ maxAgeMs?: number;
78
+ needBotInfo?: boolean;
79
+ }): Promise<FeishuProbeResult>;
80
+ /** Cached bot open_id (available after `probe()` or `startWS()`). */
81
+ get botOpenId(): string | undefined;
82
+ /** Cached bot name (available after `probe()` or `startWS()`). */
83
+ get botName(): string | undefined;
84
+ /**
85
+ * Start WebSocket event monitoring.
86
+ *
87
+ * Flow: probe bot identity → EventDispatcher → WSClient → start.
88
+ * The returned Promise resolves when `abortSignal` fires.
89
+ */
90
+ startWS(opts: {
91
+ handlers: Record<string, (data: unknown) => Promise<void>>;
92
+ abortSignal?: AbortSignal;
93
+ autoProbe?: boolean;
94
+ }): Promise<void>;
95
+ /** Whether a WebSocket client is currently active. */
96
+ get wsConnected(): boolean;
97
+ /** Disconnect WebSocket but keep instance in cache. */
98
+ disconnect(): void;
99
+ /** Disconnect + remove from cache. */
100
+ dispose(): void;
101
+ /** Assert credentials exist or throw. */
102
+ private requireCredentials;
103
+ /**
104
+ * Start the WSClient and return a promise that resolves when the
105
+ * abort signal fires (or immediately if already aborted).
106
+ */
107
+ private waitForAbort;
108
+ }
109
+ /**
110
+ * Returns the best available config for account resolution.
111
+ *
112
+ * Priority: live config (has `channels.feishu`) > fallback (has
113
+ * `channels.feishu`) > live config (last resort).
114
+ *
115
+ * The `config` object captured in tool-registration closures may be stale
116
+ * after a hot-reload, so we prefer the live config from
117
+ * `LarkClient.runtime.config.loadConfig()`. However, `loadConfig()` may
118
+ * return `{}` when the runtime config snapshot has been cleared (e.g. in
119
+ * isolated cron sessions), so we fall back to the closure-captured config
120
+ * when the live result lacks Feishu credentials.
121
+ *
122
+ * @param fallback - Config to use when the runtime is not yet initialised
123
+ * or when `loadConfig()` returns an incomplete config.
124
+ */
125
+ export declare function getResolvedConfig(fallback: ClawdbotConfig): ClawdbotConfig;
@@ -0,0 +1,468 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * Feishu / Lark SDK client management.
7
+ *
8
+ * Provides `LarkClient` — a unified manager for Lark SDK client instances,
9
+ * WebSocket connections, EventDispatcher lifecycle, and bot identity.
10
+ *
11
+ * Consumers obtain instances via factory methods:
12
+ * - `LarkClient.fromCfg(cfg, accountId)` — resolve account from config
13
+ * - `LarkClient.fromAccount(account)` — from a pre-resolved account
14
+ * - `LarkClient.fromCredentials(credentials)` — ephemeral instance (not cached)
15
+ */
16
+ /* eslint-disable @typescript-eslint/no-explicit-any */
17
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ var desc = Object.getOwnPropertyDescriptor(m, k);
20
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
+ desc = { enumerable: true, get: function() { return m[k]; } };
22
+ }
23
+ Object.defineProperty(o, k2, desc);
24
+ }) : (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ o[k2] = m[k];
27
+ }));
28
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
30
+ }) : function(o, v) {
31
+ o["default"] = v;
32
+ });
33
+ var __importStar = (this && this.__importStar) || (function () {
34
+ var ownKeys = function(o) {
35
+ ownKeys = Object.getOwnPropertyNames || function (o) {
36
+ var ar = [];
37
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
+ return ar;
39
+ };
40
+ return ownKeys(o);
41
+ };
42
+ return function (mod) {
43
+ if (mod && mod.__esModule) return mod;
44
+ var result = {};
45
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
+ __setModuleDefault(result, mod);
47
+ return result;
48
+ };
49
+ })();
50
+ Object.defineProperty(exports, "__esModule", { value: true });
51
+ exports.LarkClient = void 0;
52
+ exports.getResolvedConfig = getResolvedConfig;
53
+ const Lark = __importStar(require("@larksuiteoapi/node-sdk"));
54
+ const user_name_cache_store_1 = require("../messaging/inbound/user-name-cache-store.js");
55
+ const accounts_1 = require("./accounts.js");
56
+ const chat_info_cache_1 = require("./chat-info-cache.js");
57
+ const lark_logger_1 = require("./lark-logger.js");
58
+ const runtime_store_1 = require("./runtime-store.js");
59
+ const version_1 = require("./version.js");
60
+ const log = (0, lark_logger_1.larkLogger)('core/lark-client');
61
+ // ---------------------------------------------------------------------------
62
+ // Inject User-Agent into all Feishu SDK requests
63
+ // ---------------------------------------------------------------------------
64
+ const GLOBAL_LARK_USER_AGENT_KEY = 'LARK_USER_AGENT';
65
+ function installGlobalUserAgent() {
66
+ // node-sdk's built-in interceptor reads global.LARK_USER_AGENT to override User-Agent
67
+ globalThis[GLOBAL_LARK_USER_AGENT_KEY] = (0, version_1.getUserAgent)();
68
+ }
69
+ installGlobalUserAgent();
70
+ // Disable axios auto-proxy to prevent HTTP_PROXY env vars from corrupting request URLs.
71
+ // Proxy routing is managed centrally by OpenClaw core's global-agent.
72
+ Lark.defaultHttpInstance.defaults.proxy = false;
73
+ Lark.defaultHttpInstance.interceptors.request.handlers = [];
74
+ // Inject User-Agent header into all HTTP requests via interceptor
75
+ Lark.defaultHttpInstance.interceptors.request.use((req) => {
76
+ if (req.headers) {
77
+ req.headers['User-Agent'] = (0, version_1.getUserAgent)();
78
+ }
79
+ return req;
80
+ }, undefined, { synchronous: true });
81
+ // ---------------------------------------------------------------------------
82
+ // Brand → SDK domain
83
+ // ---------------------------------------------------------------------------
84
+ const BRAND_TO_DOMAIN = {
85
+ feishu: Lark.Domain.Feishu,
86
+ lark: Lark.Domain.Lark,
87
+ };
88
+ /** Map a `LarkBrand` to the SDK `domain` parameter. */
89
+ function resolveBrand(brand) {
90
+ return BRAND_TO_DOMAIN[brand ?? 'feishu'] ?? brand.replace(/\/+$/, '');
91
+ }
92
+ // ---------------------------------------------------------------------------
93
+ // LarkClient
94
+ // ---------------------------------------------------------------------------
95
+ /** Instance cache keyed by accountId. */
96
+ const cache = new Map();
97
+ /**
98
+ * Compare two SecretRef-shaped objects by their identity fields.
99
+ * Key-order independent, unlike JSON.stringify.
100
+ */
101
+ function secretRefsEqual(a, b) {
102
+ return a.source === b.source && a.provider === b.provider && a.id === b.id;
103
+ }
104
+ /**
105
+ * Compare two credential values that may be strings or SecretRef objects.
106
+ *
107
+ * - Both strings: direct `===`.
108
+ * - Both SecretRef objects: compare `source`, `provider`, `id` explicitly.
109
+ * - Mixed (string vs SecretRef): treat as equal — the platform resolves the
110
+ * SecretRef at startup (producing the cached string) but `loadConfig()`
111
+ * returns the raw object on subsequent calls. Detecting SecretRef identity
112
+ * changes is not useful here because the platform does not re-resolve
113
+ * feishu secrets on reload, so a new SecretRef would be equally unusable.
114
+ */
115
+ function credentialsEqual(a, b) {
116
+ if (a === b)
117
+ return true;
118
+ if (typeof a === 'string' && typeof b === 'string')
119
+ return false;
120
+ if (a && b && typeof a === 'object' && typeof b === 'object') {
121
+ return secretRefsEqual(a, b);
122
+ }
123
+ // Mixed types: keep the cached instance that holds the working string.
124
+ if ((typeof a === 'string' && b && typeof b === 'object') || (typeof b === 'string' && a && typeof a === 'object')) {
125
+ return true;
126
+ }
127
+ return false;
128
+ }
129
+ class LarkClient {
130
+ account;
131
+ _sdk = null;
132
+ _wsClient = null;
133
+ _botOpenId;
134
+ _botName;
135
+ _lastProbeResult = null;
136
+ _lastProbeAt = 0;
137
+ /** Attached message deduplicator — disposed together with the client. */
138
+ messageDedup = null;
139
+ // ---- Plugin runtime (singleton) ------------------------------------------
140
+ /** Persist the runtime instance for later retrieval (activate 阶段调用一次). */
141
+ static setRuntime(runtime) {
142
+ (0, runtime_store_1.setLarkRuntime)(runtime);
143
+ }
144
+ /** Retrieve the stored runtime instance. Throws if not yet initialised. */
145
+ static get runtime() {
146
+ return (0, runtime_store_1.getLarkRuntime)();
147
+ }
148
+ // ---- Global config (singleton) -------------------------------------------
149
+ //
150
+ // Plugin commands receive an account-scoped config (channels.feishu replaced
151
+ // with the merged per-account config, `accounts` map stripped). Commands
152
+ // that need cross-account visibility (e.g. doctor, diagnose) read the
153
+ // original global config from here.
154
+ static _globalConfig = null;
155
+ /** Store the original global config (called during monitor startup). */
156
+ static setGlobalConfig(cfg) {
157
+ LarkClient._globalConfig = cfg;
158
+ }
159
+ /** Retrieve the stored global config, or `null` if not yet set. */
160
+ static get globalConfig() {
161
+ return LarkClient._globalConfig;
162
+ }
163
+ // --------------------------------------------------------------------------
164
+ constructor(account) {
165
+ this.account = account;
166
+ }
167
+ /** Shorthand for `this.account.accountId`. */
168
+ get accountId() {
169
+ return this.account.accountId;
170
+ }
171
+ // ---- Static factory / cache ------------------------------------------------
172
+ /** Resolve account from config and return a cached `LarkClient`. */
173
+ static fromCfg(cfg, accountId) {
174
+ return LarkClient.fromAccount((0, accounts_1.getLarkAccount)(cfg, accountId));
175
+ }
176
+ /**
177
+ * Get (or create) a cached `LarkClient` for the given account.
178
+ * If the cached instance has stale credentials it is replaced.
179
+ */
180
+ static fromAccount(account) {
181
+ const existing = cache.get(account.accountId);
182
+ if (existing &&
183
+ existing.account.appId === account.appId &&
184
+ credentialsEqual(existing.account.appSecret, account.appSecret)) {
185
+ return existing;
186
+ }
187
+ // Credentials changed — tear down the stale instance before replacing it.
188
+ if (existing) {
189
+ log.info(`credentials changed, disposing stale instance`, { accountId: account.accountId });
190
+ existing.dispose();
191
+ }
192
+ const instance = new LarkClient(account);
193
+ cache.set(account.accountId, instance);
194
+ return instance;
195
+ }
196
+ /**
197
+ * Create an ephemeral `LarkClient` from bare credentials.
198
+ * The instance is **not** added to the global cache — suitable for
199
+ * one-off probe / diagnose calls that should not pollute account state.
200
+ */
201
+ static fromCredentials(credentials) {
202
+ const base = {
203
+ accountId: credentials.accountId ?? 'default',
204
+ enabled: true,
205
+ brand: credentials.brand ?? 'feishu',
206
+ config: {},
207
+ };
208
+ const account = credentials.appId && credentials.appSecret
209
+ ? { ...base, configured: true, appId: credentials.appId, appSecret: credentials.appSecret }
210
+ : { ...base, configured: false, appId: credentials.appId, appSecret: credentials.appSecret };
211
+ return new LarkClient(account);
212
+ }
213
+ /** Look up a cached instance by accountId. */
214
+ static get(accountId) {
215
+ return cache.get(accountId) ?? null;
216
+ }
217
+ /**
218
+ * Dispose one or all cached instances.
219
+ * With `accountId` — dispose that single instance.
220
+ * Without — dispose every cached instance and clear the cache.
221
+ */
222
+ static async clearCache(accountId) {
223
+ if (accountId !== undefined) {
224
+ cache.get(accountId)?.dispose();
225
+ (0, user_name_cache_store_1.clearUserNameCache)(accountId);
226
+ (0, chat_info_cache_1.clearChatInfoCache)(accountId);
227
+ }
228
+ else {
229
+ for (const inst of cache.values())
230
+ inst.dispose();
231
+ (0, user_name_cache_store_1.clearUserNameCache)();
232
+ (0, chat_info_cache_1.clearChatInfoCache)();
233
+ }
234
+ }
235
+ // ---- SDK client (lazy) -----------------------------------------------------
236
+ /** Lazily-created Lark SDK client. */
237
+ get sdk() {
238
+ if (!this._sdk) {
239
+ const { appId, appSecret } = this.requireCredentials();
240
+ this._sdk = new Lark.Client({
241
+ appId,
242
+ appSecret,
243
+ appType: Lark.AppType.SelfBuild,
244
+ domain: resolveBrand(this.account.brand),
245
+ });
246
+ }
247
+ return this._sdk;
248
+ }
249
+ // ---- Bot identity ----------------------------------------------------------
250
+ /**
251
+ * Probe bot identity via the `bot/v1/openclaw_bot/ping` API.
252
+ * Results are cached on the instance for subsequent access via
253
+ * `botOpenId` / `botName`.
254
+ */
255
+ async probe(opts) {
256
+ const maxAge = opts?.maxAgeMs ?? 0;
257
+ if (maxAge > 0 && this._lastProbeResult && Date.now() - this._lastProbeAt < maxAge) {
258
+ return this._lastProbeResult;
259
+ }
260
+ if (!this.account.appId || !this.account.appSecret) {
261
+ return { ok: false, error: 'missing credentials (appId, appSecret)' };
262
+ }
263
+ try {
264
+ const needBotInfo = opts?.needBotInfo ?? true;
265
+ const res = await this.sdk.request({
266
+ method: 'POST',
267
+ url: '/open-apis/bot/v1/openclaw_bot/ping',
268
+ data: { needBotInfo },
269
+ });
270
+ if (res.code !== 0) {
271
+ const result = {
272
+ ok: false,
273
+ appId: this.account.appId,
274
+ error: `API error: ${res.msg || `code ${res.code}`}`,
275
+ };
276
+ this._lastProbeResult = result;
277
+ this._lastProbeAt = Date.now();
278
+ return result;
279
+ }
280
+ const botInfo = res.data?.pingBotInfo;
281
+ this._botOpenId = botInfo?.botID;
282
+ this._botName = botInfo?.botName;
283
+ const result = {
284
+ ok: true,
285
+ appId: this.account.appId,
286
+ botName: this._botName,
287
+ botOpenId: this._botOpenId,
288
+ };
289
+ this._lastProbeResult = result;
290
+ this._lastProbeAt = Date.now();
291
+ return result;
292
+ }
293
+ catch (err) {
294
+ const result = {
295
+ ok: false,
296
+ appId: this.account.appId,
297
+ error: err instanceof Error ? err.message : String(err),
298
+ };
299
+ this._lastProbeResult = result;
300
+ this._lastProbeAt = Date.now();
301
+ return result;
302
+ }
303
+ }
304
+ /** Cached bot open_id (available after `probe()` or `startWS()`). */
305
+ get botOpenId() {
306
+ return this._botOpenId;
307
+ }
308
+ /** Cached bot name (available after `probe()` or `startWS()`). */
309
+ get botName() {
310
+ return this._botName;
311
+ }
312
+ // ---- WebSocket lifecycle ---------------------------------------------------
313
+ /**
314
+ * Start WebSocket event monitoring.
315
+ *
316
+ * Flow: probe bot identity → EventDispatcher → WSClient → start.
317
+ * The returned Promise resolves when `abortSignal` fires.
318
+ */
319
+ async startWS(opts) {
320
+ const { handlers, abortSignal, autoProbe = true } = opts;
321
+ if (autoProbe)
322
+ await this.probe();
323
+ const dispatcher = new Lark.EventDispatcher({
324
+ encryptKey: this.account.encryptKey ?? '',
325
+ verificationToken: this.account.verificationToken ?? '',
326
+ });
327
+ dispatcher.register(handlers);
328
+ const { appId, appSecret } = this.requireCredentials();
329
+ // Close any existing WSClient before creating a new one to prevent
330
+ // orphaned connections when startWS is called multiple times.
331
+ if (this._wsClient) {
332
+ log.warn(`closing previous WSClient before reconnect`, { accountId: this.accountId });
333
+ try {
334
+ this._wsClient.close({ force: true });
335
+ }
336
+ catch {
337
+ // Ignore — the old client may already be torn down.
338
+ }
339
+ this._wsClient = null;
340
+ }
341
+ this._wsClient = new Lark.WSClient({
342
+ appId,
343
+ appSecret,
344
+ domain: resolveBrand(this.account.brand),
345
+ loggerLevel: Lark.LoggerLevel.info,
346
+ });
347
+ // SDK 的 handleEventData 只处理 type="event",card action 回调是 type="card" 会被丢弃。
348
+ // 打 patch 将 "card" 类型消息改成 "event" 后交给原 handler,让 EventDispatcher 正常路由。
349
+ const wsClientAny = this._wsClient;
350
+ const origHandleEventData = wsClientAny.handleEventData.bind(wsClientAny);
351
+ wsClientAny.handleEventData = (data) => {
352
+ const msgType = data.headers?.find?.((h) => h.key === 'type')?.value;
353
+ if (msgType === 'card') {
354
+ const patchedData = {
355
+ ...data,
356
+ headers: data.headers.map((h) => (h.key === 'type' ? { ...h, value: 'event' } : h)),
357
+ };
358
+ return origHandleEventData(patchedData);
359
+ }
360
+ return origHandleEventData(data);
361
+ };
362
+ await this.waitForAbort(dispatcher, abortSignal);
363
+ }
364
+ /** Whether a WebSocket client is currently active. */
365
+ get wsConnected() {
366
+ return this._wsClient != null;
367
+ }
368
+ /** Disconnect WebSocket but keep instance in cache. */
369
+ disconnect() {
370
+ if (this._wsClient) {
371
+ log.info(`disconnecting WebSocket`, { accountId: this.accountId });
372
+ try {
373
+ this._wsClient.close({ force: true });
374
+ }
375
+ catch {
376
+ // Ignore errors during close — the client may already be torn down.
377
+ }
378
+ }
379
+ this._wsClient = null;
380
+ if (this.messageDedup) {
381
+ log.info(`disposing message dedup`, { accountId: this.accountId, size: this.messageDedup.size });
382
+ this.messageDedup.dispose();
383
+ this.messageDedup = null;
384
+ }
385
+ }
386
+ /** Disconnect + remove from cache. */
387
+ dispose() {
388
+ this.disconnect();
389
+ cache.delete(this.accountId);
390
+ }
391
+ // ---- Private helpers -------------------------------------------------------
392
+ /** Assert credentials exist or throw. */
393
+ requireCredentials() {
394
+ const appId = this.account.appId;
395
+ const appSecret = this.account.appSecret;
396
+ if (!appId || !appSecret) {
397
+ throw new Error(`LarkClient[${this.accountId}]: appId and appSecret are required`);
398
+ }
399
+ return { appId, appSecret };
400
+ }
401
+ /**
402
+ * Start the WSClient and return a promise that resolves when the
403
+ * abort signal fires (or immediately if already aborted).
404
+ */
405
+ waitForAbort(dispatcher, signal) {
406
+ return new Promise((resolve, reject) => {
407
+ if (signal?.aborted) {
408
+ this.disconnect();
409
+ return resolve();
410
+ }
411
+ signal?.addEventListener('abort', () => {
412
+ this.disconnect();
413
+ resolve();
414
+ }, { once: true });
415
+ try {
416
+ void this._wsClient.start({ eventDispatcher: dispatcher });
417
+ }
418
+ catch (err) {
419
+ this.disconnect();
420
+ reject(err);
421
+ }
422
+ });
423
+ }
424
+ }
425
+ exports.LarkClient = LarkClient;
426
+ // Inject LarkClient reference into chat-info-cache to break the circular
427
+ // dependency (chat-info-cache needs LarkClient.fromCfg but lark-client
428
+ // imports clearChatInfoCache from chat-info-cache).
429
+ (0, chat_info_cache_1.injectLarkClient)(LarkClient);
430
+ // ---------------------------------------------------------------------------
431
+ // Config resolution helper
432
+ // ---------------------------------------------------------------------------
433
+ /**
434
+ * Returns the best available config for account resolution.
435
+ *
436
+ * Priority: live config (has `channels.feishu`) > fallback (has
437
+ * `channels.feishu`) > live config (last resort).
438
+ *
439
+ * The `config` object captured in tool-registration closures may be stale
440
+ * after a hot-reload, so we prefer the live config from
441
+ * `LarkClient.runtime.config.loadConfig()`. However, `loadConfig()` may
442
+ * return `{}` when the runtime config snapshot has been cleared (e.g. in
443
+ * isolated cron sessions), so we fall back to the closure-captured config
444
+ * when the live result lacks Feishu credentials.
445
+ *
446
+ * @param fallback - Config to use when the runtime is not yet initialised
447
+ * or when `loadConfig()` returns an incomplete config.
448
+ */
449
+ function getResolvedConfig(fallback) {
450
+ try {
451
+ const live = LarkClient.runtime.config.loadConfig();
452
+ // loadConfig() may return {} (empty config) when runtimeConfigSnapshot
453
+ // has been cleared (e.g. after writeConfigFile, secrets teardown, or
454
+ // concurrent cron race conditions in isolated sessions). In that case
455
+ // the closure-captured fallback still holds a valid resolved config.
456
+ if (live?.channels?.feishu)
457
+ return live;
458
+ if (fallback?.channels?.feishu) {
459
+ log.debug(`loadConfig() returned config without channels.feishu, using fallback`);
460
+ return fallback;
461
+ }
462
+ return live;
463
+ }
464
+ catch {
465
+ // runtime not yet initialised — fall back to passed config
466
+ return fallback;
467
+ }
468
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * Structured logger factory for the Feishu plugin.
6
+ *
7
+ * Wraps `PluginRuntime.logging.getChildLogger()` with automatic
8
+ * LarkTicket injection from AsyncLocalStorage and a console fallback
9
+ * when the runtime is not yet initialised.
10
+ *
11
+ * Usage:
12
+ * const log = larkLogger("card/streaming");
13
+ * log.info("created entity", { cardId, sequence });
14
+ */
15
+ export interface LarkLogger {
16
+ readonly subsystem: string;
17
+ debug(message: string, meta?: Record<string, unknown>): void;
18
+ info(message: string, meta?: Record<string, unknown>): void;
19
+ warn(message: string, meta?: Record<string, unknown>): void;
20
+ error(message: string, meta?: Record<string, unknown>): void;
21
+ child(name: string): LarkLogger;
22
+ }
23
+ export declare function larkLogger(subsystem: string): LarkLogger;