@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,329 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* ChannelMessageActionAdapter for the Lark/Feishu channel plugin.
|
|
7
|
+
*
|
|
8
|
+
* Implements the standard message-action interface so the framework's
|
|
9
|
+
* built-in `message` tool can route send, react, delete and other
|
|
10
|
+
* actions to Feishu.
|
|
11
|
+
*
|
|
12
|
+
* The `send` action is the unified entry-point for text, card, media,
|
|
13
|
+
* reply and attachment delivery — matching the Telegram/Discord pattern
|
|
14
|
+
* where a single action handles all outbound message types.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.feishuMessageActions = void 0;
|
|
18
|
+
const tool_send_1 = require("openclaw/plugin-sdk/tool-send");
|
|
19
|
+
const param_readers_1 = require("openclaw/plugin-sdk/param-readers");
|
|
20
|
+
const typebox_1 = require("@sinclair/typebox");
|
|
21
|
+
const sdk_compat_1 = require("../../core/sdk-compat.js");
|
|
22
|
+
const lark_client_1 = require("../../core/lark-client.js");
|
|
23
|
+
const accounts_1 = require("../../core/accounts.js");
|
|
24
|
+
const lark_logger_1 = require("../../core/lark-logger.js");
|
|
25
|
+
const reactions_1 = require("./reactions.js");
|
|
26
|
+
const deliver_1 = require("./deliver.js");
|
|
27
|
+
const media_1 = require("./media.js");
|
|
28
|
+
const log = (0, lark_logger_1.larkLogger)('outbound/actions');
|
|
29
|
+
const FEISHU_SEND_TEXT_DESCRIPTION = 'Text to send as a separate Feishu message. During a normal Feishu streaming-card reply, do not call send just to repeat or finalize the same answer; return the final answer normally so the active card can be completed by the reply dispatcher. Use send only when the user explicitly needs an additional separate message.';
|
|
30
|
+
const FEISHU_MESSAGE_TOOL_SCHEMA = {
|
|
31
|
+
properties: {
|
|
32
|
+
message: typebox_1.Type.Optional(typebox_1.Type.String({ description: FEISHU_SEND_TEXT_DESCRIPTION })),
|
|
33
|
+
text: typebox_1.Type.Optional(typebox_1.Type.String({ description: FEISHU_SEND_TEXT_DESCRIPTION })),
|
|
34
|
+
},
|
|
35
|
+
visibility: 'current-channel',
|
|
36
|
+
};
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Helpers
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
/** Assert that a Lark SDK response has code === 0 (or no code field). */
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
function assertLarkOk(res, context) {
|
|
43
|
+
const code = res?.code;
|
|
44
|
+
if (code !== undefined && code !== 0) {
|
|
45
|
+
const msg = res?.msg ?? 'unknown error';
|
|
46
|
+
throw new Error(`[feishu-actions] ${context}: code=${code}, msg=${msg}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Supported actions
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
const SUPPORTED_ACTIONS = new Set([
|
|
53
|
+
'send',
|
|
54
|
+
'react',
|
|
55
|
+
'reactions',
|
|
56
|
+
'delete',
|
|
57
|
+
'unsend',
|
|
58
|
+
// "member-info",
|
|
59
|
+
]);
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
// Send param extraction
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
/** Try to resolve a card param to a plain object. Accepts objects directly or JSON strings. */
|
|
64
|
+
function parseCardParam(raw) {
|
|
65
|
+
if (raw == null)
|
|
66
|
+
return undefined;
|
|
67
|
+
// Already a non-array object — use directly (empty {} is never a valid card).
|
|
68
|
+
if (typeof raw === 'object' && !Array.isArray(raw)) {
|
|
69
|
+
const obj = raw;
|
|
70
|
+
if (Object.keys(obj).length === 0)
|
|
71
|
+
return undefined;
|
|
72
|
+
return obj;
|
|
73
|
+
}
|
|
74
|
+
// String — attempt JSON.parse.
|
|
75
|
+
if (typeof raw === 'string') {
|
|
76
|
+
const trimmed = raw.trim();
|
|
77
|
+
if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) {
|
|
78
|
+
log.warn('params.card is a string but not a JSON object, ignoring');
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
const parsed = JSON.parse(trimmed);
|
|
83
|
+
if (typeof parsed === 'object' && parsed != null && !Array.isArray(parsed)) {
|
|
84
|
+
log.info('params.card was a JSON string, parsed successfully');
|
|
85
|
+
return parsed;
|
|
86
|
+
}
|
|
87
|
+
log.warn('params.card JSON parsed but is not a plain object, ignoring');
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
log.warn('params.card is a string but failed to JSON.parse, ignoring');
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Other types (number, boolean, etc.) — ignore with warning.
|
|
96
|
+
log.warn(`params.card has unexpected type "${typeof raw}", ignoring`);
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Extract and normalise all send-related parameters from the raw action params.
|
|
101
|
+
* When `toolContext` is provided, thread context is inherited so that replies
|
|
102
|
+
* are routed to the correct thread.
|
|
103
|
+
*/
|
|
104
|
+
function readFeishuSendParams(params, toolContext) {
|
|
105
|
+
const to = (0, param_readers_1.readStringParam)(params, 'to') ?? '';
|
|
106
|
+
const text = (0, param_readers_1.readStringParam)(params, 'message', { allowEmpty: true }) ??
|
|
107
|
+
(0, param_readers_1.readStringParam)(params, 'text', { allowEmpty: true }) ??
|
|
108
|
+
'';
|
|
109
|
+
const mediaUrl = (0, param_readers_1.readStringParam)(params, 'media') ??
|
|
110
|
+
(0, param_readers_1.readStringParam)(params, 'path') ??
|
|
111
|
+
(0, param_readers_1.readStringParam)(params, 'filePath') ??
|
|
112
|
+
(0, param_readers_1.readStringParam)(params, 'url');
|
|
113
|
+
const fileName = (0, param_readers_1.readStringParam)(params, 'fileName') ?? (0, param_readers_1.readStringParam)(params, 'name');
|
|
114
|
+
// Thread routing: when targeting the current chat (or unspecified),
|
|
115
|
+
// inherit thread context from SDK toolContext.
|
|
116
|
+
const sameChat = !to || to === toolContext?.currentChannelId;
|
|
117
|
+
const replyInThread = sameChat && Boolean(toolContext?.currentThreadTs);
|
|
118
|
+
const replyToMessageId = (0, param_readers_1.readStringParam)(params, 'replyTo') ??
|
|
119
|
+
(replyInThread && toolContext?.currentMessageId ? String(toolContext.currentMessageId) : undefined);
|
|
120
|
+
const card = parseCardParam(params.card);
|
|
121
|
+
return {
|
|
122
|
+
to,
|
|
123
|
+
text,
|
|
124
|
+
mediaUrl: mediaUrl ?? undefined,
|
|
125
|
+
fileName: fileName ?? undefined,
|
|
126
|
+
replyToMessageId: replyToMessageId ?? undefined,
|
|
127
|
+
replyInThread,
|
|
128
|
+
card,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
// Adapter
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
exports.feishuMessageActions = {
|
|
135
|
+
describeMessageTool: ({ cfg }) => {
|
|
136
|
+
const accounts = (0, accounts_1.getEnabledLarkAccounts)(cfg);
|
|
137
|
+
if (accounts.length === 0) {
|
|
138
|
+
return { actions: [], capabilities: [], schema: null };
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
actions: Array.from(SUPPORTED_ACTIONS),
|
|
142
|
+
capabilities: ['cards'],
|
|
143
|
+
schema: FEISHU_MESSAGE_TOOL_SCHEMA,
|
|
144
|
+
};
|
|
145
|
+
},
|
|
146
|
+
supportsAction: ({ action }) => SUPPORTED_ACTIONS.has(action),
|
|
147
|
+
extractToolSend: ({ args }) => (0, tool_send_1.extractToolSend)(args, 'sendMessage'),
|
|
148
|
+
handleAction: async (ctx) => {
|
|
149
|
+
const { action, params, cfg, accountId, toolContext } = ctx;
|
|
150
|
+
const aid = accountId ?? undefined;
|
|
151
|
+
log.info(`handleAction: action=${action}, accountId=${aid ?? 'default'}`);
|
|
152
|
+
try {
|
|
153
|
+
switch (action) {
|
|
154
|
+
case 'send':
|
|
155
|
+
return await deliverMessage(cfg, readFeishuSendParams(params, toolContext), aid, ctx.mediaLocalRoots);
|
|
156
|
+
case 'react':
|
|
157
|
+
return await handleReact(cfg, params, aid);
|
|
158
|
+
case 'reactions':
|
|
159
|
+
return await handleReactions(cfg, params, aid);
|
|
160
|
+
case 'delete':
|
|
161
|
+
case 'unsend':
|
|
162
|
+
return await handleDelete(cfg, params, aid);
|
|
163
|
+
default:
|
|
164
|
+
throw new Error(`Action "${action}" is not supported for Feishu. ` +
|
|
165
|
+
`Supported actions: ${Array.from(SUPPORTED_ACTIONS).join(', ')}.`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
170
|
+
log.error(`handleAction failed: action=${action}, error=${errMsg}`);
|
|
171
|
+
throw err;
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
// Unified message delivery
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
/**
|
|
179
|
+
* Unified message delivery — handles text, card, and media payloads with
|
|
180
|
+
* optional reply-to and thread routing.
|
|
181
|
+
*
|
|
182
|
+
* Supports `fileName` for named file uploads via `uploadAndSendMediaLark`.
|
|
183
|
+
* On media upload failure, falls back to sending the URL as a text link.
|
|
184
|
+
*/
|
|
185
|
+
async function deliverMessage(cfg, sp, accountId, mediaLocalRoots) {
|
|
186
|
+
const { to, text, mediaUrl, fileName, replyToMessageId, replyInThread, card } = sp;
|
|
187
|
+
const payloadType = card ? 'card' : mediaUrl ? 'media' : 'text';
|
|
188
|
+
const target = to || replyToMessageId || 'unknown';
|
|
189
|
+
log.info(`deliverMessage: type=${payloadType}, target=${target}, ` +
|
|
190
|
+
`isReply=${Boolean(replyToMessageId)}, replyInThread=${replyInThread}, ` +
|
|
191
|
+
`textLen=${text.trim().length}, hasMedia=${Boolean(mediaUrl)}, ` +
|
|
192
|
+
`fileName=${fileName ?? '(none)'}`);
|
|
193
|
+
if (!text.trim() && !card && !mediaUrl) {
|
|
194
|
+
log.warn('deliverMessage: no payload, rejecting');
|
|
195
|
+
throw new Error('send requires at least one of: message, card, or media.');
|
|
196
|
+
}
|
|
197
|
+
const sendCtx = { cfg, to, replyToMessageId, replyInThread, accountId };
|
|
198
|
+
// Send text first if both text and card/media are present.
|
|
199
|
+
if (text.trim() && (card || mediaUrl)) {
|
|
200
|
+
log.info(`deliverMessage: sending preceding text ` + `(${text.length} chars) before ${payloadType}`);
|
|
201
|
+
await (0, deliver_1.sendTextLark)({ ...sendCtx, text });
|
|
202
|
+
}
|
|
203
|
+
// Card path.
|
|
204
|
+
if (card) {
|
|
205
|
+
const result = await (0, deliver_1.sendCardLark)({ ...sendCtx, card });
|
|
206
|
+
log.info(`deliverMessage: card sent, messageId=${result.messageId}`);
|
|
207
|
+
return (0, sdk_compat_1.jsonResult)({ ok: true, messageId: result.messageId, chatId: result.chatId });
|
|
208
|
+
}
|
|
209
|
+
// Media path — uses uploadAndSendMediaLark directly to support fileName.
|
|
210
|
+
if (mediaUrl) {
|
|
211
|
+
return await deliverMedia(cfg, sp, accountId, mediaLocalRoots);
|
|
212
|
+
}
|
|
213
|
+
// Text-only path.
|
|
214
|
+
const result = await (0, deliver_1.sendTextLark)({ ...sendCtx, text });
|
|
215
|
+
log.info(`deliverMessage: text sent, messageId=${result.messageId}`);
|
|
216
|
+
return (0, sdk_compat_1.jsonResult)({ ok: true, messageId: result.messageId, chatId: result.chatId });
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Upload and send a media file with text-link fallback on failure.
|
|
220
|
+
*/
|
|
221
|
+
async function deliverMedia(cfg, sp, accountId, mediaLocalRoots) {
|
|
222
|
+
const { to, mediaUrl, fileName, replyToMessageId, replyInThread } = sp;
|
|
223
|
+
log.info(`deliverMedia: url=${mediaUrl}, fileName=${fileName ?? '(auto)'}`);
|
|
224
|
+
try {
|
|
225
|
+
const result = await (0, media_1.uploadAndSendMediaLark)({
|
|
226
|
+
cfg,
|
|
227
|
+
to,
|
|
228
|
+
mediaUrl,
|
|
229
|
+
fileName,
|
|
230
|
+
replyToMessageId,
|
|
231
|
+
replyInThread,
|
|
232
|
+
accountId,
|
|
233
|
+
mediaLocalRoots,
|
|
234
|
+
});
|
|
235
|
+
log.info(`deliverMedia: sent, messageId=${result.messageId}`);
|
|
236
|
+
return (0, sdk_compat_1.jsonResult)({ ok: true, messageId: result.messageId, chatId: result.chatId });
|
|
237
|
+
}
|
|
238
|
+
catch (err) {
|
|
239
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
240
|
+
log.error(`deliverMedia: upload failed for "${mediaUrl}": ${errMsg}`);
|
|
241
|
+
// Fallback: send the URL with error reason as a quote above.
|
|
242
|
+
log.info('deliverMedia: falling back to text link');
|
|
243
|
+
const fallback = await (0, deliver_1.sendTextLark)({
|
|
244
|
+
cfg,
|
|
245
|
+
to,
|
|
246
|
+
text: `> ${mediaUrl}`,
|
|
247
|
+
replyToMessageId,
|
|
248
|
+
replyInThread,
|
|
249
|
+
accountId,
|
|
250
|
+
});
|
|
251
|
+
return (0, sdk_compat_1.jsonResult)({
|
|
252
|
+
ok: true,
|
|
253
|
+
messageId: fallback.messageId,
|
|
254
|
+
chatId: fallback.chatId,
|
|
255
|
+
warning: `Media upload failed (${errMsg}). A text link was sent instead.`,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// ---------------------------------------------------------------------------
|
|
260
|
+
// Reaction handlers
|
|
261
|
+
// ---------------------------------------------------------------------------
|
|
262
|
+
async function handleReact(cfg, params, accountId) {
|
|
263
|
+
const messageId = (0, param_readers_1.readStringParam)(params, 'messageId', { required: true });
|
|
264
|
+
const { emoji, remove, isEmpty } = (0, sdk_compat_1.readReactionParams)(params, {
|
|
265
|
+
removeErrorMessage: 'Emoji is required to remove a Feishu reaction.',
|
|
266
|
+
});
|
|
267
|
+
if (remove || isEmpty) {
|
|
268
|
+
log.info(`react: removing emoji=${emoji || 'all'} from messageId=${messageId}`);
|
|
269
|
+
const reactions = await (0, reactions_1.listReactionsFeishu)({
|
|
270
|
+
cfg,
|
|
271
|
+
messageId,
|
|
272
|
+
emojiType: emoji || undefined,
|
|
273
|
+
accountId,
|
|
274
|
+
});
|
|
275
|
+
const botReactions = reactions.filter((r) => r.operatorType === 'app');
|
|
276
|
+
for (const r of botReactions) {
|
|
277
|
+
await (0, reactions_1.removeReactionFeishu)({
|
|
278
|
+
cfg,
|
|
279
|
+
messageId,
|
|
280
|
+
reactionId: r.reactionId,
|
|
281
|
+
accountId,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
log.info(`react: removed ${botReactions.length} bot reaction(s)`);
|
|
285
|
+
return (0, sdk_compat_1.jsonResult)({ ok: true, removed: botReactions.length });
|
|
286
|
+
}
|
|
287
|
+
log.info(`react: adding emoji=${emoji} to messageId=${messageId}`);
|
|
288
|
+
const { reactionId } = await (0, reactions_1.addReactionFeishu)({
|
|
289
|
+
cfg,
|
|
290
|
+
messageId,
|
|
291
|
+
emojiType: emoji,
|
|
292
|
+
accountId,
|
|
293
|
+
});
|
|
294
|
+
log.info(`react: added reactionId=${reactionId}`);
|
|
295
|
+
return (0, sdk_compat_1.jsonResult)({ ok: true, reactionId });
|
|
296
|
+
}
|
|
297
|
+
async function handleReactions(cfg, params, accountId) {
|
|
298
|
+
const messageId = (0, param_readers_1.readStringParam)(params, 'messageId', { required: true });
|
|
299
|
+
const emojiType = (0, param_readers_1.readStringParam)(params, 'emoji');
|
|
300
|
+
const reactions = await (0, reactions_1.listReactionsFeishu)({
|
|
301
|
+
cfg,
|
|
302
|
+
messageId,
|
|
303
|
+
emojiType: emojiType || undefined,
|
|
304
|
+
accountId,
|
|
305
|
+
});
|
|
306
|
+
return (0, sdk_compat_1.jsonResult)({
|
|
307
|
+
ok: true,
|
|
308
|
+
reactions: reactions.map((r) => ({
|
|
309
|
+
reactionId: r.reactionId,
|
|
310
|
+
emoji: r.emojiType,
|
|
311
|
+
operatorType: r.operatorType,
|
|
312
|
+
operatorId: r.operatorId,
|
|
313
|
+
})),
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
// ---------------------------------------------------------------------------
|
|
317
|
+
// Delete
|
|
318
|
+
// ---------------------------------------------------------------------------
|
|
319
|
+
async function handleDelete(cfg, params, accountId) {
|
|
320
|
+
const messageId = (0, param_readers_1.readStringParam)(params, 'messageId', { required: true });
|
|
321
|
+
log.info(`delete: messageId=${messageId}`);
|
|
322
|
+
const client = lark_client_1.LarkClient.fromCfg(cfg, accountId).sdk;
|
|
323
|
+
const res = await client.im.message.delete({
|
|
324
|
+
path: { message_id: messageId },
|
|
325
|
+
});
|
|
326
|
+
assertLarkOk(res, `delete message ${messageId}`);
|
|
327
|
+
log.info(`delete: done, messageId=${messageId}`);
|
|
328
|
+
return (0, sdk_compat_1.jsonResult)({ ok: true, messageId, deleted: true });
|
|
329
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* AsyncLocalStorage-backed channel for telling the outbound adapter that
|
|
6
|
+
* the current dispatch is replying to a bot peer in a group chat.
|
|
7
|
+
*
|
|
8
|
+
* Why ALS instead of an extra adapter parameter: the outbound adapter is
|
|
9
|
+
* channel-agnostic (Slack / Telegram / Feishu share the same shape) and
|
|
10
|
+
* the SDK owns the call site between dispatch and our outbound. Adding a
|
|
11
|
+
* Feishu-specific "peer-is-bot" parameter would pollute that interface.
|
|
12
|
+
* ALS lets the dispatch layer attach context once and have it flow through
|
|
13
|
+
* the SDK's async chain to the outbound adapter without any other layer
|
|
14
|
+
* needing to know.
|
|
15
|
+
*
|
|
16
|
+
* Lifetime: scoped to a single `runWithBotPeerContext(...)` call. When that
|
|
17
|
+
* promise settles, the store is gone. No manual cleanup required.
|
|
18
|
+
*/
|
|
19
|
+
export interface BotPeerContext {
|
|
20
|
+
/** The peer bot's open_id — what `ensureMention` will inject. */
|
|
21
|
+
peerOpenId: string;
|
|
22
|
+
/** Display name for the rendered `<at>` element. */
|
|
23
|
+
peerName: string;
|
|
24
|
+
/**
|
|
25
|
+
* Mutable de-dup flag: set once the peer @ has appeared on an outbound
|
|
26
|
+
* chunk (model-written or injected) so multi-chunk replies don't prepend
|
|
27
|
+
* the @ to every chunk. Scoped to the single dispatch via the store.
|
|
28
|
+
*/
|
|
29
|
+
mentioned?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Run `fn` with the given bot-peer context attached to the async chain.
|
|
33
|
+
* The outbound adapter's `currentBotPeerContext()` inside `fn` (and any
|
|
34
|
+
* promises it spawns) will see this store.
|
|
35
|
+
*/
|
|
36
|
+
export declare function runWithBotPeerContext<T>(ctx: BotPeerContext, fn: () => Promise<T>): Promise<T>;
|
|
37
|
+
/**
|
|
38
|
+
* Read the active bot-peer context, or `undefined` if none is set.
|
|
39
|
+
* Outbound code uses this to decide whether to wrap the reply text with
|
|
40
|
+
* `ensureMention` so the peer bot actually receives a Feishu notification.
|
|
41
|
+
*/
|
|
42
|
+
export declare function currentBotPeerContext(): BotPeerContext | undefined;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* AsyncLocalStorage-backed channel for telling the outbound adapter that
|
|
7
|
+
* the current dispatch is replying to a bot peer in a group chat.
|
|
8
|
+
*
|
|
9
|
+
* Why ALS instead of an extra adapter parameter: the outbound adapter is
|
|
10
|
+
* channel-agnostic (Slack / Telegram / Feishu share the same shape) and
|
|
11
|
+
* the SDK owns the call site between dispatch and our outbound. Adding a
|
|
12
|
+
* Feishu-specific "peer-is-bot" parameter would pollute that interface.
|
|
13
|
+
* ALS lets the dispatch layer attach context once and have it flow through
|
|
14
|
+
* the SDK's async chain to the outbound adapter without any other layer
|
|
15
|
+
* needing to know.
|
|
16
|
+
*
|
|
17
|
+
* Lifetime: scoped to a single `runWithBotPeerContext(...)` call. When that
|
|
18
|
+
* promise settles, the store is gone. No manual cleanup required.
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.runWithBotPeerContext = runWithBotPeerContext;
|
|
22
|
+
exports.currentBotPeerContext = currentBotPeerContext;
|
|
23
|
+
const node_async_hooks_1 = require("node:async_hooks");
|
|
24
|
+
const storage = new node_async_hooks_1.AsyncLocalStorage();
|
|
25
|
+
/**
|
|
26
|
+
* Run `fn` with the given bot-peer context attached to the async chain.
|
|
27
|
+
* The outbound adapter's `currentBotPeerContext()` inside `fn` (and any
|
|
28
|
+
* promises it spawns) will see this store.
|
|
29
|
+
*/
|
|
30
|
+
function runWithBotPeerContext(ctx, fn) {
|
|
31
|
+
return storage.run(ctx, fn);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Read the active bot-peer context, or `undefined` if none is set.
|
|
35
|
+
* Outbound code uses this to decide whether to wrap the reply text with
|
|
36
|
+
* `ensureMention` so the peer bot actually receives a Feishu notification.
|
|
37
|
+
*/
|
|
38
|
+
function currentBotPeerContext() {
|
|
39
|
+
return storage.getStore();
|
|
40
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* Chat management for the Lark/Feishu channel plugin.
|
|
6
|
+
*
|
|
7
|
+
* Provides functions to update chat settings (name, avatar), manage
|
|
8
|
+
* members (add, remove, list) using the IM Chat API.
|
|
9
|
+
*/
|
|
10
|
+
import type { OpenClawConfig } from 'openclaw/plugin-sdk';
|
|
11
|
+
export interface FeishuChatMember {
|
|
12
|
+
/** Member ID (open_id by default). */
|
|
13
|
+
memberId: string;
|
|
14
|
+
/** Display name of the member. */
|
|
15
|
+
name: string;
|
|
16
|
+
/** ID type: "open_id", "union_id", or "user_id". */
|
|
17
|
+
memberIdType: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Update chat settings such as name or avatar.
|
|
21
|
+
*/
|
|
22
|
+
export declare function updateChatFeishu(params: {
|
|
23
|
+
cfg: OpenClawConfig;
|
|
24
|
+
chatId: string;
|
|
25
|
+
name?: string;
|
|
26
|
+
avatar?: string;
|
|
27
|
+
accountId?: string;
|
|
28
|
+
}): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Add members to a chat by their open_id list.
|
|
31
|
+
*/
|
|
32
|
+
export declare function addChatMembersFeishu(params: {
|
|
33
|
+
cfg: OpenClawConfig;
|
|
34
|
+
chatId: string;
|
|
35
|
+
memberIds: string[];
|
|
36
|
+
accountId?: string;
|
|
37
|
+
}): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Remove members from a chat by their open_id list.
|
|
40
|
+
*/
|
|
41
|
+
export declare function removeChatMembersFeishu(params: {
|
|
42
|
+
cfg: OpenClawConfig;
|
|
43
|
+
chatId: string;
|
|
44
|
+
memberIds: string[];
|
|
45
|
+
accountId?: string;
|
|
46
|
+
}): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* List members of a chat.
|
|
49
|
+
*
|
|
50
|
+
* Returns a single page (up to 100 members) to avoid unnecessary data
|
|
51
|
+
* overhead for large groups. Use the returned `pageToken` to fetch
|
|
52
|
+
* subsequent pages when needed.
|
|
53
|
+
*/
|
|
54
|
+
export declare function listChatMembersFeishu(params: {
|
|
55
|
+
cfg: OpenClawConfig;
|
|
56
|
+
chatId: string;
|
|
57
|
+
accountId?: string;
|
|
58
|
+
/** Optional page token for pagination. */
|
|
59
|
+
pageToken?: string;
|
|
60
|
+
}): Promise<{
|
|
61
|
+
members: FeishuChatMember[];
|
|
62
|
+
pageToken?: string;
|
|
63
|
+
hasMore: boolean;
|
|
64
|
+
}>;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* Chat management for the Lark/Feishu channel plugin.
|
|
7
|
+
*
|
|
8
|
+
* Provides functions to update chat settings (name, avatar), manage
|
|
9
|
+
* members (add, remove, list) using the IM Chat API.
|
|
10
|
+
*/
|
|
11
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.updateChatFeishu = updateChatFeishu;
|
|
14
|
+
exports.addChatMembersFeishu = addChatMembersFeishu;
|
|
15
|
+
exports.removeChatMembersFeishu = removeChatMembersFeishu;
|
|
16
|
+
exports.listChatMembersFeishu = listChatMembersFeishu;
|
|
17
|
+
const lark_client_1 = require("../../core/lark-client.js");
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Helpers
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
/** Assert that a Lark SDK response has code === 0 (or no code field). */
|
|
22
|
+
function assertLarkOk(res, context) {
|
|
23
|
+
const code = res?.code;
|
|
24
|
+
if (code !== undefined && code !== 0) {
|
|
25
|
+
const msg = res?.msg ?? 'unknown error';
|
|
26
|
+
throw new Error(`[feishu-chat-manage] ${context}: code=${code}, msg=${msg}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// updateChatFeishu
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
/**
|
|
33
|
+
* Update chat settings such as name or avatar.
|
|
34
|
+
*/
|
|
35
|
+
async function updateChatFeishu(params) {
|
|
36
|
+
const { cfg, chatId, name, avatar, accountId } = params;
|
|
37
|
+
const client = lark_client_1.LarkClient.fromCfg(cfg, accountId).sdk;
|
|
38
|
+
const body = {};
|
|
39
|
+
if (name)
|
|
40
|
+
body.name = name;
|
|
41
|
+
if (avatar)
|
|
42
|
+
body.avatar = avatar;
|
|
43
|
+
const res = await client.im.chat.update({
|
|
44
|
+
path: { chat_id: chatId },
|
|
45
|
+
data: body,
|
|
46
|
+
});
|
|
47
|
+
assertLarkOk(res, `updateChat for ${chatId}`);
|
|
48
|
+
}
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// addChatMembersFeishu
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
/**
|
|
53
|
+
* Add members to a chat by their open_id list.
|
|
54
|
+
*/
|
|
55
|
+
async function addChatMembersFeishu(params) {
|
|
56
|
+
const { cfg, chatId, memberIds, accountId } = params;
|
|
57
|
+
const client = lark_client_1.LarkClient.fromCfg(cfg, accountId).sdk;
|
|
58
|
+
const res = await client.im.v1.chatMembers.create({
|
|
59
|
+
path: { chat_id: chatId },
|
|
60
|
+
data: { id_list: memberIds },
|
|
61
|
+
params: { member_id_type: 'open_id' },
|
|
62
|
+
});
|
|
63
|
+
assertLarkOk(res, `addChatMembers for ${chatId}`);
|
|
64
|
+
}
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// removeChatMembersFeishu
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
/**
|
|
69
|
+
* Remove members from a chat by their open_id list.
|
|
70
|
+
*/
|
|
71
|
+
async function removeChatMembersFeishu(params) {
|
|
72
|
+
const { cfg, chatId, memberIds, accountId } = params;
|
|
73
|
+
const client = lark_client_1.LarkClient.fromCfg(cfg, accountId).sdk;
|
|
74
|
+
const res = await client.im.v1.chatMembers.delete({
|
|
75
|
+
path: { chat_id: chatId },
|
|
76
|
+
data: { id_list: memberIds },
|
|
77
|
+
params: { member_id_type: 'open_id' },
|
|
78
|
+
});
|
|
79
|
+
assertLarkOk(res, `removeChatMembers for ${chatId}`);
|
|
80
|
+
}
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
// listChatMembersFeishu
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
/**
|
|
85
|
+
* List members of a chat.
|
|
86
|
+
*
|
|
87
|
+
* Returns a single page (up to 100 members) to avoid unnecessary data
|
|
88
|
+
* overhead for large groups. Use the returned `pageToken` to fetch
|
|
89
|
+
* subsequent pages when needed.
|
|
90
|
+
*/
|
|
91
|
+
async function listChatMembersFeishu(params) {
|
|
92
|
+
const { cfg, chatId, accountId, pageToken } = params;
|
|
93
|
+
const client = lark_client_1.LarkClient.fromCfg(cfg, accountId).sdk;
|
|
94
|
+
const response = await client.im.v1.chatMembers.get({
|
|
95
|
+
path: { chat_id: chatId },
|
|
96
|
+
params: {
|
|
97
|
+
member_id_type: 'open_id',
|
|
98
|
+
page_size: 100,
|
|
99
|
+
...(pageToken ? { page_token: pageToken } : {}),
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
assertLarkOk(response, `listChatMembers for ${chatId}`);
|
|
103
|
+
const members = [];
|
|
104
|
+
const items = response?.data?.items;
|
|
105
|
+
if (items && Array.isArray(items)) {
|
|
106
|
+
for (const item of items) {
|
|
107
|
+
members.push({
|
|
108
|
+
memberId: item.member_id ?? '',
|
|
109
|
+
name: item.name ?? '',
|
|
110
|
+
memberIdType: item.member_id_type ?? 'open_id',
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const nextPageToken = response?.data?.page_token ?? undefined;
|
|
115
|
+
const hasMore = response?.data?.has_more === true && !!nextPageToken;
|
|
116
|
+
return { members, pageToken: nextPageToken, hasMore };
|
|
117
|
+
}
|