@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.
- package/LICENSE +21 -0
- package/README.md +76 -0
- package/bin/openclaw-lark.js +39 -0
- package/index.d.ts +36 -0
- package/index.js +188 -0
- package/openclaw.plugin.json +64 -0
- package/package.json +63 -0
- package/secret-contract-api.d.ts +15 -0
- package/secret-contract-api.js +78 -0
- package/skills/feishu-bitable/SKILL.md +248 -0
- package/skills/feishu-bitable/references/examples.md +813 -0
- package/skills/feishu-bitable/references/field-properties.md +763 -0
- package/skills/feishu-bitable/references/record-values.md +911 -0
- package/skills/feishu-calendar/SKILL.md +242 -0
- package/skills/feishu-channel-rules/SKILL.md +18 -0
- package/skills/feishu-channel-rules/references/markdown-syntax.md +138 -0
- package/skills/feishu-create-doc/SKILL.md +719 -0
- package/skills/feishu-fetch-doc/SKILL.md +93 -0
- package/skills/feishu-im-read/SKILL.md +163 -0
- package/skills/feishu-task/SKILL.md +340 -0
- package/skills/feishu-troubleshoot/SKILL.md +70 -0
- package/skills/feishu-update-doc/SKILL.md +285 -0
- package/src/card/builder.d.ts +152 -0
- package/src/card/builder.js +794 -0
- package/src/card/card-error.d.ts +91 -0
- package/src/card/card-error.js +206 -0
- package/src/card/cardkit.d.ts +90 -0
- package/src/card/cardkit.js +203 -0
- package/src/card/flush-controller.d.ts +45 -0
- package/src/card/flush-controller.js +138 -0
- package/src/card/image-resolver.d.ts +45 -0
- package/src/card/image-resolver.js +116 -0
- package/src/card/markdown-style.d.ts +16 -0
- package/src/card/markdown-style.js +106 -0
- package/src/card/reasoning-utils.d.ts +14 -0
- package/src/card/reasoning-utils.js +64 -0
- package/src/card/reply-dispatcher-types.d.ts +132 -0
- package/src/card/reply-dispatcher-types.js +61 -0
- package/src/card/reply-dispatcher.d.ts +15 -0
- package/src/card/reply-dispatcher.js +447 -0
- package/src/card/reply-mode.d.ts +41 -0
- package/src/card/reply-mode.js +70 -0
- package/src/card/streaming-card-controller.d.ts +118 -0
- package/src/card/streaming-card-controller.js +1045 -0
- package/src/card/tool-use-config.d.ts +26 -0
- package/src/card/tool-use-config.js +76 -0
- package/src/card/tool-use-display.d.ts +37 -0
- package/src/card/tool-use-display.js +476 -0
- package/src/card/tool-use-trace-store.d.ts +51 -0
- package/src/card/tool-use-trace-store.js +271 -0
- package/src/card/unavailable-guard.d.ts +35 -0
- package/src/card/unavailable-guard.js +87 -0
- package/src/channel/abort-detect.d.ts +47 -0
- package/src/channel/abort-detect.js +219 -0
- package/src/channel/chat-queue.d.ts +41 -0
- package/src/channel/chat-queue.js +68 -0
- package/src/channel/config-adapter.d.ts +23 -0
- package/src/channel/config-adapter.js +107 -0
- package/src/channel/directory.d.ts +57 -0
- package/src/channel/directory.js +197 -0
- package/src/channel/event-handlers.d.ts +17 -0
- package/src/channel/event-handlers.js +380 -0
- package/src/channel/interactive-dispatch.d.ts +59 -0
- package/src/channel/interactive-dispatch.js +195 -0
- package/src/channel/monitor.d.ts +17 -0
- package/src/channel/monitor.js +140 -0
- package/src/channel/onboarding-config.d.ts +18 -0
- package/src/channel/onboarding-config.js +96 -0
- package/src/channel/onboarding-migrate.d.ts +25 -0
- package/src/channel/onboarding-migrate.js +70 -0
- package/src/channel/onboarding.d.ts +12 -0
- package/src/channel/onboarding.js +300 -0
- package/src/channel/plugin.d.ts +13 -0
- package/src/channel/plugin.js +310 -0
- package/src/channel/probe.d.ts +14 -0
- package/src/channel/probe.js +24 -0
- package/src/channel/types.d.ts +37 -0
- package/src/channel/types.js +8 -0
- package/src/commands/auth.d.ts +21 -0
- package/src/commands/auth.js +165 -0
- package/src/commands/diagnose.d.ts +69 -0
- package/src/commands/diagnose.js +848 -0
- package/src/commands/doctor.d.ts +27 -0
- package/src/commands/doctor.js +588 -0
- package/src/commands/index.d.ts +25 -0
- package/src/commands/index.js +219 -0
- package/src/commands/locale.d.ts +7 -0
- package/src/commands/locale.js +8 -0
- package/src/core/accounts.d.ts +51 -0
- package/src/core/accounts.js +219 -0
- package/src/core/agent-config.d.ts +100 -0
- package/src/core/agent-config.js +148 -0
- package/src/core/api-error.d.ts +48 -0
- package/src/core/api-error.js +117 -0
- package/src/core/app-owner-fallback.d.ts +22 -0
- package/src/core/app-owner-fallback.js +39 -0
- package/src/core/app-scope-checker.d.ts +87 -0
- package/src/core/app-scope-checker.js +198 -0
- package/src/core/auth-errors.d.ts +144 -0
- package/src/core/auth-errors.js +160 -0
- package/src/core/card-action-operator.d.ts +33 -0
- package/src/core/card-action-operator.js +30 -0
- package/src/core/chat-info-cache.d.ts +67 -0
- package/src/core/chat-info-cache.js +165 -0
- package/src/core/comment-target.d.ts +65 -0
- package/src/core/comment-target.js +100 -0
- package/src/core/config-schema.d.ts +490 -0
- package/src/core/config-schema.js +223 -0
- package/src/core/device-flow.d.ts +77 -0
- package/src/core/device-flow.js +217 -0
- package/src/core/domains.d.ts +18 -0
- package/src/core/domains.js +34 -0
- package/src/core/feishu-fetch.d.ts +18 -0
- package/src/core/feishu-fetch.js +28 -0
- package/src/core/footer-config.d.ts +24 -0
- package/src/core/footer-config.js +51 -0
- package/src/core/lark-client.d.ts +125 -0
- package/src/core/lark-client.js +468 -0
- package/src/core/lark-logger.d.ts +23 -0
- package/src/core/lark-logger.js +160 -0
- package/src/core/lark-ticket.d.ts +29 -0
- package/src/core/lark-ticket.js +40 -0
- package/src/core/message-unavailable.d.ts +53 -0
- package/src/core/message-unavailable.js +142 -0
- package/src/core/owner-policy.d.ts +32 -0
- package/src/core/owner-policy.js +55 -0
- package/src/core/permission-url.d.ts +22 -0
- package/src/core/permission-url.js +76 -0
- package/src/core/raw-request.d.ts +27 -0
- package/src/core/raw-request.js +90 -0
- package/src/core/runtime-store.d.ts +13 -0
- package/src/core/runtime-store.js +29 -0
- package/src/core/scope-manager.d.ts +168 -0
- package/src/core/scope-manager.js +224 -0
- package/src/core/sdk-compat.d.ts +20 -0
- package/src/core/sdk-compat.js +28 -0
- package/src/core/security-check.d.ts +72 -0
- package/src/core/security-check.js +184 -0
- package/src/core/shutdown-hooks.d.ts +22 -0
- package/src/core/shutdown-hooks.js +61 -0
- package/src/core/synthetic-target.d.ts +33 -0
- package/src/core/synthetic-target.js +40 -0
- package/src/core/targets.d.ts +60 -0
- package/src/core/targets.js +173 -0
- package/src/core/token-store.d.ts +54 -0
- package/src/core/token-store.js +326 -0
- package/src/core/tool-client.d.ts +176 -0
- package/src/core/tool-client.js +426 -0
- package/src/core/tool-scopes.d.ts +156 -0
- package/src/core/tool-scopes.js +344 -0
- package/src/core/tools-config.d.ts +55 -0
- package/src/core/tools-config.js +143 -0
- package/src/core/types.d.ts +91 -0
- package/src/core/types.js +12 -0
- package/src/core/uat-client.d.ts +46 -0
- package/src/core/uat-client.js +192 -0
- package/src/core/version.d.ts +31 -0
- package/src/core/version.js +69 -0
- package/src/messaging/converters/audio.d.ts +8 -0
- package/src/messaging/converters/audio.js +24 -0
- package/src/messaging/converters/calendar.d.ts +13 -0
- package/src/messaging/converters/calendar.js +56 -0
- package/src/messaging/converters/content-converter-helpers.d.ts +30 -0
- package/src/messaging/converters/content-converter-helpers.js +82 -0
- package/src/messaging/converters/content-converter.d.ts +24 -0
- package/src/messaging/converters/content-converter.js +40 -0
- package/src/messaging/converters/file.d.ts +8 -0
- package/src/messaging/converters/file.js +24 -0
- package/src/messaging/converters/folder.d.ts +8 -0
- package/src/messaging/converters/folder.js +24 -0
- package/src/messaging/converters/hongbao.d.ts +8 -0
- package/src/messaging/converters/hongbao.js +20 -0
- package/src/messaging/converters/image.d.ts +8 -0
- package/src/messaging/converters/image.js +22 -0
- package/src/messaging/converters/index.d.ts +8 -0
- package/src/messaging/converters/index.js +53 -0
- package/src/messaging/converters/interactive/card-converter.d.ts +76 -0
- package/src/messaging/converters/interactive/card-converter.js +1177 -0
- package/src/messaging/converters/interactive/card-utils.d.ts +9 -0
- package/src/messaging/converters/interactive/card-utils.js +47 -0
- package/src/messaging/converters/interactive/index.d.ts +8 -0
- package/src/messaging/converters/interactive/index.js +25 -0
- package/src/messaging/converters/interactive/legacy.d.ts +11 -0
- package/src/messaging/converters/interactive/legacy.js +60 -0
- package/src/messaging/converters/interactive/types.d.ts +23 -0
- package/src/messaging/converters/interactive/types.js +27 -0
- package/src/messaging/converters/location.d.ts +8 -0
- package/src/messaging/converters/location.js +23 -0
- package/src/messaging/converters/merge-forward.d.ts +32 -0
- package/src/messaging/converters/merge-forward.js +235 -0
- package/src/messaging/converters/post.d.ts +11 -0
- package/src/messaging/converters/post.js +235 -0
- package/src/messaging/converters/share.d.ts +9 -0
- package/src/messaging/converters/share.js +28 -0
- package/src/messaging/converters/sticker.d.ts +8 -0
- package/src/messaging/converters/sticker.js +22 -0
- package/src/messaging/converters/system.d.ts +12 -0
- package/src/messaging/converters/system.js +36 -0
- package/src/messaging/converters/text.d.ts +8 -0
- package/src/messaging/converters/text.js +18 -0
- package/src/messaging/converters/todo.d.ts +8 -0
- package/src/messaging/converters/todo.js +45 -0
- package/src/messaging/converters/types.d.ts +114 -0
- package/src/messaging/converters/types.js +8 -0
- package/src/messaging/converters/unknown.d.ts +8 -0
- package/src/messaging/converters/unknown.js +20 -0
- package/src/messaging/converters/utils.d.ts +22 -0
- package/src/messaging/converters/utils.js +57 -0
- package/src/messaging/converters/video-chat.d.ts +8 -0
- package/src/messaging/converters/video-chat.js +31 -0
- package/src/messaging/converters/video.d.ts +8 -0
- package/src/messaging/converters/video.js +35 -0
- package/src/messaging/converters/vote.d.ts +8 -0
- package/src/messaging/converters/vote.js +28 -0
- package/src/messaging/inbound/bot-content.d.ts +84 -0
- package/src/messaging/inbound/bot-content.js +117 -0
- package/src/messaging/inbound/bot-loop-guard.d.ts +48 -0
- package/src/messaging/inbound/bot-loop-guard.js +89 -0
- package/src/messaging/inbound/comment-context.d.ts +82 -0
- package/src/messaging/inbound/comment-context.js +353 -0
- package/src/messaging/inbound/comment-handler.d.ts +30 -0
- package/src/messaging/inbound/comment-handler.js +269 -0
- package/src/messaging/inbound/dedup.d.ts +59 -0
- package/src/messaging/inbound/dedup.js +121 -0
- package/src/messaging/inbound/dispatch-builders.d.ts +104 -0
- package/src/messaging/inbound/dispatch-builders.js +241 -0
- package/src/messaging/inbound/dispatch-commands.d.ts +22 -0
- package/src/messaging/inbound/dispatch-commands.js +131 -0
- package/src/messaging/inbound/dispatch-context.d.ts +67 -0
- package/src/messaging/inbound/dispatch-context.js +153 -0
- package/src/messaging/inbound/dispatch.d.ts +50 -0
- package/src/messaging/inbound/dispatch.js +477 -0
- package/src/messaging/inbound/enrich.d.ts +102 -0
- package/src/messaging/inbound/enrich.js +236 -0
- package/src/messaging/inbound/gate-effects.d.ts +23 -0
- package/src/messaging/inbound/gate-effects.js +46 -0
- package/src/messaging/inbound/gate.d.ts +91 -0
- package/src/messaging/inbound/gate.js +342 -0
- package/src/messaging/inbound/handler-registry.d.ts +25 -0
- package/src/messaging/inbound/handler-registry.js +23 -0
- package/src/messaging/inbound/handler.d.ts +37 -0
- package/src/messaging/inbound/handler.js +286 -0
- package/src/messaging/inbound/media-resolver.d.ts +32 -0
- package/src/messaging/inbound/media-resolver.js +91 -0
- package/src/messaging/inbound/mention-registry.d.ts +59 -0
- package/src/messaging/inbound/mention-registry.js +115 -0
- package/src/messaging/inbound/mention.d.ts +48 -0
- package/src/messaging/inbound/mention.js +102 -0
- package/src/messaging/inbound/parse-io.d.ts +50 -0
- package/src/messaging/inbound/parse-io.js +86 -0
- package/src/messaging/inbound/parse.d.ts +28 -0
- package/src/messaging/inbound/parse.js +128 -0
- package/src/messaging/inbound/permission.d.ts +17 -0
- package/src/messaging/inbound/permission.js +44 -0
- package/src/messaging/inbound/policy.d.ts +95 -0
- package/src/messaging/inbound/policy.js +168 -0
- package/src/messaging/inbound/reaction-handler.d.ts +62 -0
- package/src/messaging/inbound/reaction-handler.js +259 -0
- package/src/messaging/inbound/sentinel-store.d.ts +37 -0
- package/src/messaging/inbound/sentinel-store.js +98 -0
- package/src/messaging/inbound/synthetic-message.d.ts +26 -0
- package/src/messaging/inbound/synthetic-message.js +59 -0
- package/src/messaging/inbound/user-name-cache-store.d.ts +62 -0
- package/src/messaging/inbound/user-name-cache-store.js +236 -0
- package/src/messaging/inbound/user-name-cache.d.ts +78 -0
- package/src/messaging/inbound/user-name-cache.js +306 -0
- package/src/messaging/inbound/vc-meeting-invited-handler.d.ts +20 -0
- package/src/messaging/inbound/vc-meeting-invited-handler.js +236 -0
- package/src/messaging/inbound/vc-sender.d.ts +41 -0
- package/src/messaging/inbound/vc-sender.js +53 -0
- package/src/messaging/outbound/actions.d.ts +16 -0
- package/src/messaging/outbound/actions.js +329 -0
- package/src/messaging/outbound/bot-peer-context.d.ts +42 -0
- package/src/messaging/outbound/bot-peer-context.js +40 -0
- package/src/messaging/outbound/chat-manage.d.ts +64 -0
- package/src/messaging/outbound/chat-manage.js +117 -0
- package/src/messaging/outbound/deliver.d.ts +186 -0
- package/src/messaging/outbound/deliver.js +410 -0
- package/src/messaging/outbound/fetch.d.ts +12 -0
- package/src/messaging/outbound/fetch.js +17 -0
- package/src/messaging/outbound/forward.d.ts +26 -0
- package/src/messaging/outbound/forward.js +51 -0
- package/src/messaging/outbound/media-url-utils.d.ts +29 -0
- package/src/messaging/outbound/media-url-utils.js +172 -0
- package/src/messaging/outbound/media.d.ts +260 -0
- package/src/messaging/outbound/media.js +865 -0
- package/src/messaging/outbound/normalize-mentions.d.ts +50 -0
- package/src/messaging/outbound/normalize-mentions.js +166 -0
- package/src/messaging/outbound/outbound-mention.d.ts +41 -0
- package/src/messaging/outbound/outbound-mention.js +112 -0
- package/src/messaging/outbound/outbound.d.ts +79 -0
- package/src/messaging/outbound/outbound.js +195 -0
- package/src/messaging/outbound/reactions.d.ts +124 -0
- package/src/messaging/outbound/reactions.js +384 -0
- package/src/messaging/outbound/send.d.ts +153 -0
- package/src/messaging/outbound/send.js +417 -0
- package/src/messaging/outbound/typing.d.ts +60 -0
- package/src/messaging/outbound/typing.js +139 -0
- package/src/messaging/shared/message-lookup.d.ts +54 -0
- package/src/messaging/shared/message-lookup.js +120 -0
- package/src/messaging/types.d.ts +316 -0
- package/src/messaging/types.js +11 -0
- package/src/tools/ask-user-question.d.ts +32 -0
- package/src/tools/ask-user-question.js +922 -0
- package/src/tools/auto-auth.d.ts +57 -0
- package/src/tools/auto-auth.js +904 -0
- package/src/tools/helpers.d.ts +264 -0
- package/src/tools/helpers.js +389 -0
- package/src/tools/mcp/doc/create.d.ts +12 -0
- package/src/tools/mcp/doc/create.js +47 -0
- package/src/tools/mcp/doc/fetch.d.ts +12 -0
- package/src/tools/mcp/doc/fetch.js +39 -0
- package/src/tools/mcp/doc/index.d.ts +12 -0
- package/src/tools/mcp/doc/index.js +50 -0
- package/src/tools/mcp/doc/update.d.ts +12 -0
- package/src/tools/mcp/doc/update.js +64 -0
- package/src/tools/mcp/shared.d.ts +59 -0
- package/src/tools/mcp/shared.js +239 -0
- package/src/tools/oapi/bitable/app-table-field.d.ts +16 -0
- package/src/tools/oapi/bitable/app-table-field.js +225 -0
- package/src/tools/oapi/bitable/app-table-record.d.ts +20 -0
- package/src/tools/oapi/bitable/app-table-record.js +439 -0
- package/src/tools/oapi/bitable/app-table-view.d.ts +16 -0
- package/src/tools/oapi/bitable/app-table-view.js +172 -0
- package/src/tools/oapi/bitable/app-table.d.ts +17 -0
- package/src/tools/oapi/bitable/app-table.js +195 -0
- package/src/tools/oapi/bitable/app.d.ts +18 -0
- package/src/tools/oapi/bitable/app.js +189 -0
- package/src/tools/oapi/bitable/index.d.ts +9 -0
- package/src/tools/oapi/bitable/index.js +17 -0
- package/src/tools/oapi/calendar/calendar.d.ts +15 -0
- package/src/tools/oapi/calendar/calendar.js +125 -0
- package/src/tools/oapi/calendar/event-attendee.d.ts +14 -0
- package/src/tools/oapi/calendar/event-attendee.js +161 -0
- package/src/tools/oapi/calendar/event.d.ts +16 -0
- package/src/tools/oapi/calendar/event.js +712 -0
- package/src/tools/oapi/calendar/freebusy.d.ts +13 -0
- package/src/tools/oapi/calendar/freebusy.js +114 -0
- package/src/tools/oapi/calendar/index.d.ts +8 -0
- package/src/tools/oapi/calendar/index.js +15 -0
- package/src/tools/oapi/chat/chat.d.ts +16 -0
- package/src/tools/oapi/chat/chat.js +127 -0
- package/src/tools/oapi/chat/index.d.ts +10 -0
- package/src/tools/oapi/chat/index.js +23 -0
- package/src/tools/oapi/chat/members.d.ts +11 -0
- package/src/tools/oapi/chat/members.js +84 -0
- package/src/tools/oapi/common/get-user.d.ts +12 -0
- package/src/tools/oapi/common/get-user.js +109 -0
- package/src/tools/oapi/common/index.d.ts +6 -0
- package/src/tools/oapi/common/index.js +11 -0
- package/src/tools/oapi/common/search-user.d.ts +11 -0
- package/src/tools/oapi/common/search-user.js +76 -0
- package/src/tools/oapi/drive/doc-comments.d.ts +15 -0
- package/src/tools/oapi/drive/doc-comments.js +351 -0
- package/src/tools/oapi/drive/doc-media.d.ts +19 -0
- package/src/tools/oapi/drive/doc-media.js +371 -0
- package/src/tools/oapi/drive/file.d.ts +19 -0
- package/src/tools/oapi/drive/file.js +519 -0
- package/src/tools/oapi/drive/index.d.ts +12 -0
- package/src/tools/oapi/drive/index.js +45 -0
- package/src/tools/oapi/helpers.d.ts +183 -0
- package/src/tools/oapi/helpers.js +385 -0
- package/src/tools/oapi/im/format-messages.d.ts +50 -0
- package/src/tools/oapi/im/format-messages.js +169 -0
- package/src/tools/oapi/im/index.d.ts +10 -0
- package/src/tools/oapi/im/index.js +25 -0
- package/src/tools/oapi/im/message-read.d.ts +13 -0
- package/src/tools/oapi/im/message-read.js +419 -0
- package/src/tools/oapi/im/message.d.ts +16 -0
- package/src/tools/oapi/im/message.js +152 -0
- package/src/tools/oapi/im/resource.d.ts +13 -0
- package/src/tools/oapi/im/resource.js +186 -0
- package/src/tools/oapi/im/time-utils.d.ts +46 -0
- package/src/tools/oapi/im/time-utils.js +212 -0
- package/src/tools/oapi/im/user-name-uat.d.ts +26 -0
- package/src/tools/oapi/im/user-name-uat.js +143 -0
- package/src/tools/oapi/index.d.ts +11 -0
- package/src/tools/oapi/index.js +64 -0
- package/src/tools/oapi/sdk-types.d.ts +96 -0
- package/src/tools/oapi/sdk-types.js +13 -0
- package/src/tools/oapi/search/doc-search.d.ts +13 -0
- package/src/tools/oapi/search/doc-search.js +194 -0
- package/src/tools/oapi/search/index.d.ts +12 -0
- package/src/tools/oapi/search/index.js +37 -0
- package/src/tools/oapi/sheets/index.d.ts +12 -0
- package/src/tools/oapi/sheets/index.js +35 -0
- package/src/tools/oapi/sheets/sheet.d.ts +16 -0
- package/src/tools/oapi/sheets/sheet.js +688 -0
- package/src/tools/oapi/task/attachment.d.ts +18 -0
- package/src/tools/oapi/task/attachment.js +107 -0
- package/src/tools/oapi/task/comment.d.ts +15 -0
- package/src/tools/oapi/task/comment.js +149 -0
- package/src/tools/oapi/task/index.d.ts +11 -0
- package/src/tools/oapi/task/index.js +21 -0
- package/src/tools/oapi/task/section.d.ts +17 -0
- package/src/tools/oapi/task/section.js +293 -0
- package/src/tools/oapi/task/subtask.d.ts +14 -0
- package/src/tools/oapi/task/subtask.js +171 -0
- package/src/tools/oapi/task/task.d.ts +19 -0
- package/src/tools/oapi/task/task.js +512 -0
- package/src/tools/oapi/task/task_agent.d.ts +14 -0
- package/src/tools/oapi/task/task_agent.js +108 -0
- package/src/tools/oapi/task/tasklist.d.ts +19 -0
- package/src/tools/oapi/task/tasklist.js +276 -0
- package/src/tools/oapi/wiki/index.d.ts +12 -0
- package/src/tools/oapi/wiki/index.js +42 -0
- package/src/tools/oapi/wiki/space-node.d.ts +17 -0
- package/src/tools/oapi/wiki/space-node.js +233 -0
- package/src/tools/oapi/wiki/space.d.ts +15 -0
- package/src/tools/oapi/wiki/space.js +133 -0
- package/src/tools/oauth-batch-auth.d.ts +11 -0
- package/src/tools/oauth-batch-auth.js +150 -0
- package/src/tools/oauth-cards.d.ts +39 -0
- package/src/tools/oauth-cards.js +324 -0
- package/src/tools/oauth.d.ts +47 -0
- package/src/tools/oauth.js +592 -0
- package/src/tools/onboarding-auth.d.ts +27 -0
- package/src/tools/onboarding-auth.js +133 -0
- package/src/tools/tat/im/index.d.ts +15 -0
- package/src/tools/tat/im/index.js +22 -0
- package/src/tools/tat/im/resource.d.ts +15 -0
- package/src/tools/tat/im/resource.js +192 -0
- package/tsdown.config.d.ts +2 -0
- package/tsdown.config.js +25 -0
- package/vitest.config.d.ts +2 -0
- package/vitest.config.js +12 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* Event handlers for the Feishu WebSocket monitor.
|
|
7
|
+
*
|
|
8
|
+
* Extracted from monitor.ts to improve testability and reduce
|
|
9
|
+
* function size. Each handler receives a MonitorContext with all
|
|
10
|
+
* dependencies needed to process the event.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.handleMessageEvent = handleMessageEvent;
|
|
14
|
+
exports.handleReactionEvent = handleReactionEvent;
|
|
15
|
+
exports.handleBotMembershipEvent = handleBotMembershipEvent;
|
|
16
|
+
exports.handleVcMeetingInvitedEvent = handleVcMeetingInvitedEvent;
|
|
17
|
+
exports.handleCommentEvent = handleCommentEvent;
|
|
18
|
+
exports.handleCardActionEvent = handleCardActionEvent;
|
|
19
|
+
const handler_1 = require("../messaging/inbound/handler.js");
|
|
20
|
+
const reaction_handler_1 = require("../messaging/inbound/reaction-handler.js");
|
|
21
|
+
const comment_handler_1 = require("../messaging/inbound/comment-handler.js");
|
|
22
|
+
const vc_meeting_invited_handler_1 = require("../messaging/inbound/vc-meeting-invited-handler.js");
|
|
23
|
+
const vc_sender_1 = require("../messaging/inbound/vc-sender.js");
|
|
24
|
+
const comment_context_1 = require("../messaging/inbound/comment-context.js");
|
|
25
|
+
const dedup_1 = require("../messaging/inbound/dedup.js");
|
|
26
|
+
const lark_ticket_1 = require("../core/lark-ticket.js");
|
|
27
|
+
const lark_logger_1 = require("../core/lark-logger.js");
|
|
28
|
+
const auto_auth_1 = require("../tools/auto-auth.js");
|
|
29
|
+
const ask_user_question_1 = require("../tools/ask-user-question.js");
|
|
30
|
+
const chat_queue_1 = require("./chat-queue.js");
|
|
31
|
+
const abort_detect_1 = require("./abort-detect.js");
|
|
32
|
+
const interactive_dispatch_1 = require("./interactive-dispatch.js");
|
|
33
|
+
const elog = (0, lark_logger_1.larkLogger)('channel/event-handlers');
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Event ownership validation
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
/**
|
|
38
|
+
* Verify that the event's app_id matches the current account.
|
|
39
|
+
*
|
|
40
|
+
* Lark SDK EventDispatcher flattens the v2 envelope header (which
|
|
41
|
+
* contains `app_id`) into the handler `data` object, so `app_id` is
|
|
42
|
+
* available directly on `data`.
|
|
43
|
+
*
|
|
44
|
+
* Returns `false` (discard event) when the app_id does not match.
|
|
45
|
+
*/
|
|
46
|
+
function isEventOwnershipValid(ctx, data) {
|
|
47
|
+
const expectedAppId = ctx.lark.account.appId;
|
|
48
|
+
if (!expectedAppId)
|
|
49
|
+
return true; // appId not configured — skip check
|
|
50
|
+
const eventAppId = data.app_id;
|
|
51
|
+
if (eventAppId == null)
|
|
52
|
+
return true; // SDK did not provide app_id — defensive skip
|
|
53
|
+
if (eventAppId !== expectedAppId) {
|
|
54
|
+
elog.warn('event app_id mismatch, discarding', {
|
|
55
|
+
accountId: ctx.accountId,
|
|
56
|
+
expected: expectedAppId,
|
|
57
|
+
received: String(eventAppId),
|
|
58
|
+
});
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Message handler
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
async function handleMessageEvent(ctx, data) {
|
|
67
|
+
if (!isEventOwnershipValid(ctx, data))
|
|
68
|
+
return;
|
|
69
|
+
const { accountId, log, error } = ctx;
|
|
70
|
+
try {
|
|
71
|
+
const event = data;
|
|
72
|
+
// Self-echo hard filter — drop messages authored by this very bot before
|
|
73
|
+
// dedup and enqueue. Prevents self-reply loops; the primary guardrail
|
|
74
|
+
// against bot-to-bot ping-pong.
|
|
75
|
+
//
|
|
76
|
+
// NOTE: if botOpenId is not yet populated (startup race before probe
|
|
77
|
+
// resolves), this filter is skipped. The downstream bot-sender gate
|
|
78
|
+
// (checkBotSenderGate) acts as fallback — bot messages default to
|
|
79
|
+
// `allowBots='mentions'`, so in groups they require an explicit @-mention
|
|
80
|
+
// of this bot to pass; DMs are pass-through under the default.
|
|
81
|
+
const senderOpenId = event.sender?.sender_id?.open_id;
|
|
82
|
+
const botOpenId = ctx.lark.botOpenId;
|
|
83
|
+
if (botOpenId && senderOpenId && senderOpenId === botOpenId) {
|
|
84
|
+
log(`feishu[${accountId}]: drop self-echo message ${event.message?.message_id ?? 'unknown'}`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const msgId = event.message?.message_id ?? 'unknown';
|
|
88
|
+
const chatId = event.message?.chat_id ?? '';
|
|
89
|
+
// In topic groups, reply events carry root_id but not thread_id.
|
|
90
|
+
// Use root_id as fallback so different topics get separate queue keys
|
|
91
|
+
// and can be processed in parallel.
|
|
92
|
+
const threadId = event.message?.thread_id || event.message?.root_id || undefined;
|
|
93
|
+
// Dedup — skip duplicate messages (e.g. from WebSocket reconnects).
|
|
94
|
+
if (!ctx.messageDedup.tryRecord(msgId, accountId)) {
|
|
95
|
+
log(`feishu[${accountId}]: duplicate message ${msgId}, skipping`);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
// Expiry — discard stale messages from reconnect replay.
|
|
99
|
+
if ((0, dedup_1.isMessageExpired)(event.message?.create_time)) {
|
|
100
|
+
log(`feishu[${accountId}]: message ${msgId} expired, discarding`);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// ---- Abort fast-path ----
|
|
104
|
+
// If the message looks like an abort trigger and there is an active
|
|
105
|
+
// reply dispatcher for this chat, fire abortCard() immediately
|
|
106
|
+
// (before the message enters the serial queue) so the streaming
|
|
107
|
+
// card is terminated without waiting for the current task.
|
|
108
|
+
const abortText = (0, abort_detect_1.extractRawTextFromEvent)(event);
|
|
109
|
+
if (abortText && (0, abort_detect_1.isLikelyAbortText)(abortText)) {
|
|
110
|
+
const queueKey = (0, chat_queue_1.buildQueueKey)(accountId, chatId, threadId);
|
|
111
|
+
if ((0, chat_queue_1.hasActiveTask)(queueKey)) {
|
|
112
|
+
const active = (0, chat_queue_1.getActiveDispatcher)(queueKey);
|
|
113
|
+
if (active) {
|
|
114
|
+
log(`feishu[${accountId}]: abort fast-path triggered for chat ${chatId} (text="${abortText}")`);
|
|
115
|
+
active.abortController?.abort();
|
|
116
|
+
active.abortCard().catch((err) => {
|
|
117
|
+
error(`feishu[${accountId}]: abort fast-path abortCard failed: ${String(err)}`);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const { status } = (0, chat_queue_1.enqueueFeishuChatTask)({
|
|
123
|
+
accountId,
|
|
124
|
+
chatId,
|
|
125
|
+
threadId,
|
|
126
|
+
task: async () => {
|
|
127
|
+
try {
|
|
128
|
+
await (0, lark_ticket_1.withTicket)({
|
|
129
|
+
messageId: msgId,
|
|
130
|
+
chatId,
|
|
131
|
+
accountId,
|
|
132
|
+
startTime: Date.now(),
|
|
133
|
+
senderOpenId: event.sender?.sender_id?.open_id || '',
|
|
134
|
+
chatType: event.message?.chat_type || undefined,
|
|
135
|
+
threadId,
|
|
136
|
+
}, () => (0, handler_1.handleFeishuMessage)({
|
|
137
|
+
cfg: ctx.cfg,
|
|
138
|
+
event,
|
|
139
|
+
botOpenId: ctx.lark.botOpenId,
|
|
140
|
+
runtime: ctx.runtime,
|
|
141
|
+
chatHistories: ctx.chatHistories,
|
|
142
|
+
accountId,
|
|
143
|
+
}));
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
error(`feishu[${accountId}]: error handling message: ${String(err)}`);
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
log(`feishu[${accountId}]: message ${msgId} in chat ${chatId}${threadId ? ` thread ${threadId}` : ''} — ${status}`);
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
error(`feishu[${accountId}]: error handling message: ${String(err)}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
// Reaction handler
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
159
|
+
async function handleReactionEvent(ctx, data) {
|
|
160
|
+
if (!isEventOwnershipValid(ctx, data))
|
|
161
|
+
return;
|
|
162
|
+
const { accountId, log, error } = ctx;
|
|
163
|
+
try {
|
|
164
|
+
const event = data;
|
|
165
|
+
const msgId = event.message_id ?? 'unknown';
|
|
166
|
+
log(`feishu[${accountId}]: reaction event on message ${msgId}`);
|
|
167
|
+
// ---- Dedup: deterministic key based on message + emoji + operator ----
|
|
168
|
+
const emojiType = event.reaction_type?.emoji_type ?? '';
|
|
169
|
+
const operatorOpenId = event.user_id?.open_id ?? '';
|
|
170
|
+
const dedupKey = `${msgId}:reaction:${emojiType}:${operatorOpenId}`;
|
|
171
|
+
if (!ctx.messageDedup.tryRecord(dedupKey, accountId)) {
|
|
172
|
+
log(`feishu[${accountId}]: duplicate reaction ${dedupKey}, skipping`);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
// ---- Expiry: discard stale reaction events ----
|
|
176
|
+
if ((0, dedup_1.isMessageExpired)(event.action_time)) {
|
|
177
|
+
log(`feishu[${accountId}]: reaction on ${msgId} expired, discarding`);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
// ---- Pre-resolve real chatId before enqueuing ----
|
|
181
|
+
// The API call (3s timeout) runs outside the queue so it doesn't
|
|
182
|
+
// block the serial chain, and is read-only so ordering is irrelevant.
|
|
183
|
+
const preResolved = await (0, reaction_handler_1.resolveReactionContext)({
|
|
184
|
+
cfg: ctx.cfg,
|
|
185
|
+
event,
|
|
186
|
+
botOpenId: ctx.lark.botOpenId,
|
|
187
|
+
runtime: ctx.runtime,
|
|
188
|
+
accountId,
|
|
189
|
+
});
|
|
190
|
+
if (!preResolved)
|
|
191
|
+
return;
|
|
192
|
+
// ---- Enqueue with the real chatId (matches normal message queue key) ----
|
|
193
|
+
const { status } = (0, chat_queue_1.enqueueFeishuChatTask)({
|
|
194
|
+
accountId,
|
|
195
|
+
chatId: preResolved.chatId,
|
|
196
|
+
threadId: preResolved.threadId,
|
|
197
|
+
task: async () => {
|
|
198
|
+
try {
|
|
199
|
+
await (0, lark_ticket_1.withTicket)({
|
|
200
|
+
messageId: msgId,
|
|
201
|
+
chatId: preResolved.chatId,
|
|
202
|
+
accountId,
|
|
203
|
+
startTime: Date.now(),
|
|
204
|
+
senderOpenId: operatorOpenId,
|
|
205
|
+
chatType: preResolved.chatType,
|
|
206
|
+
threadId: preResolved.threadId,
|
|
207
|
+
}, () => (0, reaction_handler_1.handleFeishuReaction)({
|
|
208
|
+
cfg: ctx.cfg,
|
|
209
|
+
event,
|
|
210
|
+
botOpenId: ctx.lark.botOpenId,
|
|
211
|
+
runtime: ctx.runtime,
|
|
212
|
+
chatHistories: ctx.chatHistories,
|
|
213
|
+
accountId,
|
|
214
|
+
preResolved,
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
error(`feishu[${accountId}]: error handling reaction: ${String(err)}`);
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
log(`feishu[${accountId}]: reaction on ${msgId} (chatId=${preResolved.chatId}) — ${status}`);
|
|
223
|
+
}
|
|
224
|
+
catch (err) {
|
|
225
|
+
error(`feishu[${accountId}]: error handling reaction event: ${String(err)}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// ---------------------------------------------------------------------------
|
|
229
|
+
// Bot membership handler
|
|
230
|
+
// ---------------------------------------------------------------------------
|
|
231
|
+
async function handleBotMembershipEvent(ctx, data, action) {
|
|
232
|
+
if (!isEventOwnershipValid(ctx, data))
|
|
233
|
+
return;
|
|
234
|
+
const { accountId, log, error } = ctx;
|
|
235
|
+
try {
|
|
236
|
+
const event = data;
|
|
237
|
+
log(`feishu[${accountId}]: bot ${action} ${action === 'removed' ? 'from' : 'to'} chat ${event.chat_id}`);
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
error(`feishu[${accountId}]: error handling bot ${action} event: ${String(err)}`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
// ---------------------------------------------------------------------------
|
|
244
|
+
// VC meeting invited handler
|
|
245
|
+
// ---------------------------------------------------------------------------
|
|
246
|
+
async function handleVcMeetingInvitedEvent(ctx, data) {
|
|
247
|
+
if (!isEventOwnershipValid(ctx, data))
|
|
248
|
+
return;
|
|
249
|
+
const { accountId, log, error } = ctx;
|
|
250
|
+
try {
|
|
251
|
+
const event = data;
|
|
252
|
+
const meetingNo = event.meeting?.meeting_no?.trim() ?? '';
|
|
253
|
+
const eventId = event.event_id?.trim() ?? '';
|
|
254
|
+
// Resolve the inviter identity through the shared helper so the
|
|
255
|
+
// diagnostics log and the dispatch handler always agree on the
|
|
256
|
+
// same sender semantics.
|
|
257
|
+
const sender = (0, vc_sender_1.resolveVcSender)(event);
|
|
258
|
+
const senderId = sender.senderId;
|
|
259
|
+
const invitedBotOpenId = event.bot?.id?.open_id?.trim() ?? '';
|
|
260
|
+
// VC invited origin/ownership diagnostics:
|
|
261
|
+
// - This handler is only reachable from the WebSocket monitor path.
|
|
262
|
+
// - We still log app_id/bot_open_id so operators can confirm the event
|
|
263
|
+
// is delivered to the expected bot/account, and see which required
|
|
264
|
+
// fields are missing when we skip.
|
|
265
|
+
const expectedAppId = ctx.lark.account.appId ?? '';
|
|
266
|
+
const eventAppId = event.app_id?.trim() ?? '';
|
|
267
|
+
log(`feishu[${accountId}]: vc invited event received (ingress=websocket)` +
|
|
268
|
+
`${eventId ? ` event_id=${eventId}` : ''}` +
|
|
269
|
+
`${eventAppId ? ` app_id=${eventAppId}` : ' app_id=<missing>'}` +
|
|
270
|
+
`${expectedAppId ? ` expected_app_id=${expectedAppId}` : ''}` +
|
|
271
|
+
`${invitedBotOpenId ? ` bot_open_id=${invitedBotOpenId}` : ' bot_open_id=<missing>'}` +
|
|
272
|
+
`${ctx.lark.botOpenId ? ` expected_bot_open_id=${ctx.lark.botOpenId}` : ''}` +
|
|
273
|
+
`${event.invite_time ? ` invite_time=${event.invite_time}` : ''}` +
|
|
274
|
+
` meeting_no_present=${meetingNo ? 'true' : 'false'}` +
|
|
275
|
+
` sender_present=${senderId ? 'true' : 'false'}` +
|
|
276
|
+
` sender_from=${sender.fromFallback}`);
|
|
277
|
+
if (!meetingNo) {
|
|
278
|
+
log(`feishu[${accountId}]: vc invited event missing meeting_no, skipping`);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
if (!senderId) {
|
|
282
|
+
log(`feishu[${accountId}]: vc invited event missing inviter identity, skipping`);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (ctx.lark.botOpenId && invitedBotOpenId && invitedBotOpenId !== ctx.lark.botOpenId) {
|
|
286
|
+
log(`feishu[${accountId}]: vc invited event for another bot, expected=${ctx.lark.botOpenId}, got=${invitedBotOpenId}, skipping`);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
// Prefer event_id when the SDK exposes it: historical raw payload logs
|
|
290
|
+
// show WebSocket reconnect replays reuse the same event_id, while a real
|
|
291
|
+
// second invitation yields a new event_id even for the same meeting/bot.
|
|
292
|
+
// Fallback to (meeting_no, bot) only when event_id is absent so older
|
|
293
|
+
// payload shapes still remain deduplicated.
|
|
294
|
+
const dedupBotKey = ctx.lark.botOpenId ?? invitedBotOpenId ?? 'no-bot';
|
|
295
|
+
const dedupKey = eventId ? `vc-invited:by-event:${eventId}` : `vc-invited:by-meeting:${meetingNo}:${dedupBotKey}`;
|
|
296
|
+
if (!ctx.messageDedup.tryRecord(dedupKey, accountId)) {
|
|
297
|
+
log(`feishu[${accountId}]: duplicate vc invited event detected, skipping`);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
log(`feishu[${accountId}]: vc invited event accepted for synthetic dispatch`);
|
|
301
|
+
await (0, vc_meeting_invited_handler_1.handleFeishuVcMeetingInvited)({
|
|
302
|
+
cfg: ctx.cfg,
|
|
303
|
+
event,
|
|
304
|
+
runtime: ctx.runtime,
|
|
305
|
+
chatHistories: ctx.chatHistories,
|
|
306
|
+
accountId,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
catch (err) {
|
|
310
|
+
error(`feishu[${accountId}]: error handling vc invited event: ${String(err)}`);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
// ---------------------------------------------------------------------------
|
|
314
|
+
// Drive comment handler
|
|
315
|
+
// ---------------------------------------------------------------------------
|
|
316
|
+
async function handleCommentEvent(ctx, data) {
|
|
317
|
+
if (!isEventOwnershipValid(ctx, data))
|
|
318
|
+
return;
|
|
319
|
+
const { accountId, log, error } = ctx;
|
|
320
|
+
try {
|
|
321
|
+
const parsed = (0, comment_context_1.parseFeishuDriveCommentNoticeEventPayload)(data);
|
|
322
|
+
if (!parsed) {
|
|
323
|
+
log(`feishu[${accountId}]: invalid comment event payload, skipping`);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const commentId = parsed.comment_id ?? '';
|
|
327
|
+
const replyId = parsed.reply_id ?? '';
|
|
328
|
+
// Parser has normalized notice_meta fields into canonical top-level fields
|
|
329
|
+
const _senderOpenId = parsed.user_id?.open_id ?? '';
|
|
330
|
+
const isMentioned = parsed.is_mention ?? false;
|
|
331
|
+
const eventTimestamp = parsed.action_time;
|
|
332
|
+
log(`feishu[${accountId}]: drive comment event: ` +
|
|
333
|
+
`type=${parsed.file_type}, comment=${commentId}` +
|
|
334
|
+
`${replyId ? `, reply=${replyId}` : ''}` +
|
|
335
|
+
`${isMentioned ? ', @bot' : ''}`);
|
|
336
|
+
// Dedup: build a deterministic key from the comment/reply IDs
|
|
337
|
+
const dedupKey = replyId ? `comment:${commentId}:reply:${replyId}` : `comment:${commentId}`;
|
|
338
|
+
if (!ctx.messageDedup.tryRecord(dedupKey, accountId)) {
|
|
339
|
+
log(`feishu[${accountId}]: duplicate comment event ${dedupKey}, skipping`);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
// Expiry check
|
|
343
|
+
if ((0, dedup_1.isMessageExpired)(eventTimestamp)) {
|
|
344
|
+
log(`feishu[${accountId}]: comment event expired, discarding`);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
// Dispatch the comment event (no queue serialization needed for comment threads)
|
|
348
|
+
await (0, comment_handler_1.handleFeishuCommentEvent)({
|
|
349
|
+
cfg: ctx.cfg,
|
|
350
|
+
event: parsed,
|
|
351
|
+
botOpenId: ctx.lark.botOpenId,
|
|
352
|
+
runtime: ctx.runtime,
|
|
353
|
+
chatHistories: ctx.chatHistories,
|
|
354
|
+
accountId,
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
catch (err) {
|
|
358
|
+
error(`feishu[${accountId}]: error handling comment event: ${String(err)}`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
// ---------------------------------------------------------------------------
|
|
362
|
+
// Card action handler
|
|
363
|
+
// ---------------------------------------------------------------------------
|
|
364
|
+
async function handleCardActionEvent(ctx, data) {
|
|
365
|
+
try {
|
|
366
|
+
// AskUserQuestion:表单卡片交互(宿主内建能力优先)
|
|
367
|
+
const askResult = (0, ask_user_question_1.handleAskUserAction)(data, ctx.cfg, ctx.accountId);
|
|
368
|
+
if (askResult !== undefined)
|
|
369
|
+
return askResult;
|
|
370
|
+
// auto-auth:授权/权限引导相关卡片交互(宿主内建能力优先)
|
|
371
|
+
const authResult = await (0, auto_auth_1.handleCardAction)(data, ctx.cfg, ctx.accountId);
|
|
372
|
+
if (authResult !== undefined)
|
|
373
|
+
return authResult;
|
|
374
|
+
// 业务自定义卡片交互:使用 SDK 标准 interactive dispatch 管道转发给业务插件。
|
|
375
|
+
return await (0, interactive_dispatch_1.dispatchFeishuPluginInteractiveHandler)({ cfg: ctx.cfg, accountId: ctx.accountId, data });
|
|
376
|
+
}
|
|
377
|
+
catch (err) {
|
|
378
|
+
elog.warn(`card.action.trigger handler error: ${err}`);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* Feishu interactive dispatch wrapper.
|
|
6
|
+
*
|
|
7
|
+
* This module adapts Feishu `card.action.trigger` events into OpenClaw's
|
|
8
|
+
* standard interactive dispatch pipeline:
|
|
9
|
+
* - Plugins register via `api.registerInteractiveHandler({ channel, namespace, handler })`
|
|
10
|
+
* - Channel forwards via `dispatchPluginInteractiveHandler()`
|
|
11
|
+
*
|
|
12
|
+
* We intentionally do NOT maintain any channel-local global registry here.
|
|
13
|
+
*/
|
|
14
|
+
import type { ClawdbotConfig } from 'openclaw/plugin-sdk';
|
|
15
|
+
export type FeishuInteractiveHandlerResponse = unknown;
|
|
16
|
+
export interface FeishuInteractiveHandlerContext {
|
|
17
|
+
channel: 'feishu';
|
|
18
|
+
accountId: string;
|
|
19
|
+
senderId?: string;
|
|
20
|
+
conversationId?: string;
|
|
21
|
+
messageId?: string;
|
|
22
|
+
namespace: string;
|
|
23
|
+
payload: string;
|
|
24
|
+
action: string;
|
|
25
|
+
rawEvent: unknown;
|
|
26
|
+
respond: {
|
|
27
|
+
reply: (args: {
|
|
28
|
+
text: string;
|
|
29
|
+
}) => Promise<void>;
|
|
30
|
+
followUp: (args: {
|
|
31
|
+
text: string;
|
|
32
|
+
}) => Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Best-effort "edit current message" mapping.
|
|
35
|
+
* In Feishu, we prefer updating the original interactive card when possible.
|
|
36
|
+
*/
|
|
37
|
+
editMessage: (args: {
|
|
38
|
+
text?: string;
|
|
39
|
+
blocks?: unknown[];
|
|
40
|
+
}) => Promise<void>;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Dispatch a Feishu interactive card action to business plugins through
|
|
45
|
+
* the OpenClaw SDK's standard interactive dispatch pipeline.
|
|
46
|
+
*
|
|
47
|
+
* Returns `undefined` when:
|
|
48
|
+
* - the event does not look like an interactive action we can route, or
|
|
49
|
+
* - no plugin handler is registered for the derived namespace.
|
|
50
|
+
*
|
|
51
|
+
* @param params.cfg - OpenClaw config snapshot.
|
|
52
|
+
* @param params.accountId - Current Feishu account id.
|
|
53
|
+
* @param params.data - Raw `card.action.trigger` event payload.
|
|
54
|
+
*/
|
|
55
|
+
export declare function dispatchFeishuPluginInteractiveHandler(params: {
|
|
56
|
+
cfg: ClawdbotConfig;
|
|
57
|
+
accountId: string;
|
|
58
|
+
data: unknown;
|
|
59
|
+
}): Promise<unknown | undefined>;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* Feishu interactive dispatch wrapper.
|
|
7
|
+
*
|
|
8
|
+
* This module adapts Feishu `card.action.trigger` events into OpenClaw's
|
|
9
|
+
* standard interactive dispatch pipeline:
|
|
10
|
+
* - Plugins register via `api.registerInteractiveHandler({ channel, namespace, handler })`
|
|
11
|
+
* - Channel forwards via `dispatchPluginInteractiveHandler()`
|
|
12
|
+
*
|
|
13
|
+
* We intentionally do NOT maintain any channel-local global registry here.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.dispatchFeishuPluginInteractiveHandler = dispatchFeishuPluginInteractiveHandler;
|
|
17
|
+
// NOTE: This is the SDK-standard interactive pipeline.
|
|
18
|
+
const plugin_runtime_1 = require("openclaw/plugin-sdk/plugin-runtime");
|
|
19
|
+
const card_action_operator_1 = require("../core/card-action-operator.js");
|
|
20
|
+
const lark_logger_1 = require("../core/lark-logger.js");
|
|
21
|
+
const send_1 = require("../messaging/outbound/send.js");
|
|
22
|
+
const log = (0, lark_logger_1.larkLogger)('channel/interactive-dispatch');
|
|
23
|
+
function extractBasics(data) {
|
|
24
|
+
try {
|
|
25
|
+
const ev = data;
|
|
26
|
+
const action = ev.action?.value?.action ?? ev.action?.name ?? formSubmitActionName(ev);
|
|
27
|
+
if (!action || typeof action !== 'string')
|
|
28
|
+
return null;
|
|
29
|
+
const openChatId = ev.open_chat_id ?? ev.context?.open_chat_id;
|
|
30
|
+
const openMessageId = ev.open_message_id ?? ev.context?.open_message_id;
|
|
31
|
+
return {
|
|
32
|
+
action: action.trim(),
|
|
33
|
+
senderOpenId: (0, card_action_operator_1.resolveCardCallbackOperatorId)(ev.operator),
|
|
34
|
+
openChatId,
|
|
35
|
+
openMessageId,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function formSubmitActionName(ev) {
|
|
43
|
+
const tag = ev.action?.tag;
|
|
44
|
+
if (tag !== 'form_submit')
|
|
45
|
+
return undefined;
|
|
46
|
+
return ev.action?.form_name;
|
|
47
|
+
}
|
|
48
|
+
function buildMarkdownCard(text) {
|
|
49
|
+
return {
|
|
50
|
+
schema: '2.0',
|
|
51
|
+
body: {
|
|
52
|
+
elements: [
|
|
53
|
+
{
|
|
54
|
+
tag: 'markdown',
|
|
55
|
+
content: text,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Dispatch a Feishu interactive card action to business plugins through
|
|
63
|
+
* the OpenClaw SDK's standard interactive dispatch pipeline.
|
|
64
|
+
*
|
|
65
|
+
* Returns `undefined` when:
|
|
66
|
+
* - the event does not look like an interactive action we can route, or
|
|
67
|
+
* - no plugin handler is registered for the derived namespace.
|
|
68
|
+
*
|
|
69
|
+
* @param params.cfg - OpenClaw config snapshot.
|
|
70
|
+
* @param params.accountId - Current Feishu account id.
|
|
71
|
+
* @param params.data - Raw `card.action.trigger` event payload.
|
|
72
|
+
*/
|
|
73
|
+
async function dispatchFeishuPluginInteractiveHandler(params) {
|
|
74
|
+
const basics = extractBasics(params.data);
|
|
75
|
+
if (!basics)
|
|
76
|
+
return undefined;
|
|
77
|
+
if (!basics.action)
|
|
78
|
+
return undefined;
|
|
79
|
+
const respond = {
|
|
80
|
+
reply: async (args) => {
|
|
81
|
+
if (!basics.openChatId || !String(args?.text || '').trim())
|
|
82
|
+
return;
|
|
83
|
+
await (0, send_1.sendMessageFeishu)({
|
|
84
|
+
cfg: params.cfg,
|
|
85
|
+
to: basics.openChatId,
|
|
86
|
+
text: String(args?.text || ''),
|
|
87
|
+
replyToMessageId: basics.openMessageId,
|
|
88
|
+
accountId: params.accountId,
|
|
89
|
+
replyInThread: false,
|
|
90
|
+
});
|
|
91
|
+
},
|
|
92
|
+
followUp: async (args) => {
|
|
93
|
+
if (!basics.openChatId || !String(args?.text || '').trim())
|
|
94
|
+
return;
|
|
95
|
+
await (0, send_1.sendMessageFeishu)({
|
|
96
|
+
cfg: params.cfg,
|
|
97
|
+
to: basics.openChatId,
|
|
98
|
+
text: String(args?.text || ''),
|
|
99
|
+
replyToMessageId: basics.openMessageId,
|
|
100
|
+
accountId: params.accountId,
|
|
101
|
+
replyInThread: false,
|
|
102
|
+
});
|
|
103
|
+
},
|
|
104
|
+
editMessage: async (args) => {
|
|
105
|
+
if (!basics.openMessageId) {
|
|
106
|
+
if (Array.isArray(args?.blocks) && args.blocks.length && basics.openChatId) {
|
|
107
|
+
await (0, send_1.sendCardFeishu)({
|
|
108
|
+
cfg: params.cfg,
|
|
109
|
+
to: basics.openChatId,
|
|
110
|
+
card: { schema: '2.0', body: { elements: args.blocks } },
|
|
111
|
+
replyToMessageId: basics.openMessageId,
|
|
112
|
+
accountId: params.accountId,
|
|
113
|
+
replyInThread: false,
|
|
114
|
+
});
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (typeof args?.text === 'string' && args.text.trim() && basics.openChatId) {
|
|
118
|
+
await (0, send_1.sendMessageFeishu)({
|
|
119
|
+
cfg: params.cfg,
|
|
120
|
+
to: basics.openChatId,
|
|
121
|
+
text: args.text,
|
|
122
|
+
replyToMessageId: basics.openMessageId,
|
|
123
|
+
accountId: params.accountId,
|
|
124
|
+
replyInThread: false,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (Array.isArray(args?.blocks) && args.blocks.length) {
|
|
130
|
+
await (0, send_1.updateCardFeishu)({
|
|
131
|
+
cfg: params.cfg,
|
|
132
|
+
messageId: basics.openMessageId,
|
|
133
|
+
card: { schema: '2.0', body: { elements: args.blocks } },
|
|
134
|
+
accountId: params.accountId,
|
|
135
|
+
});
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (typeof args?.text === 'string' && args.text.trim()) {
|
|
139
|
+
await (0, send_1.updateCardFeishu)({
|
|
140
|
+
cfg: params.cfg,
|
|
141
|
+
messageId: basics.openMessageId,
|
|
142
|
+
card: buildMarkdownCard(args.text),
|
|
143
|
+
accountId: params.accountId,
|
|
144
|
+
});
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
await (0, send_1.updateCardFeishu)({
|
|
148
|
+
cfg: params.cfg,
|
|
149
|
+
messageId: basics.openMessageId,
|
|
150
|
+
card: { schema: '2.0', body: { elements: [] } },
|
|
151
|
+
accountId: params.accountId,
|
|
152
|
+
});
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
try {
|
|
156
|
+
const dedupeId = `feishu:${params.accountId}:${basics.openChatId ?? '-'}:${basics.openMessageId ?? '-'}:${basics.senderOpenId ?? '-'}:${basics.action}`;
|
|
157
|
+
let cardResponse;
|
|
158
|
+
const result = await (0, plugin_runtime_1.dispatchPluginInteractiveHandler)({
|
|
159
|
+
channel: 'feishu',
|
|
160
|
+
data: basics.action,
|
|
161
|
+
dedupeId,
|
|
162
|
+
invoke: async (match) => {
|
|
163
|
+
const { registration, namespace, payload } = match;
|
|
164
|
+
const handlerCtx = {
|
|
165
|
+
channel: 'feishu',
|
|
166
|
+
accountId: params.accountId,
|
|
167
|
+
senderId: basics.senderOpenId,
|
|
168
|
+
conversationId: basics.openChatId,
|
|
169
|
+
messageId: basics.openMessageId,
|
|
170
|
+
namespace,
|
|
171
|
+
payload,
|
|
172
|
+
action: basics.action,
|
|
173
|
+
rawEvent: params.data,
|
|
174
|
+
respond,
|
|
175
|
+
};
|
|
176
|
+
cardResponse = await registration.handler(handlerCtx);
|
|
177
|
+
// If the handler returns a card response, treat it as handled.
|
|
178
|
+
return { handled: cardResponse !== undefined };
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
log.debug(`interactive dispatch result: action=${basics.action}, matched=${result.matched}, handled=${result.handled}`);
|
|
182
|
+
if (!result.matched)
|
|
183
|
+
return undefined;
|
|
184
|
+
return cardResponse;
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
log.warn(`interactive dispatch failed: ${String(err)}`);
|
|
188
|
+
return {
|
|
189
|
+
toast: {
|
|
190
|
+
type: 'error',
|
|
191
|
+
content: '交互处理失败,请稍后重试',
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* WebSocket monitoring for the Lark/Feishu channel plugin.
|
|
6
|
+
*
|
|
7
|
+
* Manages per-account WSClient connections and routes inbound Feishu
|
|
8
|
+
* events (messages, bot membership changes, read receipts) to the
|
|
9
|
+
* appropriate handlers.
|
|
10
|
+
*/
|
|
11
|
+
import type { MonitorFeishuOpts } from './types';
|
|
12
|
+
export type { MonitorFeishuOpts } from './types';
|
|
13
|
+
/**
|
|
14
|
+
* Start monitoring for all enabled Feishu accounts (or a single
|
|
15
|
+
* account when `opts.accountId` is specified).
|
|
16
|
+
*/
|
|
17
|
+
export declare function monitorFeishuProvider(opts?: MonitorFeishuOpts): Promise<void>;
|