@openclaw/feishu 2026.7.2-beta.2 → 2026.7.2-beta.4

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.
Files changed (149) hide show
  1. package/dist/api.js +4 -4
  2. package/dist/{app-registration-BzkyrVZu.js → app-registration-cN1bVV6s.js} +5 -5
  3. package/dist/{channel-X30GQVwc.js → channel-DB1x6UJX.js} +33 -24
  4. package/dist/channel-plugin-api.js +1 -1
  5. package/dist/{channel.runtime-By2uqa3Q.js → channel.runtime-B5yAAvbT.js} +102 -17
  6. package/dist/{client-87BmeMpj.js → client-Dee7cKsS.js} +62 -1
  7. package/dist/{doctor-contract-DXH5hux1.js → doctor-contract-Cw5sdjOm.js} +29 -41
  8. package/dist/doctor-contract-api.js +1 -1
  9. package/dist/{drive-B4E8OXZ0.js → drive-_zrcOxzS.js} +2 -2
  10. package/dist/{send-DrWM_Ilf.js → media-CRJunSRr.js} +1075 -1017
  11. package/dist/{monitor-CHl0bWzb.js → monitor-8CLu6myv.js} +5 -4
  12. package/dist/{monitor.account-BSRV2hIF.js → monitor.account-CkYj45PC.js} +2113 -809
  13. package/dist/monitor.startup-CSUPT_U1.js +143 -0
  14. package/dist/{probe-BgboTHIn.js → probe-Za1kgUvx.js} +70 -10
  15. package/dist/{secret-contract-DnlMcrn5.js → secret-contract-BCpDLdg9.js} +17 -26
  16. package/dist/secret-contract-api.js +1 -1
  17. package/dist/{send-result-DsqTk27v.js → send-result-DfE5Fhz6.js} +22 -11
  18. package/dist/setup-api.js +1 -1
  19. package/node_modules/@larksuiteoapi/node-sdk/README.md +13 -0
  20. package/node_modules/@larksuiteoapi/node-sdk/README.zh.md +12 -0
  21. package/node_modules/@larksuiteoapi/node-sdk/es/index.js +8950 -3084
  22. package/node_modules/@larksuiteoapi/node-sdk/lib/index.js +8951 -3083
  23. package/node_modules/@larksuiteoapi/node-sdk/package.json +1 -1
  24. package/node_modules/@larksuiteoapi/node-sdk/types/index.d.ts +12522 -698
  25. package/node_modules/@protobufjs/utf8/CHANGELOG.md +8 -0
  26. package/node_modules/@protobufjs/utf8/index.js +29 -18
  27. package/node_modules/@protobufjs/utf8/package.json +2 -2
  28. package/node_modules/@protobufjs/utf8/tests/index.js +5 -0
  29. package/node_modules/@types/node/README.md +1 -1
  30. package/node_modules/@types/node/fs/promises.d.ts +16 -6
  31. package/node_modules/@types/node/package.json +2 -2
  32. package/node_modules/agent-base/README.md +145 -0
  33. package/node_modules/agent-base/dist/src/index.d.ts +78 -0
  34. package/node_modules/agent-base/dist/src/index.js +203 -0
  35. package/node_modules/agent-base/dist/src/index.js.map +1 -0
  36. package/node_modules/agent-base/dist/src/promisify.d.ts +4 -0
  37. package/node_modules/agent-base/dist/src/promisify.js +18 -0
  38. package/node_modules/agent-base/dist/src/promisify.js.map +1 -0
  39. package/node_modules/agent-base/package.json +64 -0
  40. package/node_modules/agent-base/src/index.ts +345 -0
  41. package/node_modules/agent-base/src/promisify.ts +33 -0
  42. package/node_modules/axios/CHANGELOG.md +197 -1
  43. package/node_modules/axios/README.md +424 -256
  44. package/node_modules/axios/dist/axios.js +589 -204
  45. package/node_modules/axios/dist/axios.min.js +3 -3
  46. package/node_modules/axios/dist/axios.min.js.map +1 -1
  47. package/node_modules/axios/dist/browser/axios.cjs +630 -185
  48. package/node_modules/axios/dist/esm/axios.js +630 -185
  49. package/node_modules/axios/dist/esm/axios.min.js +2 -2
  50. package/node_modules/axios/dist/esm/axios.min.js.map +1 -1
  51. package/node_modules/axios/dist/node/axios.cjs +949 -301
  52. package/node_modules/axios/index.d.cts +28 -5
  53. package/node_modules/axios/index.d.ts +24 -3
  54. package/node_modules/axios/lib/adapters/adapters.js +1 -1
  55. package/node_modules/axios/lib/adapters/fetch.js +223 -49
  56. package/node_modules/axios/lib/adapters/http.js +408 -193
  57. package/node_modules/axios/lib/adapters/xhr.js +3 -1
  58. package/node_modules/axios/lib/core/Axios.js +4 -2
  59. package/node_modules/axios/lib/core/AxiosError.js +13 -1
  60. package/node_modules/axios/lib/core/AxiosHeaders.js +13 -42
  61. package/node_modules/axios/lib/core/buildFullPath.js +29 -1
  62. package/node_modules/axios/lib/core/mergeConfig.js +35 -0
  63. package/node_modules/axios/lib/defaults/transitional.js +2 -0
  64. package/node_modules/axios/lib/env/data.js +1 -1
  65. package/node_modules/axios/lib/helpers/AxiosURLSearchParams.js +1 -3
  66. package/node_modules/axios/lib/helpers/Http2Sessions.js +119 -0
  67. package/node_modules/axios/lib/helpers/buildURL.js +7 -4
  68. package/node_modules/axios/lib/helpers/composeSignals.js +48 -47
  69. package/node_modules/axios/lib/helpers/cookies.js +5 -1
  70. package/node_modules/axios/lib/helpers/estimateDataURLDecodedBytes.js +16 -11
  71. package/node_modules/axios/lib/helpers/formDataToJSON.js +26 -4
  72. package/node_modules/axios/lib/helpers/formDataToStream.js +2 -2
  73. package/node_modules/axios/lib/helpers/fromDataURI.js +20 -5
  74. package/node_modules/axios/lib/helpers/progressEventReducer.js +3 -0
  75. package/node_modules/axios/lib/helpers/resolveConfig.js +26 -13
  76. package/node_modules/axios/lib/helpers/sanitizeHeaderValue.js +60 -0
  77. package/node_modules/axios/lib/helpers/shouldBypassProxy.js +33 -1
  78. package/node_modules/axios/lib/helpers/toFormData.js +48 -12
  79. package/node_modules/axios/lib/helpers/validator.js +1 -1
  80. package/node_modules/axios/lib/utils.js +105 -19
  81. package/node_modules/axios/package.json +31 -13
  82. package/node_modules/https-proxy-agent/README.md +137 -0
  83. package/node_modules/https-proxy-agent/dist/agent.d.ts +30 -0
  84. package/node_modules/https-proxy-agent/dist/agent.js +177 -0
  85. package/node_modules/https-proxy-agent/dist/agent.js.map +1 -0
  86. package/node_modules/https-proxy-agent/dist/index.d.ts +23 -0
  87. package/node_modules/https-proxy-agent/dist/index.js +14 -0
  88. package/node_modules/https-proxy-agent/dist/index.js.map +1 -0
  89. package/node_modules/https-proxy-agent/dist/parse-proxy-response.d.ts +7 -0
  90. package/node_modules/https-proxy-agent/dist/parse-proxy-response.js +66 -0
  91. package/node_modules/https-proxy-agent/dist/parse-proxy-response.js.map +1 -0
  92. package/node_modules/https-proxy-agent/package.json +56 -0
  93. package/node_modules/protobufjs/dist/light/protobuf.js +145 -188
  94. package/node_modules/protobufjs/dist/light/protobuf.js.map +1 -1
  95. package/node_modules/protobufjs/dist/light/protobuf.min.js +3 -3
  96. package/node_modules/protobufjs/dist/light/protobuf.min.js.map +1 -1
  97. package/node_modules/protobufjs/dist/minimal/protobuf.js +33 -76
  98. package/node_modules/protobufjs/dist/minimal/protobuf.js.map +1 -1
  99. package/node_modules/protobufjs/dist/minimal/protobuf.min.js +3 -3
  100. package/node_modules/protobufjs/dist/minimal/protobuf.min.js.map +1 -1
  101. package/node_modules/protobufjs/dist/protobuf.js +168 -208
  102. package/node_modules/protobufjs/dist/protobuf.js.map +1 -1
  103. package/node_modules/protobufjs/dist/protobuf.min.js +3 -3
  104. package/node_modules/protobufjs/dist/protobuf.min.js.map +1 -1
  105. package/node_modules/protobufjs/index.d.ts +0 -8
  106. package/node_modules/protobufjs/package.json +2 -3
  107. package/node_modules/protobufjs/src/parse.js +3 -0
  108. package/node_modules/protobufjs/src/util/minimal.js +0 -3
  109. package/node_modules/qs/CHANGELOG.md +11 -0
  110. package/node_modules/qs/dist/qs.js +17 -17
  111. package/node_modules/qs/lib/parse.js +19 -8
  112. package/node_modules/qs/lib/utils.js +47 -8
  113. package/node_modules/qs/package.json +6 -5
  114. package/node_modules/qs/test/parse.js +230 -0
  115. package/node_modules/qs/test/utils.js +194 -0
  116. package/node_modules/typebox/build/compile/validator.d.mts +1 -4
  117. package/node_modules/typebox/build/guard/guard.d.mts +1 -1
  118. package/node_modules/typebox/build/guard/guard.mjs +5 -2
  119. package/node_modules/typebox/build/guard/string.mjs +16 -4
  120. package/node_modules/typebox/build/schema/engine/_functions.mjs +34 -15
  121. package/node_modules/typebox/build/type/action/readonly_object.d.mts +5 -0
  122. package/node_modules/typebox/build/type/action/readonly_object.mjs +8 -0
  123. package/node_modules/typebox/build/typebox.d.mts +1 -1
  124. package/node_modules/typebox/build/typebox.mjs +1 -1
  125. package/node_modules/typebox/package.json +1 -1
  126. package/node_modules/typebox/readme.md +29 -32
  127. package/node_modules/ws/lib/receiver.js +15 -32
  128. package/node_modules/ws/lib/websocket-server.js +4 -4
  129. package/node_modules/ws/lib/websocket.js +4 -4
  130. package/node_modules/ws/package.json +5 -1
  131. package/npm-shrinkwrap.json +58 -38
  132. package/openclaw.plugin.json +26 -10
  133. package/package.json +20 -7
  134. package/dist/monitor.startup-Cy8NPGAX.js +0 -43
  135. package/node_modules/@protobufjs/inquire/CHANGELOG.md +0 -8
  136. package/node_modules/@protobufjs/inquire/LICENSE +0 -26
  137. package/node_modules/@protobufjs/inquire/README.md +0 -13
  138. package/node_modules/@protobufjs/inquire/index.d.ts +0 -10
  139. package/node_modules/@protobufjs/inquire/index.js +0 -38
  140. package/node_modules/@protobufjs/inquire/package.json +0 -21
  141. package/node_modules/@protobufjs/inquire/tests/data/array.js +0 -1
  142. package/node_modules/@protobufjs/inquire/tests/data/emptyArray.js +0 -1
  143. package/node_modules/@protobufjs/inquire/tests/data/emptyObject.js +0 -1
  144. package/node_modules/@protobufjs/inquire/tests/data/object.js +0 -1
  145. package/node_modules/@protobufjs/inquire/tests/index.js +0 -20
  146. package/node_modules/axios/dist/axios.js.map +0 -1
  147. package/node_modules/axios/dist/browser/axios.cjs.map +0 -1
  148. package/node_modules/axios/dist/esm/axios.js.map +0 -1
  149. package/node_modules/axios/dist/node/axios.cjs.map +0 -1
