@m1heng-clawd/feishu 0.1.2 → 0.1.4

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # clawd-feishu
2
2
 
3
- Feishu/Lark (飞书) channel plugin for [Clawdbot](https://github.com/clawdbot/clawdbot).
3
+ Feishu/Lark (飞书) channel plugin for [OpenClaw](https://github.com/openclaw/openclaw).
4
4
 
5
5
  [English](#english) | [中文](#中文)
6
6
 
@@ -11,7 +11,7 @@ Feishu/Lark (飞书) channel plugin for [Clawdbot](https://github.com/clawdbot/c
11
11
  ### Installation
12
12
 
13
13
  ```bash
14
- clawdbot plugins install @m1heng-clawd/feishu
14
+ openclaw plugins install @m1heng-clawd/feishu
15
15
  ```
16
16
 
17
17
  Or install via npm:
@@ -49,6 +49,18 @@ npm install @m1heng-clawd/feishu
49
49
  | `im:message:recall` | Recall | Recall sent messages |
50
50
  | `im:message.reactions:read` | Reactions | View message reactions |
51
51
 
52
+ #### Document Tools Permissions
53
+
54
+ Required if using Feishu document tools (`feishu_doc_*`):
55
+
56
+ | Permission | Description |
57
+ |------------|-------------|
58
+ | `docx:document` | Create/edit documents |
59
+ | `docx:document:readonly` | Read documents |
60
+ | `docx:document.block:convert` | Markdown to blocks conversion (required for write/append) |
61
+ | `drive:drive` | Upload images to documents |
62
+ | `drive:drive:readonly` | List folders |
63
+
52
64
  #### Event Subscriptions ⚠️
53
65
 
54
66
  > **This is the most commonly missed configuration!** If the bot can send messages but cannot receive them, check this section.
@@ -68,9 +80,9 @@ In the Feishu Open Platform console, go to **Events & Callbacks**:
68
80
  3. Ensure the event permissions are approved
69
81
 
70
82
  ```bash
71
- clawdbot config set channels.feishu.appId "cli_xxxxx"
72
- clawdbot config set channels.feishu.appSecret "your_app_secret"
73
- clawdbot config set channels.feishu.enabled true
83
+ openclaw config set channels.feishu.appId "cli_xxxxx"
84
+ openclaw config set channels.feishu.appSecret "your_app_secret"
85
+ openclaw config set channels.feishu.enabled true
74
86
  ```
75
87
 
76
88
  ### Configuration Options
@@ -116,6 +128,17 @@ channels:
116
128
  - Pairing flow for DM approval
117
129
  - User and group directory lookup
118
130
  - **Card render mode**: Optional markdown rendering with syntax highlighting
131
+ - **Document tools**: Read, create, and write Feishu documents with markdown (tables not supported due to API limitations)
132
+ - **@mention forwarding**: When you @mention someone in your message, the bot's reply will automatically @mention them too
133
+
134
+ #### @Mention Forwarding
135
+
136
+ When you want the bot to @mention someone in its reply, simply @mention them in your message:
137
+
138
+ - **In DM**: `@张三 say hello` → Bot replies with `@张三 Hello!`
139
+ - **In Group**: `@bot @张三 say hello` → Bot replies with `@张三 Hello!`
140
+
141
+ The bot automatically detects @mentions in your message and includes them in its reply. No extra permissions required beyond the standard messaging permissions.
119
142
 
120
143
  ### FAQ
121
144
 
@@ -141,14 +164,14 @@ Feishu API has rate limits. Streaming updates can easily trigger throttling. We
141
164
 
142
165
  #### Windows install error `spawn npm ENOENT`
143
166
 
144
- If `clawdbot plugins install` fails, install manually:
167
+ If `openclaw plugins install` fails, install manually:
145
168
 
146
169
  ```bash
147
170
  # 1. Download the package
148
- curl -O https://registry.npmjs.org/@m1heng-clawd/feishu/-/feishu-0.1.1.tgz
171
+ curl -O https://registry.npmjs.org/@m1heng-clawd/feishu/-/feishu-0.1.3.tgz
149
172
 
150
173
  # 2. Install from local file
151
- clawdbot plugins install ./feishu-0.1.1.tgz
174
+ openclaw plugins install ./feishu-0.1.3.tgz
152
175
  ```
153
176
 
154
177
  #### Cannot find the bot in Feishu
@@ -164,7 +187,7 @@ clawdbot plugins install ./feishu-0.1.1.tgz
164
187
  ### 安装
165
188
 
166
189
  ```bash
167
- clawdbot plugins install @m1heng-clawd/feishu
190
+ openclaw plugins install @m1heng-clawd/feishu
168
191
  ```
169
192
 
170
193
  或通过 npm 安装:
@@ -202,6 +225,18 @@ npm install @m1heng-clawd/feishu
202
225
  | `im:message:recall` | 撤回 | 撤回已发送消息 |
203
226
  | `im:message.reactions:read` | 表情 | 查看消息表情回复 |
204
227
 
228
+ #### 文档工具权限
229
+
230
+ 使用飞书文档工具(`feishu_doc_*`)需要以下权限:
231
+
232
+ | 权限 | 说明 |
233
+ |------|------|
234
+ | `docx:document` | 创建/编辑文档 |
235
+ | `docx:document:readonly` | 读取文档 |
236
+ | `docx:document.block:convert` | Markdown 转 blocks(write/append 必需) |
237
+ | `drive:drive` | 上传图片到文档 |
238
+ | `drive:drive:readonly` | 列出文件夹 |
239
+
205
240
  #### 事件订阅 ⚠️
206
241
 
207
242
  > **这是最容易遗漏的配置!** 如果机器人能发消息但收不到消息,请检查此项。
@@ -221,9 +256,9 @@ npm install @m1heng-clawd/feishu
221
256
  3. 确保事件订阅的权限已申请并通过审核
222
257
 
223
258
  ```bash
224
- clawdbot config set channels.feishu.appId "cli_xxxxx"
225
- clawdbot config set channels.feishu.appSecret "your_app_secret"
226
- clawdbot config set channels.feishu.enabled true
259
+ openclaw config set channels.feishu.appId "cli_xxxxx"
260
+ openclaw config set channels.feishu.appSecret "your_app_secret"
261
+ openclaw config set channels.feishu.enabled true
227
262
  ```
228
263
 
229
264
  ### 配置选项
@@ -269,6 +304,17 @@ channels:
269
304
  - 私聊配对审批流程
270
305
  - 用户和群组目录查询
271
306
  - **卡片渲染模式**:支持语法高亮的 Markdown 渲染
307
+ - **文档工具**:读取、创建、用 Markdown 写入飞书文档(表格因 API 限制不支持)
308
+ - **@ 转发功能**:在消息中 @ 某人,机器人的回复会自动 @ 该用户
309
+
310
+ #### @ 转发功能
311
+
312
+ 如果你希望机器人的回复中 @ 某人,只需在你的消息中 @ 他们:
313
+
314
+ - **私聊**:`@张三 跟他问好` → 机器人回复 `@张三 你好!`
315
+ - **群聊**:`@机器人 @张三 跟他问好` → 机器人回复 `@张三 你好!`
316
+
317
+ 机器人会自动检测消息中的 @ 并在回复时带上。无需额外权限。
272
318
 
273
319
  ### 常见问题
274
320
 
@@ -294,14 +340,14 @@ channels:
294
340
 
295
341
  #### Windows 安装报错 `spawn npm ENOENT`
296
342
 
297
- 如果 `clawdbot plugins install` 失败,可以手动安装:
343
+ 如果 `openclaw plugins install` 失败,可以手动安装:
298
344
 
299
345
  ```bash
300
346
  # 1. 下载插件包
301
- curl -O https://registry.npmjs.org/@m1heng-clawd/feishu/-/feishu-0.1.1.tgz
347
+ curl -O https://registry.npmjs.org/@m1heng-clawd/feishu/-/feishu-0.1.3.tgz
302
348
 
303
349
  # 2. 从本地安装
304
- clawdbot plugins install ./feishu-0.1.1.tgz
350
+ openclaw plugins install ./feishu-0.1.3.tgz
305
351
  ```
306
352
 
307
353
  #### 在飞书里找不到机器人
package/index.ts CHANGED
@@ -1,7 +1,8 @@
1
- import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
2
- import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk";
1
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
2
+ import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
3
3
  import { feishuPlugin } from "./src/channel.js";
4
4
  import { setFeishuRuntime } from "./src/runtime.js";
5
+ import { registerFeishuDocTools } from "./src/docx.js";
5
6
 
6
7
  export { monitorFeishuProvider } from "./src/monitor.js";
7
8
  export {
@@ -25,6 +26,18 @@ export {
25
26
  listReactionsFeishu,
26
27
  FeishuEmoji,
27
28
  } from "./src/reactions.js";
29
+ export {
30
+ extractMentionTargets,
31
+ extractMessageBody,
32
+ isMentionForwardRequest,
33
+ formatMentionForText,
34
+ formatMentionForCard,
35
+ formatMentionAllForText,
36
+ formatMentionAllForCard,
37
+ buildMentionedMessage,
38
+ buildMentionedCardContent,
39
+ type MentionTarget,
40
+ } from "./src/mention.js";
28
41
  export { feishuPlugin } from "./src/channel.js";
29
42
 
30
43
  const plugin = {
@@ -32,9 +45,10 @@ const plugin = {
32
45
  name: "Feishu",
33
46
  description: "Feishu/Lark channel plugin",
34
47
  configSchema: emptyPluginConfigSchema(),
35
- register(api: ClawdbotPluginApi) {
48
+ register(api: OpenClawPluginApi) {
36
49
  setFeishuRuntime(api.runtime);
37
50
  api.registerChannel({ plugin: feishuPlugin });
51
+ registerFeishuDocTools(api);
38
52
  },
39
53
  };
40
54
 
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "id": "feishu",
3
3
  "channels": ["feishu"],
4
+ "skills": ["./skills"],
4
5
  "configSchema": {
5
6
  "type": "object",
6
7
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@m1heng-clawd/feishu",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
- "description": "Clawdbot Feishu/Lark channel plugin",
5
+ "description": "OpenClaw Feishu/Lark channel plugin",
6
6
  "license": "MIT",
7
7
  "files": [
8
8
  "index.ts",
9
9
  "src",
10
- "clawdbot.plugin.json"
10
+ "openclaw.plugin.json"
11
11
  ],
12
12
  "repository": {
13
13
  "type": "git",
14
14
  "url": "git+https://github.com/m1heng/clawdbot-feishu.git"
15
15
  },
16
16
  "keywords": [
17
- "clawdbot",
17
+ "openclaw",
18
18
  "feishu",
19
19
  "lark",
20
20
  "飞书",
@@ -22,7 +22,7 @@
22
22
  "ai",
23
23
  "claude"
24
24
  ],
25
- "clawdbot": {
25
+ "openclaw": {
26
26
  "extensions": [
27
27
  "./index.ts"
28
28
  ],
@@ -46,15 +46,16 @@
46
46
  },
47
47
  "dependencies": {
48
48
  "@larksuiteoapi/node-sdk": "^1.30.0",
49
+ "@sinclair/typebox": "^0.34.48",
49
50
  "zod": "^4.3.6"
50
51
  },
51
52
  "devDependencies": {
52
53
  "@types/node": "^25.0.10",
53
- "clawdbot": "2026.1.24-2",
54
+ "openclaw": "2026.1.29",
54
55
  "tsx": "^4.21.0",
55
56
  "typescript": "^5.7.0"
56
57
  },
57
58
  "peerDependencies": {
58
- "clawdbot": ">=2026.1.24"
59
+ "openclaw": ">=2026.1.29"
59
60
  }
60
61
  }
package/src/accounts.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
2
- import { DEFAULT_ACCOUNT_ID } from "clawdbot/plugin-sdk";
1
+ import type { ClawdbotConfig } from "openclaw/plugin-sdk";
2
+ import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk";
3
3
  import type { FeishuConfig, FeishuDomain, ResolvedFeishuAccount } from "./types.js";
4
4
 
5
5
  export function resolveFeishuCredentials(cfg?: FeishuConfig): {
package/src/bot.ts CHANGED
@@ -1,11 +1,11 @@
1
- import type { ClawdbotConfig, RuntimeEnv } from "clawdbot/plugin-sdk";
1
+ import type { ClawdbotConfig, RuntimeEnv } from "openclaw/plugin-sdk";
2
2
  import {
3
3
  buildPendingHistoryContextFromMap,
4
4
  recordPendingHistoryEntryIfEnabled,
5
5
  clearHistoryEntriesIfEnabled,
6
6
  DEFAULT_GROUP_HISTORY_LIMIT,
7
7
  type HistoryEntry,
8
- } from "clawdbot/plugin-sdk";
8
+ } from "openclaw/plugin-sdk";
9
9
  import type { FeishuConfig, FeishuMessageContext, FeishuMediaInfo } from "./types.js";
10
10
  import { getFeishuRuntime } from "./runtime.js";
11
11
  import { createFeishuClient } from "./client.js";
@@ -18,6 +18,11 @@ import {
18
18
  import { createFeishuReplyDispatcher } from "./reply-dispatcher.js";
19
19
  import { getMessageFeishu } from "./send.js";
20
20
  import { downloadImageFeishu, downloadMessageResourceFeishu } from "./media.js";
21
+ import {
22
+ extractMentionTargets,
23
+ extractMessageBody,
24
+ isMentionForwardRequest,
25
+ } from "./mention.js";
21
26
 
22
27
  // --- Sender name resolution (so the agent can distinguish who is speaking in group chats) ---
23
28
  // Cache display names by open_id to avoid an API call on every message.
@@ -399,7 +404,7 @@ export function parseFeishuMessageEvent(
399
404
  const mentionedBot = checkBotMentioned(event, botOpenId);
400
405
  const content = stripBotMention(rawContent, event.message.mentions);
401
406
 
402
- return {
407
+ const ctx: FeishuMessageContext = {
403
408
  chatId: event.message.chat_id,
404
409
  messageId: event.message.message_id,
405
410
  senderId: event.sender.sender_id.user_id || event.sender.sender_id.open_id || "",
@@ -411,6 +416,19 @@ export function parseFeishuMessageEvent(
411
416
  content,
412
417
  contentType: event.message.message_type,
413
418
  };
419
+
420
+ // Detect mention forward request: message mentions bot + at least one other user
421
+ if (isMentionForwardRequest(event, botOpenId)) {
422
+ const mentionTargets = extractMentionTargets(event, botOpenId);
423
+ if (mentionTargets.length > 0) {
424
+ ctx.mentionTargets = mentionTargets;
425
+ // Extract message body (remove all @ placeholders)
426
+ const allMentionKeys = (event.message.mentions ?? []).map((m) => m.key);
427
+ ctx.mentionMessageBody = extractMessageBody(content, allMentionKeys);
428
+ }
429
+ }
430
+
431
+ return ctx;
414
432
  }
415
433
 
416
434
  export async function handleFeishuMessage(params: {
@@ -438,6 +456,12 @@ export async function handleFeishuMessage(params: {
438
456
 
439
457
  log(`feishu: received message from ${ctx.senderOpenId} in ${ctx.chatId} (${ctx.chatType})`);
440
458
 
459
+ // Log mention targets if detected
460
+ if (ctx.mentionTargets && ctx.mentionTargets.length > 0) {
461
+ const names = ctx.mentionTargets.map((t) => t.name).join(", ");
462
+ log(`feishu: detected @ forward request, targets: [${names}]`);
463
+ }
464
+
441
465
  const historyLimit = Math.max(
442
466
  0,
443
467
  feishuCfg?.historyLimit ?? cfg.messages?.groupChat?.historyLimit ?? DEFAULT_GROUP_HISTORY_LIMIT,
@@ -566,6 +590,12 @@ export async function handleFeishuMessage(params: {
566
590
  const speaker = ctx.senderName ?? ctx.senderOpenId;
567
591
  messageBody = `${speaker}: ${messageBody}`;
568
592
 
593
+ // If there are mention targets, inform the agent that replies will auto-mention them
594
+ if (ctx.mentionTargets && ctx.mentionTargets.length > 0) {
595
+ const targetNames = ctx.mentionTargets.map((t) => t.name).join(", ");
596
+ messageBody += `\n\n[System: Your reply will automatically @mention: ${targetNames}. Do not write @xxx yourself.]`;
597
+ }
598
+
569
599
  const envelopeFrom = isGroup ? `${ctx.chatId}:${ctx.senderOpenId}` : ctx.senderOpenId;
570
600
 
571
601
  const body = core.channel.reply.formatAgentEnvelope({
@@ -626,6 +656,7 @@ export async function handleFeishuMessage(params: {
626
656
  runtime: runtime as RuntimeEnv,
627
657
  chatId: ctx.chatId,
628
658
  replyToMessageId: ctx.messageId,
659
+ mentionTargets: ctx.mentionTargets,
629
660
  });
630
661
 
631
662
  log(`feishu: dispatching to agent (session=${route.sessionKey})`);
package/src/channel.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { ChannelPlugin, ClawdbotConfig } from "clawdbot/plugin-sdk";
2
- import { DEFAULT_ACCOUNT_ID, PAIRING_APPROVED_MESSAGE } from "clawdbot/plugin-sdk";
1
+ import type { ChannelPlugin, ClawdbotConfig } from "openclaw/plugin-sdk";
2
+ import { DEFAULT_ACCOUNT_ID, PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk";
3
3
  import type { ResolvedFeishuAccount, FeishuConfig } from "./types.js";
4
4
  import { resolveFeishuAccount, resolveFeishuCredentials } from "./accounts.js";
5
5
  import { feishuOutbound } from "./outbound.js";
package/src/directory.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
1
+ import type { ClawdbotConfig } from "openclaw/plugin-sdk";
2
2
  import type { FeishuConfig } from "./types.js";
3
3
  import { createFeishuClient } from "./client.js";
4
4
  import { normalizeFeishuTarget } from "./targets.js";