@lark-project/openclaw-lark-project 2026.3.131
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 +80 -0
- package/README.zh.md +80 -0
- package/dist/index.js +172 -0
- package/dist/index.js.map +7 -0
- package/dist/skills/feishu-bitable/SKILL.md +248 -0
- package/dist/skills/feishu-bitable/references/examples.md +813 -0
- package/dist/skills/feishu-bitable/references/field-properties.md +763 -0
- package/dist/skills/feishu-bitable/references/record-values.md +911 -0
- package/dist/skills/feishu-calendar/SKILL.md +244 -0
- package/dist/skills/feishu-channel-rules/SKILL.md +18 -0
- package/dist/skills/feishu-channel-rules/references/markdown-syntax.md +138 -0
- package/dist/skills/feishu-create-doc/SKILL.md +719 -0
- package/dist/skills/feishu-fetch-doc/SKILL.md +93 -0
- package/dist/skills/feishu-im-read/SKILL.md +163 -0
- package/dist/skills/feishu-project/SKILL.md +122 -0
- package/dist/skills/feishu-task/SKILL.md +293 -0
- package/dist/skills/feishu-troubleshoot/SKILL.md +70 -0
- package/dist/skills/feishu-update-doc/SKILL.md +285 -0
- package/dist/src/card/builder.js +293 -0
- package/dist/src/card/builder.js.map +7 -0
- package/dist/src/card/cardkit.js +126 -0
- package/dist/src/card/cardkit.js.map +7 -0
- package/dist/src/card/flush-controller.js +107 -0
- package/dist/src/card/flush-controller.js.map +7 -0
- package/dist/src/card/markdown-style.js +57 -0
- package/dist/src/card/markdown-style.js.map +7 -0
- package/dist/src/card/reply-dispatcher-types.js +39 -0
- package/dist/src/card/reply-dispatcher-types.js.map +7 -0
- package/dist/src/card/reply-dispatcher.js +245 -0
- package/dist/src/card/reply-dispatcher.js.map +7 -0
- package/dist/src/card/reply-mode.js +29 -0
- package/dist/src/card/reply-mode.js.map +7 -0
- package/dist/src/card/streaming-card-controller.js +653 -0
- package/dist/src/card/streaming-card-controller.js.map +7 -0
- package/dist/src/card/unavailable-guard.js +76 -0
- package/dist/src/card/unavailable-guard.js.map +7 -0
- package/dist/src/channel/abort-detect.js +79 -0
- package/dist/src/channel/abort-detect.js.map +7 -0
- package/dist/src/channel/chat-queue.js +50 -0
- package/dist/src/channel/chat-queue.js.map +7 -0
- package/dist/src/channel/config-adapter.js +89 -0
- package/dist/src/channel/config-adapter.js.map +7 -0
- package/dist/src/channel/directory.js +133 -0
- package/dist/src/channel/directory.js.map +7 -0
- package/dist/src/channel/event-handlers.js +175 -0
- package/dist/src/channel/event-handlers.js.map +7 -0
- package/dist/src/channel/monitor.js +108 -0
- package/dist/src/channel/monitor.js.map +7 -0
- package/dist/src/channel/onboarding-config.js +76 -0
- package/dist/src/channel/onboarding-config.js.map +7 -0
- package/dist/src/channel/onboarding-migrate.js +55 -0
- package/dist/src/channel/onboarding-migrate.js.map +7 -0
- package/dist/src/channel/onboarding.js +285 -0
- package/dist/src/channel/onboarding.js.map +7 -0
- package/dist/src/channel/plugin.js +260 -0
- package/dist/src/channel/plugin.js.map +7 -0
- package/dist/src/channel/probe.js +14 -0
- package/dist/src/channel/probe.js.map +7 -0
- package/dist/src/channel/types.js +1 -0
- package/dist/src/channel/types.js.map +7 -0
- package/dist/src/commands/auth.js +73 -0
- package/dist/src/commands/auth.js.map +7 -0
- package/dist/src/commands/diagnose.js +658 -0
- package/dist/src/commands/diagnose.js.map +7 -0
- package/dist/src/commands/doctor.js +327 -0
- package/dist/src/commands/doctor.js.map +7 -0
- package/dist/src/commands/index.js +124 -0
- package/dist/src/commands/index.js.map +7 -0
- package/dist/src/core/accounts.js +129 -0
- package/dist/src/core/accounts.js.map +7 -0
- package/dist/src/core/agent-config.js +60 -0
- package/dist/src/core/agent-config.js.map +7 -0
- package/dist/src/core/api-error.js +55 -0
- package/dist/src/core/api-error.js.map +7 -0
- package/dist/src/core/app-owner-fallback.js +17 -0
- package/dist/src/core/app-owner-fallback.js.map +7 -0
- package/dist/src/core/app-scope-checker.js +95 -0
- package/dist/src/core/app-scope-checker.js.map +7 -0
- package/dist/src/core/auth-errors.js +120 -0
- package/dist/src/core/auth-errors.js.map +7 -0
- package/dist/src/core/chat-info-cache.js +102 -0
- package/dist/src/core/chat-info-cache.js.map +7 -0
- package/dist/src/core/config-schema.js +150 -0
- package/dist/src/core/config-schema.js.map +7 -0
- package/dist/src/core/device-flow.js +174 -0
- package/dist/src/core/device-flow.js.map +7 -0
- package/dist/src/core/feishu-fetch.js +12 -0
- package/dist/src/core/feishu-fetch.js.map +7 -0
- package/dist/src/core/footer-config.js +16 -0
- package/dist/src/core/footer-config.js.map +7 -0
- package/dist/src/core/lark-client.js +322 -0
- package/dist/src/core/lark-client.js.map +7 -0
- package/dist/src/core/lark-logger.js +92 -0
- package/dist/src/core/lark-logger.js.map +7 -0
- package/dist/src/core/lark-ticket.js +18 -0
- package/dist/src/core/lark-ticket.js.map +7 -0
- package/dist/src/core/message-unavailable.js +119 -0
- package/dist/src/core/message-unavailable.js.map +7 -0
- package/dist/src/core/owner-policy.js +25 -0
- package/dist/src/core/owner-policy.js.map +7 -0
- package/dist/src/core/permission-url.js +37 -0
- package/dist/src/core/permission-url.js.map +7 -0
- package/dist/src/core/project-auth.js +177 -0
- package/dist/src/core/project-auth.js.map +7 -0
- package/dist/src/core/project-oauth-flow.js +124 -0
- package/dist/src/core/project-oauth-flow.js.map +7 -0
- package/dist/src/core/project-token-store.js +172 -0
- package/dist/src/core/project-token-store.js.map +7 -0
- package/dist/src/core/raw-request.js +45 -0
- package/dist/src/core/raw-request.js.map +7 -0
- package/dist/src/core/scope-manager.js +62 -0
- package/dist/src/core/scope-manager.js.map +7 -0
- package/dist/src/core/security-check.js +118 -0
- package/dist/src/core/security-check.js.map +7 -0
- package/dist/src/core/shutdown-hooks.js +37 -0
- package/dist/src/core/shutdown-hooks.js.map +7 -0
- package/dist/src/core/targets.js +55 -0
- package/dist/src/core/targets.js.map +7 -0
- package/dist/src/core/token-store.js +215 -0
- package/dist/src/core/token-store.js.map +7 -0
- package/dist/src/core/tool-client.js +335 -0
- package/dist/src/core/tool-client.js.map +7 -0
- package/dist/src/core/tool-scopes.js +207 -0
- package/dist/src/core/tool-scopes.js.map +7 -0
- package/dist/src/core/tools-config.js +57 -0
- package/dist/src/core/tools-config.js.map +7 -0
- package/dist/src/core/types.js +1 -0
- package/dist/src/core/types.js.map +7 -0
- package/dist/src/core/uat-client.js +124 -0
- package/dist/src/core/uat-client.js.map +7 -0
- package/dist/src/core/version.js +27 -0
- package/dist/src/core/version.js.map +7 -0
- package/dist/src/messaging/converters/audio.js +19 -0
- package/dist/src/messaging/converters/audio.js.map +7 -0
- package/dist/src/messaging/converters/calendar.js +46 -0
- package/dist/src/messaging/converters/calendar.js.map +7 -0
- package/dist/src/messaging/converters/content-converter.js +61 -0
- package/dist/src/messaging/converters/content-converter.js.map +7 -0
- package/dist/src/messaging/converters/file.js +18 -0
- package/dist/src/messaging/converters/file.js.map +7 -0
- package/dist/src/messaging/converters/folder.js +18 -0
- package/dist/src/messaging/converters/folder.js.map +7 -0
- package/dist/src/messaging/converters/hongbao.js +14 -0
- package/dist/src/messaging/converters/hongbao.js.map +7 -0
- package/dist/src/messaging/converters/image.js +16 -0
- package/dist/src/messaging/converters/image.js.map +7 -0
- package/dist/src/messaging/converters/index.js +48 -0
- package/dist/src/messaging/converters/index.js.map +7 -0
- package/dist/src/messaging/converters/interactive/card-converter.js +1040 -0
- package/dist/src/messaging/converters/interactive/card-converter.js.map +7 -0
- package/dist/src/messaging/converters/interactive/card-utils.js +36 -0
- package/dist/src/messaging/converters/interactive/card-utils.js.map +7 -0
- package/dist/src/messaging/converters/interactive/index.js +19 -0
- package/dist/src/messaging/converters/interactive/index.js.map +7 -0
- package/dist/src/messaging/converters/interactive/legacy.js +53 -0
- package/dist/src/messaging/converters/interactive/legacy.js.map +7 -0
- package/dist/src/messaging/converters/interactive/types.js +23 -0
- package/dist/src/messaging/converters/interactive/types.js.map +7 -0
- package/dist/src/messaging/converters/location.js +17 -0
- package/dist/src/messaging/converters/location.js.map +7 -0
- package/dist/src/messaging/converters/merge-forward.js +143 -0
- package/dist/src/messaging/converters/merge-forward.js.map +7 -0
- package/dist/src/messaging/converters/post.js +113 -0
- package/dist/src/messaging/converters/post.js.map +7 -0
- package/dist/src/messaging/converters/share.js +22 -0
- package/dist/src/messaging/converters/share.js.map +7 -0
- package/dist/src/messaging/converters/sticker.js +16 -0
- package/dist/src/messaging/converters/sticker.js.map +7 -0
- package/dist/src/messaging/converters/system.js +25 -0
- package/dist/src/messaging/converters/system.js.map +7 -0
- package/dist/src/messaging/converters/text.js +12 -0
- package/dist/src/messaging/converters/text.js.map +7 -0
- package/dist/src/messaging/converters/todo.js +37 -0
- package/dist/src/messaging/converters/todo.js.map +7 -0
- package/dist/src/messaging/converters/types.js +1 -0
- package/dist/src/messaging/converters/types.js.map +7 -0
- package/dist/src/messaging/converters/unknown.js +13 -0
- package/dist/src/messaging/converters/unknown.js.map +7 -0
- package/dist/src/messaging/converters/utils.js +35 -0
- package/dist/src/messaging/converters/utils.js.map +7 -0
- package/dist/src/messaging/converters/video-chat.js +21 -0
- package/dist/src/messaging/converters/video-chat.js.map +7 -0
- package/dist/src/messaging/converters/video.js +30 -0
- package/dist/src/messaging/converters/video.js.map +7 -0
- package/dist/src/messaging/converters/vote.js +24 -0
- package/dist/src/messaging/converters/vote.js.map +7 -0
- package/dist/src/messaging/inbound/dedup.js +82 -0
- package/dist/src/messaging/inbound/dedup.js.map +7 -0
- package/dist/src/messaging/inbound/dispatch-builders.js +98 -0
- package/dist/src/messaging/inbound/dispatch-builders.js.map +7 -0
- package/dist/src/messaging/inbound/dispatch-commands.js +94 -0
- package/dist/src/messaging/inbound/dispatch-commands.js.map +7 -0
- package/dist/src/messaging/inbound/dispatch-context.js +96 -0
- package/dist/src/messaging/inbound/dispatch-context.js.map +7 -0
- package/dist/src/messaging/inbound/dispatch.js +150 -0
- package/dist/src/messaging/inbound/dispatch.js.map +7 -0
- package/dist/src/messaging/inbound/enrich.js +137 -0
- package/dist/src/messaging/inbound/enrich.js.map +7 -0
- package/dist/src/messaging/inbound/gate-effects.js +28 -0
- package/dist/src/messaging/inbound/gate-effects.js.map +7 -0
- package/dist/src/messaging/inbound/gate.js +163 -0
- package/dist/src/messaging/inbound/gate.js.map +7 -0
- package/dist/src/messaging/inbound/handler.js +132 -0
- package/dist/src/messaging/inbound/handler.js.map +7 -0
- package/dist/src/messaging/inbound/media-resolver.js +70 -0
- package/dist/src/messaging/inbound/media-resolver.js.map +7 -0
- package/dist/src/messaging/inbound/mention.js +50 -0
- package/dist/src/messaging/inbound/mention.js.map +7 -0
- package/dist/src/messaging/inbound/parse-io.js +41 -0
- package/dist/src/messaging/inbound/parse-io.js.map +7 -0
- package/dist/src/messaging/inbound/parse.js +79 -0
- package/dist/src/messaging/inbound/parse.js.map +7 -0
- package/dist/src/messaging/inbound/permission.js +30 -0
- package/dist/src/messaging/inbound/permission.js.map +7 -0
- package/dist/src/messaging/inbound/policy.js +83 -0
- package/dist/src/messaging/inbound/policy.js.map +7 -0
- package/dist/src/messaging/inbound/reaction-handler.js +162 -0
- package/dist/src/messaging/inbound/reaction-handler.js.map +7 -0
- package/dist/src/messaging/inbound/user-name-cache.js +172 -0
- package/dist/src/messaging/inbound/user-name-cache.js.map +7 -0
- package/dist/src/messaging/outbound/actions.js +239 -0
- package/dist/src/messaging/outbound/actions.js.map +7 -0
- package/dist/src/messaging/outbound/chat-manage.js +74 -0
- package/dist/src/messaging/outbound/chat-manage.js.map +7 -0
- package/dist/src/messaging/outbound/deliver.js +162 -0
- package/dist/src/messaging/outbound/deliver.js.map +7 -0
- package/dist/src/messaging/outbound/fetch.js +7 -0
- package/dist/src/messaging/outbound/fetch.js.map +7 -0
- package/dist/src/messaging/outbound/forward.js +31 -0
- package/dist/src/messaging/outbound/forward.js.map +7 -0
- package/dist/src/messaging/outbound/media-url-utils.js +101 -0
- package/dist/src/messaging/outbound/media-url-utils.js.map +7 -0
- package/dist/src/messaging/outbound/media.js +463 -0
- package/dist/src/messaging/outbound/media.js.map +7 -0
- package/dist/src/messaging/outbound/outbound.js +95 -0
- package/dist/src/messaging/outbound/outbound.js.map +7 -0
- package/dist/src/messaging/outbound/reactions.js +312 -0
- package/dist/src/messaging/outbound/reactions.js.map +7 -0
- package/dist/src/messaging/outbound/send.js +194 -0
- package/dist/src/messaging/outbound/send.js.map +7 -0
- package/dist/src/messaging/outbound/typing.js +77 -0
- package/dist/src/messaging/outbound/typing.js.map +7 -0
- package/dist/src/messaging/shared/message-lookup.js +84 -0
- package/dist/src/messaging/shared/message-lookup.js.map +7 -0
- package/dist/src/messaging/types.js +1 -0
- package/dist/src/messaging/types.js.map +7 -0
- package/dist/src/tools/auto-auth.js +714 -0
- package/dist/src/tools/auto-auth.js.map +7 -0
- package/dist/src/tools/helpers.js +133 -0
- package/dist/src/tools/helpers.js.map +7 -0
- package/dist/src/tools/mcp/doc/create.js +35 -0
- package/dist/src/tools/mcp/doc/create.js.map +7 -0
- package/dist/src/tools/mcp/doc/fetch.js +33 -0
- package/dist/src/tools/mcp/doc/fetch.js.map +7 -0
- package/dist/src/tools/mcp/doc/index.js +32 -0
- package/dist/src/tools/mcp/doc/index.js.map +7 -0
- package/dist/src/tools/mcp/doc/update.js +61 -0
- package/dist/src/tools/mcp/doc/update.js.map +7 -0
- package/dist/src/tools/mcp/project/endpoint.js +25 -0
- package/dist/src/tools/mcp/project/endpoint.js.map +7 -0
- package/dist/src/tools/mcp/project/index.js +27 -0
- package/dist/src/tools/mcp/project/index.js.map +7 -0
- package/dist/src/tools/mcp/project/tools.js +579 -0
- package/dist/src/tools/mcp/project/tools.js.map +7 -0
- package/dist/src/tools/mcp/shared.js +170 -0
- package/dist/src/tools/mcp/shared.js.map +7 -0
- package/dist/src/tools/oapi/bitable/app-table-field.js +244 -0
- package/dist/src/tools/oapi/bitable/app-table-field.js.map +7 -0
- package/dist/src/tools/oapi/bitable/app-table-record.js +501 -0
- package/dist/src/tools/oapi/bitable/app-table-record.js.map +7 -0
- package/dist/src/tools/oapi/bitable/app-table-view.js +226 -0
- package/dist/src/tools/oapi/bitable/app-table-view.js.map +7 -0
- package/dist/src/tools/oapi/bitable/app-table.js +278 -0
- package/dist/src/tools/oapi/bitable/app-table.js.map +7 -0
- package/dist/src/tools/oapi/bitable/app.js +200 -0
- package/dist/src/tools/oapi/bitable/app.js.map +7 -0
- package/dist/src/tools/oapi/bitable/index.js +13 -0
- package/dist/src/tools/oapi/bitable/index.js.map +7 -0
- package/dist/src/tools/oapi/calendar/calendar.js +131 -0
- package/dist/src/tools/oapi/calendar/calendar.js.map +7 -0
- package/dist/src/tools/oapi/calendar/event-attendee.js +301 -0
- package/dist/src/tools/oapi/calendar/event-attendee.js.map +7 -0
- package/dist/src/tools/oapi/calendar/event.js +834 -0
- package/dist/src/tools/oapi/calendar/event.js.map +7 -0
- package/dist/src/tools/oapi/calendar/freebusy.js +111 -0
- package/dist/src/tools/oapi/calendar/freebusy.js.map +7 -0
- package/dist/src/tools/oapi/calendar/index.js +11 -0
- package/dist/src/tools/oapi/calendar/index.js.map +7 -0
- package/dist/src/tools/oapi/chat/chat.js +132 -0
- package/dist/src/tools/oapi/chat/chat.js.map +7 -0
- package/dist/src/tools/oapi/chat/index.js +11 -0
- package/dist/src/tools/oapi/chat/index.js.map +7 -0
- package/dist/src/tools/oapi/chat/members.js +83 -0
- package/dist/src/tools/oapi/chat/members.js.map +7 -0
- package/dist/src/tools/oapi/common/get-user.js +95 -0
- package/dist/src/tools/oapi/common/get-user.js.map +7 -0
- package/dist/src/tools/oapi/common/index.js +7 -0
- package/dist/src/tools/oapi/common/index.js.map +7 -0
- package/dist/src/tools/oapi/common/search-user.js +67 -0
- package/dist/src/tools/oapi/common/search-user.js.map +7 -0
- package/dist/src/tools/oapi/drive/doc-comments.js +310 -0
- package/dist/src/tools/oapi/drive/doc-comments.js.map +7 -0
- package/dist/src/tools/oapi/drive/doc-media.js +314 -0
- package/dist/src/tools/oapi/drive/doc-media.js.map +7 -0
- package/dist/src/tools/oapi/drive/file.js +548 -0
- package/dist/src/tools/oapi/drive/file.js.map +7 -0
- package/dist/src/tools/oapi/drive/index.js +29 -0
- package/dist/src/tools/oapi/drive/index.js.map +7 -0
- package/dist/src/tools/oapi/helpers.js +199 -0
- package/dist/src/tools/oapi/helpers.js.map +7 -0
- package/dist/src/tools/oapi/im/format-messages.js +128 -0
- package/dist/src/tools/oapi/im/format-messages.js.map +7 -0
- package/dist/src/tools/oapi/im/index.js +15 -0
- package/dist/src/tools/oapi/im/index.js.map +7 -0
- package/dist/src/tools/oapi/im/message-read.js +404 -0
- package/dist/src/tools/oapi/im/message-read.js.map +7 -0
- package/dist/src/tools/oapi/im/message.js +179 -0
- package/dist/src/tools/oapi/im/message.js.map +7 -0
- package/dist/src/tools/oapi/im/resource.js +126 -0
- package/dist/src/tools/oapi/im/resource.js.map +7 -0
- package/dist/src/tools/oapi/im/time-utils.js +169 -0
- package/dist/src/tools/oapi/im/time-utils.js.map +7 -0
- package/dist/src/tools/oapi/im/user-name-uat.js +103 -0
- package/dist/src/tools/oapi/im/user-name-uat.js.map +7 -0
- package/dist/src/tools/oapi/index.js +56 -0
- package/dist/src/tools/oapi/index.js.map +7 -0
- package/dist/src/tools/oapi/sdk-types.js +1 -0
- package/dist/src/tools/oapi/sdk-types.js.map +7 -0
- package/dist/src/tools/oapi/search/doc-search.js +215 -0
- package/dist/src/tools/oapi/search/doc-search.js.map +7 -0
- package/dist/src/tools/oapi/search/index.js +25 -0
- package/dist/src/tools/oapi/search/index.js.map +7 -0
- package/dist/src/tools/oapi/sheets/index.js +25 -0
- package/dist/src/tools/oapi/sheets/index.js.map +7 -0
- package/dist/src/tools/oapi/sheets/sheet.js +652 -0
- package/dist/src/tools/oapi/sheets/sheet.js.map +7 -0
- package/dist/src/tools/oapi/task/comment.js +151 -0
- package/dist/src/tools/oapi/task/comment.js.map +7 -0
- package/dist/src/tools/oapi/task/index.js +11 -0
- package/dist/src/tools/oapi/task/index.js.map +7 -0
- package/dist/src/tools/oapi/task/subtask.js +175 -0
- package/dist/src/tools/oapi/task/subtask.js.map +7 -0
- package/dist/src/tools/oapi/task/task.js +405 -0
- package/dist/src/tools/oapi/task/task.js.map +7 -0
- package/dist/src/tools/oapi/task/tasklist.js +366 -0
- package/dist/src/tools/oapi/task/tasklist.js.map +7 -0
- package/dist/src/tools/oapi/wiki/index.js +27 -0
- package/dist/src/tools/oapi/wiki/index.js.map +7 -0
- package/dist/src/tools/oapi/wiki/space-node.js +311 -0
- package/dist/src/tools/oapi/wiki/space-node.js.map +7 -0
- package/dist/src/tools/oapi/wiki/space.js +148 -0
- package/dist/src/tools/oapi/wiki/space.js.map +7 -0
- package/dist/src/tools/oauth-batch-auth.js +125 -0
- package/dist/src/tools/oauth-batch-auth.js.map +7 -0
- package/dist/src/tools/oauth-cards.js +269 -0
- package/dist/src/tools/oauth-cards.js.map +7 -0
- package/dist/src/tools/oauth.js +538 -0
- package/dist/src/tools/oauth.js.map +7 -0
- package/dist/src/tools/onboarding-auth.js +101 -0
- package/dist/src/tools/onboarding-auth.js.map +7 -0
- package/dist/src/tools/project-oauth.js +305 -0
- package/dist/src/tools/project-oauth.js.map +7 -0
- package/dist/src/tools/tat/im/index.js +9 -0
- package/dist/src/tools/tat/im/index.js.map +7 -0
- package/dist/src/tools/tat/im/resource.js +123 -0
- package/dist/src/tools/tat/im/resource.js.map +7 -0
- package/package.json +64 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { LarkClient } from "../core/lark-client";
|
|
2
|
+
import { larkLogger } from "../core/lark-logger";
|
|
3
|
+
import { normalizeFeishuTarget, normalizeMessageId, resolveReceiveIdType } from "../core/targets";
|
|
4
|
+
import { runWithMessageUnavailableGuard } from "../core/message-unavailable";
|
|
5
|
+
const log = larkLogger("card/cardkit");
|
|
6
|
+
function logCardKitResponse(params) {
|
|
7
|
+
const { resp, api, context } = params;
|
|
8
|
+
const { code, msg } = resp;
|
|
9
|
+
log.info(`cardkit ${api} response`, { code, msg, context });
|
|
10
|
+
if (code && code !== 0) {
|
|
11
|
+
log.warn(`cardkit ${api} FAILED`, { code, msg, context, fullResponse: resp });
|
|
12
|
+
throw new Error(`cardkit ${api} FAILED: code=${code}, msg=${msg ?? ""}, ${context}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
async function createCardEntity(params) {
|
|
16
|
+
const { cfg, card, accountId } = params;
|
|
17
|
+
const client = LarkClient.fromCfg(cfg, accountId).sdk;
|
|
18
|
+
const response = await client.cardkit.v1.card.create({
|
|
19
|
+
data: {
|
|
20
|
+
type: "card_json",
|
|
21
|
+
data: JSON.stringify(card)
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
const cardId = response.data?.card_id ?? response.card_id ?? null;
|
|
25
|
+
logCardKitResponse({ resp: response, api: "card.create", context: `cardId=${cardId}` });
|
|
26
|
+
return cardId;
|
|
27
|
+
}
|
|
28
|
+
async function streamCardContent(params) {
|
|
29
|
+
const { cfg, cardId, elementId, content, sequence, accountId } = params;
|
|
30
|
+
const client = LarkClient.fromCfg(cfg, accountId).sdk;
|
|
31
|
+
const resp = await client.cardkit.v1.cardElement.content({
|
|
32
|
+
data: { content, sequence },
|
|
33
|
+
path: { card_id: cardId, element_id: elementId }
|
|
34
|
+
});
|
|
35
|
+
logCardKitResponse({
|
|
36
|
+
resp,
|
|
37
|
+
api: "cardElement.content",
|
|
38
|
+
context: `seq=${sequence}, contentLen=${content.length}`
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
async function updateCardKitCard(params) {
|
|
42
|
+
const { cfg, cardId, card, sequence, accountId } = params;
|
|
43
|
+
const client = LarkClient.fromCfg(cfg, accountId).sdk;
|
|
44
|
+
const resp = await client.cardkit.v1.card.update({
|
|
45
|
+
data: {
|
|
46
|
+
card: { type: "card_json", data: JSON.stringify(card) },
|
|
47
|
+
sequence
|
|
48
|
+
},
|
|
49
|
+
path: { card_id: cardId }
|
|
50
|
+
});
|
|
51
|
+
logCardKitResponse({
|
|
52
|
+
resp,
|
|
53
|
+
api: "card.update",
|
|
54
|
+
context: `seq=${sequence}, cardId=${cardId}`
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
async function updateCardKitCardForAuth(params) {
|
|
58
|
+
return updateCardKitCard(params);
|
|
59
|
+
}
|
|
60
|
+
async function sendCardByCardId(params) {
|
|
61
|
+
const { cfg, to, cardId, replyToMessageId, replyInThread, accountId } = params;
|
|
62
|
+
const client = LarkClient.fromCfg(cfg, accountId).sdk;
|
|
63
|
+
const contentPayload = JSON.stringify({
|
|
64
|
+
type: "card",
|
|
65
|
+
data: { card_id: cardId }
|
|
66
|
+
});
|
|
67
|
+
if (replyToMessageId) {
|
|
68
|
+
const normalizedId = normalizeMessageId(replyToMessageId);
|
|
69
|
+
const response2 = await runWithMessageUnavailableGuard({
|
|
70
|
+
messageId: normalizedId,
|
|
71
|
+
operation: "im.message.reply(interactive.cardkit)",
|
|
72
|
+
fn: () => client.im.message.reply({
|
|
73
|
+
path: { message_id: normalizedId },
|
|
74
|
+
data: { content: contentPayload, msg_type: "interactive", reply_in_thread: replyInThread }
|
|
75
|
+
})
|
|
76
|
+
});
|
|
77
|
+
return {
|
|
78
|
+
messageId: response2?.data?.message_id ?? "",
|
|
79
|
+
chatId: response2?.data?.chat_id ?? ""
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const target = normalizeFeishuTarget(to);
|
|
83
|
+
if (!target) {
|
|
84
|
+
throw new Error(`[feishu-send] Invalid target: "${to}"`);
|
|
85
|
+
}
|
|
86
|
+
const receiveIdType = resolveReceiveIdType(target);
|
|
87
|
+
const response = await client.im.message.create({
|
|
88
|
+
// SDK 类型将 receive_id_type 限定为字面量联合,但运行时接受动态值
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
90
|
+
params: { receive_id_type: receiveIdType },
|
|
91
|
+
data: {
|
|
92
|
+
receive_id: target,
|
|
93
|
+
msg_type: "interactive",
|
|
94
|
+
content: contentPayload
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
return {
|
|
98
|
+
messageId: response?.data?.message_id ?? "",
|
|
99
|
+
chatId: response?.data?.chat_id ?? ""
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
async function setCardStreamingMode(params) {
|
|
103
|
+
const { cfg, cardId, streamingMode, sequence, accountId } = params;
|
|
104
|
+
const client = LarkClient.fromCfg(cfg, accountId).sdk;
|
|
105
|
+
const resp = await client.cardkit.v1.card.settings({
|
|
106
|
+
data: {
|
|
107
|
+
settings: JSON.stringify({ streaming_mode: streamingMode }),
|
|
108
|
+
sequence
|
|
109
|
+
},
|
|
110
|
+
path: { card_id: cardId }
|
|
111
|
+
});
|
|
112
|
+
logCardKitResponse({
|
|
113
|
+
resp,
|
|
114
|
+
api: "card.settings",
|
|
115
|
+
context: `seq=${sequence}, streaming_mode=${streamingMode}`
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
export {
|
|
119
|
+
createCardEntity,
|
|
120
|
+
sendCardByCardId,
|
|
121
|
+
setCardStreamingMode,
|
|
122
|
+
streamCardContent,
|
|
123
|
+
updateCardKitCard,
|
|
124
|
+
updateCardKitCardForAuth
|
|
125
|
+
};
|
|
126
|
+
//# sourceMappingURL=cardkit.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/card/cardkit.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * CardKit streaming APIs for Lark/Feishu.\n */\n\nimport type { ClawdbotConfig } from 'openclaw/plugin-sdk';\nimport type { FeishuSendResult } from '../messaging/types';\nimport { LarkClient } from '../core/lark-client';\nimport { larkLogger } from '../core/lark-logger';\nimport { normalizeFeishuTarget, normalizeMessageId, resolveReceiveIdType } from '../core/targets';\nimport { runWithMessageUnavailableGuard } from '../core/message-unavailable';\n\nconst log = larkLogger('card/cardkit');\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * \u98DE\u4E66 CardKit SDK \u54CD\u5E94\u7684\u901A\u7528\u7ED3\u6784\u3002\n * SDK \u7684 TypeScript \u7C7B\u578B\u5B9A\u4E49\u4E0D\u5305\u542B code/msg \u5B57\u6BB5\uFF0C\u4F46\u8FD0\u884C\u65F6\u5B9E\u9645\u8FD4\u56DE\u3002\n * \u4F7F\u7528\u6B64\u63A5\u53E3\u4EE3\u66FF `as any` \u4EE5\u83B7\u5F97\u7C7B\u578B\u5B89\u5168\u7684\u5B57\u6BB5\u8BBF\u95EE\u3002\n */\ninterface CardKitResponse {\n code?: number;\n msg?: string;\n data?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * \u8BB0\u5F55 CardKit API \u54CD\u5E94\u65E5\u5FD7\uFF0C\u68C0\u6D4B\u9519\u8BEF\u7801\u5E76\u629B\u51FA\u5F02\u5E38\u3002\n *\n * \u9ED8\u8BA4 fail-fast\uFF1Abody-level \u975E\u96F6 code \u89C6\u4E3A\u4E1A\u52A1\u9519\u8BEF\uFF0C\u7ACB\u5373\u629B\u51FA\uFF0C\n * \u7531\u8C03\u7528\u65B9\uFF08streaming-card-controller \u7B49\uFF09\u7EDF\u4E00\u8D70 catch \u2192 guard \u5904\u7406\u3002\n */\nfunction logCardKitResponse(params: { resp: CardKitResponse; api: string; context: string }): void {\n const { resp, api, context } = params;\n const { code, msg } = resp;\n log.info(`cardkit ${api} response`, { code, msg, context });\n if (code && code !== 0) {\n log.warn(`cardkit ${api} FAILED`, { code, msg, context, fullResponse: resp });\n throw new Error(`cardkit ${api} FAILED: code=${code}, msg=${msg ?? ''}, ${context}`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// CardKit streaming APIs\n// ---------------------------------------------------------------------------\n\n/**\n * Create a card entity via the CardKit API.\n *\n * Returns the card_id directly, bypassing the idConvert step.\n * The card can then be sent via IM API and streamed via CardKit.\n */\nexport async function createCardEntity(params: {\n cfg: ClawdbotConfig;\n card: Record<string, unknown>;\n accountId?: string;\n}): Promise<string | null> {\n const { cfg, card, accountId } = params;\n\n const client = LarkClient.fromCfg(cfg, accountId).sdk;\n\n // SDK \u8FD4\u56DE\u7C7B\u578B\u4E0D\u5B8C\u6574\uFF0C\u8FD0\u884C\u65F6\u5305\u542B code/msg/data \u5B57\u6BB5\n const response = (await client.cardkit.v1.card.create({\n data: {\n type: 'card_json',\n data: JSON.stringify(card),\n },\n })) as CardKitResponse;\n\n // \u517C\u5BB9\u4E0D\u540C SDK \u5305\u88C5\u5C42\uFF1A\u4F18\u5148 data.card_id\uFF0C\u56DE\u9000\u9876\u5C42 card_id\n const cardId =\n ((response.data?.card_id ?? (response as Record<string, unknown>).card_id) as string | undefined) ?? null;\n logCardKitResponse({ resp: response, api: 'card.create', context: `cardId=${cardId}` });\n return cardId;\n}\n\n/**\n * Stream text content to a specific card element using the CardKit API.\n *\n * The card automatically diffs the new content against the previous\n * content and renders incremental changes with a typewriter animation.\n *\n * @param params.cardId - CardKit card ID (from `convertMessageToCardId`).\n * @param params.elementId - The element ID to update (e.g. `STREAMING_ELEMENT_ID`).\n * @param params.content - The full cumulative text (not a delta).\n * @param params.sequence - Monotonically increasing sequence number.\n */\nexport async function streamCardContent(params: {\n cfg: ClawdbotConfig;\n cardId: string;\n elementId: string;\n content: string;\n sequence: number;\n accountId?: string;\n}): Promise<void> {\n const { cfg, cardId, elementId, content, sequence, accountId } = params;\n\n const client = LarkClient.fromCfg(cfg, accountId).sdk;\n\n // SDK \u8FD4\u56DE\u7C7B\u578B\u4E0D\u5B8C\u6574\uFF0C\u8FD0\u884C\u65F6\u5305\u542B code/msg \u5B57\u6BB5\n const resp = (await client.cardkit.v1.cardElement.content({\n data: { content, sequence },\n path: { card_id: cardId, element_id: elementId },\n })) as CardKitResponse;\n logCardKitResponse({\n resp,\n api: 'cardElement.content',\n context: `seq=${sequence}, contentLen=${content.length}`,\n });\n}\n\n/**\n * Fully replace a card using the CardKit API.\n *\n * Used for the final \"complete\" state update (with action buttons, green\n * header, etc.) after streaming finishes.\n *\n * @param params.cardId - CardKit card ID.\n * @param params.card - The new card JSON content.\n * @param params.sequence - Monotonically increasing sequence number.\n */\nexport async function updateCardKitCard(params: {\n cfg: ClawdbotConfig;\n cardId: string;\n card: Record<string, unknown>;\n sequence: number;\n accountId?: string;\n}): Promise<void> {\n const { cfg, cardId, card, sequence, accountId } = params;\n\n const client = LarkClient.fromCfg(cfg, accountId).sdk;\n\n // SDK \u8FD4\u56DE\u7C7B\u578B\u4E0D\u5B8C\u6574\uFF0C\u8FD0\u884C\u65F6\u5305\u542B code/msg \u5B57\u6BB5\n const resp = (await client.cardkit.v1.card.update({\n data: {\n card: { type: 'card_json', data: JSON.stringify(card) },\n sequence,\n },\n path: { card_id: cardId },\n })) as CardKitResponse;\n logCardKitResponse({\n resp,\n api: 'card.update',\n context: `seq=${sequence}, cardId=${cardId}`,\n });\n}\n\nexport async function updateCardKitCardForAuth(params: {\n cfg: ClawdbotConfig;\n cardId: string;\n card: Record<string, unknown>;\n sequence: number;\n accountId?: string;\n}): Promise<void> {\n return updateCardKitCard(params);\n}\n\n/**\n * Send an interactive card message by referencing a CardKit card_id.\n *\n * The content format is: {\"type\":\"card\",\"data\":{\"card_id\":\"xxx\"}}\n * This links the IM message to the CardKit card entity, enabling\n * streaming updates via cardElement.content().\n */\nexport async function sendCardByCardId(params: {\n cfg: ClawdbotConfig;\n to: string;\n cardId: string;\n replyToMessageId?: string;\n replyInThread?: boolean;\n accountId?: string;\n}): Promise<FeishuSendResult> {\n const { cfg, to, cardId, replyToMessageId, replyInThread, accountId } = params;\n\n const client = LarkClient.fromCfg(cfg, accountId).sdk;\n\n const contentPayload = JSON.stringify({\n type: 'card',\n data: { card_id: cardId },\n });\n\n if (replyToMessageId) {\n // \u89C4\u8303\u5316 message_id\uFF0C\u5904\u7406\u5408\u6210 ID\uFF08\u5982 \"om_xxx:auth-complete\"\uFF09\n const normalizedId = normalizeMessageId(replyToMessageId);\n const response = await runWithMessageUnavailableGuard({\n messageId: normalizedId,\n operation: 'im.message.reply(interactive.cardkit)',\n fn: () =>\n client.im.message.reply({\n path: { message_id: normalizedId! },\n data: { content: contentPayload, msg_type: 'interactive', reply_in_thread: replyInThread },\n }),\n });\n return {\n messageId: response?.data?.message_id ?? '',\n chatId: response?.data?.chat_id ?? '',\n };\n }\n\n const target = normalizeFeishuTarget(to);\n if (!target) {\n throw new Error(`[feishu-send] Invalid target: \"${to}\"`);\n }\n const receiveIdType = resolveReceiveIdType(target);\n\n const response = await client.im.message.create({\n // SDK \u7C7B\u578B\u5C06 receive_id_type \u9650\u5B9A\u4E3A\u5B57\u9762\u91CF\u8054\u5408\uFF0C\u4F46\u8FD0\u884C\u65F6\u63A5\u53D7\u52A8\u6001\u503C\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n params: { receive_id_type: receiveIdType as any },\n data: {\n receive_id: target,\n msg_type: 'interactive',\n content: contentPayload,\n },\n });\n\n return {\n messageId: response?.data?.message_id ?? '',\n chatId: response?.data?.chat_id ?? '',\n };\n}\n\n/**\n * Close (or open) the streaming mode on a CardKit card.\n *\n * Must be called after streaming is complete to restore normal card\n * behaviour (forwarding, interaction callbacks, etc.).\n */\nexport async function setCardStreamingMode(params: {\n cfg: ClawdbotConfig;\n cardId: string;\n streamingMode: boolean;\n sequence: number;\n accountId?: string;\n}): Promise<void> {\n const { cfg, cardId, streamingMode, sequence, accountId } = params;\n\n const client = LarkClient.fromCfg(cfg, accountId).sdk;\n\n // SDK \u8FD4\u56DE\u7C7B\u578B\u4E0D\u5B8C\u6574\uFF0C\u8FD0\u884C\u65F6\u5305\u542B code/msg \u5B57\u6BB5\n const resp = (await client.cardkit.v1.card.settings({\n data: {\n settings: JSON.stringify({ streaming_mode: streamingMode }),\n sequence,\n },\n path: { card_id: cardId },\n })) as CardKitResponse;\n logCardKitResponse({\n resp,\n api: 'card.settings',\n context: `seq=${sequence}, streaming_mode=${streamingMode}`,\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["response"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { THROTTLE_CONSTANTS } from "./reply-dispatcher-types";
|
|
2
|
+
class FlushController {
|
|
3
|
+
constructor(doFlush) {
|
|
4
|
+
this.doFlush = doFlush;
|
|
5
|
+
}
|
|
6
|
+
flushInProgress = false;
|
|
7
|
+
flushResolvers = [];
|
|
8
|
+
needsReflush = false;
|
|
9
|
+
pendingFlushTimer = null;
|
|
10
|
+
lastUpdateTime = 0;
|
|
11
|
+
isCompleted = false;
|
|
12
|
+
/** Mark the controller as completed — no more flushes after current one. */
|
|
13
|
+
complete() {
|
|
14
|
+
this.isCompleted = true;
|
|
15
|
+
}
|
|
16
|
+
/** Cancel any pending deferred flush timer. */
|
|
17
|
+
cancelPendingFlush() {
|
|
18
|
+
if (this.pendingFlushTimer) {
|
|
19
|
+
clearTimeout(this.pendingFlushTimer);
|
|
20
|
+
this.pendingFlushTimer = null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/** Wait for any in-progress flush to finish. */
|
|
24
|
+
waitForFlush() {
|
|
25
|
+
if (!this.flushInProgress) return Promise.resolve();
|
|
26
|
+
return new Promise((resolve) => this.flushResolvers.push(resolve));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Execute a flush (mutex-guarded, with reflush on conflict).
|
|
30
|
+
*
|
|
31
|
+
* If a flush is already in progress, marks needsReflush so a
|
|
32
|
+
* follow-up flush fires immediately after the current one completes.
|
|
33
|
+
*/
|
|
34
|
+
async flush() {
|
|
35
|
+
if (!this.cardMessageReady() || this.flushInProgress || this.isCompleted) {
|
|
36
|
+
if (this.flushInProgress && !this.isCompleted) this.needsReflush = true;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
this.flushInProgress = true;
|
|
40
|
+
this.needsReflush = false;
|
|
41
|
+
this.lastUpdateTime = Date.now();
|
|
42
|
+
try {
|
|
43
|
+
await this.doFlush();
|
|
44
|
+
this.lastUpdateTime = Date.now();
|
|
45
|
+
} finally {
|
|
46
|
+
this.flushInProgress = false;
|
|
47
|
+
const resolvers = this.flushResolvers;
|
|
48
|
+
this.flushResolvers = [];
|
|
49
|
+
for (const resolve of resolvers) resolve();
|
|
50
|
+
if (this.needsReflush && !this.isCompleted && !this.pendingFlushTimer) {
|
|
51
|
+
this.needsReflush = false;
|
|
52
|
+
this.pendingFlushTimer = setTimeout(() => {
|
|
53
|
+
this.pendingFlushTimer = null;
|
|
54
|
+
void this.flush();
|
|
55
|
+
}, 0);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Throttled update entry point.
|
|
61
|
+
*
|
|
62
|
+
* @param throttleMs - Minimum interval between flushes (varies by
|
|
63
|
+
* CardKit vs IM patch mode). Passed in by the caller so this
|
|
64
|
+
* controller remains business-logic-free.
|
|
65
|
+
*/
|
|
66
|
+
async throttledUpdate(throttleMs) {
|
|
67
|
+
if (!this.cardMessageReady()) return;
|
|
68
|
+
const now = Date.now();
|
|
69
|
+
const elapsed = now - this.lastUpdateTime;
|
|
70
|
+
if (elapsed >= throttleMs) {
|
|
71
|
+
this.cancelPendingFlush();
|
|
72
|
+
if (elapsed > THROTTLE_CONSTANTS.LONG_GAP_THRESHOLD_MS) {
|
|
73
|
+
this.lastUpdateTime = now;
|
|
74
|
+
this.pendingFlushTimer = setTimeout(() => {
|
|
75
|
+
this.pendingFlushTimer = null;
|
|
76
|
+
void this.flush();
|
|
77
|
+
}, THROTTLE_CONSTANTS.BATCH_AFTER_GAP_MS);
|
|
78
|
+
} else {
|
|
79
|
+
await this.flush();
|
|
80
|
+
}
|
|
81
|
+
} else if (!this.pendingFlushTimer) {
|
|
82
|
+
const delay = throttleMs - elapsed;
|
|
83
|
+
this.pendingFlushTimer = setTimeout(() => {
|
|
84
|
+
this.pendingFlushTimer = null;
|
|
85
|
+
void this.flush();
|
|
86
|
+
}, delay);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// ------------------------------------------------------------------
|
|
90
|
+
// Internal
|
|
91
|
+
// ------------------------------------------------------------------
|
|
92
|
+
/** Overridable gate: subclasses / consumers can set via setCardMessageReady. */
|
|
93
|
+
_cardMessageReady = false;
|
|
94
|
+
cardMessageReady() {
|
|
95
|
+
return this._cardMessageReady;
|
|
96
|
+
}
|
|
97
|
+
setCardMessageReady(ready) {
|
|
98
|
+
this._cardMessageReady = ready;
|
|
99
|
+
if (ready) {
|
|
100
|
+
this.lastUpdateTime = Date.now();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export {
|
|
105
|
+
FlushController
|
|
106
|
+
};
|
|
107
|
+
//# sourceMappingURL=flush-controller.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/card/flush-controller.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * Generic throttled flush controller.\n *\n * A pure scheduling primitive that manages timer-based throttling,\n * mutex-guarded flushing, and reflush-on-conflict. Contains no\n * business logic \u2014 the actual flush work is provided via a callback.\n */\n\nimport { THROTTLE_CONSTANTS } from './reply-dispatcher-types';\n\n// ---------------------------------------------------------------------------\n// FlushController\n// ---------------------------------------------------------------------------\n\nexport class FlushController {\n private flushInProgress = false;\n private flushResolvers: Array<() => void> = [];\n private needsReflush = false;\n private pendingFlushTimer: ReturnType<typeof setTimeout> | null = null;\n private lastUpdateTime = 0;\n private isCompleted = false;\n\n constructor(private readonly doFlush: () => Promise<void>) {}\n\n /** Mark the controller as completed \u2014 no more flushes after current one. */\n complete(): void {\n this.isCompleted = true;\n }\n\n /** Cancel any pending deferred flush timer. */\n cancelPendingFlush(): void {\n if (this.pendingFlushTimer) {\n clearTimeout(this.pendingFlushTimer);\n this.pendingFlushTimer = null;\n }\n }\n\n /** Wait for any in-progress flush to finish. */\n waitForFlush(): Promise<void> {\n if (!this.flushInProgress) return Promise.resolve();\n return new Promise<void>((resolve) => this.flushResolvers.push(resolve));\n }\n\n /**\n * Execute a flush (mutex-guarded, with reflush on conflict).\n *\n * If a flush is already in progress, marks needsReflush so a\n * follow-up flush fires immediately after the current one completes.\n */\n async flush(): Promise<void> {\n if (!this.cardMessageReady() || this.flushInProgress || this.isCompleted) {\n if (this.flushInProgress && !this.isCompleted) this.needsReflush = true;\n return;\n }\n this.flushInProgress = true;\n this.needsReflush = false;\n // Update timestamp BEFORE the API call to prevent concurrent callers\n // from also entering the flush (race condition fix).\n this.lastUpdateTime = Date.now();\n try {\n await this.doFlush();\n this.lastUpdateTime = Date.now();\n } finally {\n this.flushInProgress = false;\n const resolvers = this.flushResolvers;\n this.flushResolvers = [];\n for (const resolve of resolvers) resolve();\n\n // If events arrived while the API call was in flight,\n // schedule an immediate follow-up flush.\n if (this.needsReflush && !this.isCompleted && !this.pendingFlushTimer) {\n this.needsReflush = false;\n this.pendingFlushTimer = setTimeout(() => {\n this.pendingFlushTimer = null;\n void this.flush();\n }, 0);\n }\n }\n }\n\n /**\n * Throttled update entry point.\n *\n * @param throttleMs - Minimum interval between flushes (varies by\n * CardKit vs IM patch mode). Passed in by the caller so this\n * controller remains business-logic-free.\n */\n async throttledUpdate(throttleMs: number): Promise<void> {\n if (!this.cardMessageReady()) return;\n\n const now = Date.now();\n const elapsed = now - this.lastUpdateTime;\n\n if (elapsed >= throttleMs) {\n this.cancelPendingFlush();\n if (elapsed > THROTTLE_CONSTANTS.LONG_GAP_THRESHOLD_MS) {\n // After a long gap, batch briefly so the first visible update\n // contains meaningful text rather than just 1-2 characters.\n this.lastUpdateTime = now;\n this.pendingFlushTimer = setTimeout(() => {\n this.pendingFlushTimer = null;\n void this.flush();\n }, THROTTLE_CONSTANTS.BATCH_AFTER_GAP_MS);\n } else {\n await this.flush();\n }\n } else if (!this.pendingFlushTimer) {\n // Inside throttle window \u2014 schedule a deferred flush\n const delay = throttleMs - elapsed;\n this.pendingFlushTimer = setTimeout(() => {\n this.pendingFlushTimer = null;\n void this.flush();\n }, delay);\n }\n }\n\n // ------------------------------------------------------------------\n // Internal\n // ------------------------------------------------------------------\n\n /** Overridable gate: subclasses / consumers can set via setCardMessageReady. */\n private _cardMessageReady = false;\n\n cardMessageReady(): boolean {\n return this._cardMessageReady;\n }\n\n setCardMessageReady(ready: boolean): void {\n this._cardMessageReady = ready;\n if (ready) {\n // Initialize the timestamp so the first throttledUpdate sees a\n // small elapsed time (matching original behavior where\n // lastCardUpdateTime = Date.now() was set during card creation).\n this.lastUpdateTime = Date.now();\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "AAWA,SAAS,0BAA0B;AAM5B,MAAM,gBAAgB;AAAA,EAQ3B,YAA6B,SAA8B;AAA9B;AAAA,EAA+B;AAAA,EAPpD,kBAAkB;AAAA,EAClB,iBAAoC,CAAC;AAAA,EACrC,eAAe;AAAA,EACf,oBAA0D;AAAA,EAC1D,iBAAiB;AAAA,EACjB,cAAc;AAAA;AAAA,EAKtB,WAAiB;AACf,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA,EAGA,qBAA2B;AACzB,QAAI,KAAK,mBAAmB;AAC1B,mBAAa,KAAK,iBAAiB;AACnC,WAAK,oBAAoB;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA,EAGA,eAA8B;AAC5B,QAAI,CAAC,KAAK,gBAAiB,QAAO,QAAQ,QAAQ;AAClD,WAAO,IAAI,QAAc,CAAC,YAAY,KAAK,eAAe,KAAK,OAAO,CAAC;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,QAAuB;AAC3B,QAAI,CAAC,KAAK,iBAAiB,KAAK,KAAK,mBAAmB,KAAK,aAAa;AACxE,UAAI,KAAK,mBAAmB,CAAC,KAAK,YAAa,MAAK,eAAe;AACnE;AAAA,IACF;AACA,SAAK,kBAAkB;AACvB,SAAK,eAAe;AAGpB,SAAK,iBAAiB,KAAK,IAAI;AAC/B,QAAI;AACF,YAAM,KAAK,QAAQ;AACnB,WAAK,iBAAiB,KAAK,IAAI;AAAA,IACjC,UAAE;AACA,WAAK,kBAAkB;AACvB,YAAM,YAAY,KAAK;AACvB,WAAK,iBAAiB,CAAC;AACvB,iBAAW,WAAW,UAAW,SAAQ;AAIzC,UAAI,KAAK,gBAAgB,CAAC,KAAK,eAAe,CAAC,KAAK,mBAAmB;AACrE,aAAK,eAAe;AACpB,aAAK,oBAAoB,WAAW,MAAM;AACxC,eAAK,oBAAoB;AACzB,eAAK,KAAK,MAAM;AAAA,QAClB,GAAG,CAAC;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,gBAAgB,YAAmC;AACvD,QAAI,CAAC,KAAK,iBAAiB,EAAG;AAE9B,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,UAAU,MAAM,KAAK;AAE3B,QAAI,WAAW,YAAY;AACzB,WAAK,mBAAmB;AACxB,UAAI,UAAU,mBAAmB,uBAAuB;AAGtD,aAAK,iBAAiB;AACtB,aAAK,oBAAoB,WAAW,MAAM;AACxC,eAAK,oBAAoB;AACzB,eAAK,KAAK,MAAM;AAAA,QAClB,GAAG,mBAAmB,kBAAkB;AAAA,MAC1C,OAAO;AACL,cAAM,KAAK,MAAM;AAAA,MACnB;AAAA,IACF,WAAW,CAAC,KAAK,mBAAmB;AAElC,YAAM,QAAQ,aAAa;AAC3B,WAAK,oBAAoB,WAAW,MAAM;AACxC,aAAK,oBAAoB;AACzB,aAAK,KAAK,MAAM;AAAA,MAClB,GAAG,KAAK;AAAA,IACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,oBAAoB;AAAA,EAE5B,mBAA4B;AAC1B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,oBAAoB,OAAsB;AACxC,SAAK,oBAAoB;AACzB,QAAI,OAAO;AAIT,WAAK,iBAAiB,KAAK,IAAI;AAAA,IACjC;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
function optimizeMarkdownStyle(text, cardVersion = 2) {
|
|
2
|
+
try {
|
|
3
|
+
let r = _optimizeMarkdownStyle(text, cardVersion);
|
|
4
|
+
r = stripInvalidImageKeys(r);
|
|
5
|
+
return r;
|
|
6
|
+
} catch {
|
|
7
|
+
return text;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function _optimizeMarkdownStyle(text, cardVersion = 2) {
|
|
11
|
+
const MARK = "___CB_";
|
|
12
|
+
const codeBlocks = [];
|
|
13
|
+
let r = text.replace(/```[\s\S]*?```/g, (m) => {
|
|
14
|
+
return `${MARK}${codeBlocks.push(m) - 1}___`;
|
|
15
|
+
});
|
|
16
|
+
const hasH1toH3 = /^#{1,3} /m.test(text);
|
|
17
|
+
if (hasH1toH3) {
|
|
18
|
+
r = r.replace(/^#{2,6} (.+)$/gm, "##### $1");
|
|
19
|
+
r = r.replace(/^# (.+)$/gm, "#### $1");
|
|
20
|
+
}
|
|
21
|
+
if (cardVersion >= 2) {
|
|
22
|
+
r = r.replace(/^(#{4,5} .+)\n{1,2}(#{4,5} )/gm, "$1\n<br>\n$2");
|
|
23
|
+
r = r.replace(/^([^|\n].*)\n(\|.+\|)/gm, "$1\n\n$2");
|
|
24
|
+
r = r.replace(/\n\n((?:\|.+\|[^\S\n]*\n?)+)/g, "\n\n<br>\n\n$1");
|
|
25
|
+
r = r.replace(/((?:^\|.+\|[^\S\n]*\n?)+)/gm, "$1\n<br>\n");
|
|
26
|
+
r = r.replace(/^((?!#{4,5} )(?!\*\*).+)\n\n(<br>)\n\n(\|)/gm, "$1\n$2\n$3");
|
|
27
|
+
r = r.replace(/^(\*\*.+)\n\n(<br>)\n\n(\|)/gm, "$1\n$2\n\n$3");
|
|
28
|
+
r = r.replace(/(\|[^\n]*\n)\n(<br>\n)((?!#{4,5} )(?!\*\*))/gm, "$1$2$3");
|
|
29
|
+
codeBlocks.forEach((block, i) => {
|
|
30
|
+
r = r.replace(`${MARK}${i}___`, `
|
|
31
|
+
<br>
|
|
32
|
+
${block}
|
|
33
|
+
<br>
|
|
34
|
+
`);
|
|
35
|
+
});
|
|
36
|
+
} else {
|
|
37
|
+
codeBlocks.forEach((block, i) => {
|
|
38
|
+
r = r.replace(`${MARK}${i}___`, block);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
r = r.replace(/\n{3,}/g, "\n\n");
|
|
42
|
+
return r;
|
|
43
|
+
}
|
|
44
|
+
const IMAGE_RE = /!\[([^\]]*)\]\(([^)\s]+)\)/g;
|
|
45
|
+
function stripInvalidImageKeys(text) {
|
|
46
|
+
if (!text.includes("![")) return text;
|
|
47
|
+
return text.replace(IMAGE_RE, (fullMatch, _alt, value) => {
|
|
48
|
+
if (value.startsWith("img_")) return fullMatch;
|
|
49
|
+
if (value.startsWith("http://")) return fullMatch;
|
|
50
|
+
if (value.startsWith("https://")) return fullMatch;
|
|
51
|
+
return value;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
optimizeMarkdownStyle
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=markdown-style.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/card/markdown-style.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * Markdown \u6837\u5F0F\u4F18\u5316\u5DE5\u5177\n */\n\n/**\n * \u4F18\u5316 Markdown \u6837\u5F0F\uFF1A\n * - \u6807\u9898\u964D\u7EA7\uFF1AH1 \u2192 H4\uFF0CH2~H6 \u2192 H5\n * - \u8868\u683C\u524D\u540E\u589E\u52A0\u6BB5\u843D\u95F4\u8DDD\n * - \u6709\u5E8F\u5217\u8868\uFF1A\u5E8F\u53F7\u540E\u786E\u4FDD\u53EA\u6709\u4E00\u4E2A\u7A7A\u683C\n * - \u65E0\u5E8F\u5217\u8868\uFF1A\"- \" \u683C\u5F0F\u89C4\u8303\u5316\uFF08\u8DF3\u8FC7\u5206\u9694\u7EBF ---\uFF09\n * - \u8868\u683C\uFF1A\u5355\u5143\u683C\u524D\u540E\u8865\u7A7A\u683C\uFF0C\u5206\u9694\u7B26\u884C\u89C4\u8303\u5316\uFF0C\u8868\u683C\u524D\u540E\u52A0\u7A7A\u884C\n * - \u4EE3\u7801\u5757\u5185\u5BB9\u4E0D\u53D7\u5F71\u54CD\n */\nexport function optimizeMarkdownStyle(text: string, cardVersion = 2): string {\n try {\n let r = _optimizeMarkdownStyle(text, cardVersion);\n r = stripInvalidImageKeys(r);\n return r;\n } catch {\n return text;\n }\n}\n\nfunction _optimizeMarkdownStyle(text: string, cardVersion = 2): string {\n // \u2500\u2500 1. \u63D0\u53D6\u4EE3\u7801\u5757\uFF0C\u7528\u5360\u4F4D\u7B26\u4FDD\u62A4\uFF0C\u5904\u7406\u540E\u518D\u8FD8\u539F \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const MARK = '___CB_';\n const codeBlocks: string[] = [];\n let r = text.replace(/```[\\s\\S]*?```/g, (m) => {\n return `${MARK}${codeBlocks.push(m) - 1}___`;\n });\n\n // \u2500\u2500 2. \u6807\u9898\u964D\u7EA7 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // \u53EA\u6709\u5F53\u539F\u6587\u6863\u5305\u542B h1~h3 \u6807\u9898\u65F6\u624D\u6267\u884C\u964D\u7EA7\n // \u5148\u5904\u7406 H2~H6 \u2192 H5\uFF0C\u518D\u5904\u7406 H1 \u2192 H4\n // \u987A\u5E8F\u4E0D\u80FD\u98A0\u5012\uFF1A\u82E5\u5148 H1\u2192H4\uFF0CH4\uFF08####\uFF09\u4F1A\u88AB\u540E\u9762\u7684 #{2,6} \u518D\u6B21\u5339\u914D\u6210 H5\n const hasH1toH3 = /^#{1,3} /m.test(text);\n if (hasH1toH3) {\n r = r.replace(/^#{2,6} (.+)$/gm, '##### $1'); // H2~H6 \u2192 H5\n r = r.replace(/^# (.+)$/gm, '#### $1'); // H1 \u2192 H4\n }\n\n if (cardVersion >= 2) {\n // \u2500\u2500 3. \u8FDE\u7EED\u6807\u9898\u95F4\u589E\u52A0\u6BB5\u843D\u95F4\u8DDD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n r = r.replace(/^(#{4,5} .+)\\n{1,2}(#{4,5} )/gm, '$1\\n<br>\\n$2');\n\n // \u2500\u2500 4. \u8868\u683C\u524D\u540E\u589E\u52A0\u6BB5\u843D\u95F4\u8DDD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // 4a. \u975E\u8868\u683C\u884C\u76F4\u63A5\u8DDF\u8868\u683C\u884C\u65F6\uFF0C\u5148\u8865\u4E00\u4E2A\u7A7A\u884C\n r = r.replace(/^([^|\\n].*)\\n(\\|.+\\|)/gm, '$1\\n\\n$2');\n // 4b. \u8868\u683C\u524D\uFF1A\u5728\u7A7A\u884C\u4E4B\u524D\u63D2\u5165 <br>\uFF08\u5373 \\n\\n| \u2192 \\n<br>\\n\\n| \uFF09\n r = r.replace(/\\n\\n((?:\\|.+\\|[^\\S\\n]*\\n?)+)/g, '\\n\\n<br>\\n\\n$1');\n // 4c. \u8868\u683C\u540E\uFF1A\u5728\u8868\u683C\u5757\u672B\u5C3E\u8FFD\u52A0 <br>\n r = r.replace(/((?:^\\|.+\\|[^\\S\\n]*\\n?)+)/gm, '$1\\n<br>\\n');\n // 4d. \u8868\u683C\u524D\u662F\u666E\u901A\u6587\u672C\uFF08\u975E\u6807\u9898\u3001\u975E\u52A0\u7C97\u884C\uFF09\u65F6\uFF0C\u53EA\u9700 <br>\uFF0C\u53BB\u6389\u591A\u4F59\u7A7A\u884C\n // \"text\\n\\n<br>\\n\\n|\" \u2192 \"text\\n<br>\\n|\"\n r = r.replace(/^((?!#{4,5} )(?!\\*\\*).+)\\n\\n(<br>)\\n\\n(\\|)/gm, '$1\\n$2\\n$3');\n // 4d2. \u8868\u683C\u524D\u662F\u52A0\u7C97\u884C\u65F6\uFF0C<br> \u7D27\u8D34\u52A0\u7C97\u884C\uFF0C\u7A7A\u884C\u4FDD\u7559\u5728\u540E\u9762\n // \"**bold**\\n\\n<br>\\n\\n|\" \u2192 \"**bold**\\n<br>\\n\\n|\"\n r = r.replace(/^(\\*\\*.+)\\n\\n(<br>)\\n\\n(\\|)/gm, '$1\\n$2\\n\\n$3');\n // 4e. \u8868\u683C\u540E\u662F\u666E\u901A\u6587\u672C\uFF08\u975E\u6807\u9898\u3001\u975E\u52A0\u7C97\u884C\uFF09\u65F6\uFF0C\u53EA\u9700 <br>\uFF0C\u53BB\u6389\u591A\u4F59\u7A7A\u884C\n // \"| row |\\n\\n<br>\\ntext\" \u2192 \"| row |\\n<br>\\ntext\"\n r = r.replace(/(\\|[^\\n]*\\n)\\n(<br>\\n)((?!#{4,5} )(?!\\*\\*))/gm, '$1$2$3');\n\n // \u2500\u2500 5. \u8FD8\u539F\u4EE3\u7801\u5757\uFF0C\u5E76\u5728\u524D\u540E\u8FFD\u52A0 <br> \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n codeBlocks.forEach((block, i) => {\n r = r.replace(`${MARK}${i}___`, `\\n<br>\\n${block}\\n<br>\\n`);\n });\n } else {\n // \u2500\u2500 5. \u8FD8\u539F\u4EE3\u7801\u5757\uFF08\u65E0 <br>\uFF09\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n codeBlocks.forEach((block, i) => {\n r = r.replace(`${MARK}${i}___`, block);\n });\n }\n\n // \u2500\u2500 6. \u538B\u7F29\u591A\u4F59\u7A7A\u884C\uFF083 \u4E2A\u4EE5\u4E0A\u8FDE\u7EED\u6362\u884C \u2192 2 \u4E2A\uFF09\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n r = r.replace(/\\n{3,}/g, '\\n\\n');\n\n return r;\n}\n\n// ---------------------------------------------------------------------------\n// stripInvalidImageKeys\n// ---------------------------------------------------------------------------\n\n/** Matches complete markdown image syntax: `` */\nconst IMAGE_RE = /!\\[([^\\]]*)\\]\\(([^)\\s]+)\\)/g;\n\n/**\n * Strip `` where value is not a valid Feishu image key\n * (`img_xxx`) or remote URL. Prevents CardKit error 200570.\n */\nfunction stripInvalidImageKeys(text: string): string {\n if (!text.includes('![')) return text;\n return text.replace(IMAGE_RE, (fullMatch, _alt, value) => {\n if (value.startsWith('img_')) return fullMatch;\n if (value.startsWith('http://')) return fullMatch;\n if (value.startsWith('https://')) return fullMatch;\n return value;\n });\n}\n"],
|
|
5
|
+
"mappings": "AAgBO,SAAS,sBAAsB,MAAc,cAAc,GAAW;AAC3E,MAAI;AACF,QAAI,IAAI,uBAAuB,MAAM,WAAW;AAChD,QAAI,sBAAsB,CAAC;AAC3B,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,uBAAuB,MAAc,cAAc,GAAW;AAErE,QAAM,OAAO;AACb,QAAM,aAAuB,CAAC;AAC9B,MAAI,IAAI,KAAK,QAAQ,mBAAmB,CAAC,MAAM;AAC7C,WAAO,GAAG,IAAI,GAAG,WAAW,KAAK,CAAC,IAAI,CAAC;AAAA,EACzC,CAAC;AAMD,QAAM,YAAY,YAAY,KAAK,IAAI;AACvC,MAAI,WAAW;AACb,QAAI,EAAE,QAAQ,mBAAmB,UAAU;AAC3C,QAAI,EAAE,QAAQ,cAAc,SAAS;AAAA,EACvC;AAEA,MAAI,eAAe,GAAG;AAEpB,QAAI,EAAE,QAAQ,kCAAkC,cAAc;AAI9D,QAAI,EAAE,QAAQ,2BAA2B,UAAU;AAEnD,QAAI,EAAE,QAAQ,iCAAiC,gBAAgB;AAE/D,QAAI,EAAE,QAAQ,+BAA+B,YAAY;AAGzD,QAAI,EAAE,QAAQ,gDAAgD,YAAY;AAG1E,QAAI,EAAE,QAAQ,iCAAiC,cAAc;AAG7D,QAAI,EAAE,QAAQ,iDAAiD,QAAQ;AAGvE,eAAW,QAAQ,CAAC,OAAO,MAAM;AAC/B,UAAI,EAAE,QAAQ,GAAG,IAAI,GAAG,CAAC,OAAO;AAAA;AAAA,EAAW,KAAK;AAAA;AAAA,CAAU;AAAA,IAC5D,CAAC;AAAA,EACH,OAAO;AAEL,eAAW,QAAQ,CAAC,OAAO,MAAM;AAC/B,UAAI,EAAE,QAAQ,GAAG,IAAI,GAAG,CAAC,OAAO,KAAK;AAAA,IACvC,CAAC;AAAA,EACH;AAGA,MAAI,EAAE,QAAQ,WAAW,MAAM;AAE/B,SAAO;AACT;AAOA,MAAM,WAAW;AAMjB,SAAS,sBAAsB,MAAsB;AACnD,MAAI,CAAC,KAAK,SAAS,IAAI,EAAG,QAAO;AACjC,SAAO,KAAK,QAAQ,UAAU,CAAC,WAAW,MAAM,UAAU;AACxD,QAAI,MAAM,WAAW,MAAM,EAAG,QAAO;AACrC,QAAI,MAAM,WAAW,SAAS,EAAG,QAAO;AACxC,QAAI,MAAM,WAAW,UAAU,EAAG,QAAO;AACzC,WAAO;AAAA,EACT,CAAC;AACH;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const CARD_PHASES = {
|
|
2
|
+
idle: "idle",
|
|
3
|
+
creating: "creating",
|
|
4
|
+
streaming: "streaming",
|
|
5
|
+
completed: "completed",
|
|
6
|
+
aborted: "aborted",
|
|
7
|
+
terminated: "terminated",
|
|
8
|
+
creation_failed: "creation_failed"
|
|
9
|
+
};
|
|
10
|
+
const TERMINAL_PHASES = /* @__PURE__ */ new Set([
|
|
11
|
+
"completed",
|
|
12
|
+
"aborted",
|
|
13
|
+
"terminated",
|
|
14
|
+
"creation_failed"
|
|
15
|
+
]);
|
|
16
|
+
const PHASE_TRANSITIONS = {
|
|
17
|
+
idle: /* @__PURE__ */ new Set(["creating", "aborted", "terminated"]),
|
|
18
|
+
creating: /* @__PURE__ */ new Set(["streaming", "creation_failed", "aborted", "terminated"]),
|
|
19
|
+
streaming: /* @__PURE__ */ new Set(["completed", "aborted", "terminated"]),
|
|
20
|
+
completed: /* @__PURE__ */ new Set(),
|
|
21
|
+
aborted: /* @__PURE__ */ new Set(),
|
|
22
|
+
terminated: /* @__PURE__ */ new Set(),
|
|
23
|
+
creation_failed: /* @__PURE__ */ new Set()
|
|
24
|
+
};
|
|
25
|
+
const THROTTLE_CONSTANTS = {
|
|
26
|
+
CARDKIT_MS: 100,
|
|
27
|
+
PATCH_MS: 1500,
|
|
28
|
+
LONG_GAP_THRESHOLD_MS: 2e3,
|
|
29
|
+
BATCH_AFTER_GAP_MS: 300
|
|
30
|
+
};
|
|
31
|
+
const EMPTY_REPLY_FALLBACK_TEXT = "Done.";
|
|
32
|
+
export {
|
|
33
|
+
CARD_PHASES,
|
|
34
|
+
EMPTY_REPLY_FALLBACK_TEXT,
|
|
35
|
+
PHASE_TRANSITIONS,
|
|
36
|
+
TERMINAL_PHASES,
|
|
37
|
+
THROTTLE_CONSTANTS
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=reply-dispatcher-types.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/card/reply-dispatcher-types.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * Type definitions for the Feishu reply dispatcher subsystem.\n *\n * Consolidates all interfaces, state shapes, and constants used across\n * reply-dispatcher.ts, streaming-card-controller.ts, flush-controller.ts,\n * and unavailable-guard.ts.\n */\n\nimport type { ClawdbotConfig, ReplyPayload } from 'openclaw/plugin-sdk';\nimport type { FeishuFooterConfig } from '../core/types';\n\n// ---------------------------------------------------------------------------\n// CardPhase \u2014 explicit state machine replacing boolean flags\n// ---------------------------------------------------------------------------\n\nexport const CARD_PHASES = {\n idle: 'idle',\n creating: 'creating',\n streaming: 'streaming',\n completed: 'completed',\n aborted: 'aborted',\n terminated: 'terminated',\n creation_failed: 'creation_failed',\n} as const;\n\nexport type CardPhase = (typeof CARD_PHASES)[keyof typeof CARD_PHASES];\n\nexport const TERMINAL_PHASES: ReadonlySet<CardPhase> = new Set([\n 'completed',\n 'aborted',\n 'terminated',\n 'creation_failed',\n]);\n\n/**\n * Why a terminal phase was entered.\n *\n * - `normal` \u2014 streaming completed successfully (onIdle).\n * - `error` \u2014 an error occurred during reply generation (onError).\n * - `abort` \u2014 explicitly cancelled by the caller (abortCard).\n * - `unavailable` \u2014 source message was deleted/recalled (UnavailableGuard).\n * - `creation_failed` \u2014 card creation failed, falling back to static delivery.\n */\nexport type TerminalReason = 'normal' | 'error' | 'abort' | 'unavailable' | 'creation_failed';\n\nexport const PHASE_TRANSITIONS: Record<CardPhase, ReadonlySet<CardPhase>> = {\n idle: new Set(['creating', 'aborted', 'terminated']),\n creating: new Set(['streaming', 'creation_failed', 'aborted', 'terminated']),\n streaming: new Set(['completed', 'aborted', 'terminated']),\n completed: new Set(),\n aborted: new Set(),\n terminated: new Set(),\n creation_failed: new Set(),\n};\n\n// ---------------------------------------------------------------------------\n// Structured state aggregates\n// ---------------------------------------------------------------------------\n\nexport interface ReasoningState {\n accumulatedReasoningText: string;\n reasoningStartTime: number | null;\n reasoningElapsedMs: number;\n isReasoningPhase: boolean;\n}\n\nexport interface StreamingTextState {\n accumulatedText: string;\n completedText: string;\n streamingPrefix: string;\n lastPartialText: string;\n}\n\nexport interface CardKitState {\n cardKitCardId: string | null;\n originalCardKitCardId: string | null;\n cardKitSequence: number;\n cardMessageId: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// Throttle constants\n// ---------------------------------------------------------------------------\n\n/**\n * Throttle intervals for card updates.\n *\n * - `CARDKIT_MS`: CardKit `cardElement.content()` \u2014 designed for streaming,\n * low throttle is fine.\n * - `PATCH_MS`: `im.message.patch` \u2014 strict rate limits (code 230020).\n * - `LONG_GAP_THRESHOLD_MS`: After a long idle gap (tool call / LLM thinking),\n * defer the first flush briefly.\n * - `BATCH_AFTER_GAP_MS`: Batching window after a long gap.\n */\nexport const THROTTLE_CONSTANTS = {\n CARDKIT_MS: 100,\n PATCH_MS: 1500,\n LONG_GAP_THRESHOLD_MS: 2000,\n BATCH_AFTER_GAP_MS: 300,\n} as const;\n\nexport const EMPTY_REPLY_FALLBACK_TEXT = 'Done.';\n\n// ---------------------------------------------------------------------------\n// Factory params and result\n// ---------------------------------------------------------------------------\n\nexport interface CreateFeishuReplyDispatcherParams {\n cfg: ClawdbotConfig;\n agentId: string;\n chatId: string;\n replyToMessageId?: string;\n /** Account ID for multi-account support. */\n accountId?: string;\n /** Chat type for scene-aware reply mode selection. */\n chatType?: 'p2p' | 'group';\n /** When true, typing indicators are suppressed entirely. */\n skipTyping?: boolean;\n /** When true, replies are sent into the thread instead of main chat. */\n replyInThread?: boolean;\n}\n\n/**\n * Manual mirror of the SDK-internal ReplyDispatcher type\n * (from openclaw/plugin-sdk auto-reply/reply/reply-dispatcher.d.ts).\n *\n * Must be kept in sync when the SDK updates the dispatcher signature.\n */\nexport interface ReplyDispatcher {\n sendToolResult: (payload: ReplyPayload) => boolean;\n sendBlockReply: (payload: ReplyPayload) => boolean;\n sendFinalReply: (payload: ReplyPayload) => boolean;\n waitForIdle: () => Promise<void>;\n getQueuedCounts: () => Record<string, number>;\n markComplete: () => void;\n}\n\n/**\n * The structured return type of createFeishuReplyDispatcher.\n *\n * `replyOptions` is typed as `Record<string, unknown>` because the consumer\n * (`dispatchReplyFromConfig`) accepts the SDK-internal `GetReplyOptions`\n * which is not re-exported from `openclaw/plugin-sdk`. The record type\n * is compatible with spread-assignment into `dispatchReplyFromConfig`.\n */\nexport interface FeishuReplyDispatcherResult {\n dispatcher: ReplyDispatcher;\n replyOptions: Record<string, unknown>;\n markDispatchIdle: () => void;\n markFullyComplete: () => void;\n abortCard: () => Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// StreamingCardController dependencies (injected via constructor)\n// ---------------------------------------------------------------------------\n\nexport interface StreamingCardDeps {\n cfg: ClawdbotConfig;\n accountId: string | undefined;\n chatId: string;\n replyToMessageId: string | undefined;\n replyInThread: boolean | undefined;\n resolvedFooter: Required<FeishuFooterConfig>;\n}\n"],
|
|
5
|
+
"mappings": "AAkBO,MAAM,cAAc;AAAA,EACzB,MAAM;AAAA,EACN,UAAU;AAAA,EACV,WAAW;AAAA,EACX,WAAW;AAAA,EACX,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,iBAAiB;AACnB;AAIO,MAAM,kBAA0C,oBAAI,IAAI;AAAA,EAC7D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAaM,MAAM,oBAA+D;AAAA,EAC1E,MAAM,oBAAI,IAAI,CAAC,YAAY,WAAW,YAAY,CAAC;AAAA,EACnD,UAAU,oBAAI,IAAI,CAAC,aAAa,mBAAmB,WAAW,YAAY,CAAC;AAAA,EAC3E,WAAW,oBAAI,IAAI,CAAC,aAAa,WAAW,YAAY,CAAC;AAAA,EACzD,WAAW,oBAAI,IAAI;AAAA,EACnB,SAAS,oBAAI,IAAI;AAAA,EACjB,YAAY,oBAAI,IAAI;AAAA,EACpB,iBAAiB,oBAAI,IAAI;AAC3B;AAyCO,MAAM,qBAAqB;AAAA,EAChC,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,uBAAuB;AAAA,EACvB,oBAAoB;AACtB;AAEO,MAAM,4BAA4B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|