@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,184 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * Multi-account isolation checks.
7
+ *
8
+ * Detects potentially unsafe configurations where multiple Feishu accounts
9
+ * belonging to different tenants (different appId) share the default agent
10
+ * without proper isolation via agents + bindings.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.checkMultiAccountIsolation = checkMultiAccountIsolation;
14
+ exports.needsDmScopeFix = needsDmScopeFix;
15
+ exports.getDmScopeFixCommand = getDmScopeFixCommand;
16
+ exports.formatIsolationWarning = formatIsolationWarning;
17
+ exports.generateIsolationFixCommands = generateIsolationFixCommands;
18
+ exports.generateSharedAgentCommands = generateSharedAgentCommands;
19
+ exports.collectIsolationWarnings = collectIsolationWarnings;
20
+ exports.emitSecurityWarnings = emitSecurityWarnings;
21
+ const accounts_1 = require("./accounts.js");
22
+ // ---------------------------------------------------------------------------
23
+ // Check logic
24
+ // ---------------------------------------------------------------------------
25
+ /**
26
+ * Diagnose whether multiple enabled accounts from different tenants
27
+ * are properly isolated via agent bindings.
28
+ */
29
+ function checkMultiAccountIsolation(cfg) {
30
+ const accounts = (0, accounts_1.getEnabledLarkAccounts)(cfg);
31
+ if (accounts.length <= 1)
32
+ return { mode: 'not-applicable' };
33
+ const appIds = new Set(accounts.map((a) => (a.configured ? a.appId : undefined)).filter((id) => !!id));
34
+ if (appIds.size <= 1)
35
+ return { mode: 'not-applicable' };
36
+ const feishuBindings = cfg.bindings?.filter((b) => b.match?.channel === 'feishu' && b.match?.accountId);
37
+ if (!feishuBindings || feishuBindings.length === 0) {
38
+ return { mode: 'shared-implicit', accounts, unboundAccounts: accounts };
39
+ }
40
+ const boundAccountIds = new Set(feishuBindings.map((b) => b.match.accountId));
41
+ const unboundAccounts = accounts.filter((a) => !boundAccountIds.has(a.accountId));
42
+ if (unboundAccounts.length > 0) {
43
+ return { mode: 'shared-implicit', accounts, unboundAccounts };
44
+ }
45
+ const agentIds = new Set(feishuBindings.map((b) => b.agentId));
46
+ if (agentIds.size === 1) {
47
+ return {
48
+ mode: 'shared-explicit',
49
+ accounts,
50
+ sharedAgentId: agentIds.values().next().value,
51
+ };
52
+ }
53
+ return { mode: 'isolated', accounts };
54
+ }
55
+ // ---------------------------------------------------------------------------
56
+ // Helpers
57
+ // ---------------------------------------------------------------------------
58
+ function accountNames(accounts) {
59
+ return accounts.map((a) => a.name ?? a.accountId).join('、');
60
+ }
61
+ function isMultiTenant(cfg) {
62
+ const accounts = (0, accounts_1.getEnabledLarkAccounts)(cfg);
63
+ if (accounts.length <= 1)
64
+ return false;
65
+ const appIds = new Set(accounts.map((a) => (a.configured ? a.appId : undefined)).filter((id) => !!id));
66
+ return appIds.size > 1;
67
+ }
68
+ // ---------------------------------------------------------------------------
69
+ // Session dmScope
70
+ // ---------------------------------------------------------------------------
71
+ const RECOMMENDED_DM_SCOPE = 'per-account-channel-peer';
72
+ /**
73
+ * Check whether `session.dmScope` is set to per-account isolation.
74
+ *
75
+ * Without this setting, different bots talking to the same user share
76
+ * the same session — even if agent bindings are configured.
77
+ */
78
+ function needsDmScopeFix(cfg) {
79
+ if (!isMultiTenant(cfg))
80
+ return false;
81
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
82
+ return cfg.session?.dmScope !== RECOMMENDED_DM_SCOPE;
83
+ }
84
+ /** Return the fix command string, or null if not needed. */
85
+ function getDmScopeFixCommand(cfg) {
86
+ if (!needsDmScopeFix(cfg))
87
+ return null;
88
+ return `openclaw config set session.dmScope "${RECOMMENDED_DM_SCOPE}"`;
89
+ }
90
+ /** User-facing dmScope warning block (markdown). */
91
+ function formatDmScopeWarning() {
92
+ return ('⚠️ **私聊消息串混**\n\n' +
93
+ '当同一个用户同时使用多个机器人时,不同机器人的私聊消息会混在同一段对话里,' +
94
+ '导致 AI 无法区分用户在跟哪个机器人说话。');
95
+ }
96
+ // ---------------------------------------------------------------------------
97
+ // Warning text for /feishu doctor & /feishu start
98
+ // ---------------------------------------------------------------------------
99
+ /**
100
+ * Generate a combined warning block for doctor / start.
101
+ * Returns null when everything is fine.
102
+ */
103
+ function formatIsolationWarning(status, cfg) {
104
+ const sections = [];
105
+ // Agent sharing warning
106
+ if (status.mode === 'shared-implicit') {
107
+ const names = accountNames(status.accounts);
108
+ sections.push(`⚠️ **多个机器人共用记忆,对话内容可能互相可见**\n\n` +
109
+ `当前 ${status.accounts.length} 个飞书机器人(${names})共用同一个 AI 记忆。\n` +
110
+ `用户 A 跟机器人「${status.accounts[0].name ?? status.accounts[0].accountId}」说的话,` +
111
+ `可能出现在机器人「${status.accounts[1]?.name ?? status.accounts[1]?.accountId ?? '...'}」的回复中。\n\n` +
112
+ `👉 发送 **/feishu isolate** 一键查看修复方案`);
113
+ }
114
+ // dmScope warning
115
+ if (cfg && needsDmScopeFix(cfg)) {
116
+ sections.push(formatDmScopeWarning() + '\n\n' + '👉 发送 **/feishu isolate** 一键查看修复方案');
117
+ }
118
+ if (sections.length === 0)
119
+ return null;
120
+ return sections.join('\n\n---\n\n');
121
+ }
122
+ // ---------------------------------------------------------------------------
123
+ // Fix command generation
124
+ // ---------------------------------------------------------------------------
125
+ /**
126
+ * Generate `openclaw config set` commands for per-account isolation.
127
+ */
128
+ function generateIsolationFixCommands(cfg) {
129
+ const status = checkMultiAccountIsolation(cfg);
130
+ if (status.mode !== 'shared-implicit')
131
+ return null;
132
+ const accounts = status.accounts;
133
+ const commands = [];
134
+ const agentsList = accounts.map((a) => ({
135
+ id: `feishu-${a.accountId}`,
136
+ name: `飞书 ${a.name ?? a.accountId}`,
137
+ }));
138
+ commands.push(`openclaw config set agents.list '${JSON.stringify(agentsList)}' --json`);
139
+ const bindings = accounts.map((a) => ({
140
+ match: { channel: 'feishu', accountId: a.accountId },
141
+ agentId: `feishu-${a.accountId}`,
142
+ }));
143
+ commands.push(`openclaw config set bindings '${JSON.stringify(bindings)}' --json`);
144
+ const dmScopeCmd = getDmScopeFixCommand(cfg);
145
+ if (dmScopeCmd)
146
+ commands.push(dmScopeCmd);
147
+ commands.push('openclaw gateway restart');
148
+ const previewLines = accounts.map((a) => ` ${a.name ?? a.accountId} → 独立记忆(feishu-${a.accountId})`);
149
+ return { commands, preview: previewLines.join('\n') };
150
+ }
151
+ /**
152
+ * Generate commands for explicitly sharing the same agent across accounts.
153
+ */
154
+ function generateSharedAgentCommands(cfg) {
155
+ const status = checkMultiAccountIsolation(cfg);
156
+ if (status.mode !== 'shared-implicit')
157
+ return null;
158
+ const accounts = status.accounts;
159
+ const commands = [];
160
+ const bindings = accounts.map((a) => ({
161
+ match: { channel: 'feishu', accountId: a.accountId },
162
+ agentId: 'default',
163
+ }));
164
+ commands.push(`openclaw config set bindings '${JSON.stringify(bindings)}' --json`);
165
+ const dmScopeCmd = getDmScopeFixCommand(cfg);
166
+ if (dmScopeCmd)
167
+ commands.push(dmScopeCmd);
168
+ commands.push('openclaw gateway restart');
169
+ const previewLines = accounts.map((a) => ` ${a.name ?? a.accountId} → 共用记忆(default)`);
170
+ return { commands, preview: previewLines.join('\n') };
171
+ }
172
+ // ---------------------------------------------------------------------------
173
+ // collectWarnings adapter (for SDK security.collectWarnings)
174
+ // ---------------------------------------------------------------------------
175
+ function collectIsolationWarnings(_cfg) {
176
+ // TODO: 产品明确多账号隔离方案后再透出告警
177
+ return [];
178
+ }
179
+ // ---------------------------------------------------------------------------
180
+ // Startup log
181
+ // ---------------------------------------------------------------------------
182
+ function emitSecurityWarnings(_cfg, _logger) {
183
+ // TODO: 产品明确多账号隔离方案后再透出告警
184
+ }
@@ -0,0 +1,22 @@
1
+ /** @internal — test-only reset. */
2
+ export declare function _resetShutdownHooks(): void;
3
+ /**
4
+ * Register a cleanup callback to run during graceful shutdown.
5
+ *
6
+ * @param key - Unique identifier for this hook (duplicate keys overwrite).
7
+ * @param cleanup - Async function to execute on shutdown.
8
+ * @returns An unregister function — call it when the resource is
9
+ * released normally (e.g. card streaming completes).
10
+ */
11
+ export declare function registerShutdownHook(key: string, cleanup: () => Promise<void>): () => void;
12
+ /**
13
+ * Drain all registered shutdown hooks (best-effort, bounded by deadline).
14
+ *
15
+ * @param opts - Optional configuration.
16
+ * @param opts.deadlineMs - Maximum time to wait for all hooks (default 5000).
17
+ * @param opts.log - Logger function for progress/error output.
18
+ */
19
+ export declare function drainShutdownHooks(opts?: {
20
+ deadlineMs?: number;
21
+ log?: (...args: unknown[]) => void;
22
+ }): Promise<void>;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ // SPDX-License-Identifier: MIT
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports._resetShutdownHooks = _resetShutdownHooks;
5
+ exports.registerShutdownHook = registerShutdownHook;
6
+ exports.drainShutdownHooks = drainShutdownHooks;
7
+ /**
8
+ * Process-level graceful shutdown hook registry.
9
+ *
10
+ * Provides a singleton Map of async cleanup callbacks, drained
11
+ * during graceful shutdown by the channel monitor.
12
+ */
13
+ const hooks = new Map();
14
+ /** @internal — test-only reset. */
15
+ function _resetShutdownHooks() {
16
+ hooks.clear();
17
+ }
18
+ /**
19
+ * Register a cleanup callback to run during graceful shutdown.
20
+ *
21
+ * @param key - Unique identifier for this hook (duplicate keys overwrite).
22
+ * @param cleanup - Async function to execute on shutdown.
23
+ * @returns An unregister function — call it when the resource is
24
+ * released normally (e.g. card streaming completes).
25
+ */
26
+ function registerShutdownHook(key, cleanup) {
27
+ hooks.set(key, cleanup);
28
+ return () => {
29
+ hooks.delete(key);
30
+ };
31
+ }
32
+ /**
33
+ * Drain all registered shutdown hooks (best-effort, bounded by deadline).
34
+ *
35
+ * @param opts - Optional configuration.
36
+ * @param opts.deadlineMs - Maximum time to wait for all hooks (default 5000).
37
+ * @param opts.log - Logger function for progress/error output.
38
+ */
39
+ async function drainShutdownHooks(opts) {
40
+ if (hooks.size === 0)
41
+ return;
42
+ const log = opts?.log;
43
+ const deadline = opts?.deadlineMs ?? 5000;
44
+ log?.(`graceful shutdown: draining ${hooks.size} cleanup hook(s)`);
45
+ const entries = Array.from(hooks.entries());
46
+ hooks.clear();
47
+ const promises = entries.map(async ([key, cleanup]) => {
48
+ try {
49
+ await cleanup();
50
+ log?.(`graceful shutdown: hook "${key}" done`);
51
+ }
52
+ catch (err) {
53
+ log?.(`graceful shutdown: hook "${key}" failed: ${String(err)}`);
54
+ }
55
+ });
56
+ let timer;
57
+ const timeoutPromise = new Promise((resolve) => {
58
+ timer = setTimeout(resolve, deadline);
59
+ });
60
+ await Promise.race([Promise.allSettled(promises).then(() => clearTimeout(timer)), timeoutPromise]);
61
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * Synthetic IM target utilities.
6
+ *
7
+ * Some inbound flows (VC meeting-invited, other service-triggered events)
8
+ * do not map to a real IM chat — there is no chat_id / open_id the agent
9
+ * should send messages into. To keep the dispatch pipeline uniform we give
10
+ * these flows a sentinel chatId ("synthetic:<kind>") and teach outbound
11
+ * deliverers to short-circuit whenever they see this prefix. This is the
12
+ * same pattern used by `core/comment-target.ts` for Drive comment threads.
13
+ */
14
+ /** Sentinel chatId for VC `vc.bot.meeting_invited_v1` synthetic inbound. */
15
+ export declare const SYNTHETIC_VC_CHAT_ID = "synthetic:vc-invited";
16
+ /**
17
+ * The `chatType` stamped on synthetic VC contexts.
18
+ *
19
+ * `MessageContext.chatType` is currently typed as `'p2p' | 'group'` across
20
+ * the plugin and widening that union touches every downstream signature.
21
+ * 'p2p' is the closest match (single-peer, non-group) and the outbound
22
+ * short-circuit gates on the sentinel chatId — not the chatType — so this
23
+ * choice does not produce any DMs on its own.
24
+ *
25
+ * TODO(synthetic-target): widen MessageContext.chatType to include
26
+ * `synthetic` once downstream signatures are audited.
27
+ */
28
+ export declare const SYNTHETIC_VC_CHAT_TYPE: "p2p";
29
+ /**
30
+ * Return `true` when `target` is a synthetic sentinel that outbound
31
+ * deliverers should not try to send an IM message to.
32
+ */
33
+ export declare function isSyntheticTarget(target: string | undefined | null): boolean;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * Synthetic IM target utilities.
7
+ *
8
+ * Some inbound flows (VC meeting-invited, other service-triggered events)
9
+ * do not map to a real IM chat — there is no chat_id / open_id the agent
10
+ * should send messages into. To keep the dispatch pipeline uniform we give
11
+ * these flows a sentinel chatId ("synthetic:<kind>") and teach outbound
12
+ * deliverers to short-circuit whenever they see this prefix. This is the
13
+ * same pattern used by `core/comment-target.ts` for Drive comment threads.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.SYNTHETIC_VC_CHAT_TYPE = exports.SYNTHETIC_VC_CHAT_ID = void 0;
17
+ exports.isSyntheticTarget = isSyntheticTarget;
18
+ const SYNTHETIC_PREFIX = 'synthetic:';
19
+ /** Sentinel chatId for VC `vc.bot.meeting_invited_v1` synthetic inbound. */
20
+ exports.SYNTHETIC_VC_CHAT_ID = 'synthetic:vc-invited';
21
+ /**
22
+ * The `chatType` stamped on synthetic VC contexts.
23
+ *
24
+ * `MessageContext.chatType` is currently typed as `'p2p' | 'group'` across
25
+ * the plugin and widening that union touches every downstream signature.
26
+ * 'p2p' is the closest match (single-peer, non-group) and the outbound
27
+ * short-circuit gates on the sentinel chatId — not the chatType — so this
28
+ * choice does not produce any DMs on its own.
29
+ *
30
+ * TODO(synthetic-target): widen MessageContext.chatType to include
31
+ * `synthetic` once downstream signatures are audited.
32
+ */
33
+ exports.SYNTHETIC_VC_CHAT_TYPE = 'p2p';
34
+ /**
35
+ * Return `true` when `target` is a synthetic sentinel that outbound
36
+ * deliverers should not try to send an IM message to.
37
+ */
38
+ function isSyntheticTarget(target) {
39
+ return Boolean(target && target.startsWith(SYNTHETIC_PREFIX));
40
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * Feishu target ID parsing and formatting utilities.
6
+ *
7
+ * Feishu uses several namespaced identifier prefixes:
8
+ * - `oc_*` -- chat (group / DM) IDs
9
+ * - `ou_*` -- open user IDs
10
+ * - plain alphanumeric strings -- user IDs from the tenant directory
11
+ *
12
+ * This module provides helpers to detect, normalise, and format these IDs
13
+ * for both internal routing and outbound Feishu API calls.
14
+ */
15
+ import type { FeishuIdType } from './types';
16
+ /**
17
+ * Detect the Feishu ID type from a raw identifier string.
18
+ *
19
+ * Returns `null` when the string does not match any known pattern.
20
+ */
21
+ export declare function detectIdType(id: string): FeishuIdType | null;
22
+ /**
23
+ * Strip OpenClaw routing prefixes (`chat:`, `user:`, `open_id:`) from a
24
+ * raw target string, returning the bare Feishu identifier.
25
+ *
26
+ * Returns `null` when the input is empty or falsy.
27
+ */
28
+ export declare function normalizeFeishuTarget(raw: string): string | null;
29
+ export interface FeishuRouteTarget {
30
+ target: string;
31
+ replyToMessageId?: string;
32
+ threadId?: string;
33
+ }
34
+ export declare function parseFeishuRouteTarget(raw: string): FeishuRouteTarget;
35
+ export declare function encodeFeishuRouteTarget(params: {
36
+ target: string;
37
+ replyToMessageId?: string;
38
+ threadId?: string | number | null;
39
+ }): string;
40
+ /**
41
+ * Add the appropriate OpenClaw routing prefix to a bare Feishu identifier.
42
+ *
43
+ * When `type` is omitted, the prefix is inferred via `detectIdType`.
44
+ */
45
+ export declare function formatFeishuTarget(id: string, type?: FeishuIdType): string;
46
+ /**
47
+ * Determine the `receive_id_type` query parameter for the Feishu send-message
48
+ * API based on the target identifier.
49
+ */
50
+ export declare function resolveReceiveIdType(id: string): 'chat_id' | 'open_id' | 'user_id';
51
+ /**
52
+ * 规范化 message_id,去除合成后缀(如 `om_xxx:auth-complete` → `om_xxx`)。
53
+ */
54
+ export declare function normalizeMessageId(messageId: string): string;
55
+ export declare function normalizeMessageId(messageId: string | undefined): string | undefined;
56
+ /**
57
+ * Return `true` when a raw string looks like it could be a Feishu target
58
+ * (either an OpenClaw-tagged form or a native prefix).
59
+ */
60
+ export declare function looksLikeFeishuId(raw: string): boolean;
@@ -0,0 +1,173 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * Feishu target ID parsing and formatting utilities.
7
+ *
8
+ * Feishu uses several namespaced identifier prefixes:
9
+ * - `oc_*` -- chat (group / DM) IDs
10
+ * - `ou_*` -- open user IDs
11
+ * - plain alphanumeric strings -- user IDs from the tenant directory
12
+ *
13
+ * This module provides helpers to detect, normalise, and format these IDs
14
+ * for both internal routing and outbound Feishu API calls.
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.detectIdType = detectIdType;
18
+ exports.normalizeFeishuTarget = normalizeFeishuTarget;
19
+ exports.parseFeishuRouteTarget = parseFeishuRouteTarget;
20
+ exports.encodeFeishuRouteTarget = encodeFeishuRouteTarget;
21
+ exports.formatFeishuTarget = formatFeishuTarget;
22
+ exports.resolveReceiveIdType = resolveReceiveIdType;
23
+ exports.normalizeMessageId = normalizeMessageId;
24
+ exports.looksLikeFeishuId = looksLikeFeishuId;
25
+ // ---------------------------------------------------------------------------
26
+ // Known prefix patterns
27
+ // ---------------------------------------------------------------------------
28
+ const CHAT_PREFIX = 'oc_';
29
+ const OPEN_ID_PREFIX = 'ou_';
30
+ // Canonical routing prefixes used inside OpenClaw (not Feishu-native).
31
+ const TAG_CHAT = 'chat:';
32
+ const TAG_USER = 'user:';
33
+ const TAG_OPEN_ID = 'open_id:';
34
+ // Feishu channel prefix (used by SDK for some routing scenarios).
35
+ const TAG_FEISHU = 'feishu:';
36
+ const ROUTE_META_FRAGMENT_REPLY_TO = '__feishu_reply_to';
37
+ const ROUTE_META_FRAGMENT_THREAD_ID = '__feishu_thread_id';
38
+ // ---------------------------------------------------------------------------
39
+ // Detection
40
+ // ---------------------------------------------------------------------------
41
+ /**
42
+ * Detect the Feishu ID type from a raw identifier string.
43
+ *
44
+ * Returns `null` when the string does not match any known pattern.
45
+ */
46
+ function detectIdType(id) {
47
+ if (!id)
48
+ return null;
49
+ if (id.startsWith(CHAT_PREFIX))
50
+ return 'chat_id';
51
+ if (id.startsWith(OPEN_ID_PREFIX))
52
+ return 'open_id';
53
+ // Plain alphanumeric strings (no prefix) are treated as tenant user IDs.
54
+ if (/^[a-zA-Z0-9]+$/.test(id))
55
+ return 'user_id';
56
+ return null;
57
+ }
58
+ // ---------------------------------------------------------------------------
59
+ // Normalisation
60
+ // ---------------------------------------------------------------------------
61
+ /**
62
+ * Strip OpenClaw routing prefixes (`chat:`, `user:`, `open_id:`) from a
63
+ * raw target string, returning the bare Feishu identifier.
64
+ *
65
+ * Returns `null` when the input is empty or falsy.
66
+ */
67
+ function normalizeFeishuTarget(raw) {
68
+ if (!raw)
69
+ return null;
70
+ const trimmed = parseFeishuRouteTarget(raw).target.trim();
71
+ if (!trimmed)
72
+ return null;
73
+ // Handle Feishu channel prefix (e.g., "feishu:ou_xxx" -> "ou_xxx")
74
+ if (trimmed.startsWith(TAG_FEISHU)) {
75
+ const inner = trimmed.slice(TAG_FEISHU.length).trim();
76
+ if (inner)
77
+ return inner;
78
+ }
79
+ if (trimmed.startsWith(TAG_CHAT))
80
+ return trimmed.slice(TAG_CHAT.length);
81
+ if (trimmed.startsWith(TAG_USER))
82
+ return trimmed.slice(TAG_USER.length);
83
+ if (trimmed.startsWith(TAG_OPEN_ID))
84
+ return trimmed.slice(TAG_OPEN_ID.length);
85
+ return trimmed;
86
+ }
87
+ function parseFeishuRouteTarget(raw) {
88
+ const trimmed = raw.trim();
89
+ if (!trimmed)
90
+ return { target: '' };
91
+ const hashIndex = trimmed.indexOf('#');
92
+ if (hashIndex < 0)
93
+ return { target: trimmed };
94
+ const target = trimmed.slice(0, hashIndex).trim();
95
+ const fragment = trimmed.slice(hashIndex + 1).trim();
96
+ if (!fragment)
97
+ return { target };
98
+ const params = new URLSearchParams(fragment);
99
+ const replyToMessageId = normalizeMessageId(params.get(ROUTE_META_FRAGMENT_REPLY_TO)?.trim() || undefined);
100
+ const threadId = params.get(ROUTE_META_FRAGMENT_THREAD_ID)?.trim() || undefined;
101
+ return {
102
+ target,
103
+ ...(replyToMessageId ? { replyToMessageId } : {}),
104
+ ...(threadId ? { threadId } : {}),
105
+ };
106
+ }
107
+ function encodeFeishuRouteTarget(params) {
108
+ const target = params.target.trim();
109
+ if (!target)
110
+ return target;
111
+ const replyToMessageId = normalizeMessageId(params.replyToMessageId?.trim() || undefined);
112
+ const threadId = params.threadId != null && String(params.threadId).trim() !== '' ? String(params.threadId).trim() : undefined;
113
+ if (!replyToMessageId && !threadId)
114
+ return target;
115
+ const fragment = new URLSearchParams();
116
+ if (replyToMessageId)
117
+ fragment.set(ROUTE_META_FRAGMENT_REPLY_TO, replyToMessageId);
118
+ if (threadId)
119
+ fragment.set(ROUTE_META_FRAGMENT_THREAD_ID, threadId);
120
+ return `${target}#${fragment.toString()}`;
121
+ }
122
+ // ---------------------------------------------------------------------------
123
+ // Formatting
124
+ // ---------------------------------------------------------------------------
125
+ /**
126
+ * Add the appropriate OpenClaw routing prefix to a bare Feishu identifier.
127
+ *
128
+ * When `type` is omitted, the prefix is inferred via `detectIdType`.
129
+ */
130
+ function formatFeishuTarget(id, type) {
131
+ const resolved = type ?? detectIdType(id);
132
+ if (resolved === 'chat_id')
133
+ return `${TAG_CHAT}${id}`;
134
+ return `${TAG_USER}${id}`;
135
+ }
136
+ // ---------------------------------------------------------------------------
137
+ // API receive-ID resolution
138
+ // ---------------------------------------------------------------------------
139
+ /**
140
+ * Determine the `receive_id_type` query parameter for the Feishu send-message
141
+ * API based on the target identifier.
142
+ */
143
+ function resolveReceiveIdType(id) {
144
+ if (id.startsWith(CHAT_PREFIX))
145
+ return 'chat_id';
146
+ if (id.startsWith(OPEN_ID_PREFIX))
147
+ return 'open_id';
148
+ return 'open_id';
149
+ }
150
+ function normalizeMessageId(messageId) {
151
+ if (!messageId)
152
+ return undefined;
153
+ const colonIndex = messageId.indexOf(':');
154
+ if (colonIndex >= 0)
155
+ return messageId.slice(0, colonIndex);
156
+ return messageId;
157
+ }
158
+ // ---------------------------------------------------------------------------
159
+ // Quick predicate
160
+ // ---------------------------------------------------------------------------
161
+ /**
162
+ * Return `true` when a raw string looks like it could be a Feishu target
163
+ * (either an OpenClaw-tagged form or a native prefix).
164
+ */
165
+ function looksLikeFeishuId(raw) {
166
+ if (!raw)
167
+ return false;
168
+ return (raw.startsWith(TAG_CHAT) ||
169
+ raw.startsWith(TAG_USER) ||
170
+ raw.startsWith(TAG_OPEN_ID) ||
171
+ raw.startsWith(CHAT_PREFIX) ||
172
+ raw.startsWith(OPEN_ID_PREFIX));
173
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * UAT (User Access Token) persistent storage with cross-platform support.
6
+ *
7
+ * Stores OAuth token data using OS-native credential services so that tokens
8
+ * survive process restarts without introducing plain-text local files.
9
+ *
10
+ * Platform backends:
11
+ * macOS – Keychain Access via `security` CLI
12
+ * Linux – AES-256-GCM encrypted files (XDG_DATA_HOME)
13
+ * Windows – AES-256-GCM encrypted files (%LOCALAPPDATA%)
14
+ *
15
+ * Storage layout:
16
+ * Service = "openclaw-feishu-uat"
17
+ * Account = "{appId}:{userOpenId}"
18
+ * Password = JSON-serialised StoredUAToken
19
+ */
20
+ export interface StoredUAToken {
21
+ userOpenId: string;
22
+ appId: string;
23
+ accessToken: string;
24
+ refreshToken: string;
25
+ expiresAt: number;
26
+ refreshExpiresAt: number;
27
+ scope: string;
28
+ grantedAt: number;
29
+ }
30
+ /** Mask a token for safe logging: only the last 4 chars are visible. */
31
+ export declare function maskToken(token: string): string;
32
+ /**
33
+ * Read the stored UAT for a given (appId, userOpenId) pair.
34
+ * Returns `null` when no entry exists or the payload is unparseable.
35
+ */
36
+ export declare function getStoredToken(appId: string, userOpenId: string): Promise<StoredUAToken | null>;
37
+ /**
38
+ * Persist a UAT using the platform credential store.
39
+ *
40
+ * Overwrites any existing entry for the same (appId, userOpenId).
41
+ */
42
+ export declare function setStoredToken(token: StoredUAToken): Promise<void>;
43
+ /**
44
+ * Remove a stored UAT from the credential store.
45
+ */
46
+ export declare function removeStoredToken(appId: string, userOpenId: string): Promise<void>;
47
+ /**
48
+ * Determine the freshness of a stored token.
49
+ *
50
+ * - `"valid"` – access_token is still good (expires > 5 min from now)
51
+ * - `"needs_refresh"` – access_token expired/expiring but refresh_token is valid
52
+ * - `"expired"` – both tokens are expired; re-authorization required
53
+ */
54
+ export declare function tokenStatus(token: StoredUAToken): 'valid' | 'needs_refresh' | 'expired';