@larksuite/openclaw-lark 2026.3.26 → 2026.3.29-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/bin/openclaw-lark.js +10 -22
  2. package/openclaw.plugin.json +8 -1
  3. package/package.json +16 -11
  4. package/src/card/builder.js +5 -3
  5. package/src/card/card-error.js +2 -2
  6. package/src/card/reply-dispatcher.js +1 -2
  7. package/src/channel/directory.d.ts +1 -1
  8. package/src/channel/plugin.js +2 -2
  9. package/src/channel/probe.d.ts +1 -1
  10. package/src/commands/doctor.d.ts +2 -1
  11. package/src/commands/index.d.ts +1 -1
  12. package/src/commands/index.js +1 -1
  13. package/src/core/accounts.d.ts +1 -1
  14. package/src/core/accounts.js +2 -3
  15. package/src/core/app-owner-fallback.d.ts +2 -1
  16. package/src/core/app-owner-fallback.js +1 -3
  17. package/src/core/auth-errors.js +1 -3
  18. package/src/core/chat-info-cache.d.ts +9 -1
  19. package/src/core/chat-info-cache.js +0 -7
  20. package/src/core/config-schema.d.ts +7 -0
  21. package/src/core/config-schema.js +3 -1
  22. package/src/core/lark-client.d.ts +1 -2
  23. package/src/core/lark-client.js +11 -15
  24. package/src/core/lark-logger.js +6 -3
  25. package/src/core/message-unavailable.d.ts +1 -1
  26. package/src/core/message-unavailable.js +1 -1
  27. package/src/core/owner-policy.d.ts +2 -1
  28. package/src/core/owner-policy.js +1 -3
  29. package/src/core/runtime-store.d.ts +13 -0
  30. package/src/core/runtime-store.js +29 -0
  31. package/src/core/scope-manager.d.ts +1 -1
  32. package/src/core/tool-client.d.ts +2 -2
  33. package/src/core/tool-client.js +2 -2
  34. package/src/core/tools-config.d.ts +1 -1
  35. package/src/core/types.d.ts +1 -1
  36. package/src/messaging/converters/audio.js +1 -2
  37. package/src/messaging/converters/content-converter-helpers.d.ts +25 -0
  38. package/src/messaging/converters/content-converter-helpers.js +76 -0
  39. package/src/messaging/converters/content-converter.d.ts +2 -19
  40. package/src/messaging/converters/content-converter.js +7 -79
  41. package/src/messaging/converters/interactive/card-converter.d.ts +1 -1
  42. package/src/messaging/converters/interactive/card-converter.js +22 -22
  43. package/src/messaging/converters/interactive/legacy.js +1 -1
  44. package/src/messaging/converters/merge-forward.js +15 -9
  45. package/src/messaging/converters/post.js +2 -2
  46. package/src/messaging/converters/text.js +2 -2
  47. package/src/messaging/converters/types.d.ts +7 -0
  48. package/src/messaging/converters/video.js +1 -2
  49. package/src/messaging/inbound/dispatch-builders.d.ts +1 -1
  50. package/src/messaging/inbound/dispatch-builders.js +1 -1
  51. package/src/messaging/inbound/dispatch-commands.d.ts +2 -2
  52. package/src/messaging/inbound/dispatch.d.ts +2 -4
  53. package/src/messaging/inbound/dispatch.js +12 -5
  54. package/src/messaging/inbound/enrich.d.ts +1 -1
  55. package/src/messaging/inbound/enrich.js +3 -4
  56. package/src/messaging/inbound/gate.d.ts +17 -2
  57. package/src/messaging/inbound/gate.js +24 -0
  58. package/src/messaging/inbound/handler-registry.d.ts +25 -0
  59. package/src/messaging/inbound/handler-registry.js +23 -0
  60. package/src/messaging/inbound/handler.js +3 -1
  61. package/src/messaging/inbound/mention.d.ts +9 -0
  62. package/src/messaging/inbound/mention.js +10 -0
  63. package/src/messaging/inbound/parse.js +16 -1
  64. package/src/messaging/inbound/reaction-handler.js +4 -3
  65. package/src/messaging/inbound/synthetic-message.d.ts +26 -0
  66. package/src/messaging/inbound/synthetic-message.js +59 -0
  67. package/src/messaging/inbound/user-name-cache-store.d.ts +22 -0
  68. package/src/messaging/inbound/user-name-cache-store.js +99 -0
  69. package/src/messaging/inbound/user-name-cache.d.ts +1 -29
  70. package/src/messaging/inbound/user-name-cache.js +8 -114
  71. package/src/messaging/outbound/actions.js +4 -4
  72. package/src/messaging/outbound/deliver.js +5 -5
  73. package/src/messaging/outbound/media.js +1 -1
  74. package/src/messaging/outbound/outbound.js +1 -1
  75. package/src/messaging/outbound/reactions.js +1 -1
  76. package/src/messaging/outbound/send.d.ts +1 -2
  77. package/src/messaging/types.d.ts +2 -0
  78. package/src/tools/ask-user-question.d.ts +1 -1
  79. package/src/tools/ask-user-question.js +103 -10
  80. package/src/tools/auto-auth.d.ts +2 -1
  81. package/src/tools/auto-auth.js +26 -50
  82. package/src/tools/helpers.d.ts +13 -10
  83. package/src/tools/helpers.js +1 -1
  84. package/src/tools/mcp/shared.js +3 -3
  85. package/src/tools/oapi/calendar/event.js +2 -2
  86. package/src/tools/oapi/drive/doc-media.js +3 -3
  87. package/src/tools/oapi/drive/file.js +2 -2
  88. package/src/tools/oapi/helpers.d.ts +4 -3
  89. package/src/tools/oapi/helpers.js +3 -4
  90. package/src/tools/oapi/im/format-messages.d.ts +2 -2
  91. package/src/tools/oapi/im/resource.js +2 -2
  92. package/src/tools/oapi/im/user-name-uat.js +0 -2
  93. package/src/tools/oapi/index.js +27 -27
  94. package/src/tools/oapi/sheets/sheet.js +2 -2
  95. package/src/tools/oauth-batch-auth.js +2 -2
  96. package/src/tools/oauth-cards.js +1 -2
  97. package/src/tools/oauth.d.ts +1 -1
  98. package/src/tools/oauth.js +24 -56
  99. package/src/tools/onboarding-auth.js +1 -1
  100. package/src/tools/tat/im/resource.js +2 -2
  101. package/tsdown.config.d.ts +1 -14
  102. package/tsdown.config.js +8 -5
  103. package/vitest.config.d.ts +2 -0
  104. package/vitest.config.js +12 -0
@@ -1,47 +1,35 @@
1
1
  #!/usr/bin/env node
2
-
3
- import { execFileSync } from "node:child_process";
4
- import { dirname, join } from "node:path";
2
+ import { execFileSync } from 'node:child_process';
3
+ import { dirname, join } from 'node:path';
5
4
 
6
5
  // --tools-version <ver> lets the user pin a specific version
7
6
  const args = process.argv.slice(2);
8
- let version = "latest";
7
+ let version = 'latest';
9
8
 
10
- const vIdx = args.indexOf("--tools-version");
9
+ const vIdx = args.indexOf('--tools-version');
11
10
  if (vIdx !== -1) {
12
11
  version = args[vIdx + 1];
13
12
  // Remove --tools-version <ver> from forwarded args
14
13
  args.splice(vIdx, 2);
15
14
  }
16
15
 
17
- const allArgs = ["--yes", "--prefer-online", `@larksuite/openclaw-lark-tools@${version}`, ...args];
16
+ const allArgs = ['--yes', '--prefer-online', `@larksuite/openclaw-lark-tools@${version}`, ...args];
18
17
 
19
18
  try {
20
- if (process.platform === "win32") {
19
+ if (process.platform === 'win32') {
21
20
  // On Windows, npx is a .cmd shim that can be broken or trigger
22
21
  // DEP0190. Bypass it entirely: run node with the npx-cli.js
23
22
  // script located next to the running node binary.
24
- const npxCli = join(
25
- dirname(process.execPath),
26
- "node_modules",
27
- "npm",
28
- "bin",
29
- "npx-cli.js",
30
- );
23
+ const npxCli = join(dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npx-cli.js');
31
24
  execFileSync(process.execPath, [npxCli, ...allArgs], {
32
- stdio: "inherit",
25
+ stdio: 'inherit',
33
26
  env: {
34
27
  ...process.env,
35
- NODE_OPTIONS: [
36
- process.env.NODE_OPTIONS,
37
- "--disable-warning=DEP0190",
38
- ]
39
- .filter(Boolean)
40
- .join(" "),
28
+ NODE_OPTIONS: [process.env.NODE_OPTIONS, '--disable-warning=DEP0190'].filter(Boolean).join(' '),
41
29
  },
42
30
  });
43
31
  } else {
44
- execFileSync("npx", allArgs, { stdio: "inherit" });
32
+ execFileSync('npx', allArgs, { stdio: 'inherit' });
45
33
  }
46
34
  } catch (error) {
47
35
  process.exit(error.status ?? 1);
@@ -6,5 +6,12 @@
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
8
  "properties": {}
9
+ },
10
+ "channelConfigs": {
11
+ "feishu": {
12
+ "schema": {
13
+ "type": "object"
14
+ }
15
+ }
9
16
  }
10
- }
17
+ }
package/package.json CHANGED
@@ -1,16 +1,29 @@
1
1
  {
2
2
  "name": "@larksuite/openclaw-lark",
3
- "version": "2026.3.26",
3
+ "version": "2026.3.29-beta.0",
4
4
  "description": "OpenClaw Lark/Feishu channel plugin",
5
+ "exports": {
6
+ ".": {
7
+ "import": {
8
+ "types": "./dist/index.d.mts",
9
+ "default": "./dist/index.mjs"
10
+ }
11
+ }
12
+ },
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
5
15
  "bin": {
6
16
  "openclaw-lark": "bin/openclaw-lark.js"
7
17
  },
8
- "main": "index.js",
9
18
  "files": [
10
19
  "**/*"
11
20
  ],
21
+ "packageManager": "pnpm@10.32.1",
22
+ "engines": {
23
+ "node": ">=22"
24
+ },
12
25
  "dependencies": {
13
- "@larksuiteoapi/node-sdk": "^1.59.0",
26
+ "@larksuiteoapi/node-sdk": "^1.60.0",
14
27
  "@sinclair/typebox": "0.34.48",
15
28
  "image-size": "^2.0.2",
16
29
  "zod": "^4.3.6"
@@ -40,13 +53,5 @@
40
53
  "localPath": "extensions/feishu",
41
54
  "defaultChoice": "npm"
42
55
  }
43
- },
44
- "types": "index.d.ts",
45
- "exports": {
46
- ".": {
47
- "types": "./index.d.ts",
48
- "import": "./index.js",
49
- "default": "./index.js"
50
- }
51
56
  }
