@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.
- package/bin/openclaw-lark.js +10 -22
- package/openclaw.plugin.json +8 -1
- package/package.json +16 -11
- package/src/card/builder.js +5 -3
- package/src/card/card-error.js +2 -2
- package/src/card/reply-dispatcher.js +1 -2
- package/src/channel/directory.d.ts +1 -1
- package/src/channel/plugin.js +2 -2
- package/src/channel/probe.d.ts +1 -1
- package/src/commands/doctor.d.ts +2 -1
- package/src/commands/index.d.ts +1 -1
- package/src/commands/index.js +1 -1
- package/src/core/accounts.d.ts +1 -1
- package/src/core/accounts.js +2 -3
- package/src/core/app-owner-fallback.d.ts +2 -1
- package/src/core/app-owner-fallback.js +1 -3
- package/src/core/auth-errors.js +1 -3
- package/src/core/chat-info-cache.d.ts +9 -1
- package/src/core/chat-info-cache.js +0 -7
- package/src/core/config-schema.d.ts +7 -0
- package/src/core/config-schema.js +3 -1
- package/src/core/lark-client.d.ts +1 -2
- package/src/core/lark-client.js +11 -15
- package/src/core/lark-logger.js +6 -3
- package/src/core/message-unavailable.d.ts +1 -1
- package/src/core/message-unavailable.js +1 -1
- package/src/core/owner-policy.d.ts +2 -1
- package/src/core/owner-policy.js +1 -3
- package/src/core/runtime-store.d.ts +13 -0
- package/src/core/runtime-store.js +29 -0
- package/src/core/scope-manager.d.ts +1 -1
- package/src/core/tool-client.d.ts +2 -2
- package/src/core/tool-client.js +2 -2
- package/src/core/tools-config.d.ts +1 -1
- package/src/core/types.d.ts +1 -1
- package/src/messaging/converters/audio.js +1 -2
- package/src/messaging/converters/content-converter-helpers.d.ts +25 -0
- package/src/messaging/converters/content-converter-helpers.js +76 -0
- package/src/messaging/converters/content-converter.d.ts +2 -19
- package/src/messaging/converters/content-converter.js +7 -79
- package/src/messaging/converters/interactive/card-converter.d.ts +1 -1
- package/src/messaging/converters/interactive/card-converter.js +22 -22
- package/src/messaging/converters/interactive/legacy.js +1 -1
- package/src/messaging/converters/merge-forward.js +15 -9
- package/src/messaging/converters/post.js +2 -2
- package/src/messaging/converters/text.js +2 -2
- package/src/messaging/converters/types.d.ts +7 -0
- package/src/messaging/converters/video.js +1 -2
- package/src/messaging/inbound/dispatch-builders.d.ts +1 -1
- package/src/messaging/inbound/dispatch-builders.js +1 -1
- package/src/messaging/inbound/dispatch-commands.d.ts +2 -2
- package/src/messaging/inbound/dispatch.d.ts +2 -4
- package/src/messaging/inbound/dispatch.js +12 -5
- package/src/messaging/inbound/enrich.d.ts +1 -1
- package/src/messaging/inbound/enrich.js +3 -4
- package/src/messaging/inbound/gate.d.ts +17 -2
- package/src/messaging/inbound/gate.js +24 -0
- package/src/messaging/inbound/handler-registry.d.ts +25 -0
- package/src/messaging/inbound/handler-registry.js +23 -0
- package/src/messaging/inbound/handler.js +3 -1
- package/src/messaging/inbound/mention.d.ts +9 -0
- package/src/messaging/inbound/mention.js +10 -0
- package/src/messaging/inbound/parse.js +16 -1
- package/src/messaging/inbound/reaction-handler.js +4 -3
- package/src/messaging/inbound/synthetic-message.d.ts +26 -0
- package/src/messaging/inbound/synthetic-message.js +59 -0
- package/src/messaging/inbound/user-name-cache-store.d.ts +22 -0
- package/src/messaging/inbound/user-name-cache-store.js +99 -0
- package/src/messaging/inbound/user-name-cache.d.ts +1 -29
- package/src/messaging/inbound/user-name-cache.js +8 -114
- package/src/messaging/outbound/actions.js +4 -4
- package/src/messaging/outbound/deliver.js +5 -5
- package/src/messaging/outbound/media.js +1 -1
- package/src/messaging/outbound/outbound.js +1 -1
- package/src/messaging/outbound/reactions.js +1 -1
- package/src/messaging/outbound/send.d.ts +1 -2
- package/src/messaging/types.d.ts +2 -0
- package/src/tools/ask-user-question.d.ts +1 -1
- package/src/tools/ask-user-question.js +103 -10
- package/src/tools/auto-auth.d.ts +2 -1
- package/src/tools/auto-auth.js +26 -50
- package/src/tools/helpers.d.ts +13 -10
- package/src/tools/helpers.js +1 -1
- package/src/tools/mcp/shared.js +3 -3
- package/src/tools/oapi/calendar/event.js +2 -2
- package/src/tools/oapi/drive/doc-media.js +3 -3
- package/src/tools/oapi/drive/file.js +2 -2
- package/src/tools/oapi/helpers.d.ts +4 -3
- package/src/tools/oapi/helpers.js +3 -4
- package/src/tools/oapi/im/format-messages.d.ts +2 -2
- package/src/tools/oapi/im/resource.js +2 -2
- package/src/tools/oapi/im/user-name-uat.js +0 -2
- package/src/tools/oapi/index.js +27 -27
- package/src/tools/oapi/sheets/sheet.js +2 -2
- package/src/tools/oauth-batch-auth.js +2 -2
- package/src/tools/oauth-cards.js +1 -2
- package/src/tools/oauth.d.ts +1 -1
- package/src/tools/oauth.js +24 -56
- package/src/tools/onboarding-auth.js +1 -1
- package/src/tools/tat/im/resource.js +2 -2
- package/tsdown.config.d.ts +1 -14
- package/tsdown.config.js +8 -5
- package/vitest.config.d.ts +2 -0
- package/vitest.config.js +12 -0
package/bin/openclaw-lark.js
CHANGED
|
@@ -1,47 +1,35 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import {
|
|
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 =
|
|
7
|
+
let version = 'latest';
|
|
9
8
|
|
|
10
|
-
const vIdx = args.indexOf(
|
|
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 = [
|
|
16
|
+
const allArgs = ['--yes', '--prefer-online', `@larksuite/openclaw-lark-tools@${version}`, ...args];
|
|
18
17
|
|
|
19
18
|
try {
|
|
20
|
-
if (process.platform ===
|
|
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:
|
|
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(
|
|
32
|
+
execFileSync('npx', allArgs, { stdio: 'inherit' });
|
|
45
33
|
}
|
|
46
34
|
} catch (error) {
|
|
47
35
|
process.exit(error.status ?? 1);
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@larksuite/openclaw-lark",
|
|
3
|
-
"version": "2026.3.
|
|
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.
|
|
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
|
}
|
package/src/card/builder.js
CHANGED
|
@@ -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(/[*_
|
|
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 },
|
package/src/card/card-error.js
CHANGED
|
@@ -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
|
|
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
|
|
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,
|
|
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 {
|
|
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).
|
package/src/channel/plugin.js
CHANGED
|
@@ -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;
|
package/src/channel/probe.d.ts
CHANGED
|
@@ -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
|
*
|
package/src/commands/doctor.d.ts
CHANGED
|
@@ -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 =
|
|
14
|
+
export type DoctorLocale = FeishuLocale;
|
|
14
15
|
/**
|
|
15
16
|
* 运行飞书插件诊断,生成 Markdown 格式报告。
|
|
16
17
|
*
|
package/src/commands/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Register all chat commands (/feishu_diagnose, /feishu_doctor, /feishu_auth, /feishu).
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
7
|
+
import type { OpenClawConfig, OpenClawPluginApi } from 'openclaw/plugin-sdk';
|
|
8
8
|
import type { FeishuLocale } from './locale';
|
|
9
9
|
/**
|
|
10
10
|
* 运行 /feishu start 校验,返回 Markdown 格式结果。
|
package/src/commands/index.js
CHANGED
|
@@ -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
|
// ---------------------------------------------------------------------------
|
package/src/core/accounts.d.ts
CHANGED
|
@@ -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
|
|
12
|
+
import type { ConfiguredLarkAccount, FeishuConfig, LarkAccount, LarkCredentials } from './types';
|
|
13
13
|
/**
|
|
14
14
|
* List all account IDs defined in the Lark config.
|
|
15
15
|
*
|
package/src/core/accounts.js
CHANGED
|
@@ -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
|
|
22
|
-
|
|
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:
|
|
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);
|
package/src/core/auth-errors.js
CHANGED
|
@@ -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:
|
|
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
|
|
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. */
|
package/src/core/lark-client.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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 &&
|
|
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
|
|
362
|
+
return this._wsClient != null;
|
|
367
363
|
}
|
|
368
364
|
/** Disconnect WebSocket but keep instance in cache. */
|
|
369
365
|
disconnect() {
|
package/src/core/lark-logger.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
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:
|
|
32
|
+
export declare function assertOwnerAccessStrict(account: ConfiguredLarkAccount, sdk: Lark.Client, userOpenId: string): Promise<void>;
|
package/src/core/owner-policy.js
CHANGED
|
@@ -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;
|