@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,306 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* Account-scoped LRU cache for Feishu user display names.
|
|
7
|
+
*
|
|
8
|
+
* Provides:
|
|
9
|
+
* - `UserNameCache` — per-account LRU Map with TTL
|
|
10
|
+
* - `getUserNameCache(accountId)` — singleton registry
|
|
11
|
+
* - `batchResolveUserNames()` — batch API via `contact/v3/users/batch`
|
|
12
|
+
* - `resolveUserName()` — single-user fallback via `contact.user.get`
|
|
13
|
+
* - `clearUserNameCache()` — teardown hook (called from LarkClient.clearCache)
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.getUserNameCache = exports.clearUserNameCache = exports.UserNameCache = void 0;
|
|
17
|
+
exports.batchResolveUserNames = batchResolveUserNames;
|
|
18
|
+
exports.createBatchResolveNames = createBatchResolveNames;
|
|
19
|
+
exports.resolveBotName = resolveBotName;
|
|
20
|
+
exports.prefetchChatBots = prefetchChatBots;
|
|
21
|
+
exports.prefetchChatMembers = prefetchChatMembers;
|
|
22
|
+
exports.resolveUserName = resolveUserName;
|
|
23
|
+
const lark_client_1 = require("../../core/lark-client.js");
|
|
24
|
+
const user_name_cache_store_1 = require("./user-name-cache-store.js");
|
|
25
|
+
const permission_1 = require("./permission.js");
|
|
26
|
+
var user_name_cache_store_2 = require("./user-name-cache-store.js");
|
|
27
|
+
Object.defineProperty(exports, "UserNameCache", { enumerable: true, get: function () { return user_name_cache_store_2.UserNameCache; } });
|
|
28
|
+
Object.defineProperty(exports, "clearUserNameCache", { enumerable: true, get: function () { return user_name_cache_store_2.clearUserNameCache; } });
|
|
29
|
+
Object.defineProperty(exports, "getUserNameCache", { enumerable: true, get: function () { return user_name_cache_store_2.getUserNameCache; } });
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Batch resolve via contact/v3/users/batch
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
/** Max user_ids per API call (Feishu limit). */
|
|
34
|
+
const BATCH_SIZE = 50;
|
|
35
|
+
/**
|
|
36
|
+
* Batch-resolve user display names.
|
|
37
|
+
*
|
|
38
|
+
* 1. Check cache → collect misses
|
|
39
|
+
* 2. Deduplicate
|
|
40
|
+
* 3. Call `GET /open-apis/contact/v3/users/batch` in chunks of 50
|
|
41
|
+
* 4. Write results back to cache
|
|
42
|
+
* 5. Return full Map<openId, name> (cache hits + API results)
|
|
43
|
+
*
|
|
44
|
+
* Best-effort: API errors are logged but never thrown.
|
|
45
|
+
*/
|
|
46
|
+
async function batchResolveUserNames(params) {
|
|
47
|
+
const { account, openIds, log } = params;
|
|
48
|
+
if (!account.configured || openIds.length === 0) {
|
|
49
|
+
return new Map();
|
|
50
|
+
}
|
|
51
|
+
const cache = (0, user_name_cache_store_1.getUserNameCache)(account.accountId);
|
|
52
|
+
const result = cache.getMany(openIds);
|
|
53
|
+
// Deduplicate missing IDs
|
|
54
|
+
const missing = [...new Set(cache.filterMissing(openIds))];
|
|
55
|
+
if (missing.length === 0)
|
|
56
|
+
return result;
|
|
57
|
+
const client = lark_client_1.LarkClient.fromAccount(account).sdk;
|
|
58
|
+
// Split into chunks of BATCH_SIZE and call SDK method
|
|
59
|
+
for (let i = 0; i < missing.length; i += BATCH_SIZE) {
|
|
60
|
+
const chunk = missing.slice(i, i + BATCH_SIZE);
|
|
61
|
+
try {
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63
|
+
const res = await client.contact.user.batch({
|
|
64
|
+
params: {
|
|
65
|
+
user_ids: chunk,
|
|
66
|
+
user_id_type: 'open_id',
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
70
|
+
const items = res?.data?.items ?? [];
|
|
71
|
+
const resolved = new Set();
|
|
72
|
+
for (const item of items) {
|
|
73
|
+
const openId = item.open_id;
|
|
74
|
+
if (!openId)
|
|
75
|
+
continue;
|
|
76
|
+
const name = item.name || item.display_name || item.nickname || item.en_name || '';
|
|
77
|
+
cache.setWithKind(openId, name, 'user');
|
|
78
|
+
result.set(openId, name);
|
|
79
|
+
resolved.add(openId);
|
|
80
|
+
}
|
|
81
|
+
// Cache empty names for IDs the API didn't return (no permission, etc.)
|
|
82
|
+
for (const id of chunk) {
|
|
83
|
+
if (!resolved.has(id)) {
|
|
84
|
+
cache.setWithKind(id, '', 'user');
|
|
85
|
+
result.set(id, '');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
log(`batchResolveUserNames: failed: ${String(err)}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Create a `batchResolveNames` callback for use in `ConvertContext`.
|
|
97
|
+
*
|
|
98
|
+
* The returned function calls `batchResolveUserNames` with the given
|
|
99
|
+
* account and log function, populating the TAT user-name cache.
|
|
100
|
+
*/
|
|
101
|
+
function createBatchResolveNames(account, log) {
|
|
102
|
+
return async (openIds) => {
|
|
103
|
+
await batchResolveUserNames({ account, openIds, log });
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Resolve a single bot's display name via `/open-apis/bot/v3/bots/basic_batch`.
|
|
108
|
+
*
|
|
109
|
+
* Bots are not returned by the contact API, so they have their own endpoint.
|
|
110
|
+
* Names share the same account-scoped cache (keyed by openId) since both
|
|
111
|
+
* bots and users have `ou_` prefixed openIds and a single display name.
|
|
112
|
+
*/
|
|
113
|
+
async function resolveBotName(params) {
|
|
114
|
+
const { account, openId, log } = params;
|
|
115
|
+
if (!account.configured || !openId)
|
|
116
|
+
return {};
|
|
117
|
+
const cache = (0, user_name_cache_store_1.getUserNameCache)(account.accountId);
|
|
118
|
+
if (cache.has(openId))
|
|
119
|
+
return { name: cache.get(openId) ?? '' };
|
|
120
|
+
try {
|
|
121
|
+
const client = lark_client_1.LarkClient.fromAccount(account).sdk;
|
|
122
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
123
|
+
const res = await client.request({
|
|
124
|
+
method: 'GET',
|
|
125
|
+
url: '/open-apis/bot/v3/bots/basic_batch',
|
|
126
|
+
params: { bot_ids: [openId] },
|
|
127
|
+
});
|
|
128
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
129
|
+
const bot = res?.data?.bots?.[openId];
|
|
130
|
+
const name = bot?.name || bot?.i18n_names?.zh_cn || bot?.i18n_names?.en_us || '';
|
|
131
|
+
// Cache even empty names to avoid repeated API calls for bots
|
|
132
|
+
// whose names we cannot resolve.
|
|
133
|
+
cache.setWithKind(openId, name, 'bot');
|
|
134
|
+
return { name: name || undefined };
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
// Bot name resolution is best-effort: missing `bot:basic_info` scope
|
|
138
|
+
// should not surface as a permission notification to the agent. Log
|
|
139
|
+
// and cache an empty name so we don't retry, then fall back to openId.
|
|
140
|
+
const permErr = (0, permission_1.extractPermissionError)(err);
|
|
141
|
+
if (permErr) {
|
|
142
|
+
log(`feishu: permission error resolving bot name (best-effort, ignored): code=${permErr.code}`);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
log(`feishu: failed to resolve bot name for ${openId}: ${String(err)}`);
|
|
146
|
+
}
|
|
147
|
+
cache.setWithKind(openId, '', 'bot');
|
|
148
|
+
return {};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
// Lazy chat-member prefetch
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
/** Returns the numeric Feishu API error code from a thrown error, or null. */
|
|
155
|
+
function extractApiCode(err) {
|
|
156
|
+
const permErr = (0, permission_1.extractPermissionError)(err);
|
|
157
|
+
if (typeof permErr?.code === 'number')
|
|
158
|
+
return permErr.code;
|
|
159
|
+
if (err && typeof err === 'object') {
|
|
160
|
+
const code = err.response?.data?.code;
|
|
161
|
+
if (typeof code === 'number')
|
|
162
|
+
return code;
|
|
163
|
+
}
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Runs a chat-member prefetch with shared lifecycle:
|
|
168
|
+
*
|
|
169
|
+
* 1. Skip on unconfigured account or empty chatId.
|
|
170
|
+
* 2. Dedup concurrent calls per (tag, chatId) via `cache.inFlight`.
|
|
171
|
+
* 3. Skip when an in-TTL snapshot already exists.
|
|
172
|
+
* 4. On API error, cache an empty list to short-circuit retries; on
|
|
173
|
+
* transient errors, leave the cache untouched so the next call retries.
|
|
174
|
+
*/
|
|
175
|
+
async function runChatPrefetch(spec, account, chatId, log) {
|
|
176
|
+
if (!account.configured || !chatId)
|
|
177
|
+
return;
|
|
178
|
+
const cache = (0, user_name_cache_store_1.getUserNameCache)(account.accountId);
|
|
179
|
+
const key = `${spec.tag}:${chatId}`;
|
|
180
|
+
const existing = cache.getInflight(key);
|
|
181
|
+
if (existing)
|
|
182
|
+
return existing;
|
|
183
|
+
if (spec.isFresh(cache, chatId))
|
|
184
|
+
return;
|
|
185
|
+
const promise = (async () => {
|
|
186
|
+
try {
|
|
187
|
+
const client = lark_client_1.LarkClient.fromAccount(account).sdk;
|
|
188
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
189
|
+
const res = await client.request({
|
|
190
|
+
method: 'GET',
|
|
191
|
+
url: spec.url(chatId),
|
|
192
|
+
params: spec.params,
|
|
193
|
+
});
|
|
194
|
+
const items = res?.data?.items ?? [];
|
|
195
|
+
const members = items.map(spec.parseItem).filter((m) => m !== null);
|
|
196
|
+
spec.record(cache, chatId, members);
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
const apiCode = extractApiCode(err);
|
|
200
|
+
if (apiCode != null) {
|
|
201
|
+
// Application-level refusal: cache an empty list to short-circuit
|
|
202
|
+
// further retries. Persistent errors (e.g. missing scope) will not
|
|
203
|
+
// resolve within the cache TTL anyway.
|
|
204
|
+
log(`prefetchChat${spec.tag}[${chatId}]: API error code=${apiCode}, caching empty`);
|
|
205
|
+
spec.record(cache, chatId, []);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
log(`prefetchChat${spec.tag}[${chatId}]: failed: ${String(err)}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
cache.clearInflight(key);
|
|
213
|
+
}
|
|
214
|
+
})();
|
|
215
|
+
cache.setInflight(key, promise);
|
|
216
|
+
return promise;
|
|
217
|
+
}
|
|
218
|
+
const CHAT_BOTS_SPEC = {
|
|
219
|
+
tag: 'Bots',
|
|
220
|
+
url: (chatId) => `/open-apis/im/v1/chats/${chatId}/members/bots`,
|
|
221
|
+
params: {},
|
|
222
|
+
parseItem: (raw) => {
|
|
223
|
+
const it = raw;
|
|
224
|
+
const openId = String(it.bot_id ?? it.open_id ?? '');
|
|
225
|
+
if (!openId)
|
|
226
|
+
return null;
|
|
227
|
+
return { openId, name: String(it.bot_name ?? it.name ?? '') };
|
|
228
|
+
},
|
|
229
|
+
isFresh: (cache, chatId) => cache.getChatBots(chatId) !== null,
|
|
230
|
+
record: (cache, chatId, members) => cache.recordChatBots(chatId, members),
|
|
231
|
+
};
|
|
232
|
+
function memberTypeToKind(type) {
|
|
233
|
+
return type === 'app' ? 'bot' : 'user';
|
|
234
|
+
}
|
|
235
|
+
const CHAT_MEMBERS_SPEC = {
|
|
236
|
+
tag: 'Members',
|
|
237
|
+
url: (chatId) => `/open-apis/im/v1/chats/${chatId}/members`,
|
|
238
|
+
params: { member_id_type: 'open_id', page_size: 100 },
|
|
239
|
+
parseItem: (raw) => {
|
|
240
|
+
const it = raw;
|
|
241
|
+
const openId = String(it.member_id ?? it.open_id ?? '');
|
|
242
|
+
if (!openId)
|
|
243
|
+
return null;
|
|
244
|
+
return { openId, name: String(it.name ?? ''), kind: memberTypeToKind(it.member_type) };
|
|
245
|
+
},
|
|
246
|
+
isFresh: (cache, chatId) => cache.getChatMembers(chatId) !== null,
|
|
247
|
+
record: (cache, chatId, members) => cache.recordChatMembers(chatId, members),
|
|
248
|
+
};
|
|
249
|
+
/**
|
|
250
|
+
* Fetches the bot members of a chat via
|
|
251
|
+
* `GET /open-apis/im/v1/chats/{chat_id}/members/bots` and writes them
|
|
252
|
+
* to the per-account cache.
|
|
253
|
+
*/
|
|
254
|
+
async function prefetchChatBots(account, chatId, log) {
|
|
255
|
+
return runChatPrefetch(CHAT_BOTS_SPEC, account, chatId, log);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Fetches the human members of a chat via
|
|
259
|
+
* `GET /open-apis/im/v1/chats/{chat_id}/members` and writes them to
|
|
260
|
+
* the per-account cache.
|
|
261
|
+
*/
|
|
262
|
+
async function prefetchChatMembers(account, chatId, log) {
|
|
263
|
+
return runChatPrefetch(CHAT_MEMBERS_SPEC, account, chatId, log);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Resolve a single user's display name.
|
|
267
|
+
*
|
|
268
|
+
* Checks the account-scoped cache first, then falls back to the
|
|
269
|
+
* `contact.user.get` API (same as the old `resolveFeishuSenderName`).
|
|
270
|
+
*/
|
|
271
|
+
async function resolveUserName(params) {
|
|
272
|
+
const { account, openId, log } = params;
|
|
273
|
+
if (!account.configured || !openId)
|
|
274
|
+
return {};
|
|
275
|
+
const cache = (0, user_name_cache_store_1.getUserNameCache)(account.accountId);
|
|
276
|
+
if (cache.has(openId))
|
|
277
|
+
return { name: cache.get(openId) ?? '' };
|
|
278
|
+
try {
|
|
279
|
+
const client = lark_client_1.LarkClient.fromAccount(account).sdk;
|
|
280
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
281
|
+
const res = await client.contact.user.get({
|
|
282
|
+
path: { user_id: openId },
|
|
283
|
+
params: { user_id_type: 'open_id' },
|
|
284
|
+
});
|
|
285
|
+
const name = res?.data?.user?.name ||
|
|
286
|
+
res?.data?.user?.display_name ||
|
|
287
|
+
res?.data?.user?.nickname ||
|
|
288
|
+
res?.data?.user?.en_name ||
|
|
289
|
+
'';
|
|
290
|
+
// Cache even empty names to avoid repeated API calls for users
|
|
291
|
+
// whose names we cannot resolve (e.g. due to permissions).
|
|
292
|
+
cache.setWithKind(openId, name, 'user');
|
|
293
|
+
return { name: name || undefined };
|
|
294
|
+
}
|
|
295
|
+
catch (err) {
|
|
296
|
+
const permErr = (0, permission_1.extractPermissionError)(err);
|
|
297
|
+
if (permErr) {
|
|
298
|
+
log(`feishu: permission error resolving user name: code=${permErr.code}`);
|
|
299
|
+
// Cache empty name so we don't retry a known-failing openId
|
|
300
|
+
cache.setWithKind(openId, '', 'user');
|
|
301
|
+
return { permissionError: permErr };
|
|
302
|
+
}
|
|
303
|
+
log(`feishu: failed to resolve user name for ${openId}: ${String(err)}`);
|
|
304
|
+
return {};
|
|
305
|
+
}
|
|
306
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* VC meeting invited event handler for the Lark/Feishu channel plugin.
|
|
6
|
+
*
|
|
7
|
+
* Handles `vc.bot.meeting_invited_v1` by converting the event into a
|
|
8
|
+
* synthetic natural-language inbound and dispatching it through the
|
|
9
|
+
* standard OpenClaw agent pipeline.
|
|
10
|
+
*/
|
|
11
|
+
import type { ClawdbotConfig, RuntimeEnv } from 'openclaw/plugin-sdk';
|
|
12
|
+
import type { HistoryEntry } from 'openclaw/plugin-sdk/reply-history';
|
|
13
|
+
import type { FeishuVcMeetingInvitedEvent } from '../types';
|
|
14
|
+
export declare function handleFeishuVcMeetingInvited(params: {
|
|
15
|
+
cfg: ClawdbotConfig;
|
|
16
|
+
event: FeishuVcMeetingInvitedEvent;
|
|
17
|
+
runtime?: RuntimeEnv;
|
|
18
|
+
chatHistories?: Map<string, HistoryEntry[]>;
|
|
19
|
+
accountId?: string;
|
|
20
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* VC meeting invited event handler for the Lark/Feishu channel plugin.
|
|
7
|
+
*
|
|
8
|
+
* Handles `vc.bot.meeting_invited_v1` by converting the event into a
|
|
9
|
+
* synthetic natural-language inbound and dispatching it through the
|
|
10
|
+
* standard OpenClaw agent pipeline.
|
|
11
|
+
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
exports.handleFeishuVcMeetingInvited = handleFeishuVcMeetingInvited;
|
|
47
|
+
const crypto = __importStar(require("node:crypto"));
|
|
48
|
+
const synthetic_target_1 = require("../../core/synthetic-target.js");
|
|
49
|
+
const accounts_1 = require("../../core/accounts.js");
|
|
50
|
+
const lark_logger_1 = require("../../core/lark-logger.js");
|
|
51
|
+
const dispatch_1 = require("./dispatch.js");
|
|
52
|
+
const gate_effects_1 = require("./gate-effects.js");
|
|
53
|
+
const gate_1 = require("./gate.js");
|
|
54
|
+
const policy_1 = require("./policy.js");
|
|
55
|
+
const vc_sender_1 = require("./vc-sender.js");
|
|
56
|
+
const logger = (0, lark_logger_1.larkLogger)('inbound/vc-meeting-invited-handler');
|
|
57
|
+
function buildSyntheticEvent(event) {
|
|
58
|
+
const meetingNo = event.meeting?.meeting_no?.trim() ?? '';
|
|
59
|
+
// Both meeting_no and inviter identity are required for this event.
|
|
60
|
+
if (!meetingNo) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const sender = (0, vc_sender_1.resolveVcSender)(event);
|
|
64
|
+
if (!sender.senderId) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
eventType: 'vc.bot.meeting_invited_v1',
|
|
69
|
+
source: 'feishu-vc-event',
|
|
70
|
+
eventId: event.event_id?.trim() || undefined,
|
|
71
|
+
meetingId: event.meeting?.id?.trim() || undefined,
|
|
72
|
+
meetingNo,
|
|
73
|
+
topic: event.meeting?.topic?.trim() || undefined,
|
|
74
|
+
senderId: sender.senderId,
|
|
75
|
+
senderOpenId: sender.senderOpenId,
|
|
76
|
+
senderUserId: sender.senderUserId,
|
|
77
|
+
senderUnionId: sender.senderUnionId,
|
|
78
|
+
senderName: sender.senderName,
|
|
79
|
+
inviteTime: event.invite_time?.trim() || undefined,
|
|
80
|
+
callId: event.call_id?.trim() || undefined,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function buildSyntheticContext(event) {
|
|
84
|
+
// Keep the synthetic inbound prompt in English for now: it is an
|
|
85
|
+
// agent-facing intent string rather than user-visible copy, and the final
|
|
86
|
+
// reply language is still governed by the agent/session prompt stack.
|
|
87
|
+
// If we later need locale-aware synthetic prompts, this is the single place
|
|
88
|
+
// to introduce a template or config-based language switch.
|
|
89
|
+
// Only append the call_id instruction when the invite event actually
|
|
90
|
+
// carries one. Forcing call_id="" into the prompt would assume every
|
|
91
|
+
// downstream join tool / CLI shortcut already recognises the parameter —
|
|
92
|
+
// during rollout that assumption can break auto-join. When absent we keep
|
|
93
|
+
// the legacy prompt shape so behavior degrades to the pre-call_id path.
|
|
94
|
+
const callIdInstruction = event.callId
|
|
95
|
+
? ` When invoking the join tool, pass call_id="${event.callId}".`
|
|
96
|
+
: '';
|
|
97
|
+
const syntheticText = `Use the available tool to join the meeting with meeting number ${event.meetingNo} immediately. Do not ask for confirmation.${callIdInstruction}`;
|
|
98
|
+
const syntheticMessageId = event.eventId
|
|
99
|
+
? `vc-invited:event:${event.eventId}`
|
|
100
|
+
: `vc-invited:${event.meetingNo}:${event.inviteTime ?? crypto.randomUUID()}`;
|
|
101
|
+
// VC-invited events have no real chat/thread — they are service-to-service
|
|
102
|
+
// triggers. Using the inviter's open_id as chatId would cause downstream
|
|
103
|
+
// senders (reply / card / media) to fire off unsolicited DMs to the inviter
|
|
104
|
+
// whenever the agent produced any output. Use a synthetic sentinel instead
|
|
105
|
+
// and let IM-facing deliverers short-circuit on it (see SYNTHETIC_VC_CHAT_ID).
|
|
106
|
+
return {
|
|
107
|
+
chatId: synthetic_target_1.SYNTHETIC_VC_CHAT_ID,
|
|
108
|
+
messageId: syntheticMessageId,
|
|
109
|
+
senderId: event.senderId,
|
|
110
|
+
senderName: event.senderName,
|
|
111
|
+
chatType: synthetic_target_1.SYNTHETIC_VC_CHAT_TYPE,
|
|
112
|
+
content: syntheticText,
|
|
113
|
+
contentType: 'text',
|
|
114
|
+
resources: [],
|
|
115
|
+
mentions: [],
|
|
116
|
+
mentionAll: false,
|
|
117
|
+
rawMessage: {
|
|
118
|
+
message_id: syntheticMessageId,
|
|
119
|
+
chat_id: synthetic_target_1.SYNTHETIC_VC_CHAT_ID,
|
|
120
|
+
chat_type: synthetic_target_1.SYNTHETIC_VC_CHAT_TYPE,
|
|
121
|
+
message_type: 'text',
|
|
122
|
+
content: JSON.stringify({ text: syntheticText }),
|
|
123
|
+
create_time: event.inviteTime ?? String(Date.now()),
|
|
124
|
+
},
|
|
125
|
+
rawSender: {
|
|
126
|
+
sender_id: {
|
|
127
|
+
...(event.senderOpenId ? { open_id: event.senderOpenId } : {}),
|
|
128
|
+
...(event.senderUserId ? { user_id: event.senderUserId } : {}),
|
|
129
|
+
...(event.senderUnionId ? { union_id: event.senderUnionId } : {}),
|
|
130
|
+
},
|
|
131
|
+
sender_type: 'user',
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function matchesAnySenderId(params) {
|
|
136
|
+
const candidates = [...new Set(params.senderIds.map((id) => id?.trim()).filter(Boolean))];
|
|
137
|
+
return candidates.some((candidate) => (0, policy_1.resolveFeishuAllowlistMatch)({
|
|
138
|
+
allowFrom: params.allowFrom,
|
|
139
|
+
senderId: candidate,
|
|
140
|
+
}).allowed);
|
|
141
|
+
}
|
|
142
|
+
async function handleFeishuVcMeetingInvited(params) {
|
|
143
|
+
const { cfg, event, runtime, chatHistories, accountId } = params;
|
|
144
|
+
const log = runtime?.log ?? ((...args) => logger.info(args.map(String).join(' ')));
|
|
145
|
+
const error = runtime?.error ?? ((...args) => logger.error(args.map(String).join(' ')));
|
|
146
|
+
const syntheticEvent = buildSyntheticEvent(event);
|
|
147
|
+
if (!syntheticEvent) {
|
|
148
|
+
log(`feishu[${accountId}]: vc invited event missing meeting_no or inviter identity, skipping`);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const account = (0, accounts_1.getLarkAccount)(cfg, accountId);
|
|
152
|
+
const accountScopedCfg = {
|
|
153
|
+
...cfg,
|
|
154
|
+
channels: { ...cfg.channels, feishu: account.config },
|
|
155
|
+
};
|
|
156
|
+
const accountFeishuCfg = account.config;
|
|
157
|
+
// ---- Access policy enforcement (DM-style) ----
|
|
158
|
+
// VC invited events are user-triggered service events. Align their access
|
|
159
|
+
// semantics with direct-message/comment flows so unpaired users cannot
|
|
160
|
+
// trigger agent behavior through event ingress.
|
|
161
|
+
const dmPolicy = accountFeishuCfg?.dmPolicy ?? 'pairing';
|
|
162
|
+
if (dmPolicy === 'disabled') {
|
|
163
|
+
log(`feishu[${accountId}]: vc invited event rejected (dmPolicy=disabled)`);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (dmPolicy !== 'open') {
|
|
167
|
+
const configAllowFrom = accountFeishuCfg?.allowFrom ?? [];
|
|
168
|
+
const storeAllowFrom = await (0, gate_1.readFeishuAllowFromStore)(account.accountId).catch(() => []);
|
|
169
|
+
const combinedAllowFrom = [...configAllowFrom, ...storeAllowFrom];
|
|
170
|
+
const allowed = matchesAnySenderId({
|
|
171
|
+
allowFrom: combinedAllowFrom,
|
|
172
|
+
senderIds: [
|
|
173
|
+
syntheticEvent.senderOpenId,
|
|
174
|
+
syntheticEvent.senderUserId,
|
|
175
|
+
syntheticEvent.senderUnionId,
|
|
176
|
+
],
|
|
177
|
+
});
|
|
178
|
+
if (!allowed) {
|
|
179
|
+
if (dmPolicy === 'pairing') {
|
|
180
|
+
if (syntheticEvent.senderOpenId) {
|
|
181
|
+
log(`feishu[${accountId}]: vc inviter not paired, creating pairing request`);
|
|
182
|
+
try {
|
|
183
|
+
await (0, gate_effects_1.sendPairingReply)({
|
|
184
|
+
senderId: syntheticEvent.senderOpenId,
|
|
185
|
+
chatId: syntheticEvent.senderOpenId,
|
|
186
|
+
accountId: account.accountId,
|
|
187
|
+
accountScopedCfg,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
catch (pairingErr) {
|
|
191
|
+
log(`feishu[${accountId}]: failed to create pairing request for vc inviter: ${String(pairingErr)}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
log(`feishu[${accountId}]: vc inviter not paired and has no open_id for pairing reply, rejecting`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
log(`feishu[${accountId}]: vc invited event rejected (dmPolicy=${dmPolicy}, inviter not in allowlist)`);
|
|
200
|
+
}
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const ctx = buildSyntheticContext(syntheticEvent);
|
|
205
|
+
log(`feishu[${accountId}]: vc meeting invited, dispatching synthetic inbound` +
|
|
206
|
+
` sender=${syntheticEvent.senderId} meeting_no=${syntheticEvent.meetingNo}`);
|
|
207
|
+
try {
|
|
208
|
+
await (0, dispatch_1.dispatchToAgent)({
|
|
209
|
+
ctx,
|
|
210
|
+
permissionError: undefined,
|
|
211
|
+
mediaPayload: {},
|
|
212
|
+
extraInboundFields: {
|
|
213
|
+
SyntheticEventType: syntheticEvent.eventType,
|
|
214
|
+
VcMeetingId: syntheticEvent.meetingId,
|
|
215
|
+
VcMeetingNo: syntheticEvent.meetingNo,
|
|
216
|
+
VcMeetingTopic: syntheticEvent.topic,
|
|
217
|
+
VcInviterOpenId: syntheticEvent.senderOpenId,
|
|
218
|
+
VcInviteTime: syntheticEvent.inviteTime,
|
|
219
|
+
VcCallId: syntheticEvent.callId,
|
|
220
|
+
},
|
|
221
|
+
quotedContent: undefined,
|
|
222
|
+
account,
|
|
223
|
+
accountScopedCfg,
|
|
224
|
+
runtime,
|
|
225
|
+
chatHistories,
|
|
226
|
+
historyLimit: 0,
|
|
227
|
+
// VC events do not originate from a real IM message.
|
|
228
|
+
replyToMessageId: undefined,
|
|
229
|
+
commandAuthorized: false,
|
|
230
|
+
skipTyping: true,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
error(`feishu[${accountId}]: error dispatching vc invited synthetic inbound: ${String(err)}`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* Shared sender-identity resolution for the VC meeting-invited event.
|
|
6
|
+
*
|
|
7
|
+
* Both the raw event handler (for diagnostics / dedup / ownership check)
|
|
8
|
+
* and the synthetic inbound builder (for dispatchToAgent) need a single,
|
|
9
|
+
* deterministic fallback chain. Keeping a dedicated module avoids drift
|
|
10
|
+
* between the two code paths when the event schema changes again.
|
|
11
|
+
*/
|
|
12
|
+
import type { FeishuVcMeetingInvitedEvent } from '../types';
|
|
13
|
+
/** Which bucket the final senderId was picked from. */
|
|
14
|
+
export type VcSenderFallback = 'inviter' | 'none';
|
|
15
|
+
export interface ResolvedVcSender {
|
|
16
|
+
/**
|
|
17
|
+
* Final sender id used for logging / extraInboundFields. Sender is defined
|
|
18
|
+
* as the real inviter only; if inviter identity is missing, the event
|
|
19
|
+
* should be skipped instead of degrading to bot/config ids.
|
|
20
|
+
*/
|
|
21
|
+
senderId: string;
|
|
22
|
+
/** Raw inviter-level open_id (if present); useful for agent "at inviter" use-cases. */
|
|
23
|
+
senderOpenId?: string;
|
|
24
|
+
/** Raw inviter-level user_id (if present). */
|
|
25
|
+
senderUserId?: string;
|
|
26
|
+
/** Raw inviter-level union_id (if present). */
|
|
27
|
+
senderUnionId?: string;
|
|
28
|
+
/** Human-readable name from inviter.user_name. */
|
|
29
|
+
senderName?: string;
|
|
30
|
+
/** Which bucket the senderId fell back to. */
|
|
31
|
+
fromFallback: VcSenderFallback;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolve the effective sender identity for a `vc.bot.meeting_invited_v1`
|
|
35
|
+
* event. See {@link ResolvedVcSender} for the field contract.
|
|
36
|
+
*
|
|
37
|
+
* Sender resolution order (first non-empty wins):
|
|
38
|
+
* 1. inviter.id.open_id → user_id → union_id
|
|
39
|
+
* 2. empty string + fromFallback='none'
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveVcSender(event: FeishuVcMeetingInvitedEvent): ResolvedVcSender;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* Shared sender-identity resolution for the VC meeting-invited event.
|
|
7
|
+
*
|
|
8
|
+
* Both the raw event handler (for diagnostics / dedup / ownership check)
|
|
9
|
+
* and the synthetic inbound builder (for dispatchToAgent) need a single,
|
|
10
|
+
* deterministic fallback chain. Keeping a dedicated module avoids drift
|
|
11
|
+
* between the two code paths when the event schema changes again.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.resolveVcSender = resolveVcSender;
|
|
15
|
+
/**
|
|
16
|
+
* Trim a possibly-null identifier and treat the empty string as missing.
|
|
17
|
+
*
|
|
18
|
+
* The event schema marks open_id / user_id / union_id as nullable and we
|
|
19
|
+
* have observed tenants returning empty strings in practice, so `||`/`??`
|
|
20
|
+
* alone are not enough.
|
|
21
|
+
*/
|
|
22
|
+
function pickId(value) {
|
|
23
|
+
const trimmed = value?.trim();
|
|
24
|
+
return trimmed && trimmed.length > 0 ? trimmed : undefined;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolve the effective sender identity for a `vc.bot.meeting_invited_v1`
|
|
28
|
+
* event. See {@link ResolvedVcSender} for the field contract.
|
|
29
|
+
*
|
|
30
|
+
* Sender resolution order (first non-empty wins):
|
|
31
|
+
* 1. inviter.id.open_id → user_id → union_id
|
|
32
|
+
* 2. empty string + fromFallback='none'
|
|
33
|
+
*/
|
|
34
|
+
function resolveVcSender(event) {
|
|
35
|
+
const inviterId = event.inviter?.id;
|
|
36
|
+
const inviterOpenId = pickId(inviterId?.open_id);
|
|
37
|
+
const inviterUserId = pickId(inviterId?.user_id);
|
|
38
|
+
const inviterUnionId = pickId(inviterId?.union_id);
|
|
39
|
+
let senderId = '';
|
|
40
|
+
let fromFallback = 'none';
|
|
41
|
+
if (inviterOpenId ?? inviterUserId ?? inviterUnionId) {
|
|
42
|
+
senderId = inviterOpenId ?? inviterUserId ?? inviterUnionId ?? '';
|
|
43
|
+
fromFallback = 'inviter';
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
senderId,
|
|
47
|
+
senderOpenId: inviterOpenId,
|
|
48
|
+
senderUserId: inviterUserId,
|
|
49
|
+
senderUnionId: inviterUnionId,
|
|
50
|
+
senderName: pickId(event.inviter?.user_name) ?? undefined,
|
|
51
|
+
fromFallback,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* ChannelMessageActionAdapter for the Lark/Feishu channel plugin.
|
|
6
|
+
*
|
|
7
|
+
* Implements the standard message-action interface so the framework's
|
|
8
|
+
* built-in `message` tool can route send, react, delete and other
|
|
9
|
+
* actions to Feishu.
|
|
10
|
+
*
|
|
11
|
+
* The `send` action is the unified entry-point for text, card, media,
|
|
12
|
+
* reply and attachment delivery — matching the Telegram/Discord pattern
|
|
13
|
+
* where a single action handles all outbound message types.
|
|
14
|
+
*/
|
|
15
|
+
import type { ChannelMessageActionAdapter } from 'openclaw/plugin-sdk';
|
|
16
|
+
export declare const feishuMessageActions: ChannelMessageActionAdapter;
|