@lark-project/openclaw-lark-project 2026.3.131

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (368) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -0
  3. package/README.zh.md +80 -0
  4. package/dist/index.js +172 -0
  5. package/dist/index.js.map +7 -0
  6. package/dist/skills/feishu-bitable/SKILL.md +248 -0
  7. package/dist/skills/feishu-bitable/references/examples.md +813 -0
  8. package/dist/skills/feishu-bitable/references/field-properties.md +763 -0
  9. package/dist/skills/feishu-bitable/references/record-values.md +911 -0
  10. package/dist/skills/feishu-calendar/SKILL.md +244 -0
  11. package/dist/skills/feishu-channel-rules/SKILL.md +18 -0
  12. package/dist/skills/feishu-channel-rules/references/markdown-syntax.md +138 -0
  13. package/dist/skills/feishu-create-doc/SKILL.md +719 -0
  14. package/dist/skills/feishu-fetch-doc/SKILL.md +93 -0
  15. package/dist/skills/feishu-im-read/SKILL.md +163 -0
  16. package/dist/skills/feishu-project/SKILL.md +122 -0
  17. package/dist/skills/feishu-task/SKILL.md +293 -0
  18. package/dist/skills/feishu-troubleshoot/SKILL.md +70 -0
  19. package/dist/skills/feishu-update-doc/SKILL.md +285 -0
  20. package/dist/src/card/builder.js +293 -0
  21. package/dist/src/card/builder.js.map +7 -0
  22. package/dist/src/card/cardkit.js +126 -0
  23. package/dist/src/card/cardkit.js.map +7 -0
  24. package/dist/src/card/flush-controller.js +107 -0
  25. package/dist/src/card/flush-controller.js.map +7 -0
  26. package/dist/src/card/markdown-style.js +57 -0
  27. package/dist/src/card/markdown-style.js.map +7 -0
  28. package/dist/src/card/reply-dispatcher-types.js +39 -0
  29. package/dist/src/card/reply-dispatcher-types.js.map +7 -0
  30. package/dist/src/card/reply-dispatcher.js +245 -0
  31. package/dist/src/card/reply-dispatcher.js.map +7 -0
  32. package/dist/src/card/reply-mode.js +29 -0
  33. package/dist/src/card/reply-mode.js.map +7 -0
  34. package/dist/src/card/streaming-card-controller.js +653 -0
  35. package/dist/src/card/streaming-card-controller.js.map +7 -0
  36. package/dist/src/card/unavailable-guard.js +76 -0
  37. package/dist/src/card/unavailable-guard.js.map +7 -0
  38. package/dist/src/channel/abort-detect.js +79 -0
  39. package/dist/src/channel/abort-detect.js.map +7 -0
  40. package/dist/src/channel/chat-queue.js +50 -0
  41. package/dist/src/channel/chat-queue.js.map +7 -0
  42. package/dist/src/channel/config-adapter.js +89 -0
  43. package/dist/src/channel/config-adapter.js.map +7 -0
  44. package/dist/src/channel/directory.js +133 -0
  45. package/dist/src/channel/directory.js.map +7 -0
  46. package/dist/src/channel/event-handlers.js +175 -0
  47. package/dist/src/channel/event-handlers.js.map +7 -0
  48. package/dist/src/channel/monitor.js +108 -0
  49. package/dist/src/channel/monitor.js.map +7 -0
  50. package/dist/src/channel/onboarding-config.js +76 -0
  51. package/dist/src/channel/onboarding-config.js.map +7 -0
  52. package/dist/src/channel/onboarding-migrate.js +55 -0
  53. package/dist/src/channel/onboarding-migrate.js.map +7 -0
  54. package/dist/src/channel/onboarding.js +285 -0
  55. package/dist/src/channel/onboarding.js.map +7 -0
  56. package/dist/src/channel/plugin.js +260 -0
  57. package/dist/src/channel/plugin.js.map +7 -0
  58. package/dist/src/channel/probe.js +14 -0
  59. package/dist/src/channel/probe.js.map +7 -0
  60. package/dist/src/channel/types.js +1 -0
  61. package/dist/src/channel/types.js.map +7 -0
  62. package/dist/src/commands/auth.js +73 -0
  63. package/dist/src/commands/auth.js.map +7 -0
  64. package/dist/src/commands/diagnose.js +658 -0
  65. package/dist/src/commands/diagnose.js.map +7 -0
  66. package/dist/src/commands/doctor.js +327 -0
  67. package/dist/src/commands/doctor.js.map +7 -0
  68. package/dist/src/commands/index.js +124 -0
  69. package/dist/src/commands/index.js.map +7 -0
  70. package/dist/src/core/accounts.js +129 -0
  71. package/dist/src/core/accounts.js.map +7 -0
  72. package/dist/src/core/agent-config.js +60 -0
  73. package/dist/src/core/agent-config.js.map +7 -0
  74. package/dist/src/core/api-error.js +55 -0
  75. package/dist/src/core/api-error.js.map +7 -0
  76. package/dist/src/core/app-owner-fallback.js +17 -0
  77. package/dist/src/core/app-owner-fallback.js.map +7 -0
  78. package/dist/src/core/app-scope-checker.js +95 -0
  79. package/dist/src/core/app-scope-checker.js.map +7 -0
  80. package/dist/src/core/auth-errors.js +120 -0
  81. package/dist/src/core/auth-errors.js.map +7 -0
  82. package/dist/src/core/chat-info-cache.js +102 -0
  83. package/dist/src/core/chat-info-cache.js.map +7 -0
  84. package/dist/src/core/config-schema.js +150 -0
  85. package/dist/src/core/config-schema.js.map +7 -0
  86. package/dist/src/core/device-flow.js +174 -0
  87. package/dist/src/core/device-flow.js.map +7 -0
  88. package/dist/src/core/feishu-fetch.js +12 -0
  89. package/dist/src/core/feishu-fetch.js.map +7 -0
  90. package/dist/src/core/footer-config.js +16 -0
  91. package/dist/src/core/footer-config.js.map +7 -0
  92. package/dist/src/core/lark-client.js +322 -0
  93. package/dist/src/core/lark-client.js.map +7 -0
  94. package/dist/src/core/lark-logger.js +92 -0
  95. package/dist/src/core/lark-logger.js.map +7 -0
  96. package/dist/src/core/lark-ticket.js +18 -0
  97. package/dist/src/core/lark-ticket.js.map +7 -0
  98. package/dist/src/core/message-unavailable.js +119 -0
  99. package/dist/src/core/message-unavailable.js.map +7 -0
  100. package/dist/src/core/owner-policy.js +25 -0
  101. package/dist/src/core/owner-policy.js.map +7 -0
  102. package/dist/src/core/permission-url.js +37 -0
  103. package/dist/src/core/permission-url.js.map +7 -0
  104. package/dist/src/core/project-auth.js +177 -0
  105. package/dist/src/core/project-auth.js.map +7 -0
  106. package/dist/src/core/project-oauth-flow.js +124 -0
  107. package/dist/src/core/project-oauth-flow.js.map +7 -0
  108. package/dist/src/core/project-token-store.js +172 -0
  109. package/dist/src/core/project-token-store.js.map +7 -0
  110. package/dist/src/core/raw-request.js +45 -0
  111. package/dist/src/core/raw-request.js.map +7 -0
  112. package/dist/src/core/scope-manager.js +62 -0
  113. package/dist/src/core/scope-manager.js.map +7 -0
  114. package/dist/src/core/security-check.js +118 -0
  115. package/dist/src/core/security-check.js.map +7 -0
  116. package/dist/src/core/shutdown-hooks.js +37 -0
  117. package/dist/src/core/shutdown-hooks.js.map +7 -0
  118. package/dist/src/core/targets.js +55 -0
  119. package/dist/src/core/targets.js.map +7 -0
  120. package/dist/src/core/token-store.js +215 -0
  121. package/dist/src/core/token-store.js.map +7 -0
  122. package/dist/src/core/tool-client.js +335 -0
  123. package/dist/src/core/tool-client.js.map +7 -0
  124. package/dist/src/core/tool-scopes.js +207 -0
  125. package/dist/src/core/tool-scopes.js.map +7 -0
  126. package/dist/src/core/tools-config.js +57 -0
  127. package/dist/src/core/tools-config.js.map +7 -0
  128. package/dist/src/core/types.js +1 -0
  129. package/dist/src/core/types.js.map +7 -0
  130. package/dist/src/core/uat-client.js +124 -0
  131. package/dist/src/core/uat-client.js.map +7 -0
  132. package/dist/src/core/version.js +27 -0
  133. package/dist/src/core/version.js.map +7 -0
  134. package/dist/src/messaging/converters/audio.js +19 -0
  135. package/dist/src/messaging/converters/audio.js.map +7 -0
  136. package/dist/src/messaging/converters/calendar.js +46 -0
  137. package/dist/src/messaging/converters/calendar.js.map +7 -0
  138. package/dist/src/messaging/converters/content-converter.js +61 -0
  139. package/dist/src/messaging/converters/content-converter.js.map +7 -0
  140. package/dist/src/messaging/converters/file.js +18 -0
  141. package/dist/src/messaging/converters/file.js.map +7 -0
  142. package/dist/src/messaging/converters/folder.js +18 -0
  143. package/dist/src/messaging/converters/folder.js.map +7 -0
  144. package/dist/src/messaging/converters/hongbao.js +14 -0
  145. package/dist/src/messaging/converters/hongbao.js.map +7 -0
  146. package/dist/src/messaging/converters/image.js +16 -0
  147. package/dist/src/messaging/converters/image.js.map +7 -0
  148. package/dist/src/messaging/converters/index.js +48 -0
  149. package/dist/src/messaging/converters/index.js.map +7 -0
  150. package/dist/src/messaging/converters/interactive/card-converter.js +1040 -0
  151. package/dist/src/messaging/converters/interactive/card-converter.js.map +7 -0
  152. package/dist/src/messaging/converters/interactive/card-utils.js +36 -0
  153. package/dist/src/messaging/converters/interactive/card-utils.js.map +7 -0
  154. package/dist/src/messaging/converters/interactive/index.js +19 -0
  155. package/dist/src/messaging/converters/interactive/index.js.map +7 -0
  156. package/dist/src/messaging/converters/interactive/legacy.js +53 -0
  157. package/dist/src/messaging/converters/interactive/legacy.js.map +7 -0
  158. package/dist/src/messaging/converters/interactive/types.js +23 -0
  159. package/dist/src/messaging/converters/interactive/types.js.map +7 -0
  160. package/dist/src/messaging/converters/location.js +17 -0
  161. package/dist/src/messaging/converters/location.js.map +7 -0
  162. package/dist/src/messaging/converters/merge-forward.js +143 -0
  163. package/dist/src/messaging/converters/merge-forward.js.map +7 -0
  164. package/dist/src/messaging/converters/post.js +113 -0
  165. package/dist/src/messaging/converters/post.js.map +7 -0
  166. package/dist/src/messaging/converters/share.js +22 -0
  167. package/dist/src/messaging/converters/share.js.map +7 -0
  168. package/dist/src/messaging/converters/sticker.js +16 -0
  169. package/dist/src/messaging/converters/sticker.js.map +7 -0
  170. package/dist/src/messaging/converters/system.js +25 -0
  171. package/dist/src/messaging/converters/system.js.map +7 -0
  172. package/dist/src/messaging/converters/text.js +12 -0
  173. package/dist/src/messaging/converters/text.js.map +7 -0
  174. package/dist/src/messaging/converters/todo.js +37 -0
  175. package/dist/src/messaging/converters/todo.js.map +7 -0
  176. package/dist/src/messaging/converters/types.js +1 -0
  177. package/dist/src/messaging/converters/types.js.map +7 -0
  178. package/dist/src/messaging/converters/unknown.js +13 -0
  179. package/dist/src/messaging/converters/unknown.js.map +7 -0
  180. package/dist/src/messaging/converters/utils.js +35 -0
  181. package/dist/src/messaging/converters/utils.js.map +7 -0
  182. package/dist/src/messaging/converters/video-chat.js +21 -0
  183. package/dist/src/messaging/converters/video-chat.js.map +7 -0
  184. package/dist/src/messaging/converters/video.js +30 -0
  185. package/dist/src/messaging/converters/video.js.map +7 -0
  186. package/dist/src/messaging/converters/vote.js +24 -0
  187. package/dist/src/messaging/converters/vote.js.map +7 -0
  188. package/dist/src/messaging/inbound/dedup.js +82 -0
  189. package/dist/src/messaging/inbound/dedup.js.map +7 -0
  190. package/dist/src/messaging/inbound/dispatch-builders.js +98 -0
  191. package/dist/src/messaging/inbound/dispatch-builders.js.map +7 -0
  192. package/dist/src/messaging/inbound/dispatch-commands.js +94 -0
  193. package/dist/src/messaging/inbound/dispatch-commands.js.map +7 -0
  194. package/dist/src/messaging/inbound/dispatch-context.js +96 -0
  195. package/dist/src/messaging/inbound/dispatch-context.js.map +7 -0
  196. package/dist/src/messaging/inbound/dispatch.js +150 -0
  197. package/dist/src/messaging/inbound/dispatch.js.map +7 -0
  198. package/dist/src/messaging/inbound/enrich.js +137 -0
  199. package/dist/src/messaging/inbound/enrich.js.map +7 -0
  200. package/dist/src/messaging/inbound/gate-effects.js +28 -0
  201. package/dist/src/messaging/inbound/gate-effects.js.map +7 -0
  202. package/dist/src/messaging/inbound/gate.js +163 -0
  203. package/dist/src/messaging/inbound/gate.js.map +7 -0
  204. package/dist/src/messaging/inbound/handler.js +132 -0
  205. package/dist/src/messaging/inbound/handler.js.map +7 -0
  206. package/dist/src/messaging/inbound/media-resolver.js +70 -0
  207. package/dist/src/messaging/inbound/media-resolver.js.map +7 -0
  208. package/dist/src/messaging/inbound/mention.js +50 -0
  209. package/dist/src/messaging/inbound/mention.js.map +7 -0
  210. package/dist/src/messaging/inbound/parse-io.js +41 -0
  211. package/dist/src/messaging/inbound/parse-io.js.map +7 -0
  212. package/dist/src/messaging/inbound/parse.js +79 -0
  213. package/dist/src/messaging/inbound/parse.js.map +7 -0
  214. package/dist/src/messaging/inbound/permission.js +30 -0
  215. package/dist/src/messaging/inbound/permission.js.map +7 -0
  216. package/dist/src/messaging/inbound/policy.js +83 -0
  217. package/dist/src/messaging/inbound/policy.js.map +7 -0
  218. package/dist/src/messaging/inbound/reaction-handler.js +162 -0
  219. package/dist/src/messaging/inbound/reaction-handler.js.map +7 -0
  220. package/dist/src/messaging/inbound/user-name-cache.js +172 -0
  221. package/dist/src/messaging/inbound/user-name-cache.js.map +7 -0
  222. package/dist/src/messaging/outbound/actions.js +239 -0
  223. package/dist/src/messaging/outbound/actions.js.map +7 -0
  224. package/dist/src/messaging/outbound/chat-manage.js +74 -0
  225. package/dist/src/messaging/outbound/chat-manage.js.map +7 -0
  226. package/dist/src/messaging/outbound/deliver.js +162 -0
  227. package/dist/src/messaging/outbound/deliver.js.map +7 -0
  228. package/dist/src/messaging/outbound/fetch.js +7 -0
  229. package/dist/src/messaging/outbound/fetch.js.map +7 -0
  230. package/dist/src/messaging/outbound/forward.js +31 -0
  231. package/dist/src/messaging/outbound/forward.js.map +7 -0
  232. package/dist/src/messaging/outbound/media-url-utils.js +101 -0
  233. package/dist/src/messaging/outbound/media-url-utils.js.map +7 -0
  234. package/dist/src/messaging/outbound/media.js +463 -0
  235. package/dist/src/messaging/outbound/media.js.map +7 -0
  236. package/dist/src/messaging/outbound/outbound.js +95 -0
  237. package/dist/src/messaging/outbound/outbound.js.map +7 -0
  238. package/dist/src/messaging/outbound/reactions.js +312 -0
  239. package/dist/src/messaging/outbound/reactions.js.map +7 -0
  240. package/dist/src/messaging/outbound/send.js +194 -0
  241. package/dist/src/messaging/outbound/send.js.map +7 -0
  242. package/dist/src/messaging/outbound/typing.js +77 -0
  243. package/dist/src/messaging/outbound/typing.js.map +7 -0
  244. package/dist/src/messaging/shared/message-lookup.js +84 -0
  245. package/dist/src/messaging/shared/message-lookup.js.map +7 -0
  246. package/dist/src/messaging/types.js +1 -0
  247. package/dist/src/messaging/types.js.map +7 -0
  248. package/dist/src/tools/auto-auth.js +714 -0
  249. package/dist/src/tools/auto-auth.js.map +7 -0
  250. package/dist/src/tools/helpers.js +133 -0
  251. package/dist/src/tools/helpers.js.map +7 -0
  252. package/dist/src/tools/mcp/doc/create.js +35 -0
  253. package/dist/src/tools/mcp/doc/create.js.map +7 -0
  254. package/dist/src/tools/mcp/doc/fetch.js +33 -0
  255. package/dist/src/tools/mcp/doc/fetch.js.map +7 -0
  256. package/dist/src/tools/mcp/doc/index.js +32 -0
  257. package/dist/src/tools/mcp/doc/index.js.map +7 -0
  258. package/dist/src/tools/mcp/doc/update.js +61 -0
  259. package/dist/src/tools/mcp/doc/update.js.map +7 -0
  260. package/dist/src/tools/mcp/project/endpoint.js +25 -0
  261. package/dist/src/tools/mcp/project/endpoint.js.map +7 -0
  262. package/dist/src/tools/mcp/project/index.js +27 -0
  263. package/dist/src/tools/mcp/project/index.js.map +7 -0
  264. package/dist/src/tools/mcp/project/tools.js +579 -0
  265. package/dist/src/tools/mcp/project/tools.js.map +7 -0
  266. package/dist/src/tools/mcp/shared.js +170 -0
  267. package/dist/src/tools/mcp/shared.js.map +7 -0
  268. package/dist/src/tools/oapi/bitable/app-table-field.js +244 -0
  269. package/dist/src/tools/oapi/bitable/app-table-field.js.map +7 -0
  270. package/dist/src/tools/oapi/bitable/app-table-record.js +501 -0
  271. package/dist/src/tools/oapi/bitable/app-table-record.js.map +7 -0
  272. package/dist/src/tools/oapi/bitable/app-table-view.js +226 -0
  273. package/dist/src/tools/oapi/bitable/app-table-view.js.map +7 -0
  274. package/dist/src/tools/oapi/bitable/app-table.js +278 -0
  275. package/dist/src/tools/oapi/bitable/app-table.js.map +7 -0
  276. package/dist/src/tools/oapi/bitable/app.js +200 -0
  277. package/dist/src/tools/oapi/bitable/app.js.map +7 -0
  278. package/dist/src/tools/oapi/bitable/index.js +13 -0
  279. package/dist/src/tools/oapi/bitable/index.js.map +7 -0
  280. package/dist/src/tools/oapi/calendar/calendar.js +131 -0
  281. package/dist/src/tools/oapi/calendar/calendar.js.map +7 -0
  282. package/dist/src/tools/oapi/calendar/event-attendee.js +301 -0
  283. package/dist/src/tools/oapi/calendar/event-attendee.js.map +7 -0
  284. package/dist/src/tools/oapi/calendar/event.js +834 -0
  285. package/dist/src/tools/oapi/calendar/event.js.map +7 -0
  286. package/dist/src/tools/oapi/calendar/freebusy.js +111 -0
  287. package/dist/src/tools/oapi/calendar/freebusy.js.map +7 -0
  288. package/dist/src/tools/oapi/calendar/index.js +11 -0
  289. package/dist/src/tools/oapi/calendar/index.js.map +7 -0
  290. package/dist/src/tools/oapi/chat/chat.js +132 -0
  291. package/dist/src/tools/oapi/chat/chat.js.map +7 -0
  292. package/dist/src/tools/oapi/chat/index.js +11 -0
  293. package/dist/src/tools/oapi/chat/index.js.map +7 -0
  294. package/dist/src/tools/oapi/chat/members.js +83 -0
  295. package/dist/src/tools/oapi/chat/members.js.map +7 -0
  296. package/dist/src/tools/oapi/common/get-user.js +95 -0
  297. package/dist/src/tools/oapi/common/get-user.js.map +7 -0
  298. package/dist/src/tools/oapi/common/index.js +7 -0
  299. package/dist/src/tools/oapi/common/index.js.map +7 -0
  300. package/dist/src/tools/oapi/common/search-user.js +67 -0
  301. package/dist/src/tools/oapi/common/search-user.js.map +7 -0
  302. package/dist/src/tools/oapi/drive/doc-comments.js +310 -0
  303. package/dist/src/tools/oapi/drive/doc-comments.js.map +7 -0
  304. package/dist/src/tools/oapi/drive/doc-media.js +314 -0
  305. package/dist/src/tools/oapi/drive/doc-media.js.map +7 -0
  306. package/dist/src/tools/oapi/drive/file.js +548 -0
  307. package/dist/src/tools/oapi/drive/file.js.map +7 -0
  308. package/dist/src/tools/oapi/drive/index.js +29 -0
  309. package/dist/src/tools/oapi/drive/index.js.map +7 -0
  310. package/dist/src/tools/oapi/helpers.js +199 -0
  311. package/dist/src/tools/oapi/helpers.js.map +7 -0
  312. package/dist/src/tools/oapi/im/format-messages.js +128 -0
  313. package/dist/src/tools/oapi/im/format-messages.js.map +7 -0
  314. package/dist/src/tools/oapi/im/index.js +15 -0
  315. package/dist/src/tools/oapi/im/index.js.map +7 -0
  316. package/dist/src/tools/oapi/im/message-read.js +404 -0
  317. package/dist/src/tools/oapi/im/message-read.js.map +7 -0
  318. package/dist/src/tools/oapi/im/message.js +179 -0
  319. package/dist/src/tools/oapi/im/message.js.map +7 -0
  320. package/dist/src/tools/oapi/im/resource.js +126 -0
  321. package/dist/src/tools/oapi/im/resource.js.map +7 -0
  322. package/dist/src/tools/oapi/im/time-utils.js +169 -0
  323. package/dist/src/tools/oapi/im/time-utils.js.map +7 -0
  324. package/dist/src/tools/oapi/im/user-name-uat.js +103 -0
  325. package/dist/src/tools/oapi/im/user-name-uat.js.map +7 -0
  326. package/dist/src/tools/oapi/index.js +56 -0
  327. package/dist/src/tools/oapi/index.js.map +7 -0
  328. package/dist/src/tools/oapi/sdk-types.js +1 -0
  329. package/dist/src/tools/oapi/sdk-types.js.map +7 -0
  330. package/dist/src/tools/oapi/search/doc-search.js +215 -0
  331. package/dist/src/tools/oapi/search/doc-search.js.map +7 -0
  332. package/dist/src/tools/oapi/search/index.js +25 -0
  333. package/dist/src/tools/oapi/search/index.js.map +7 -0
  334. package/dist/src/tools/oapi/sheets/index.js +25 -0
  335. package/dist/src/tools/oapi/sheets/index.js.map +7 -0
  336. package/dist/src/tools/oapi/sheets/sheet.js +652 -0
  337. package/dist/src/tools/oapi/sheets/sheet.js.map +7 -0
  338. package/dist/src/tools/oapi/task/comment.js +151 -0
  339. package/dist/src/tools/oapi/task/comment.js.map +7 -0
  340. package/dist/src/tools/oapi/task/index.js +11 -0
  341. package/dist/src/tools/oapi/task/index.js.map +7 -0
  342. package/dist/src/tools/oapi/task/subtask.js +175 -0
  343. package/dist/src/tools/oapi/task/subtask.js.map +7 -0
  344. package/dist/src/tools/oapi/task/task.js +405 -0
  345. package/dist/src/tools/oapi/task/task.js.map +7 -0
  346. package/dist/src/tools/oapi/task/tasklist.js +366 -0
  347. package/dist/src/tools/oapi/task/tasklist.js.map +7 -0
  348. package/dist/src/tools/oapi/wiki/index.js +27 -0
  349. package/dist/src/tools/oapi/wiki/index.js.map +7 -0
  350. package/dist/src/tools/oapi/wiki/space-node.js +311 -0
  351. package/dist/src/tools/oapi/wiki/space-node.js.map +7 -0
  352. package/dist/src/tools/oapi/wiki/space.js +148 -0
  353. package/dist/src/tools/oapi/wiki/space.js.map +7 -0
  354. package/dist/src/tools/oauth-batch-auth.js +125 -0
  355. package/dist/src/tools/oauth-batch-auth.js.map +7 -0
  356. package/dist/src/tools/oauth-cards.js +269 -0
  357. package/dist/src/tools/oauth-cards.js.map +7 -0
  358. package/dist/src/tools/oauth.js +538 -0
  359. package/dist/src/tools/oauth.js.map +7 -0
  360. package/dist/src/tools/onboarding-auth.js +101 -0
  361. package/dist/src/tools/onboarding-auth.js.map +7 -0
  362. package/dist/src/tools/project-oauth.js +305 -0
  363. package/dist/src/tools/project-oauth.js.map +7 -0
  364. package/dist/src/tools/tat/im/index.js +9 -0
  365. package/dist/src/tools/tat/im/index.js.map +7 -0
  366. package/dist/src/tools/tat/im/resource.js +123 -0
  367. package/dist/src/tools/tat/im/resource.js.map +7 -0
  368. package/package.json +64 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/commands/diagnose.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * Diagnostic module for the Lark/Feishu plugin.\n *\n * Collects environment info, account configuration, API connectivity,\n * app permissions, tool registration state, and recent error logs into\n * a structured report that users can share with developers for\n * remote troubleshooting.\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\n\nimport type { OpenClawConfig } from 'openclaw/plugin-sdk';\n\ninterface DiagLogger {\n info: (message: string) => void;\n warn: (message: string) => void;\n error: (message: string) => void;\n}\nimport type * as Lark from '@larksuiteoapi/node-sdk';\n\nimport { probeFeishu } from '../channel/probe';\nimport { getLarkAccountIds, getLarkAccount, getEnabledLarkAccounts } from '../core/accounts';\nimport { LarkClient } from '../core/lark-client';\n\n/**\n * Resolve the global config for cross-account operations.\n * See doctor.ts for rationale.\n */\nfunction resolveGlobalConfig(config: OpenClawConfig): OpenClawConfig {\n return LarkClient.globalConfig ?? config;\n}\nimport { assertLarkOk, formatLarkError } from '../core/api-error';\nimport { resolveAnyEnabledToolsConfig } from '../core/tools-config';\nimport type { LarkAccount } from '../core/types';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype CheckStatus = 'pass' | 'warn' | 'fail' | 'skip';\n\ninterface DiagCheckResult {\n name: string;\n status: CheckStatus;\n message: string;\n details?: string;\n}\n\ninterface AccountDiagResult {\n accountId: string;\n name?: string;\n enabled: boolean;\n configured: boolean;\n appId?: string;\n brand: string;\n checks: DiagCheckResult[];\n}\n\ninterface DiagReport {\n timestamp: string;\n environment: {\n nodeVersion: string;\n platform: string;\n arch: string;\n pluginVersion: string;\n };\n accounts: AccountDiagResult[];\n toolsRegistered: string[];\n recentErrors: string[];\n overallStatus: 'healthy' | 'degraded' | 'unhealthy';\n checks: DiagCheckResult[];\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst PLUGIN_VERSION = '2026.2.10';\nconst LOG_READ_BYTES = 256 * 1024; // read last 256KB of log\nconst MAX_ERROR_LINES = 20;\n/** Matches a timestamped log line: 2026-02-13T09:23:35.038Z [level]: ... */\nconst TIMESTAMPED_LINE_RE = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}/;\nconst ERROR_LEVEL_RE = /\\[error\\]|\\[warn\\]/i;\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction maskSecret(secret?: string): string {\n if (!secret) return '(\u672A\u8BBE\u7F6E)';\n if (secret.length <= 4) return '****';\n return secret.slice(0, 4) + '****';\n}\n\nasync function extractRecentErrors(logPath: string): Promise<string[]> {\n try {\n await fs.access(logPath);\n } catch {\n return [];\n }\n\n try {\n const stat = await fs.stat(logPath);\n const readSize = Math.min(stat.size, LOG_READ_BYTES);\n const fd = await fs.open(logPath, 'r');\n try {\n const buffer = Buffer.alloc(readSize);\n await fd.read(buffer, 0, readSize, Math.max(0, stat.size - readSize));\n const content = buffer.toString('utf-8');\n const lines = content.split('\\n').filter(Boolean);\n // Only pick timestamped log entries at error/warn level,\n // ignoring stack trace fragments and other noise.\n const errorLines = lines.filter((line) => TIMESTAMPED_LINE_RE.test(line) && ERROR_LEVEL_RE.test(line));\n return errorLines.slice(-MAX_ERROR_LINES);\n } finally {\n await fd.close();\n }\n } catch {\n return [];\n }\n}\n\nasync function checkAppScopes(client: Lark.Client): Promise<{ granted: number; pending: number; summary: string }> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const res = await (client as any).application.scope.list({});\n assertLarkOk(res);\n\n const scopes = res.data?.scopes ?? [];\n const granted = scopes.filter((s: { grant_status?: number }) => s.grant_status === 1);\n const pending = scopes.filter((s: { grant_status?: number }) => s.grant_status !== 1);\n\n return {\n granted: granted.length,\n pending: pending.length,\n summary: `${granted.length} \u5DF2\u6388\u6743, ${pending.length} \u5F85\u6388\u6743`,\n };\n}\n\nfunction detectRegisteredTools(config: OpenClawConfig): string[] {\n const accounts = getEnabledLarkAccounts(config);\n if (accounts.length === 0) return [];\n\n const toolsCfg = resolveAnyEnabledToolsConfig(accounts);\n\n const tools: string[] = [];\n if (toolsCfg.doc) tools.push('feishu_doc');\n if (toolsCfg.scopes) tools.push('feishu_app_scopes');\n if (toolsCfg.wiki) tools.push('feishu_wiki');\n if (toolsCfg.drive) tools.push('feishu_drive');\n if (toolsCfg.perm) tools.push('feishu_perm');\n tools.push(\n 'feishu_bitable_get_meta',\n 'feishu_bitable_list_fields',\n 'feishu_bitable_list_records',\n 'feishu_bitable_get_record',\n 'feishu_bitable_create_record',\n 'feishu_bitable_update_record',\n );\n tools.push('feishu_task');\n tools.push('feishu_calendar');\n\n return tools;\n}\n\nasync function diagnoseAccount(account: LarkAccount): Promise<AccountDiagResult> {\n const checks: DiagCheckResult[] = [];\n const result: AccountDiagResult = {\n accountId: account.accountId,\n name: account.name,\n enabled: account.enabled,\n configured: account.configured,\n appId: account.appId ?? '(\u672A\u8BBE\u7F6E)',\n brand: account.brand,\n checks,\n };\n\n // A1: Credentials\n checks.push({\n name: '\u51ED\u8BC1\u5B8C\u6574\u6027',\n status: account.configured ? 'pass' : 'fail',\n message: account.configured\n ? `appId: ${account.appId}, appSecret: ${maskSecret(account.appSecret)}`\n : '\u7F3A\u5C11 appId \u6216 appSecret',\n });\n\n // A2: Enabled\n checks.push({\n name: '\u8D26\u6237\u542F\u7528',\n status: account.enabled ? 'pass' : 'warn',\n message: account.enabled ? '\u5DF2\u542F\u7528' : '\u5DF2\u7981\u7528',\n });\n\n if (!account.configured || !account.appId || !account.appSecret) {\n checks.push({\n name: 'API \u8FDE\u901A\u6027',\n status: 'skip',\n message: '\u51ED\u8BC1\u672A\u914D\u7F6E\uFF0C\u8DF3\u8FC7',\n });\n return result;\n }\n\n // A3: API connectivity via probe\n try {\n const probeResult = await probeFeishu({\n accountId: account.accountId,\n appId: account.appId,\n appSecret: account.appSecret,\n brand: account.brand,\n });\n\n checks.push({\n name: 'API \u8FDE\u901A\u6027',\n status: probeResult.ok ? 'pass' : 'fail',\n message: probeResult.ok ? `\u8FDE\u63A5\u6210\u529F` : `\u8FDE\u63A5\u5931\u8D25: ${probeResult.error}`,\n });\n\n // A4: Bot info\n if (probeResult.ok) {\n checks.push({\n name: 'Bot \u4FE1\u606F',\n status: probeResult.botName ? 'pass' : 'warn',\n message: probeResult.botName ? `${probeResult.botName} (${probeResult.botOpenId})` : '\u672A\u83B7\u53D6\u5230 Bot \u540D\u79F0',\n });\n }\n } catch (err) {\n checks.push({\n name: 'API \u8FDE\u901A\u6027',\n status: 'fail',\n message: `\u63A2\u6D4B\u5F02\u5E38: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n\n // A5: App scopes\n try {\n const client = LarkClient.fromAccount(account).sdk;\n const scopesResult = await checkAppScopes(client);\n\n checks.push({\n name: '\u5E94\u7528\u6743\u9650',\n status: scopesResult.pending > 0 ? 'warn' : 'pass',\n message: scopesResult.summary,\n details: scopesResult.pending > 0 ? '\u5B58\u5728\u672A\u6388\u6743\u7684\u6743\u9650\uFF0C\u53EF\u80FD\u5F71\u54CD\u90E8\u5206\u529F\u80FD' : undefined,\n });\n } catch (err) {\n checks.push({\n name: '\u5E94\u7528\u6743\u9650',\n status: 'warn',\n message: `\u6743\u9650\u68C0\u67E5\u5931\u8D25: ${formatLarkError(err)}`,\n });\n }\n\n // A6: Brand\n checks.push({\n name: '\u54C1\u724C\u914D\u7F6E',\n status: 'pass',\n message: `brand: ${account.brand}`,\n });\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Core\n// ---------------------------------------------------------------------------\n\nexport async function runDiagnosis(params: { config: OpenClawConfig; logger?: DiagLogger }): Promise<DiagReport> {\n const { config } = params;\n // Use the global config to enumerate all accounts \u2014 the passed-in\n // config may be account-scoped (accounts map stripped).\n const globalCfg = resolveGlobalConfig(config);\n const globalChecks: DiagCheckResult[] = [];\n\n // -- Environment --\n const nodeVer = parseInt(process.version.slice(1), 10);\n globalChecks.push({\n name: 'Node.js \u7248\u672C',\n status: nodeVer >= 18 ? 'pass' : 'warn',\n message: process.version,\n details: nodeVer < 18 ? '\u5EFA\u8BAE\u5347\u7EA7\u5230 Node.js 18+' : undefined,\n });\n\n // -- Account count --\n const accountIds = getLarkAccountIds(globalCfg);\n globalChecks.push({\n name: '\u98DE\u4E66\u8D26\u6237\u6570\u91CF',\n status: accountIds.length > 0 ? 'pass' : 'fail',\n message: `${accountIds.length} \u4E2A\u8D26\u6237`,\n });\n\n // -- Log file --\n const logPath = path.join(os.homedir(), '.openclaw', 'logs', 'gateway.log');\n let logExists = false;\n try {\n await fs.access(logPath);\n logExists = true;\n } catch {\n // noop\n }\n globalChecks.push({\n name: '\u65E5\u5FD7\u6587\u4EF6',\n status: logExists ? 'pass' : 'warn',\n message: logExists ? logPath : `\u672A\u627E\u5230: ${logPath}`,\n });\n\n // -- Per-account diagnosis (sequential to avoid rate limits) --\n const accountResults: AccountDiagResult[] = [];\n for (const id of accountIds) {\n const account = getLarkAccount(globalCfg, id);\n const result = await diagnoseAccount(account);\n accountResults.push(result);\n }\n\n // -- Tools --\n const tools = detectRegisteredTools(globalCfg);\n\n // -- Recent errors --\n const recentErrors = await extractRecentErrors(logPath);\n globalChecks.push({\n name: '\u6700\u8FD1\u9519\u8BEF\u65E5\u5FD7',\n status: recentErrors.length > 0 ? 'warn' : 'pass',\n message: recentErrors.length > 0 ? `\u53D1\u73B0 ${recentErrors.length} \u6761\u9519\u8BEF` : '\u65E0\u6700\u8FD1\u9519\u8BEF',\n });\n\n // -- Overall status --\n const allChecks = [...globalChecks, ...accountResults.flatMap((a) => a.checks)];\n const hasFail = allChecks.some((c) => c.status === 'fail');\n const hasWarn = allChecks.some((c) => c.status === 'warn');\n\n return {\n timestamp: new Date().toISOString(),\n environment: {\n nodeVersion: process.version,\n platform: process.platform,\n arch: process.arch,\n pluginVersion: PLUGIN_VERSION,\n },\n accounts: accountResults,\n toolsRegistered: tools,\n recentErrors,\n overallStatus: hasFail ? 'unhealthy' : hasWarn ? 'degraded' : 'healthy',\n checks: globalChecks,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Formatting \u2014 plain text (chat command)\n// ---------------------------------------------------------------------------\n\nconst STATUS_LABEL: Record<CheckStatus, string> = {\n pass: '[PASS]',\n warn: '[WARN]',\n fail: '[FAIL]',\n skip: '[SKIP]',\n};\n\nfunction formatCheck(c: DiagCheckResult): string {\n let line = ` ${STATUS_LABEL[c.status]} ${c.name}: ${c.message}`;\n if (c.details) {\n line += `\\n ${c.details}`;\n }\n return line;\n}\n\nexport function formatDiagReportText(report: DiagReport): string {\n const lines: string[] = [];\n const sep = '====================================';\n\n lines.push(sep);\n lines.push(' \u98DE\u4E66\u63D2\u4EF6\u8BCA\u65AD\u62A5\u544A');\n lines.push(` ${report.timestamp}`);\n lines.push(sep);\n lines.push('');\n\n // Environment\n lines.push('\u3010\u73AF\u5883\u4FE1\u606F\u3011');\n lines.push(` Node.js: ${report.environment.nodeVersion}`);\n lines.push(` \u63D2\u4EF6\u7248\u672C: ${report.environment.pluginVersion}`);\n lines.push(` \u7CFB\u7EDF: ${report.environment.platform} ${report.environment.arch}`);\n lines.push('');\n\n // Global checks\n lines.push('\u3010\u5168\u5C40\u68C0\u67E5\u3011');\n for (const c of report.checks) {\n lines.push(formatCheck(c));\n }\n lines.push('');\n\n // Per-account\n for (const acct of report.accounts) {\n lines.push(`\u3010\u8D26\u6237: ${acct.accountId}\u3011`);\n if (acct.name) lines.push(` \u540D\u79F0: ${acct.name}`);\n lines.push(` App ID: ${acct.appId}`);\n lines.push(` \u54C1\u724C: ${acct.brand}`);\n lines.push('');\n for (const c of acct.checks) {\n lines.push(formatCheck(c));\n }\n lines.push('');\n }\n\n // Tools\n lines.push('\u3010\u5DE5\u5177\u6CE8\u518C\u3011');\n if (report.toolsRegistered.length > 0) {\n lines.push(` ${report.toolsRegistered.join(', ')}`);\n lines.push(` \u5171 ${report.toolsRegistered.length} \u4E2A`);\n } else {\n lines.push(' \u65E0\u5DE5\u5177\u6CE8\u518C\uFF08\u672A\u627E\u5230\u5DF2\u914D\u7F6E\u7684\u8D26\u6237\uFF09');\n }\n lines.push('');\n\n // Recent errors\n if (report.recentErrors.length > 0) {\n lines.push(`\u3010\u6700\u8FD1\u9519\u8BEF\u3011(${report.recentErrors.length} \u6761)`);\n for (let i = 0; i < report.recentErrors.length; i++) {\n lines.push(` ${i + 1}. ${report.recentErrors[i]}`);\n }\n lines.push('');\n }\n\n // Overall\n const statusMap = {\n healthy: 'HEALTHY',\n degraded: 'DEGRADED (\u5B58\u5728\u8B66\u544A)',\n unhealthy: 'UNHEALTHY (\u5B58\u5728\u5931\u8D25\u9879)',\n };\n lines.push(sep);\n lines.push(` \u603B\u4F53\u72B6\u6001: ${statusMap[report.overallStatus]}`);\n lines.push(sep);\n\n return lines.join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// Formatting \u2014 ANSI colored (CLI)\n// ---------------------------------------------------------------------------\n\nconst ANSI = {\n reset: '\\x1b[0m',\n bold: '\\x1b[1m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n red: '\\x1b[31m',\n gray: '\\x1b[90m',\n};\n\nconst STATUS_LABEL_CLI: Record<CheckStatus, string> = {\n pass: `${ANSI.green}[PASS]${ANSI.reset}`,\n warn: `${ANSI.yellow}[WARN]${ANSI.reset}`,\n fail: `${ANSI.red}[FAIL]${ANSI.reset}`,\n skip: `${ANSI.gray}[SKIP]${ANSI.reset}`,\n};\n\nfunction formatCheckCli(c: DiagCheckResult): string {\n let line = ` ${STATUS_LABEL_CLI[c.status]} ${c.name}: ${c.message}`;\n if (c.details) {\n line += `\\n ${ANSI.gray}${c.details}${ANSI.reset}`;\n }\n return line;\n}\n\n// ---------------------------------------------------------------------------\n// Trace by message_id\n// ---------------------------------------------------------------------------\n\n/**\n * Extract all log lines tagged with a specific message_id from gateway.log.\n *\n * Scans the last 1MB of the log file for lines containing `[msg:{messageId}]`.\n * Returns matching lines in chronological order.\n */\nexport async function traceByMessageId(messageId: string): Promise<string[]> {\n const logPath = path.join(os.homedir(), '.openclaw', 'logs', 'gateway.log');\n try {\n await fs.access(logPath);\n } catch {\n return [];\n }\n\n const TRACE_READ_BYTES = 1024 * 1024; // 1MB \u2014 more than extractRecentErrors\n try {\n const stat = await fs.stat(logPath);\n const readSize = Math.min(stat.size, TRACE_READ_BYTES);\n const fd = await fs.open(logPath, 'r');\n try {\n const buffer = Buffer.alloc(readSize);\n await fd.read(buffer, 0, readSize, Math.max(0, stat.size - readSize));\n const content = buffer.toString('utf-8');\n const needle = `[msg:${messageId}]`;\n return content.split('\\n').filter((line) => line.includes(needle));\n } finally {\n await fd.close();\n }\n } catch {\n return [];\n }\n}\n\n/**\n * Format trace output for CLI display.\n */\nexport function formatTraceOutput(lines: string[], messageId: string): string {\n const sep = '\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500';\n\n if (lines.length === 0) {\n return [\n sep,\n ` \u672A\u627E\u5230 ${messageId} \u7684\u8FFD\u8E2A\u65E5\u5FD7`,\n '',\n ' \u53EF\u80FD\u539F\u56E0:',\n ' 1. \u8BE5\u6D88\u606F\u5C1A\u672A\u88AB\u5904\u7406',\n ' 2. \u65E5\u5FD7\u5DF2\u88AB\u8F6E\u8F6C',\n ' 3. \u8FFD\u8E2A\u529F\u80FD\u672A\u542F\u7528\uFF08\u9700\u8981\u66F4\u65B0\u63D2\u4EF6\u7248\u672C\uFF09',\n sep,\n ].join('\\n');\n }\n\n const header = `\u8FFD\u8E2A ${messageId} \u7684\u5904\u7406\u94FE\u8DEF (${lines.length} \u6761\u65E5\u5FD7):`;\n const output: string[] = [header, sep];\n for (const line of lines) {\n output.push(line);\n }\n output.push(sep);\n return output.join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// Trace analysis\n// ---------------------------------------------------------------------------\n\n/** Parsed trace event extracted from a log line. */\ninterface TraceEvent {\n timestamp: Date;\n raw: string;\n /** The message body after the trace prefix. */\n body: string;\n}\n\n/** Classification of a trace event. */\ntype EventKind =\n | 'received'\n | 'sender_resolved'\n | 'rejected'\n | 'dispatching'\n | 'dispatch_complete'\n | 'card_created'\n | 'card_sent'\n | 'card_stream'\n | 'card_stream_fail'\n | 'card_settings'\n | 'card_update'\n | 'card_fallback'\n | 'reply_completed'\n | 'reply_error'\n | 'tool_call'\n | 'tool_done'\n | 'tool_fail'\n | 'other';\n\nfunction classifyEvent(body: string): EventKind {\n if (body.startsWith('received from')) return 'received';\n if (body.startsWith('sender resolved')) return 'sender_resolved';\n if (body.startsWith('rejected:')) return 'rejected';\n if (body.startsWith('dispatching to agent')) return 'dispatching';\n if (body.startsWith('dispatch complete')) return 'dispatch_complete';\n if (body.startsWith('card entity created')) return 'card_created';\n if (body.startsWith('card message sent')) return 'card_sent';\n if (body.startsWith('cardkit cardElement.content:')) return 'card_stream';\n if (body.startsWith('card stream update failed')) return 'card_stream_fail';\n if (body.startsWith('cardkit card.settings:')) return 'card_settings';\n if (body.startsWith('cardkit card.update:')) return 'card_update';\n if (body.startsWith('card creation failed')) return 'card_fallback';\n if (body.startsWith('reply completed')) return 'reply_completed';\n if (body.startsWith('reply error')) return 'reply_error';\n if (body.startsWith('tool call:')) return 'tool_call';\n if (body.startsWith('tool done:')) return 'tool_done';\n if (body.startsWith('tool fail:')) return 'tool_fail';\n return 'other';\n}\n\nconst EVENT_LABEL: Partial<Record<EventKind, string>> = {\n received: '\u6D88\u606F\u63A5\u6536',\n sender_resolved: 'Sender \u89E3\u6790',\n rejected: '\u6D88\u606F\u62D2\u7EDD',\n dispatching: '\u5206\u53D1\u5230 Agent',\n dispatch_complete: 'Agent \u5904\u7406\u5B8C\u6210',\n card_created: '\u5361\u7247\u521B\u5EFA',\n card_sent: '\u5361\u7247\u6D88\u606F\u53D1\u9001',\n card_stream: '\u6D41\u5F0F\u66F4\u65B0',\n card_stream_fail: '\u6D41\u5F0F\u66F4\u65B0\u5931\u8D25',\n card_settings: '\u5361\u7247\u8BBE\u7F6E',\n card_update: '\u5361\u7247\u6700\u7EC8\u66F4\u65B0',\n card_fallback: '\u5361\u7247\u964D\u7EA7',\n reply_completed: '\u56DE\u590D\u5B8C\u6210',\n reply_error: '\u56DE\u590D\u9519\u8BEF',\n tool_call: '\u5DE5\u5177\u8C03\u7528',\n tool_done: '\u5DE5\u5177\u5B8C\u6210',\n tool_fail: '\u5DE5\u5177\u5931\u8D25',\n};\n\n/** Expected stages in a normal message processing flow. */\nconst EXPECTED_STAGES: { kind: EventKind; label: string }[] = [\n { kind: 'received', label: '\u6D88\u606F\u63A5\u6536 (received from)' },\n { kind: 'dispatching', label: '\u5206\u53D1\u5230 Agent (dispatching to agent)' },\n { kind: 'card_created', label: '\u5361\u7247\u521B\u5EFA (card entity created)' },\n { kind: 'card_sent', label: '\u5361\u7247\u6D88\u606F\u53D1\u9001 (card message sent)' },\n { kind: 'card_stream', label: '\u6D41\u5F0F\u8F93\u51FA (cardElement.content)' },\n { kind: 'dispatch_complete', label: '\u5904\u7406\u5B8C\u6210 (dispatch complete)' },\n { kind: 'reply_completed', label: '\u56DE\u590D\u6536\u5C3E (reply completed)' },\n];\n\n/** Time gap thresholds (ms) for performance warnings. */\nconst PERF_THRESHOLDS: { from: EventKind; to: EventKind; warnMs: number; label: string }[] = [\n { from: 'received', to: 'dispatching', warnMs: 500, label: '\u6D88\u606F\u63A5\u6536 \u2192 \u5206\u53D1' },\n { from: 'dispatching', to: 'card_created', warnMs: 5000, label: '\u5206\u53D1 \u2192 \u5361\u7247\u521B\u5EFA' },\n { from: 'card_created', to: 'card_stream', warnMs: 30000, label: '\u5361\u7247\u521B\u5EFA \u2192 \u9996\u6B21\u6D41\u5F0F\u8F93\u51FA' },\n];\n\nfunction parseTraceLines(lines: string[]): TraceEvent[] {\n const events: TraceEvent[] = [];\n // Match: 2026-02-13T12:42:04.682Z [feishu] feishu[...][msg:...]: <body>\n const re = /^(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d+Z)\\s.*?\\]:\\s(.+)$/;\n for (const line of lines) {\n const m = line.match(re);\n if (m) {\n events.push({ timestamp: new Date(m[1]), raw: line, body: m[2] });\n }\n }\n return events;\n}\n\n/**\n * Analyze trace log lines and produce a structured CLI report.\n */\nexport function analyzeTrace(lines: string[], _messageId: string): string {\n const events = parseTraceLines(lines);\n if (events.length === 0) {\n return `\u65E0\u6CD5\u89E3\u6790\u65E5\u5FD7\u884C\uFF0C\u8BF7\u786E\u8BA4\u65E5\u5FD7\u683C\u5F0F\u6B63\u786E\u3002`;\n }\n\n const out: string[] = [];\n const sep = '\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500';\n const startTime = events[0].timestamp.getTime();\n const totalMs = events[events.length - 1].timestamp.getTime() - startTime;\n\n // \u2500\u2500 Section 1: Timeline \u2500\u2500\n out.push('');\n out.push(`${ANSI.bold}\u3010\u65F6\u95F4\u7EBF\u3011${ANSI.reset} (${events.length} \u6761\u65E5\u5FD7\uFF0C\u8DE8\u5EA6 ${(totalMs / 1000).toFixed(1)}s)`);\n out.push(sep);\n\n let prevMs = startTime;\n // Collapse consecutive card_stream events\n let streamCount = 0;\n let streamFirstSeq = '';\n let streamLastSeq = '';\n\n function flushStream() {\n if (streamCount > 0) {\n const label =\n streamCount === 1\n ? ` ${ANSI.gray}...${ANSI.reset} \u6D41\u5F0F\u66F4\u65B0 seq=${streamFirstSeq}`\n : ` ${ANSI.gray}...${ANSI.reset} \u6D41\u5F0F\u66F4\u65B0 x${streamCount} (seq=${streamFirstSeq}~${streamLastSeq})`;\n out.push(label);\n streamCount = 0;\n }\n }\n\n for (const ev of events) {\n const kind = classifyEvent(ev.body);\n const deltaMs = ev.timestamp.getTime() - prevMs;\n prevMs = ev.timestamp.getTime();\n const offsetMs = ev.timestamp.getTime() - startTime;\n const offsetStr = `+${offsetMs}ms`.padStart(10);\n\n // Collapse card_stream\n if (kind === 'card_stream') {\n const seqMatch = ev.body.match(/seq=(\\d+)/);\n const seq = seqMatch ? seqMatch[1] : '?';\n if (streamCount === 0) streamFirstSeq = seq;\n streamLastSeq = seq;\n streamCount++;\n continue;\n }\n flushStream();\n\n const label = EVENT_LABEL[kind] ?? kind;\n const gapWarn = deltaMs > 5000 ? ` ${ANSI.yellow}\u26A0 ${(deltaMs / 1000).toFixed(1)}s${ANSI.reset}` : '';\n\n // Marker for errors\n let marker = ' ';\n if (\n kind === 'rejected' ||\n kind === 'reply_error' ||\n kind === 'tool_fail' ||\n kind === 'card_stream_fail' ||\n kind === 'card_fallback'\n ) {\n marker = `${ANSI.red}\u2718 ${ANSI.reset}`;\n } else if (kind === 'tool_call') {\n marker = '\u2192 ';\n }\n\n // Extract key detail from body\n let detail = '';\n if (kind === 'received') {\n const m = ev.body.match(/from (\\S+) in (\\S+) \\((\\w+)\\)/);\n if (m) detail = `sender=${m[1]}, chat=${m[2]} (${m[3]})`;\n } else if (kind === 'dispatching') {\n const m = ev.body.match(/session=(\\S+)\\)/);\n if (m) detail = `session=${m[1]}`;\n } else if (kind === 'dispatch_complete') {\n const m = ev.body.match(/replies=(\\d+), elapsed=(\\d+)ms/);\n if (m) detail = `replies=${m[1]}, elapsed=${m[2]}ms`;\n } else if (kind === 'tool_call') {\n const m = ev.body.match(/tool call: (\\S+)/);\n if (m) detail = m[1];\n } else if (kind === 'tool_fail') {\n detail = ev.body.replace('tool fail: ', '');\n } else if (kind === 'card_created') {\n const m = ev.body.match(/card_id=(\\S+)\\)/);\n if (m) detail = `card_id=${m[1]}`;\n } else if (kind === 'reply_completed') {\n const m = ev.body.match(/elapsed=(\\d+)ms/);\n if (m) detail = `elapsed=${m[1]}ms`;\n } else if (kind === 'rejected') {\n detail = ev.body.replace('rejected: ', '');\n }\n\n out.push(`${ANSI.gray}[${offsetStr}]${ANSI.reset} ${marker}${label}${detail ? ` \u2014 ${detail}` : ''}${gapWarn}`);\n }\n flushStream();\n out.push('');\n\n // \u2500\u2500 Section 2: Anomaly detection \u2500\u2500\n const issues: string[] = [];\n const kindSet = new Set(events.map((e) => classifyEvent(e.body)));\n\n // 2.1 Missing stages\n for (const stage of EXPECTED_STAGES) {\n if (!kindSet.has(stage.kind)) {\n // dispatch_complete \u548C reply_completed \u7F3A\u5931\u4EC5\u5728\u6709 dispatching \u65F6\u624D\u544A\u8B66\n if ((stage.kind === 'dispatch_complete' || stage.kind === 'reply_completed') && !kindSet.has('dispatching'))\n continue;\n // card \u76F8\u5173\u9636\u6BB5\u5728\u6709 rejected \u65F6\u4E0D\u544A\u8B66\n if (\n (stage.kind === 'card_created' || stage.kind === 'card_sent' || stage.kind === 'card_stream') &&\n kindSet.has('rejected')\n )\n continue;\n issues.push(`\u7F3A\u5931\u9636\u6BB5: ${stage.label}`);\n }\n }\n\n // 2.2 Errors\n for (const ev of events) {\n const kind = classifyEvent(ev.body);\n if (kind === 'rejected') issues.push(`\u6D88\u606F\u88AB\u62D2\u7EDD: ${ev.body.replace('rejected: ', '')}`);\n if (kind === 'reply_error') issues.push(`\u56DE\u590D\u9519\u8BEF: ${ev.body}`);\n if (kind === 'tool_fail') issues.push(`\u5DE5\u5177\u5931\u8D25: ${ev.body}`);\n if (kind === 'card_stream_fail') issues.push(`\u6D41\u5F0F\u66F4\u65B0\u5931\u8D25: ${ev.body}`);\n if (kind === 'card_fallback') issues.push(`\u5361\u7247\u964D\u7EA7: ${ev.body}`);\n\n // CardKit non-zero code\n if (kind === 'card_stream' || kind === 'card_update' || kind === 'card_settings' || kind === 'card_created') {\n const codeMatch = ev.body.match(/code=(\\d+)/);\n if (codeMatch && codeMatch[1] !== '0') {\n issues.push(`API \u8FD4\u56DE\u9519\u8BEF\u7801: code=${codeMatch[1]} \u2014 ${ev.body}`);\n }\n }\n }\n\n // 2.3 Performance thresholds\n const firstByKind = new Map<EventKind, TraceEvent>();\n for (const ev of events) {\n const kind = classifyEvent(ev.body);\n if (!firstByKind.has(kind)) firstByKind.set(kind, ev);\n }\n for (const rule of PERF_THRESHOLDS) {\n const from = firstByKind.get(rule.from);\n const to = firstByKind.get(rule.to);\n if (from && to) {\n const gap = to.timestamp.getTime() - from.timestamp.getTime();\n if (gap > rule.warnMs) {\n issues.push(\n `\u6027\u80FD\u8B66\u544A: ${rule.label} \u8017\u65F6 ${(gap / 1000).toFixed(1)}s\uFF08\u9608\u503C ${(rule.warnMs / 1000).toFixed(0)}s\uFF09`,\n );\n }\n }\n }\n\n // 2.4 Duplicate delivery\n const receivedCount = events.filter((e) => classifyEvent(e.body) === 'received').length;\n if (receivedCount > 1) {\n issues.push(`\u91CD\u590D\u6295\u9012: \u540C\u4E00\u6D88\u606F\u88AB\u63A5\u6536 ${receivedCount} \u6B21\uFF08WebSocket \u91CD\u6295\u9012\uFF09`);\n }\n\n // 2.5 Card stream continuity\n const streamSeqs: number[] = [];\n for (const ev of events) {\n if (classifyEvent(ev.body) === 'card_stream') {\n const m = ev.body.match(/seq=(\\d+)/);\n if (m) streamSeqs.push(parseInt(m[1], 10));\n }\n }\n if (streamSeqs.length > 1) {\n for (let i = 1; i < streamSeqs.length; i++) {\n if (streamSeqs[i] !== streamSeqs[i - 1] + 1) {\n issues.push(\n `\u6D41\u5F0F seq \u4E0D\u8FDE\u7EED: seq=${streamSeqs[i - 1]} \u2192 seq=${streamSeqs[i]}\uFF08\u8DF3\u8FC7\u4E86 ${streamSeqs[i] - streamSeqs[i - 1] - 1} \u4E2A\uFF09`,\n );\n break;\n }\n }\n }\n\n out.push(`${ANSI.bold}\u3010\u5F02\u5E38\u68C0\u6D4B\u3011${ANSI.reset}`);\n out.push(sep);\n if (issues.length === 0) {\n out.push(` ${ANSI.green}\u672A\u53D1\u73B0\u5F02\u5E38${ANSI.reset}`);\n } else {\n for (let i = 0; i < issues.length; i++) {\n const isError =\n issues[i].startsWith('\u5DE5\u5177\u5931\u8D25') ||\n issues[i].startsWith('\u56DE\u590D\u9519\u8BEF') ||\n issues[i].startsWith('API \u8FD4\u56DE\u9519\u8BEF\u7801') ||\n issues[i].startsWith('\u6D41\u5F0F\u66F4\u65B0\u5931\u8D25');\n const color = isError ? ANSI.red : ANSI.yellow;\n out.push(` ${color}${i + 1}. ${issues[i]}${ANSI.reset}`);\n }\n }\n out.push('');\n\n // \u2500\u2500 Section 3: Diagnosis \u2500\u2500\n out.push(`${ANSI.bold}\u3010\u8BCA\u65AD\u603B\u7ED3\u3011${ANSI.reset}`);\n out.push(sep);\n\n const hasError = issues.some(\n (i) =>\n i.startsWith('\u5DE5\u5177\u5931\u8D25') ||\n i.startsWith('\u56DE\u590D\u9519\u8BEF') ||\n i.startsWith('API \u8FD4\u56DE\u9519\u8BEF\u7801') ||\n i.startsWith('\u6D41\u5F0F\u66F4\u65B0\u5931\u8D25') ||\n i.startsWith('\u7F3A\u5931\u9636\u6BB5'),\n );\n const hasWarn = issues.length > 0;\n\n if (!hasWarn) {\n out.push(` \u72B6\u6001: ${ANSI.green}\u2713 \u6B63\u5E38${ANSI.reset}`);\n out.push(` \u6D88\u606F\u5904\u7406\u94FE\u8DEF\u5B8C\u6574\uFF0C\u5168\u7A0B\u8017\u65F6 ${(totalMs / 1000).toFixed(1)}s\u3002`);\n\n // Break down time\n const dispatchComplete = events.find(\n (e) =>\n classifyEvent(e.body) === 'dispatch_complete' && e.body.includes('replies=') && !e.body.includes('replies=0'),\n );\n if (dispatchComplete) {\n const m = dispatchComplete.body.match(/elapsed=(\\d+)ms/);\n if (m) {\n out.push(` \u5176\u4E2D Agent \u5904\u7406\u8017\u65F6 ${(parseInt(m[1], 10) / 1000).toFixed(1)}s\uFF08\u542B AI \u63A8\u7406 + \u5DE5\u5177\u8C03\u7528\uFF09\u3002`);\n }\n }\n } else if (hasError) {\n out.push(` \u72B6\u6001: ${ANSI.red}\u2718 \u5F02\u5E38${ANSI.reset}`);\n out.push(` \u53D1\u73B0 ${issues.length} \u4E2A\u95EE\u9898\uFF0C\u9700\u8981\u6392\u67E5\u3002`);\n } else {\n out.push(` \u72B6\u6001: ${ANSI.yellow}\u26A0 \u6709\u8B66\u544A${ANSI.reset}`);\n out.push(` \u53D1\u73B0 ${issues.length} \u4E2A\u8B66\u544A\uFF0C\u529F\u80FD\u53EF\u7528\u4F46\u9700\u5173\u6CE8\u3002`);\n }\n out.push('');\n\n return out.join('\\n');\n}\n\nexport function formatDiagReportCli(report: DiagReport): string {\n const lines: string[] = [];\n const sep = '====================================';\n\n lines.push(sep);\n lines.push(` ${ANSI.bold}\u98DE\u4E66\u63D2\u4EF6\u8BCA\u65AD\u62A5\u544A${ANSI.reset}`);\n lines.push(` ${report.timestamp}`);\n lines.push(sep);\n lines.push('');\n\n // Environment\n lines.push(`${ANSI.bold}\u3010\u73AF\u5883\u4FE1\u606F\u3011${ANSI.reset}`);\n lines.push(` Node.js: ${report.environment.nodeVersion}`);\n lines.push(` \u63D2\u4EF6\u7248\u672C: ${report.environment.pluginVersion}`);\n lines.push(` \u7CFB\u7EDF: ${report.environment.platform} ${report.environment.arch}`);\n lines.push('');\n\n // Global checks\n lines.push(`${ANSI.bold}\u3010\u5168\u5C40\u68C0\u67E5\u3011${ANSI.reset}`);\n for (const c of report.checks) {\n lines.push(formatCheckCli(c));\n }\n lines.push('');\n\n // Per-account\n for (const acct of report.accounts) {\n lines.push(`${ANSI.bold}\u3010\u8D26\u6237: ${acct.accountId}\u3011${ANSI.reset}`);\n if (acct.name) lines.push(` \u540D\u79F0: ${acct.name}`);\n lines.push(` App ID: ${acct.appId}`);\n lines.push(` \u54C1\u724C: ${acct.brand}`);\n lines.push('');\n for (const c of acct.checks) {\n lines.push(formatCheckCli(c));\n }\n lines.push('');\n }\n\n // Tools\n lines.push(`${ANSI.bold}\u3010\u5DE5\u5177\u6CE8\u518C\u3011${ANSI.reset}`);\n if (report.toolsRegistered.length > 0) {\n lines.push(` ${report.toolsRegistered.join(', ')}`);\n lines.push(` \u5171 ${report.toolsRegistered.length} \u4E2A`);\n } else {\n lines.push(' \u65E0\u5DE5\u5177\u6CE8\u518C\uFF08\u672A\u627E\u5230\u5DF2\u914D\u7F6E\u7684\u8D26\u6237\uFF09');\n }\n lines.push('');\n\n // Recent errors\n if (report.recentErrors.length > 0) {\n lines.push(`${ANSI.bold}\u3010\u6700\u8FD1\u9519\u8BEF\u3011${ANSI.reset}(${report.recentErrors.length} \u6761)`);\n for (let i = 0; i < report.recentErrors.length; i++) {\n lines.push(` ${ANSI.gray}${i + 1}. ${report.recentErrors[i]}${ANSI.reset}`);\n }\n lines.push('');\n }\n\n // Overall\n const statusColorMap = {\n healthy: `${ANSI.green}HEALTHY${ANSI.reset}`,\n degraded: `${ANSI.yellow}DEGRADED (\u5B58\u5728\u8B66\u544A)${ANSI.reset}`,\n unhealthy: `${ANSI.red}UNHEALTHY (\u5B58\u5728\u5931\u8D25\u9879)${ANSI.reset}`,\n };\n lines.push(sep);\n lines.push(` \u603B\u4F53\u72B6\u6001: ${statusColorMap[report.overallStatus]}`);\n lines.push(sep);\n\n return lines.join('\\n');\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,327 @@
1
+ import { getEnabledLarkAccounts } from "../core/accounts";
2
+ import { LarkClient } from "../core/lark-client";
3
+ function resolveGlobalConfig(config) {
4
+ return LarkClient.globalConfig ?? config;
5
+ }
6
+ import { getAppGrantedScopes, missingScopes } from "../core/app-scope-checker";
7
+ import { getAppOwnerFallback } from "../core/app-owner-fallback";
8
+ import { getStoredToken, tokenStatus } from "../core/token-store";
9
+ import { filterSensitiveScopes, REQUIRED_APP_SCOPES, TOOL_SCOPES } from "../core/tool-scopes";
10
+ import { probeFeishu } from "../channel/probe";
11
+ import { AppScopeCheckFailedError } from "../core/tool-client";
12
+ import { getPluginVersion } from "../core/version";
13
+ function formatTimestamp(date) {
14
+ return date.toLocaleString("sv-SE", { timeZone: "Asia/Shanghai" }).replace("T", " ");
15
+ }
16
+ function getAllToolScopes() {
17
+ const scopesSet = /* @__PURE__ */ new Set();
18
+ for (const scopes of Object.values(TOOL_SCOPES)) {
19
+ for (const scope of scopes) {
20
+ scopesSet.add(scope);
21
+ }
22
+ }
23
+ return Array.from(scopesSet).sort();
24
+ }
25
+ function maskSecret(secret) {
26
+ if (!secret) return "(\u672A\u8BBE\u7F6E)";
27
+ if (secret.length <= 4) return "****";
28
+ return secret.slice(0, 4) + "****";
29
+ }
30
+ async function checkBasicInfo(account, config) {
31
+ const lines = [];
32
+ let status = "pass";
33
+ const feishuEntry = config.plugins?.entries?.feishu;
34
+ if (feishuEntry && feishuEntry.enabled !== false) {
35
+ status = "fail";
36
+ lines.push(
37
+ "\u274C **\u65E7\u7248\u63D2\u4EF6**: \u68C0\u6D4B\u5230\u65E7\u7248\u5B98\u65B9\u63D2\u4EF6\u672A\u7981\u7528\n\u{1F449} \u8BF7\u4F9D\u6B21\u8FD0\u884C\u547D\u4EE4\uFF1A\n```\nopenclaw config set plugins.entries.feishu.enabled false --json\nopenclaw gateway restart\n```"
38
+ );
39
+ } else {
40
+ lines.push("\u2705 **\u65E7\u7248\u63D2\u4EF6**: \u5DF2\u7981\u7528");
41
+ }
42
+ lines.push(`\u2705 **\u51ED\u8BC1\u5B8C\u6574\u6027**: appId: ${account.appId}, appSecret: ${maskSecret(account.appSecret)}`);
43
+ lines.push(`\u2705 **\u8D26\u6237\u542F\u7528**: \u5DF2\u542F\u7528`);
44
+ try {
45
+ const probeResult = await probeFeishu({
46
+ accountId: account.accountId,
47
+ appId: account.appId,
48
+ appSecret: account.appSecret,
49
+ brand: account.brand
50
+ });
51
+ if (probeResult.ok) {
52
+ lines.push(`\u2705 **API \u8FDE\u901A\u6027**: \u8FDE\u63A5\u6210\u529F`);
53
+ } else {
54
+ status = "fail";
55
+ lines.push(`\u274C **API \u8FDE\u901A\u6027**: \u8FDE\u63A5\u5931\u8D25 - ${probeResult.error}`);
56
+ }
57
+ } catch (err) {
58
+ status = "fail";
59
+ lines.push(`\u274C **API \u8FDE\u901A\u6027**: \u63A2\u6D4B\u5F02\u5E38 - ${err instanceof Error ? err.message : String(err)}`);
60
+ }
61
+ return {
62
+ status,
63
+ markdown: lines.join("\n")
64
+ };
65
+ }
66
+ const INCOMPLETE_PROFILES = /* @__PURE__ */ new Set(["minimal", "coding", "messaging"]);
67
+ function checkToolsProfile(config) {
68
+ const tools = config.tools;
69
+ const profile = tools?.profile;
70
+ if (!profile) {
71
+ return {
72
+ status: "pass",
73
+ markdown: "\u2705 \u98DE\u4E66\u5DE5\u5177\u52A0\u8F7D\u6682\u672A\u53D1\u73B0\u5F02\u5E38"
74
+ };
75
+ }
76
+ if (INCOMPLETE_PROFILES.has(profile)) {
77
+ return {
78
+ status: "warn",
79
+ markdown: `\u26A0\uFE0F **\u5DE5\u5177\u57FA\u7840\u5141\u8BB8\u5217\u8868**: \u5F53\u524D\u4E3A \`${profile}\`\uFF0C\u98DE\u4E66\u5DE5\u5177\u53EF\u80FD\u65E0\u6CD5\u52A0\u8F7D\u3002\u53EF\u4EE5\u6309\u9700\u4FEE\u6539\u914D\u7F6E\uFF1A
80
+ \`\`\`
81
+ openclaw config set tools.profile "full"
82
+ openclaw gateway restart
83
+ \`\`\`
84
+ \u{1F4D6} \u53C2\u8003\u6587\u6863: https://docs.openclaw.ai/zh-CN/tools`
85
+ };
86
+ }
87
+ return {
88
+ status: "pass",
89
+ markdown: `\u2705 \u98DE\u4E66\u5DE5\u5177\u52A0\u8F7D\u6682\u672A\u53D1\u73B0\u5F02\u5E38`
90
+ };
91
+ }
92
+ async function checkAppPermissions(account, sdk) {
93
+ const { appId } = account;
94
+ try {
95
+ const grantedScopes = await getAppGrantedScopes(sdk, appId, "tenant");
96
+ const requiredMissing = missingScopes(grantedScopes, Array.from(REQUIRED_APP_SCOPES));
97
+ if (requiredMissing.length === 0) {
98
+ return {
99
+ status: "pass",
100
+ markdown: `\u5168\u90E8 ${REQUIRED_APP_SCOPES.length} \u4E2A\u5FC5\u9700\u6743\u9650\u5DF2\u5F00\u901A`,
101
+ missingScopes: []
102
+ };
103
+ }
104
+ const lines = [];
105
+ let applyUrl = `https://open.feishu.cn/app/${appId}/auth?op_from=feishu-openclaw&token_type=tenant`;
106
+ if (requiredMissing.length < 20) {
107
+ applyUrl = `https://open.feishu.cn/app/${appId}/auth?q=${encodeURIComponent(requiredMissing.join(","))}&op_from=feishu-openclaw&token_type=tenant`;
108
+ }
109
+ lines.push(`\u7F3A\u5C11 ${requiredMissing.length} \u4E2A\u5FC5\u9700\u6743\u9650\u3002\u9700\u5E94\u7528\u7BA1\u7406\u5458\u7533\u8BF7\u5F00\u901A [\u7533\u8BF7](${applyUrl})`);
110
+ lines.push("");
111
+ for (const scope of requiredMissing) {
112
+ lines.push(`- ${scope}`);
113
+ }
114
+ return {
115
+ status: "fail",
116
+ markdown: lines.join("\n"),
117
+ missingScopes: requiredMissing
118
+ };
119
+ } catch (err) {
120
+ const applyUrl = `https://open.feishu.cn/app/${appId}/auth?q=application:application:self_manage&op_from=feishu-openclaw&token_type=tenant`;
121
+ if (err instanceof AppScopeCheckFailedError) {
122
+ return {
123
+ status: "fail",
124
+ markdown: `\u65E0\u6CD5\u67E5\u8BE2\u5E94\u7528\u6743\u9650\u72B6\u6001\u3002\u539F\u56E0\uFF1A\u672A\u5F00\u901A application:application:self_manage \u6743\u9650
125
+
126
+ \u9700\u5E94\u7528\u7BA1\u7406\u5458\u7533\u8BF7\u5F00\u901A [\u7533\u8BF7](${applyUrl})`,
127
+ missingScopes: []
128
+ };
129
+ }
130
+ return {
131
+ status: "fail",
132
+ markdown: `\u65E0\u6CD5\u67E5\u8BE2\u5E94\u7528\u6743\u9650\u72B6\u6001\u3002${err instanceof Error ? err.message : String(err)}
133
+
134
+ \u5EFA\u8BAE\u68C0\u67E5 application:application:self_manage \u6743\u9650 [\u7533\u8BF7](${applyUrl})`,
135
+ missingScopes: []
136
+ };
137
+ }
138
+ }
139
+ function generatePermissionTable(appGrantedScopes, userGrantedScopes, hasValidUser) {
140
+ let allScopes = getAllToolScopes();
141
+ allScopes = filterSensitiveScopes(allScopes);
142
+ const appSet = new Set(appGrantedScopes);
143
+ const userSet = new Set(userGrantedScopes);
144
+ const lines = [];
145
+ lines.push("| \u6743\u9650\u540D\u79F0 | \u5E94\u7528\u5DF2\u5F00\u901A | \u7528\u6237\u5DF2\u6388\u6743 |");
146
+ lines.push("|----------|-----------|-----------|");
147
+ for (const scope of allScopes) {
148
+ const appGranted = appSet.has(scope) ? "\u2705" : "\u274C";
149
+ const userGranted = !hasValidUser ? "\u2796" : userSet.has(scope) ? "\u2705" : "\u274C";
150
+ lines.push(`| ${scope} | ${appGranted} | ${userGranted} |`);
151
+ }
152
+ return lines.join("\n");
153
+ }
154
+ async function checkUserPermissions(account, sdk) {
155
+ const { appId } = account;
156
+ const lines = [];
157
+ try {
158
+ const ownerId = await getAppOwnerFallback(account, sdk);
159
+ const token = ownerId ? await getStoredToken(appId, ownerId) : null;
160
+ const hasUserAuth = !!token;
161
+ let authStatus = "warn";
162
+ let refreshStatus = "warn";
163
+ let validCount = 0;
164
+ let scopes = [];
165
+ let userTokenStatus = "expired";
166
+ let userMissing = [];
167
+ const appUserScopes = await getAppGrantedScopes(sdk, appId, "user");
168
+ const allScopes = getAllToolScopes();
169
+ const appGrantedCount = appUserScopes.filter((s) => allScopes.includes(s)).length;
170
+ if (hasUserAuth) {
171
+ const status = tokenStatus(token);
172
+ userTokenStatus = status;
173
+ scopes = token.scope.split(" ").filter(Boolean);
174
+ validCount = status === "valid" ? 1 : 0;
175
+ const needsRefreshCount = status === "needs_refresh" ? 1 : 0;
176
+ const expiredCount = status === "expired" ? 1 : 0;
177
+ authStatus = expiredCount > 0 ? "warn" : validCount === 1 ? "pass" : "warn";
178
+ const authEmoji = authStatus === "pass" ? "\u2705" : "\u26A0\uFE0F";
179
+ lines.push(
180
+ `${authEmoji} **\u6388\u6743\u72B6\u6001**: \u5171 1 \u4E2A\u7528\u6237 | \u2713 \u6709\u6548: ${validCount}, \u27F3 \u9700\u5237\u65B0: ${needsRefreshCount}, \u2717 \u5DF2\u8FC7\u671F: ${expiredCount}`
181
+ );
182
+ const hasOfflineAccess = scopes.includes("offline_access");
183
+ refreshStatus = hasOfflineAccess ? "pass" : "warn";
184
+ const refreshEmoji = refreshStatus === "pass" ? "\u2705" : "\u26A0\uFE0F";
185
+ lines.push(
186
+ `${refreshEmoji} **Token \u81EA\u52A8\u5237\u65B0**: ${hasOfflineAccess ? "\u2713 \u5DF2\u5F00\u542F\u81EA\u52A8\u5237\u65B0 (1/1 \u4E2A\u7528\u6237)" : "\u2717 \u672A\u5F00\u542F\u81EA\u52A8\u5237\u65B0\uFF0CToken \u5C06\u5728 2 \u5C0F\u65F6\u540E\u8FC7\u671F"}`
187
+ );
188
+ } else {
189
+ lines.push("\u26A0\uFE0F **\u6682\u65E0\u7528\u6237\u6388\u6743**");
190
+ lines.push("");
191
+ lines.push("\u5C1A\u672A\u6709\u7528\u6237\u901A\u8FC7 OAuth \u6388\u6743\u3002\u7528\u6237\u9996\u6B21\u4F7F\u7528\u9700\u4EE5\u7528\u6237\u8EAB\u4EFD\u7684\u529F\u80FD\u65F6\uFF0C\u4F1A\u81EA\u52A8\u89E6\u53D1\u6388\u6743\u6D41\u7A0B\u3002");
192
+ lines.push("");
193
+ }
194
+ const userGrantedCount = validCount === 1 ? scopes.filter((s) => allScopes.includes(s)).length : 0;
195
+ if (hasUserAuth && validCount === 1) {
196
+ const scopeSet = new Set(scopes);
197
+ userMissing = allScopes.filter((s) => !scopeSet.has(s));
198
+ }
199
+ const tableStatus = appGrantedCount < allScopes.length || userGrantedCount < allScopes.length ? appGrantedCount < allScopes.length ? "fail" : "warn" : "pass";
200
+ const tableEmoji = tableStatus === "pass" ? "\u2705" : tableStatus === "warn" ? "\u26A0\uFE0F" : "\u274C";
201
+ if (validCount === 0) {
202
+ lines.push(`**\u6743\u9650\u5BF9\u7167**: \u5E94\u7528 **${appGrantedCount}/${allScopes.length}** \u5DF2\u5F00\u901A\uFF0C\u7528\u6237 **\u6682\u65E0\u6388\u6743**`);
203
+ } else if (userGrantedCount < allScopes.length) {
204
+ lines.push(
205
+ `${tableEmoji} **\u7528\u6237\u8EAB\u4EFD\u6743\u9650\u4E0D\u8DB3**: \u5E94\u7528 **${appGrantedCount}/${allScopes.length}** \u5DF2\u5F00\u901A\uFF0C\u7528\u6237 **${userGrantedCount}/${allScopes.length}** \u5DF2\u6388\u6743`
206
+ );
207
+ } else {
208
+ lines.push(
209
+ `${tableEmoji} **\u6743\u9650\u5BF9\u7167**: \u5E94\u7528 **${appGrantedCount}/${allScopes.length}** \u5DF2\u5F00\u901A\uFF0C\u7528\u6237 **${userGrantedCount}/${allScopes.length}** \u5DF2\u6388\u6743`
210
+ );
211
+ }
212
+ lines.push("");
213
+ if (appGrantedCount < allScopes.length) {
214
+ const appMissingScopes = allScopes.filter((s) => !appUserScopes.includes(s));
215
+ let appApplyUrl = `https://open.feishu.cn/app/${appId}/auth?op_from=feishu-openclaw&token_type=user`;
216
+ if (appMissingScopes.length < 20) {
217
+ appApplyUrl = `https://open.feishu.cn/app/${appId}/auth?q=${encodeURIComponent(appMissingScopes.join(","))}&op_from=feishu-openclaw&token_type=user`;
218
+ }
219
+ lines.push(`\u{1F4A1} \u5E94\u7528\u7F3A\u5C11 ${appMissingScopes.length} \u4E2A\u7528\u6237\u8EAB\u4EFD\u6743\u9650\u3002\u9700\u5E94\u7528\u7BA1\u7406\u5458\u7533\u8BF7\u5F00\u901A [\u7533\u8BF7](${appApplyUrl})`);
220
+ }
221
+ if (userGrantedCount < allScopes.length && validCount > 0) {
222
+ lines.push(`\u{1F4A1} \u7528\u6237\u9700\u8981\u91CD\u65B0\u6388\u6743\u4EE5\u83B7\u5F97\u5B8C\u6574\u6743\u9650\uFF0C\u53EF\u4EE5\u5411\u673A\u5668\u4EBA\u53D1\u9001\u6D88\u606F "**/feishu auth**"`);
223
+ lines.push("");
224
+ } else if (!hasUserAuth) {
225
+ lines.push(`\u{1F4A1} \u7528\u6237\u9700\u8981\u8FDB\u884C OAuth \u6388\u6743\uFF0C\u53EF\u4EE5\u5411\u673A\u5668\u4EBA\u53D1\u9001\u6D88\u606F "**/feishu auth**"`);
226
+ lines.push("");
227
+ }
228
+ const table = generatePermissionTable(appUserScopes, validCount === 1 ? scopes : [], validCount === 1);
229
+ lines.push(table);
230
+ const overallStatus = tableStatus === "fail" ? "fail" : authStatus === "warn" || refreshStatus === "warn" || tableStatus === "warn" ? "warn" : "pass";
231
+ return {
232
+ status: overallStatus,
233
+ markdown: lines.join("\n"),
234
+ hasAuth: hasUserAuth,
235
+ tokenExpired: userTokenStatus === "expired",
236
+ missingUserScopes: userMissing
237
+ };
238
+ } catch (err) {
239
+ const applyUrl = `https://open.feishu.cn/app/${appId}/auth?q=application:application:self_manage&op_from=feishu-openclaw&token_type=tenant`;
240
+ if (err instanceof AppScopeCheckFailedError) {
241
+ return {
242
+ status: "warn",
243
+ markdown: `\u7528\u6237\u6743\u9650\u68C0\u67E5\u5931\u8D25\uFF1A\u65E0\u6CD5\u67E5\u8BE2\u5E94\u7528\u6743\u9650\u3002\u539F\u56E0\uFF1A\u672A\u5F00\u901A application:application:self_manage \u6743\u9650
244
+
245
+ \u9700\u5E94\u7528\u7BA1\u7406\u5458\u7533\u8BF7\u5F00\u901A [\u7533\u8BF7](${applyUrl})`,
246
+ hasAuth: false,
247
+ tokenExpired: false,
248
+ missingUserScopes: []
249
+ };
250
+ }
251
+ return {
252
+ status: "warn",
253
+ markdown: `\u7528\u6237\u6743\u9650\u68C0\u67E5\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`,
254
+ hasAuth: false,
255
+ tokenExpired: false,
256
+ missingUserScopes: []
257
+ };
258
+ }
259
+ }
260
+ async function runFeishuDoctor(config, currentAccountId) {
261
+ const lines = [];
262
+ const globalCfg = resolveGlobalConfig(config);
263
+ const allAccounts = getEnabledLarkAccounts(globalCfg);
264
+ if (allAccounts.length === 0) {
265
+ return "\u274C **\u9519\u8BEF**: \u672A\u627E\u5230\u5DF2\u542F\u7528\u7684\u98DE\u4E66\u8D26\u6237\n\n\u8BF7\u5728 OpenClaw \u914D\u7F6E\u6587\u4EF6\u4E2D\u914D\u7F6E\u98DE\u4E66\u8D26\u6237\u5E76\u542F\u7528\u3002";
266
+ }
267
+ const accounts = currentAccountId ? allAccounts.filter((a) => a.accountId === currentAccountId) : allAccounts;
268
+ if (accounts.length === 0) {
269
+ return `\u274C **\u9519\u8BEF**: \u672A\u627E\u5230\u8D26\u6237 "${currentAccountId}"
270
+
271
+ \u5F53\u524D\u5DF2\u542F\u7528\u7684\u8D26\u6237: ${allAccounts.map((a) => a.accountId).join(", ")}`;
272
+ }
273
+ lines.push("### \u98DE\u4E66\u63D2\u4EF6\u8BCA\u65AD");
274
+ lines.push("");
275
+ lines.push(`\u63D2\u4EF6\u7248\u672C: ${getPluginVersion()} | \u8BCA\u65AD\u65F6\u95F4: ${formatTimestamp(/* @__PURE__ */ new Date())}`);
276
+ lines.push("");
277
+ lines.push("---");
278
+ lines.push("");
279
+ const toolsResult = checkToolsProfile(config);
280
+ const toolsTitle = toolsResult.status === "pass" ? "#### \u2705 \u5DE5\u5177\u914D\u7F6E\u68C0\u67E5\u901A\u8FC7" : "#### \u26A0\uFE0F \u5DE5\u5177\u914D\u7F6E\u68C0\u67E5\u5F02\u5E38";
281
+ lines.push(toolsTitle);
282
+ lines.push("");
283
+ lines.push(toolsResult.markdown);
284
+ lines.push("");
285
+ lines.push("---");
286
+ lines.push("");
287
+ for (let i = 0; i < accounts.length; i++) {
288
+ const account = accounts[i];
289
+ const sdk = LarkClient.fromAccount(account).sdk;
290
+ const accountLabel = account.accountId || account.appId;
291
+ if (accounts.length > 1) {
292
+ lines.push(`### \u8D26\u6237 ${i + 1}: ${accountLabel}`);
293
+ lines.push("");
294
+ }
295
+ const basicInfoResult = await checkBasicInfo(account, config);
296
+ const basicTitle = basicInfoResult.status === "pass" ? "#### \u2705 \u73AF\u5883\u4FE1\u606F\u68C0\u67E5\u901A\u8FC7" : "#### \u274C \u73AF\u5883\u4FE1\u606F\u68C0\u67E5\u672A\u901A\u8FC7";
297
+ lines.push(basicTitle);
298
+ lines.push("");
299
+ lines.push(basicInfoResult.markdown);
300
+ lines.push("");
301
+ lines.push("---");
302
+ lines.push("");
303
+ const appResult = await checkAppPermissions(account, sdk);
304
+ const appTitle = appResult.status === "pass" ? "#### \u2705 \u5E94\u7528\u8EAB\u4EFD\u6743\u9650\u68C0\u67E5\u901A\u8FC7" : "#### \u274C \u5E94\u7528\u8EAB\u4EFD\u6743\u9650\u68C0\u67E5\u672A\u901A\u8FC7";
305
+ lines.push(appTitle);
306
+ lines.push("");
307
+ lines.push(appResult.markdown);
308
+ lines.push("");
309
+ lines.push("---");
310
+ lines.push("");
311
+ const userResult = await checkUserPermissions(account, sdk);
312
+ const userTitle = userResult.status === "pass" ? "#### \u2705 \u7528\u6237\u8EAB\u4EFD\u6743\u9650\u68C0\u67E5\u901A\u8FC7" : "#### \u274C \u7528\u6237\u8EAB\u4EFD\u6743\u9650\u68C0\u67E5\u672A\u901A\u8FC7";
313
+ lines.push(userTitle);
314
+ lines.push("");
315
+ lines.push(userResult.markdown);
316
+ lines.push("");
317
+ if (i < accounts.length - 1) {
318
+ lines.push("---");
319
+ lines.push("");
320
+ }
321
+ }
322
+ return lines.join("\n");
323
+ }
324
+ export {
325
+ runFeishuDoctor
326
+ };
327
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/commands/doctor.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * feishu-doctor \u8BCA\u65AD\u62A5\u544A Markdown \u683C\u5F0F\u5316\uFF08\u5B8C\u5168\u91CD\u6784\u7248\uFF09\n *\n * \u76F4\u63A5\u751F\u6210 Markdown \u8BCA\u65AD\u62A5\u544A\uFF0C\u4E0D\u4F9D\u8D56 diagnose.ts \u7684\u4EFB\u4F55\u67B6\u6784\u548C\u4EE3\u7801\u3002\n * \u6309\u7167 doctor_template.md \u7684\u683C\u5F0F\u89C4\u8303\u5B9E\u73B0\u3002\n */\n\nimport type { OpenClawConfig } from 'openclaw/plugin-sdk';\nimport type * as Lark from '@larksuiteoapi/node-sdk';\n\nimport { getEnabledLarkAccounts } from '../core/accounts';\nimport { LarkClient } from '../core/lark-client';\n\n/**\n * Resolve the global config for cross-account operations.\n *\n * Plugin commands receive an account-scoped config where `channels.feishu`\n * has been replaced with the merged per-account config (the `accounts` map\n * is stripped by `baseConfig()`). Commands that enumerate all accounts\n * need the original global config to see the full `accounts` map.\n */\nfunction resolveGlobalConfig(config: OpenClawConfig): OpenClawConfig {\n return LarkClient.globalConfig ?? config;\n}\nimport type { ConfiguredLarkAccount } from '../core/types';\nimport { getAppGrantedScopes, missingScopes } from '../core/app-scope-checker';\nimport { getAppOwnerFallback } from '../core/app-owner-fallback';\nimport { getStoredToken, tokenStatus } from '../core/token-store';\n\nimport { filterSensitiveScopes, REQUIRED_APP_SCOPES, TOOL_SCOPES } from '../core/tool-scopes';\nimport { probeFeishu } from '../channel/probe';\nimport { AppScopeCheckFailedError } from '../core/tool-client';\nimport { getPluginVersion } from '../core/version';\n// TODO: \u6682\u65F6\u6CE8\u91CA\u6389\uFF0C\u7B49\u4EA7\u54C1\u7B56\u7565\u660E\u786E\u540E\u518D\u653E\u5F00\n// import { checkMultiAccountIsolation, formatIsolationWarning } from \"../core/security-check\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype CheckStatus = 'pass' | 'warn' | 'fail';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * \u683C\u5F0F\u5316\u65F6\u95F4\u6233\u4E3A \"YYYY-MM-DD HH:mm:ss\"\n */\nfunction formatTimestamp(date: Date): string {\n return date.toLocaleString('sv-SE', { timeZone: 'Asia/Shanghai' }).replace('T', ' ');\n}\n\n/**\n * \u83B7\u53D6\u6240\u6709\u5DE5\u5177\u52A8\u4F5C\u9700\u8981\u7684\u552F\u4E00 scope \u5217\u8868\uFF08\u4ECE diagnose.ts \u590D\u5236\uFF09\n */\nfunction getAllToolScopes(): string[] {\n const scopesSet = new Set<string>();\n for (const scopes of Object.values(TOOL_SCOPES)) {\n for (const scope of scopes) {\n scopesSet.add(scope);\n }\n }\n return Array.from(scopesSet).sort();\n}\n\n// ---------------------------------------------------------------------------\n// \u57FA\u7840\u4FE1\u606F\u68C0\u67E5\n// ---------------------------------------------------------------------------\n\n/**\n * \u63A9\u7801\u654F\u611F\u4FE1\u606F\uFF08appSecret\uFF09\n */\nfunction maskSecret(secret?: string): string {\n if (!secret) return '(\u672A\u8BBE\u7F6E)';\n if (secret.length <= 4) return '****';\n return secret.slice(0, 4) + '****';\n}\n\n/**\n * \u68C0\u67E5\u57FA\u7840\u4FE1\u606F\u548C\u8D26\u53F7\u72B6\u6001\n */\nasync function checkBasicInfo(\n account: ConfiguredLarkAccount,\n config: OpenClawConfig,\n): Promise<{ status: CheckStatus; markdown: string }> {\n const lines: string[] = [];\n let status: CheckStatus = 'pass';\n\n // \u65E7\u7248\u5B98\u65B9\u63D2\u4EF6\u662F\u5426\u5DF2\u7981\u7528\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const feishuEntry = (config as any).plugins?.entries?.feishu;\n if (feishuEntry && feishuEntry.enabled !== false) {\n status = 'fail';\n lines.push(\n '\u274C **\u65E7\u7248\u63D2\u4EF6**: \u68C0\u6D4B\u5230\u65E7\u7248\u5B98\u65B9\u63D2\u4EF6\u672A\u7981\u7528\\n' +\n '\uD83D\uDC49 \u8BF7\u4F9D\u6B21\u8FD0\u884C\u547D\u4EE4\uFF1A\\n' +\n '```\\n' +\n 'openclaw config set plugins.entries.feishu.enabled false --json\\n' +\n 'openclaw gateway restart\\n' +\n '```',\n );\n } else {\n lines.push('\u2705 **\u65E7\u7248\u63D2\u4EF6**: \u5DF2\u7981\u7528');\n }\n\n lines.push(`\u2705 **\u51ED\u8BC1\u5B8C\u6574\u6027**: appId: ${account.appId}, appSecret: ${maskSecret(account.appSecret)}`);\n lines.push(`\u2705 **\u8D26\u6237\u542F\u7528**: \u5DF2\u542F\u7528`);\n\n // API \u8FDE\u901A\u6027\n try {\n const probeResult = await probeFeishu({\n accountId: account.accountId,\n appId: account.appId,\n appSecret: account.appSecret,\n brand: account.brand,\n });\n\n if (probeResult.ok) {\n lines.push(`\u2705 **API \u8FDE\u901A\u6027**: \u8FDE\u63A5\u6210\u529F`);\n } else {\n status = 'fail';\n lines.push(`\u274C **API \u8FDE\u901A\u6027**: \u8FDE\u63A5\u5931\u8D25 - ${probeResult.error}`);\n }\n } catch (err) {\n status = 'fail';\n lines.push(`\u274C **API \u8FDE\u901A\u6027**: \u63A2\u6D4B\u5F02\u5E38 - ${err instanceof Error ? err.message : String(err)}`);\n }\n\n return {\n status,\n markdown: lines.join('\\n'),\n };\n}\n\n// ---------------------------------------------------------------------------\n// \u5DE5\u5177\u914D\u7F6E\u68C0\u67E5\n// ---------------------------------------------------------------------------\n\nconst INCOMPLETE_PROFILES = new Set(['minimal', 'coding', 'messaging']);\n\nfunction checkToolsProfile(config: OpenClawConfig): { status: CheckStatus; markdown: string } {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const tools = (config as any).tools;\n const profile: string | undefined = tools?.profile;\n\n if (!profile) {\n return {\n status: 'pass',\n markdown: '\u2705 \u98DE\u4E66\u5DE5\u5177\u52A0\u8F7D\u6682\u672A\u53D1\u73B0\u5F02\u5E38',\n };\n }\n\n if (INCOMPLETE_PROFILES.has(profile)) {\n return {\n status: 'warn',\n markdown:\n `\u26A0\uFE0F **\u5DE5\u5177\u57FA\u7840\u5141\u8BB8\u5217\u8868**: \u5F53\u524D\u4E3A \\`${profile}\\`\uFF0C\u98DE\u4E66\u5DE5\u5177\u53EF\u80FD\u65E0\u6CD5\u52A0\u8F7D\u3002\u53EF\u4EE5\u6309\u9700\u4FEE\u6539\u914D\u7F6E\uFF1A\\n` +\n '```\\n' +\n 'openclaw config set tools.profile \"full\"\\n' +\n 'openclaw gateway restart\\n' +\n '```\\n' +\n '\uD83D\uDCD6 \u53C2\u8003\u6587\u6863: https://docs.openclaw.ai/zh-CN/tools',\n };\n }\n\n // profile === \"full\" \u6216\u5176\u4ED6\u672A\u77E5\u503C\n return {\n status: 'pass',\n markdown: `\u2705 \u98DE\u4E66\u5DE5\u5177\u52A0\u8F7D\u6682\u672A\u53D1\u73B0\u5F02\u5E38`,\n };\n}\n\n// ---------------------------------------------------------------------------\n// \u5E94\u7528\u6743\u9650\u68C0\u67E5\n// ---------------------------------------------------------------------------\n\n/**\n * \u68C0\u67E5\u5E94\u7528\u6743\u9650\u72B6\u6001\n */\nasync function checkAppPermissions(\n account: ConfiguredLarkAccount,\n sdk: Lark.Client,\n): Promise<{ status: CheckStatus; markdown: string; missingScopes: string[] }> {\n const { appId } = account;\n\n try {\n // \u83B7\u53D6\u5E94\u7528\u5DF2\u5F00\u901A\u7684\u6743\u9650\uFF08tenant token\uFF09\n const grantedScopes = await getAppGrantedScopes(sdk, appId, 'tenant');\n\n // \u8BA1\u7B97\u7F3A\u5931\u7684\u5FC5\u9700\u6743\u9650\n const requiredMissing = missingScopes(grantedScopes, Array.from(REQUIRED_APP_SCOPES));\n\n if (requiredMissing.length === 0) {\n // \u5168\u90E8\u6743\u9650\u5DF2\u5F00\u901A\n return {\n status: 'pass',\n markdown: `\u5168\u90E8 ${REQUIRED_APP_SCOPES.length} \u4E2A\u5FC5\u9700\u6743\u9650\u5DF2\u5F00\u901A`,\n missingScopes: [],\n };\n }\n\n // \u7F3A\u5C11\u5FC5\u9700\u6743\u9650\n const lines: string[] = [];\n let applyUrl = `https://open.feishu.cn/app/${appId}/auth?op_from=feishu-openclaw&token_type=tenant`;\n if (requiredMissing.length < 20) {\n applyUrl = `https://open.feishu.cn/app/${appId}/auth?q=${encodeURIComponent(requiredMissing.join(','))}&op_from=feishu-openclaw&token_type=tenant`;\n }\n lines.push(`\u7F3A\u5C11 ${requiredMissing.length} \u4E2A\u5FC5\u9700\u6743\u9650\u3002\u9700\u5E94\u7528\u7BA1\u7406\u5458\u7533\u8BF7\u5F00\u901A [\u7533\u8BF7](${applyUrl})`);\n lines.push('');\n for (const scope of requiredMissing) {\n lines.push(`- ${scope}`);\n }\n\n return {\n status: 'fail',\n markdown: lines.join('\\n'),\n missingScopes: requiredMissing,\n };\n } catch (err) {\n // API \u8C03\u7528\u5931\u8D25\uFF08\u901A\u5E38\u662F\u7F3A\u5C11 application:application:self_manage \u6743\u9650\uFF09\n const applyUrl = `https://open.feishu.cn/app/${appId}/auth?q=application:application:self_manage&op_from=feishu-openclaw&token_type=tenant`;\n\n if (err instanceof AppScopeCheckFailedError) {\n return {\n status: 'fail',\n markdown: `\u65E0\u6CD5\u67E5\u8BE2\u5E94\u7528\u6743\u9650\u72B6\u6001\u3002\u539F\u56E0\uFF1A\u672A\u5F00\u901A application:application:self_manage \u6743\u9650\\n\\n\u9700\u5E94\u7528\u7BA1\u7406\u5458\u7533\u8BF7\u5F00\u901A [\u7533\u8BF7](${applyUrl})`,\n missingScopes: [],\n };\n }\n\n return {\n status: 'fail',\n markdown: `\u65E0\u6CD5\u67E5\u8BE2\u5E94\u7528\u6743\u9650\u72B6\u6001\u3002${err instanceof Error ? err.message : String(err)}\\n\\n\u5EFA\u8BAE\u68C0\u67E5 application:application:self_manage \u6743\u9650 [\u7533\u8BF7](${applyUrl})`,\n missingScopes: [],\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// \u7528\u6237\u6743\u9650\u68C0\u67E5\n// ---------------------------------------------------------------------------\n\n/**\n * \u751F\u6210\u6743\u9650\u5BF9\u7167\u8868\n */\nfunction generatePermissionTable(\n appGrantedScopes: string[],\n userGrantedScopes: string[],\n hasValidUser: boolean,\n): string {\n let allScopes = getAllToolScopes();\n allScopes = filterSensitiveScopes(allScopes);\n const appSet = new Set(appGrantedScopes);\n const userSet = new Set(userGrantedScopes);\n\n const lines: string[] = [];\n lines.push('| \u6743\u9650\u540D\u79F0 | \u5E94\u7528\u5DF2\u5F00\u901A | \u7528\u6237\u5DF2\u6388\u6743 |');\n lines.push('|----------|-----------|-----------|');\n\n for (const scope of allScopes) {\n const appGranted = appSet.has(scope) ? '\u2705' : '\u274C';\n // \u5982\u679C\u6CA1\u6709\u6709\u6548\u7528\u6237\uFF0C\u663E\u793A \u2796\uFF1B\u5426\u5219\u6839\u636E\u6388\u6743\u60C5\u51B5\u663E\u793A \u2705 \u6216 \u274C\n const userGranted = !hasValidUser ? '\u2796' : userSet.has(scope) ? '\u2705' : '\u274C';\n lines.push(`| ${scope} | ${appGranted} | ${userGranted} |`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * \u68C0\u67E5\u7528\u6237\u6743\u9650\u72B6\u6001\n */\nasync function checkUserPermissions(\n account: ConfiguredLarkAccount,\n sdk: Lark.Client,\n): Promise<{\n status: CheckStatus;\n markdown: string;\n hasAuth: boolean;\n tokenExpired: boolean;\n missingUserScopes: string[];\n}> {\n const { appId } = account;\n const lines: string[] = [];\n\n try {\n // 1. \u83B7\u53D6\u5E94\u7528\u6240\u6709\u8005\n const ownerId = await getAppOwnerFallback(account, sdk);\n\n // 2. \u8BFB\u53D6 token\n const token = ownerId ? await getStoredToken(appId, ownerId) : null;\n\n // \u5224\u65AD\u662F\u5426\u6709\u6709\u6548\u7684\u7528\u6237\u6388\u6743\n const hasUserAuth = !!token;\n\n // \u53D8\u91CF\u521D\u59CB\u5316\n let authStatus: CheckStatus = 'warn';\n let refreshStatus: CheckStatus = 'warn';\n let validCount = 0;\n let scopes: string[] = [];\n let userTokenStatus: 'valid' | 'needs_refresh' | 'expired' = 'expired';\n let userMissing: string[] = [];\n\n // \u83B7\u53D6\u5E94\u7528\u5F00\u901A\u7684\u652F\u6301 user token \u7684\u6743\u9650\n const appUserScopes = await getAppGrantedScopes(sdk, appId, 'user');\n const allScopes = getAllToolScopes();\n const appGrantedCount = appUserScopes.filter((s) => allScopes.includes(s)).length;\n\n if (hasUserAuth) {\n // \u6709\u7528\u6237\u6388\u6743 - \u68C0\u67E5\u6388\u6743\u72B6\u6001\n const status = tokenStatus(token);\n userTokenStatus = status;\n scopes = token.scope.split(' ').filter(Boolean);\n validCount = status === 'valid' ? 1 : 0;\n const needsRefreshCount = status === 'needs_refresh' ? 1 : 0;\n const expiredCount = status === 'expired' ? 1 : 0;\n\n authStatus = expiredCount > 0 ? 'warn' : validCount === 1 ? 'pass' : 'warn';\n const authEmoji = authStatus === 'pass' ? '\u2705' : '\u26A0\uFE0F';\n\n lines.push(\n `${authEmoji} **\u6388\u6743\u72B6\u6001**: \u5171 1 \u4E2A\u7528\u6237 | \u2713 \u6709\u6548: ${validCount}, \u27F3 \u9700\u5237\u65B0: ${needsRefreshCount}, \u2717 \u5DF2\u8FC7\u671F: ${expiredCount}`,\n );\n\n // Token \u81EA\u52A8\u5237\u65B0\u68C0\u67E5\n const hasOfflineAccess = scopes.includes('offline_access');\n refreshStatus = hasOfflineAccess ? 'pass' : 'warn';\n const refreshEmoji = refreshStatus === 'pass' ? '\u2705' : '\u26A0\uFE0F';\n\n lines.push(\n `${refreshEmoji} **Token \u81EA\u52A8\u5237\u65B0**: ${hasOfflineAccess ? '\u2713 \u5DF2\u5F00\u542F\u81EA\u52A8\u5237\u65B0 (1/1 \u4E2A\u7528\u6237)' : '\u2717 \u672A\u5F00\u542F\u81EA\u52A8\u5237\u65B0\uFF0CToken \u5C06\u5728 2 \u5C0F\u65F6\u540E\u8FC7\u671F'}`,\n );\n } else {\n // \u6CA1\u6709\u7528\u6237\u6388\u6743\n lines.push('\u26A0\uFE0F **\u6682\u65E0\u7528\u6237\u6388\u6743**');\n lines.push('');\n lines.push('\u5C1A\u672A\u6709\u7528\u6237\u901A\u8FC7 OAuth \u6388\u6743\u3002\u7528\u6237\u9996\u6B21\u4F7F\u7528\u9700\u4EE5\u7528\u6237\u8EAB\u4EFD\u7684\u529F\u80FD\u65F6\uFF0C\u4F1A\u81EA\u52A8\u89E6\u53D1\u6388\u6743\u6D41\u7A0B\u3002');\n lines.push('');\n }\n\n // \u8BA1\u7B97\u7528\u6237\u5DF2\u6388\u6743\u6743\u9650\u6570\n const userGrantedCount = validCount === 1 ? scopes.filter((s) => allScopes.includes(s)).length : 0;\n\n // \u8BA1\u7B97\u7528\u6237\u7F3A\u5931\u7684\u6743\u9650\n if (hasUserAuth && validCount === 1) {\n const scopeSet = new Set(scopes);\n userMissing = allScopes.filter((s) => !scopeSet.has(s));\n }\n\n // \u6743\u9650\u5BF9\u7167\u7EDF\u8BA1\n const tableStatus: CheckStatus =\n appGrantedCount < allScopes.length || userGrantedCount < allScopes.length\n ? appGrantedCount < allScopes.length\n ? 'fail'\n : 'warn'\n : 'pass';\n const tableEmoji = tableStatus === 'pass' ? '\u2705' : tableStatus === 'warn' ? '\u26A0\uFE0F' : '\u274C';\n\n if (validCount === 0) {\n lines.push(`**\u6743\u9650\u5BF9\u7167**: \u5E94\u7528 **${appGrantedCount}/${allScopes.length}** \u5DF2\u5F00\u901A\uFF0C\u7528\u6237 **\u6682\u65E0\u6388\u6743**`);\n } else if (userGrantedCount < allScopes.length) {\n lines.push(\n `${tableEmoji} **\u7528\u6237\u8EAB\u4EFD\u6743\u9650\u4E0D\u8DB3**: \u5E94\u7528 **${appGrantedCount}/${allScopes.length}** \u5DF2\u5F00\u901A\uFF0C\u7528\u6237 **${userGrantedCount}/${allScopes.length}** \u5DF2\u6388\u6743`,\n );\n } else {\n lines.push(\n `${tableEmoji} **\u6743\u9650\u5BF9\u7167**: \u5E94\u7528 **${appGrantedCount}/${allScopes.length}** \u5DF2\u5F00\u901A\uFF0C\u7528\u6237 **${userGrantedCount}/${allScopes.length}** \u5DF2\u6388\u6743`,\n );\n }\n lines.push('');\n\n // \u6DFB\u52A0\u6307\u5F15\u4FE1\u606F\n if (appGrantedCount < allScopes.length) {\n // \u8BA1\u7B97\u7F3A\u5931\u7684\u5E94\u7528\u6743\u9650\n const appMissingScopes = allScopes.filter((s) => !appUserScopes.includes(s));\n let appApplyUrl = `https://open.feishu.cn/app/${appId}/auth?op_from=feishu-openclaw&token_type=user`;\n if (appMissingScopes.length < 20) {\n appApplyUrl = `https://open.feishu.cn/app/${appId}/auth?q=${encodeURIComponent(appMissingScopes.join(','))}&op_from=feishu-openclaw&token_type=user`;\n }\n\n lines.push(`\uD83D\uDCA1 \u5E94\u7528\u7F3A\u5C11 ${appMissingScopes.length} \u4E2A\u7528\u6237\u8EAB\u4EFD\u6743\u9650\u3002\u9700\u5E94\u7528\u7BA1\u7406\u5458\u7533\u8BF7\u5F00\u901A [\u7533\u8BF7](${appApplyUrl})`);\n // lines.push(\"\");\n }\n if (userGrantedCount < allScopes.length && validCount > 0) {\n lines.push(`\uD83D\uDCA1 \u7528\u6237\u9700\u8981\u91CD\u65B0\u6388\u6743\u4EE5\u83B7\u5F97\u5B8C\u6574\u6743\u9650\uFF0C\u53EF\u4EE5\u5411\u673A\u5668\u4EBA\u53D1\u9001\u6D88\u606F \"**/feishu auth**\"`);\n lines.push('');\n } else if (!hasUserAuth) {\n lines.push(`\uD83D\uDCA1 \u7528\u6237\u9700\u8981\u8FDB\u884C OAuth \u6388\u6743\uFF0C\u53EF\u4EE5\u5411\u673A\u5668\u4EBA\u53D1\u9001\u6D88\u606F \"**/feishu auth**\"`);\n lines.push('');\n }\n\n // \u751F\u6210\u8BE6\u7EC6\u6743\u9650\u5BF9\u7167\u8868\n const table = generatePermissionTable(appUserScopes, validCount === 1 ? scopes : [], validCount === 1);\n lines.push(table);\n\n // \u8BA1\u7B97\u603B\u4F53\u72B6\u6001\n const overallStatus: CheckStatus =\n tableStatus === 'fail'\n ? 'fail'\n : authStatus === 'warn' || refreshStatus === 'warn' || tableStatus === 'warn'\n ? 'warn'\n : 'pass';\n\n return {\n status: overallStatus,\n markdown: lines.join('\\n'),\n hasAuth: hasUserAuth,\n tokenExpired: userTokenStatus === 'expired',\n missingUserScopes: userMissing,\n };\n } catch (err) {\n const applyUrl = `https://open.feishu.cn/app/${appId}/auth?q=application:application:self_manage&op_from=feishu-openclaw&token_type=tenant`;\n\n if (err instanceof AppScopeCheckFailedError) {\n return {\n status: 'warn',\n markdown: `\u7528\u6237\u6743\u9650\u68C0\u67E5\u5931\u8D25\uFF1A\u65E0\u6CD5\u67E5\u8BE2\u5E94\u7528\u6743\u9650\u3002\u539F\u56E0\uFF1A\u672A\u5F00\u901A application:application:self_manage \u6743\u9650\\n\\n\u9700\u5E94\u7528\u7BA1\u7406\u5458\u7533\u8BF7\u5F00\u901A [\u7533\u8BF7](${applyUrl})`,\n hasAuth: false,\n tokenExpired: false,\n missingUserScopes: [],\n };\n }\n\n return {\n status: 'warn',\n markdown: `\u7528\u6237\u6743\u9650\u68C0\u67E5\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`,\n hasAuth: false,\n tokenExpired: false,\n missingUserScopes: [],\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// \u4E3B\u51FD\u6570\n// ---------------------------------------------------------------------------\n\n/**\n * \u8FD0\u884C\u98DE\u4E66\u63D2\u4EF6\u8BCA\u65AD\uFF0C\u751F\u6210 Markdown \u683C\u5F0F\u62A5\u544A\u3002\n *\n * @param config - OpenClaw \u914D\u7F6E\n * @param currentAccountId - \u5F53\u524D\u53D1\u9001\u547D\u4EE4\u7684\u673A\u5668\u4EBA\u8D26\u53F7 ID\uFF08\u82E5\u6709\u5219\u53EA\u8BCA\u65AD\u8BE5\u8D26\u53F7\uFF09\n */\nexport async function runFeishuDoctor(config: OpenClawConfig, currentAccountId?: string): Promise<string> {\n const lines: string[] = [];\n\n // 1. \u83B7\u53D6\u76EE\u6807\u8D26\u6237\n // Use the global config to enumerate all accounts \u2014 the passed-in\n // config may be account-scoped (accounts map stripped).\n const globalCfg = resolveGlobalConfig(config);\n const allAccounts = getEnabledLarkAccounts(globalCfg);\n if (allAccounts.length === 0) {\n return '\u274C **\u9519\u8BEF**: \u672A\u627E\u5230\u5DF2\u542F\u7528\u7684\u98DE\u4E66\u8D26\u6237\\n\\n\u8BF7\u5728 OpenClaw \u914D\u7F6E\u6587\u4EF6\u4E2D\u914D\u7F6E\u98DE\u4E66\u8D26\u6237\u5E76\u542F\u7528\u3002';\n }\n\n // \u82E5\u6307\u5B9A\u4E86 accountId\uFF0C\u53EA\u8BCA\u65AD\u8BE5\u8D26\u53F7\n const accounts = currentAccountId ? allAccounts.filter((a) => a.accountId === currentAccountId) : allAccounts;\n\n if (accounts.length === 0) {\n return `\u274C **\u9519\u8BEF**: \u672A\u627E\u5230\u8D26\u6237 \"${currentAccountId}\"\\n\\n\u5F53\u524D\u5DF2\u542F\u7528\u7684\u8D26\u6237: ${allAccounts.map((a) => a.accountId).join(', ')}`;\n }\n\n // 2. \u751F\u6210\u62A5\u544A\u5934\u90E8\n lines.push('### \u98DE\u4E66\u63D2\u4EF6\u8BCA\u65AD');\n lines.push('');\n lines.push(`\u63D2\u4EF6\u7248\u672C: ${getPluginVersion()} | \u8BCA\u65AD\u65F6\u95F4: ${formatTimestamp(new Date())}`);\n lines.push('');\n lines.push('---');\n lines.push('');\n\n // 3. \u5DE5\u5177\u914D\u7F6E\uFF08\u5168\u5C40\uFF0C\u4E0D\u533A\u5206\u8D26\u6237\uFF09\n const toolsResult = checkToolsProfile(config);\n const toolsTitle = toolsResult.status === 'pass' ? '#### \u2705 \u5DE5\u5177\u914D\u7F6E\u68C0\u67E5\u901A\u8FC7' : '#### \u26A0\uFE0F \u5DE5\u5177\u914D\u7F6E\u68C0\u67E5\u5F02\u5E38';\n lines.push(toolsTitle);\n lines.push('');\n lines.push(toolsResult.markdown);\n lines.push('');\n lines.push('---');\n lines.push('');\n\n // 3.5 \u591A\u8D26\u53F7\u9694\u79BB\u68C0\u67E5\uFF08\u5168\u5C40\u95EE\u9898\uFF0C\u59CB\u7EC8\u5C55\u793A\uFF09\n // TODO: \u6682\u65F6\u6CE8\u91CA\u6389\uFF0C\u7B49\u4EA7\u54C1\u7B56\u7565\u660E\u786E\u540E\u518D\u653E\u5F00\n // const isolationStatus = checkMultiAccountIsolation(config);\n // const isolationWarning = formatIsolationWarning(isolationStatus, config);\n // if (isolationWarning) {\n // lines.push(isolationWarning);\n // lines.push(\"\");\n // lines.push(\"---\");\n // lines.push(\"\");\n // }\n\n // 4. \u9010\u8D26\u6237\u8BCA\u65AD\uFF08\u4EC5\u76EE\u6807\u8D26\u6237\uFF09\n for (let i = 0; i < accounts.length; i++) {\n const account = accounts[i] as ConfiguredLarkAccount;\n const sdk = LarkClient.fromAccount(account).sdk;\n const accountLabel = account.accountId || account.appId;\n\n if (accounts.length > 1) {\n lines.push(`### \u8D26\u6237 ${i + 1}: ${accountLabel}`);\n lines.push('');\n }\n\n // 4a. \u73AF\u5883\u4FE1\u606F\n const basicInfoResult = await checkBasicInfo(account, config);\n const basicTitle = basicInfoResult.status === 'pass' ? '#### \u2705 \u73AF\u5883\u4FE1\u606F\u68C0\u67E5\u901A\u8FC7' : '#### \u274C \u73AF\u5883\u4FE1\u606F\u68C0\u67E5\u672A\u901A\u8FC7';\n lines.push(basicTitle);\n lines.push('');\n lines.push(basicInfoResult.markdown);\n lines.push('');\n lines.push('---');\n lines.push('');\n\n // 4b. \u5E94\u7528\u6743\u9650\n const appResult = await checkAppPermissions(account, sdk);\n const appTitle = appResult.status === 'pass' ? '#### \u2705 \u5E94\u7528\u8EAB\u4EFD\u6743\u9650\u68C0\u67E5\u901A\u8FC7' : '#### \u274C \u5E94\u7528\u8EAB\u4EFD\u6743\u9650\u68C0\u67E5\u672A\u901A\u8FC7';\n lines.push(appTitle);\n lines.push('');\n lines.push(appResult.markdown);\n lines.push('');\n lines.push('---');\n lines.push('');\n\n // 4c. \u7528\u6237\u6743\u9650\n const userResult = await checkUserPermissions(account, sdk);\n const userTitle = userResult.status === 'pass' ? '#### \u2705 \u7528\u6237\u8EAB\u4EFD\u6743\u9650\u68C0\u67E5\u901A\u8FC7' : '#### \u274C \u7528\u6237\u8EAB\u4EFD\u6743\u9650\u68C0\u67E5\u672A\u901A\u8FC7';\n lines.push(userTitle);\n lines.push('');\n lines.push(userResult.markdown);\n lines.push('');\n\n if (i < accounts.length - 1) {\n lines.push('---');\n lines.push('');\n }\n }\n\n return lines.join('\\n');\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }