@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,168 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * Access control policies for the Lark/Feishu channel plugin.
7
+ *
8
+ * Provides allowlist matching, group configuration lookup, tool policy
9
+ * extraction, and group access checks.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.resolveFeishuAllowlistMatch = resolveFeishuAllowlistMatch;
13
+ exports.resolveFeishuGroupConfig = resolveFeishuGroupConfig;
14
+ exports.resolveFeishuGroupToolPolicy = resolveFeishuGroupToolPolicy;
15
+ exports.isFeishuGroupAllowed = isFeishuGroupAllowed;
16
+ exports.splitLegacyGroupAllowFrom = splitLegacyGroupAllowFrom;
17
+ exports.resolveGroupSenderPolicyContext = resolveGroupSenderPolicyContext;
18
+ const accounts_1 = require("../../core/accounts.js");
19
+ /**
20
+ * Check whether a sender is permitted by a given allowlist.
21
+ *
22
+ * Entries are normalised to lowercase strings before comparison.
23
+ * A single "*" entry acts as a wildcard that matches everyone.
24
+ * When the allowlist is empty the result is `{ allowed: false }`.
25
+ */
26
+ function resolveFeishuAllowlistMatch(params) {
27
+ const allowFrom = params.allowFrom.map((entry) => String(entry).trim().toLowerCase()).filter(Boolean);
28
+ if (allowFrom.length === 0) {
29
+ return { allowed: false };
30
+ }
31
+ // Wildcard: allow everyone
32
+ if (allowFrom.includes('*')) {
33
+ return { allowed: true, matchKey: '*', matchSource: 'wildcard' };
34
+ }
35
+ // Match by sender ID
36
+ const senderId = params.senderId.toLowerCase();
37
+ if (allowFrom.includes(senderId)) {
38
+ return { allowed: true, matchKey: senderId, matchSource: 'id' };
39
+ }
40
+ /* // Match by sender display name
41
+ const senderName = params.senderName?.toLowerCase();
42
+ if (senderName && allowFrom.includes(senderName)) {
43
+ return { allowed: true, matchKey: senderName, matchSource: 'name' };
44
+ }*/
45
+ return { allowed: false };
46
+ }
47
+ // ---------------------------------------------------------------------------
48
+ // Group configuration lookup
49
+ // ---------------------------------------------------------------------------
50
+ /**
51
+ * Look up the per-group configuration by group ID.
52
+ *
53
+ * Performs a case-insensitive lookup against the keys in `cfg.groups`.
54
+ * Returns `undefined` when no matching group entry is found.
55
+ */
56
+ function resolveFeishuGroupConfig(params) {
57
+ const groups = params.cfg?.groups ?? {};
58
+ const groupId = params.groupId?.trim();
59
+ if (!groupId) {
60
+ return undefined;
61
+ }
62
+ // Direct (exact-key) lookup first
63
+ const direct = groups[groupId];
64
+ if (direct) {
65
+ return direct;
66
+ }
67
+ // Case-insensitive fallback
68
+ const lowered = groupId.toLowerCase();
69
+ const matchKey = Object.keys(groups).find((key) => key.toLowerCase() === lowered);
70
+ return matchKey ? groups[matchKey] : undefined;
71
+ }
72
+ // ---------------------------------------------------------------------------
73
+ // Group tool policy
74
+ // ---------------------------------------------------------------------------
75
+ /**
76
+ * Extract the tool policy configuration from the group config that
77
+ * corresponds to the given group context.
78
+ *
79
+ * ★ 多账号配置隔离:SDK 回调传入的 params.cfg 是顶层全局配置,
80
+ * cfg.channels.feishu 不包含 per-account 的覆盖值。
81
+ * 这里通过 getLarkAccount() 获取当前 account 合并后的配置,
82
+ * 确保每个账号的 groups / tool policy 配置独立生效。
83
+ */
84
+ function resolveFeishuGroupToolPolicy(params) {
85
+ // 使用 getLarkAccount 获取 per-account 合并后的飞书渠道配置,
86
+ // 而非直接读取 cfg.channels.feishu(顶层全局配置)。
87
+ const account = (0, accounts_1.getLarkAccount)(params.cfg, params.accountId ?? undefined);
88
+ const accountFeishuCfg = account.config;
89
+ if (!accountFeishuCfg) {
90
+ return undefined;
91
+ }
92
+ const groupConfig = resolveFeishuGroupConfig({
93
+ cfg: accountFeishuCfg,
94
+ groupId: params.groupId,
95
+ });
96
+ return groupConfig?.tools;
97
+ }
98
+ // ---------------------------------------------------------------------------
99
+ // Group access gate
100
+ // ---------------------------------------------------------------------------
101
+ /**
102
+ * Determine whether an inbound group message should be processed.
103
+ *
104
+ * - `disabled` --> always rejected
105
+ * - `open` --> always allowed
106
+ * - `allowlist` --> allowed only when the sender matches the allowlist
107
+ */
108
+ function isFeishuGroupAllowed(params) {
109
+ const { groupPolicy } = params;
110
+ if (groupPolicy === 'disabled') {
111
+ return false;
112
+ }
113
+ if (groupPolicy === 'open') {
114
+ return true;
115
+ }
116
+ // allowlist
117
+ return resolveFeishuAllowlistMatch(params).allowed;
118
+ }
119
+ // ---------------------------------------------------------------------------
120
+ // Legacy compat: groupAllowFrom splitting
121
+ // ---------------------------------------------------------------------------
122
+ /**
123
+ * Split a raw `groupAllowFrom` array into legacy chat-ID entries
124
+ * (`oc_xxx`) and sender-level entries.
125
+ *
126
+ * Older Feishu configs used `groupAllowFrom` with `oc_xxx` chat IDs to
127
+ * control which groups are allowed. The correct semantic (aligned with
128
+ * Telegram) is sender IDs. This function separates the two concerns so
129
+ * both layers can work independently.
130
+ */
131
+ function splitLegacyGroupAllowFrom(rawGroupAllowFrom) {
132
+ const legacyChatIds = [];
133
+ const senderAllowFrom = [];
134
+ for (const entry of rawGroupAllowFrom) {
135
+ const str = String(entry);
136
+ if (str.startsWith('oc_')) {
137
+ legacyChatIds.push(str);
138
+ }
139
+ else {
140
+ senderAllowFrom.push(str);
141
+ }
142
+ }
143
+ return { legacyChatIds, senderAllowFrom };
144
+ }
145
+ // ---------------------------------------------------------------------------
146
+ // Sender policy context resolution
147
+ // ---------------------------------------------------------------------------
148
+ /**
149
+ * Resolve the effective sender-level group policy and the merged
150
+ * `allowFrom` list for sender filtering within a group.
151
+ *
152
+ * The precedence chain for `senderPolicy` is:
153
+ * per-group `groupPolicy` > default ("*") group `groupPolicy` >
154
+ * global `groupPolicy` > "open" (default).
155
+ *
156
+ * The `senderAllowFrom` is the union of global (non-oc_) entries,
157
+ * per-group entries, and default ("*") entries (when no per-group config).
158
+ */
159
+ function resolveGroupSenderPolicyContext(params) {
160
+ const { groupConfig, defaultConfig, accountFeishuCfg, senderGroupAllowFrom } = params;
161
+ const senderPolicy = groupConfig?.groupPolicy ?? defaultConfig?.groupPolicy ?? accountFeishuCfg?.groupPolicy ?? 'open';
162
+ const senderAllowFrom = [
163
+ ...senderGroupAllowFrom,
164
+ ...(groupConfig?.allowFrom ?? []),
165
+ ...(!groupConfig && defaultConfig?.allowFrom ? defaultConfig.allowFrom : []),
166
+ ];
167
+ return { senderPolicy, senderAllowFrom };
168
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * Reaction event handler for the Lark/Feishu channel plugin.
6
+ *
7
+ * Handles `im.message.reaction.created_v1` events by building a
8
+ * {@link MessageContext} directly and dispatching to the agent via
9
+ * {@link dispatchToAgent}, bypassing the full 7-stage message pipeline.
10
+ *
11
+ * Controlled by `reactionNotifications` (default: "own"):
12
+ * - `"off"` — reaction events are silently ignored.
13
+ * - `"own"` — only reactions on the bot's own messages are dispatched.
14
+ * - `"all"` — reactions on any message in the chat are dispatched.
15
+ */
16
+ import type { ClawdbotConfig, RuntimeEnv } from 'openclaw/plugin-sdk';
17
+ import type { HistoryEntry } from 'openclaw/plugin-sdk/reply-history';
18
+ import type { FeishuReactionCreatedEvent } from '../types';
19
+ import { type FeishuMessageInfo } from '../shared/message-lookup';
20
+ export interface ReactionContext {
21
+ /** Real chatId (from message API, or `p2p:${operatorOpenId}` fallback). */
22
+ chatId: string;
23
+ /** Resolved chat type. */
24
+ chatType: 'p2p' | 'group';
25
+ /** Thread ID from the fetched message, if any. */
26
+ threadId?: string;
27
+ /** Whether the chat is thread-capable (topic or thread-mode group). */
28
+ threadCapable?: boolean;
29
+ /** Fetched message info used to build the synthetic event. */
30
+ msg: FeishuMessageInfo;
31
+ }
32
+ /**
33
+ * Pre-resolve reaction context before enqueuing.
34
+ *
35
+ * Performs account config checks, safety filters, API fetch of the
36
+ * original message, ownership verification, chat type resolution, and
37
+ * thread-capable detection. Returns `null` when the reaction should
38
+ * be skipped (mode off, safety filter, timeout, ownership mismatch,
39
+ * thread-capable group with threadSession enabled).
40
+ *
41
+ * This function is intentionally separated so that the caller
42
+ * (event-handlers.ts) can resolve the real chatId *before* enqueuing,
43
+ * ensuring the reaction shares the same queue key as normal messages
44
+ * for the same chat.
45
+ */
46
+ export declare function resolveReactionContext(params: {
47
+ cfg: ClawdbotConfig;
48
+ event: FeishuReactionCreatedEvent;
49
+ botOpenId?: string;
50
+ runtime?: RuntimeEnv;
51
+ accountId?: string;
52
+ }): Promise<ReactionContext | null>;
53
+ export declare function handleFeishuReaction(params: {
54
+ cfg: ClawdbotConfig;
55
+ event: FeishuReactionCreatedEvent;
56
+ botOpenId?: string;
57
+ runtime?: RuntimeEnv;
58
+ chatHistories?: Map<string, HistoryEntry[]>;
59
+ accountId?: string;
60
+ /** Pre-resolved context from resolveReactionContext(). */
61
+ preResolved: ReactionContext;
62
+ }): Promise<void>;
@@ -0,0 +1,259 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * Reaction event handler for the Lark/Feishu channel plugin.
7
+ *
8
+ * Handles `im.message.reaction.created_v1` events by building a
9
+ * {@link MessageContext} directly and dispatching to the agent via
10
+ * {@link dispatchToAgent}, bypassing the full 7-stage message pipeline.
11
+ *
12
+ * Controlled by `reactionNotifications` (default: "own"):
13
+ * - `"off"` — reaction events are silently ignored.
14
+ * - `"own"` — only reactions on the bot's own messages are dispatched.
15
+ * - `"all"` — reactions on any message in the chat are dispatched.
16
+ */
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.resolveReactionContext = resolveReactionContext;
52
+ exports.handleFeishuReaction = handleFeishuReaction;
53
+ const crypto = __importStar(require("node:crypto"));
54
+ const reply_history_1 = require("openclaw/plugin-sdk/reply-history");
55
+ const accounts_1 = require("../../core/accounts.js");
56
+ const message_lookup_1 = require("../shared/message-lookup.js");
57
+ const chat_info_cache_1 = require("../../core/chat-info-cache.js");
58
+ const lark_logger_1 = require("../../core/lark-logger.js");
59
+ const user_name_cache_1 = require("./user-name-cache.js");
60
+ const dispatch_1 = require("./dispatch.js");
61
+ const policy_1 = require("./policy.js");
62
+ const logger = (0, lark_logger_1.larkLogger)('inbound/reaction-handler');
63
+ const REACTION_VERIFY_TIMEOUT_MS = 3_000;
64
+ /**
65
+ * Pre-resolve reaction context before enqueuing.
66
+ *
67
+ * Performs account config checks, safety filters, API fetch of the
68
+ * original message, ownership verification, chat type resolution, and
69
+ * thread-capable detection. Returns `null` when the reaction should
70
+ * be skipped (mode off, safety filter, timeout, ownership mismatch,
71
+ * thread-capable group with threadSession enabled).
72
+ *
73
+ * This function is intentionally separated so that the caller
74
+ * (event-handlers.ts) can resolve the real chatId *before* enqueuing,
75
+ * ensuring the reaction shares the same queue key as normal messages
76
+ * for the same chat.
77
+ */
78
+ async function resolveReactionContext(params) {
79
+ const { cfg, event, botOpenId, runtime, accountId } = params;
80
+ const log = runtime?.log ?? ((...args) => logger.info(args.map(String).join(' ')));
81
+ const account = (0, accounts_1.getLarkAccount)(cfg, accountId);
82
+ const reactionMode = account.config?.reactionNotifications ?? 'own';
83
+ if (reactionMode === 'off') {
84
+ return null;
85
+ }
86
+ const emojiType = event.reaction_type?.emoji_type;
87
+ const messageId = event.message_id;
88
+ const operatorOpenId = event.user_id?.open_id ?? '';
89
+ if (!emojiType || !messageId || !operatorOpenId) {
90
+ return null;
91
+ }
92
+ // ---- Safety filters (aligned with official) ----
93
+ if (event.operator_type === 'app' || operatorOpenId === botOpenId) {
94
+ log(`feishu[${accountId}]: ignoring app/self reaction on ${messageId}`);
95
+ return null;
96
+ }
97
+ if (emojiType === 'Typing') {
98
+ return null;
99
+ }
100
+ // "own" mode requires botOpenId to verify message ownership
101
+ if (reactionMode === 'own' && !botOpenId) {
102
+ log(`feishu[${accountId}]: bot open_id unavailable, skipping reaction on ${messageId}`);
103
+ return null;
104
+ }
105
+ // ---- Fetch original message with timeout (fail-closed) ----
106
+ const msg = await Promise.race([
107
+ (0, message_lookup_1.getMessageFeishu)({ cfg, messageId, accountId }),
108
+ new Promise((resolve) => setTimeout(() => resolve(null), REACTION_VERIFY_TIMEOUT_MS)),
109
+ ]).catch(() => null);
110
+ if (!msg) {
111
+ log(`feishu[${accountId}]: reacted message ${messageId} not found or timed out, skipping`);
112
+ return null;
113
+ }
114
+ // mget API returns app_id (cli_xxx) as sender.id for bot messages.
115
+ const isBotMessage = msg.senderType === 'app' && msg.senderId === account.appId;
116
+ const isOtherBotMessage = msg.senderType === 'app' && account.appId && msg.senderId !== account.appId;
117
+ // 'own': only react to this bot's messages; 'all': also skip other bots' messages.
118
+ if ((reactionMode === 'own' && !isBotMessage) || (reactionMode === 'all' && isOtherBotMessage)) {
119
+ log(`feishu[${accountId}]: reaction on ${isOtherBotMessage ? 'other bot' : 'non-bot'} message ${messageId}, skipping`);
120
+ return null;
121
+ }
122
+ // ---- Resolve effective chatId ----
123
+ const rawChatId = event.chat_id?.trim() || msg.chatId?.trim() || '';
124
+ const effectiveChatId = rawChatId || `p2p:${operatorOpenId}`;
125
+ // ---- Resolve chat type ----
126
+ // im.message.reaction.created_v1 does NOT include chat_id or chat_type
127
+ // (confirmed from Feishu docs). The message GET API returns chat_id but
128
+ // NOT chat_type. So we must determine chat_type via im.chat.get.
129
+ //
130
+ // Determine chat type: event payload → fetched message → im.chat.get API.
131
+ // The first two sources are almost always empty for reaction events, so
132
+ // getChatTypeFeishu is the primary path.
133
+ let chatType = event.chat_type === 'group'
134
+ ? 'group'
135
+ : event.chat_type === 'p2p' || event.chat_type === 'private'
136
+ ? 'p2p'
137
+ : msg.chatType === 'group' || msg.chatType === 'p2p'
138
+ ? msg.chatType
139
+ : 'p2p'; // tentative default, overridden below when chatId is available
140
+ // When we have a real chat_id (from event or message API), query the
141
+ // authoritative chat type via im.chat.get. This is the only reliable
142
+ // source for reaction events.
143
+ if (rawChatId && chatType === 'p2p' && !event.chat_type && !msg.chatType) {
144
+ try {
145
+ chatType = await (0, chat_info_cache_1.getChatTypeFeishu)({ cfg, chatId: rawChatId, accountId });
146
+ }
147
+ catch {
148
+ // getChatTypeFeishu already logs errors and defaults to "p2p"
149
+ }
150
+ }
151
+ // ---- Thread session: skip for thread-capable groups ----
152
+ // The mget API does not return thread_id, so we cannot route the
153
+ // synthetic event to the correct thread session. Skip reaction handling
154
+ // only for thread-capable groups (topic / thread-mode); p2p and regular
155
+ // groups are unaffected since they have no threads.
156
+ let threadCapable = false;
157
+ const threadSessionEnabled = account.config?.threadSession === true;
158
+ if (rawChatId && chatType === 'group') {
159
+ threadCapable = await (0, chat_info_cache_1.isThreadCapableGroup)({ cfg, chatId: rawChatId, accountId });
160
+ if (threadSessionEnabled && threadCapable) {
161
+ log(`feishu[${accountId}]: reaction on thread-capable group ${rawChatId}, skipping (threadSession enabled)`);
162
+ return null;
163
+ }
164
+ }
165
+ return {
166
+ chatId: effectiveChatId,
167
+ chatType,
168
+ threadId: msg.threadId,
169
+ threadCapable,
170
+ msg,
171
+ };
172
+ }
173
+ // ---------------------------------------------------------------------------
174
+ // Public API
175
+ // ---------------------------------------------------------------------------
176
+ async function handleFeishuReaction(params) {
177
+ const { cfg, event, runtime, chatHistories, accountId, preResolved } = params;
178
+ const log = runtime?.log ?? ((...args) => logger.info(args.map(String).join(' ')));
179
+ const error = runtime?.error ?? ((...args) => logger.error(args.map(String).join(' ')));
180
+ const emojiType = event.reaction_type?.emoji_type ?? '';
181
+ const messageId = event.message_id;
182
+ const operatorOpenId = event.user_id?.open_id ?? '';
183
+ // ---- Step A: Account resolution + accountScopedCfg ----
184
+ const account = (0, accounts_1.getLarkAccount)(cfg, accountId);
185
+ const accountFeishuCfg = account.config;
186
+ const accountScopedCfg = {
187
+ ...cfg,
188
+ channels: { ...cfg.channels, feishu: accountFeishuCfg },
189
+ };
190
+ // ---- Step B: Build MessageContext directly ----
191
+ const excerpt = preResolved.msg.content.length > 200 ? `${preResolved.msg.content.slice(0, 200)}…` : preResolved.msg.content;
192
+ const syntheticText = excerpt
193
+ ? `[reacted with ${emojiType} to message ${messageId}: "${excerpt}"]`
194
+ : `[reacted with ${emojiType} to message ${messageId}]`;
195
+ const syntheticMessageId = `${messageId}:reaction:${emojiType}:${crypto.randomUUID()}`;
196
+ let ctx = {
197
+ chatId: preResolved.chatId,
198
+ messageId: syntheticMessageId,
199
+ senderId: operatorOpenId,
200
+ chatType: preResolved.chatType,
201
+ content: syntheticText,
202
+ contentType: 'text',
203
+ resources: [],
204
+ mentions: [],
205
+ mentionAll: false,
206
+ threadId: preResolved.threadId,
207
+ rawMessage: {
208
+ message_id: syntheticMessageId,
209
+ chat_id: preResolved.chatId,
210
+ chat_type: preResolved.chatType,
211
+ message_type: 'text',
212
+ content: JSON.stringify({ text: syntheticText }),
213
+ create_time: event.action_time ?? String(Date.now()),
214
+ thread_id: preResolved.threadId,
215
+ },
216
+ rawSender: {
217
+ sender_id: {
218
+ open_id: operatorOpenId,
219
+ user_id: event.user_id?.user_id,
220
+ union_id: event.user_id?.union_id,
221
+ },
222
+ sender_type: 'user',
223
+ },
224
+ };
225
+ // ---- Step C: Sender name resolution ----
226
+ const senderResult = await (0, user_name_cache_1.resolveUserName)({ account, openId: operatorOpenId, log });
227
+ if (senderResult.name) {
228
+ ctx = { ...ctx, senderName: senderResult.name };
229
+ }
230
+ log(`feishu[${accountId}]: reaction "${emojiType}" by ${operatorOpenId} on ${messageId} (chatId=${preResolved.chatId}, chatType=${preResolved.chatType}${preResolved.threadId ? `, thread=${preResolved.threadId}` : ''}), dispatching to AI`);
231
+ logger.info(`reaction "${emojiType}" by ${operatorOpenId} on ${messageId} (chatType=${preResolved.chatType})`);
232
+ // ---- Step D: Group config resolution ----
233
+ const isGroup = ctx.chatType === 'group';
234
+ const groupConfig = isGroup ? (0, policy_1.resolveFeishuGroupConfig)({ cfg: accountFeishuCfg, groupId: ctx.chatId }) : undefined;
235
+ const defaultGroupConfig = isGroup ? accountFeishuCfg?.groups?.['*'] : undefined;
236
+ const historyLimit = Math.max(0, accountFeishuCfg?.historyLimit ?? accountScopedCfg.messages?.groupChat?.historyLimit ?? reply_history_1.DEFAULT_GROUP_HISTORY_LIMIT);
237
+ // ---- Step E: Dispatch directly to agent ----
238
+ try {
239
+ await (0, dispatch_1.dispatchToAgent)({
240
+ ctx,
241
+ permissionError: undefined,
242
+ mediaPayload: {},
243
+ quotedContent: undefined,
244
+ account,
245
+ accountScopedCfg,
246
+ runtime,
247
+ chatHistories,
248
+ historyLimit,
249
+ replyToMessageId: messageId,
250
+ commandAuthorized: false,
251
+ groupConfig,
252
+ defaultGroupConfig,
253
+ skipTyping: true,
254
+ });
255
+ }
256
+ catch (err) {
257
+ error(`feishu[${accountId}]: error dispatching reaction event: ${String(err)}`);
258
+ }
259
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * Per-thread store for unresolved mention feedback. The outbound
6
+ * normalizer records a SentinelEntry whenever an `@Name` cannot be
7
+ * resolved; the next inbound message on the same thread consumes
8
+ * (take and delete) the entries, which buildMentionAnnotation surfaces
9
+ * as a system note so the next reply can disambiguate.
10
+ *
11
+ * Kept separate from UserNameCache because the lifecycle differs:
12
+ * 10-minute TTL, per-thread keying, and take-and-delete consumption.
13
+ */
14
+ export interface SentinelEntry {
15
+ /** Literal name as it appeared in the outbound text. */
16
+ name: string;
17
+ /** Why parsing failed. */
18
+ reason: 'not_found' | 'ambiguous';
19
+ /** Candidate open_ids when reason === 'ambiguous'. */
20
+ candidates?: Array<{
21
+ openId: string;
22
+ kind?: 'user' | 'bot';
23
+ }>;
24
+ }
25
+ export declare class SentinelStore {
26
+ private byThread;
27
+ private maxThreads;
28
+ private ttlMs;
29
+ constructor(maxThreads?: number, ttlMs?: number);
30
+ recordSentinels(threadKey: string, sentinels: SentinelEntry[]): void;
31
+ consumeSentinels(threadKey: string): SentinelEntry[];
32
+ clear(): void;
33
+ private evict;
34
+ }
35
+ export declare function getSentinelStore(accountId: string, maxThreads?: number, ttlMs?: number): SentinelStore;
36
+ export declare function clearSentinelStore(accountId?: string): void;
37
+ export declare function clearAllSentinelStores(): void;
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * Per-thread store for unresolved mention feedback. The outbound
7
+ * normalizer records a SentinelEntry whenever an `@Name` cannot be
8
+ * resolved; the next inbound message on the same thread consumes
9
+ * (take and delete) the entries, which buildMentionAnnotation surfaces
10
+ * as a system note so the next reply can disambiguate.
11
+ *
12
+ * Kept separate from UserNameCache because the lifecycle differs:
13
+ * 10-minute TTL, per-thread keying, and take-and-delete consumption.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.SentinelStore = void 0;
17
+ exports.getSentinelStore = getSentinelStore;
18
+ exports.clearSentinelStore = clearSentinelStore;
19
+ exports.clearAllSentinelStores = clearAllSentinelStores;
20
+ const DEFAULT_TTL_MS = 10 * 60 * 1000; // 10 min — short, avoid stale feedback
21
+ const DEFAULT_MAX_THREADS = 200; // per-account
22
+ function dedup(entries) {
23
+ const seen = new Set();
24
+ const out = [];
25
+ for (const e of entries) {
26
+ const key = `${e.reason}:${e.name}`;
27
+ if (seen.has(key))
28
+ continue;
29
+ seen.add(key);
30
+ out.push(e);
31
+ }
32
+ return out;
33
+ }
34
+ class SentinelStore {
35
+ byThread = new Map();
36
+ maxThreads;
37
+ ttlMs;
38
+ constructor(maxThreads = DEFAULT_MAX_THREADS, ttlMs = DEFAULT_TTL_MS) {
39
+ this.maxThreads = maxThreads;
40
+ this.ttlMs = ttlMs;
41
+ }
42
+ recordSentinels(threadKey, sentinels) {
43
+ if (sentinels.length === 0)
44
+ return;
45
+ const existing = this.byThread.get(threadKey);
46
+ const merged = existing ? [...existing.entries, ...sentinels] : sentinels;
47
+ this.byThread.delete(threadKey); // bump LRU
48
+ this.byThread.set(threadKey, {
49
+ entries: dedup(merged),
50
+ expireAt: Date.now() + this.ttlMs,
51
+ });
52
+ this.evict();
53
+ }
54
+ consumeSentinels(threadKey) {
55
+ const stored = this.byThread.get(threadKey);
56
+ if (!stored)
57
+ return [];
58
+ this.byThread.delete(threadKey);
59
+ if (stored.expireAt <= Date.now())
60
+ return [];
61
+ return stored.entries;
62
+ }
63
+ clear() {
64
+ this.byThread.clear();
65
+ }
66
+ evict() {
67
+ while (this.byThread.size > this.maxThreads) {
68
+ const oldest = this.byThread.keys().next().value;
69
+ if (oldest === undefined)
70
+ break;
71
+ this.byThread.delete(oldest);
72
+ }
73
+ }
74
+ }
75
+ exports.SentinelStore = SentinelStore;
76
+ const registry = new Map();
77
+ function getSentinelStore(accountId, maxThreads, ttlMs) {
78
+ let store = registry.get(accountId);
79
+ if (!store) {
80
+ store = new SentinelStore(maxThreads, ttlMs);
81
+ registry.set(accountId, store);
82
+ }
83
+ return store;
84
+ }
85
+ function clearSentinelStore(accountId) {
86
+ if (accountId !== undefined) {
87
+ registry.get(accountId)?.clear();
88
+ registry.delete(accountId);
89
+ }
90
+ else {
91
+ clearAllSentinelStores();
92
+ }
93
+ }
94
+ function clearAllSentinelStores() {
95
+ for (const s of registry.values())
96
+ s.clear();
97
+ registry.clear();
98
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * Shared helper for dispatching synthetic inbound text messages.
6
+ *
7
+ * Synthetic messages are used to resume the normal inbound pipeline after
8
+ * card actions or OAuth flows complete.
9
+ */
10
+ import type { ClawdbotConfig } from 'openclaw/plugin-sdk';
11
+ export declare function dispatchSyntheticTextMessage(params: {
12
+ cfg: ClawdbotConfig;
13
+ accountId: string;
14
+ chatId: string;
15
+ senderOpenId: string;
16
+ text: string;
17
+ syntheticMessageId: string;
18
+ replyToMessageId: string;
19
+ chatType?: 'p2p' | 'group';
20
+ threadId?: string;
21
+ runtime?: {
22
+ log?: (msg: string) => void;
23
+ error?: (msg: string) => void;
24
+ };
25
+ forceMention?: boolean;
26
+ }): Promise<string>;