package/dist/api.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { r as listEnabledFeishuAccounts } from "./accounts-BDoGHJDk.js";
2
- import { a as setFeishuNamedAccountEnabled, i as feishuSetupAdapter, n as feishuSetupWizard, r as runFeishuLogin, t as feishuPlugin } from "./channel-X30GQVwc.js";
3
- import { p as parseFeishuMarkdown, u as chunkFeishuMarkdown } from "./send-result-DsqTk27v.js";
2
+ import { a as setFeishuNamedAccountEnabled, i as feishuSetupAdapter, n as feishuSetupWizard, r as runFeishuLogin, t as feishuPlugin } from "./channel-DB1x6UJX.js";
3
+ import { p as parseFeishuMarkdown, u as chunkFeishuMarkdown } from "./send-result-DfE5Fhz6.js";
4
4
  import { a as parseFeishuTargetId, i as parseFeishuDirectConversationId, n as buildFeishuModelOverrideParentCandidates, r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-BeJL-wq7.js";
5
- import { r as createFeishuClient, s as resolveConfiguredHttpTimeoutMs } from "./client-87BmeMpj.js";
5
+ import { r as createFeishuClient, s as resolveConfiguredHttpTimeoutMs } from "./client-Dee7cKsS.js";
6
6
  import { t as getFeishuRuntime } from "./runtime-C5JxBWZp.js";
7
- import { a as toolExecutionErrorResult, f as registerFeishuChatTools, g as resolveToolsConfig, h as resolveFeishuToolAccount, m as resolveAnyEnabledFeishuToolsConfig, n as registerFeishuDriveTools, o as unknownToolActionResult, p as createFeishuToolClient } from "./drive-B4E8OXZ0.js";
7
+ import { a as toolExecutionErrorResult, f as registerFeishuChatTools, g as resolveToolsConfig, h as resolveFeishuToolAccount, m as resolveAnyEnabledFeishuToolsConfig, n as registerFeishuDriveTools, o as unknownToolActionResult, p as createFeishuToolClient } from "./drive-_zrcOxzS.js";
8
8
  import { n as getFeishuThreadBindingManager, r as testing, t as createFeishuThreadBindingManager } from "./thread-bindings-V0bwk0A1.js";
9
9
  import { n as handleFeishuSubagentEnded, r as handleFeishuSubagentSpawning, t as handleFeishuSubagentDeliveryTarget } from "./subagent-hooks-BKTOxB-T.js";
10
10
  import { optionalPositiveIntegerSchema } from "openclaw/plugin-sdk/channel-actions";
@@ -1,7 +1,7 @@
1
1
  import { t as readFeishuJsonResponse } from "./json-response-CheljwGr.js";
2
2
  import { finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime";
3
3
  import { renderQrTerminal } from "openclaw/plugin-sdk/media-runtime";
4
- import { sleep } from "openclaw/plugin-sdk/runtime-env";
4
+ import { sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
5
5
  import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
6
6
  //#region extensions/feishu/src/app-registration.ts
7
7
  /**
@@ -108,7 +108,7 @@ async function pollAppRegistration(params) {
108
108
  lookupFn
109
109
  });
110
110
  } catch {
111
- await sleepRegistrationPollInterval(currentInterval);
111
+ await sleepRegistrationPollInterval(currentInterval, abortSignal);
112
112
  continue;
113
113
  }
114
114
  if (pollRes.user_info?.tenant_brand) {
@@ -135,7 +135,7 @@ async function pollAppRegistration(params) {
135
135
  status: "error",
136
136
  message: `${pollRes.error}: ${pollRes.error_description ?? "unknown"}`
137
137
  };
138
- await sleepRegistrationPollInterval(currentInterval);
138
+ await sleepRegistrationPollInterval(currentInterval, abortSignal);
139
139
  }
140
140
  return { status: "timeout" };
141
141
  }
@@ -194,8 +194,8 @@ async function getAppOwnerOpenId(params) {
194
194
  return;
195
195
  }
196
196
  }
197
- function sleepRegistrationPollInterval(intervalSeconds) {
198
- return sleep(finiteSecondsToTimerSafeMilliseconds(intervalSeconds) ?? DEFAULT_REGISTRATION_POLL_INTERVAL_SECONDS * 1e3);
197
+ async function sleepRegistrationPollInterval(intervalSeconds, abortSignal) {
198
+ await sleepWithAbort(finiteSecondsToTimerSafeMilliseconds(intervalSeconds) ?? DEFAULT_REGISTRATION_POLL_INTERVAL_SECONDS * 1e3, abortSignal).catch(() => {});
199
199
  }
200
200
  //#endregion
201
201
  export { beginAppRegistration, getAppOwnerOpenId, initAppRegistration, pollAppRegistration, printQrCode };
@@ -1,10 +1,10 @@
1
1
  import { a as resolveDefaultFeishuAccountId, d as isRecord$1, i as listFeishuAccountIds, n as inspectFeishuCredentials, o as resolveFeishuAccount, r as listEnabledFeishuAccounts, s as resolveFeishuRuntimeAccount } from "./accounts-BDoGHJDk.js";
2
2
  import { i as resolveReceiveIdType, n as looksLikeFeishuId, r as normalizeFeishuTarget } from "./targets-BUjQ1TcA.js";
3
- import { A as resolveFeishuChatType, D as resolveFeishuGroupToolPolicy, N as createFeishuCardInteractionEnvelope, _ as canEnumerateAllFeishuPeers, a as readNativeFeishuCardJson, b as resolveFeishuChatReadPreliminaryAuthorization, g as canEnumerateAllFeishuGroups, h as authorizeFeishuChatMemberRead, k as normalizeFeishuChatType, m as assertFeishuChatReadAllowed, n as createFeishuSendReceipt, u as chunkFeishuMarkdown, v as isFeishuGroupReadAllowed, w as resolveFeishuGroupConfig, y as isFeishuGroupReadEnabled } from "./send-result-DsqTk27v.js";
3
+ import { A as resolveFeishuChatType, D as resolveFeishuGroupToolPolicy, N as createFeishuCardInteractionEnvelope, _ as canEnumerateAllFeishuPeers, a as readNativeFeishuCardJson, b as resolveFeishuChatReadPreliminaryAuthorization, g as canEnumerateAllFeishuGroups, h as authorizeFeishuChatMemberRead, k as normalizeFeishuChatType, m as assertFeishuChatReadAllowed, n as createFeishuSendReceipt, u as chunkFeishuMarkdown, v as isFeishuGroupReadAllowed, w as resolveFeishuGroupConfig, y as isFeishuGroupReadEnabled } from "./send-result-DfE5Fhz6.js";
4
4
  import { a as parseFeishuTargetId, i as parseFeishuDirectConversationId, n as buildFeishuModelOverrideParentCandidates, o as resolveConfiguredFeishuGroupSessionScope, r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-BeJL-wq7.js";
5
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-DXH5hux1.js";
5
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-Cw5sdjOm.js";
6
6
  import { t as messageActionTargetAliases } from "./security-audit-BIeA3W3Q.js";
7
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-DnlMcrn5.js";
7
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-BCpDLdg9.js";
8
8
  import { t as collectFeishuSecurityAuditFindings } from "./security-audit-shared-BIHeF-S_.js";
9
9
  import { t as resolveFeishuSessionConversation } from "./session-conversation-BksWrfzm.js";
10
10
  import { createLazyRuntimeModule, createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
@@ -18,12 +18,12 @@ import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing
18
18
  import { createAllowlistProviderGroupPolicyWarningCollector, projectConfigAccountIdWarningCollector } from "openclaw/plugin-sdk/channel-policy";
19
19
  import { getSessionBindingService } from "openclaw/plugin-sdk/conversation-runtime";
20
20
  import { applyDirectoryQueryAndLimit, createChannelDirectoryAdapter, createRuntimeDirectoryLiveAdapter, listDirectoryGroupEntriesFromMapKeysAndAllowFrom, listDirectoryUserEntriesFromAllowFrom, listDirectoryUserEntriesFromAllowFromAndMapKeys } from "openclaw/plugin-sdk/directory-runtime";
21
- import { interactiveReplyToPresentation, normalizeInteractiveReply, normalizeMessagePresentation, renderMessagePresentationChartFallbackText, renderMessagePresentationFallbackText, renderMessagePresentationTableFallbackText, resolveInteractiveTextFallback } from "openclaw/plugin-sdk/interactive-runtime";
21
+ import { legacyInteractiveReplyToPresentation, normalizeLegacyInteractiveReply, normalizeMessagePresentation, renderMessagePresentationChartFallbackText, renderMessagePresentationFallbackText, renderMessagePresentationTableFallbackText, resolveLegacyInteractiveTextFallback } from "openclaw/plugin-sdk/interactive-runtime";
22
22
  import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
23
23
  import { buildProbeChannelStatusSummary, createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
24
24
  import { isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
25
25
  import { sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
26
- import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$2 } from "openclaw/plugin-sdk/account-resolution";
26
+ import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$3 } from "openclaw/plugin-sdk/account-resolution";
27
27
  import { createChannelApprovalAuth } from "openclaw/plugin-sdk/approval-auth-runtime";
28
28
  import { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/channel-status";
29
29
  import { normalizeAccountId as normalizeAccountId$1 } from "openclaw/plugin-sdk/account-id";
@@ -36,7 +36,8 @@ import path from "node:path";
36
36
  import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
37
37
  import { deleteSessionEntry, isValidAgentHarnessSessionStoreEntry, listSessionEntries, loadTranscriptEventsSync, parseSqliteSessionFileMarker, resolveSessionStoreBackupPaths, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
38
38
  import { resolveStateDir } from "openclaw/plugin-sdk/state-paths";
39
- import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, createSetupTranslator, formatDocsLink, hasConfiguredSecretInput as hasConfiguredSecretInput$1, mergeAllowFromEntries, patchTopLevelChannelConfigSection, promptSingleChannelSecretInput, setSetupChannelEnabled, splitSetupEntries } from "openclaw/plugin-sdk/setup";
39
+ import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
40
+ import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$2, createSetupTranslator, formatDocsLink, hasConfiguredSecretInput as hasConfiguredSecretInput$1, mergeAllowFromEntries, patchTopLevelChannelConfigSection, promptSingleChannelSecretInput, setSetupChannelEnabled, splitSetupEntries } from "openclaw/plugin-sdk/setup";
40
41
  //#region extensions/feishu/src/approval-auth.ts
41
42
  function normalizeFeishuApproverId(value) {
42
43
  const trimmed = normalizeOptionalLowercaseString(normalizeFeishuTarget(String(value)));
@@ -212,7 +213,7 @@ const FeishuSharedConfigShape = {
212
213
  textChunkLimit: z.number().int().positive().optional(),
213
214
  mediaMaxMb: z.number().positive().optional(),
214
215
  httpTimeoutMs: z.number().int().positive().max(3e5).optional(),
215
- heartbeat: ChannelHeartbeatVisibilitySchema,
216
+ heartbeatVisibility: ChannelHeartbeatVisibilitySchema,
216
217
  renderMode: RenderModeSchema,
217
218
  streaming: FeishuStreamingSchema,
218
219
  tools: FeishuToolsConfigSchema,
@@ -221,6 +222,8 @@ const FeishuSharedConfigShape = {
221
222
  reactionNotifications: ReactionNotificationModeSchema,
222
223
  typingIndicator: z.boolean().optional(),
223
224
  resolveSenderNames: z.boolean().optional(),
225
+ allowBots: z.boolean().optional(),
226
+ vcAutoJoin: z.boolean().optional(),
224
227
  tts: TtsOverrideSchema
225
228
  };
226
229
  /**
@@ -1217,7 +1220,7 @@ function setFeishuNamedAccountEnabled$1(cfg, accountId, enabled) {
1217
1220
  const feishuSetupAdapter = {
1218
1221
  resolveAccountId: ({ cfg, accountId }) => accountId?.trim() || resolveDefaultFeishuAccountId(cfg),
1219
1222
  applyAccountConfig: ({ cfg, accountId }) => {
1220
- if (!accountId || accountId === DEFAULT_ACCOUNT_ID$1) return {
1223
+ if (!accountId || accountId === DEFAULT_ACCOUNT_ID$2) return {
1221
1224
  ...cfg,
1222
1225
  channels: {
1223
1226
  ...cfg.channels,
@@ -1230,6 +1233,10 @@ const feishuSetupAdapter = {
1230
1233
  return setFeishuNamedAccountEnabled$1(cfg, accountId, true);
1231
1234
  }
1232
1235
  };
1236
+ const feishuSetupContract = defineChannelSetupContract({
1237
+ fields: {},
1238
+ legacyAdapter: feishuSetupAdapter
1239
+ });
1233
1240
  //#endregion
1234
1241
  //#region extensions/feishu/src/setup-surface.ts
1235
1242
  const t = createSetupTranslator();
@@ -1269,7 +1276,7 @@ function formatFeishuStatusLine(status) {
1269
1276
  */
1270
1277
  function patchFeishuConfig(cfg, accountId, patch) {
1271
1278
  const feishuCfg = cfg.channels?.feishu;
1272
- if (accountId === DEFAULT_ACCOUNT_ID$1) return patchTopLevelChannelConfigSection({
1279
+ if (accountId === DEFAULT_ACCOUNT_ID$2) return patchTopLevelChannelConfigSection({
1273
1280
  cfg,
1274
1281
  channel,
1275
1282
  enabled: true,
@@ -1293,7 +1300,7 @@ function patchFeishuConfig(cfg, accountId, patch) {
1293
1300
  async function promptFeishuAllowFrom(params) {
1294
1301
  const feishuCfg = params.cfg.channels?.feishu;
1295
1302
  const resolvedAccountId = params.accountId ?? resolveDefaultFeishuAccountId(params.cfg);
1296
- const existingAllowFrom = (resolvedAccountId !== DEFAULT_ACCOUNT_ID$1 ? feishuCfg?.accounts?.[resolvedAccountId] : void 0)?.allowFrom ?? feishuCfg?.allowFrom ?? [];
1303
+ const existingAllowFrom = (resolvedAccountId !== DEFAULT_ACCOUNT_ID$2 ? feishuCfg?.accounts?.[resolvedAccountId] : void 0)?.allowFrom ?? feishuCfg?.allowFrom ?? [];
1297
1304
  await params.prompter.note([
1298
1305
  t("wizard.feishu.allowlistIntro"),
1299
1306
  t("wizard.feishu.allowlistFindUser"),
@@ -1333,7 +1340,7 @@ const feishuDmPolicy = {
1333
1340
  allowFromKey: "channels.feishu.allowFrom",
1334
1341
  resolveConfigKeys: (_cfg, accountId) => {
1335
1342
  const resolvedAccountId = accountId ?? resolveDefaultFeishuAccountId(_cfg);
1336
- return resolvedAccountId !== DEFAULT_ACCOUNT_ID$1 ? {
1343
+ return resolvedAccountId !== DEFAULT_ACCOUNT_ID$2 ? {
1337
1344
  policyKey: `channels.feishu.accounts.${resolvedAccountId}.dmPolicy`,
1338
1345
  allowFromKey: `channels.feishu.accounts.${resolvedAccountId}.allowFrom`
1339
1346
  } : {
@@ -1344,7 +1351,7 @@ const feishuDmPolicy = {
1344
1351
  getCurrent: (cfg, accountId) => {
1345
1352
  const feishuCfg = cfg.channels?.feishu;
1346
1353
  const resolvedAccountId = accountId ?? resolveDefaultFeishuAccountId(cfg);
1347
- if (resolvedAccountId !== DEFAULT_ACCOUNT_ID$1) {
1354
+ if (resolvedAccountId !== DEFAULT_ACCOUNT_ID$2) {
1348
1355
  const account = feishuCfg?.accounts?.[resolvedAccountId];
1349
1356
  if (account?.dmPolicy) return account.dmPolicy;
1350
1357
  }
@@ -1369,7 +1376,7 @@ function applyNewAppSecurityPolicy(cfg, accountId, openId, groupPolicy) {
1369
1376
  next = patchFeishuConfig(next, accountId, groupPatch);
1370
1377
  return next;
1371
1378
  }
1372
- const loadAppRegistrationModule = createLazyRuntimeModule(() => import("./app-registration-BzkyrVZu.js"));
1379
+ const loadAppRegistrationModule = createLazyRuntimeModule(() => import("./app-registration-cN1bVV6s.js"));
1373
1380
  async function promptFeishuDomain(params) {
1374
1381
  return await params.prompter.select({
1375
1382
  message: t("wizard.feishu.domainPrompt"),
@@ -1594,7 +1601,7 @@ const feishuSetupWizard = {
1594
1601
  });
1595
1602
  let probeResult = null;
1596
1603
  if (configured && account.configured) try {
1597
- const { probeFeishu } = await import("./probe-BgboTHIn.js").then((n) => n.n);
1604
+ const { probeFeishu } = await import("./probe-Za1kgUvx.js").then((n) => n.n);
1598
1605
  probeResult = await probeFeishu(account);
1599
1606
  } catch {}
1600
1607
  if (!configured) return [formatFeishuStatusLine("needs-credentials")];
@@ -1666,7 +1673,7 @@ const meta = {
1666
1673
  order: 70,
1667
1674
  preferSessionLookupForAnnounceTarget: true
1668
1675
  };
1669
- const loadFeishuChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-By2uqa3Q.js"), "feishuChannelRuntime");
1676
+ const loadFeishuChannelRuntime = createLazyRuntimeNamedExport(() => import("./channel.runtime-B5yAAvbT.js"), "feishuChannelRuntime");
1670
1677
  function toFeishuMessageSendResult(result, kind) {
1671
1678
  const receipt = result.receipt ?? createFeishuSendReceipt({
1672
1679
  messageId: result.messageId,
@@ -1710,7 +1717,7 @@ const feishuMessageAdapter = defineChannelMessageAdapter({
1710
1717
  }
1711
1718
  });
1712
1719
  async function createFeishuActionClient(account) {
1713
- const { createFeishuClient } = await import("./client-87BmeMpj.js").then((n) => n.t);
1720
+ const { createFeishuClient } = await import("./client-Dee7cKsS.js").then((n) => n.t);
1714
1721
  return createFeishuClient(account);
1715
1722
  }
1716
1723
  async function resolveFeishuChatTypeById(params) {
@@ -1931,7 +1938,8 @@ function readFirstString(params, keys, fallback) {
1931
1938
  }
1932
1939
  const UNRESOLVED_RESPONSE_PREFIX_VAR_PATTERN = /\{[a-zA-Z][a-zA-Z0-9.]*\}/;
1933
1940
  function resolveFeishuMessageActionResponsePrefix(ctx) {
1934
- const configured = ctx.cfg.messages?.responsePrefix;
1941
+ const channel = ctx.cfg.channels?.feishu;
1942
+ const configured = (ctx.accountId ? channel?.accounts?.[ctx.accountId]?.responsePrefix : void 0) ?? channel?.responsePrefix ?? (channel === void 0 ? ctx.cfg.messages?.responsePrefix : void 0);
1935
1943
  if (!configured) return;
1936
1944
  const agentId = (ctx.agentId?.trim() || "main").toLowerCase();
1937
1945
  const identityName = ctx.cfg.agents?.list?.find((agent) => agent.id.trim().toLowerCase() === agentId)?.identity?.name?.trim();
@@ -2148,7 +2156,7 @@ const feishuPlugin = createChatChannelPlugin({
2148
2156
  config: {
2149
2157
  ...feishuConfigAdapter,
2150
2158
  setAccountEnabled: ({ cfg, accountId, enabled }) => {
2151
- if (accountId === DEFAULT_ACCOUNT_ID$2) return {
2159
+ if (accountId === DEFAULT_ACCOUNT_ID$3) return {
2152
2160
  ...cfg,
2153
2161
  channels: {
2154
2162
  ...cfg.channels,
@@ -2161,7 +2169,7 @@ const feishuPlugin = createChatChannelPlugin({
2161
2169
  return setFeishuNamedAccountEnabled(cfg, accountId, enabled);
2162
2170
  },
2163
2171
  deleteAccount: ({ cfg, accountId }) => {
2164
- if (accountId === DEFAULT_ACCOUNT_ID$2) {
2172
+ if (accountId === DEFAULT_ACCOUNT_ID$3) {
2165
2173
  const next = { ...cfg };
2166
2174
  const nextChannels = { ...cfg.channels };
2167
2175
  delete nextChannels.feishu;
@@ -2217,14 +2225,14 @@ const feishuPlugin = createChatChannelPlugin({
2217
2225
  if (ctx.action === "thread-reply" && !replyToMessageId) throw new Error("Feishu thread-reply requires messageId.");
2218
2226
  const text = readFirstString(ctx.params, ["text", "message"]);
2219
2227
  const textCard = readNativeFeishuCardJson(text, { responsePrefix: resolveFeishuMessageActionResponsePrefix(ctx) });
2220
- const interactive = normalizeInteractiveReply(ctx.params.interactive);
2221
- const presentation = normalizeMessagePresentation(ctx.params.presentation) ?? (interactive ? interactiveReplyToPresentation(interactive) : void 0);
2228
+ const interactive = normalizeLegacyInteractiveReply(ctx.params.interactive);
2229
+ const presentation = normalizeMessagePresentation(ctx.params.presentation) ?? (interactive ? legacyInteractiveReplyToPresentation(interactive) : void 0);
2222
2230
  const mediaUrl = readFeishuMediaParam(ctx.params);
2223
2231
  const audioAsVoice = readBooleanParam(ctx.params, ["asVoice", "audioAsVoice"]);
2224
2232
  if (textCard && !presentation) assertFeishuCardWithinEnvelope(textCard, "Feishu native card");
2225
2233
  const generatedCard = presentation ? buildFeishuPresentationCard({
2226
2234
  presentation,
2227
- fallbackText: textCard ? void 0 : resolveInteractiveTextFallback({
2235
+ fallbackText: textCard ? void 0 : resolveLegacyInteractiveTextFallback({
2228
2236
  text,
2229
2237
  interactive
2230
2238
  })
@@ -2685,6 +2693,7 @@ const feishuPlugin = createChatChannelPlugin({
2685
2693
  });
2686
2694
  } },
2687
2695
  setup: feishuSetupAdapter,
2696
+ setupContract: feishuSetupContract,
2688
2697
  setupWizard: feishuSetupWizard,
2689
2698
  messaging: {
2690
2699
  targetPrefixes: ["feishu", "lark"],
@@ -2739,7 +2748,7 @@ const feishuPlugin = createChatChannelPlugin({
2739
2748
  })
2740
2749
  }),
2741
2750
  status: createComputedAccountStatusAdapter({
2742
- defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID$2, { port: null }),
2751
+ defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID$3, { port: null }),
2743
2752
  buildChannelSummary: ({ snapshot }) => buildProbeChannelStatusSummary(snapshot, { port: snapshot.port ?? null }),
2744
2753
  probeAccount: async ({ account }) => await (await loadFeishuChannelRuntime()).probeFeishu(account),
2745
2754
  resolveAccountSnapshot: ({ account, runtime }) => ({
@@ -2755,7 +2764,7 @@ const feishuPlugin = createChatChannelPlugin({
2755
2764
  })
2756
2765
  }),
2757
2766
  gateway: { startAccount: async (ctx) => {
2758
- const { monitorFeishuProvider } = await import("./monitor-CHl0bWzb.js");
2767
+ const { monitorFeishuProvider } = await import("./monitor-8CLu6myv.js");
2759
2768
  const account = resolveFeishuRuntimeAccount({
2760
2769
  cfg: ctx.cfg,
2761
2770
  accountId: ctx.accountId
@@ -1,2 +1,2 @@
1
- import { t as feishuPlugin } from "./channel-X30GQVwc.js";
1
+ import { t as feishuPlugin } from "./channel-DB1x6UJX.js";
2
2
  export { feishuPlugin };
@@ -1,19 +1,19 @@
1
1
  import { o as resolveFeishuAccount, s as resolveFeishuRuntimeAccount, v as parseFeishuCommentTarget } from "./accounts-BDoGHJDk.js";
2
- import { c as isFeishuCardWithinEnvelope, l as listFeishuDirectoryGroups, o as assertFeishuCardWithinEnvelope, s as buildFeishuPresentationCardElements, u as listFeishuDirectoryPeers } from "./channel-X30GQVwc.js";
3
- import { a as readNativeFeishuCardJson, d as chunkFeishuPostMarkdown, f as materializeFeishuPostMarkdownSoftBreaks, o as resolveFeishuCardTemplate, s as sanitizeNativeFeishuCard, u as chunkFeishuMarkdown } from "./send-result-DsqTk27v.js";
4
- import { r as createFeishuClient } from "./client-87BmeMpj.js";
5
- import { c as buildFeishuDirectChatMembers, d as getFeishuMemberInfo, l as getChatInfo, r as cleanupAmbientCommentTypingReaction, s as assertFeishuChatMember, t as deliverCommentThreadText, u as getChatMembers } from "./drive-B4E8OXZ0.js";
6
- import { a as sendMarkdownCardFeishu, h as shouldSuppressFeishuTextForVoiceMedia, i as sendCardFeishu, m as sendMediaFeishu, n as getMessageFeishu, o as sendMessageFeishu, s as sendStructuredCardFeishu, t as editMessageFeishu, v as resolveFeishuIdentityHeaderTitle } from "./send-DrWM_Ilf.js";
7
- import { t as probeFeishu } from "./probe-BgboTHIn.js";
2
+ import { c as isFeishuCardWithinEnvelope, l as listFeishuDirectoryGroups, o as assertFeishuCardWithinEnvelope, s as buildFeishuPresentationCardElements, u as listFeishuDirectoryPeers } from "./channel-DB1x6UJX.js";
3
+ import { a as readNativeFeishuCardJson, d as chunkFeishuPostMarkdown, f as materializeFeishuPostMarkdownSoftBreaks, o as resolveFeishuCardTemplate, s as sanitizeNativeFeishuCard, u as chunkFeishuMarkdown } from "./send-result-DfE5Fhz6.js";
4
+ import { r as createFeishuClient } from "./client-Dee7cKsS.js";
5
+ import { c as buildFeishuDirectChatMembers, d as getFeishuMemberInfo, l as getChatInfo, r as cleanupAmbientCommentTypingReaction, s as assertFeishuChatMember, t as deliverCommentThreadText, u as getChatMembers } from "./drive-_zrcOxzS.js";
6
+ import { _ as buildFeishuMediaFallbackText, a as getMessageFeishu, c as sendMarkdownCardFeishu, i as editMessageFeishu, l as sendMessageFeishu, n as sendMediaFeishu, r as shouldSuppressFeishuTextForVoiceMedia, s as sendCardFeishu, u as sendStructuredCardFeishu, y as resolveFeishuIdentityHeaderTitle } from "./media-CRJunSRr.js";
7
+ import { t as probeFeishu } from "./probe-Za1kgUvx.js";
8
8
  import { createReplyToFanout } from "openclaw/plugin-sdk/channel-outbound";
9
- import { interactiveReplyToPresentation, normalizeInteractiveReply, normalizeMessagePresentation, renderMessagePresentationFallbackText, resolveInteractiveTextFallback } from "openclaw/plugin-sdk/interactive-runtime";
9
+ import { legacyInteractiveReplyToPresentation, normalizeLegacyInteractiveReply, normalizeMessagePresentation, renderMessagePresentationFallbackText, resolveLegacyInteractiveTextFallback } from "openclaw/plugin-sdk/interactive-runtime";
10
10
  import { isRecord, normalizeLowercaseStringOrEmpty, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
11
11
  import { convertMarkdownTables } from "openclaw/plugin-sdk/text-chunking";
12
12
  import path from "node:path";
13
13
  import { resolveChunkMode, resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-chunking";
14
14
  import { attachChannelToResult, createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
15
15
  import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
16
- import { resolvePayloadMediaUrls, sendPayloadMediaSequenceAndFinalize, sendTextMediaPayload } from "openclaw/plugin-sdk/reply-payload";
16
+ import { getReplyPayloadTtsSupplement, resolvePayloadMediaUrls, sendPayloadMediaSequenceAndFinalize, sendTextMediaPayload } from "openclaw/plugin-sdk/reply-payload";
17
17
  import { statRegularFileSync } from "openclaw/plugin-sdk/security-runtime";
18
18
  //#region extensions/feishu/src/directory.ts
19
19
  const MAX_FEISHU_DIRECTORY_PAGES = 100;
@@ -167,14 +167,14 @@ function buildFeishuPayloadCard(params) {
167
167
  }
168
168
  const rawText = params.text ?? params.payload.text;
169
169
  const textCard = readNativeFeishuCardJson(rawText);
170
- const interactive = normalizeInteractiveReply(params.payload.interactive);
171
- const presentation = normalizeMessagePresentation(params.payload.presentation) ?? (interactive ? interactiveReplyToPresentation(interactive) : void 0);
170
+ const interactive = normalizeLegacyInteractiveReply(params.payload.interactive);
171
+ const presentation = normalizeMessagePresentation(params.payload.presentation) ?? (interactive ? legacyInteractiveReplyToPresentation(interactive) : void 0);
172
172
  if (!presentation && !interactive) {
173
173
  if (!textCard) return;
174
174
  assertFeishuCardWithinEnvelope(textCard, "Feishu native card");
175
175
  return markRenderedFeishuCard(textCard);
176
176
  }
177
- const text = textCard ? void 0 : resolveInteractiveTextFallback({
177
+ const text = textCard ? void 0 : resolveLegacyInteractiveTextFallback({
178
178
  text: rawText,
179
179
  interactive
180
180
  });
@@ -393,6 +393,51 @@ async function sendFeishuFallbackPayload(params) {
393
393
  }
394
394
  return lastResult;
395
395
  }
396
+ async function sendFeishuTtsSupplementPayload(params) {
397
+ const sendMedia = feishuOutbound.sendMedia;
398
+ const sendText = feishuOutbound.sendText;
399
+ if (!sendMedia || !sendText) throw new Error("Feishu TTS supplement delivery is not available.");
400
+ const { normalizedReplyToId } = resolveFeishuReplyMode({
401
+ replyToId: params.ctx.replyToId,
402
+ threadId: params.ctx.threadId
403
+ });
404
+ const nextReplyToId = createReplyToFanout({
405
+ replyToId: normalizedReplyToId,
406
+ replyToIdSource: params.ctx.replyToIdSource,
407
+ replyToMode: params.ctx.replyToMode
408
+ });
409
+ const ctx = {
410
+ ...params.ctx,
411
+ payload: params.payload
412
+ };
413
+ let lastResult;
414
+ if (params.sendVisiblePayload) {
415
+ lastResult = await params.sendVisiblePayload(nextReplyToId());
416
+ await ctx.onDeliveryResult?.(lastResult);
417
+ } else if (params.supplement.visibleTextAlreadyDelivered !== true) {
418
+ const text = params.payload.text?.trim() ? params.payload.text : params.supplement.spokenText;
419
+ for (const chunk of chunkFeishuMarkdown(text, FEISHU_TEXT_CHUNK_LIMIT)) {
420
+ lastResult = await sendText({
421
+ ...ctx,
422
+ text: chunk,
423
+ replyToId: nextReplyToId(),
424
+ onDeliveryResult: void 0
425
+ });
426
+ await ctx.onDeliveryResult?.(lastResult);
427
+ }
428
+ }
429
+ for (const mediaUrl of normalizeStringEntries(resolvePayloadMediaUrls(params.payload))) lastResult = await sendMedia({
430
+ ...ctx,
431
+ text: "",
432
+ mediaUrl,
433
+ replyToId: nextReplyToId(),
434
+ audioAsVoice: params.payload.audioAsVoice ?? ctx.audioAsVoice
435
+ });
436
+ return lastResult ?? {
437
+ channel: "feishu",
438
+ messageId: ""
439
+ };
440
+ }
396
441
  const feishuOutbound = {
397
442
  deliveryMode: "direct",
398
443
  chunker: chunkFeishuMarkdown,
@@ -421,9 +466,10 @@ const feishuOutbound = {
421
466
  renderPresentation: renderFeishuPresentationPayload,
422
467
  sendPayload: async (ctx) => {
423
468
  const { payload, presentationFallback } = consumeFeishuPresentationFallbackMarker(ctx.payload);
469
+ const ttsSupplement = getReplyPayloadTtsSupplement(payload);
424
470
  if (parseFeishuCommentTarget(ctx.to)) {
425
- const interactive = normalizeInteractiveReply(payload.interactive);
426
- const normalizedPresentation = normalizeMessagePresentation(payload.presentation) ?? (interactive ? interactiveReplyToPresentation(interactive) : void 0);
471
+ const interactive = normalizeLegacyInteractiveReply(payload.interactive);
472
+ const normalizedPresentation = normalizeMessagePresentation(payload.presentation) ?? (interactive ? legacyInteractiveReplyToPresentation(interactive) : void 0);
427
473
  const textCard = readNativeFeishuCardJson(payload.text);
428
474
  const presentationFallbackText = renderMessagePresentationFallbackText({
429
475
  text: textCard ? void 0 : payload.text,
@@ -450,8 +496,13 @@ const feishuOutbound = {
450
496
  identity: ctx.identity
451
497
  });
452
498
  if (!card) {
453
- const interactive = normalizeInteractiveReply(payload.interactive);
454
- const presentation = normalizeMessagePresentation(payload.presentation) ?? (interactive ? interactiveReplyToPresentation(interactive) : void 0);
499
+ if (ttsSupplement) return await sendFeishuTtsSupplementPayload({
500
+ ctx,
501
+ payload,
502
+ supplement: ttsSupplement
503
+ });
504
+ const interactive = normalizeLegacyInteractiveReply(payload.interactive);
505
+ const presentation = normalizeMessagePresentation(payload.presentation) ?? (interactive ? legacyInteractiveReplyToPresentation(interactive) : void 0);
455
506
  return await sendFeishuFallbackPayload({
456
507
  ctx,
457
508
  payload: presentation ? {
@@ -466,6 +517,25 @@ const feishuOutbound = {
466
517
  separateMediaAndText: presentationFallback || presentation !== void 0
467
518
  });
468
519
  }
520
+ if (ttsSupplement) return await sendFeishuTtsSupplementPayload({
521
+ ctx,
522
+ payload,
523
+ supplement: ttsSupplement,
524
+ sendVisiblePayload: async (replyToId) => {
525
+ const { replyToMessageId, replyInThread } = resolveFeishuReplyMode({
526
+ replyToId,
527
+ threadId: ctx.threadId
528
+ });
529
+ return attachChannelToResult("feishu", await sendCardFeishu({
530
+ cfg: ctx.cfg,
531
+ to: ctx.to,
532
+ card,
533
+ replyToMessageId,
534
+ replyInThread,
535
+ accountId: ctx.accountId ?? void 0
536
+ }));
537
+ }
538
+ });
469
539
  const { normalizedReplyToId } = resolveFeishuReplyMode({
470
540
  replyToId: ctx.replyToId,
471
541
  threadId: ctx.threadId
@@ -532,6 +602,14 @@ const feishuOutbound = {
532
602
  });
533
603
  } catch (err) {
534
604
  console.error(`[feishu] local image path auto-send failed:`, err);
605
+ return await sendOutboundText({
606
+ cfg,
607
+ to,
608
+ text: await buildFeishuMediaFallbackText({}),
609
+ accountId: accountId ?? void 0,
610
+ replyToMessageId,
611
+ replyInThread
612
+ });
535
613
  }
536
614
  if (parseFeishuCommentTarget(to)) return await sendOutboundText({
537
615
  cfg,
@@ -589,7 +667,11 @@ const feishuOutbound = {
589
667
  if (parseFeishuCommentTarget(to)) return await sendOutboundText({
590
668
  cfg,
591
669
  to,
592
- text: [text?.trim(), mediaUrl?.trim()].filter(Boolean).join("\n\n") || mediaUrl || text || "",
670
+ text: mediaUrl?.trim() ? await buildFeishuMediaFallbackText({
671
+ text,
672
+ mediaUrl,
673
+ mediaLinkStyle: "plain"
674
+ }) : text?.trim() ?? "",
593
675
  accountId: accountId ?? void 0,
594
676
  replyToMessageId,
595
677
  replyInThread
@@ -632,7 +714,10 @@ const feishuOutbound = {
632
714
  const fallbackResult = await sendOutboundText({
633
715
  cfg,
634
716
  to,
635
- text: [textSent ? void 0 : text?.trim(), `📎 ${mediaUrl}`].filter(Boolean).join("\n\n"),
717
+ text: await buildFeishuMediaFallbackText({
718
+ text: textSent ? void 0 : text,
719
+ mediaUrl
720
+ }),
636
721
  accountId: accountId ?? void 0,
637
722
  replyToMessageId,
638
723
  replyInThread
@@ -62,6 +62,67 @@ function setRequestUserAgent(req) {
62
62
  return req;
63
63
  }
64
64
  Lark.defaultHttpInstance.interceptors?.request?.use(setRequestUserAgent);
65
+ function isRecord(value) {
66
+ return typeof value === "object" && value !== null && !Array.isArray(value);
67
+ }
68
+ function readHeader(headers, name) {
69
+ if (!isRecord(headers)) return;
70
+ const normalizedName = name.toLowerCase();
71
+ for (const [key, value] of Object.entries(headers)) {
72
+ if (key.toLowerCase() !== normalizedName) continue;
73
+ if (typeof value === "string") return value;
74
+ if (Array.isArray(value)) {
75
+ const first = value.find((entry) => typeof entry === "string");
76
+ return typeof first === "string" ? first : void 0;
77
+ }
78
+ }
79
+ }
80
+ function isMultipartFormRequest(opts) {
81
+ return /^multipart\/form-data(?:;|$)/i.test(readHeader(opts.headers, "content-type") ?? "");
82
+ }
83
+ const FEISHU_MESSAGE_MEDIA_UPLOAD_PATHS = /* @__PURE__ */ new Set(["/open-apis/im/v1/files", "/open-apis/im/v1/images"]);
84
+ function isFeishuMessageMediaUploadRequest(opts, data) {
85
+ if (typeof opts.url !== "string" || opts.method?.toUpperCase() !== "POST") return false;
86
+ let pathname;
87
+ try {
88
+ pathname = new URL(opts.url).pathname;
89
+ } catch {
90
+ return false;
91
+ }
92
+ return FEISHU_MESSAGE_MEDIA_UPLOAD_PATHS.has(pathname) && (Buffer.isBuffer(data.file) || Buffer.isBuffer(data.image));
93
+ }
94
+ function stringifyMultipartFieldValue(value) {
95
+ switch (typeof value) {
96
+ case "string": return value;
97
+ case "number":
98
+ case "boolean":
99
+ case "bigint": return String(value);
100
+ default: return;
101
+ }
102
+ }
103
+ function bufferToBlobPart(value) {
104
+ const bytes = new Uint8Array(value.byteLength);
105
+ bytes.set(value);
106
+ return bytes;
107
+ }
108
+ function normalizeMultipartUploadData(opts) {
109
+ if (!isMultipartFormRequest(opts) || !isRecord(opts.data) || !isFeishuMessageMediaUploadRequest(opts, opts.data)) return opts;
110
+ const form = new FormData();
111
+ const fileName = typeof opts.data.file_name === "string" && opts.data.file_name ? opts.data.file_name : void 0;
112
+ for (const [key, value] of Object.entries(opts.data)) {
113
+ if (value === void 0 || value === null) continue;
114
+ if (Buffer.isBuffer(value)) {
115
+ form.append(key, new Blob([bufferToBlobPart(value)]), key === "file" && fileName ? fileName : `${key}.bin`);
116
+ continue;
117
+ }
118
+ const fieldValue = stringifyMultipartFieldValue(value);
119
+ if (fieldValue !== void 0) form.append(key, fieldValue);
120
+ }
121
+ return {
122
+ ...opts,
123
+ data: form
124
+ };
125
+ }
65
126
  function isManagedProxyActive() {
66
127
  return process.env["OPENCLAW_PROXY_ACTIVE"] === "1";
67
128
  }
@@ -118,7 +179,7 @@ function createFeishuHttpInstance(defaultTimeoutMs) {
118
179
  return next;
119
180
  }
120
181
  return {
121
- request: async (opts) => base.request(await injectRequestOptions(opts)),
182
+ request: async (opts) => base.request(await injectRequestOptions(normalizeMultipartUploadData(opts))),
122
183
  get: async (url, opts) => base.get(url, await injectRequestOptions(opts)),
123
184
  post: async (url, data, opts) => base.post(url, data, await injectRequestOptions(opts)),
124
185
  put: async (url, data, opts) => base.put(url, data, await injectRequestOptions(opts)),
@@ -1,4 +1,4 @@
1
- import { asObjectRecord, defineChannelAliasMigration } from "openclaw/plugin-sdk/runtime-doctor";
1
+ import { asObjectRecord, defineChannelAliasMigration, normalizeChannelConfigEntries } from "openclaw/plugin-sdk/runtime-doctor";
2
2
  //#region extensions/feishu/src/doctor-contract.ts
3
3
  const streamingAliasMigration = defineChannelAliasMigration({
4
4
  channelId: "feishu",
@@ -10,6 +10,21 @@ const LEGACY_COALESCE_FIELDS = [
10
10
  "minDelayMs",
11
11
  "maxDelayMs"
12
12
  ];
13
+ const LEGACY_HEARTBEAT_FIELDS = ["visibility", "intervalMs"];
14
+ function sanitizeLegacyHeartbeatFields(params) {
15
+ const heartbeat = asObjectRecord(params.entry.heartbeat);
16
+ if (!heartbeat || Object.keys(heartbeat).length > 0 && !LEGACY_HEARTBEAT_FIELDS.some((field) => Object.hasOwn(heartbeat, field))) return {
17
+ entry: params.entry,
18
+ changed: false
19
+ };
20
+ const next = { ...params.entry };
21
+ delete next.heartbeat;
22
+ params.changes.push(`Removed ${params.pathPrefix}.heartbeat (legacy Feishu fields were never read by runtime).`);
23
+ return {
24
+ entry: next,
25
+ changed: true
26
+ };
27
+ }
13
28
  function sanitizeLegacyCoalesceFields(params) {
14
29
  const streaming = asObjectRecord(params.entry.streaming);
15
30
  const block = asObjectRecord(streaming?.block);
@@ -41,49 +56,22 @@ function sanitizeLegacyCoalesceFields(params) {
41
56
  };
42
57
  }
43
58
  function sanitizeFeishuCoalesce(cfg, changes) {
44
- const channels = cfg.channels;
45
- const entry = asObjectRecord(channels?.feishu);
46
- if (!entry) return cfg;
47
- const root = sanitizeLegacyCoalesceFields({
48
- entry,
49
- pathPrefix: "channels.feishu",
50
- changes
51
- });
52
- let updated = root.entry;
53
- let changed = root.changed;
54
- const accounts = asObjectRecord(updated.accounts);
55
- if (accounts) {
56
- let accountsChanged = false;
57
- const nextAccounts = { ...accounts };
58
- for (const [accountId, rawAccount] of Object.entries(accounts)) {
59
- const account = asObjectRecord(rawAccount);
60
- if (!account) continue;
61
- const sanitized = sanitizeLegacyCoalesceFields({
62
- entry: account,
63
- pathPrefix: `channels.feishu.accounts.${accountId}`,
64
- changes
59
+ return normalizeChannelConfigEntries({
60
+ cfg,
61
+ channelId: "feishu",
62
+ changes,
63
+ normalizeEntry: (params) => {
64
+ const coalesce = sanitizeLegacyCoalesceFields(params);
65
+ const heartbeat = sanitizeLegacyHeartbeatFields({
66
+ ...params,
67
+ entry: coalesce.entry
65
68
  });
66
- if (sanitized.changed) {
67
- nextAccounts[accountId] = sanitized.entry;
68
- accountsChanged = true;
69
- }
70
- }
71
- if (accountsChanged) {
72
- updated = {
73
- ...updated,
74
- accounts: nextAccounts
69
+ return {
70
+ entry: heartbeat.entry,
71
+ changed: coalesce.changed || heartbeat.changed
75
72
  };
76
- changed = true;
77
73
  }
78
- }
79
- if (!changed) return cfg;
80
- return {
81
- ...cfg,
82
- channels: {
83
- ...channels,
84
- feishu: updated
85
- }
86
- };
74
+ }).config;
87
75
  }
88
76
  const legacyConfigRules = streamingAliasMigration.legacyConfigRules;
89
77
  function normalizeCompatibilityConfig({ cfg }) {
@@ -1,2 +1,2 @@
1
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-DXH5hux1.js";
1
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-Cw5sdjOm.js";
2
2
  export { legacyConfigRules, normalizeCompatibilityConfig };
@@ -1,6 +1,6 @@
1
1
  import { c as encodeQuery, d as isRecord$1, i as listFeishuAccountIds, l as extractReplyText, m as readString, o as resolveFeishuAccount, r as listEnabledFeishuAccounts, s as resolveFeishuRuntimeAccount, u as formatFeishuApiError, v as parseFeishuCommentTarget } from "./accounts-BDoGHJDk.js";
2
- import { A as resolveFeishuChatType, b as resolveFeishuChatReadPreliminaryAuthorization, h as authorizeFeishuChatMemberRead, m as assertFeishuChatReadAllowed } from "./send-result-DsqTk27v.js";
3
- import { r as createFeishuClient } from "./client-87BmeMpj.js";
2
+ import { A as resolveFeishuChatType, b as resolveFeishuChatReadPreliminaryAuthorization, h as authorizeFeishuChatMemberRead, m as assertFeishuChatReadAllowed } from "./send-result-DfE5Fhz6.js";
3
+ import { r as createFeishuClient } from "./client-Dee7cKsS.js";
4
4
  import { optionalPositiveIntegerSchema } from "openclaw/plugin-sdk/channel-actions";
5
5
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
6
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";