@m1heng-clawd/feishu 0.1.8 → 0.1.10
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/README.md +42 -28
- package/index.ts +3 -1
- package/package.json +5 -5
- package/src/bitable-tools/actions.ts +199 -0
- package/src/bitable-tools/common.ts +90 -0
- package/src/bitable-tools/meta.ts +80 -0
- package/src/bitable-tools/register.ts +195 -0
- package/src/bitable-tools/schemas.ts +221 -0
- package/src/bitable.ts +1 -441
- package/src/bot.ts +130 -68
- package/src/channel.ts +6 -8
- package/src/config-schema.ts +7 -0
- package/src/dedup.ts +31 -0
- package/src/docx.ts +440 -62
- package/src/drive-schema.ts +20 -0
- package/src/drive.ts +84 -27
- package/src/dynamic-agent.ts +8 -4
- package/src/media.ts +25 -40
- package/src/monitor.ts +29 -2
- package/src/onboarding.ts +186 -105
- package/src/perm.ts +23 -24
- package/src/probe.ts +108 -4
- package/src/reply-dispatcher.ts +137 -73
- package/src/streaming-card.ts +211 -0
- package/src/targets.ts +1 -1
- package/src/task-tools/actions.ts +137 -0
- package/src/task-tools/common.ts +18 -0
- package/src/task-tools/register.ts +101 -0
- package/src/task-tools/schemas.ts +138 -0
- package/src/task.ts +1 -0
- package/src/tools-common/feishu-api.ts +184 -0
- package/src/tools-common/tool-context.ts +23 -0
- package/src/tools-common/tool-exec.ts +73 -0
- package/src/tools-config.ts +2 -1
- package/src/types.ts +1 -0
- package/src/wiki.ts +42 -43
package/src/onboarding.ts
CHANGED
|
@@ -5,45 +5,99 @@ import type {
|
|
|
5
5
|
DmPolicy,
|
|
6
6
|
WizardPrompter,
|
|
7
7
|
} from "openclaw/plugin-sdk";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
addWildcardAllowFrom,
|
|
10
|
+
DEFAULT_ACCOUNT_ID,
|
|
11
|
+
formatDocsLink,
|
|
12
|
+
normalizeAccountId,
|
|
13
|
+
promptAccountId,
|
|
14
|
+
} from "openclaw/plugin-sdk";
|
|
9
15
|
|
|
10
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
listFeishuAccountIds,
|
|
18
|
+
resolveDefaultFeishuAccountId,
|
|
19
|
+
resolveFeishuAccount,
|
|
20
|
+
resolveFeishuCredentials,
|
|
21
|
+
} from "./accounts.js";
|
|
11
22
|
import { probeFeishu } from "./probe.js";
|
|
12
23
|
import type { FeishuConfig } from "./types.js";
|
|
13
24
|
|
|
14
25
|
const channel = "feishu" as const;
|
|
15
26
|
|
|
16
|
-
function
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return
|
|
22
|
-
...cfg,
|
|
23
|
-
channels: {
|
|
24
|
-
...cfg.channels,
|
|
25
|
-
feishu: {
|
|
26
|
-
...cfg.channels?.feishu,
|
|
27
|
-
dmPolicy,
|
|
28
|
-
...(allowFrom ? { allowFrom } : {}),
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
};
|
|
27
|
+
function resolveOnboardingAccountId(cfg: ClawdbotConfig, accountId?: string | null): string {
|
|
28
|
+
const raw = accountId?.trim();
|
|
29
|
+
if (raw) {
|
|
30
|
+
return normalizeAccountId(raw);
|
|
31
|
+
}
|
|
32
|
+
return resolveDefaultFeishuAccountId(cfg);
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
function
|
|
35
|
+
function upsertFeishuAccountConfig(
|
|
36
|
+
cfg: ClawdbotConfig,
|
|
37
|
+
accountId: string,
|
|
38
|
+
patch: Partial<FeishuConfig>,
|
|
39
|
+
): ClawdbotConfig {
|
|
40
|
+
const normalizedAccountId = normalizeAccountId(accountId);
|
|
41
|
+
const feishuCfg = cfg.channels?.feishu as FeishuConfig | undefined;
|
|
42
|
+
|
|
43
|
+
if (normalizedAccountId === DEFAULT_ACCOUNT_ID) {
|
|
44
|
+
return {
|
|
45
|
+
...cfg,
|
|
46
|
+
channels: {
|
|
47
|
+
...cfg.channels,
|
|
48
|
+
feishu: {
|
|
49
|
+
...feishuCfg,
|
|
50
|
+
...patch,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const existingAccount = feishuCfg?.accounts?.[normalizedAccountId];
|
|
35
57
|
return {
|
|
36
58
|
...cfg,
|
|
37
59
|
channels: {
|
|
38
60
|
...cfg.channels,
|
|
39
61
|
feishu: {
|
|
40
|
-
...
|
|
41
|
-
|
|
62
|
+
...feishuCfg,
|
|
63
|
+
enabled: true,
|
|
64
|
+
accounts: {
|
|
65
|
+
...feishuCfg?.accounts,
|
|
66
|
+
[normalizedAccountId]: {
|
|
67
|
+
...existingAccount,
|
|
68
|
+
enabled: existingAccount?.enabled ?? true,
|
|
69
|
+
...patch,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
42
72
|
},
|
|
43
73
|
},
|
|
44
74
|
};
|
|
45
75
|
}
|
|
46
76
|
|
|
77
|
+
function setFeishuDmPolicy(
|
|
78
|
+
cfg: ClawdbotConfig,
|
|
79
|
+
dmPolicy: DmPolicy,
|
|
80
|
+
accountId?: string,
|
|
81
|
+
): ClawdbotConfig {
|
|
82
|
+
const resolvedAccountId = resolveOnboardingAccountId(cfg, accountId);
|
|
83
|
+
const account = resolveFeishuAccount({ cfg, accountId: resolvedAccountId });
|
|
84
|
+
// Feishu channel config does not support "disabled" as a dmPolicy value.
|
|
85
|
+
const effectiveDmPolicy = dmPolicy === "disabled" ? "pairing" : dmPolicy;
|
|
86
|
+
const allowFrom =
|
|
87
|
+
effectiveDmPolicy === "open"
|
|
88
|
+
? addWildcardAllowFrom(account.config.allowFrom)?.map((entry) => String(entry))
|
|
89
|
+
: undefined;
|
|
90
|
+
return upsertFeishuAccountConfig(cfg, resolvedAccountId, {
|
|
91
|
+
dmPolicy: effectiveDmPolicy,
|
|
92
|
+
...(allowFrom ? { allowFrom } : {}),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function setFeishuAllowFrom(cfg: ClawdbotConfig, allowFrom: string[], accountId?: string): ClawdbotConfig {
|
|
97
|
+
const resolvedAccountId = resolveOnboardingAccountId(cfg, accountId);
|
|
98
|
+
return upsertFeishuAccountConfig(cfg, resolvedAccountId, { allowFrom });
|
|
99
|
+
}
|
|
100
|
+
|
|
47
101
|
function parseAllowFromInput(raw: string): string[] {
|
|
48
102
|
return raw
|
|
49
103
|
.split(/[\n,;]+/g)
|
|
@@ -54,10 +108,14 @@ function parseAllowFromInput(raw: string): string[] {
|
|
|
54
108
|
async function promptFeishuAllowFrom(params: {
|
|
55
109
|
cfg: ClawdbotConfig;
|
|
56
110
|
prompter: WizardPrompter;
|
|
111
|
+
accountId?: string;
|
|
57
112
|
}): Promise<ClawdbotConfig> {
|
|
58
|
-
const
|
|
113
|
+
const accountId = resolveOnboardingAccountId(params.cfg, params.accountId);
|
|
114
|
+
const existing = resolveFeishuAccount({ cfg: params.cfg, accountId }).config.allowFrom ?? [];
|
|
115
|
+
const accountLabel = accountId === DEFAULT_ACCOUNT_ID ? "default" : accountId;
|
|
59
116
|
await params.prompter.note(
|
|
60
117
|
[
|
|
118
|
+
`Account: ${accountLabel}`,
|
|
61
119
|
"Allowlist Feishu DMs by open_id or user_id.",
|
|
62
120
|
"You can find user open_id in Feishu admin console or via API.",
|
|
63
121
|
"Examples:",
|
|
@@ -83,7 +141,7 @@ async function promptFeishuAllowFrom(params: {
|
|
|
83
141
|
const unique = [
|
|
84
142
|
...new Set([...existing.map((v) => String(v).trim()).filter(Boolean), ...parts]),
|
|
85
143
|
];
|
|
86
|
-
return setFeishuAllowFrom(params.cfg, unique);
|
|
144
|
+
return setFeishuAllowFrom(params.cfg, unique, accountId);
|
|
87
145
|
}
|
|
88
146
|
}
|
|
89
147
|
|
|
@@ -105,31 +163,24 @@ async function noteFeishuCredentialHelp(prompter: WizardPrompter): Promise<void>
|
|
|
105
163
|
function setFeishuGroupPolicy(
|
|
106
164
|
cfg: ClawdbotConfig,
|
|
107
165
|
groupPolicy: "open" | "allowlist" | "disabled",
|
|
166
|
+
accountId?: string,
|
|
108
167
|
): ClawdbotConfig {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
channels: {
|
|
112
|
-
...cfg.channels,
|
|
113
|
-
feishu: {
|
|
114
|
-
...cfg.channels?.feishu,
|
|
115
|
-
enabled: true,
|
|
116
|
-
groupPolicy,
|
|
117
|
-
},
|
|
118
|
-
},
|
|
119
|
-
};
|
|
168
|
+
const resolvedAccountId = resolveOnboardingAccountId(cfg, accountId);
|
|
169
|
+
return upsertFeishuAccountConfig(cfg, resolvedAccountId, { enabled: true, groupPolicy });
|
|
120
170
|
}
|
|
121
171
|
|
|
122
|
-
function setFeishuGroupAllowFrom(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
172
|
+
function setFeishuGroupAllowFrom(
|
|
173
|
+
cfg: ClawdbotConfig,
|
|
174
|
+
groupAllowFrom: string[],
|
|
175
|
+
accountId?: string,
|
|
176
|
+
): ClawdbotConfig {
|
|
177
|
+
const resolvedAccountId = resolveOnboardingAccountId(cfg, accountId);
|
|
178
|
+
return upsertFeishuAccountConfig(cfg, resolvedAccountId, { groupAllowFrom });
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function setFeishuDomain(cfg: ClawdbotConfig, domain: "feishu" | "lark", accountId?: string): ClawdbotConfig {
|
|
182
|
+
const resolvedAccountId = resolveOnboardingAccountId(cfg, accountId);
|
|
183
|
+
return upsertFeishuAccountConfig(cfg, resolvedAccountId, { domain });
|
|
133
184
|
}
|
|
134
185
|
|
|
135
186
|
const dmPolicy: ChannelOnboardingDmPolicy = {
|
|
@@ -137,22 +188,30 @@ const dmPolicy: ChannelOnboardingDmPolicy = {
|
|
|
137
188
|
channel,
|
|
138
189
|
policyKey: "channels.feishu.dmPolicy",
|
|
139
190
|
allowFromKey: "channels.feishu.allowFrom",
|
|
140
|
-
getCurrent: (cfg) =>
|
|
141
|
-
|
|
191
|
+
getCurrent: (cfg) => {
|
|
192
|
+
const accountId = resolveDefaultFeishuAccountId(cfg);
|
|
193
|
+
return resolveFeishuAccount({ cfg, accountId }).config.dmPolicy ?? "pairing";
|
|
194
|
+
},
|
|
195
|
+
setPolicy: (cfg, policy, accountId?: string) => setFeishuDmPolicy(cfg, policy, accountId),
|
|
142
196
|
promptAllowFrom: promptFeishuAllowFrom,
|
|
143
197
|
};
|
|
144
198
|
|
|
145
199
|
export const feishuOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
146
200
|
channel,
|
|
147
|
-
getStatus: async ({ cfg }) => {
|
|
148
|
-
const
|
|
149
|
-
const
|
|
201
|
+
getStatus: async ({ cfg, accountOverrides }) => {
|
|
202
|
+
const override = accountOverrides?.feishu?.trim();
|
|
203
|
+
const accountIds = override
|
|
204
|
+
? [resolveOnboardingAccountId(cfg, override)]
|
|
205
|
+
: listFeishuAccountIds(cfg);
|
|
206
|
+
const accounts = accountIds.map((accountId) => resolveFeishuAccount({ cfg, accountId }));
|
|
207
|
+
const configuredAccounts = accounts.filter((account) => account.configured);
|
|
208
|
+
const configured = configuredAccounts.length > 0;
|
|
150
209
|
|
|
151
210
|
// Try to probe if configured
|
|
152
211
|
let probeResult = null;
|
|
153
|
-
if (
|
|
212
|
+
if (configuredAccounts[0]) {
|
|
154
213
|
try {
|
|
155
|
-
probeResult = await probeFeishu(
|
|
214
|
+
probeResult = await probeFeishu(configuredAccounts[0]);
|
|
156
215
|
} catch {
|
|
157
216
|
// Ignore probe errors
|
|
158
217
|
}
|
|
@@ -162,7 +221,16 @@ export const feishuOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
162
221
|
if (!configured) {
|
|
163
222
|
statusLines.push("Feishu: needs app credentials");
|
|
164
223
|
} else if (probeResult?.ok) {
|
|
165
|
-
|
|
224
|
+
const probeAccountId = configuredAccounts[0]?.accountId ?? DEFAULT_ACCOUNT_ID;
|
|
225
|
+
const accountNote = probeAccountId === DEFAULT_ACCOUNT_ID ? "" : ` [${probeAccountId}]`;
|
|
226
|
+
statusLines.push(
|
|
227
|
+
`Feishu${accountNote}: connected as ${probeResult.botName ?? probeResult.botOpenId ?? "bot"}`,
|
|
228
|
+
);
|
|
229
|
+
if (!override && configuredAccounts.length > 1) {
|
|
230
|
+
statusLines.push(`Feishu: ${configuredAccounts.length} account(s) configured`);
|
|
231
|
+
}
|
|
232
|
+
} else if (!override && configuredAccounts.length > 1) {
|
|
233
|
+
statusLines.push(`Feishu: configured (${configuredAccounts.length} account(s), connection not verified)`);
|
|
166
234
|
} else {
|
|
167
235
|
statusLines.push("Feishu: configured (connection not verified)");
|
|
168
236
|
}
|
|
@@ -176,11 +244,30 @@ export const feishuOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
176
244
|
};
|
|
177
245
|
},
|
|
178
246
|
|
|
179
|
-
configure: async ({ cfg, prompter }) => {
|
|
180
|
-
const
|
|
181
|
-
const
|
|
182
|
-
|
|
247
|
+
configure: async ({ cfg, prompter, accountOverrides, shouldPromptAccountIds }) => {
|
|
248
|
+
const feishuOverride = accountOverrides?.feishu?.trim();
|
|
249
|
+
const defaultFeishuAccountId = resolveDefaultFeishuAccountId(cfg);
|
|
250
|
+
let feishuAccountId = feishuOverride
|
|
251
|
+
? normalizeAccountId(feishuOverride)
|
|
252
|
+
: defaultFeishuAccountId;
|
|
253
|
+
if (shouldPromptAccountIds && !feishuOverride) {
|
|
254
|
+
feishuAccountId = await promptAccountId({
|
|
255
|
+
cfg,
|
|
256
|
+
prompter,
|
|
257
|
+
label: "Feishu",
|
|
258
|
+
currentId: feishuAccountId,
|
|
259
|
+
listAccountIds: listFeishuAccountIds,
|
|
260
|
+
defaultAccountId: defaultFeishuAccountId,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
const accountLabel = feishuAccountId === DEFAULT_ACCOUNT_ID ? "default" : feishuAccountId;
|
|
264
|
+
const currentAccount = resolveFeishuAccount({ cfg, accountId: feishuAccountId });
|
|
265
|
+
const resolved = resolveFeishuCredentials(currentAccount.config);
|
|
266
|
+
const hasConfigCreds = Boolean(
|
|
267
|
+
currentAccount.config.appId?.trim() && currentAccount.config.appSecret?.trim(),
|
|
268
|
+
);
|
|
183
269
|
const canUseEnv = Boolean(
|
|
270
|
+
feishuAccountId === DEFAULT_ACCOUNT_ID &&
|
|
184
271
|
!hasConfigCreds &&
|
|
185
272
|
process.env.FEISHU_APP_ID?.trim() &&
|
|
186
273
|
process.env.FEISHU_APP_SECRET?.trim(),
|
|
@@ -189,6 +276,14 @@ export const feishuOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
189
276
|
let next = cfg;
|
|
190
277
|
let appId: string | null = null;
|
|
191
278
|
let appSecret: string | null = null;
|
|
279
|
+
const appIdPrompt =
|
|
280
|
+
feishuAccountId === DEFAULT_ACCOUNT_ID
|
|
281
|
+
? "Enter Feishu App ID"
|
|
282
|
+
: `Enter Feishu App ID for account "${accountLabel}"`;
|
|
283
|
+
const appSecretPrompt =
|
|
284
|
+
feishuAccountId === DEFAULT_ACCOUNT_ID
|
|
285
|
+
? "Enter Feishu App Secret"
|
|
286
|
+
: `Enter Feishu App Secret for account "${accountLabel}"`;
|
|
192
287
|
|
|
193
288
|
if (!resolved) {
|
|
194
289
|
await noteFeishuCredentialHelp(prompter);
|
|
@@ -200,42 +295,36 @@ export const feishuOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
200
295
|
initialValue: true,
|
|
201
296
|
});
|
|
202
297
|
if (keepEnv) {
|
|
203
|
-
next = {
|
|
204
|
-
...next,
|
|
205
|
-
channels: {
|
|
206
|
-
...next.channels,
|
|
207
|
-
feishu: { ...next.channels?.feishu, enabled: true },
|
|
208
|
-
},
|
|
209
|
-
};
|
|
298
|
+
next = upsertFeishuAccountConfig(next, feishuAccountId, { enabled: true });
|
|
210
299
|
} else {
|
|
211
300
|
appId = String(
|
|
212
301
|
await prompter.text({
|
|
213
|
-
message:
|
|
302
|
+
message: appIdPrompt,
|
|
214
303
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
215
304
|
}),
|
|
216
305
|
).trim();
|
|
217
306
|
appSecret = String(
|
|
218
307
|
await prompter.text({
|
|
219
|
-
message:
|
|
308
|
+
message: appSecretPrompt,
|
|
220
309
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
221
310
|
}),
|
|
222
311
|
).trim();
|
|
223
312
|
}
|
|
224
313
|
} else if (hasConfigCreds) {
|
|
225
314
|
const keep = await prompter.confirm({
|
|
226
|
-
message:
|
|
315
|
+
message: `Feishu credentials already configured for account "${accountLabel}". Keep them?`,
|
|
227
316
|
initialValue: true,
|
|
228
317
|
});
|
|
229
318
|
if (!keep) {
|
|
230
319
|
appId = String(
|
|
231
320
|
await prompter.text({
|
|
232
|
-
message:
|
|
321
|
+
message: appIdPrompt,
|
|
233
322
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
234
323
|
}),
|
|
235
324
|
).trim();
|
|
236
325
|
appSecret = String(
|
|
237
326
|
await prompter.text({
|
|
238
|
-
message:
|
|
327
|
+
message: appSecretPrompt,
|
|
239
328
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
240
329
|
}),
|
|
241
330
|
).trim();
|
|
@@ -243,54 +332,50 @@ export const feishuOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
243
332
|
} else {
|
|
244
333
|
appId = String(
|
|
245
334
|
await prompter.text({
|
|
246
|
-
message:
|
|
335
|
+
message: appIdPrompt,
|
|
247
336
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
248
337
|
}),
|
|
249
338
|
).trim();
|
|
250
339
|
appSecret = String(
|
|
251
340
|
await prompter.text({
|
|
252
|
-
message:
|
|
341
|
+
message: appSecretPrompt,
|
|
253
342
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
254
343
|
}),
|
|
255
344
|
).trim();
|
|
256
345
|
}
|
|
257
346
|
|
|
258
347
|
if (appId && appSecret) {
|
|
259
|
-
next = {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
...next.channels?.feishu,
|
|
265
|
-
enabled: true,
|
|
266
|
-
appId,
|
|
267
|
-
appSecret,
|
|
268
|
-
},
|
|
269
|
-
},
|
|
270
|
-
};
|
|
348
|
+
next = upsertFeishuAccountConfig(next, feishuAccountId, {
|
|
349
|
+
enabled: true,
|
|
350
|
+
appId,
|
|
351
|
+
appSecret,
|
|
352
|
+
});
|
|
271
353
|
|
|
272
354
|
// Test connection
|
|
273
|
-
const
|
|
355
|
+
const testAccount = resolveFeishuAccount({ cfg: next, accountId: feishuAccountId });
|
|
274
356
|
try {
|
|
275
|
-
const probe = await probeFeishu(
|
|
357
|
+
const probe = await probeFeishu(testAccount);
|
|
276
358
|
if (probe.ok) {
|
|
277
359
|
await prompter.note(
|
|
278
360
|
`Connected as ${probe.botName ?? probe.botOpenId ?? "bot"}`,
|
|
279
|
-
|
|
361
|
+
`Feishu connection test (${accountLabel})`,
|
|
280
362
|
);
|
|
281
363
|
} else {
|
|
282
364
|
await prompter.note(
|
|
283
365
|
`Connection failed: ${probe.error ?? "unknown error"}`,
|
|
284
|
-
|
|
366
|
+
`Feishu connection test (${accountLabel})`,
|
|
285
367
|
);
|
|
286
368
|
}
|
|
287
369
|
} catch (err) {
|
|
288
|
-
await prompter.note(
|
|
370
|
+
await prompter.note(
|
|
371
|
+
`Connection test failed: ${String(err)}`,
|
|
372
|
+
`Feishu connection test (${accountLabel})`,
|
|
373
|
+
);
|
|
289
374
|
}
|
|
290
375
|
}
|
|
291
376
|
|
|
292
377
|
// Domain selection
|
|
293
|
-
const currentDomain = (next
|
|
378
|
+
const currentDomain = resolveFeishuAccount({ cfg: next, accountId: feishuAccountId }).config.domain ?? "feishu";
|
|
294
379
|
const domain = await prompter.select({
|
|
295
380
|
message: "Which Feishu domain?",
|
|
296
381
|
options: [
|
|
@@ -300,19 +385,11 @@ export const feishuOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
300
385
|
initialValue: currentDomain,
|
|
301
386
|
});
|
|
302
387
|
if (domain) {
|
|
303
|
-
next =
|
|
304
|
-
...next,
|
|
305
|
-
channels: {
|
|
306
|
-
...next.channels,
|
|
307
|
-
feishu: {
|
|
308
|
-
...next.channels?.feishu,
|
|
309
|
-
domain: domain as "feishu" | "lark",
|
|
310
|
-
},
|
|
311
|
-
},
|
|
312
|
-
};
|
|
388
|
+
next = setFeishuDomain(next, domain as "feishu" | "lark", feishuAccountId);
|
|
313
389
|
}
|
|
314
390
|
|
|
315
391
|
// Group policy
|
|
392
|
+
const groupPolicyAccount = resolveFeishuAccount({ cfg: next, accountId: feishuAccountId });
|
|
316
393
|
const groupPolicy = await prompter.select({
|
|
317
394
|
message: "Group chat policy",
|
|
318
395
|
options: [
|
|
@@ -320,16 +397,20 @@ export const feishuOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
320
397
|
{ value: "open", label: "Open - respond in all groups (requires mention)" },
|
|
321
398
|
{ value: "disabled", label: "Disabled - don't respond in groups" },
|
|
322
399
|
],
|
|
323
|
-
initialValue:
|
|
324
|
-
(next.channels?.feishu as FeishuConfig | undefined)?.groupPolicy ?? "allowlist",
|
|
400
|
+
initialValue: groupPolicyAccount.config.groupPolicy ?? "allowlist",
|
|
325
401
|
});
|
|
326
402
|
if (groupPolicy) {
|
|
327
|
-
next = setFeishuGroupPolicy(
|
|
403
|
+
next = setFeishuGroupPolicy(
|
|
404
|
+
next,
|
|
405
|
+
groupPolicy as "open" | "allowlist" | "disabled",
|
|
406
|
+
feishuAccountId,
|
|
407
|
+
);
|
|
328
408
|
}
|
|
329
409
|
|
|
330
410
|
// Group allowlist if needed
|
|
331
411
|
if (groupPolicy === "allowlist") {
|
|
332
|
-
const existing =
|
|
412
|
+
const existing =
|
|
413
|
+
resolveFeishuAccount({ cfg: next, accountId: feishuAccountId }).config.groupAllowFrom ?? [];
|
|
333
414
|
const entry = await prompter.text({
|
|
334
415
|
message: "Group chat allowlist (chat_ids)",
|
|
335
416
|
placeholder: "oc_xxxxx, oc_yyyyy",
|
|
@@ -338,12 +419,12 @@ export const feishuOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
338
419
|
if (entry) {
|
|
339
420
|
const parts = parseAllowFromInput(String(entry));
|
|
340
421
|
if (parts.length > 0) {
|
|
341
|
-
next = setFeishuGroupAllowFrom(next, parts);
|
|
422
|
+
next = setFeishuGroupAllowFrom(next, parts, feishuAccountId);
|
|
342
423
|
}
|
|
343
424
|
}
|
|
344
425
|
}
|
|
345
426
|
|
|
346
|
-
return { cfg: next, accountId:
|
|
427
|
+
return { cfg: next, accountId: feishuAccountId };
|
|
347
428
|
},
|
|
348
429
|
|
|
349
430
|
dmPolicy,
|
package/src/perm.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
|
-
import { createFeishuClient } from "./client.js";
|
|
3
|
-
import { listEnabledFeishuAccounts } from "./accounts.js";
|
|
4
2
|
import type * as Lark from "@larksuiteoapi/node-sdk";
|
|
5
3
|
import { FeishuPermSchema, type FeishuPermParams } from "./perm-schema.js";
|
|
6
|
-
import {
|
|
4
|
+
import { hasFeishuToolEnabledForAnyAccount, withFeishuToolClient } from "./tools-common/tool-exec.js";
|
|
7
5
|
|
|
8
6
|
// ============ Helpers ============
|
|
9
7
|
|
|
@@ -117,21 +115,16 @@ export function registerFeishuPermTools(api: OpenClawPluginApi) {
|
|
|
117
115
|
return;
|
|
118
116
|
}
|
|
119
117
|
|
|
120
|
-
|
|
121
|
-
if (accounts.length === 0) {
|
|
118
|
+
if (!hasFeishuToolEnabledForAnyAccount(api.config)) {
|
|
122
119
|
api.logger.debug?.("feishu_perm: No Feishu accounts configured, skipping perm tools");
|
|
123
120
|
return;
|
|
124
121
|
}
|
|
125
122
|
|
|
126
|
-
|
|
127
|
-
const toolsCfg = resolveToolsConfig(firstAccount.config.tools);
|
|
128
|
-
if (!toolsCfg.perm) {
|
|
123
|
+
if (!hasFeishuToolEnabledForAnyAccount(api.config, "perm")) {
|
|
129
124
|
api.logger.debug?.("feishu_perm: perm tool disabled in config (default: false)");
|
|
130
125
|
return;
|
|
131
126
|
}
|
|
132
127
|
|
|
133
|
-
const getClient = () => createFeishuClient(firstAccount);
|
|
134
|
-
|
|
135
128
|
api.registerTool(
|
|
136
129
|
{
|
|
137
130
|
name: "feishu_perm",
|
|
@@ -141,19 +134,25 @@ export function registerFeishuPermTools(api: OpenClawPluginApi) {
|
|
|
141
134
|
async execute(_toolCallId, params) {
|
|
142
135
|
const p = params as FeishuPermParams;
|
|
143
136
|
try {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
137
|
+
return await withFeishuToolClient({
|
|
138
|
+
api,
|
|
139
|
+
toolName: "feishu_perm",
|
|
140
|
+
requiredTool: "perm",
|
|
141
|
+
run: async ({ client }) => {
|
|
142
|
+
switch (p.action) {
|
|
143
|
+
case "list":
|
|
144
|
+
return json(await listMembers(client, p.token, p.type));
|
|
145
|
+
case "add":
|
|
146
|
+
return json(
|
|
147
|
+
await addMember(client, p.token, p.type, p.member_type, p.member_id, p.perm),
|
|
148
|
+
);
|
|
149
|
+
case "remove":
|
|
150
|
+
return json(await removeMember(client, p.token, p.type, p.member_type, p.member_id));
|
|
151
|
+
default:
|
|
152
|
+
return json({ error: `Unknown action: ${(p as any).action}` });
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
});
|
|
157
156
|
} catch (err) {
|
|
158
157
|
return json({ error: err instanceof Error ? err.message : String(err) });
|
|
159
158
|
}
|
|
@@ -162,5 +161,5 @@ export function registerFeishuPermTools(api: OpenClawPluginApi) {
|
|
|
162
161
|
{ name: "feishu_perm" },
|
|
163
162
|
);
|
|
164
163
|
|
|
165
|
-
api.logger.
|
|
164
|
+
api.logger.debug?.("feishu_perm: Registered feishu_perm tool");
|
|
166
165
|
}
|