52
57
  }
@@ -138,12 +138,14 @@ function formatElapsed(ms) {
138
138
  function buildFooter(zhText, enText, isError) {
139
139
  const zhContent = isError ? `<font color='red'>${zhText}</font>` : zhText;
140
140
  const enContent = isError ? `<font color='red'>${enText}</font>` : enText;
141
- return [{
141
+ return [
142
+ {
142
143
  tag: 'markdown',
143
144
  content: enContent,
144
145
  i18n_content: { zh_cn: zhContent, en_us: enContent },
145
146
  text_size: 'notation',
146
- }];
147
+ },
148
+ ];
147
149
  }
148
150
  function compactNumber(value) {
149
151
  const abs = Math.abs(value);
@@ -381,7 +383,7 @@ function buildCompleteCard(params) {
381
383
  }
382
384
  // Use the answer text (not reasoning) as the feed preview summary.
383
385
  // Strip markdown syntax so the preview reads as plain text.
384
- const summaryText = text.replace(/[*_`#>\[\]()~]/g, '').trim();
386
+ const summaryText = text.replace(/[*_`#>[\]()~]/g, '').trim();
385
387
  const summary = summaryText ? { content: summaryText.slice(0, 120) } : undefined;
386
388
  return {
387
389
  config: { wide_screen_mode: true, update_multi: true, locales: ['zh_cn', 'en_us'], summary },
@@ -140,7 +140,7 @@ function findMarkdownTablesOutsideCodeBlocks(text) {
140
140
  const codeBlockRanges = [];
141
141
  const codeBlockRegex = /```[\s\S]*?```/g;
142
142
  let codeBlockMatch = codeBlockRegex.exec(text);
143
- while (codeBlockMatch !== null) {
143
+ while (codeBlockMatch != null) {
144
144
  codeBlockRanges.push({
145
145
  start: codeBlockMatch.index,
146
146
  end: codeBlockMatch.index + codeBlockMatch[0].length,
@@ -151,7 +151,7 @@ function findMarkdownTablesOutsideCodeBlocks(text) {
151
151
  const tableRegex = /\|.+\|[\r\n]+\|[-:| ]+\|[\s\S]*?(?=\n\n|\n(?!\|)|$)/g;
152
152
  const matches = [];
153
153
  let tableMatch = tableRegex.exec(text);
154
- while (tableMatch !== null) {
154
+ while (tableMatch != null) {
155
155
  if (!isInsideCodeBlock(tableMatch.index)) {
156
156
  matches.push({
157
157
  index: tableMatch.index,
@@ -15,7 +15,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.createFeishuReplyDispatcher = createFeishuReplyDispatcher;
16
16
  const channel_runtime_1 = require("openclaw/plugin-sdk/channel-runtime");
17
17
  const channel_feedback_1 = require("openclaw/plugin-sdk/channel-feedback");
18
- const channel_runtime_2 = require("openclaw/plugin-sdk/channel-runtime");
19
18
  const accounts_1 = require("../core/accounts.js");
20
19
  const footer_config_1 = require("../core/footer-config.js");
21
20
  const lark_client_1 = require("../core/lark-client.js");
@@ -111,7 +110,7 @@ function createFeishuReplyDispatcher(params) {
111
110
  // ---- Typing indicator (reaction-based) ----
112
111
  let typingState = null;
113
112
  let typingStopped = false;
114
- const typingCallbacks = (0, channel_runtime_2.createTypingCallbacks)({
113
+ const typingCallbacks = (0, channel_runtime_1.createTypingCallbacks)({
115
114
  keepaliveIntervalMs: 0,
116
115
  start: async () => {
117
116
  if (shouldSkip('typing.start.precheck'))
@@ -8,7 +8,7 @@
8
8
  * lookups so the outbound subsystem and UI can resolve targets.
9
9
  */
10
10
  import type { ClawdbotConfig } from 'openclaw/plugin-sdk';
11
- import type { FeishuDirectoryPeer, FeishuDirectoryGroup } from './types';
11
+ import type { FeishuDirectoryGroup, FeishuDirectoryPeer } from './types';
12
12
  export type { FeishuDirectoryPeer, FeishuDirectoryGroup } from './types';
13
13
  /**
14
14
  * List users known from the channel config (allowFrom + dms fields).
@@ -47,7 +47,6 @@ exports.feishuPlugin = void 0;
47
47
  const account_id_1 = require("openclaw/plugin-sdk/account-id");
48
48
  const channel_status_1 = require("openclaw/plugin-sdk/channel-status");
49
49
  const accounts_1 = require("../core/accounts.js");
50
- const directory_1 = require("./directory.js");
51
50
  const outbound_1 = require("../messaging/outbound/outbound.js");
52
51
  const actions_1 = require("../messaging/outbound/actions.js");
53
52
  const policy_1 = require("../messaging/inbound/policy.js");
@@ -55,9 +54,10 @@ const lark_client_1 = require("../core/lark-client.js");
55
54
  const send_1 = require("../messaging/outbound/send.js");
56
55
  const targets_1 = require("../core/targets.js");
57
56
  const onboarding_auth_1 = require("../tools/onboarding-auth.js");
58
- const config_adapter_1 = require("./config-adapter.js");
59
57
  const lark_logger_1 = require("../core/lark-logger.js");
60
58
  const config_schema_1 = require("../core/config-schema.js");
59
+ const config_adapter_1 = require("./config-adapter.js");
60
+ const directory_1 = require("./directory.js");
61
61
  const pluginLog = (0, lark_logger_1.larkLogger)('channel/plugin');
62
62
  /** 状态轮询的探针结果缓存时长(10 分钟)。 */
63
63
  const PROBE_CACHE_TTL_MS = 10 * 60 * 1000;
@@ -2,8 +2,8 @@
2
2
  * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
3
3
  * SPDX-License-Identifier: MIT
4
4
  */
5
- import type { FeishuProbeResult } from './types';
6
5
  import { type LarkClientCredentials } from '../core/lark-client';
6
+ import type { FeishuProbeResult } from './types';
7
7
  /**
8
8
  * Probe the Feishu bot connection by calling the bot/v3/info API.
9
9
  *
@@ -9,8 +9,9 @@
9
9
  */
10
10
  import type { OpenClawConfig } from 'openclaw/plugin-sdk';
11
11
  export type { FeishuLocale } from './locale';
12
+ import type { FeishuLocale } from './locale';
12
13
  /** @deprecated Use FeishuLocale instead */
13
- export type DoctorLocale = import('./locale').FeishuLocale;
14
+ export type DoctorLocale = FeishuLocale;
14
15
  /**
15
16
  * 运行飞书插件诊断,生成 Markdown 格式报告。
16
17
  *
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * Register all chat commands (/feishu_diagnose, /feishu_doctor, /feishu_auth, /feishu).
6
6
  */
7
- import type { OpenClawPluginApi, OpenClawConfig } from 'openclaw/plugin-sdk';
7
+ import type { OpenClawConfig, OpenClawPluginApi } from 'openclaw/plugin-sdk';
8
8
  import type { FeishuLocale } from './locale';
9
9
  /**
10
10
  * 运行 /feishu start 校验,返回 Markdown 格式结果。
@@ -11,10 +11,10 @@ exports.runFeishuStartI18n = runFeishuStartI18n;
11
11
  exports.getFeishuHelp = getFeishuHelp;
12
12
  exports.getFeishuHelpI18n = getFeishuHelpI18n;
13
13
  exports.registerCommands = registerCommands;
14
+ const version_1 = require("../core/version.js");
14
15
  const diagnose_1 = require("./diagnose.js");
15
16
  const doctor_1 = require("./doctor.js");
16
17
  const auth_1 = require("./auth.js");
17
- const version_1 = require("../core/version.js");
18
18
  // ---------------------------------------------------------------------------
19
19
  // I18n text map for /feishu start, help, and error messages
20
20
  // ---------------------------------------------------------------------------
@@ -9,7 +9,7 @@
9
9
  * unset fields fall back to the top-level defaults.
10
10
  */
11
11
  import type { ClawdbotConfig } from 'openclaw/plugin-sdk';
12
- import type { FeishuConfig, LarkAccount, LarkCredentials, ConfiguredLarkAccount } from './types';
12
+ import type { ConfiguredLarkAccount, FeishuConfig, LarkAccount, LarkCredentials } from './types';
13
13
  /**
14
14
  * List all account IDs defined in the Lark config.
15
15
  *
@@ -18,9 +18,8 @@ exports.getEnabledLarkAccounts = getEnabledLarkAccounts;
18
18
  exports.getLarkCredentials = getLarkCredentials;
19
19
  exports.isConfigured = isConfigured;
20
20
  const account_id_1 = require("openclaw/plugin-sdk/account-id");
21
- const account_id_2 = require("openclaw/plugin-sdk/account-id");
22
- const normalizeAccountId = typeof account_id_2.normalizeAccountId === 'function'
23
- ? account_id_2.normalizeAccountId
21
+ const normalizeAccountId = typeof account_id_1.normalizeAccountId === 'function'
22
+ ? account_id_1.normalizeAccountId
24
23
  : (id) => id?.trim().toLowerCase() || undefined;
25
24
  // ---------------------------------------------------------------------------
26
25
  // Internal helpers
@@ -7,6 +7,7 @@
7
7
  * 所有 owner 判定统一使用 {@link getAppInfo} 返回的 `effectiveOwnerOpenId`。
8
8
  * 不维护独立缓存,完全依赖 app-scope-checker 的 30s 缓存。
9
9
  */
10
+ import type * as Lark from '@larksuiteoapi/node-sdk';
10
11
  import type { ConfiguredLarkAccount } from './types';
11
12
  /**
12
13
  * 获取应用的 effectiveOwnerOpenId。
@@ -18,4 +19,4 @@ import type { ConfiguredLarkAccount } from './types';
18
19
  * @param sdk - 飞书 SDK 实例(必须已初始化 TAT)
19
20
  * @returns 应用所有者的 open_id,如果查询失败则返回 undefined
20
21
  */
21
- export declare function getAppOwnerFallback(account: ConfiguredLarkAccount, sdk: any): Promise<string | undefined>;
22
+ export declare function getAppOwnerFallback(account: ConfiguredLarkAccount, sdk: Lark.Client): Promise<string | undefined>;
@@ -26,9 +26,7 @@ const log = (0, lark_logger_1.larkLogger)('core/app-owner-fallback');
26
26
  * @param sdk - 飞书 SDK 实例(必须已初始化 TAT)
27
27
  * @returns 应用所有者的 open_id,如果查询失败则返回 undefined
28
28
  */
29
- async function getAppOwnerFallback(account,
30
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
- sdk) {
29
+ async function getAppOwnerFallback(account, sdk) {
32
30
  const { appId } = account;
33
31
  try {
34
32
  const appInfo = await (0, app_scope_checker_1.getAppInfo)(sdk, appId);
@@ -41,9 +41,7 @@ exports.LARK_ERROR = {
41
41
  MESSAGE_DELETED: 231003,
42
42
  };
43
43
  /** refresh token 端点可重试的错误码集合(服务端瞬时故障)。遇到后重试一次,仍失败则清 token。 */
44
- exports.REFRESH_TOKEN_RETRYABLE = new Set([
45
- exports.LARK_ERROR.REFRESH_SERVER_ERROR,
46
- ]);
44
+ exports.REFRESH_TOKEN_RETRYABLE = new Set([exports.LARK_ERROR.REFRESH_SERVER_ERROR]);
47
45
  /** 消息终止错误码集合(撤回/删除),遇到后应停止对该消息的后续操作。 */
48
46
  exports.MESSAGE_TERMINAL_CODES = new Set([
49
47
  exports.LARK_ERROR.MESSAGE_RECALLED,
@@ -11,9 +11,16 @@
11
11
  * - `chat_mode`: "group" | "topic" | "p2p"
12
12
  * - `group_message_type`: "chat" | "thread" (only for chat_mode=group)
13
13
  */
14
+ import type * as Lark from '@larksuiteoapi/node-sdk';
14
15
  import type { ClawdbotConfig } from 'openclaw/plugin-sdk';
16
+ /** Minimal structural type for LarkClient class (avoids circular import). */
17
+ interface LarkClientStatic {
18
+ fromCfg(cfg: ClawdbotConfig, accountId?: string): {
19
+ sdk: Lark.Client;
20
+ };
21
+ }
15
22
  /** @internal Called by lark-client.ts at module init time. */
16
- export declare function injectLarkClient(cls: any): void;
23
+ export declare function injectLarkClient(cls: LarkClientStatic): void;
17
24
  export interface ChatInfo {
18
25
  chatMode: 'group' | 'topic' | 'p2p';
19
26
  groupMessageType?: 'chat' | 'thread';
@@ -57,3 +64,4 @@ export declare function getChatTypeFeishu(params: {
57
64
  chatId: string;
58
65
  accountId?: string;
59
66
  }): Promise<'p2p' | 'group'>;
67
+ export {};
@@ -19,15 +19,8 @@ exports.isThreadCapableGroup = isThreadCapableGroup;
19
19
  exports.getChatInfo = getChatInfo;
20
20
  exports.getChatTypeFeishu = getChatTypeFeishu;
21
21
  const lark_logger_1 = require("./lark-logger.js");
22
- // ---------------------------------------------------------------------------
23
- // LarkClient injection — breaks circular dependency with lark-client.ts.
24
- // lark-client.ts calls injectLarkClient() at module init time, so the
25
- // reference is available before any message processing begins.
26
- // ---------------------------------------------------------------------------
27
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
22
  let _LarkClient = null;
29
23
  /** @internal Called by lark-client.ts at module init time. */
30
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
24
  function injectLarkClient(cls) {
32
25
  _LarkClient = cls;
33
26
  }
@@ -21,6 +21,7 @@ export declare const FeishuGroupSchema: z.ZodObject<{
21
21
  disabled: "disabled";
22
22
  }>>;
23
23
  requireMention: z.ZodOptional<z.ZodBoolean>;
24
+ respondToMentionAll: z.ZodOptional<z.ZodBoolean>;
24
25
  tools: z.ZodOptional<z.ZodObject<{
25
26
  allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
26
27
  deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -58,6 +59,7 @@ export declare const FeishuAccountConfigSchema: z.ZodObject<{
58
59
  }>>;
59
60
  groupAllowFrom: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>, z.ZodTransform<string[] | undefined, string | string[] | undefined>>;
60
61
  requireMention: z.ZodOptional<z.ZodBoolean>;
62
+ respondToMentionAll: z.ZodOptional<z.ZodBoolean>;
61
63
  groups: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
62
64
  groupPolicy: z.ZodOptional<z.ZodEnum<{
63
65
  open: "open";
@@ -65,6 +67,7 @@ export declare const FeishuAccountConfigSchema: z.ZodObject<{
65
67
  disabled: "disabled";
66
68
  }>>;
67
69
  requireMention: z.ZodOptional<z.ZodBoolean>;
70
+ respondToMentionAll: z.ZodOptional<z.ZodBoolean>;
68
71
  tools: z.ZodOptional<z.ZodObject<{
69
72
  allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
70
73
  deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -198,6 +201,7 @@ export declare const FeishuConfigSchema: z.ZodObject<{
198
201
  }>>;
199
202
  groupAllowFrom: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>, z.ZodTransform<string[] | undefined, string | string[] | undefined>>;
200
203
  requireMention: z.ZodOptional<z.ZodBoolean>;
204
+ respondToMentionAll: z.ZodOptional<z.ZodBoolean>;
201
205
  groups: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
202
206
  groupPolicy: z.ZodOptional<z.ZodEnum<{
203
207
  open: "open";
@@ -205,6 +209,7 @@ export declare const FeishuConfigSchema: z.ZodObject<{
205
209
  disabled: "disabled";
206
210
  }>>;
207
211
  requireMention: z.ZodOptional<z.ZodBoolean>;
212
+ respondToMentionAll: z.ZodOptional<z.ZodBoolean>;
208
213
  tools: z.ZodOptional<z.ZodObject<{
209
214
  allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
210
215
  deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -337,6 +342,7 @@ export declare const FeishuConfigSchema: z.ZodObject<{
337
342
  }>>;
338
343
  groupAllowFrom: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>, z.ZodTransform<string[] | undefined, string | string[] | undefined>>;
339
344
  requireMention: z.ZodOptional<z.ZodBoolean>;
345
+ respondToMentionAll: z.ZodOptional<z.ZodBoolean>;
340
346
  groups: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
341
347
  groupPolicy: z.ZodOptional<z.ZodEnum<{
342
348
  open: "open";
@@ -344,6 +350,7 @@ export declare const FeishuConfigSchema: z.ZodObject<{
344
350
  disabled: "disabled";
345
351
  }>>;
346
352
  requireMention: z.ZodOptional<z.ZodBoolean>;
353
+ respondToMentionAll: z.ZodOptional<z.ZodBoolean>;
347
354
  tools: z.ZodOptional<z.ZodObject<{
348
355
  allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
349
356
  deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -35,7 +35,7 @@ const AllowFromSchema = zod_1.z
35
35
  .union([zod_1.z.string(), zod_1.z.array(zod_1.z.string())])
36
36
  .optional()
37
37
  .transform((v) => {
38
- if (v === undefined || v === null)
38
+ if (v === undefined || v == null)
39
39
  return undefined;
40
40
  return Array.isArray(v) ? v : [v];
41
41
  });
@@ -124,6 +124,7 @@ const DmConfigSchema = zod_1.z
124
124
  exports.FeishuGroupSchema = zod_1.z.object({
125
125
  groupPolicy: GroupPolicyEnum.optional(),
126
126
  requireMention: zod_1.z.boolean().optional(),
127
+ respondToMentionAll: zod_1.z.boolean().optional(),
127
128
  tools: ToolPolicySchema,
128
129
  skills: zod_1.z.array(zod_1.z.string()).optional(),
129
130
  enabled: zod_1.z.boolean().optional(),
@@ -149,6 +150,7 @@ exports.FeishuAccountConfigSchema = zod_1.z.object({
149
150
  groupPolicy: GroupPolicyEnum.optional(),
150
151
  groupAllowFrom: AllowFromSchema,
151
152
  requireMention: zod_1.z.boolean().optional(),
153
+ respondToMentionAll: zod_1.z.boolean().optional(),
152
154
  groups: zod_1.z.record(zod_1.z.string(), exports.FeishuGroupSchema).optional(),
153
155
  historyLimit: zod_1.z.number().optional(),
154
156
  dmHistoryLimit: zod_1.z.number().optional(),
@@ -14,8 +14,8 @@
14
14
  */
15
15
  import * as Lark from '@larksuiteoapi/node-sdk';
16
16
  import type { ClawdbotConfig, PluginRuntime } from 'openclaw/plugin-sdk';
17
- import type { LarkBrand, LarkAccount, FeishuProbeResult } from './types';
18
17
  import type { MessageDedup } from '../messaging/inbound/dedup';
18
+ import type { FeishuProbeResult, LarkAccount, LarkBrand } from './types';
19
19
  /** Credential set accepted by the ephemeral `fromCredentials` factory. */
20
20
  export interface LarkClientCredentials {
21
21
  accountId?: string;
@@ -33,7 +33,6 @@ export declare class LarkClient {
33
33
  private _lastProbeAt;
34
34
  /** Attached message deduplicator — disposed together with the client. */
35
35
  messageDedup: MessageDedup | null;
36
- private static _runtime;
37
36
  /** Persist the runtime instance for later retrieval (activate 阶段调用一次). */
38
37
  static setRuntime(runtime: PluginRuntime): void;
39
38
  /** Retrieve the stored runtime instance. Throws if not yet initialised. */
@@ -51,12 +51,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
51
51
  exports.LarkClient = void 0;
52
52
  exports.getResolvedConfig = getResolvedConfig;
53
53
  const Lark = __importStar(require("@larksuiteoapi/node-sdk"));
54
+ const user_name_cache_store_1 = require("../messaging/inbound/user-name-cache-store.js");
54
55
  const accounts_1 = require("./accounts.js");
55
- // NOTE: clearUserNameCache is lazy-imported in clearCache() to break a
56
- // circular dependency with user-name-cache.ts (which imports LarkClient).
57
56
  const chat_info_cache_1 = require("./chat-info-cache.js");
58
- const version_1 = require("./version.js");
59
57
  const lark_logger_1 = require("./lark-logger.js");
58
+ const runtime_store_1 = require("./runtime-store.js");
59
+ const version_1 = require("./version.js");
60
60
  const log = (0, lark_logger_1.larkLogger)('core/lark-client');
61
61
  // ---------------------------------------------------------------------------
62
62
  // 注入 User-Agent 到所有飞书 SDK 请求
@@ -134,18 +134,13 @@ class LarkClient {
134
134
  /** Attached message deduplicator — disposed together with the client. */
135
135
  messageDedup = null;
136
136
  // ---- Plugin runtime (singleton) ------------------------------------------
137
- static _runtime = null;
138
137
  /** Persist the runtime instance for later retrieval (activate 阶段调用一次). */
139
138
  static setRuntime(runtime) {
140
- LarkClient._runtime = runtime;
139
+ (0, runtime_store_1.setLarkRuntime)(runtime);
141
140
  }
142
141
  /** Retrieve the stored runtime instance. Throws if not yet initialised. */
143
142
  static get runtime() {
144
- if (!LarkClient._runtime) {
145
- throw new Error('Feishu plugin runtime has not been initialised. ' +
146
- 'Ensure LarkClient.setRuntime() is called during plugin activation.');
147
- }
148
- return LarkClient._runtime;
143
+ return (0, runtime_store_1.getLarkRuntime)();
149
144
  }
150
145
  // ---- Global config (singleton) -------------------------------------------
151
146
  //
@@ -181,7 +176,9 @@ class LarkClient {
181
176
  */
182
177
  static fromAccount(account) {
183
178
  const existing = cache.get(account.accountId);
184
- if (existing && existing.account.appId === account.appId && credentialsEqual(existing.account.appSecret, account.appSecret)) {
179
+ if (existing &&
180
+ existing.account.appId === account.appId &&
181
+ credentialsEqual(existing.account.appSecret, account.appSecret)) {
185
182
  return existing;
186
183
  }
187
184
  // Credentials changed — tear down the stale instance before replacing it.
@@ -220,16 +217,15 @@ class LarkClient {
220
217
  * Without — dispose every cached instance and clear the cache.
221
218
  */
222
219
  static async clearCache(accountId) {
223
- const { clearUserNameCache } = await Promise.resolve().then(() => __importStar(require('../messaging/inbound/user-name-cache.js')));
224
220
  if (accountId !== undefined) {
225
221
  cache.get(accountId)?.dispose();
226
- clearUserNameCache(accountId);
222
+ (0, user_name_cache_store_1.clearUserNameCache)(accountId);
227
223
  (0, chat_info_cache_1.clearChatInfoCache)(accountId);
228
224
  }
229
225
  else {
230
226
  for (const inst of cache.values())
231
227
  inst.dispose();
232
- clearUserNameCache();
228
+ (0, user_name_cache_store_1.clearUserNameCache)();
233
229
  (0, chat_info_cache_1.clearChatInfoCache)();
234
230
  }
235
231
  }
@@ -363,7 +359,7 @@ class LarkClient {
363
359
  }
364
360
  /** Whether a WebSocket client is currently active. */
365
361
  get wsConnected() {
366
- return this._wsClient !== null;
362
+ return this._wsClient != null;
367
363
  }
368
364
  /** Disconnect WebSocket but keep instance in cache. */
369
365
  disconnect() {
@@ -15,8 +15,8 @@
15
15
  */
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.larkLogger = larkLogger;
18
- const lark_client_1 = require("./lark-client.js");
19
18
  const lark_ticket_1 = require("./lark-ticket.js");
19
+ const runtime_store_1 = require("./runtime-store.js");
20
20
  // ---------------------------------------------------------------------------
21
21
  // Console fallback (with ANSI colors)
22
22
  // ---------------------------------------------------------------------------
@@ -42,7 +42,10 @@ function consoleFallback(subsystem) {
42
42
  // ---------------------------------------------------------------------------
43
43
  function resolveRuntimeLogger(subsystem) {
44
44
  try {
45
- return lark_client_1.LarkClient.runtime.logging.getChildLogger({
45
+ const runtime = (0, runtime_store_1.tryGetLarkRuntime)();
46
+ if (!runtime)
47
+ return null;
48
+ return runtime.logging.getChildLogger({
46
49
  subsystem: `feishu/${subsystem}`,
47
50
  });
48
51
  }
@@ -105,7 +108,7 @@ function formatMessage(message, meta) {
105
108
  return `${prefix} ${message}`;
106
109
  const parts = Object.entries(meta)
107
110
  .map(([k, v]) => {
108
- if (v === undefined || v === null)
111
+ if (v === undefined || v == null)
109
112
  return null;
110
113
  if (typeof v === 'object')
111
114
  return `${k}=${JSON.stringify(v)}`;
@@ -8,7 +8,7 @@
8
8
  * 1) 当命中飞书终止错误码(230011/231003)时,按 message_id 标记不可用;
9
9
  * 2) 后续针对该 message_id 的 API 调用直接短路,避免持续报错刷屏。
10
10
  */
11
- import { LARK_ERROR } from './auth-errors';
11
+ import type { LARK_ERROR } from './auth-errors';
12
12
  export type TerminalMessageApiCode = typeof LARK_ERROR.MESSAGE_RECALLED | typeof LARK_ERROR.MESSAGE_DELETED;
13
13
  export interface MessageUnavailableState {
14
14
  apiCode: TerminalMessageApiCode;
@@ -94,7 +94,7 @@ class MessageUnavailableError extends Error {
94
94
  exports.MessageUnavailableError = MessageUnavailableError;
95
95
  function isMessageUnavailableError(error) {
96
96
  return (error instanceof MessageUnavailableError ||
97
- (typeof error === 'object' && error !== null && error.name === 'MessageUnavailableError'));
97
+ (typeof error === 'object' && error != null && error.name === 'MessageUnavailableError'));
98
98
  }
99
99
  function assertMessageAvailable(messageId, operation) {
100
100
  const normalizedId = (0, targets_1.normalizeMessageId)(messageId);
@@ -7,6 +7,7 @@
7
7
  * 从 uat-client.ts 迁移 owner 检查逻辑到独立 policy 层。
8
8
  * 提供 fail-close 策略(安全优先:授权发起路径)。
9
9
  */
10
+ import type * as Lark from '@larksuiteoapi/node-sdk';
10
11
  import type { ConfiguredLarkAccount } from './types';
11
12
  /**
12
13
  * 非应用 owner 尝试执行 owner-only 操作时抛出。
@@ -28,4 +29,4 @@ export declare class OwnerAccessDeniedError extends Error {
28
29
  * 适用于:`executeAuthorize`(OAuth 授权发起)、`commands/auth.ts`(批量授权)等
29
30
  * 赋予实质性权限的入口。
30
31
  */
31
- export declare function assertOwnerAccessStrict(account: ConfiguredLarkAccount, sdk: any, userOpenId: string): Promise<void>;
32
+ export declare function assertOwnerAccessStrict(account: ConfiguredLarkAccount, sdk: Lark.Client, userOpenId: string): Promise<void>;
@@ -44,9 +44,7 @@ exports.OwnerAccessDeniedError = OwnerAccessDeniedError;
44
44
  * 适用于:`executeAuthorize`(OAuth 授权发起)、`commands/auth.ts`(批量授权)等
45
45
  * 赋予实质性权限的入口。
46
46
  */
47
- async function assertOwnerAccessStrict(account,
48
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
- sdk, userOpenId) {
47
+ async function assertOwnerAccessStrict(account, sdk, userOpenId) {
50
48
  const ownerOpenId = await (0, app_owner_fallback_1.getAppOwnerFallback)(account, sdk);
51
49
  if (!ownerOpenId) {
52
50
  throw new OwnerAccessDeniedError(userOpenId, 'unknown');
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * Shared runtime store for the Feishu plugin.
6
+ *
7
+ * Allows modules such as the logger to access the plugin runtime without
8
+ * importing LarkClient directly, which would otherwise create static cycles.
9
+ */
10
+ import type { PluginRuntime } from 'openclaw/plugin-sdk';
11
+ export declare function setLarkRuntime(nextRuntime: PluginRuntime): void;
12
+ export declare function tryGetLarkRuntime(): PluginRuntime | null;
13
+ export declare function getLarkRuntime(): PluginRuntime;