@larksuite/openclaw-lark 2025.7.15-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (426) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +76 -0
  3. package/bin/openclaw-lark.js +39 -0
  4. package/index.d.ts +36 -0
  5. package/index.js +188 -0
  6. package/openclaw.plugin.json +64 -0
  7. package/package.json +63 -0
  8. package/secret-contract-api.d.ts +15 -0
  9. package/secret-contract-api.js +78 -0
  10. package/skills/feishu-bitable/SKILL.md +248 -0
  11. package/skills/feishu-bitable/references/examples.md +813 -0
  12. package/skills/feishu-bitable/references/field-properties.md +763 -0
  13. package/skills/feishu-bitable/references/record-values.md +911 -0
  14. package/skills/feishu-calendar/SKILL.md +242 -0
  15. package/skills/feishu-channel-rules/SKILL.md +18 -0
  16. package/skills/feishu-channel-rules/references/markdown-syntax.md +138 -0
  17. package/skills/feishu-create-doc/SKILL.md +719 -0
  18. package/skills/feishu-fetch-doc/SKILL.md +93 -0
  19. package/skills/feishu-im-read/SKILL.md +163 -0
  20. package/skills/feishu-task/SKILL.md +340 -0
  21. package/skills/feishu-troubleshoot/SKILL.md +70 -0
  22. package/skills/feishu-update-doc/SKILL.md +285 -0
  23. package/src/card/builder.d.ts +152 -0
  24. package/src/card/builder.js +794 -0
  25. package/src/card/card-error.d.ts +91 -0
  26. package/src/card/card-error.js +206 -0
  27. package/src/card/cardkit.d.ts +90 -0
  28. package/src/card/cardkit.js +203 -0
  29. package/src/card/flush-controller.d.ts +45 -0
  30. package/src/card/flush-controller.js +138 -0
  31. package/src/card/image-resolver.d.ts +45 -0
  32. package/src/card/image-resolver.js +116 -0
  33. package/src/card/markdown-style.d.ts +16 -0
  34. package/src/card/markdown-style.js +106 -0
  35. package/src/card/reasoning-utils.d.ts +14 -0
  36. package/src/card/reasoning-utils.js +64 -0
  37. package/src/card/reply-dispatcher-types.d.ts +132 -0
  38. package/src/card/reply-dispatcher-types.js +61 -0
  39. package/src/card/reply-dispatcher.d.ts +15 -0
  40. package/src/card/reply-dispatcher.js +447 -0
  41. package/src/card/reply-mode.d.ts +41 -0
  42. package/src/card/reply-mode.js +70 -0
  43. package/src/card/streaming-card-controller.d.ts +118 -0
  44. package/src/card/streaming-card-controller.js +1045 -0
  45. package/src/card/tool-use-config.d.ts +26 -0
  46. package/src/card/tool-use-config.js +76 -0
  47. package/src/card/tool-use-display.d.ts +37 -0
  48. package/src/card/tool-use-display.js +476 -0
  49. package/src/card/tool-use-trace-store.d.ts +51 -0
  50. package/src/card/tool-use-trace-store.js +271 -0
  51. package/src/card/unavailable-guard.d.ts +35 -0
  52. package/src/card/unavailable-guard.js +87 -0
  53. package/src/channel/abort-detect.d.ts +47 -0
  54. package/src/channel/abort-detect.js +219 -0
  55. package/src/channel/chat-queue.d.ts +41 -0
  56. package/src/channel/chat-queue.js +68 -0
  57. package/src/channel/config-adapter.d.ts +23 -0
  58. package/src/channel/config-adapter.js +107 -0
  59. package/src/channel/directory.d.ts +57 -0
  60. package/src/channel/directory.js +197 -0
  61. package/src/channel/event-handlers.d.ts +17 -0
  62. package/src/channel/event-handlers.js +380 -0
  63. package/src/channel/interactive-dispatch.d.ts +59 -0
  64. package/src/channel/interactive-dispatch.js +195 -0
  65. package/src/channel/monitor.d.ts +17 -0
  66. package/src/channel/monitor.js +140 -0
  67. package/src/channel/onboarding-config.d.ts +18 -0
  68. package/src/channel/onboarding-config.js +96 -0
  69. package/src/channel/onboarding-migrate.d.ts +25 -0
  70. package/src/channel/onboarding-migrate.js +70 -0
  71. package/src/channel/onboarding.d.ts +12 -0
  72. package/src/channel/onboarding.js +300 -0
  73. package/src/channel/plugin.d.ts +13 -0
  74. package/src/channel/plugin.js +310 -0
  75. package/src/channel/probe.d.ts +14 -0
  76. package/src/channel/probe.js +24 -0
  77. package/src/channel/types.d.ts +37 -0
  78. package/src/channel/types.js +8 -0
  79. package/src/commands/auth.d.ts +21 -0
  80. package/src/commands/auth.js +165 -0
  81. package/src/commands/diagnose.d.ts +69 -0
  82. package/src/commands/diagnose.js +848 -0
  83. package/src/commands/doctor.d.ts +27 -0
  84. package/src/commands/doctor.js +588 -0
  85. package/src/commands/index.d.ts +25 -0
  86. package/src/commands/index.js +219 -0
  87. package/src/commands/locale.d.ts +7 -0
  88. package/src/commands/locale.js +8 -0
  89. package/src/core/accounts.d.ts +51 -0
  90. package/src/core/accounts.js +219 -0
  91. package/src/core/agent-config.d.ts +100 -0
  92. package/src/core/agent-config.js +148 -0
  93. package/src/core/api-error.d.ts +48 -0
  94. package/src/core/api-error.js +117 -0
  95. package/src/core/app-owner-fallback.d.ts +22 -0
  96. package/src/core/app-owner-fallback.js +39 -0
  97. package/src/core/app-scope-checker.d.ts +87 -0
  98. package/src/core/app-scope-checker.js +198 -0
  99. package/src/core/auth-errors.d.ts +144 -0
  100. package/src/core/auth-errors.js +160 -0
  101. package/src/core/card-action-operator.d.ts +33 -0
  102. package/src/core/card-action-operator.js +30 -0
  103. package/src/core/chat-info-cache.d.ts +67 -0
  104. package/src/core/chat-info-cache.js +165 -0
  105. package/src/core/comment-target.d.ts +65 -0
  106. package/src/core/comment-target.js +100 -0
  107. package/src/core/config-schema.d.ts +490 -0
  108. package/src/core/config-schema.js +223 -0
  109. package/src/core/device-flow.d.ts +77 -0
  110. package/src/core/device-flow.js +217 -0
  111. package/src/core/domains.d.ts +18 -0
  112. package/src/core/domains.js +34 -0
  113. package/src/core/feishu-fetch.d.ts +18 -0
  114. package/src/core/feishu-fetch.js +28 -0
  115. package/src/core/footer-config.d.ts +24 -0
  116. package/src/core/footer-config.js +51 -0
  117. package/src/core/lark-client.d.ts +125 -0
  118. package/src/core/lark-client.js +468 -0
  119. package/src/core/lark-logger.d.ts +23 -0
  120. package/src/core/lark-logger.js +160 -0
  121. package/src/core/lark-ticket.d.ts +29 -0
  122. package/src/core/lark-ticket.js +40 -0
  123. package/src/core/message-unavailable.d.ts +53 -0
  124. package/src/core/message-unavailable.js +142 -0
  125. package/src/core/owner-policy.d.ts +32 -0
  126. package/src/core/owner-policy.js +55 -0
  127. package/src/core/permission-url.d.ts +22 -0
  128. package/src/core/permission-url.js +76 -0
  129. package/src/core/raw-request.d.ts +27 -0
  130. package/src/core/raw-request.js +90 -0
  131. package/src/core/runtime-store.d.ts +13 -0
  132. package/src/core/runtime-store.js +29 -0
  133. package/src/core/scope-manager.d.ts +168 -0
  134. package/src/core/scope-manager.js +224 -0
  135. package/src/core/sdk-compat.d.ts +20 -0
  136. package/src/core/sdk-compat.js +28 -0
  137. package/src/core/security-check.d.ts +72 -0
  138. package/src/core/security-check.js +184 -0
  139. package/src/core/shutdown-hooks.d.ts +22 -0
  140. package/src/core/shutdown-hooks.js +61 -0
  141. package/src/core/synthetic-target.d.ts +33 -0
  142. package/src/core/synthetic-target.js +40 -0
  143. package/src/core/targets.d.ts +60 -0
  144. package/src/core/targets.js +173 -0
  145. package/src/core/token-store.d.ts +54 -0
  146. package/src/core/token-store.js +326 -0
  147. package/src/core/tool-client.d.ts +176 -0
  148. package/src/core/tool-client.js +426 -0
  149. package/src/core/tool-scopes.d.ts +156 -0
  150. package/src/core/tool-scopes.js +344 -0
  151. package/src/core/tools-config.d.ts +55 -0
  152. package/src/core/tools-config.js +143 -0
  153. package/src/core/types.d.ts +91 -0
  154. package/src/core/types.js +12 -0
  155. package/src/core/uat-client.d.ts +46 -0
  156. package/src/core/uat-client.js +192 -0
  157. package/src/core/version.d.ts +31 -0
  158. package/src/core/version.js +69 -0
  159. package/src/messaging/converters/audio.d.ts +8 -0
  160. package/src/messaging/converters/audio.js +24 -0
  161. package/src/messaging/converters/calendar.d.ts +13 -0
  162. package/src/messaging/converters/calendar.js +56 -0
  163. package/src/messaging/converters/content-converter-helpers.d.ts +30 -0
  164. package/src/messaging/converters/content-converter-helpers.js +82 -0
  165. package/src/messaging/converters/content-converter.d.ts +24 -0
  166. package/src/messaging/converters/content-converter.js +40 -0
  167. package/src/messaging/converters/file.d.ts +8 -0
  168. package/src/messaging/converters/file.js +24 -0
  169. package/src/messaging/converters/folder.d.ts +8 -0
  170. package/src/messaging/converters/folder.js +24 -0
  171. package/src/messaging/converters/hongbao.d.ts +8 -0
  172. package/src/messaging/converters/hongbao.js +20 -0
  173. package/src/messaging/converters/image.d.ts +8 -0
  174. package/src/messaging/converters/image.js +22 -0
  175. package/src/messaging/converters/index.d.ts +8 -0
  176. package/src/messaging/converters/index.js +53 -0
  177. package/src/messaging/converters/interactive/card-converter.d.ts +76 -0
  178. package/src/messaging/converters/interactive/card-converter.js +1177 -0
  179. package/src/messaging/converters/interactive/card-utils.d.ts +9 -0
  180. package/src/messaging/converters/interactive/card-utils.js +47 -0
  181. package/src/messaging/converters/interactive/index.d.ts +8 -0
  182. package/src/messaging/converters/interactive/index.js +25 -0
  183. package/src/messaging/converters/interactive/legacy.d.ts +11 -0
  184. package/src/messaging/converters/interactive/legacy.js +60 -0
  185. package/src/messaging/converters/interactive/types.d.ts +23 -0
  186. package/src/messaging/converters/interactive/types.js +27 -0
  187. package/src/messaging/converters/location.d.ts +8 -0
  188. package/src/messaging/converters/location.js +23 -0
  189. package/src/messaging/converters/merge-forward.d.ts +32 -0
  190. package/src/messaging/converters/merge-forward.js +235 -0
  191. package/src/messaging/converters/post.d.ts +11 -0
  192. package/src/messaging/converters/post.js +235 -0
  193. package/src/messaging/converters/share.d.ts +9 -0
  194. package/src/messaging/converters/share.js +28 -0
  195. package/src/messaging/converters/sticker.d.ts +8 -0
  196. package/src/messaging/converters/sticker.js +22 -0
  197. package/src/messaging/converters/system.d.ts +12 -0
  198. package/src/messaging/converters/system.js +36 -0
  199. package/src/messaging/converters/text.d.ts +8 -0
  200. package/src/messaging/converters/text.js +18 -0
  201. package/src/messaging/converters/todo.d.ts +8 -0
  202. package/src/messaging/converters/todo.js +45 -0
  203. package/src/messaging/converters/types.d.ts +114 -0
  204. package/src/messaging/converters/types.js +8 -0
  205. package/src/messaging/converters/unknown.d.ts +8 -0
  206. package/src/messaging/converters/unknown.js +20 -0
  207. package/src/messaging/converters/utils.d.ts +22 -0
  208. package/src/messaging/converters/utils.js +57 -0
  209. package/src/messaging/converters/video-chat.d.ts +8 -0
  210. package/src/messaging/converters/video-chat.js +31 -0
  211. package/src/messaging/converters/video.d.ts +8 -0
  212. package/src/messaging/converters/video.js +35 -0
  213. package/src/messaging/converters/vote.d.ts +8 -0
  214. package/src/messaging/converters/vote.js +28 -0
  215. package/src/messaging/inbound/bot-content.d.ts +84 -0
  216. package/src/messaging/inbound/bot-content.js +117 -0
  217. package/src/messaging/inbound/bot-loop-guard.d.ts +48 -0
  218. package/src/messaging/inbound/bot-loop-guard.js +89 -0
  219. package/src/messaging/inbound/comment-context.d.ts +82 -0
  220. package/src/messaging/inbound/comment-context.js +353 -0
  221. package/src/messaging/inbound/comment-handler.d.ts +30 -0
  222. package/src/messaging/inbound/comment-handler.js +269 -0
  223. package/src/messaging/inbound/dedup.d.ts +59 -0
  224. package/src/messaging/inbound/dedup.js +121 -0
  225. package/src/messaging/inbound/dispatch-builders.d.ts +104 -0
  226. package/src/messaging/inbound/dispatch-builders.js +241 -0
  227. package/src/messaging/inbound/dispatch-commands.d.ts +22 -0
  228. package/src/messaging/inbound/dispatch-commands.js +131 -0
  229. package/src/messaging/inbound/dispatch-context.d.ts +67 -0
  230. package/src/messaging/inbound/dispatch-context.js +153 -0
  231. package/src/messaging/inbound/dispatch.d.ts +50 -0
  232. package/src/messaging/inbound/dispatch.js +477 -0
  233. package/src/messaging/inbound/enrich.d.ts +102 -0
  234. package/src/messaging/inbound/enrich.js +236 -0
  235. package/src/messaging/inbound/gate-effects.d.ts +23 -0
  236. package/src/messaging/inbound/gate-effects.js +46 -0
  237. package/src/messaging/inbound/gate.d.ts +91 -0
  238. package/src/messaging/inbound/gate.js +342 -0
  239. package/src/messaging/inbound/handler-registry.d.ts +25 -0
  240. package/src/messaging/inbound/handler-registry.js +23 -0
  241. package/src/messaging/inbound/handler.d.ts +37 -0
  242. package/src/messaging/inbound/handler.js +286 -0
  243. package/src/messaging/inbound/media-resolver.d.ts +32 -0
  244. package/src/messaging/inbound/media-resolver.js +91 -0
  245. package/src/messaging/inbound/mention-registry.d.ts +59 -0
  246. package/src/messaging/inbound/mention-registry.js +115 -0
  247. package/src/messaging/inbound/mention.d.ts +48 -0
  248. package/src/messaging/inbound/mention.js +102 -0
  249. package/src/messaging/inbound/parse-io.d.ts +50 -0
  250. package/src/messaging/inbound/parse-io.js +86 -0
  251. package/src/messaging/inbound/parse.d.ts +28 -0
  252. package/src/messaging/inbound/parse.js +128 -0
  253. package/src/messaging/inbound/permission.d.ts +17 -0
  254. package/src/messaging/inbound/permission.js +44 -0
  255. package/src/messaging/inbound/policy.d.ts +95 -0
  256. package/src/messaging/inbound/policy.js +168 -0
  257. package/src/messaging/inbound/reaction-handler.d.ts +62 -0
  258. package/src/messaging/inbound/reaction-handler.js +259 -0
  259. package/src/messaging/inbound/sentinel-store.d.ts +37 -0
  260. package/src/messaging/inbound/sentinel-store.js +98 -0
  261. package/src/messaging/inbound/synthetic-message.d.ts +26 -0
  262. package/src/messaging/inbound/synthetic-message.js +59 -0
  263. package/src/messaging/inbound/user-name-cache-store.d.ts +62 -0
  264. package/src/messaging/inbound/user-name-cache-store.js +236 -0
  265. package/src/messaging/inbound/user-name-cache.d.ts +78 -0
  266. package/src/messaging/inbound/user-name-cache.js +306 -0
  267. package/src/messaging/inbound/vc-meeting-invited-handler.d.ts +20 -0
  268. package/src/messaging/inbound/vc-meeting-invited-handler.js +236 -0
  269. package/src/messaging/inbound/vc-sender.d.ts +41 -0
  270. package/src/messaging/inbound/vc-sender.js +53 -0
  271. package/src/messaging/outbound/actions.d.ts +16 -0
  272. package/src/messaging/outbound/actions.js +329 -0
  273. package/src/messaging/outbound/bot-peer-context.d.ts +42 -0
  274. package/src/messaging/outbound/bot-peer-context.js +40 -0
  275. package/src/messaging/outbound/chat-manage.d.ts +64 -0
  276. package/src/messaging/outbound/chat-manage.js +117 -0
  277. package/src/messaging/outbound/deliver.d.ts +186 -0
  278. package/src/messaging/outbound/deliver.js +410 -0
  279. package/src/messaging/outbound/fetch.d.ts +12 -0
  280. package/src/messaging/outbound/fetch.js +17 -0
  281. package/src/messaging/outbound/forward.d.ts +26 -0
  282. package/src/messaging/outbound/forward.js +51 -0
  283. package/src/messaging/outbound/media-url-utils.d.ts +29 -0
  284. package/src/messaging/outbound/media-url-utils.js +172 -0
  285. package/src/messaging/outbound/media.d.ts +260 -0
  286. package/src/messaging/outbound/media.js +865 -0
  287. package/src/messaging/outbound/normalize-mentions.d.ts +50 -0
  288. package/src/messaging/outbound/normalize-mentions.js +166 -0
  289. package/src/messaging/outbound/outbound-mention.d.ts +41 -0
  290. package/src/messaging/outbound/outbound-mention.js +112 -0
  291. package/src/messaging/outbound/outbound.d.ts +79 -0
  292. package/src/messaging/outbound/outbound.js +195 -0
  293. package/src/messaging/outbound/reactions.d.ts +124 -0
  294. package/src/messaging/outbound/reactions.js +384 -0
  295. package/src/messaging/outbound/send.d.ts +153 -0
  296. package/src/messaging/outbound/send.js +417 -0
  297. package/src/messaging/outbound/typing.d.ts +60 -0
  298. package/src/messaging/outbound/typing.js +139 -0
  299. package/src/messaging/shared/message-lookup.d.ts +54 -0
  300. package/src/messaging/shared/message-lookup.js +120 -0
  301. package/src/messaging/types.d.ts +316 -0
  302. package/src/messaging/types.js +11 -0
  303. package/src/tools/ask-user-question.d.ts +32 -0
  304. package/src/tools/ask-user-question.js +922 -0
  305. package/src/tools/auto-auth.d.ts +57 -0
  306. package/src/tools/auto-auth.js +904 -0
  307. package/src/tools/helpers.d.ts +264 -0
  308. package/src/tools/helpers.js +389 -0
  309. package/src/tools/mcp/doc/create.d.ts +12 -0
  310. package/src/tools/mcp/doc/create.js +47 -0
  311. package/src/tools/mcp/doc/fetch.d.ts +12 -0
  312. package/src/tools/mcp/doc/fetch.js +39 -0
  313. package/src/tools/mcp/doc/index.d.ts +12 -0
  314. package/src/tools/mcp/doc/index.js +50 -0
  315. package/src/tools/mcp/doc/update.d.ts +12 -0
  316. package/src/tools/mcp/doc/update.js +64 -0
  317. package/src/tools/mcp/shared.d.ts +59 -0
  318. package/src/tools/mcp/shared.js +239 -0
  319. package/src/tools/oapi/bitable/app-table-field.d.ts +16 -0
  320. package/src/tools/oapi/bitable/app-table-field.js +225 -0
  321. package/src/tools/oapi/bitable/app-table-record.d.ts +20 -0
  322. package/src/tools/oapi/bitable/app-table-record.js +439 -0
  323. package/src/tools/oapi/bitable/app-table-view.d.ts +16 -0
  324. package/src/tools/oapi/bitable/app-table-view.js +172 -0
  325. package/src/tools/oapi/bitable/app-table.d.ts +17 -0
  326. package/src/tools/oapi/bitable/app-table.js +195 -0
  327. package/src/tools/oapi/bitable/app.d.ts +18 -0
  328. package/src/tools/oapi/bitable/app.js +189 -0
  329. package/src/tools/oapi/bitable/index.d.ts +9 -0
  330. package/src/tools/oapi/bitable/index.js +17 -0
  331. package/src/tools/oapi/calendar/calendar.d.ts +15 -0
  332. package/src/tools/oapi/calendar/calendar.js +125 -0
  333. package/src/tools/oapi/calendar/event-attendee.d.ts +14 -0
  334. package/src/tools/oapi/calendar/event-attendee.js +161 -0
  335. package/src/tools/oapi/calendar/event.d.ts +16 -0
  336. package/src/tools/oapi/calendar/event.js +712 -0
  337. package/src/tools/oapi/calendar/freebusy.d.ts +13 -0
  338. package/src/tools/oapi/calendar/freebusy.js +114 -0
  339. package/src/tools/oapi/calendar/index.d.ts +8 -0
  340. package/src/tools/oapi/calendar/index.js +15 -0
  341. package/src/tools/oapi/chat/chat.d.ts +16 -0
  342. package/src/tools/oapi/chat/chat.js +127 -0
  343. package/src/tools/oapi/chat/index.d.ts +10 -0
  344. package/src/tools/oapi/chat/index.js +23 -0
  345. package/src/tools/oapi/chat/members.d.ts +11 -0
  346. package/src/tools/oapi/chat/members.js +84 -0
  347. package/src/tools/oapi/common/get-user.d.ts +12 -0
  348. package/src/tools/oapi/common/get-user.js +109 -0
  349. package/src/tools/oapi/common/index.d.ts +6 -0
  350. package/src/tools/oapi/common/index.js +11 -0
  351. package/src/tools/oapi/common/search-user.d.ts +11 -0
  352. package/src/tools/oapi/common/search-user.js +76 -0
  353. package/src/tools/oapi/drive/doc-comments.d.ts +15 -0
  354. package/src/tools/oapi/drive/doc-comments.js +351 -0
  355. package/src/tools/oapi/drive/doc-media.d.ts +19 -0
  356. package/src/tools/oapi/drive/doc-media.js +371 -0
  357. package/src/tools/oapi/drive/file.d.ts +19 -0
  358. package/src/tools/oapi/drive/file.js +519 -0
  359. package/src/tools/oapi/drive/index.d.ts +12 -0
  360. package/src/tools/oapi/drive/index.js +45 -0
  361. package/src/tools/oapi/helpers.d.ts +183 -0
  362. package/src/tools/oapi/helpers.js +385 -0
  363. package/src/tools/oapi/im/format-messages.d.ts +50 -0
  364. package/src/tools/oapi/im/format-messages.js +169 -0
  365. package/src/tools/oapi/im/index.d.ts +10 -0
  366. package/src/tools/oapi/im/index.js +25 -0
  367. package/src/tools/oapi/im/message-read.d.ts +13 -0
  368. package/src/tools/oapi/im/message-read.js +419 -0
  369. package/src/tools/oapi/im/message.d.ts +16 -0
  370. package/src/tools/oapi/im/message.js +152 -0
  371. package/src/tools/oapi/im/resource.d.ts +13 -0
  372. package/src/tools/oapi/im/resource.js +186 -0
  373. package/src/tools/oapi/im/time-utils.d.ts +46 -0
  374. package/src/tools/oapi/im/time-utils.js +212 -0
  375. package/src/tools/oapi/im/user-name-uat.d.ts +26 -0
  376. package/src/tools/oapi/im/user-name-uat.js +143 -0
  377. package/src/tools/oapi/index.d.ts +11 -0
  378. package/src/tools/oapi/index.js +64 -0
  379. package/src/tools/oapi/sdk-types.d.ts +96 -0
  380. package/src/tools/oapi/sdk-types.js +13 -0
  381. package/src/tools/oapi/search/doc-search.d.ts +13 -0
  382. package/src/tools/oapi/search/doc-search.js +194 -0
  383. package/src/tools/oapi/search/index.d.ts +12 -0
  384. package/src/tools/oapi/search/index.js +37 -0
  385. package/src/tools/oapi/sheets/index.d.ts +12 -0
  386. package/src/tools/oapi/sheets/index.js +35 -0
  387. package/src/tools/oapi/sheets/sheet.d.ts +16 -0
  388. package/src/tools/oapi/sheets/sheet.js +688 -0
  389. package/src/tools/oapi/task/attachment.d.ts +18 -0
  390. package/src/tools/oapi/task/attachment.js +107 -0
  391. package/src/tools/oapi/task/comment.d.ts +15 -0
  392. package/src/tools/oapi/task/comment.js +149 -0
  393. package/src/tools/oapi/task/index.d.ts +11 -0
  394. package/src/tools/oapi/task/index.js +21 -0
  395. package/src/tools/oapi/task/section.d.ts +17 -0
  396. package/src/tools/oapi/task/section.js +293 -0
  397. package/src/tools/oapi/task/subtask.d.ts +14 -0
  398. package/src/tools/oapi/task/subtask.js +171 -0
  399. package/src/tools/oapi/task/task.d.ts +19 -0
  400. package/src/tools/oapi/task/task.js +512 -0
  401. package/src/tools/oapi/task/task_agent.d.ts +14 -0
  402. package/src/tools/oapi/task/task_agent.js +108 -0
  403. package/src/tools/oapi/task/tasklist.d.ts +19 -0
  404. package/src/tools/oapi/task/tasklist.js +276 -0
  405. package/src/tools/oapi/wiki/index.d.ts +12 -0
  406. package/src/tools/oapi/wiki/index.js +42 -0
  407. package/src/tools/oapi/wiki/space-node.d.ts +17 -0
  408. package/src/tools/oapi/wiki/space-node.js +233 -0
  409. package/src/tools/oapi/wiki/space.d.ts +15 -0
  410. package/src/tools/oapi/wiki/space.js +133 -0
  411. package/src/tools/oauth-batch-auth.d.ts +11 -0
  412. package/src/tools/oauth-batch-auth.js +150 -0
  413. package/src/tools/oauth-cards.d.ts +39 -0
  414. package/src/tools/oauth-cards.js +324 -0
  415. package/src/tools/oauth.d.ts +47 -0
  416. package/src/tools/oauth.js +592 -0
  417. package/src/tools/onboarding-auth.d.ts +27 -0
  418. package/src/tools/onboarding-auth.js +133 -0
  419. package/src/tools/tat/im/index.d.ts +15 -0
  420. package/src/tools/tat/im/index.js +22 -0
  421. package/src/tools/tat/im/resource.d.ts +15 -0
  422. package/src/tools/tat/im/resource.js +192 -0
  423. package/tsdown.config.d.ts +2 -0
  424. package/tsdown.config.js +25 -0
  425. package/vitest.config.d.ts +2 -0
  426. package/vitest.config.js +12 -0
@@ -0,0 +1,848 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * Diagnostic module for the Lark/Feishu plugin.
7
+ *
8
+ * Collects environment info, account configuration, API connectivity,
9
+ * app permissions, tool registration state, and recent error logs into
10
+ * a structured report that users can share with developers for
11
+ * remote troubleshooting.
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ Object.defineProperty(exports, "__esModule", { value: true });
47
+ exports.runDiagnosis = runDiagnosis;
48
+ exports.formatDiagReportText = formatDiagReportText;
49
+ exports.traceByMessageId = traceByMessageId;
50
+ exports.formatTraceOutput = formatTraceOutput;
51
+ exports.analyzeTrace = analyzeTrace;
52
+ exports.formatDiagReportCli = formatDiagReportCli;
53
+ const fs = __importStar(require("node:fs/promises"));
54
+ const path = __importStar(require("node:path"));
55
+ const os = __importStar(require("node:os"));
56
+ const probe_1 = require("../channel/probe.js");
57
+ const accounts_1 = require("../core/accounts.js");
58
+ const lark_client_1 = require("../core/lark-client.js");
59
+ /**
60
+ * Resolve the global config for cross-account operations.
61
+ * See doctor.ts for rationale.
62
+ */
63
+ function resolveGlobalConfig(config) {
64
+ return lark_client_1.LarkClient.globalConfig ?? config;
65
+ }
66
+ const api_error_1 = require("../core/api-error.js");
67
+ const tools_config_1 = require("../core/tools-config.js");
68
+ // ---------------------------------------------------------------------------
69
+ // Constants
70
+ // ---------------------------------------------------------------------------
71
+ const PLUGIN_VERSION = '2026.2.10';
72
+ const LOG_READ_BYTES = 256 * 1024; // read last 256KB of log
73
+ const MAX_ERROR_LINES = 20;
74
+ /** Matches a timestamped log line: 2026-02-13T09:23:35.038Z [level]: ... */
75
+ const TIMESTAMPED_LINE_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;
76
+ const ERROR_LEVEL_RE = /\[error\]|\[warn\]/i;
77
+ // ---------------------------------------------------------------------------
78
+ // Helpers
79
+ // ---------------------------------------------------------------------------
80
+ function maskSecret(secret) {
81
+ if (!secret)
82
+ return '(未设置)';
83
+ if (secret.length <= 4)
84
+ return '****';
85
+ return secret.slice(0, 4) + '****';
86
+ }
87
+ async function extractRecentErrors(logPath) {
88
+ try {
89
+ await fs.access(logPath);
90
+ }
91
+ catch {
92
+ return [];
93
+ }
94
+ try {
95
+ const stat = await fs.stat(logPath);
96
+ const readSize = Math.min(stat.size, LOG_READ_BYTES);
97
+ const fd = await fs.open(logPath, 'r');
98
+ try {
99
+ const buffer = Buffer.alloc(readSize);
100
+ await fd.read(buffer, 0, readSize, Math.max(0, stat.size - readSize));
101
+ const content = buffer.toString('utf-8');
102
+ const lines = content.split('\n').filter(Boolean);
103
+ // Only pick timestamped log entries at error/warn level,
104
+ // ignoring stack trace fragments and other noise.
105
+ const errorLines = lines.filter((line) => TIMESTAMPED_LINE_RE.test(line) && ERROR_LEVEL_RE.test(line));
106
+ return errorLines.slice(-MAX_ERROR_LINES);
107
+ }
108
+ finally {
109
+ await fd.close();
110
+ }
111
+ }
112
+ catch {
113
+ return [];
114
+ }
115
+ }
116
+ async function checkAppScopes(client) {
117
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
118
+ const res = await client.application.scope.list({});
119
+ (0, api_error_1.assertLarkOk)(res);
120
+ const scopes = res.data?.scopes ?? [];
121
+ const granted = scopes.filter((s) => s.grant_status === 1);
122
+ const pending = scopes.filter((s) => s.grant_status !== 1);
123
+ return {
124
+ granted: granted.length,
125
+ pending: pending.length,
126
+ summary: `${granted.length} 已授权, ${pending.length} 待授权`,
127
+ };
128
+ }
129
+ function detectRegisteredTools(config) {
130
+ const accounts = (0, accounts_1.getEnabledLarkAccounts)(config);
131
+ if (accounts.length === 0)
132
+ return [];
133
+ const toolsCfg = (0, tools_config_1.resolveAnyEnabledToolsConfig)(accounts);
134
+ const tools = [];
135
+ if (toolsCfg.doc)
136
+ tools.push('feishu_doc');
137
+ if (toolsCfg.scopes)
138
+ tools.push('feishu_app_scopes');
139
+ if (toolsCfg.wiki)
140
+ tools.push('feishu_wiki');
141
+ if (toolsCfg.drive)
142
+ tools.push('feishu_drive');
143
+ if (toolsCfg.perm)
144
+ tools.push('feishu_perm');
145
+ tools.push('feishu_bitable_get_meta', 'feishu_bitable_list_fields', 'feishu_bitable_list_records', 'feishu_bitable_get_record', 'feishu_bitable_create_record', 'feishu_bitable_update_record');
146
+ tools.push('feishu_task');
147
+ tools.push('feishu_calendar');
148
+ return tools;
149
+ }
150
+ async function diagnoseAccount(account) {
151
+ const checks = [];
152
+ const result = {
153
+ accountId: account.accountId,
154
+ name: account.name,
155
+ enabled: account.enabled,
156
+ configured: account.configured,
157
+ appId: account.appId ?? '(未设置)',
158
+ brand: account.brand,
159
+ checks,
160
+ };
161
+ // A1: Credentials
162
+ checks.push({
163
+ name: '凭证完整性',
164
+ status: account.configured ? 'pass' : 'fail',
165
+ message: account.configured
166
+ ? `appId: ${account.appId}, appSecret: ${maskSecret(account.appSecret)}`
167
+ : '缺少 appId 或 appSecret',
168
+ });
169
+ // A2: Enabled
170
+ checks.push({
171
+ name: '账户启用',
172
+ status: account.enabled ? 'pass' : 'warn',
173
+ message: account.enabled ? '已启用' : '已禁用',
174
+ });
175
+ if (!account.configured || !account.appId || !account.appSecret) {
176
+ checks.push({
177
+ name: 'API 连通性',
178
+ status: 'skip',
179
+ message: '凭证未配置,跳过',
180
+ });
181
+ return result;
182
+ }
183
+ // A3: API connectivity via probe
184
+ try {
185
+ const probeResult = await (0, probe_1.probeFeishu)({
186
+ accountId: account.accountId,
187
+ appId: account.appId,
188
+ appSecret: account.appSecret,
189
+ brand: account.brand,
190
+ });
191
+ checks.push({
192
+ name: 'API 连通性',
193
+ status: probeResult.ok ? 'pass' : 'fail',
194
+ message: probeResult.ok ? `连接成功` : `连接失败: ${probeResult.error}`,
195
+ });
196
+ // A4: Bot info
197
+ if (probeResult.ok) {
198
+ checks.push({
199
+ name: 'Bot 信息',
200
+ status: probeResult.botName ? 'pass' : 'warn',
201
+ message: probeResult.botName ? `${probeResult.botName} (${probeResult.botOpenId})` : '未获取到 Bot 名称',
202
+ });
203
+ }
204
+ }
205
+ catch (err) {
206
+ checks.push({
207
+ name: 'API 连通性',
208
+ status: 'fail',
209
+ message: `探测异常: ${err instanceof Error ? err.message : String(err)}`,
210
+ });
211
+ }
212
+ // A5: App scopes
213
+ try {
214
+ const client = lark_client_1.LarkClient.fromAccount(account).sdk;
215
+ const scopesResult = await checkAppScopes(client);
216
+ checks.push({
217
+ name: '应用权限',
218
+ status: scopesResult.pending > 0 ? 'warn' : 'pass',
219
+ message: scopesResult.summary,
220
+ details: scopesResult.pending > 0 ? '存在未授权的权限,可能影响部分功能' : undefined,
221
+ });
222
+ }
223
+ catch (err) {
224
+ checks.push({
225
+ name: '应用权限',
226
+ status: 'warn',
227
+ message: `权限检查失败: ${(0, api_error_1.formatLarkError)(err)}`,
228
+ });
229
+ }
230
+ // A6: Brand
231
+ checks.push({
232
+ name: '品牌配置',
233
+ status: 'pass',
234
+ message: `brand: ${account.brand}`,
235
+ });
236
+ return result;
237
+ }
238
+ // ---------------------------------------------------------------------------
239
+ // Core
240
+ // ---------------------------------------------------------------------------
241
+ async function runDiagnosis(params) {
242
+ const { config } = params;
243
+ // Use the global config to enumerate all accounts — the passed-in
244
+ // config may be account-scoped (accounts map stripped).
245
+ const globalCfg = resolveGlobalConfig(config);
246
+ const globalChecks = [];
247
+ // -- Environment --
248
+ const nodeVer = parseInt(process.version.slice(1), 10);
249
+ globalChecks.push({
250
+ name: 'Node.js 版本',
251
+ status: nodeVer >= 18 ? 'pass' : 'warn',
252
+ message: process.version,
253
+ details: nodeVer < 18 ? '建议升级到 Node.js 18+' : undefined,
254
+ });
255
+ // -- Account count --
256
+ const accountIds = (0, accounts_1.getLarkAccountIds)(globalCfg);
257
+ globalChecks.push({
258
+ name: '飞书账户数量',
259
+ status: accountIds.length > 0 ? 'pass' : 'fail',
260
+ message: `${accountIds.length} 个账户`,
261
+ });
262
+ // -- Log file --
263
+ const logPath = path.join(os.homedir(), '.openclaw', 'logs', 'gateway.log');
264
+ let logExists = false;
265
+ try {
266
+ await fs.access(logPath);
267
+ logExists = true;
268
+ }
269
+ catch {
270
+ // noop
271
+ }
272
+ globalChecks.push({
273
+ name: '日志文件',
274
+ status: logExists ? 'pass' : 'warn',
275
+ message: logExists ? logPath : `未找到: ${logPath}`,
276
+ });
277
+ // -- Per-account diagnosis (sequential to avoid rate limits) --
278
+ const accountResults = [];
279
+ for (const id of accountIds) {
280
+ const account = (0, accounts_1.getLarkAccount)(globalCfg, id);
281
+ const result = await diagnoseAccount(account);
282
+ accountResults.push(result);
283
+ }
284
+ // -- Tools --
285
+ const tools = detectRegisteredTools(globalCfg);
286
+ // -- Recent errors --
287
+ const recentErrors = await extractRecentErrors(logPath);
288
+ globalChecks.push({
289
+ name: '最近错误日志',
290
+ status: recentErrors.length > 0 ? 'warn' : 'pass',
291
+ message: recentErrors.length > 0 ? `发现 ${recentErrors.length} 条错误` : '无最近错误',
292
+ });
293
+ // -- Overall status --
294
+ const allChecks = [...globalChecks, ...accountResults.flatMap((a) => a.checks)];
295
+ const hasFail = allChecks.some((c) => c.status === 'fail');
296
+ const hasWarn = allChecks.some((c) => c.status === 'warn');
297
+ return {
298
+ timestamp: new Date().toISOString(),
299
+ environment: {
300
+ nodeVersion: process.version,
301
+ platform: process.platform,
302
+ arch: process.arch,
303
+ pluginVersion: PLUGIN_VERSION,
304
+ },
305
+ accounts: accountResults,
306
+ toolsRegistered: tools,
307
+ recentErrors,
308
+ overallStatus: hasFail ? 'unhealthy' : hasWarn ? 'degraded' : 'healthy',
309
+ checks: globalChecks,
310
+ };
311
+ }
312
+ // ---------------------------------------------------------------------------
313
+ // Formatting — plain text (chat command)
314
+ // ---------------------------------------------------------------------------
315
+ const STATUS_LABEL = {
316
+ pass: '[PASS]',
317
+ warn: '[WARN]',
318
+ fail: '[FAIL]',
319
+ skip: '[SKIP]',
320
+ };
321
+ function formatCheck(c) {
322
+ let line = ` ${STATUS_LABEL[c.status]} ${c.name}: ${c.message}`;
323
+ if (c.details) {
324
+ line += `\n ${c.details}`;
325
+ }
326
+ return line;
327
+ }
328
+ function formatDiagReportText(report) {
329
+ const lines = [];
330
+ const sep = '====================================';
331
+ lines.push(sep);
332
+ lines.push(' 飞书插件诊断报告');
333
+ lines.push(` ${report.timestamp}`);
334
+ lines.push(sep);
335
+ lines.push('');
336
+ // Environment
337
+ lines.push('【环境信息】');
338
+ lines.push(` Node.js: ${report.environment.nodeVersion}`);
339
+ lines.push(` 插件版本: ${report.environment.pluginVersion}`);
340
+ lines.push(` 系统: ${report.environment.platform} ${report.environment.arch}`);
341
+ lines.push('');
342
+ // Global checks
343
+ lines.push('【全局检查】');
344
+ for (const c of report.checks) {
345
+ lines.push(formatCheck(c));
346
+ }
347
+ lines.push('');
348
+ // Per-account
349
+ for (const acct of report.accounts) {
350
+ lines.push(`【账户: ${acct.accountId}】`);
351
+ if (acct.name)
352
+ lines.push(` 名称: ${acct.name}`);
353
+ lines.push(` App ID: ${acct.appId}`);
354
+ lines.push(` 品牌: ${acct.brand}`);
355
+ lines.push('');
356
+ for (const c of acct.checks) {
357
+ lines.push(formatCheck(c));
358
+ }
359
+ lines.push('');
360
+ }
361
+ // Tools
362
+ lines.push('【工具注册】');
363
+ if (report.toolsRegistered.length > 0) {
364
+ lines.push(` ${report.toolsRegistered.join(', ')}`);
365
+ lines.push(` 共 ${report.toolsRegistered.length} 个`);
366
+ }
367
+ else {
368
+ lines.push(' 无工具注册(未找到已配置的账户)');
369
+ }
370
+ lines.push('');
371
+ // Recent errors
372
+ if (report.recentErrors.length > 0) {
373
+ lines.push(`【最近错误】(${report.recentErrors.length} 条)`);
374
+ for (let i = 0; i < report.recentErrors.length; i++) {
375
+ lines.push(` ${i + 1}. ${report.recentErrors[i]}`);
376
+ }
377
+ lines.push('');
378
+ }
379
+ // Overall
380
+ const statusMap = {
381
+ healthy: 'HEALTHY',
382
+ degraded: 'DEGRADED (存在警告)',
383
+ unhealthy: 'UNHEALTHY (存在失败项)',
384
+ };
385
+ lines.push(sep);
386
+ lines.push(` 总体状态: ${statusMap[report.overallStatus]}`);
387
+ lines.push(sep);
388
+ return lines.join('\n');
389
+ }
390
+ // ---------------------------------------------------------------------------
391
+ // Formatting — ANSI colored (CLI)
392
+ // ---------------------------------------------------------------------------
393
+ const ANSI = {
394
+ reset: '\x1b[0m',
395
+ bold: '\x1b[1m',
396
+ green: '\x1b[32m',
397
+ yellow: '\x1b[33m',
398
+ red: '\x1b[31m',
399
+ gray: '\x1b[90m',
400
+ };
401
+ const STATUS_LABEL_CLI = {
402
+ pass: `${ANSI.green}[PASS]${ANSI.reset}`,
403
+ warn: `${ANSI.yellow}[WARN]${ANSI.reset}`,
404
+ fail: `${ANSI.red}[FAIL]${ANSI.reset}`,
405
+ skip: `${ANSI.gray}[SKIP]${ANSI.reset}`,
406
+ };
407
+ function formatCheckCli(c) {
408
+ let line = ` ${STATUS_LABEL_CLI[c.status]} ${c.name}: ${c.message}`;
409
+ if (c.details) {
410
+ line += `\n ${ANSI.gray}${c.details}${ANSI.reset}`;
411
+ }
412
+ return line;
413
+ }
414
+ // ---------------------------------------------------------------------------
415
+ // Trace by message_id
416
+ // ---------------------------------------------------------------------------
417
+ /**
418
+ * Extract all log lines tagged with a specific message_id from gateway.log.
419
+ *
420
+ * Scans the last 1MB of the log file for lines containing `[msg:{messageId}]`.
421
+ * Returns matching lines in chronological order.
422
+ */
423
+ async function traceByMessageId(messageId) {
424
+ const logPath = path.join(os.homedir(), '.openclaw', 'logs', 'gateway.log');
425
+ try {
426
+ await fs.access(logPath);
427
+ }
428
+ catch {
429
+ return [];
430
+ }
431
+ const TRACE_READ_BYTES = 1024 * 1024; // 1MB — more than extractRecentErrors
432
+ try {
433
+ const stat = await fs.stat(logPath);
434
+ const readSize = Math.min(stat.size, TRACE_READ_BYTES);
435
+ const fd = await fs.open(logPath, 'r');
436
+ try {
437
+ const buffer = Buffer.alloc(readSize);
438
+ await fd.read(buffer, 0, readSize, Math.max(0, stat.size - readSize));
439
+ const content = buffer.toString('utf-8');
440
+ const needle = `[msg:${messageId}]`;
441
+ return content.split('\n').filter((line) => line.includes(needle));
442
+ }
443
+ finally {
444
+ await fd.close();
445
+ }
446
+ }
447
+ catch {
448
+ return [];
449
+ }
450
+ }
451
+ /**
452
+ * Format trace output for CLI display.
453
+ */
454
+ function formatTraceOutput(lines, messageId) {
455
+ const sep = '────────────────────────────────';
456
+ if (lines.length === 0) {
457
+ return [
458
+ sep,
459
+ ` 未找到 ${messageId} 的追踪日志`,
460
+ '',
461
+ ' 可能原因:',
462
+ ' 1. 该消息尚未被处理',
463
+ ' 2. 日志已被轮转',
464
+ ' 3. 追踪功能未启用(需要更新插件版本)',
465
+ sep,
466
+ ].join('\n');
467
+ }
468
+ const header = `追踪 ${messageId} 的处理链路 (${lines.length} 条日志):`;
469
+ const output = [header, sep];
470
+ for (const line of lines) {
471
+ output.push(line);
472
+ }
473
+ output.push(sep);
474
+ return output.join('\n');
475
+ }
476
+ function classifyEvent(body) {
477
+ if (body.startsWith('received from'))
478
+ return 'received';
479
+ if (body.startsWith('sender resolved'))
480
+ return 'sender_resolved';
481
+ if (body.startsWith('rejected:'))
482
+ return 'rejected';
483
+ if (body.startsWith('dispatching to agent'))
484
+ return 'dispatching';
485
+ if (body.startsWith('dispatch complete'))
486
+ return 'dispatch_complete';
487
+ if (body.startsWith('card entity created'))
488
+ return 'card_created';
489
+ if (body.startsWith('card message sent'))
490
+ return 'card_sent';
491
+ if (body.startsWith('cardkit cardElement.content:'))
492
+ return 'card_stream';
493
+ if (body.startsWith('card stream update failed'))
494
+ return 'card_stream_fail';
495
+ if (body.startsWith('cardkit card.settings:'))
496
+ return 'card_settings';
497
+ if (body.startsWith('cardkit card.update:'))
498
+ return 'card_update';
499
+ if (body.startsWith('card creation failed'))
500
+ return 'card_fallback';
501
+ if (body.startsWith('reply completed'))
502
+ return 'reply_completed';
503
+ if (body.startsWith('reply error'))
504
+ return 'reply_error';
505
+ if (body.startsWith('tool call:'))
506
+ return 'tool_call';
507
+ if (body.startsWith('tool done:'))
508
+ return 'tool_done';
509
+ if (body.startsWith('tool fail:'))
510
+ return 'tool_fail';
511
+ return 'other';
512
+ }
513
+ const EVENT_LABEL = {
514
+ received: '消息接收',
515
+ sender_resolved: 'Sender 解析',
516
+ rejected: '消息拒绝',
517
+ dispatching: '分发到 Agent',
518
+ dispatch_complete: 'Agent 处理完成',
519
+ card_created: '卡片创建',
520
+ card_sent: '卡片消息发送',
521
+ card_stream: '流式更新',
522
+ card_stream_fail: '流式更新失败',
523
+ card_settings: '卡片设置',
524
+ card_update: '卡片最终更新',
525
+ card_fallback: '卡片降级',
526
+ reply_completed: '回复完成',
527
+ reply_error: '回复错误',
528
+ tool_call: '工具调用',
529
+ tool_done: '工具完成',
530
+ tool_fail: '工具失败',
531
+ };
532
+ /** Expected stages in a normal message processing flow. */
533
+ const EXPECTED_STAGES = [
534
+ { kind: 'received', label: '消息接收 (received from)' },
535
+ { kind: 'dispatching', label: '分发到 Agent (dispatching to agent)' },
536
+ { kind: 'card_created', label: '卡片创建 (card entity created)' },
537
+ { kind: 'card_sent', label: '卡片消息发送 (card message sent)' },
538
+ { kind: 'card_stream', label: '流式输出 (cardElement.content)' },
539
+ { kind: 'dispatch_complete', label: '处理完成 (dispatch complete)' },
540
+ { kind: 'reply_completed', label: '回复收尾 (reply completed)' },
541
+ ];
542
+ /** Time gap thresholds (ms) for performance warnings. */
543
+ const PERF_THRESHOLDS = [
544
+ { from: 'received', to: 'dispatching', warnMs: 500, label: '消息接收 → 分发' },
545
+ { from: 'dispatching', to: 'card_created', warnMs: 5000, label: '分发 → 卡片创建' },
546
+ { from: 'card_created', to: 'card_stream', warnMs: 30000, label: '卡片创建 → 首次流式输出' },
547
+ ];
548
+ function parseTraceLines(lines) {
549
+ const events = [];
550
+ // Match: 2026-02-13T12:42:04.682Z [feishu] feishu[...][msg:...]: <body>
551
+ const re = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z)\s.*?\]:\s(.+)$/;
552
+ for (const line of lines) {
553
+ const m = line.match(re);
554
+ if (m) {
555
+ events.push({ timestamp: new Date(m[1]), raw: line, body: m[2] });
556
+ }
557
+ }
558
+ return events;
559
+ }
560
+ /**
561
+ * Analyze trace log lines and produce a structured CLI report.
562
+ */
563
+ function analyzeTrace(lines, _messageId) {
564
+ const events = parseTraceLines(lines);
565
+ if (events.length === 0) {
566
+ return `无法解析日志行,请确认日志格式正确。`;
567
+ }
568
+ const out = [];
569
+ const sep = '────────────────────────────────';
570
+ const startTime = events[0].timestamp.getTime();
571
+ const totalMs = events[events.length - 1].timestamp.getTime() - startTime;
572
+ // ── Section 1: Timeline ──
573
+ out.push('');
574
+ out.push(`${ANSI.bold}【时间线】${ANSI.reset} (${events.length} 条日志,跨度 ${(totalMs / 1000).toFixed(1)}s)`);
575
+ out.push(sep);
576
+ let prevMs = startTime;
577
+ // Collapse consecutive card_stream events
578
+ let streamCount = 0;
579
+ let streamFirstSeq = '';
580
+ let streamLastSeq = '';
581
+ function flushStream() {
582
+ if (streamCount > 0) {
583
+ const label = streamCount === 1
584
+ ? ` ${ANSI.gray}...${ANSI.reset} 流式更新 seq=${streamFirstSeq}`
585
+ : ` ${ANSI.gray}...${ANSI.reset} 流式更新 x${streamCount} (seq=${streamFirstSeq}~${streamLastSeq})`;
586
+ out.push(label);
587
+ streamCount = 0;
588
+ }
589
+ }
590
+ for (const ev of events) {
591
+ const kind = classifyEvent(ev.body);
592
+ const deltaMs = ev.timestamp.getTime() - prevMs;
593
+ prevMs = ev.timestamp.getTime();
594
+ const offsetMs = ev.timestamp.getTime() - startTime;
595
+ const offsetStr = `+${offsetMs}ms`.padStart(10);
596
+ // Collapse card_stream
597
+ if (kind === 'card_stream') {
598
+ const seqMatch = ev.body.match(/seq=(\d+)/);
599
+ const seq = seqMatch ? seqMatch[1] : '?';
600
+ if (streamCount === 0)
601
+ streamFirstSeq = seq;
602
+ streamLastSeq = seq;
603
+ streamCount++;
604
+ continue;
605
+ }
606
+ flushStream();
607
+ const label = EVENT_LABEL[kind] ?? kind;
608
+ const gapWarn = deltaMs > 5000 ? ` ${ANSI.yellow}⚠ ${(deltaMs / 1000).toFixed(1)}s${ANSI.reset}` : '';
609
+ // Marker for errors
610
+ let marker = ' ';
611
+ if (kind === 'rejected' ||
612
+ kind === 'reply_error' ||
613
+ kind === 'tool_fail' ||
614
+ kind === 'card_stream_fail' ||
615
+ kind === 'card_fallback') {
616
+ marker = `${ANSI.red}✘ ${ANSI.reset}`;
617
+ }
618
+ else if (kind === 'tool_call') {
619
+ marker = '→ ';
620
+ }
621
+ // Extract key detail from body
622
+ let detail = '';
623
+ if (kind === 'received') {
624
+ const m = ev.body.match(/from (\S+) in (\S+) \((\w+)\)/);
625
+ if (m)
626
+ detail = `sender=${m[1]}, chat=${m[2]} (${m[3]})`;
627
+ }
628
+ else if (kind === 'dispatching') {
629
+ const m = ev.body.match(/session=(\S+)\)/);
630
+ if (m)
631
+ detail = `session=${m[1]}`;
632
+ }
633
+ else if (kind === 'dispatch_complete') {
634
+ const m = ev.body.match(/replies=(\d+), elapsed=(\d+)ms/);
635
+ if (m)
636
+ detail = `replies=${m[1]}, elapsed=${m[2]}ms`;
637
+ }
638
+ else if (kind === 'tool_call') {
639
+ const m = ev.body.match(/tool call: (\S+)/);
640
+ if (m)
641
+ detail = m[1];
642
+ }
643
+ else if (kind === 'tool_fail') {
644
+ detail = ev.body.replace('tool fail: ', '');
645
+ }
646
+ else if (kind === 'card_created') {
647
+ const m = ev.body.match(/card_id=(\S+)\)/);
648
+ if (m)
649
+ detail = `card_id=${m[1]}`;
650
+ }
651
+ else if (kind === 'reply_completed') {
652
+ const m = ev.body.match(/elapsed=(\d+)ms/);
653
+ if (m)
654
+ detail = `elapsed=${m[1]}ms`;
655
+ }
656
+ else if (kind === 'rejected') {
657
+ detail = ev.body.replace('rejected: ', '');
658
+ }
659
+ out.push(`${ANSI.gray}[${offsetStr}]${ANSI.reset} ${marker}${label}${detail ? ` — ${detail}` : ''}${gapWarn}`);
660
+ }
661
+ flushStream();
662
+ out.push('');
663
+ // ── Section 2: Anomaly detection ──
664
+ const issues = [];
665
+ const kindSet = new Set(events.map((e) => classifyEvent(e.body)));
666
+ // 2.1 Missing stages
667
+ for (const stage of EXPECTED_STAGES) {
668
+ if (!kindSet.has(stage.kind)) {
669
+ // dispatch_complete 和 reply_completed 缺失仅在有 dispatching 时才告警
670
+ if ((stage.kind === 'dispatch_complete' || stage.kind === 'reply_completed') && !kindSet.has('dispatching'))
671
+ continue;
672
+ // card 相关阶段在有 rejected 时不告警
673
+ if ((stage.kind === 'card_created' || stage.kind === 'card_sent' || stage.kind === 'card_stream') &&
674
+ kindSet.has('rejected'))
675
+ continue;
676
+ issues.push(`缺失阶段: ${stage.label}`);
677
+ }
678
+ }
679
+ // 2.2 Errors
680
+ for (const ev of events) {
681
+ const kind = classifyEvent(ev.body);
682
+ if (kind === 'rejected')
683
+ issues.push(`消息被拒绝: ${ev.body.replace('rejected: ', '')}`);
684
+ if (kind === 'reply_error')
685
+ issues.push(`回复错误: ${ev.body}`);
686
+ if (kind === 'tool_fail')
687
+ issues.push(`工具失败: ${ev.body}`);
688
+ if (kind === 'card_stream_fail')
689
+ issues.push(`流式更新失败: ${ev.body}`);
690
+ if (kind === 'card_fallback')
691
+ issues.push(`卡片降级: ${ev.body}`);
692
+ // CardKit non-zero code
693
+ if (kind === 'card_stream' || kind === 'card_update' || kind === 'card_settings' || kind === 'card_created') {
694
+ const codeMatch = ev.body.match(/code=(\d+)/);
695
+ if (codeMatch && codeMatch[1] !== '0') {
696
+ issues.push(`API 返回错误码: code=${codeMatch[1]} — ${ev.body}`);
697
+ }
698
+ }
699
+ }
700
+ // 2.3 Performance thresholds
701
+ const firstByKind = new Map();
702
+ for (const ev of events) {
703
+ const kind = classifyEvent(ev.body);
704
+ if (!firstByKind.has(kind))
705
+ firstByKind.set(kind, ev);
706
+ }
707
+ for (const rule of PERF_THRESHOLDS) {
708
+ const from = firstByKind.get(rule.from);
709
+ const to = firstByKind.get(rule.to);
710
+ if (from && to) {
711
+ const gap = to.timestamp.getTime() - from.timestamp.getTime();
712
+ if (gap > rule.warnMs) {
713
+ issues.push(`性能警告: ${rule.label} 耗时 ${(gap / 1000).toFixed(1)}s(阈值 ${(rule.warnMs / 1000).toFixed(0)}s)`);
714
+ }
715
+ }
716
+ }
717
+ // 2.4 Duplicate delivery
718
+ const receivedCount = events.filter((e) => classifyEvent(e.body) === 'received').length;
719
+ if (receivedCount > 1) {
720
+ issues.push(`重复投递: 同一消息被接收 ${receivedCount} 次(WebSocket 重投递)`);
721
+ }
722
+ // 2.5 Card stream continuity
723
+ const streamSeqs = [];
724
+ for (const ev of events) {
725
+ if (classifyEvent(ev.body) === 'card_stream') {
726
+ const m = ev.body.match(/seq=(\d+)/);
727
+ if (m)
728
+ streamSeqs.push(parseInt(m[1], 10));
729
+ }
730
+ }
731
+ if (streamSeqs.length > 1) {
732
+ for (let i = 1; i < streamSeqs.length; i++) {
733
+ if (streamSeqs[i] !== streamSeqs[i - 1] + 1) {
734
+ issues.push(`流式 seq 不连续: seq=${streamSeqs[i - 1]} → seq=${streamSeqs[i]}(跳过了 ${streamSeqs[i] - streamSeqs[i - 1] - 1} 个)`);
735
+ break;
736
+ }
737
+ }
738
+ }
739
+ out.push(`${ANSI.bold}【异常检测】${ANSI.reset}`);
740
+ out.push(sep);
741
+ if (issues.length === 0) {
742
+ out.push(` ${ANSI.green}未发现异常${ANSI.reset}`);
743
+ }
744
+ else {
745
+ for (let i = 0; i < issues.length; i++) {
746
+ const isError = issues[i].startsWith('工具失败') ||
747
+ issues[i].startsWith('回复错误') ||
748
+ issues[i].startsWith('API 返回错误码') ||
749
+ issues[i].startsWith('流式更新失败');
750
+ const color = isError ? ANSI.red : ANSI.yellow;
751
+ out.push(` ${color}${i + 1}. ${issues[i]}${ANSI.reset}`);
752
+ }
753
+ }
754
+ out.push('');
755
+ // ── Section 3: Diagnosis ──
756
+ out.push(`${ANSI.bold}【诊断总结】${ANSI.reset}`);
757
+ out.push(sep);
758
+ const hasError = issues.some((i) => i.startsWith('工具失败') ||
759
+ i.startsWith('回复错误') ||
760
+ i.startsWith('API 返回错误码') ||
761
+ i.startsWith('流式更新失败') ||
762
+ i.startsWith('缺失阶段'));
763
+ const hasWarn = issues.length > 0;
764
+ if (!hasWarn) {
765
+ out.push(` 状态: ${ANSI.green}✓ 正常${ANSI.reset}`);
766
+ out.push(` 消息处理链路完整,全程耗时 ${(totalMs / 1000).toFixed(1)}s。`);
767
+ // Break down time
768
+ const dispatchComplete = events.find((e) => classifyEvent(e.body) === 'dispatch_complete' && e.body.includes('replies=') && !e.body.includes('replies=0'));
769
+ if (dispatchComplete) {
770
+ const m = dispatchComplete.body.match(/elapsed=(\d+)ms/);
771
+ if (m) {
772
+ out.push(` 其中 Agent 处理耗时 ${(parseInt(m[1], 10) / 1000).toFixed(1)}s(含 AI 推理 + 工具调用)。`);
773
+ }
774
+ }
775
+ }
776
+ else if (hasError) {
777
+ out.push(` 状态: ${ANSI.red}✘ 异常${ANSI.reset}`);
778
+ out.push(` 发现 ${issues.length} 个问题,需要排查。`);
779
+ }
780
+ else {
781
+ out.push(` 状态: ${ANSI.yellow}⚠ 有警告${ANSI.reset}`);
782
+ out.push(` 发现 ${issues.length} 个警告,功能可用但需关注。`);
783
+ }
784
+ out.push('');
785
+ return out.join('\n');
786
+ }
787
+ function formatDiagReportCli(report) {
788
+ const lines = [];
789
+ const sep = '====================================';
790
+ lines.push(sep);
791
+ lines.push(` ${ANSI.bold}飞书插件诊断报告${ANSI.reset}`);
792
+ lines.push(` ${report.timestamp}`);
793
+ lines.push(sep);
794
+ lines.push('');
795
+ // Environment
796
+ lines.push(`${ANSI.bold}【环境信息】${ANSI.reset}`);
797
+ lines.push(` Node.js: ${report.environment.nodeVersion}`);
798
+ lines.push(` 插件版本: ${report.environment.pluginVersion}`);
799
+ lines.push(` 系统: ${report.environment.platform} ${report.environment.arch}`);
800
+ lines.push('');
801
+ // Global checks
802
+ lines.push(`${ANSI.bold}【全局检查】${ANSI.reset}`);
803
+ for (const c of report.checks) {
804
+ lines.push(formatCheckCli(c));
805
+ }
806
+ lines.push('');
807
+ // Per-account
808
+ for (const acct of report.accounts) {
809
+ lines.push(`${ANSI.bold}【账户: ${acct.accountId}】${ANSI.reset}`);
810
+ if (acct.name)
811
+ lines.push(` 名称: ${acct.name}`);
812
+ lines.push(` App ID: ${acct.appId}`);
813
+ lines.push(` 品牌: ${acct.brand}`);
814
+ lines.push('');
815
+ for (const c of acct.checks) {
816
+ lines.push(formatCheckCli(c));
817
+ }
818
+ lines.push('');
819
+ }
820
+ // Tools
821
+ lines.push(`${ANSI.bold}【工具注册】${ANSI.reset}`);
822
+ if (report.toolsRegistered.length > 0) {
823
+ lines.push(` ${report.toolsRegistered.join(', ')}`);
824
+ lines.push(` 共 ${report.toolsRegistered.length} 个`);
825
+ }
826
+ else {
827
+ lines.push(' 无工具注册(未找到已配置的账户)');
828
+ }
829
+ lines.push('');
830
+ // Recent errors
831
+ if (report.recentErrors.length > 0) {
832
+ lines.push(`${ANSI.bold}【最近错误】${ANSI.reset}(${report.recentErrors.length} 条)`);
833
+ for (let i = 0; i < report.recentErrors.length; i++) {
834
+ lines.push(` ${ANSI.gray}${i + 1}. ${report.recentErrors[i]}${ANSI.reset}`);
835
+ }
836
+ lines.push('');
837
+ }
838
+ // Overall
839
+ const statusColorMap = {
840
+ healthy: `${ANSI.green}HEALTHY${ANSI.reset}`,
841
+ degraded: `${ANSI.yellow}DEGRADED (存在警告)${ANSI.reset}`,
842
+ unhealthy: `${ANSI.red}UNHEALTHY (存在失败项)${ANSI.reset}`,
843
+ };
844
+ lines.push(sep);
845
+ lines.push(` 总体状态: ${statusColorMap[report.overallStatus]}`);
846
+ lines.push(sep);
847
+ return lines.join('\n');
848
+ }