@openclaw/feishu 2026.3.13 → 2026.5.1-beta.1
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/api.ts +31 -0
- package/channel-entry.ts +20 -0
- package/channel-plugin-api.ts +1 -0
- package/contract-api.ts +16 -0
- package/index.ts +70 -53
- package/openclaw.plugin.json +1653 -4
- package/package.json +32 -7
- package/runtime-api.ts +55 -0
- package/secret-contract-api.ts +5 -0
- package/security-contract-api.ts +1 -0
- package/session-key-api.ts +1 -0
- package/setup-api.ts +3 -0
- package/setup-entry.test.ts +14 -0
- package/setup-entry.ts +13 -0
- package/src/accounts.test.ts +95 -7
- package/src/accounts.ts +199 -117
- package/src/app-registration.ts +331 -0
- package/src/approval-auth.test.ts +24 -0
- package/src/approval-auth.ts +25 -0
- package/src/async.test.ts +35 -0
- package/src/async.ts +43 -1
- package/src/audio-preflight.runtime.ts +9 -0
- package/src/bitable.test.ts +131 -0
- package/src/bitable.ts +59 -22
- package/src/bot-content.ts +474 -0
- package/src/bot-group-name.test.ts +108 -0
- package/src/bot-runtime-api.ts +12 -0
- package/src/bot-sender-name.ts +125 -0
- package/src/bot.broadcast.test.ts +463 -0
- package/src/bot.card-action.test.ts +519 -5
- package/src/bot.checkBotMentioned.test.ts +92 -20
- package/src/bot.helpers.test.ts +118 -0
- package/src/bot.stripBotMention.test.ts +13 -21
- package/src/bot.test.ts +1334 -401
- package/src/bot.ts +778 -775
- package/src/card-action.ts +408 -40
- package/src/card-interaction.test.ts +129 -0
- package/src/card-interaction.ts +159 -0
- package/src/card-test-helpers.ts +47 -0
- package/src/card-ux-approval.ts +65 -0
- package/src/card-ux-launcher.test.ts +99 -0
- package/src/card-ux-launcher.ts +121 -0
- package/src/card-ux-shared.ts +33 -0
- package/src/channel-runtime-api.ts +16 -0
- package/src/channel.runtime.ts +47 -0
- package/src/channel.test.ts +914 -3
- package/src/channel.ts +1252 -309
- package/src/chat-schema.ts +5 -4
- package/src/chat.test.ts +84 -28
- package/src/chat.ts +68 -10
- package/src/client.test.ts +212 -103
- package/src/client.ts +115 -21
- package/src/comment-dispatcher-runtime-api.ts +6 -0
- package/src/comment-dispatcher.test.ts +169 -0
- package/src/comment-dispatcher.ts +107 -0
- package/src/comment-handler-runtime-api.ts +3 -0
- package/src/comment-handler.test.ts +486 -0
- package/src/comment-handler.ts +309 -0
- package/src/comment-reaction.test.ts +166 -0
- package/src/comment-reaction.ts +259 -0
- package/src/comment-shared.test.ts +182 -0
- package/src/comment-shared.ts +365 -0
- package/src/comment-target.ts +44 -0
- package/src/config-schema.test.ts +63 -1
- package/src/config-schema.ts +31 -4
- package/src/conversation-id.test.ts +18 -0
- package/src/conversation-id.ts +199 -0
- package/src/dedup-runtime-api.ts +1 -0
- package/src/dedup.ts +32 -94
- package/src/directory.static.ts +61 -0
- package/src/directory.test.ts +119 -20
- package/src/directory.ts +61 -91
- package/src/doc-schema.ts +1 -1
- package/src/docx-batch-insert.test.ts +39 -38
- package/src/docx-batch-insert.ts +55 -19
- package/src/docx-color-text.ts +9 -4
- package/src/docx-table-ops.test.ts +53 -0
- package/src/docx-table-ops.ts +52 -34
- package/src/docx-types.ts +38 -0
- package/src/docx.account-selection.test.ts +12 -3
- package/src/docx.test.ts +314 -74
- package/src/docx.ts +278 -122
- package/src/drive-schema.ts +47 -1
- package/src/drive.test.ts +1219 -0
- package/src/drive.ts +614 -13
- package/src/dynamic-agent.ts +10 -4
- package/src/event-types.ts +45 -0
- package/src/external-keys.ts +1 -1
- package/src/lifecycle.test-support.ts +220 -0
- package/src/media.test.ts +375 -26
- package/src/media.ts +434 -88
- package/src/mention-target.types.ts +5 -0
- package/src/mention.ts +32 -51
- package/src/message-action-contract.ts +13 -0
- package/src/monitor-state-runtime-api.ts +7 -0
- package/src/monitor-transport-runtime-api.ts +7 -0
- package/src/monitor.account.ts +218 -312
- package/src/monitor.acp-init-failure.lifecycle.test-support.ts +219 -0
- package/src/monitor.bot-identity.ts +86 -0
- package/src/monitor.bot-menu-handler.ts +165 -0
- package/src/monitor.bot-menu.lifecycle.test-support.ts +224 -0
- package/src/monitor.bot-menu.test.ts +178 -0
- package/src/monitor.broadcast.reply-once.lifecycle.test-support.ts +264 -0
- package/src/monitor.card-action.lifecycle.test-support.ts +373 -0
- package/src/monitor.cleanup.test.ts +376 -0
- package/src/monitor.comment-notice-handler.ts +105 -0
- package/src/monitor.comment.test.ts +937 -0
- package/src/monitor.comment.ts +1386 -0
- package/src/monitor.lifecycle.test.ts +4 -0
- package/src/monitor.message-handler.ts +339 -0
- package/src/monitor.reaction.lifecycle.test-support.ts +68 -0
- package/src/monitor.reaction.test.ts +108 -48
- package/src/monitor.reply-once.lifecycle.test-support.ts +190 -0
- package/src/monitor.startup.test.ts +11 -9
- package/src/monitor.startup.ts +26 -16
- package/src/monitor.state.ts +20 -5
- package/src/monitor.synthetic-error.ts +18 -0
- package/src/monitor.test-mocks.ts +2 -2
- package/src/monitor.transport.ts +220 -60
- package/src/monitor.ts +15 -10
- package/src/monitor.webhook-e2e.test.ts +65 -7
- package/src/monitor.webhook-security.test.ts +122 -0
- package/src/monitor.webhook.test-helpers.ts +44 -26
- package/src/outbound-runtime-api.ts +1 -0
- package/src/outbound.test.ts +616 -37
- package/src/outbound.ts +623 -81
- package/src/perm-schema.ts +1 -1
- package/src/perm.ts +1 -7
- package/src/pins.ts +108 -0
- package/src/policy.test.ts +297 -117
- package/src/policy.ts +142 -29
- package/src/post.ts +7 -6
- package/src/probe.test.ts +14 -9
- package/src/probe.ts +26 -16
- package/src/processing-claims.ts +59 -0
- package/src/qr-terminal.ts +1 -0
- package/src/reactions.ts +4 -34
- package/src/reasoning-preview.test.ts +59 -0
- package/src/reasoning-preview.ts +20 -0
- package/src/reply-dispatcher-runtime-api.ts +7 -0
- package/src/reply-dispatcher.test.ts +660 -29
- package/src/reply-dispatcher.ts +407 -154
- package/src/runtime.ts +6 -3
- package/src/secret-contract.ts +145 -0
- package/src/secret-input.ts +1 -13
- package/src/security-audit-shared.ts +69 -0
- package/src/security-audit.test.ts +61 -0
- package/src/security-audit.ts +1 -0
- package/src/send-result.ts +1 -1
- package/src/send-target.test.ts +9 -3
- package/src/send-target.ts +10 -4
- package/src/send.reply-fallback.test.ts +77 -2
- package/src/send.test.ts +386 -4
- package/src/send.ts +399 -86
- package/src/sequential-key.test.ts +72 -0
- package/src/sequential-key.ts +28 -0
- package/src/sequential-queue.test.ts +92 -0
- package/src/sequential-queue.ts +16 -0
- package/src/session-conversation.ts +42 -0
- package/src/session-route.ts +48 -0
- package/src/setup-core.ts +51 -0
- package/src/{onboarding.test.ts → setup-surface.test.ts} +52 -21
- package/src/setup-surface.ts +581 -0
- package/src/streaming-card.test.ts +138 -2
- package/src/streaming-card.ts +134 -18
- package/src/subagent-hooks.test.ts +603 -0
- package/src/subagent-hooks.ts +397 -0
- package/src/targets.ts +3 -13
- package/src/test-support/lifecycle-test-support.ts +479 -0
- package/src/thread-bindings.test.ts +143 -0
- package/src/thread-bindings.ts +330 -0
- package/src/tool-account-routing.test.ts +66 -8
- package/src/tool-account.test.ts +44 -0
- package/src/tool-account.ts +40 -17
- package/src/tool-factory-test-harness.ts +11 -8
- package/src/tool-result.ts +3 -1
- package/src/tools-config.ts +1 -1
- package/src/types.ts +16 -15
- package/src/typing.ts +10 -6
- package/src/wiki-schema.ts +1 -1
- package/src/wiki.ts +1 -7
- package/subagent-hooks-api.ts +31 -0
- package/tsconfig.json +16 -0
- package/src/feishu-command-handler.ts +0 -59
- package/src/onboarding.status.test.ts +0 -25
- package/src/onboarding.ts +0 -489
- package/src/send-message.ts +0 -71
- package/src/targets.test.ts +0 -70
package/src/accounts.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_ACCOUNT_ID,
|
|
3
|
+
type OpenClawConfig as ClawdbotConfig,
|
|
4
|
+
createAccountListHelpers,
|
|
5
|
+
normalizeAccountId,
|
|
6
|
+
normalizeOptionalAccountId,
|
|
7
|
+
resolveMergedAccountConfig,
|
|
8
|
+
} from "openclaw/plugin-sdk/account-resolution";
|
|
9
|
+
import { coerceSecretRef } from "openclaw/plugin-sdk/provider-auth";
|
|
10
|
+
import { normalizeString } from "./comment-shared.js";
|
|
4
11
|
import type {
|
|
5
12
|
FeishuConfig,
|
|
6
13
|
FeishuAccountConfig,
|
|
@@ -9,28 +16,126 @@ import type {
|
|
|
9
16
|
ResolvedFeishuAccount,
|
|
10
17
|
} from "./types.js";
|
|
11
18
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
const { listAccountIds: listFeishuAccountIds, resolveDefaultAccountId } = createAccountListHelpers(
|
|
20
|
+
"feishu",
|
|
21
|
+
{
|
|
22
|
+
allowUnlistedDefaultAccount: true,
|
|
23
|
+
},
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
export { listFeishuAccountIds };
|
|
27
|
+
|
|
28
|
+
type FeishuCredentialResolutionMode = "inspect" | "strict";
|
|
29
|
+
type FeishuResolvedSecretRef = NonNullable<ReturnType<typeof coerceSecretRef>>;
|
|
30
|
+
|
|
31
|
+
function formatSecretRefLabel(ref: FeishuResolvedSecretRef): string {
|
|
32
|
+
return `${ref.source}:${ref.provider}:${ref.id}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class FeishuSecretRefUnavailableError extends Error {
|
|
36
|
+
path: string;
|
|
37
|
+
|
|
38
|
+
constructor(path: string, ref: FeishuResolvedSecretRef) {
|
|
39
|
+
super(
|
|
40
|
+
`${path}: unresolved SecretRef "${formatSecretRefLabel(ref)}". ` +
|
|
41
|
+
"Resolve this command against an active gateway runtime snapshot before reading it.",
|
|
42
|
+
);
|
|
43
|
+
this.name = "FeishuSecretRefUnavailableError";
|
|
44
|
+
this.path = path;
|
|
19
45
|
}
|
|
20
|
-
return Object.keys(accounts).filter(Boolean);
|
|
21
46
|
}
|
|
22
47
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
48
|
+
export function isFeishuSecretRefUnavailableError(
|
|
49
|
+
error: unknown,
|
|
50
|
+
): error is FeishuSecretRefUnavailableError {
|
|
51
|
+
return error instanceof FeishuSecretRefUnavailableError;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function resolveFeishuSecretLike(params: {
|
|
55
|
+
value: unknown;
|
|
56
|
+
path: string;
|
|
57
|
+
mode: FeishuCredentialResolutionMode;
|
|
58
|
+
allowEnvSecretRefRead?: boolean;
|
|
59
|
+
}): string | undefined {
|
|
60
|
+
const asString = normalizeString(params.value);
|
|
61
|
+
if (asString) {
|
|
62
|
+
return asString;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const ref = coerceSecretRef(params.value);
|
|
66
|
+
if (!ref) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (params.mode === "inspect") {
|
|
71
|
+
if (params.allowEnvSecretRefRead && ref.source === "env") {
|
|
72
|
+
const envValue = normalizeString(process.env[ref.id]);
|
|
73
|
+
if (envValue) {
|
|
74
|
+
return envValue;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
throw new FeishuSecretRefUnavailableError(params.path, ref);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function resolveFeishuBaseCredentials(
|
|
84
|
+
cfg: FeishuConfig | undefined,
|
|
85
|
+
mode: FeishuCredentialResolutionMode,
|
|
86
|
+
): {
|
|
87
|
+
appId: string;
|
|
88
|
+
appSecret: string;
|
|
89
|
+
domain: FeishuDomain;
|
|
90
|
+
} | null {
|
|
91
|
+
const appId = resolveFeishuSecretLike({
|
|
92
|
+
value: cfg?.appId,
|
|
93
|
+
path: "channels.feishu.appId",
|
|
94
|
+
mode,
|
|
95
|
+
allowEnvSecretRefRead: true,
|
|
96
|
+
});
|
|
97
|
+
const appSecret = resolveFeishuSecretLike({
|
|
98
|
+
value: cfg?.appSecret,
|
|
99
|
+
path: "channels.feishu.appSecret",
|
|
100
|
+
mode,
|
|
101
|
+
allowEnvSecretRefRead: true,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (!appId || !appSecret) {
|
|
105
|
+
return null;
|
|
32
106
|
}
|
|
33
|
-
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
appId,
|
|
110
|
+
appSecret,
|
|
111
|
+
domain: cfg?.domain ?? "feishu",
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function resolveFeishuEventSecrets(
|
|
116
|
+
cfg: FeishuConfig | undefined,
|
|
117
|
+
mode: FeishuCredentialResolutionMode,
|
|
118
|
+
): {
|
|
119
|
+
encryptKey?: string;
|
|
120
|
+
verificationToken?: string;
|
|
121
|
+
} {
|
|
122
|
+
return {
|
|
123
|
+
encryptKey:
|
|
124
|
+
(cfg?.connectionMode ?? "websocket") === "webhook"
|
|
125
|
+
? resolveFeishuSecretLike({
|
|
126
|
+
value: cfg?.encryptKey,
|
|
127
|
+
path: "channels.feishu.encryptKey",
|
|
128
|
+
mode,
|
|
129
|
+
allowEnvSecretRefRead: true,
|
|
130
|
+
})
|
|
131
|
+
: normalizeString(cfg?.encryptKey),
|
|
132
|
+
verificationToken: resolveFeishuSecretLike({
|
|
133
|
+
value: cfg?.verificationToken,
|
|
134
|
+
path: "channels.feishu.verificationToken",
|
|
135
|
+
mode,
|
|
136
|
+
allowEnvSecretRefRead: true,
|
|
137
|
+
}),
|
|
138
|
+
};
|
|
34
139
|
}
|
|
35
140
|
|
|
36
141
|
/**
|
|
@@ -40,8 +145,9 @@ export function resolveDefaultFeishuAccountSelection(cfg: ClawdbotConfig): {
|
|
|
40
145
|
accountId: string;
|
|
41
146
|
source: FeishuDefaultAccountSelectionSource;
|
|
42
147
|
} {
|
|
43
|
-
const
|
|
44
|
-
|
|
148
|
+
const preferred = normalizeOptionalAccountId(
|
|
149
|
+
(cfg.channels?.feishu as FeishuConfig | undefined)?.defaultAccount,
|
|
150
|
+
);
|
|
45
151
|
if (preferred) {
|
|
46
152
|
return {
|
|
47
153
|
accountId: preferred,
|
|
@@ -65,21 +171,7 @@ export function resolveDefaultFeishuAccountSelection(cfg: ClawdbotConfig): {
|
|
|
65
171
|
* Resolve the default account ID.
|
|
66
172
|
*/
|
|
67
173
|
export function resolveDefaultFeishuAccountId(cfg: ClawdbotConfig): string {
|
|
68
|
-
return
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Get the raw account-specific config.
|
|
73
|
-
*/
|
|
74
|
-
function resolveAccountConfig(
|
|
75
|
-
cfg: ClawdbotConfig,
|
|
76
|
-
accountId: string,
|
|
77
|
-
): FeishuAccountConfig | undefined {
|
|
78
|
-
const accounts = (cfg.channels?.feishu as FeishuConfig)?.accounts;
|
|
79
|
-
if (!accounts || typeof accounts !== "object") {
|
|
80
|
-
return undefined;
|
|
81
|
-
}
|
|
82
|
-
return accounts[accountId];
|
|
174
|
+
return resolveDefaultAccountId(cfg);
|
|
83
175
|
}
|
|
84
176
|
|
|
85
177
|
/**
|
|
@@ -88,15 +180,12 @@ function resolveAccountConfig(
|
|
|
88
180
|
*/
|
|
89
181
|
function mergeFeishuAccountConfig(cfg: ClawdbotConfig, accountId: string): FeishuConfig {
|
|
90
182
|
const feishuCfg = cfg.channels?.feishu as FeishuConfig | undefined;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// Merge: account config overrides base config
|
|
99
|
-
return { ...base, ...account } as FeishuConfig;
|
|
183
|
+
return resolveMergedAccountConfig<FeishuConfig>({
|
|
184
|
+
channelConfig: feishuCfg,
|
|
185
|
+
accounts: feishuCfg?.accounts as Record<string, Partial<FeishuConfig>> | undefined,
|
|
186
|
+
accountId,
|
|
187
|
+
omitKeys: ["defaultAccount"],
|
|
188
|
+
});
|
|
100
189
|
}
|
|
101
190
|
|
|
102
191
|
/**
|
|
@@ -111,7 +200,10 @@ export function resolveFeishuCredentials(cfg?: FeishuConfig): {
|
|
|
111
200
|
} | null;
|
|
112
201
|
export function resolveFeishuCredentials(
|
|
113
202
|
cfg: FeishuConfig | undefined,
|
|
114
|
-
options: {
|
|
203
|
+
options: {
|
|
204
|
+
mode?: FeishuCredentialResolutionMode;
|
|
205
|
+
allowUnresolvedSecretRef?: boolean;
|
|
206
|
+
},
|
|
115
207
|
): {
|
|
116
208
|
appId: string;
|
|
117
209
|
appSecret: string;
|
|
@@ -121,7 +213,10 @@ export function resolveFeishuCredentials(
|
|
|
121
213
|
} | null;
|
|
122
214
|
export function resolveFeishuCredentials(
|
|
123
215
|
cfg?: FeishuConfig,
|
|
124
|
-
options?: {
|
|
216
|
+
options?: {
|
|
217
|
+
mode?: FeishuCredentialResolutionMode;
|
|
218
|
+
allowUnresolvedSecretRef?: boolean;
|
|
219
|
+
},
|
|
125
220
|
): {
|
|
126
221
|
appId: string;
|
|
127
222
|
appSecret: string;
|
|
@@ -129,68 +224,28 @@ export function resolveFeishuCredentials(
|
|
|
129
224
|
verificationToken?: string;
|
|
130
225
|
domain: FeishuDomain;
|
|
131
226
|
} | null {
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
const trimmed = value.trim();
|
|
137
|
-
return trimmed ? trimmed : undefined;
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const resolveSecretLike = (value: unknown, path: string): string | undefined => {
|
|
141
|
-
const asString = normalizeString(value);
|
|
142
|
-
if (asString) {
|
|
143
|
-
return asString;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// In relaxed/onboarding paths only: allow direct env SecretRef reads for UX.
|
|
147
|
-
// Default resolution path must preserve unresolved-ref diagnostics/policy semantics.
|
|
148
|
-
if (options?.allowUnresolvedSecretRef && typeof value === "object" && value !== null) {
|
|
149
|
-
const rec = value as Record<string, unknown>;
|
|
150
|
-
const source = normalizeString(rec.source)?.toLowerCase();
|
|
151
|
-
const id = normalizeString(rec.id);
|
|
152
|
-
if (source === "env" && id) {
|
|
153
|
-
const envValue = normalizeString(process.env[id]);
|
|
154
|
-
if (envValue) {
|
|
155
|
-
return envValue;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (options?.allowUnresolvedSecretRef) {
|
|
161
|
-
return normalizeSecretInputString(value);
|
|
162
|
-
}
|
|
163
|
-
return normalizeResolvedSecretInputString({ value, path });
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
const appId = resolveSecretLike(cfg?.appId, "channels.feishu.appId");
|
|
167
|
-
const appSecret = resolveSecretLike(cfg?.appSecret, "channels.feishu.appSecret");
|
|
168
|
-
|
|
169
|
-
if (!appId || !appSecret) {
|
|
227
|
+
const mode = options?.mode ?? (options?.allowUnresolvedSecretRef ? "inspect" : "strict");
|
|
228
|
+
const base = resolveFeishuBaseCredentials(cfg, mode);
|
|
229
|
+
if (!base) {
|
|
170
230
|
return null;
|
|
171
231
|
}
|
|
172
|
-
const
|
|
232
|
+
const eventSecrets = resolveFeishuEventSecrets(cfg, mode);
|
|
233
|
+
|
|
173
234
|
return {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
encryptKey:
|
|
177
|
-
connectionMode === "webhook"
|
|
178
|
-
? resolveSecretLike(cfg?.encryptKey, "channels.feishu.encryptKey")
|
|
179
|
-
: normalizeString(cfg?.encryptKey),
|
|
180
|
-
verificationToken: resolveSecretLike(
|
|
181
|
-
cfg?.verificationToken,
|
|
182
|
-
"channels.feishu.verificationToken",
|
|
183
|
-
),
|
|
184
|
-
domain: cfg?.domain ?? "feishu",
|
|
235
|
+
...base,
|
|
236
|
+
...eventSecrets,
|
|
185
237
|
};
|
|
186
238
|
}
|
|
187
239
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
240
|
+
export function inspectFeishuCredentials(cfg?: FeishuConfig) {
|
|
241
|
+
return resolveFeishuCredentials(cfg, { mode: "inspect" });
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function buildResolvedFeishuAccount(params: {
|
|
192
245
|
cfg: ClawdbotConfig;
|
|
193
246
|
accountId?: string | null;
|
|
247
|
+
baseMode: FeishuCredentialResolutionMode;
|
|
248
|
+
eventSecretMode: FeishuCredentialResolutionMode;
|
|
194
249
|
}): ResolvedFeishuAccount {
|
|
195
250
|
const hasExplicitAccountId =
|
|
196
251
|
typeof params.accountId === "string" && params.accountId.trim() !== "";
|
|
@@ -205,35 +260,62 @@ export function resolveFeishuAccount(params: {
|
|
|
205
260
|
: (defaultSelection?.source ?? "fallback");
|
|
206
261
|
const feishuCfg = params.cfg.channels?.feishu as FeishuConfig | undefined;
|
|
207
262
|
|
|
208
|
-
// Base enabled state (top-level)
|
|
209
263
|
const baseEnabled = feishuCfg?.enabled !== false;
|
|
210
|
-
|
|
211
|
-
// Merge configs
|
|
212
264
|
const merged = mergeFeishuAccountConfig(params.cfg, accountId);
|
|
213
|
-
|
|
214
|
-
// Account-level enabled state
|
|
215
265
|
const accountEnabled = merged.enabled !== false;
|
|
216
266
|
const enabled = baseEnabled && accountEnabled;
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const creds = resolveFeishuCredentials(merged);
|
|
267
|
+
const baseCreds = resolveFeishuBaseCredentials(merged, params.baseMode);
|
|
268
|
+
const eventSecrets = resolveFeishuEventSecrets(merged, params.eventSecretMode);
|
|
220
269
|
const accountName = (merged as FeishuAccountConfig).name;
|
|
221
270
|
|
|
222
271
|
return {
|
|
223
272
|
accountId,
|
|
224
273
|
selectionSource,
|
|
225
274
|
enabled,
|
|
226
|
-
configured: Boolean(
|
|
275
|
+
configured: Boolean(baseCreds),
|
|
227
276
|
name: typeof accountName === "string" ? accountName.trim() || undefined : undefined,
|
|
228
|
-
appId:
|
|
229
|
-
appSecret:
|
|
230
|
-
encryptKey:
|
|
231
|
-
verificationToken:
|
|
232
|
-
domain:
|
|
277
|
+
appId: baseCreds?.appId,
|
|
278
|
+
appSecret: baseCreds?.appSecret,
|
|
279
|
+
encryptKey: eventSecrets.encryptKey,
|
|
280
|
+
verificationToken: eventSecrets.verificationToken,
|
|
281
|
+
domain: baseCreds?.domain ?? "feishu",
|
|
233
282
|
config: merged,
|
|
234
283
|
};
|
|
235
284
|
}
|
|
236
285
|
|
|
286
|
+
/**
|
|
287
|
+
* Resolve a read-only Feishu account snapshot for CLI/config surfaces.
|
|
288
|
+
* Unresolved SecretRefs are treated as unavailable instead of throwing.
|
|
289
|
+
*/
|
|
290
|
+
export function resolveFeishuAccount(params: {
|
|
291
|
+
cfg: ClawdbotConfig;
|
|
292
|
+
accountId?: string | null;
|
|
293
|
+
}): ResolvedFeishuAccount {
|
|
294
|
+
return buildResolvedFeishuAccount({
|
|
295
|
+
...params,
|
|
296
|
+
baseMode: "inspect",
|
|
297
|
+
eventSecretMode: "inspect",
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Resolve a runtime Feishu account.
|
|
303
|
+
* Required app credentials stay strict; event-only secrets can be required by callers.
|
|
304
|
+
*/
|
|
305
|
+
export function resolveFeishuRuntimeAccount(
|
|
306
|
+
params: {
|
|
307
|
+
cfg: ClawdbotConfig;
|
|
308
|
+
accountId?: string | null;
|
|
309
|
+
},
|
|
310
|
+
options?: { requireEventSecrets?: boolean },
|
|
311
|
+
): ResolvedFeishuAccount {
|
|
312
|
+
return buildResolvedFeishuAccount({
|
|
313
|
+
...params,
|
|
314
|
+
baseMode: "strict",
|
|
315
|
+
eventSecretMode: options?.requireEventSecrets ? "strict" : "inspect",
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
237
319
|
/**
|
|
238
320
|
* List all enabled and configured accounts.
|
|
239
321
|
*/
|