@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,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* Default values and resolution logic for the Feishu card footer configuration.
|
|
7
|
+
*
|
|
8
|
+
* Each boolean flag controls whether a particular metadata item is displayed
|
|
9
|
+
* in the card footer (e.g. elapsed time, model name).
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.DEFAULT_FOOTER_CONFIG = void 0;
|
|
13
|
+
exports.resolveFooterConfig = resolveFooterConfig;
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Defaults
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
/**
|
|
18
|
+
* The default footer configuration.
|
|
19
|
+
*
|
|
20
|
+
* By default all metadata items are hidden — neither status text
|
|
21
|
+
* ("已完成" / "出错" / "已停止") nor elapsed time are shown.
|
|
22
|
+
*/
|
|
23
|
+
exports.DEFAULT_FOOTER_CONFIG = {
|
|
24
|
+
status: false,
|
|
25
|
+
elapsed: false,
|
|
26
|
+
tokens: false,
|
|
27
|
+
cache: false,
|
|
28
|
+
context: false,
|
|
29
|
+
model: false,
|
|
30
|
+
};
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Resolver
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
/**
|
|
35
|
+
* Merge a partial footer configuration with `DEFAULT_FOOTER_CONFIG`.
|
|
36
|
+
*
|
|
37
|
+
* Fields present in the input take precedence; anything absent falls back
|
|
38
|
+
* to the default value.
|
|
39
|
+
*/
|
|
40
|
+
function resolveFooterConfig(cfg) {
|
|
41
|
+
if (!cfg)
|
|
42
|
+
return { ...exports.DEFAULT_FOOTER_CONFIG };
|
|
43
|
+
return {
|
|
44
|
+
status: cfg.status ?? exports.DEFAULT_FOOTER_CONFIG.status,
|
|
45
|
+
elapsed: cfg.elapsed ?? exports.DEFAULT_FOOTER_CONFIG.elapsed,
|
|
46
|
+
tokens: cfg.tokens ?? exports.DEFAULT_FOOTER_CONFIG.tokens,
|
|
47
|
+
cache: cfg.cache ?? exports.DEFAULT_FOOTER_CONFIG.cache,
|
|
48
|
+
context: cfg.context ?? exports.DEFAULT_FOOTER_CONFIG.context,
|
|
49
|
+
model: cfg.model ?? exports.DEFAULT_FOOTER_CONFIG.model,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* Feishu / Lark SDK client management.
|
|
6
|
+
*
|
|
7
|
+
* Provides `LarkClient` — a unified manager for Lark SDK client instances,
|
|
8
|
+
* WebSocket connections, EventDispatcher lifecycle, and bot identity.
|
|
9
|
+
*
|
|
10
|
+
* Consumers obtain instances via factory methods:
|
|
11
|
+
* - `LarkClient.fromCfg(cfg, accountId)` — resolve account from config
|
|
12
|
+
* - `LarkClient.fromAccount(account)` — from a pre-resolved account
|
|
13
|
+
* - `LarkClient.fromCredentials(credentials)` — ephemeral instance (not cached)
|
|
14
|
+
*/
|
|
15
|
+
import * as Lark from '@larksuiteoapi/node-sdk';
|
|
16
|
+
import type { ClawdbotConfig, PluginRuntime } from 'openclaw/plugin-sdk';
|
|
17
|
+
import type { MessageDedup } from '../messaging/inbound/dedup';
|
|
18
|
+
import type { FeishuProbeResult, LarkAccount, LarkBrand } from './types';
|
|
19
|
+
/** Credential set accepted by the ephemeral `fromCredentials` factory. */
|
|
20
|
+
export interface LarkClientCredentials {
|
|
21
|
+
accountId?: string;
|
|
22
|
+
appId?: string;
|
|
23
|
+
appSecret?: string;
|
|
24
|
+
brand?: LarkBrand;
|
|
25
|
+
}
|
|
26
|
+
export declare class LarkClient {
|
|
27
|
+
readonly account: LarkAccount;
|
|
28
|
+
private _sdk;
|
|
29
|
+
private _wsClient;
|
|
30
|
+
private _botOpenId;
|
|
31
|
+
private _botName;
|
|
32
|
+
private _lastProbeResult;
|
|
33
|
+
private _lastProbeAt;
|
|
34
|
+
/** Attached message deduplicator — disposed together with the client. */
|
|
35
|
+
messageDedup: MessageDedup | null;
|
|
36
|
+
/** Persist the runtime instance for later retrieval (activate 阶段调用一次). */
|
|
37
|
+
static setRuntime(runtime: PluginRuntime): void;
|
|
38
|
+
/** Retrieve the stored runtime instance. Throws if not yet initialised. */
|
|
39
|
+
static get runtime(): PluginRuntime;
|
|
40
|
+
private static _globalConfig;
|
|
41
|
+
/** Store the original global config (called during monitor startup). */
|
|
42
|
+
static setGlobalConfig(cfg: ClawdbotConfig): void;
|
|
43
|
+
/** Retrieve the stored global config, or `null` if not yet set. */
|
|
44
|
+
static get globalConfig(): ClawdbotConfig | null;
|
|
45
|
+
private constructor();
|
|
46
|
+
/** Shorthand for `this.account.accountId`. */
|
|
47
|
+
get accountId(): string;
|
|
48
|
+
/** Resolve account from config and return a cached `LarkClient`. */
|
|
49
|
+
static fromCfg(cfg: ClawdbotConfig, accountId?: string): LarkClient;
|
|
50
|
+
/**
|
|
51
|
+
* Get (or create) a cached `LarkClient` for the given account.
|
|
52
|
+
* If the cached instance has stale credentials it is replaced.
|
|
53
|
+
*/
|
|
54
|
+
static fromAccount(account: LarkAccount): LarkClient;
|
|
55
|
+
/**
|
|
56
|
+
* Create an ephemeral `LarkClient` from bare credentials.
|
|
57
|
+
* The instance is **not** added to the global cache — suitable for
|
|
58
|
+
* one-off probe / diagnose calls that should not pollute account state.
|
|
59
|
+
*/
|
|
60
|
+
static fromCredentials(credentials: LarkClientCredentials): LarkClient;
|
|
61
|
+
/** Look up a cached instance by accountId. */
|
|
62
|
+
static get(accountId: string): LarkClient | null;
|
|
63
|
+
/**
|
|
64
|
+
* Dispose one or all cached instances.
|
|
65
|
+
* With `accountId` — dispose that single instance.
|
|
66
|
+
* Without — dispose every cached instance and clear the cache.
|
|
67
|
+
*/
|
|
68
|
+
static clearCache(accountId?: string): Promise<void>;
|
|
69
|
+
/** Lazily-created Lark SDK client. */
|
|
70
|
+
get sdk(): Lark.Client;
|
|
71
|
+
/**
|
|
72
|
+
* Probe bot identity via the `bot/v1/openclaw_bot/ping` API.
|
|
73
|
+
* Results are cached on the instance for subsequent access via
|
|
74
|
+
* `botOpenId` / `botName`.
|
|
75
|
+
*/
|
|
76
|
+
probe(opts?: {
|
|
77
|
+
maxAgeMs?: number;
|
|
78
|
+
needBotInfo?: boolean;
|
|
79
|
+
}): Promise<FeishuProbeResult>;
|
|
80
|
+
/** Cached bot open_id (available after `probe()` or `startWS()`). */
|
|
81
|
+
get botOpenId(): string | undefined;
|
|
82
|
+
/** Cached bot name (available after `probe()` or `startWS()`). */
|
|
83
|
+
get botName(): string | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* Start WebSocket event monitoring.
|
|
86
|
+
*
|
|
87
|
+
* Flow: probe bot identity → EventDispatcher → WSClient → start.
|
|
88
|
+
* The returned Promise resolves when `abortSignal` fires.
|
|
89
|
+
*/
|
|
90
|
+
startWS(opts: {
|
|
91
|
+
handlers: Record<string, (data: unknown) => Promise<void>>;
|
|
92
|
+
abortSignal?: AbortSignal;
|
|
93
|
+
autoProbe?: boolean;
|
|
94
|
+
}): Promise<void>;
|
|
95
|
+
/** Whether a WebSocket client is currently active. */
|
|
96
|
+
get wsConnected(): boolean;
|
|
97
|
+
/** Disconnect WebSocket but keep instance in cache. */
|
|
98
|
+
disconnect(): void;
|
|
99
|
+
/** Disconnect + remove from cache. */
|
|
100
|
+
dispose(): void;
|
|
101
|
+
/** Assert credentials exist or throw. */
|
|
102
|
+
private requireCredentials;
|
|
103
|
+
/**
|
|
104
|
+
* Start the WSClient and return a promise that resolves when the
|
|
105
|
+
* abort signal fires (or immediately if already aborted).
|
|
106
|
+
*/
|
|
107
|
+
private waitForAbort;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Returns the best available config for account resolution.
|
|
111
|
+
*
|
|
112
|
+
* Priority: live config (has `channels.feishu`) > fallback (has
|
|
113
|
+
* `channels.feishu`) > live config (last resort).
|
|
114
|
+
*
|
|
115
|
+
* The `config` object captured in tool-registration closures may be stale
|
|
116
|
+
* after a hot-reload, so we prefer the live config from
|
|
117
|
+
* `LarkClient.runtime.config.loadConfig()`. However, `loadConfig()` may
|
|
118
|
+
* return `{}` when the runtime config snapshot has been cleared (e.g. in
|
|
119
|
+
* isolated cron sessions), so we fall back to the closure-captured config
|
|
120
|
+
* when the live result lacks Feishu credentials.
|
|
121
|
+
*
|
|
122
|
+
* @param fallback - Config to use when the runtime is not yet initialised
|
|
123
|
+
* or when `loadConfig()` returns an incomplete config.
|
|
124
|
+
*/
|
|
125
|
+
export declare function getResolvedConfig(fallback: ClawdbotConfig): ClawdbotConfig;
|
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* Feishu / Lark SDK client management.
|
|
7
|
+
*
|
|
8
|
+
* Provides `LarkClient` — a unified manager for Lark SDK client instances,
|
|
9
|
+
* WebSocket connections, EventDispatcher lifecycle, and bot identity.
|
|
10
|
+
*
|
|
11
|
+
* Consumers obtain instances via factory methods:
|
|
12
|
+
* - `LarkClient.fromCfg(cfg, accountId)` — resolve account from config
|
|
13
|
+
* - `LarkClient.fromAccount(account)` — from a pre-resolved account
|
|
14
|
+
* - `LarkClient.fromCredentials(credentials)` — ephemeral instance (not cached)
|
|
15
|
+
*/
|
|
16
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
17
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
20
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
21
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
22
|
+
}
|
|
23
|
+
Object.defineProperty(o, k2, desc);
|
|
24
|
+
}) : (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
o[k2] = m[k];
|
|
27
|
+
}));
|
|
28
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
+
}) : function(o, v) {
|
|
31
|
+
o["default"] = v;
|
|
32
|
+
});
|
|
33
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
34
|
+
var ownKeys = function(o) {
|
|
35
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
36
|
+
var ar = [];
|
|
37
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
38
|
+
return ar;
|
|
39
|
+
};
|
|
40
|
+
return ownKeys(o);
|
|
41
|
+
};
|
|
42
|
+
return function (mod) {
|
|
43
|
+
if (mod && mod.__esModule) return mod;
|
|
44
|
+
var result = {};
|
|
45
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
46
|
+
__setModuleDefault(result, mod);
|
|
47
|
+
return result;
|
|
48
|
+
};
|
|
49
|
+
})();
|
|
50
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
+
exports.LarkClient = void 0;
|
|
52
|
+
exports.getResolvedConfig = getResolvedConfig;
|
|
53
|
+
const Lark = __importStar(require("@larksuiteoapi/node-sdk"));
|
|
54
|
+
const user_name_cache_store_1 = require("../messaging/inbound/user-name-cache-store.js");
|
|
55
|
+
const accounts_1 = require("./accounts.js");
|
|
56
|
+
const chat_info_cache_1 = require("./chat-info-cache.js");
|
|
57
|
+
const lark_logger_1 = require("./lark-logger.js");
|
|
58
|
+
const runtime_store_1 = require("./runtime-store.js");
|
|
59
|
+
const version_1 = require("./version.js");
|
|
60
|
+
const log = (0, lark_logger_1.larkLogger)('core/lark-client');
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Inject User-Agent into all Feishu SDK requests
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
const GLOBAL_LARK_USER_AGENT_KEY = 'LARK_USER_AGENT';
|
|
65
|
+
function installGlobalUserAgent() {
|
|
66
|
+
// node-sdk's built-in interceptor reads global.LARK_USER_AGENT to override User-Agent
|
|
67
|
+
globalThis[GLOBAL_LARK_USER_AGENT_KEY] = (0, version_1.getUserAgent)();
|
|
68
|
+
}
|
|
69
|
+
installGlobalUserAgent();
|
|
70
|
+
// Disable axios auto-proxy to prevent HTTP_PROXY env vars from corrupting request URLs.
|
|
71
|
+
// Proxy routing is managed centrally by OpenClaw core's global-agent.
|
|
72
|
+
Lark.defaultHttpInstance.defaults.proxy = false;
|
|
73
|
+
Lark.defaultHttpInstance.interceptors.request.handlers = [];
|
|
74
|
+
// Inject User-Agent header into all HTTP requests via interceptor
|
|
75
|
+
Lark.defaultHttpInstance.interceptors.request.use((req) => {
|
|
76
|
+
if (req.headers) {
|
|
77
|
+
req.headers['User-Agent'] = (0, version_1.getUserAgent)();
|
|
78
|
+
}
|
|
79
|
+
return req;
|
|
80
|
+
}, undefined, { synchronous: true });
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
// Brand → SDK domain
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
const BRAND_TO_DOMAIN = {
|
|
85
|
+
feishu: Lark.Domain.Feishu,
|
|
86
|
+
lark: Lark.Domain.Lark,
|
|
87
|
+
};
|
|
88
|
+
/** Map a `LarkBrand` to the SDK `domain` parameter. */
|
|
89
|
+
function resolveBrand(brand) {
|
|
90
|
+
return BRAND_TO_DOMAIN[brand ?? 'feishu'] ?? brand.replace(/\/+$/, '');
|
|
91
|
+
}
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// LarkClient
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
/** Instance cache keyed by accountId. */
|
|
96
|
+
const cache = new Map();
|
|
97
|
+
/**
|
|
98
|
+
* Compare two SecretRef-shaped objects by their identity fields.
|
|
99
|
+
* Key-order independent, unlike JSON.stringify.
|
|
100
|
+
*/
|
|
101
|
+
function secretRefsEqual(a, b) {
|
|
102
|
+
return a.source === b.source && a.provider === b.provider && a.id === b.id;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Compare two credential values that may be strings or SecretRef objects.
|
|
106
|
+
*
|
|
107
|
+
* - Both strings: direct `===`.
|
|
108
|
+
* - Both SecretRef objects: compare `source`, `provider`, `id` explicitly.
|
|
109
|
+
* - Mixed (string vs SecretRef): treat as equal — the platform resolves the
|
|
110
|
+
* SecretRef at startup (producing the cached string) but `loadConfig()`
|
|
111
|
+
* returns the raw object on subsequent calls. Detecting SecretRef identity
|
|
112
|
+
* changes is not useful here because the platform does not re-resolve
|
|
113
|
+
* feishu secrets on reload, so a new SecretRef would be equally unusable.
|
|
114
|
+
*/
|
|
115
|
+
function credentialsEqual(a, b) {
|
|
116
|
+
if (a === b)
|
|
117
|
+
return true;
|
|
118
|
+
if (typeof a === 'string' && typeof b === 'string')
|
|
119
|
+
return false;
|
|
120
|
+
if (a && b && typeof a === 'object' && typeof b === 'object') {
|
|
121
|
+
return secretRefsEqual(a, b);
|
|
122
|
+
}
|
|
123
|
+
// Mixed types: keep the cached instance that holds the working string.
|
|
124
|
+
if ((typeof a === 'string' && b && typeof b === 'object') || (typeof b === 'string' && a && typeof a === 'object')) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
class LarkClient {
|
|
130
|
+
account;
|
|
131
|
+
_sdk = null;
|
|
132
|
+
_wsClient = null;
|
|
133
|
+
_botOpenId;
|
|
134
|
+
_botName;
|
|
135
|
+
_lastProbeResult = null;
|
|
136
|
+
_lastProbeAt = 0;
|
|
137
|
+
/** Attached message deduplicator — disposed together with the client. */
|
|
138
|
+
messageDedup = null;
|
|
139
|
+
// ---- Plugin runtime (singleton) ------------------------------------------
|
|
140
|
+
/** Persist the runtime instance for later retrieval (activate 阶段调用一次). */
|
|
141
|
+
static setRuntime(runtime) {
|
|
142
|
+
(0, runtime_store_1.setLarkRuntime)(runtime);
|
|
143
|
+
}
|
|
144
|
+
/** Retrieve the stored runtime instance. Throws if not yet initialised. */
|
|
145
|
+
static get runtime() {
|
|
146
|
+
return (0, runtime_store_1.getLarkRuntime)();
|
|
147
|
+
}
|
|
148
|
+
// ---- Global config (singleton) -------------------------------------------
|
|
149
|
+
//
|
|
150
|
+
// Plugin commands receive an account-scoped config (channels.feishu replaced
|
|
151
|
+
// with the merged per-account config, `accounts` map stripped). Commands
|
|
152
|
+
// that need cross-account visibility (e.g. doctor, diagnose) read the
|
|
153
|
+
// original global config from here.
|
|
154
|
+
static _globalConfig = null;
|
|
155
|
+
/** Store the original global config (called during monitor startup). */
|
|
156
|
+
static setGlobalConfig(cfg) {
|
|
157
|
+
LarkClient._globalConfig = cfg;
|
|
158
|
+
}
|
|
159
|
+
/** Retrieve the stored global config, or `null` if not yet set. */
|
|
160
|
+
static get globalConfig() {
|
|
161
|
+
return LarkClient._globalConfig;
|
|
162
|
+
}
|
|
163
|
+
// --------------------------------------------------------------------------
|
|
164
|
+
constructor(account) {
|
|
165
|
+
this.account = account;
|
|
166
|
+
}
|
|
167
|
+
/** Shorthand for `this.account.accountId`. */
|
|
168
|
+
get accountId() {
|
|
169
|
+
return this.account.accountId;
|
|
170
|
+
}
|
|
171
|
+
// ---- Static factory / cache ------------------------------------------------
|
|
172
|
+
/** Resolve account from config and return a cached `LarkClient`. */
|
|
173
|
+
static fromCfg(cfg, accountId) {
|
|
174
|
+
return LarkClient.fromAccount((0, accounts_1.getLarkAccount)(cfg, accountId));
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Get (or create) a cached `LarkClient` for the given account.
|
|
178
|
+
* If the cached instance has stale credentials it is replaced.
|
|
179
|
+
*/
|
|
180
|
+
static fromAccount(account) {
|
|
181
|
+
const existing = cache.get(account.accountId);
|
|
182
|
+
if (existing &&
|
|
183
|
+
existing.account.appId === account.appId &&
|
|
184
|
+
credentialsEqual(existing.account.appSecret, account.appSecret)) {
|
|
185
|
+
return existing;
|
|
186
|
+
}
|
|
187
|
+
// Credentials changed — tear down the stale instance before replacing it.
|
|
188
|
+
if (existing) {
|
|
189
|
+
log.info(`credentials changed, disposing stale instance`, { accountId: account.accountId });
|
|
190
|
+
existing.dispose();
|
|
191
|
+
}
|
|
192
|
+
const instance = new LarkClient(account);
|
|
193
|
+
cache.set(account.accountId, instance);
|
|
194
|
+
return instance;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Create an ephemeral `LarkClient` from bare credentials.
|
|
198
|
+
* The instance is **not** added to the global cache — suitable for
|
|
199
|
+
* one-off probe / diagnose calls that should not pollute account state.
|
|
200
|
+
*/
|
|
201
|
+
static fromCredentials(credentials) {
|
|
202
|
+
const base = {
|
|
203
|
+
accountId: credentials.accountId ?? 'default',
|
|
204
|
+
enabled: true,
|
|
205
|
+
brand: credentials.brand ?? 'feishu',
|
|
206
|
+
config: {},
|
|
207
|
+
};
|
|
208
|
+
const account = credentials.appId && credentials.appSecret
|
|
209
|
+
? { ...base, configured: true, appId: credentials.appId, appSecret: credentials.appSecret }
|
|
210
|
+
: { ...base, configured: false, appId: credentials.appId, appSecret: credentials.appSecret };
|
|
211
|
+
return new LarkClient(account);
|
|
212
|
+
}
|
|
213
|
+
/** Look up a cached instance by accountId. */
|
|
214
|
+
static get(accountId) {
|
|
215
|
+
return cache.get(accountId) ?? null;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Dispose one or all cached instances.
|
|
219
|
+
* With `accountId` — dispose that single instance.
|
|
220
|
+
* Without — dispose every cached instance and clear the cache.
|
|
221
|
+
*/
|
|
222
|
+
static async clearCache(accountId) {
|
|
223
|
+
if (accountId !== undefined) {
|
|
224
|
+
cache.get(accountId)?.dispose();
|
|
225
|
+
(0, user_name_cache_store_1.clearUserNameCache)(accountId);
|
|
226
|
+
(0, chat_info_cache_1.clearChatInfoCache)(accountId);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
for (const inst of cache.values())
|
|
230
|
+
inst.dispose();
|
|
231
|
+
(0, user_name_cache_store_1.clearUserNameCache)();
|
|
232
|
+
(0, chat_info_cache_1.clearChatInfoCache)();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// ---- SDK client (lazy) -----------------------------------------------------
|
|
236
|
+
/** Lazily-created Lark SDK client. */
|
|
237
|
+
get sdk() {
|
|
238
|
+
if (!this._sdk) {
|
|
239
|
+
const { appId, appSecret } = this.requireCredentials();
|
|
240
|
+
this._sdk = new Lark.Client({
|
|
241
|
+
appId,
|
|
242
|
+
appSecret,
|
|
243
|
+
appType: Lark.AppType.SelfBuild,
|
|
244
|
+
domain: resolveBrand(this.account.brand),
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
return this._sdk;
|
|
248
|
+
}
|
|
249
|
+
// ---- Bot identity ----------------------------------------------------------
|
|
250
|
+
/**
|
|
251
|
+
* Probe bot identity via the `bot/v1/openclaw_bot/ping` API.
|
|
252
|
+
* Results are cached on the instance for subsequent access via
|
|
253
|
+
* `botOpenId` / `botName`.
|
|
254
|
+
*/
|
|
255
|
+
async probe(opts) {
|
|
256
|
+
const maxAge = opts?.maxAgeMs ?? 0;
|
|
257
|
+
if (maxAge > 0 && this._lastProbeResult && Date.now() - this._lastProbeAt < maxAge) {
|
|
258
|
+
return this._lastProbeResult;
|
|
259
|
+
}
|
|
260
|
+
if (!this.account.appId || !this.account.appSecret) {
|
|
261
|
+
return { ok: false, error: 'missing credentials (appId, appSecret)' };
|
|
262
|
+
}
|
|
263
|
+
try {
|
|
264
|
+
const needBotInfo = opts?.needBotInfo ?? true;
|
|
265
|
+
const res = await this.sdk.request({
|
|
266
|
+
method: 'POST',
|
|
267
|
+
url: '/open-apis/bot/v1/openclaw_bot/ping',
|
|
268
|
+
data: { needBotInfo },
|
|
269
|
+
});
|
|
270
|
+
if (res.code !== 0) {
|
|
271
|
+
const result = {
|
|
272
|
+
ok: false,
|
|
273
|
+
appId: this.account.appId,
|
|
274
|
+
error: `API error: ${res.msg || `code ${res.code}`}`,
|
|
275
|
+
};
|
|
276
|
+
this._lastProbeResult = result;
|
|
277
|
+
this._lastProbeAt = Date.now();
|
|
278
|
+
return result;
|
|
279
|
+
}
|
|
280
|
+
const botInfo = res.data?.pingBotInfo;
|
|
281
|
+
this._botOpenId = botInfo?.botID;
|
|
282
|
+
this._botName = botInfo?.botName;
|
|
283
|
+
const result = {
|
|
284
|
+
ok: true,
|
|
285
|
+
appId: this.account.appId,
|
|
286
|
+
botName: this._botName,
|
|
287
|
+
botOpenId: this._botOpenId,
|
|
288
|
+
};
|
|
289
|
+
this._lastProbeResult = result;
|
|
290
|
+
this._lastProbeAt = Date.now();
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
293
|
+
catch (err) {
|
|
294
|
+
const result = {
|
|
295
|
+
ok: false,
|
|
296
|
+
appId: this.account.appId,
|
|
297
|
+
error: err instanceof Error ? err.message : String(err),
|
|
298
|
+
};
|
|
299
|
+
this._lastProbeResult = result;
|
|
300
|
+
this._lastProbeAt = Date.now();
|
|
301
|
+
return result;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/** Cached bot open_id (available after `probe()` or `startWS()`). */
|
|
305
|
+
get botOpenId() {
|
|
306
|
+
return this._botOpenId;
|
|
307
|
+
}
|
|
308
|
+
/** Cached bot name (available after `probe()` or `startWS()`). */
|
|
309
|
+
get botName() {
|
|
310
|
+
return this._botName;
|
|
311
|
+
}
|
|
312
|
+
// ---- WebSocket lifecycle ---------------------------------------------------
|
|
313
|
+
/**
|
|
314
|
+
* Start WebSocket event monitoring.
|
|
315
|
+
*
|
|
316
|
+
* Flow: probe bot identity → EventDispatcher → WSClient → start.
|
|
317
|
+
* The returned Promise resolves when `abortSignal` fires.
|
|
318
|
+
*/
|
|
319
|
+
async startWS(opts) {
|
|
320
|
+
const { handlers, abortSignal, autoProbe = true } = opts;
|
|
321
|
+
if (autoProbe)
|
|
322
|
+
await this.probe();
|
|
323
|
+
const dispatcher = new Lark.EventDispatcher({
|
|
324
|
+
encryptKey: this.account.encryptKey ?? '',
|
|
325
|
+
verificationToken: this.account.verificationToken ?? '',
|
|
326
|
+
});
|
|
327
|
+
dispatcher.register(handlers);
|
|
328
|
+
const { appId, appSecret } = this.requireCredentials();
|
|
329
|
+
// Close any existing WSClient before creating a new one to prevent
|
|
330
|
+
// orphaned connections when startWS is called multiple times.
|
|
331
|
+
if (this._wsClient) {
|
|
332
|
+
log.warn(`closing previous WSClient before reconnect`, { accountId: this.accountId });
|
|
333
|
+
try {
|
|
334
|
+
this._wsClient.close({ force: true });
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
// Ignore — the old client may already be torn down.
|
|
338
|
+
}
|
|
339
|
+
this._wsClient = null;
|
|
340
|
+
}
|
|
341
|
+
this._wsClient = new Lark.WSClient({
|
|
342
|
+
appId,
|
|
343
|
+
appSecret,
|
|
344
|
+
domain: resolveBrand(this.account.brand),
|
|
345
|
+
loggerLevel: Lark.LoggerLevel.info,
|
|
346
|
+
});
|
|
347
|
+
// SDK 的 handleEventData 只处理 type="event",card action 回调是 type="card" 会被丢弃。
|
|
348
|
+
// 打 patch 将 "card" 类型消息改成 "event" 后交给原 handler,让 EventDispatcher 正常路由。
|
|
349
|
+
const wsClientAny = this._wsClient;
|
|
350
|
+
const origHandleEventData = wsClientAny.handleEventData.bind(wsClientAny);
|
|
351
|
+
wsClientAny.handleEventData = (data) => {
|
|
352
|
+
const msgType = data.headers?.find?.((h) => h.key === 'type')?.value;
|
|
353
|
+
if (msgType === 'card') {
|
|
354
|
+
const patchedData = {
|
|
355
|
+
...data,
|
|
356
|
+
headers: data.headers.map((h) => (h.key === 'type' ? { ...h, value: 'event' } : h)),
|
|
357
|
+
};
|
|
358
|
+
return origHandleEventData(patchedData);
|
|
359
|
+
}
|
|
360
|
+
return origHandleEventData(data);
|
|
361
|
+
};
|
|
362
|
+
await this.waitForAbort(dispatcher, abortSignal);
|
|
363
|
+
}
|
|
364
|
+
/** Whether a WebSocket client is currently active. */
|
|
365
|
+
get wsConnected() {
|
|
366
|
+
return this._wsClient != null;
|
|
367
|
+
}
|
|
368
|
+
/** Disconnect WebSocket but keep instance in cache. */
|
|
369
|
+
disconnect() {
|
|
370
|
+
if (this._wsClient) {
|
|
371
|
+
log.info(`disconnecting WebSocket`, { accountId: this.accountId });
|
|
372
|
+
try {
|
|
373
|
+
this._wsClient.close({ force: true });
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
// Ignore errors during close — the client may already be torn down.
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
this._wsClient = null;
|
|
380
|
+
if (this.messageDedup) {
|
|
381
|
+
log.info(`disposing message dedup`, { accountId: this.accountId, size: this.messageDedup.size });
|
|
382
|
+
this.messageDedup.dispose();
|
|
383
|
+
this.messageDedup = null;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
/** Disconnect + remove from cache. */
|
|
387
|
+
dispose() {
|
|
388
|
+
this.disconnect();
|
|
389
|
+
cache.delete(this.accountId);
|
|
390
|
+
}
|
|
391
|
+
// ---- Private helpers -------------------------------------------------------
|
|
392
|
+
/** Assert credentials exist or throw. */
|
|
393
|
+
requireCredentials() {
|
|
394
|
+
const appId = this.account.appId;
|
|
395
|
+
const appSecret = this.account.appSecret;
|
|
396
|
+
if (!appId || !appSecret) {
|
|
397
|
+
throw new Error(`LarkClient[${this.accountId}]: appId and appSecret are required`);
|
|
398
|
+
}
|
|
399
|
+
return { appId, appSecret };
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Start the WSClient and return a promise that resolves when the
|
|
403
|
+
* abort signal fires (or immediately if already aborted).
|
|
404
|
+
*/
|
|
405
|
+
waitForAbort(dispatcher, signal) {
|
|
406
|
+
return new Promise((resolve, reject) => {
|
|
407
|
+
if (signal?.aborted) {
|
|
408
|
+
this.disconnect();
|
|
409
|
+
return resolve();
|
|
410
|
+
}
|
|
411
|
+
signal?.addEventListener('abort', () => {
|
|
412
|
+
this.disconnect();
|
|
413
|
+
resolve();
|
|
414
|
+
}, { once: true });
|
|
415
|
+
try {
|
|
416
|
+
void this._wsClient.start({ eventDispatcher: dispatcher });
|
|
417
|
+
}
|
|
418
|
+
catch (err) {
|
|
419
|
+
this.disconnect();
|
|
420
|
+
reject(err);
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
exports.LarkClient = LarkClient;
|
|
426
|
+
// Inject LarkClient reference into chat-info-cache to break the circular
|
|
427
|
+
// dependency (chat-info-cache needs LarkClient.fromCfg but lark-client
|
|
428
|
+
// imports clearChatInfoCache from chat-info-cache).
|
|
429
|
+
(0, chat_info_cache_1.injectLarkClient)(LarkClient);
|
|
430
|
+
// ---------------------------------------------------------------------------
|
|
431
|
+
// Config resolution helper
|
|
432
|
+
// ---------------------------------------------------------------------------
|
|
433
|
+
/**
|
|
434
|
+
* Returns the best available config for account resolution.
|
|
435
|
+
*
|
|
436
|
+
* Priority: live config (has `channels.feishu`) > fallback (has
|
|
437
|
+
* `channels.feishu`) > live config (last resort).
|
|
438
|
+
*
|
|
439
|
+
* The `config` object captured in tool-registration closures may be stale
|
|
440
|
+
* after a hot-reload, so we prefer the live config from
|
|
441
|
+
* `LarkClient.runtime.config.loadConfig()`. However, `loadConfig()` may
|
|
442
|
+
* return `{}` when the runtime config snapshot has been cleared (e.g. in
|
|
443
|
+
* isolated cron sessions), so we fall back to the closure-captured config
|
|
444
|
+
* when the live result lacks Feishu credentials.
|
|
445
|
+
*
|
|
446
|
+
* @param fallback - Config to use when the runtime is not yet initialised
|
|
447
|
+
* or when `loadConfig()` returns an incomplete config.
|
|
448
|
+
*/
|
|
449
|
+
function getResolvedConfig(fallback) {
|
|
450
|
+
try {
|
|
451
|
+
const live = LarkClient.runtime.config.loadConfig();
|
|
452
|
+
// loadConfig() may return {} (empty config) when runtimeConfigSnapshot
|
|
453
|
+
// has been cleared (e.g. after writeConfigFile, secrets teardown, or
|
|
454
|
+
// concurrent cron race conditions in isolated sessions). In that case
|
|
455
|
+
// the closure-captured fallback still holds a valid resolved config.
|
|
456
|
+
if (live?.channels?.feishu)
|
|
457
|
+
return live;
|
|
458
|
+
if (fallback?.channels?.feishu) {
|
|
459
|
+
log.debug(`loadConfig() returned config without channels.feishu, using fallback`);
|
|
460
|
+
return fallback;
|
|
461
|
+
}
|
|
462
|
+
return live;
|
|
463
|
+
}
|
|
464
|
+
catch {
|
|
465
|
+
// runtime not yet initialised — fall back to passed config
|
|
466
|
+
return fallback;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* Structured logger factory for the Feishu plugin.
|
|
6
|
+
*
|
|
7
|
+
* Wraps `PluginRuntime.logging.getChildLogger()` with automatic
|
|
8
|
+
* LarkTicket injection from AsyncLocalStorage and a console fallback
|
|
9
|
+
* when the runtime is not yet initialised.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* const log = larkLogger("card/streaming");
|
|
13
|
+
* log.info("created entity", { cardId, sequence });
|
|
14
|
+
*/
|
|
15
|
+
export interface LarkLogger {
|
|
16
|
+
readonly subsystem: string;
|
|
17
|
+
debug(message: string, meta?: Record<string, unknown>): void;
|
|
18
|
+
info(message: string, meta?: Record<string, unknown>): void;
|
|
19
|
+
warn(message: string, meta?: Record<string, unknown>): void;
|
|
20
|
+
error(message: string, meta?: Record<string, unknown>): void;
|
|
21
|
+
child(name: string): LarkLogger;
|
|
22
|
+
}
|
|
23
|
+
export declare function larkLogger(subsystem: string): LarkLogger;
|