@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,477 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * Agent dispatch for inbound Feishu messages.
7
+ *
8
+ * Builds the agent envelope, prepends chat history context, and
9
+ * dispatches through the appropriate reply path (system command
10
+ * vs. normal streaming/static flow).
11
+ *
12
+ * Implementation details are split across focused modules:
13
+ * - dispatch-context.ts — DispatchContext type, route/session/event
14
+ * - dispatch-builders.ts — pure payload/body/envelope construction
15
+ * - dispatch-commands.ts — system command & permission notification
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.dispatchToAgent = dispatchToAgent;
19
+ const reply_history_1 = require("openclaw/plugin-sdk/reply-history");
20
+ const lark_logger_1 = require("../../core/lark-logger.js");
21
+ const lark_ticket_1 = require("../../core/lark-ticket.js");
22
+ const reply_dispatcher_1 = require("../../card/reply-dispatcher.js");
23
+ const chat_queue_1 = require("../../channel/chat-queue.js");
24
+ const tool_use_config_1 = require("../../card/tool-use-config.js");
25
+ const tool_use_trace_store_1 = require("../../card/tool-use-trace-store.js");
26
+ const abort_detect_1 = require("../../channel/abort-detect.js");
27
+ const bot_peer_context_1 = require("../outbound/bot-peer-context.js");
28
+ const comment_target_1 = require("../../core/comment-target.js");
29
+ const synthetic_target_1 = require("../../core/synthetic-target.js");
30
+ const targets_1 = require("../../core/targets.js");
31
+ const deliver_1 = require("../outbound/deliver.js");
32
+ const doctor_1 = require("../../commands/doctor.js");
33
+ const auth_1 = require("../../commands/auth.js");
34
+ const index_1 = require("../../commands/index.js");
35
+ const send_1 = require("../outbound/send.js");
36
+ const bot_content_1 = require("./bot-content.js");
37
+ const dispatch_commands_1 = require("./dispatch-commands.js");
38
+ const dispatch_builders_1 = require("./dispatch-builders.js");
39
+ const sentinel_store_1 = require("./sentinel-store.js");
40
+ const dispatch_context_1 = require("./dispatch-context.js");
41
+ const mention_1 = require("./mention.js");
42
+ const gate_1 = require("./gate.js");
43
+ const log = (0, lark_logger_1.larkLogger)('inbound/dispatch');
44
+ // ---------------------------------------------------------------------------
45
+ // Internal: normal message dispatch
46
+ // ---------------------------------------------------------------------------
47
+ /**
48
+ * Dispatch a normal (non-command) message via the streaming card flow.
49
+ * Cleans up consumed history entries after dispatch completes.
50
+ *
51
+ * Note: history cleanup is intentionally placed here and NOT in the
52
+ * system-command path — command handlers don't consume history context,
53
+ * so the entries should be preserved for the next normal message.
54
+ */
55
+ /**
56
+ * Dispatch a comment-target message via the buffered block dispatcher.
57
+ *
58
+ * Comment targets cannot use the streaming card flow (IM APIs don't
59
+ * understand comment:... targets). Instead we use the SDK's buffered
60
+ * block dispatcher with a deliver callback that sends via the Drive
61
+ * comment reply API.
62
+ */
63
+ async function dispatchCommentMessage(dc, ctxPayload, skillFilter) {
64
+ const effectiveSessionKey = dc.threadSessionKey ?? dc.route.sessionKey;
65
+ dc.log(`feishu[${dc.account.accountId}]: dispatching comment reply (session=${effectiveSessionKey})`);
66
+ log.info(`dispatching comment reply (session=${effectiveSessionKey})`);
67
+ let delivered = false;
68
+ await dc.core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
69
+ ctx: ctxPayload,
70
+ cfg: dc.accountScopedCfg,
71
+ dispatcherOptions: {
72
+ deliver: async (payload) => {
73
+ const text = payload.text?.trim() ?? '';
74
+ if (!text || text === 'NO_REPLY')
75
+ return;
76
+ await (0, deliver_1.sendCommentReplyLark)({
77
+ cfg: dc.accountScopedCfg,
78
+ to: dc.ctx.chatId,
79
+ text,
80
+ accountId: dc.account.accountId,
81
+ });
82
+ delivered = true;
83
+ },
84
+ onSkip: (_payload, info) => {
85
+ if (info.reason !== 'silent') {
86
+ dc.log(`feishu[${dc.account.accountId}]: comment reply skipped (reason=${info.reason})`);
87
+ }
88
+ },
89
+ onError: (err, info) => {
90
+ dc.error(`feishu[${dc.account.accountId}]: comment ${info.kind} reply failed: ${String(err)}`);
91
+ },
92
+ },
93
+ replyOptions: {
94
+ ...(skillFilter ? { skillFilter } : {}),
95
+ },
96
+ });
97
+ dc.log(`feishu[${dc.account.accountId}]: comment dispatch complete (delivered=${delivered})`);
98
+ log.info(`comment dispatch complete (delivered=${delivered}, elapsed=${(0, lark_ticket_1.ticketElapsed)()}ms)`);
99
+ }
100
+ /**
101
+ * Dispatch a synthetic-target message via the buffered block dispatcher
102
+ * while discarding every delivered payload.
103
+ *
104
+ * Synthetic contexts (e.g. VC meeting-invited) trigger the agent for its
105
+ * side-effects (tool calls) — they do not correspond to a real IM chat,
106
+ * so any text / card the agent emits must be dropped instead of being
107
+ * sent as a DM to whatever open_id happens to be in ctx.chatId.
108
+ */
109
+ async function dispatchSyntheticMessage(dc, ctxPayload, skillFilter) {
110
+ const effectiveSessionKey = dc.threadSessionKey ?? dc.route.sessionKey;
111
+ const isVcSynthetic = dc.ctx.chatId === synthetic_target_1.SYNTHETIC_VC_CHAT_ID;
112
+ let deliveredFinalToSender = false;
113
+ dc.log(`feishu[${dc.account.accountId}]: dispatching synthetic reply (session=${effectiveSessionKey}, target=${dc.ctx.chatId})`);
114
+ log.info(`dispatching synthetic reply (session=${effectiveSessionKey})`);
115
+ await dc.core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
116
+ ctx: ctxPayload,
117
+ cfg: dc.accountScopedCfg,
118
+ dispatcherOptions: {
119
+ deliver: async (payload, info) => {
120
+ const text = payload.text?.trim() ?? '';
121
+ const preview = text.slice(0, 120);
122
+ // VC invited flows intentionally keep the synthetic target to avoid
123
+ // leaking intermediate tool output to IM, but the final business
124
+ // result should be explicitly notified to the inviter.
125
+ //
126
+ // Important: this DM is only a transport bridge for the final text.
127
+ // It does not rebind the inviter's DM conversation to the synthetic
128
+ // meeting-scoped session; later DM replies will still be routed by the
129
+ // normal OpenClaw DM session rules.
130
+ if (isVcSynthetic && info.kind === 'final' && text && text !== 'NO_REPLY' && !deliveredFinalToSender) {
131
+ deliveredFinalToSender = true;
132
+ try {
133
+ await (0, send_1.sendMessageFeishu)({
134
+ cfg: dc.accountScopedCfg,
135
+ to: dc.ctx.senderId,
136
+ text,
137
+ accountId: dc.account.accountId,
138
+ });
139
+ dc.log(`feishu[${dc.account.accountId}]: synthetic VC final delivered explicitly to sender=${dc.ctx.senderId}, preview="${preview}"`);
140
+ return;
141
+ }
142
+ catch (err) {
143
+ deliveredFinalToSender = false;
144
+ dc.error(`feishu[${dc.account.accountId}]: synthetic VC final delivery failed to sender=${dc.ctx.senderId}: ${String(err)}`);
145
+ }
146
+ }
147
+ if (info.kind === 'final') {
148
+ dc.log(`feishu[${dc.account.accountId}]: synthetic final payload dropped (target=${dc.ctx.chatId})`);
149
+ }
150
+ },
151
+ onSkip: (_payload, info) => {
152
+ if (info.reason !== 'silent') {
153
+ dc.log(`feishu[${dc.account.accountId}]: synthetic reply skipped (reason=${info.reason})`);
154
+ }
155
+ },
156
+ onError: (err, info) => {
157
+ dc.error(`feishu[${dc.account.accountId}]: synthetic ${info.kind} reply failed: ${String(err)}`);
158
+ },
159
+ },
160
+ replyOptions: {
161
+ ...(skillFilter ? { skillFilter } : {}),
162
+ },
163
+ });
164
+ dc.log(`feishu[${dc.account.accountId}]: synthetic dispatch complete (elapsed=${(0, lark_ticket_1.ticketElapsed)()}ms)`);
165
+ }
166
+ async function dispatchNormalMessage(dc, ctxPayload, routing, chatHistories, historyKey, historyLimit, replyToMessageId, skillFilter, skipTyping, botPeer) {
167
+ // Synthetic targets (e.g. VC meeting-invited) have no real IM peer to
168
+ // deliver replies to. Route them through the buffered block dispatcher
169
+ // with a deliver() that drops every payload — the agent still runs
170
+ // (tool calls, side-effects) but produces no outbound IM traffic.
171
+ if ((0, synthetic_target_1.isSyntheticTarget)(dc.ctx.chatId)) {
172
+ await dispatchSyntheticMessage(dc, ctxPayload, skillFilter);
173
+ return;
174
+ }
175
+ // Comment targets bypass the streaming card / IM flow entirely —
176
+ // route through the Drive comment reply API.
177
+ if ((0, comment_target_1.isCommentTarget)(dc.ctx.chatId)) {
178
+ await dispatchCommentMessage(dc, ctxPayload, skillFilter);
179
+ return;
180
+ }
181
+ // Abort messages should never create streaming cards — dispatch via the
182
+ // plain-text system-command path so the SDK's abort handler can reply
183
+ // without touching CardKit.
184
+ if ((0, abort_detect_1.isLikelyAbortText)(dc.ctx.content?.trim() ?? '')) {
185
+ dc.log(`feishu[${dc.account.accountId}]: abort message detected, using plain-text dispatch`);
186
+ log.info('abort message detected, using plain-text dispatch');
187
+ await (0, dispatch_commands_1.dispatchSystemCommand)(dc, ctxPayload, replyToMessageId);
188
+ return;
189
+ }
190
+ const effectiveSessionKey = dc.threadSessionKey ?? dc.route.sessionKey;
191
+ const toolUseDisplay = (0, tool_use_config_1.resolveToolUseDisplayConfig)({
192
+ cfg: dc.accountScopedCfg,
193
+ feishuCfg: dc.account.config,
194
+ agentId: dc.route.agentId,
195
+ sessionKey: effectiveSessionKey,
196
+ body: dc.ctx.content,
197
+ });
198
+ if (toolUseDisplay.showToolUse) {
199
+ (0, tool_use_trace_store_1.startToolUseTraceRun)(effectiveSessionKey);
200
+ }
201
+ else {
202
+ (0, tool_use_trace_store_1.clearToolUseTraceRun)(effectiveSessionKey);
203
+ }
204
+ const { dispatcher, replyOptions, markDispatchIdle, markFullyComplete, abortCard } = (0, reply_dispatcher_1.createFeishuReplyDispatcher)({
205
+ cfg: dc.accountScopedCfg,
206
+ agentId: dc.route.agentId,
207
+ chatId: dc.ctx.chatId,
208
+ sessionKey: effectiveSessionKey,
209
+ replyToMessageId: replyToMessageId ?? dc.ctx.messageId,
210
+ accountId: dc.account.accountId,
211
+ chatType: dc.ctx.chatType,
212
+ skipTyping,
213
+ replyInThread: routing.replyInThread,
214
+ threadId: routing.threadId,
215
+ toolUseDisplay,
216
+ });
217
+ // Create an AbortController so the abort fast-path can cancel the
218
+ // underlying LLM request (not just the streaming card UI).
219
+ const abortController = new AbortController();
220
+ // Register the active dispatcher so the monitor abort fast-path can
221
+ // terminate the streaming card before this task completes.
222
+ const queueKey = (0, chat_queue_1.buildQueueKey)(dc.account.accountId, dc.ctx.chatId, dc.ctx.threadId);
223
+ (0, chat_queue_1.registerActiveDispatcher)(queueKey, { abortCard, abortController });
224
+ dc.log(`feishu[${dc.account.accountId}]: dispatching to agent (session=${effectiveSessionKey})`);
225
+ log.info(`dispatching to agent (session=${effectiveSessionKey})`);
226
+ // Attach the resolved bot-peer (if any) so the outbound `ensureMention`
227
+ // backstop can guarantee an @ even when the LLM forgets. Resolved by the
228
+ // caller (dispatchToAgent) and decoupled from thread routing. Undefined →
229
+ // pure no-op.
230
+ const withBotPeer = botPeer
231
+ ? (fn) => (0, bot_peer_context_1.runWithBotPeerContext)(botPeer, fn)
232
+ : (fn) => fn();
233
+ try {
234
+ const { queuedFinal, counts } = await withBotPeer(() => dc.core.channel.reply.dispatchReplyFromConfig({
235
+ ctx: ctxPayload,
236
+ cfg: dc.accountScopedCfg,
237
+ dispatcher,
238
+ replyOptions: {
239
+ ...replyOptions,
240
+ abortSignal: abortController.signal,
241
+ ...(skillFilter ? { skillFilter } : {}),
242
+ },
243
+ }));
244
+ // Wait for all enqueued deliver() calls in the SDK's sendChain to
245
+ // complete before marking the dispatch as done. Without this,
246
+ // dispatchReplyFromConfig() may return while the final deliver() is
247
+ // still pending in the Promise chain, causing markFullyComplete() to
248
+ // block it and leaving completedText incomplete — which in turn makes
249
+ // the streaming card's final update show truncated content.
250
+ //
251
+ // Run under withBotPeer too so any deliveries flushed during waitForIdle
252
+ // still see the peer context.
253
+ await withBotPeer(() => dispatcher.waitForIdle());
254
+ markFullyComplete();
255
+ markDispatchIdle();
256
+ // Clean up consumed history entries
257
+ if (dc.isGroup && historyKey && chatHistories) {
258
+ (0, reply_history_1.clearHistoryEntriesIfEnabled)({
259
+ historyMap: chatHistories,
260
+ historyKey,
261
+ limit: historyLimit,
262
+ });
263
+ }
264
+ dc.log(`feishu[${dc.account.accountId}]: dispatch complete (queuedFinal=${queuedFinal}, replies=${counts.final})`);
265
+ log.info(`dispatch complete (replies=${counts.final}, elapsed=${(0, lark_ticket_1.ticketElapsed)()}ms)`);
266
+ }
267
+ finally {
268
+ (0, chat_queue_1.unregisterActiveDispatcher)(queueKey);
269
+ }
270
+ }
271
+ // ---------------------------------------------------------------------------
272
+ // Public API
273
+ // ---------------------------------------------------------------------------
274
+ async function dispatchToAgent(params) {
275
+ // 1. Derive shared context (including route resolution + system event)
276
+ const dc = (0, dispatch_context_1.buildDispatchContext)(params);
277
+ // 1a. Reply routing: handles topic-group thread inference (may mutate dc)
278
+ // and bot-peer suppression for bot→bot group scenarios (#32980).
279
+ // See src/messaging/inbound/bot-content.ts for the full rationale.
280
+ const replyInThreadConfig = params.groupConfig?.replyInThread ??
281
+ params.defaultGroupConfig?.replyInThread ??
282
+ dc.account.config?.replyInThread;
283
+ const routing = await (0, bot_content_1.resolveFeishuReplyRouting)(dc, { replyInThreadConfig });
284
+ // 1b. Resolve thread session isolation (async: may query group info API)
285
+ if (dc.isThread && dc.ctx.threadId) {
286
+ dc.threadSessionKey = await (0, dispatch_context_1.resolveThreadSessionKey)({
287
+ accountScopedCfg: dc.accountScopedCfg,
288
+ account: dc.account,
289
+ chatId: dc.ctx.chatId,
290
+ threadId: dc.ctx.threadId,
291
+ baseSessionKey: dc.route.sessionKey,
292
+ });
293
+ }
294
+ // Consume any pending mention sentinels for this thread. Take and
295
+ // delete is one shot per inbound — capture once, hand to both body
296
+ // builders below.
297
+ const sentinelKey = (0, chat_queue_1.threadScopedKey)(dc.ctx.chatId, dc.isThread ? dc.ctx.threadId : undefined);
298
+ const sentinels = (0, sentinel_store_1.getSentinelStore)(dc.account.accountId).consumeSentinels(sentinelKey);
299
+ // 3. Build annotated message body
300
+ const messageBody = (0, dispatch_builders_1.buildMessageBody)(params.ctx, params.quotedContent, sentinels);
301
+ // 4. Permission-error notification (optional side-effect).
302
+ // Isolated so a failure here does not block the main message dispatch.
303
+ // Skipped for comment targets: the streaming card dispatcher inside
304
+ // dispatchPermissionNotification sends via IM APIs which don't
305
+ // understand comment:... targets.
306
+ if (params.permissionError && !(0, comment_target_1.isCommentTarget)(dc.ctx.chatId)) {
307
+ try {
308
+ await (0, dispatch_commands_1.dispatchPermissionNotification)(dc, params.permissionError, params.replyToMessageId);
309
+ }
310
+ catch (err) {
311
+ dc.error(`feishu[${dc.account.accountId}]: permission notification failed, continuing: ${String(err)}`);
312
+ }
313
+ }
314
+ // 5. Build main envelope (with group chat history)
315
+ const { combinedBody, historyKey } = (0, dispatch_builders_1.buildEnvelopeWithHistory)(dc, messageBody, params.chatHistories, params.historyLimit);
316
+ // 6. Build BodyForAgent with mention annotation (if any).
317
+ // SDK >= 2026.2.10 no longer falls back to Body for BodyForAgent,
318
+ // so we must set it explicitly to preserve the annotation.
319
+ const bodyForAgent = (0, dispatch_builders_1.buildBodyForAgent)(params.ctx, sentinels);
320
+ // 7. Build InboundHistory for SDK metadata injection (>= 2026.2.10).
321
+ // The SDK's buildInboundUserContextPrefix renders these as structured
322
+ // JSON blocks; earlier SDK versions simply ignore unknown fields.
323
+ const threadHistoryKey = (0, chat_queue_1.threadScopedKey)(dc.ctx.chatId, dc.isThread ? dc.ctx.threadId : undefined);
324
+ const inboundHistory = dc.isGroup && params.chatHistories && params.historyLimit > 0
325
+ ? (params.chatHistories.get(threadHistoryKey) ?? []).map((entry) => ({
326
+ sender: entry.sender,
327
+ body: entry.body,
328
+ timestamp: entry.timestamp ?? Date.now(),
329
+ }))
330
+ : undefined;
331
+ // 8. Build inbound context payload
332
+ const isBareNewOrReset = /^\/(?:new|reset)\s*$/i.test((params.ctx.content ?? '').trim());
333
+ const configuredGroupPrompt = dc.isGroup
334
+ ? params.groupConfig?.systemPrompt?.trim() || params.defaultGroupConfig?.systemPrompt?.trim() || undefined
335
+ : undefined;
336
+ // In group chats, always inject bot-at-bot guidance (self open_id + @
337
+ // delivery rules + loop hygiene), merged with any operator-configured
338
+ // group prompt. Complements the deterministic ensureMention safety net.
339
+ const groupSystemPrompt = dc.isGroup
340
+ ? (0, dispatch_builders_1.buildFeishuGroupSystemPrompt)(configuredGroupPrompt, params.botOpenId)
341
+ : undefined;
342
+ const originatingTo = isBareNewOrReset && dc.isThread
343
+ ? (0, targets_1.encodeFeishuRouteTarget)({
344
+ target: dc.feishuTo,
345
+ replyToMessageId: params.replyToMessageId ?? params.ctx.messageId,
346
+ threadId: dc.ctx.threadId,
347
+ })
348
+ : undefined;
349
+ const ctxPayload = (0, dispatch_builders_1.buildInboundPayload)(dc, {
350
+ body: combinedBody,
351
+ bodyForAgent,
352
+ rawBody: params.ctx.content,
353
+ commandBody: params.ctx.content,
354
+ originatingTo,
355
+ senderName: params.ctx.senderName ?? params.ctx.senderId,
356
+ senderId: params.ctx.senderId,
357
+ messageSid: params.ctx.messageId,
358
+ wasMentioned: (0, mention_1.mentionedBot)(params.ctx) ||
359
+ (params.ctx.mentionAll &&
360
+ (0, gate_1.resolveRespondToMentionAll)({
361
+ groupConfig: params.groupConfig,
362
+ defaultConfig: params.defaultGroupConfig,
363
+ accountFeishuCfg: params.account.config,
364
+ })),
365
+ replyToBody: params.quotedContent,
366
+ inboundHistory,
367
+ extraFields: {
368
+ ...params.mediaPayload,
369
+ ...(params.extraInboundFields ?? {}),
370
+ ...(0, dispatch_builders_1.buildFeishuIdentityFields)(params.ctx, params.botOpenId),
371
+ ...(groupSystemPrompt ? { GroupSystemPrompt: groupSystemPrompt } : {}),
372
+ ...(dc.ctx.threadId ? { MessageThreadId: dc.ctx.threadId } : {}),
373
+ },
374
+ });
375
+ // 9a. Intercept /feishu commands for i18n multi-locale card dispatch
376
+ // Must run BEFORE the SDK command check — the SDK does not recognise
377
+ // plugin-registered commands via isControlCommandMessage, so
378
+ // /feishu_* falls through to the AI agent otherwise.
379
+ // Skipped for comment targets: comment text won't match /feishu_*
380
+ // patterns in practice, and sendCardFeishu/sendMessageFeishu can't
381
+ // deliver to comment:... targets.
382
+ const contentTrimmed = (params.ctx.content ?? '').trim();
383
+ const isCommentFlow = (0, comment_target_1.isCommentTarget)(dc.ctx.chatId);
384
+ const isDoctorCommand = !isCommentFlow && /^\/feishu[_ ]doctor\s*$/i.test(contentTrimmed);
385
+ const isAuthCommand = !isCommentFlow && /^\/feishu[_ ](?:auth|onboarding)\s*$/i.test(contentTrimmed);
386
+ const isStartCommand = !isCommentFlow && /^\/feishu[_ ]start\s*$/i.test(contentTrimmed);
387
+ const isHelpCommand = !isCommentFlow && /^\/feishu(?:[_ ]help)?\s*$/i.test(contentTrimmed);
388
+ const i18nCommandName = isDoctorCommand
389
+ ? 'doctor'
390
+ : isAuthCommand
391
+ ? 'auth'
392
+ : isStartCommand
393
+ ? 'start'
394
+ : isHelpCommand
395
+ ? 'help'
396
+ : null;
397
+ if (i18nCommandName) {
398
+ dc.log(`feishu[${dc.account.accountId}]: ${i18nCommandName} command detected, using i18n dispatch`);
399
+ log.info(`${i18nCommandName} command detected, using i18n dispatch`);
400
+ try {
401
+ let i18nTexts;
402
+ if (isDoctorCommand) {
403
+ i18nTexts = await (0, doctor_1.runFeishuDoctorI18n)(dc.accountScopedCfg, dc.account.accountId);
404
+ }
405
+ else if (isAuthCommand) {
406
+ i18nTexts = await (0, auth_1.runFeishuAuthI18n)(dc.accountScopedCfg);
407
+ }
408
+ else if (isStartCommand) {
409
+ i18nTexts = (0, index_1.runFeishuStartI18n)(dc.accountScopedCfg);
410
+ }
411
+ else {
412
+ i18nTexts = (0, index_1.getFeishuHelpI18n)();
413
+ }
414
+ const card = (0, send_1.buildI18nMarkdownCard)(i18nTexts);
415
+ await (0, send_1.sendCardFeishu)({
416
+ cfg: dc.accountScopedCfg,
417
+ to: dc.ctx.chatId,
418
+ card,
419
+ replyToMessageId: params.replyToMessageId ?? dc.ctx.messageId,
420
+ accountId: dc.account.accountId,
421
+ replyInThread: routing.replyInThread,
422
+ });
423
+ }
424
+ catch (err) {
425
+ const errMsg = err instanceof Error ? err.message : String(err);
426
+ dc.error(`feishu[${dc.account.accountId}]: ${i18nCommandName} i18n dispatch failed: ${errMsg}`);
427
+ await (0, send_1.sendMessageFeishu)({
428
+ cfg: dc.accountScopedCfg,
429
+ to: dc.ctx.chatId,
430
+ text: `${i18nCommandName} failed: ${errMsg}`,
431
+ replyToMessageId: params.replyToMessageId ?? dc.ctx.messageId,
432
+ accountId: dc.account.accountId,
433
+ replyInThread: routing.replyInThread,
434
+ });
435
+ }
436
+ return;
437
+ }
438
+ // 8. Dispatch: system command vs. normal message
439
+ // Comment targets always go to normal dispatch — system command
440
+ // delivery uses sendMessageFeishu which can't reach comment threads.
441
+ const isCommand = !isCommentFlow &&
442
+ dc.core.channel.commands.isControlCommandMessage(params.ctx.content, params.accountScopedCfg);
443
+ // Resolve per-group skill filter (per-group > default "*")
444
+ const skillFilter = dc.isGroup ? (params.groupConfig?.skills ?? params.defaultGroupConfig?.skills) : undefined;
445
+ if (isCommand) {
446
+ await (0, dispatch_commands_1.dispatchSystemCommand)(dc, ctxPayload, params.replyToMessageId);
447
+ // /new and /reset explicitly start a new session — clear pending history
448
+ if (isBareNewOrReset && dc.isGroup && historyKey && params.chatHistories) {
449
+ (0, reply_history_1.clearHistoryEntriesIfEnabled)({
450
+ historyMap: params.chatHistories,
451
+ historyKey,
452
+ limit: params.historyLimit,
453
+ });
454
+ }
455
+ }
456
+ else {
457
+ // Normal message dispatch; history cleanup happens inside.
458
+ // System commands intentionally skip history cleanup — command handlers
459
+ // don't consume history context, so entries are preserved for the next
460
+ // normal message.
461
+ // A human asking the bots to stop ("中断对话", "stop talking", …) must NOT
462
+ // get a forced peer-@: the deterministic ensureMention backstop would
463
+ // re-wake the peer bot and defeat the interruption. Skip peer resolution
464
+ // on stop-intent; the kickoff/continue path ("你们辩论") is unaffected.
465
+ const botPeer = (0, abort_detect_1.isConversationStopIntent)(dc.ctx.content ?? '')
466
+ ? undefined
467
+ : (0, bot_content_1.resolveBotPeerForMention)({
468
+ isGroup: dc.isGroup,
469
+ senderIsBot: dc.ctx.senderIsBot,
470
+ senderId: dc.ctx.senderId,
471
+ senderName: dc.ctx.senderName ?? undefined,
472
+ mentions: dc.ctx.mentions,
473
+ botOpenId: params.botOpenId,
474
+ });
475
+ await dispatchNormalMessage(dc, ctxPayload, routing, params.chatHistories, historyKey, params.historyLimit, params.replyToMessageId, skillFilter, params.skipTyping, botPeer);
476
+ }
477
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * Context enrichment for inbound Feishu messages.
6
+ *
7
+ * Enrichment phases:
8
+ *
9
+ * - **resolveSenderInfo** (lightweight, before gate) — resolves sender
10
+ * display name and tracks permission errors.
11
+ * - **prefetchUserNames** (after gate, before content resolution) — batch
12
+ * pre-warm the account-scoped user-name cache for the sender and all
13
+ * non-bot mentions so that downstream merge_forward expansion and
14
+ * quoted-message formatting can read names synchronously.
15
+ * - **resolveMedia** (after gate) — downloads binary media attachments
16
+ * using ResourceDescriptors from the converter phase.
17
+ * - **resolveQuotedContent** (after gate) — fetches the replied-to
18
+ * message text for context.
19
+ *
20
+ * Note: merge_forward expansion for the primary message is now handled
21
+ * at parse time in {@link parseMessageEvent}. Quoted merge_forward
22
+ * messages are still expanded here via {@link resolveQuotedContent}.
23
+ */
24
+ import type { ClawdbotConfig } from 'openclaw/plugin-sdk';
25
+ import type { FeishuMediaInfo, MessageContext } from '../types';
26
+ import type { LarkAccount } from '../../core/types';
27
+ import type { PermissionError } from './permission';
28
+ /**
29
+ * Resolve the sender display name and track permission errors.
30
+ *
31
+ * This must run before the gate check because per-group sender
32
+ * allowlists may match on senderName.
33
+ */
34
+ export declare function resolveSenderInfo(params: {
35
+ ctx: MessageContext;
36
+ account: LarkAccount;
37
+ log: (...args: unknown[]) => void;
38
+ }): Promise<{
39
+ ctx: MessageContext;
40
+ permissionError?: PermissionError;
41
+ }>;
42
+ /**
43
+ * Batch-prefetch user display names for the sender and all non-bot
44
+ * mentions. Mention names that are already known from the event payload
45
+ * are written into the cache for free.
46
+ */
47
+ export declare function prefetchUserNames(params: {
48
+ ctx: MessageContext;
49
+ account: LarkAccount;
50
+ log: (...args: unknown[]) => void;
51
+ }): Promise<void>;
52
+ /** Result of media resolution: envelope payload + per-file mapping. */
53
+ export interface ResolveMediaResult {
54
+ payload: Record<string, unknown>;
55
+ mediaList: FeishuMediaInfo[];
56
+ }
57
+ /**
58
+ * Download and save binary media attachments (images, files, audio,
59
+ * video, stickers) from the inbound message.
60
+ *
61
+ * Uses ResourceDescriptors extracted by content converters during the
62
+ * parse phase — no re-parsing of rawMessage.content needed.
63
+ *
64
+ * Returns a payload object whose keys (`MediaPath`, `MediaType`, …)
65
+ * are spread directly into the agent envelope, plus the raw mediaList
66
+ * for content substitution.
67
+ */
68
+ export declare function resolveMedia(params: {
69
+ ctx: MessageContext;
70
+ /** account 级别的 ClawdbotConfig(channels.feishu 已替换为 per-account 合并后的配置) */
71
+ accountScopedCfg: ClawdbotConfig;
72
+ account: LarkAccount;
73
+ log: (...args: unknown[]) => void;
74
+ }): Promise<ResolveMediaResult>;
75
+ /**
76
+ * Replace Feishu file-key references in message content with actual
77
+ * local file paths after download.
78
+ *
79
+ * This is critical for:
80
+ * - **Images / stickers**: The SDK's `detectAndLoadPromptImages` scans
81
+ * the prompt text for local file paths with image extensions.
82
+ * - **Audio / video / files**: Gives the AI meaningful context about
83
+ * what was received (the SDK reads these via `MediaPath` directly,
84
+ * but the text body should still reflect the actual attachments).
85
+ */
86
+ export declare function substituteMediaPaths(content: string, mediaList: FeishuMediaInfo[]): string;
87
+ /**
88
+ * Fetch the text content of the message that the user replied to.
89
+ *
90
+ * If the quoted message is itself a merge_forward, its sub-messages are
91
+ * fetched and formatted as a single text block.
92
+ *
93
+ * Returns `"senderName: content"` when the sender name is available so
94
+ * the AI knows who originally wrote the quoted message.
95
+ */
96
+ export declare function resolveQuotedContent(params: {
97
+ ctx: MessageContext;
98
+ /** account 级别的 ClawdbotConfig(channels.feishu 已替换为 per-account 合并后的配置) */
99
+ accountScopedCfg: ClawdbotConfig;
100
+ account: LarkAccount;
101
+ log: (...args: unknown[]) => void;
102
+ }): Promise<string | undefined>;