@openclaw/feishu 2026.2.6 → 2026.2.9
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/package.json +1 -1
- package/src/bitable.ts +4 -2
- package/src/bot.ts +1 -1
- package/src/channel.ts +31 -13
- package/src/onboarding.ts +4 -1
- package/src/outbound.ts +20 -5
- package/src/reply-dispatcher.ts +3 -8
package/package.json
CHANGED
package/src/bitable.ts
CHANGED
|
@@ -212,7 +212,8 @@ async function createRecord(
|
|
|
212
212
|
) {
|
|
213
213
|
const res = await client.bitable.appTableRecord.create({
|
|
214
214
|
path: { app_token: appToken, table_id: tableId },
|
|
215
|
-
|
|
215
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
216
|
+
data: { fields: fields as any },
|
|
216
217
|
});
|
|
217
218
|
if (res.code !== 0) {
|
|
218
219
|
throw new Error(res.msg);
|
|
@@ -232,7 +233,8 @@ async function updateRecord(
|
|
|
232
233
|
) {
|
|
233
234
|
const res = await client.bitable.appTableRecord.update({
|
|
234
235
|
path: { app_token: appToken, table_id: tableId, record_id: recordId },
|
|
235
|
-
|
|
236
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
237
|
+
data: { fields: fields as any },
|
|
236
238
|
});
|
|
237
239
|
if (res.code !== 0) {
|
|
238
240
|
throw new Error(res.msg);
|
package/src/bot.ts
CHANGED
|
@@ -652,7 +652,7 @@ export async function handleFeishuMessage(params: {
|
|
|
652
652
|
channel: "feishu",
|
|
653
653
|
accountId: account.accountId,
|
|
654
654
|
peer: {
|
|
655
|
-
kind: isGroup ? "group" : "
|
|
655
|
+
kind: isGroup ? "group" : "direct",
|
|
656
656
|
id: isGroup ? ctx.chatId : ctx.senderOpenId,
|
|
657
657
|
},
|
|
658
658
|
});
|
package/src/channel.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChannelPlugin, ClawdbotConfig } from "openclaw/plugin-sdk";
|
|
1
|
+
import type { ChannelMeta, ChannelPlugin, ClawdbotConfig } from "openclaw/plugin-sdk";
|
|
2
2
|
import { DEFAULT_ACCOUNT_ID, PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk";
|
|
3
3
|
import type { ResolvedFeishuAccount, FeishuConfig } from "./types.js";
|
|
4
4
|
import {
|
|
@@ -19,7 +19,7 @@ import { probeFeishu } from "./probe.js";
|
|
|
19
19
|
import { sendMessageFeishu } from "./send.js";
|
|
20
20
|
import { normalizeFeishuTarget, looksLikeFeishuId } from "./targets.js";
|
|
21
21
|
|
|
22
|
-
const meta = {
|
|
22
|
+
const meta: ChannelMeta = {
|
|
23
23
|
id: "feishu",
|
|
24
24
|
label: "Feishu",
|
|
25
25
|
selectionLabel: "Feishu/Lark (飞书)",
|
|
@@ -28,7 +28,7 @@ const meta = {
|
|
|
28
28
|
blurb: "飞书/Lark enterprise messaging.",
|
|
29
29
|
aliases: ["lark"],
|
|
30
30
|
order: 70,
|
|
31
|
-
}
|
|
31
|
+
};
|
|
32
32
|
|
|
33
33
|
export const feishuPlugin: ChannelPlugin<ResolvedFeishuAccount> = {
|
|
34
34
|
id: "feishu",
|
|
@@ -38,12 +38,11 @@ export const feishuPlugin: ChannelPlugin<ResolvedFeishuAccount> = {
|
|
|
38
38
|
pairing: {
|
|
39
39
|
idLabel: "feishuUserId",
|
|
40
40
|
normalizeAllowEntry: (entry) => entry.replace(/^(feishu|user|open_id):/i, ""),
|
|
41
|
-
notifyApproval: async ({ cfg, id
|
|
41
|
+
notifyApproval: async ({ cfg, id }) => {
|
|
42
42
|
await sendMessageFeishu({
|
|
43
43
|
cfg,
|
|
44
44
|
to: id,
|
|
45
45
|
text: PAIRING_APPROVED_MESSAGE,
|
|
46
|
-
accountId,
|
|
47
46
|
});
|
|
48
47
|
},
|
|
49
48
|
},
|
|
@@ -202,7 +201,7 @@ export const feishuPlugin: ChannelPlugin<ResolvedFeishuAccount> = {
|
|
|
202
201
|
}),
|
|
203
202
|
resolveAllowFrom: ({ cfg, accountId }) => {
|
|
204
203
|
const account = resolveFeishuAccount({ cfg, accountId });
|
|
205
|
-
return account.config?.allowFrom ?? [];
|
|
204
|
+
return (account.config?.allowFrom ?? []).map((entry) => String(entry));
|
|
206
205
|
},
|
|
207
206
|
formatAllowFrom: ({ allowFrom }) =>
|
|
208
207
|
allowFrom
|
|
@@ -265,7 +264,7 @@ export const feishuPlugin: ChannelPlugin<ResolvedFeishuAccount> = {
|
|
|
265
264
|
},
|
|
266
265
|
onboarding: feishuOnboardingAdapter,
|
|
267
266
|
messaging: {
|
|
268
|
-
normalizeTarget: normalizeFeishuTarget,
|
|
267
|
+
normalizeTarget: (raw) => normalizeFeishuTarget(raw) ?? undefined,
|
|
269
268
|
targetResolver: {
|
|
270
269
|
looksLikeId: looksLikeFeishuId,
|
|
271
270
|
hint: "<chatId|user:openId|chat:chatId>",
|
|
@@ -274,13 +273,33 @@ export const feishuPlugin: ChannelPlugin<ResolvedFeishuAccount> = {
|
|
|
274
273
|
directory: {
|
|
275
274
|
self: async () => null,
|
|
276
275
|
listPeers: async ({ cfg, query, limit, accountId }) =>
|
|
277
|
-
listFeishuDirectoryPeers({
|
|
276
|
+
listFeishuDirectoryPeers({
|
|
277
|
+
cfg,
|
|
278
|
+
query: query ?? undefined,
|
|
279
|
+
limit: limit ?? undefined,
|
|
280
|
+
accountId: accountId ?? undefined,
|
|
281
|
+
}),
|
|
278
282
|
listGroups: async ({ cfg, query, limit, accountId }) =>
|
|
279
|
-
listFeishuDirectoryGroups({
|
|
283
|
+
listFeishuDirectoryGroups({
|
|
284
|
+
cfg,
|
|
285
|
+
query: query ?? undefined,
|
|
286
|
+
limit: limit ?? undefined,
|
|
287
|
+
accountId: accountId ?? undefined,
|
|
288
|
+
}),
|
|
280
289
|
listPeersLive: async ({ cfg, query, limit, accountId }) =>
|
|
281
|
-
listFeishuDirectoryPeersLive({
|
|
290
|
+
listFeishuDirectoryPeersLive({
|
|
291
|
+
cfg,
|
|
292
|
+
query: query ?? undefined,
|
|
293
|
+
limit: limit ?? undefined,
|
|
294
|
+
accountId: accountId ?? undefined,
|
|
295
|
+
}),
|
|
282
296
|
listGroupsLive: async ({ cfg, query, limit, accountId }) =>
|
|
283
|
-
listFeishuDirectoryGroupsLive({
|
|
297
|
+
listFeishuDirectoryGroupsLive({
|
|
298
|
+
cfg,
|
|
299
|
+
query: query ?? undefined,
|
|
300
|
+
limit: limit ?? undefined,
|
|
301
|
+
accountId: accountId ?? undefined,
|
|
302
|
+
}),
|
|
284
303
|
},
|
|
285
304
|
outbound: feishuOutbound,
|
|
286
305
|
status: {
|
|
@@ -302,8 +321,7 @@ export const feishuPlugin: ChannelPlugin<ResolvedFeishuAccount> = {
|
|
|
302
321
|
probe: snapshot.probe,
|
|
303
322
|
lastProbeAt: snapshot.lastProbeAt ?? null,
|
|
304
323
|
}),
|
|
305
|
-
probeAccount: async ({
|
|
306
|
-
const account = resolveFeishuAccount({ cfg, accountId });
|
|
324
|
+
probeAccount: async ({ account }) => {
|
|
307
325
|
return await probeFeishu(account);
|
|
308
326
|
},
|
|
309
327
|
buildAccountSnapshot: ({ account, runtime, probe }) => ({
|
package/src/onboarding.ts
CHANGED
|
@@ -80,7 +80,10 @@ async function promptFeishuAllowFrom(params: {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
const unique = [
|
|
83
|
-
...new Set([
|
|
83
|
+
...new Set([
|
|
84
|
+
...existing.map((v: string | number) => String(v).trim()).filter(Boolean),
|
|
85
|
+
...parts,
|
|
86
|
+
]),
|
|
84
87
|
];
|
|
85
88
|
return setFeishuAllowFrom(params.cfg, unique);
|
|
86
89
|
}
|
package/src/outbound.ts
CHANGED
|
@@ -9,32 +9,47 @@ export const feishuOutbound: ChannelOutboundAdapter = {
|
|
|
9
9
|
chunkerMode: "markdown",
|
|
10
10
|
textChunkLimit: 4000,
|
|
11
11
|
sendText: async ({ cfg, to, text, accountId }) => {
|
|
12
|
-
const result = await sendMessageFeishu({ cfg, to, text, accountId });
|
|
12
|
+
const result = await sendMessageFeishu({ cfg, to, text, accountId: accountId ?? undefined });
|
|
13
13
|
return { channel: "feishu", ...result };
|
|
14
14
|
},
|
|
15
15
|
sendMedia: async ({ cfg, to, text, mediaUrl, accountId }) => {
|
|
16
16
|
// Send text first if provided
|
|
17
17
|
if (text?.trim()) {
|
|
18
|
-
await sendMessageFeishu({ cfg, to, text, accountId });
|
|
18
|
+
await sendMessageFeishu({ cfg, to, text, accountId: accountId ?? undefined });
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
// Upload and send media if URL provided
|
|
22
22
|
if (mediaUrl) {
|
|
23
23
|
try {
|
|
24
|
-
const result = await sendMediaFeishu({
|
|
24
|
+
const result = await sendMediaFeishu({
|
|
25
|
+
cfg,
|
|
26
|
+
to,
|
|
27
|
+
mediaUrl,
|
|
28
|
+
accountId: accountId ?? undefined,
|
|
29
|
+
});
|
|
25
30
|
return { channel: "feishu", ...result };
|
|
26
31
|
} catch (err) {
|
|
27
32
|
// Log the error for debugging
|
|
28
33
|
console.error(`[feishu] sendMediaFeishu failed:`, err);
|
|
29
34
|
// Fallback to URL link if upload fails
|
|
30
35
|
const fallbackText = `📎 ${mediaUrl}`;
|
|
31
|
-
const result = await sendMessageFeishu({
|
|
36
|
+
const result = await sendMessageFeishu({
|
|
37
|
+
cfg,
|
|
38
|
+
to,
|
|
39
|
+
text: fallbackText,
|
|
40
|
+
accountId: accountId ?? undefined,
|
|
41
|
+
});
|
|
32
42
|
return { channel: "feishu", ...result };
|
|
33
43
|
}
|
|
34
44
|
}
|
|
35
45
|
|
|
36
46
|
// No media URL, just return text result
|
|
37
|
-
const result = await sendMessageFeishu({
|
|
47
|
+
const result = await sendMessageFeishu({
|
|
48
|
+
cfg,
|
|
49
|
+
to,
|
|
50
|
+
text: text ?? "",
|
|
51
|
+
accountId: accountId ?? undefined,
|
|
52
|
+
});
|
|
38
53
|
return { channel: "feishu", ...result };
|
|
39
54
|
},
|
|
40
55
|
};
|
package/src/reply-dispatcher.ts
CHANGED
|
@@ -90,16 +90,11 @@ export function createFeishuReplyDispatcher(params: CreateFeishuReplyDispatcherP
|
|
|
90
90
|
},
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
-
const textChunkLimit = core.channel.text.resolveTextChunkLimit({
|
|
94
|
-
|
|
95
|
-
channel: "feishu",
|
|
96
|
-
defaultLimit: 4000,
|
|
93
|
+
const textChunkLimit = core.channel.text.resolveTextChunkLimit(cfg, "feishu", accountId, {
|
|
94
|
+
fallbackLimit: 4000,
|
|
97
95
|
});
|
|
98
96
|
const chunkMode = core.channel.text.resolveChunkMode(cfg, "feishu");
|
|
99
|
-
const tableMode = core.channel.text.resolveMarkdownTableMode({
|
|
100
|
-
cfg,
|
|
101
|
-
channel: "feishu",
|
|
102
|
-
});
|
|
97
|
+
const tableMode = core.channel.text.resolveMarkdownTableMode({ cfg, channel: "feishu" });
|
|
103
98
|
|
|
104
99
|
const { dispatcher, replyOptions, markDispatchIdle } =
|
|
105
100
|
core.channel.reply.createReplyDispatcherWithTyping({
|