@zhin.js/adapter-lark 1.1.0 → 1.1.2

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.
Files changed (51) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/README.md +7 -8
  3. package/adapters/{lark.js → lark/index.js} +6 -6
  4. package/adapters/{lark.ts → lark/index.ts} +9 -9
  5. package/agents/lark/agent.json +20 -0
  6. package/agents/lark/boundaries.md +3 -0
  7. package/agents/lark/conventions.md +3 -0
  8. package/agents/lark/skills/lark/SKILL.md +22 -0
  9. package/agents/lark/skills/lark/tools/add_members/index.js +19 -0
  10. package/{agent/tools/add_members.ts → agents/lark/skills/lark/tools/add_members/index.ts} +3 -4
  11. package/agents/lark/skills/lark/tools/create_chat/index.js +18 -0
  12. package/{agent/tools/create_chat.ts → agents/lark/skills/lark/tools/create_chat/index.ts} +1 -1
  13. package/agents/lark/skills/lark/tools/dissolve_chat/index.js +16 -0
  14. package/{agent/tools/dissolve_chat.ts → agents/lark/skills/lark/tools/dissolve_chat/index.ts} +1 -1
  15. package/agents/lark/skills/lark/tools/get_user/index.js +15 -0
  16. package/{agent/tools/get_user.ts → agents/lark/skills/lark/tools/get_user/index.ts} +1 -1
  17. package/agents/lark/skills/lark/tools/remove_managers/index.js +19 -0
  18. package/{agent/tools/remove_managers.ts → agents/lark/skills/lark/tools/remove_managers/index.ts} +3 -4
  19. package/agents/lark/skills/lark/tools/set_managers/index.js +19 -0
  20. package/{agent/tools/set_managers.ts → agents/lark/skills/lark/tools/set_managers/index.ts} +3 -4
  21. package/agents/lark/skills/lark/tools/update_chat/index.js +20 -0
  22. package/{agent/tools/update_chat.ts → agents/lark/skills/lark/tools/update_chat/index.ts} +3 -4
  23. package/agents/lark/skills/lark/tools/upload_file/index.js +17 -0
  24. package/{agent/tools/upload_file.ts → agents/lark/skills/lark/tools/upload_file/index.ts} +1 -1
  25. package/agents/lark/system.md +3 -0
  26. package/commands/{endpoint/add/[id].js → lark/endpoint/add/[id]/index.js} +1 -1
  27. package/commands/lark/endpoint/add/[id]/index.ts +3 -0
  28. package/{lib/lark-endpoint-commands.js → commands/lark/endpoint/definition.js} +4 -3
  29. package/{src/lark-endpoint-commands.ts → commands/lark/endpoint/definition.ts} +3 -3
  30. package/commands/{endpoint/list.js → lark/endpoint/list/index.js} +1 -1
  31. package/commands/lark/endpoint/list/index.ts +3 -0
  32. package/commands/{endpoint/remove/[id].js → lark/endpoint/remove/[id]/index.js} +1 -1
  33. package/commands/lark/endpoint/remove/[id]/index.ts +3 -0
  34. package/lib/index.d.ts +1 -1
  35. package/lib/lark-runtime-state.js +1 -1
  36. package/lib/media-upload.d.ts +1 -1
  37. package/lib/media-upload.js +1 -1
  38. package/lib/protocol.d.ts +7 -11
  39. package/lib/protocol.js +16 -17
  40. package/package.json +33 -21
  41. package/schema.json +14 -1
  42. package/src/index.ts +1 -1
  43. package/src/lark-runtime-state.ts +1 -1
  44. package/src/media-upload.ts +1 -1
  45. package/src/protocol.ts +25 -31
  46. package/agent/skills/lark.md +0 -89
  47. package/commands/endpoint/add/[id].ts +0 -3
  48. package/commands/endpoint/list.ts +0 -3
  49. package/commands/endpoint/remove/[id].ts +0 -3
  50. package/lib/lark-endpoint-commands.d.ts +0 -1
  51. /package/{agent/PERMITS.md → PERMITS.md} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,97 @@
1
1
  # @zhin.js/adapter-lark
2
2
 
3
+ ## 1.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - a9e4a40: Derive Command user routes only from explicit `commands/**/*/index.ts(x)` entry paths instead of prepending the plugin owner. Child plugins can now publish top-level static or dynamic commands, while duplicate routes across owners fail during generation construction. Adapter endpoint commands move to explicit paths such as `commands/qq/endpoint/list/index.ts` and are invoked as `qq endpoint list`.
8
+ - 8740059: Standardize TypeScript capabilities on named module directories such as `commands/foo/index.ts`, `middlewares/audit/index.ts`, `handlers/message-receive/index.ts`, `pages/workroom/index.tsx`, and `mcps/filesystem/index.ts`. Only the fixed `index` entry is discovered; sibling files remain private helpers.
9
+
10
+ Command route segments come from directories, while `[name]`, `[[name]]`, `[...name]`, and `[[...name]]` directories declare dynamic parameters. Plugin owners do not enter the route unless their config explicitly sets `commandNamespace`; Endpoint `commandPrefix` remains platform-owned and defaults to an empty string.
11
+
12
+ Migrate the built-in adapters, plugins, examples, generators, migration tooling, hot reload classification, Agent authoring surfaces, documentation, and release artifacts to the explicit entry convention.
13
+
14
+ Make Tool ownership and progressive disclosure explicit across all four supported locations: plugin-public `tools/`, Agent-private `agents/<name>/tools/`, Skill-private `skills/<name>/tools/`, and Agent-Skill-private `agents/<name>/skills/<name>/tools/`. Move adapter and group-suite operations that require domain instructions into their owning Skills so `load_skill` is the only path that unlocks their schemas.
15
+
16
+ Remove the package-root `agent/` convention. Public capabilities now use named package-root directories, schedules use `schedules/<name>/index.ts` or `plugin.ts` injection, MCP connections use `mcps/<name>/index.ts`, Prompt Sections use `prompt-sections/<name>/index.ts`, Agent definitions use `agents/<name>/`, and permission vocabulary is published as `PERMITS.md`.
17
+
18
+ - 25a845a: Unify Skills on `skills/<name>/SKILL.md`, support Agent-private Skills and nested Skill-private Tools, publish and mount existing plugin Skills, add governed Skill metadata and Turn access filtering, unlock only already-admitted same-owner Tools, and make `on-risk` and `once` approval behavior precise.
19
+ - ddbb92e: Isolate adapter Skills under platform-specific Agents and automatically select the matching platform Agent for IM ingress, preventing unrelated adapter Skills from entering another platform's prompt surface.
20
+ - 4380cf9: Colocate adapter command definitions and Agent Skill handlers with their owning capabilities, and provide a shared validated platform permission constructor.
21
+ - aaa9361: Require the canonical expanded Lark endpoint configuration. The protocol no longer reinterprets nested `endpoints` or reads endpoint identity and app credentials from `process.env`. The public config type is now `LarkEndpointConfig`, and each schema entry uses `id` as its identity.
22
+ - 5c3858e: Make `@zhin.js/im-contract` the explicit zero-dependency owner of transport identities, canonical segments, media guards, conversation facts, stores, and delivery contracts. Platform adapters now read media contracts from that foundation instead of reaching through Core.
23
+ - 33ea736: Use `tools/<name>/index.ts` and `defineAgentTool` from `@zhin.js/tool` as the sole Agent Tool authoring model. Remove the duplicate `@zhin.js/tools` definition, context, bridge, export, and discovery path; migrate plugin manifests, examples, scaffolding, HMR, and prepack compilation to the generation-owned Tool Feature.
24
+ - Updated dependencies [c861789]
25
+ - Updated dependencies [1414ccb]
26
+ - Updated dependencies [743d470]
27
+ - Updated dependencies [62dee52]
28
+ - Updated dependencies [cd54131]
29
+ - Updated dependencies [244e475]
30
+ - Updated dependencies [a9e4a40]
31
+ - Updated dependencies [5855db7]
32
+ - Updated dependencies [ec921d2]
33
+ - Updated dependencies [8740059]
34
+ - Updated dependencies [63d1f7a]
35
+ - Updated dependencies [25a845a]
36
+ - Updated dependencies [103f2c3]
37
+ - Updated dependencies [9110ab8]
38
+ - Updated dependencies [cd2a888]
39
+ - Updated dependencies [eb3227a]
40
+ - Updated dependencies [b853dba]
41
+ - Updated dependencies [e561309]
42
+ - Updated dependencies [d4c6175]
43
+ - Updated dependencies [7a0e1ca]
44
+ - Updated dependencies [103b5d3]
45
+ - Updated dependencies [5a7a7f7]
46
+ - Updated dependencies [b076eae]
47
+ - Updated dependencies [535fed1]
48
+ - Updated dependencies [73a24b7]
49
+ - Updated dependencies [2dbbc15]
50
+ - Updated dependencies [1cb1163]
51
+ - Updated dependencies [be3061e]
52
+ - Updated dependencies [75f8332]
53
+ - Updated dependencies [81935e2]
54
+ - Updated dependencies [f9ed01b]
55
+ - Updated dependencies [ac0ab50]
56
+ - Updated dependencies [5140ce1]
57
+ - Updated dependencies [522d75f]
58
+ - Updated dependencies [a7611b3]
59
+ - Updated dependencies [8823044]
60
+ - Updated dependencies [379439b]
61
+ - Updated dependencies [11c9352]
62
+ - Updated dependencies [6b70e46]
63
+ - Updated dependencies [135ac91]
64
+ - Updated dependencies [140cf0f]
65
+ - Updated dependencies [251e4d2]
66
+ - Updated dependencies [203ad34]
67
+ - Updated dependencies [e6c5113]
68
+ - Updated dependencies [e0f6478]
69
+ - Updated dependencies [baef56b]
70
+ - Updated dependencies [698f16f]
71
+ - Updated dependencies [da0a8e3]
72
+ - Updated dependencies [2fd8017]
73
+ - Updated dependencies [5c3858e]
74
+ - Updated dependencies [33ea736]
75
+ - Updated dependencies [507d602]
76
+ - Updated dependencies [df9f76b]
77
+ - @zhin.js/core@1.1.37
78
+ - @zhin.js/tool@1.1.1
79
+ - @zhin.js/host-http@1.1.1
80
+ - @zhin.js/adapter@1.1.14
81
+ - @zhin.js/feature-kit@1.1.1
82
+ - @zhin.js/agent-feature@1.1.1
83
+ - @zhin.js/skill@1.1.1
84
+ - @zhin.js/logger@1.1.1
85
+ - @zhin.js/im-contract@1.1.1
86
+
87
+ ## 1.1.1
88
+
89
+ ### Patch Changes
90
+
91
+ - Updated dependencies [769e67f]
92
+ - @zhin.js/adapter@1.1.13
93
+ - @zhin.js/core@1.1.36
94
+
3
95
  ## 1.1.0
4
96
 
5
97
  ### Minor Changes
package/README.md CHANGED
@@ -19,7 +19,7 @@ pnpm add @zhin.js/adapter-lark
19
19
 
20
20
  ## Plugin Runtime
21
21
 
22
- - `@zhin.js/adapter` — 约定式 `adapters/lark.ts`(`defineAdapter`)
22
+ - `@zhin.js/adapter` — 约定式 `adapters/lark/index.ts`(`defineAdapter`)
23
23
  - `@zhin.js/core` — `Endpoint.emit(...)` 入站、`outboundMessageToken` 出站
24
24
  - `@zhin.js/host-http` — `httpHostToken` 注册 Webhook 路由(**非** legacy host-router/Koa)
25
25
  - `zhin.js` — `plugin.ts`(`definePlugin`)
@@ -28,7 +28,7 @@ pnpm add @zhin.js/adapter-lark
28
28
  入站:`gateway.receive({ conversation, message: { conversation, id }, content: text, sender, metadata })`
29
29
  出站:`send({ conversation, payload })` → `im/v1/messages`
30
30
 
31
- 入站 `metadata.mentioned`:**未接线**。消息事件的 `mentions[]` 元素含 `id.open_id`,但本适配器拿不到 bot 自身的 open_id——配置(`appId` / `appSecret` / `name` 等)不含 bot open_id,代码也未调用 `bot/v3/info` 获取应用信息,故无可靠判据比对 mentions。
31
+ 入站 `metadata.mentioned`:**未接线**。消息事件的 `mentions[]` 元素含 `id.open_id`,但本适配器拿不到 bot 自身的 open_id——配置(`appId` / `appSecret` / `id` 等)不含 bot open_id,代码也未调用 `bot/v3/info` 获取应用信息,故无可靠判据比对 mentions。
32
32
 
33
33
  ## 前置条件
34
34
 
@@ -37,7 +37,7 @@ pnpm add @zhin.js/adapter-lark
37
37
  3. 启用机器人能力并配置事件订阅 URL:`https://your-domain/lark/webhook`
38
38
  4. Runtime Host(`http`)须已 listen,Webhook 才可达
39
39
 
40
- 必填字段(`endpoints[i]`):`name`、`appId`、`appSecret`。
40
+ 必填字段(`endpoints[i]`):`id`、`appId`、`appSecret`。
41
41
 
42
42
  ## 最小配置
43
43
 
@@ -49,7 +49,7 @@ plugins:
49
49
  isFeishu: true # 可选,默认 true
50
50
  # apiBaseUrl: https://open.feishu.cn/open-apis
51
51
  endpoints:
52
- - name: my-lark-bot
52
+ - id: my-lark-bot
53
53
  appId: ${LARK_APP_ID}
54
54
  appSecret: ${LARK_APP_SECRET}
55
55
  # encryptKey: ${LARK_ENCRYPT_KEY} # 可选
@@ -62,9 +62,8 @@ plugins:
62
62
 
63
63
  | 变量 | 说明 |
64
64
  |------|------|
65
- | `LARK_APP_ID` | 应用 App ID |
66
- | `LARK_APP_SECRET` | 应用 App Secret |
67
- | `LARK_BOT_NAME` | 默认 endpoint 名称(可选) |
65
+ | `LARK_APP_ID` | 示例中由 YAML `${LARK_APP_ID}` 引用的 App ID;变量名可自行定义 |
66
+ | `LARK_APP_SECRET` | 示例中由 YAML `${LARK_APP_SECRET}` 引用的 App Secret;变量名可自行定义 |
68
67
 
69
68
  ## 消息类型映射
70
69
 
@@ -79,7 +78,7 @@ plugins:
79
78
 
80
79
  ## Agent 工具
81
80
 
82
- `agent/` 目录保留(get_user、群聊、管理员、上传文件等)。工具声明 `adapter: 'lark'` 后,通过惰性的 `context.$client` 自动取得当前操作的 `LarkClient`;无需把 Endpoint id 暴露给模型。
81
+ `tools/` 目录提供 get_user、群聊、管理员、上传文件等 Tool。工具声明 `adapter: 'lark'` 后,通过惰性的 `context.$client` 自动取得当前操作的 `LarkClient`;无需把 Endpoint id 暴露给模型。
83
82
 
84
83
  ## 平台权限(platform permit)
85
84
 
@@ -1,13 +1,13 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  /**
3
- * Convention entry: discover `adapters/lark.ts` → defineAdapter.
3
+ * Convention entry: discover `adapters/lark/index.ts` → defineAdapter.
4
4
  */
5
5
  import { defineAdapter } from 'zhin.js/adapter';
6
6
  import { httpHostToken } from '@zhin.js/host-http';
7
- import { LarkEndpoint } from "../lib/endpoint.js";
8
- import { resolveLarkConfig, } from "../lib/protocol.js";
9
- import { larkRuntimeStateToken } from "../lib/lark-runtime-state.js";
10
- export { LarkEndpoint } from "../lib/endpoint.js";
7
+ import { LarkEndpoint } from "../../lib/endpoint.js";
8
+ import { resolveLarkConfig, } from "../../lib/protocol.js";
9
+ import { larkRuntimeStateToken } from "../../lib/lark-runtime-state.js";
10
+ export { LarkEndpoint } from "../../lib/endpoint.js";
11
11
  export default defineAdapter({
12
12
  capabilities: ['inbound', 'outbound'],
13
13
  operations: ['recall'],
@@ -22,7 +22,7 @@ export default defineAdapter({
22
22
  },
23
23
  create(context) {
24
24
  const config = resolveLarkConfig(context.config);
25
- // 注册到插件运行时状态(lark.endpoint list 的"运行中"数据源)
25
+ // 注册到插件运行时状态(lark endpoint list 的"运行中"数据源)
26
26
  context.use(larkRuntimeStateToken).endpoints.set(config.id, {
27
27
  id: config.id,
28
28
  mode: 'webhook',
@@ -1,19 +1,19 @@
1
1
  /**
2
- * Convention entry: discover `adapters/lark.ts` → defineAdapter.
2
+ * Convention entry: discover `adapters/lark/index.ts` → defineAdapter.
3
3
  */
4
4
  import { defineAdapter } from 'zhin.js/adapter';
5
5
  import { httpHostToken } from '@zhin.js/host-http';
6
- import { LarkEndpoint } from '../src/endpoint.js';
6
+ import { LarkEndpoint } from '../../src/endpoint.js';
7
7
  import {
8
8
  resolveLarkConfig,
9
- type LarkAdapterConfig,
10
- } from '../src/protocol.js';
11
- import { larkRuntimeStateToken } from '../src/lark-runtime-state.js';
9
+ type LarkEndpointConfig,
10
+ } from '../../src/protocol.js';
11
+ import { larkRuntimeStateToken } from '../../src/lark-runtime-state.js';
12
12
 
13
- export { LarkEndpoint } from '../src/endpoint.js';
14
- export type { LarkEndpointOptions, LarkFetch } from '../src/endpoint.js';
13
+ export { LarkEndpoint } from '../../src/endpoint.js';
14
+ export type { LarkEndpointOptions, LarkFetch } from '../../src/endpoint.js';
15
15
 
16
- export default defineAdapter<LarkAdapterConfig>({
16
+ export default defineAdapter<LarkEndpointConfig>({
17
17
  capabilities: ['inbound', 'outbound'],
18
18
  operations: ['recall'],
19
19
  // image 段 canonical MediaRef 经 /im/v1/images 物化为 image_key
@@ -27,7 +27,7 @@ export default defineAdapter<LarkAdapterConfig>({
27
27
  },
28
28
  create(context) {
29
29
  const config = resolveLarkConfig(context.config);
30
- // 注册到插件运行时状态(lark.endpoint list 的"运行中"数据源)
30
+ // 注册到插件运行时状态(lark endpoint list 的"运行中"数据源)
31
31
  context.use(larkRuntimeStateToken).endpoints.set(config.id, {
32
32
  id: config.id,
33
33
  mode: 'webhook',
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "LARK Platform Agent",
3
+ "version": "1.0.0",
4
+ "description": "Handles lark platform-specific operations and progressively loads only the required platform Skill.",
5
+ "trigger_rules": {
6
+ "file_patterns": [],
7
+ "keywords": [
8
+ "lark",
9
+ "adapter:lark"
10
+ ]
11
+ },
12
+ "entry_points": [
13
+ "system.md",
14
+ "boundaries.md",
15
+ "conventions.md"
16
+ ],
17
+ "platforms": [
18
+ "lark"
19
+ ]
20
+ }
@@ -0,0 +1,3 @@
1
+ # Boundaries
2
+
3
+ Operate only on the active lark endpoint and authenticated conversation context. Respect every Tool permission and approval policy. Do not infer identifiers, roles, or authorization from display names.
@@ -0,0 +1,3 @@
1
+ # Conventions
2
+
3
+ Use stable platform identifiers from the current turn or directory queries. Load one task-specific Skill at a time, and use the unified reply and outbound message path.
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: lark
3
+ platforms: [lark]
4
+ description: 飞书用户查询、群聊生命周期、管理员和文件上传能力。
5
+ keywords: [lark, 飞书, user, chat, manager, file]
6
+ tags: [adapter, collaboration]
7
+ tools:
8
+ - get_user
9
+ - create_chat
10
+ - update_chat
11
+ - add_members
12
+ - set_managers
13
+ - remove_managers
14
+ - dissolve_chat
15
+ - upload_file
16
+ ---
17
+
18
+ # 飞书
19
+
20
+ 涉及成员的操作先用 `get_user` 取得稳定用户 ID。创建群聊后可添加成员、更新群设置和维护管理员;解散群聊属于不可逆操作,应依照 Tool 审批策略执行。文件发送前先用 `upload_file` 获得文件标识。
21
+
22
+ 当前 Agent Tool 不提供当前群成员列表、踢人或独立群详情查询。
@@ -0,0 +1,19 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineAgentTool } from '@zhin.js/tool';
3
+ import { z } from 'zod';
4
+ import { platformPermission } from '@zhin.js/permission';
5
+ export default defineAgentTool({
6
+ description: '添加飞书群成员',
7
+ inputSchema: z.object({
8
+ chat_id: z.string().describe('群聊 ID'),
9
+ user_ids: z.string().describe('用户 open_id 列表,逗号分隔'),
10
+ }),
11
+ adapter: 'lark',
12
+ tags: ['lark'],
13
+ permissions: [platformPermission('lark', 'chat_admin')],
14
+ async execute({ chat_id, user_ids }, context) {
15
+ const endpoint = context.$client;
16
+ const success = await endpoint.addChatMembers(chat_id, user_ids.split(','));
17
+ return { success, message: success ? '成员添加成功' : '添加失败' };
18
+ },
19
+ });
@@ -1,6 +1,6 @@
1
- import { defineAgentTool } from '@zhin.js/agent/tools';
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
2
  import { z } from 'zod';
3
- import { platformPermit } from '../../src/platform-permit.js';
3
+ import { platformPermission } from '@zhin.js/permission';
4
4
 
5
5
  export default defineAgentTool<{ chat_id: string; user_ids: string }>({
6
6
  description: '添加飞书群成员',
@@ -10,11 +10,10 @@ export default defineAgentTool<{ chat_id: string; user_ids: string }>({
10
10
  }),
11
11
  adapter: 'lark',
12
12
  tags: ['lark'],
13
- permissions: [platformPermit('chat_admin')],
13
+ permissions: [platformPermission('lark', 'chat_admin')],
14
14
  async execute({ chat_id, user_ids }: { chat_id: string; user_ids: string }, context) {
15
15
  const endpoint = context.$client;
16
16
  const success = await endpoint.addChatMembers(chat_id, user_ids.split(','));
17
17
  return { success, message: success ? '成员添加成功' : '添加失败' };
18
18
  },
19
19
  });
20
-
@@ -0,0 +1,18 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineAgentTool } from '@zhin.js/tool';
3
+ import { z } from 'zod';
4
+ export default defineAgentTool({
5
+ description: '创建飞书群聊',
6
+ inputSchema: z.object({
7
+ name: z.string().describe('群名'),
8
+ members: z.string().describe('成员 open_id 列表,逗号分隔'),
9
+ owner: z.string().optional().describe('群主 open_id(可选)'),
10
+ }),
11
+ adapter: 'lark',
12
+ tags: ['lark'],
13
+ async execute({ name, members, owner }, context) {
14
+ const endpoint = context.$client;
15
+ const chatId = await endpoint.createChat(name, members.split(','), owner);
16
+ return { success: !!chatId, chat_id: chatId, message: chatId ? `群聊创建成功: ${chatId}` : '创建失败' };
17
+ },
18
+ });
@@ -1,4 +1,4 @@
1
- import { defineAgentTool } from '@zhin.js/agent/tools';
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
2
  import { z } from 'zod';
3
3
  export default defineAgentTool<{ name: string; members: string; owner?: string }>({
4
4
  description: '创建飞书群聊',
@@ -0,0 +1,16 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineAgentTool } from '@zhin.js/tool';
3
+ import { z } from 'zod';
4
+ export default defineAgentTool({
5
+ description: '解散飞书群聊(需要群主权限)',
6
+ inputSchema: z.object({
7
+ chat_id: z.string().describe('群聊 ID'),
8
+ }),
9
+ adapter: 'lark',
10
+ tags: ['lark'],
11
+ async execute({ chat_id }, context) {
12
+ const endpoint = context.$client;
13
+ const success = await endpoint.dissolveChat(chat_id);
14
+ return { success, message: success ? '群聊已解散' : '解散失败' };
15
+ },
16
+ });
@@ -1,4 +1,4 @@
1
- import { defineAgentTool } from '@zhin.js/agent/tools';
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
2
  import { z } from 'zod';
3
3
  export default defineAgentTool<{ chat_id: string }>({
4
4
  description: '解散飞书群聊(需要群主权限)',
@@ -0,0 +1,15 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineAgentTool } from '@zhin.js/tool';
3
+ import { z } from 'zod';
4
+ export default defineAgentTool({
5
+ description: '获取飞书用户信息',
6
+ inputSchema: z.object({
7
+ user_id: z.string().describe('用户 ID (open_id)'),
8
+ }),
9
+ adapter: 'lark',
10
+ tags: ['lark'],
11
+ async execute({ user_id }, context) {
12
+ const endpoint = context.$client;
13
+ return await endpoint.getUserInfo(user_id);
14
+ },
15
+ });
@@ -1,4 +1,4 @@
1
- import { defineAgentTool } from '@zhin.js/agent/tools';
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
2
  import { z } from 'zod';
3
3
 
4
4
  export default defineAgentTool<{ user_id: string }>({
@@ -0,0 +1,19 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineAgentTool } from '@zhin.js/tool';
3
+ import { z } from 'zod';
4
+ import { platformPermission } from '@zhin.js/permission';
5
+ export default defineAgentTool({
6
+ description: '移除飞书群管理员',
7
+ inputSchema: z.object({
8
+ chat_id: z.string().describe('群聊 ID'),
9
+ user_ids: z.string().describe('用户 open_id 列表,逗号分隔'),
10
+ }),
11
+ adapter: 'lark',
12
+ tags: ['lark'],
13
+ permissions: [platformPermission('lark', 'manage_managers')],
14
+ async execute({ chat_id, user_ids }, context) {
15
+ const endpoint = context.$client;
16
+ const success = await endpoint.removeChatManagers(chat_id, user_ids.split(','));
17
+ return { success, message: success ? '管理员移除成功' : '移除失败' };
18
+ },
19
+ });
@@ -1,6 +1,6 @@
1
- import { defineAgentTool } from '@zhin.js/agent/tools';
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
2
  import { z } from 'zod';
3
- import { platformPermit } from '../../src/platform-permit.js';
3
+ import { platformPermission } from '@zhin.js/permission';
4
4
 
5
5
  export default defineAgentTool<{ chat_id: string; user_ids: string }>({
6
6
  description: '移除飞书群管理员',
@@ -10,11 +10,10 @@ export default defineAgentTool<{ chat_id: string; user_ids: string }>({
10
10
  }),
11
11
  adapter: 'lark',
12
12
  tags: ['lark'],
13
- permissions: [platformPermit('manage_managers')],
13
+ permissions: [platformPermission('lark', 'manage_managers')],
14
14
  async execute({ chat_id, user_ids }: { chat_id: string; user_ids: string }, context) {
15
15
  const endpoint = context.$client;
16
16
  const success = await endpoint.removeChatManagers(chat_id, user_ids.split(','));
17
17
  return { success, message: success ? '管理员移除成功' : '移除失败' };
18
18
  },
19
19
  });
20
-
@@ -0,0 +1,19 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineAgentTool } from '@zhin.js/tool';
3
+ import { z } from 'zod';
4
+ import { platformPermission } from '@zhin.js/permission';
5
+ export default defineAgentTool({
6
+ description: '设置飞书群管理员',
7
+ inputSchema: z.object({
8
+ chat_id: z.string().describe('群聊 ID'),
9
+ user_ids: z.string().describe('用户 open_id 列表,逗号分隔'),
10
+ }),
11
+ adapter: 'lark',
12
+ tags: ['lark'],
13
+ permissions: [platformPermission('lark', 'manage_managers')],
14
+ async execute({ chat_id, user_ids }, context) {
15
+ const endpoint = context.$client;
16
+ const success = await endpoint.setChatManagers(chat_id, user_ids.split(','));
17
+ return { success, message: success ? '管理员设置成功' : '设置失败' };
18
+ },
19
+ });
@@ -1,6 +1,6 @@
1
- import { defineAgentTool } from '@zhin.js/agent/tools';
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
2
  import { z } from 'zod';
3
- import { platformPermit } from '../../src/platform-permit.js';
3
+ import { platformPermission } from '@zhin.js/permission';
4
4
 
5
5
  export default defineAgentTool<{ chat_id: string; user_ids: string }>({
6
6
  description: '设置飞书群管理员',
@@ -10,11 +10,10 @@ export default defineAgentTool<{ chat_id: string; user_ids: string }>({
10
10
  }),
11
11
  adapter: 'lark',
12
12
  tags: ['lark'],
13
- permissions: [platformPermit('manage_managers')],
13
+ permissions: [platformPermission('lark', 'manage_managers')],
14
14
  async execute({ chat_id, user_ids }: { chat_id: string; user_ids: string }, context) {
15
15
  const endpoint = context.$client;
16
16
  const success = await endpoint.setChatManagers(chat_id, user_ids.split(','));
17
17
  return { success, message: success ? '管理员设置成功' : '设置失败' };
18
18
  },
19
19
  });
20
-
@@ -0,0 +1,20 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineAgentTool } from '@zhin.js/tool';
3
+ import { z } from 'zod';
4
+ import { platformPermission } from '@zhin.js/permission';
5
+ export default defineAgentTool({
6
+ description: '更新飞书群聊信息(群名、描述)',
7
+ inputSchema: z.object({
8
+ chat_id: z.string().describe('群聊 ID'),
9
+ name: z.string().optional().describe('新群名(可选)'),
10
+ description: z.string().optional().describe('新描述(可选)'),
11
+ }),
12
+ adapter: 'lark',
13
+ tags: ['lark'],
14
+ permissions: [platformPermission('lark', 'chat_admin')],
15
+ async execute({ chat_id, name, description }, context) {
16
+ const endpoint = context.$client;
17
+ const success = await endpoint.updateChatInfo(chat_id, { name, description });
18
+ return { success, message: success ? '群信息更新成功' : '更新失败' };
19
+ },
20
+ });
@@ -1,6 +1,6 @@
1
- import { defineAgentTool } from '@zhin.js/agent/tools';
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
2
  import { z } from 'zod';
3
- import { platformPermit } from '../../src/platform-permit.js';
3
+ import { platformPermission } from '@zhin.js/permission';
4
4
 
5
5
  export default defineAgentTool<{ chat_id: string; name?: string; description?: string }>({
6
6
  description: '更新飞书群聊信息(群名、描述)',
@@ -11,11 +11,10 @@ export default defineAgentTool<{ chat_id: string; name?: string; description?: s
11
11
  }),
12
12
  adapter: 'lark',
13
13
  tags: ['lark'],
14
- permissions: [platformPermit('chat_admin')],
14
+ permissions: [platformPermission('lark', 'chat_admin')],
15
15
  async execute({ chat_id, name, description }: { chat_id: string; name?: string; description?: string }, context) {
16
16
  const endpoint = context.$client;
17
17
  const success = await endpoint.updateChatInfo(chat_id, { name, description });
18
18
  return { success, message: success ? '群信息更新成功' : '更新失败' };
19
19
  },
20
20
  });
21
-
@@ -0,0 +1,17 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineAgentTool } from '@zhin.js/tool';
3
+ import { z } from 'zod';
4
+ export default defineAgentTool({
5
+ description: '上传文件到飞书(image/file/video/audio)',
6
+ inputSchema: z.object({
7
+ file_path: z.string().describe('本地文件路径'),
8
+ file_type: z.enum(['image', 'file', 'video', 'audio']).default('file').describe('飞书文件类型'),
9
+ }),
10
+ adapter: 'lark',
11
+ tags: ['lark'],
12
+ async execute({ file_path, file_type }, context) {
13
+ const endpoint = context.$client;
14
+ const result = await endpoint.uploadFile(file_path, file_type);
15
+ return { success: true, file_key: result, message: `文件已上传,file_key: ${result}` };
16
+ },
17
+ });
@@ -1,4 +1,4 @@
1
- import { defineAgentTool } from '@zhin.js/agent/tools';
1
+ import { defineAgentTool } from '@zhin.js/tool';
2
2
  import { z } from 'zod';
3
3
 
4
4
  export default defineAgentTool<{
@@ -0,0 +1,3 @@
1
+ # LARK Platform Agent
2
+
3
+ You are the lark platform specialist. Interpret requests in the current lark conversation and load only the narrowest private Skill needed for the task.
@@ -1,3 +1,3 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
- import { larkEndpointCommands } from "../../../lib/lark-endpoint-commands.js";
2
+ import { larkEndpointCommands } from '../../definition.js';
3
3
  export default larkEndpointCommands.add;
@@ -0,0 +1,3 @@
1
+ import { larkEndpointCommands } from '../../definition.js';
2
+
3
+ export default larkEndpointCommands.add;
@@ -1,10 +1,11 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
1
2
  /**
2
- * `lark.endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
3
- * commands/endpoint/ 下的 list / add / remove 直接默认导出这三项。
3
+ * `lark endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
4
+ * commands/lark/endpoint/ 下的 list / add / remove 直接默认导出这三项。
4
5
  */
5
6
  import { createEndpointCommands } from 'zhin.js/adapter';
6
7
  import { defineCommand } from 'zhin.js/command';
7
- import { larkRuntimeStateToken } from './lark-runtime-state.js';
8
+ import { larkRuntimeStateToken } from "../../../lib/lark-runtime-state.js";
8
9
  export const larkEndpointCommands = createEndpointCommands({
9
10
  adapterKey: 'lark',
10
11
  adapterDisplayName: 'Lark',
@@ -1,10 +1,10 @@
1
1
  /**
2
- * `lark.endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
3
- * commands/endpoint/ 下的 list / add / remove 直接默认导出这三项。
2
+ * `lark endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
3
+ * commands/lark/endpoint/ 下的 list / add / remove 直接默认导出这三项。
4
4
  */
5
5
  import { createEndpointCommands } from 'zhin.js/adapter';
6
6
  import { defineCommand } from 'zhin.js/command';
7
- import { larkRuntimeStateToken } from './lark-runtime-state.js';
7
+ import { larkRuntimeStateToken } from '../../../src/lark-runtime-state.js';
8
8
 
9
9
  export const larkEndpointCommands = createEndpointCommands({
10
10
  adapterKey: 'lark',
@@ -1,3 +1,3 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
- import { larkEndpointCommands } from "../../lib/lark-endpoint-commands.js";
2
+ import { larkEndpointCommands } from '../definition.js';
3
3
  export default larkEndpointCommands.list;
@@ -0,0 +1,3 @@
1
+ import { larkEndpointCommands } from '../definition.js';
2
+
3
+ export default larkEndpointCommands.list;
@@ -1,3 +1,3 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
- import { larkEndpointCommands } from "../../../lib/lark-endpoint-commands.js";
2
+ import { larkEndpointCommands } from '../../definition.js';
3
3
  export default larkEndpointCommands.remove;
@@ -0,0 +1,3 @@
1
+ import { larkEndpointCommands } from '../../definition.js';
2
+
3
+ export default larkEndpointCommands.remove;
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { formatInboundContent, formatOutboundBody, generateMessageId, headerValue, larkInboundConversation, normalizeWebhookPath, readTextBody, resolveChatType, resolveLarkConfig, resolveSender, verifySignature, type AccessToken, type LarkAdapterConfig, type LarkApiResponse, type LarkEventBody, type LarkMessage, type LarkSendBody, type LarkWireSegment, type ResolvedLarkConfig, } from './protocol.js';
1
+ export { formatInboundContent, formatOutboundBody, generateMessageId, headerValue, larkInboundConversation, normalizeWebhookPath, readTextBody, resolveChatType, resolveLarkConfig, resolveSender, verifySignature, type AccessToken, type LarkEndpointConfig, type LarkApiResponse, type LarkEventBody, type LarkMessage, type LarkSendBody, type LarkWireSegment, type ResolvedLarkConfig, } from './protocol.js';
2
2
  export { larkClient, type LarkClientEventMap } from './client.js';
3
3
  export { checkLarkPlatformPermit, larkGroupPermitResolver, normalizeLarkSenderForPermit, platformPermit, } from './platform-permit.js';
4
4
  export { LarkClient, LarkEndpoint, type LarkClientApi, type LarkEndpointOptions, type LarkFetch, } from './endpoint.js';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Lark 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
3
- * 由 plugin.ts setup() provide,adapter create 与 `lark.endpoint` 命令共享(同一 owner generation)。
3
+ * 由 plugin.ts setup() provide,adapter create 与 `lark endpoint` 命令共享(同一 owner generation)。
4
4
  */
5
5
  import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
6
6
  export const larkRuntimeStateToken = defineEndpointRuntimeStateToken('lark');
@@ -1,4 +1,4 @@
1
- import { type MediaRef } from '@zhin.js/core';
1
+ import { type MediaRef } from '@zhin.js/im-contract';
2
2
  export interface MediaBinary {
3
3
  readonly data: Buffer;
4
4
  readonly mimeType: string;
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { readFile } from 'node:fs/promises';
7
7
  import { basename } from 'node:path';
8
- import { isMediaRef } from '@zhin.js/core';
8
+ import { isMediaRef } from '@zhin.js/im-contract';
9
9
  const MIME_EXT = {
10
10
  'image/jpeg': 'jpg',
11
11
  'image/png': 'png',
package/lib/protocol.d.ts CHANGED
@@ -3,21 +3,17 @@
3
3
  * Canonicalization is owned by gateway/core before endpoint.send.
4
4
  */
5
5
  import type { IncomingMessage } from 'node:http';
6
- import type { ConversationRef } from '@zhin.js/im-contract';
7
- /** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
8
- export interface LarkAdapterConfig {
9
- readonly id?: string;
10
- readonly appId?: string;
11
- readonly appSecret?: string;
6
+ import { type ConversationRef } from '@zhin.js/im-contract';
7
+ /** One endpoint config after AdapterIndex expands `plugins.<instanceKey>.endpoints`. */
8
+ export interface LarkEndpointConfig {
9
+ readonly id: string;
10
+ readonly appId: string;
11
+ readonly appSecret: string;
12
12
  readonly encryptKey?: string;
13
13
  readonly verificationToken?: string;
14
14
  readonly webhookPath?: string;
15
15
  readonly apiBaseUrl?: string;
16
16
  readonly isFeishu?: boolean;
17
- /** Transitional: legacy root `endpoints[]` with `context: lark`. */
18
- readonly endpoints?: ReadonlyArray<Partial<ResolvedLarkConfig> & {
19
- readonly context?: string;
20
- }>;
21
17
  }
22
18
  export interface ResolvedLarkConfig {
23
19
  readonly context: 'lark';
@@ -94,7 +90,7 @@ export interface LarkSendBody {
94
90
  readonly msg_type: string;
95
91
  readonly content: string;
96
92
  }
97
- export declare function resolveLarkConfig(config?: LarkAdapterConfig): ResolvedLarkConfig;
93
+ export declare function resolveLarkConfig(config: LarkEndpointConfig): ResolvedLarkConfig;
98
94
  export declare function normalizeWebhookPath(path: string): string;
99
95
  export declare function resolveChatType(chatId?: string, chatType?: string): 'group' | 'private';
100
96
  /**
package/lib/protocol.js CHANGED
@@ -3,28 +3,21 @@
3
3
  * Canonicalization is owned by gateway/core before endpoint.send.
4
4
  */
5
5
  import { createHash, timingSafeEqual } from 'node:crypto';
6
- import { isMediaRef } from '@zhin.js/core';
6
+ import { isMediaRef } from '@zhin.js/im-contract';
7
7
  import { formatCompact, getLogger } from '@zhin.js/logger';
8
8
  const logger = getLogger('lark');
9
- export function resolveLarkConfig(config = {}) {
10
- const entry = config.endpoints?.find((item) => item.context === 'lark');
11
- const appId = config.appId ?? entry?.appId ?? process.env.LARK_APP_ID;
12
- const appSecret = config.appSecret ?? entry?.appSecret ?? process.env.LARK_APP_SECRET;
13
- if (!appId || !appSecret) {
14
- throw new TypeError('Lark adapter requires appId + appSecret (plugins.<key> or endpoints with context: lark)');
15
- }
16
- const isFeishu = config.isFeishu ?? entry?.isFeishu ?? true;
17
- const id = (typeof config.id === 'string' && config.id)
18
- || (typeof entry?.id === 'string' && entry.id)
19
- || process.env.LARK_BOT_NAME
20
- || 'lark-bot';
21
- const webhookPath = normalizeWebhookPath(config.webhookPath ?? entry?.webhookPath ?? '/lark/webhook');
9
+ export function resolveLarkConfig(config) {
10
+ const id = requiredEndpointField(config.id, 'id');
11
+ const appId = requiredEndpointField(config.appId, 'appId');
12
+ const appSecret = requiredEndpointField(config.appSecret, 'appSecret');
13
+ const isFeishu = config.isFeishu ?? true;
14
+ const webhookPath = normalizeWebhookPath(config.webhookPath ?? '/lark/webhook');
22
15
  const defaultBase = isFeishu
23
16
  ? 'https://open.feishu.cn/open-apis'
24
17
  : 'https://open.larksuite.com/open-apis';
25
- const apiBaseUrl = (config.apiBaseUrl ?? entry?.apiBaseUrl ?? defaultBase).replace(/\/$/, '');
26
- const encryptKey = config.encryptKey ?? entry?.encryptKey;
27
- const verificationToken = config.verificationToken ?? entry?.verificationToken;
18
+ const apiBaseUrl = (config.apiBaseUrl ?? defaultBase).replace(/\/$/, '');
19
+ const encryptKey = config.encryptKey;
20
+ const verificationToken = config.verificationToken;
28
21
  return {
29
22
  context: 'lark',
30
23
  id,
@@ -37,6 +30,12 @@ export function resolveLarkConfig(config = {}) {
37
30
  isFeishu,
38
31
  };
39
32
  }
33
+ function requiredEndpointField(value, field) {
34
+ if (typeof value !== 'string' || !value.trim()) {
35
+ throw new TypeError(`Lark endpoint requires a non-empty ${field}`);
36
+ }
37
+ return value.trim();
38
+ }
40
39
  export function normalizeWebhookPath(path) {
41
40
  const trimmed = path.trim() || '/lark/webhook';
42
41
  return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-lark",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Zhin.js Lark/Feishu (飞书) adapter for Plugin Runtime (HTTP webhook)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -34,27 +34,26 @@
34
34
  "directory": "plugins/adapters/lark"
35
35
  },
36
36
  "dependencies": {
37
- "@zhin.js/adapter": "1.1.12",
38
- "@zhin.js/core": "1.1.35",
39
- "@zhin.js/feature-kit": "1.1.0",
40
- "@zhin.js/host-http": "1.1.0",
41
- "@zhin.js/im-contract": "1.1.0",
42
- "@zhin.js/logger": "1.1.0"
37
+ "@zhin.js/adapter": "1.1.14",
38
+ "@zhin.js/agent-feature": "1.1.1",
39
+ "@zhin.js/core": "1.1.37",
40
+ "@zhin.js/feature-kit": "1.1.1",
41
+ "@zhin.js/host-http": "1.1.1",
42
+ "@zhin.js/im-contract": "1.1.1",
43
+ "@zhin.js/logger": "1.1.1",
44
+ "@zhin.js/skill": "1.1.1",
45
+ "@zhin.js/tool": "1.1.1"
43
46
  },
44
47
  "peerDependencies": {
45
48
  "zod": "^4.0.0",
46
- "@zhin.js/adapter": "^1.1.12",
47
- "@zhin.js/agent": "^1.1.23",
48
- "@zhin.js/command": "^1.1.0",
49
- "@zhin.js/core": "^1.1.35",
50
- "@zhin.js/host-http": "^1.1.0",
51
- "@zhin.js/permission": "^1.1.0",
52
- "zhin.js": "^1.1.0"
49
+ "@zhin.js/adapter": "^1.1.14",
50
+ "@zhin.js/command": "^1.1.1",
51
+ "@zhin.js/core": "^1.1.37",
52
+ "@zhin.js/host-http": "^1.1.1",
53
+ "@zhin.js/permission": "^1.1.1",
54
+ "zhin.js": "^1.1.2"
53
55
  },
54
56
  "peerDependenciesMeta": {
55
- "@zhin.js/agent": {
56
- "optional": true
57
- },
58
57
  "@zhin.js/command": {
59
58
  "optional": true
60
59
  },
@@ -70,8 +69,7 @@
70
69
  "typescript": "^6.0.3",
71
70
  "vitest": "^4.1.10",
72
71
  "zod": "^4.4.3",
73
- "@zhin.js/agent": "1.1.23",
74
- "zhin.js": "1.1.0"
72
+ "zhin.js": "1.1.2"
75
73
  },
76
74
  "files": [
77
75
  "adapters",
@@ -80,9 +78,11 @@
80
78
  "schema.json",
81
79
  "src",
82
80
  "lib",
83
- "agent",
81
+ "tools",
82
+ "agents",
84
83
  "README.md",
85
- "CHANGELOG.md"
84
+ "CHANGELOG.md",
85
+ "PERMITS.md"
86
86
  ],
87
87
  "publishConfig": {
88
88
  "access": "public",
@@ -105,6 +105,18 @@
105
105
  {
106
106
  "package": "@zhin.js/command",
107
107
  "api": "^1.0.0"
108
+ },
109
+ {
110
+ "package": "@zhin.js/tool",
111
+ "api": "^1.0.0"
112
+ },
113
+ {
114
+ "package": "@zhin.js/skill",
115
+ "api": "^1.0.0"
116
+ },
117
+ {
118
+ "package": "@zhin.js/agent-feature",
119
+ "api": "^1.0.0"
108
120
  }
109
121
  ],
110
122
  "plugins": []
package/schema.json CHANGED
@@ -34,10 +34,11 @@
34
34
  },
35
35
  "endpoints": {
36
36
  "type": "array",
37
+ "minItems": 1,
37
38
  "description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(id 必填,其余覆盖顶层)",
38
39
  "items": {
39
40
  "type": "object",
40
- "additionalProperties": true,
41
+ "additionalProperties": false,
41
42
  "properties": {
42
43
  "master": {
43
44
  "type": [
@@ -73,6 +74,18 @@
73
74
  "type": "string",
74
75
  "description": "Lark verification token"
75
76
  },
77
+ "webhookPath": {
78
+ "type": "string"
79
+ },
80
+ "apiBaseUrl": {
81
+ "type": "string"
82
+ },
83
+ "isFeishu": {
84
+ "type": "boolean"
85
+ },
86
+ "commandPrefix": {
87
+ "type": "string"
88
+ },
76
89
  "id": {
77
90
  "type": "string",
78
91
  "description": "Lark bot name"
package/src/index.ts CHANGED
@@ -11,7 +11,7 @@ export {
11
11
  resolveSender,
12
12
  verifySignature,
13
13
  type AccessToken,
14
- type LarkAdapterConfig,
14
+ type LarkEndpointConfig,
15
15
  type LarkApiResponse,
16
16
  type LarkEventBody,
17
17
  type LarkMessage,
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Lark 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
3
- * 由 plugin.ts setup() provide,adapter create 与 `lark.endpoint` 命令共享(同一 owner generation)。
3
+ * 由 plugin.ts setup() provide,adapter create 与 `lark endpoint` 命令共享(同一 owner generation)。
4
4
  */
5
5
  import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
6
6
 
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { readFile } from 'node:fs/promises';
7
7
  import { basename } from 'node:path';
8
- import { isMediaRef, type MediaRef } from '@zhin.js/core';
8
+ import { isMediaRef, type MediaRef } from '@zhin.js/im-contract';
9
9
 
10
10
  export interface MediaBinary {
11
11
  readonly data: Buffer;
package/src/protocol.ts CHANGED
@@ -5,26 +5,21 @@
5
5
 
6
6
  import { createHash, timingSafeEqual } from 'node:crypto';
7
7
  import type { IncomingMessage } from 'node:http';
8
- import { isMediaRef } from '@zhin.js/core';
9
- import type { ConversationRef } from '@zhin.js/im-contract';
8
+ import { isMediaRef, type ConversationRef } from '@zhin.js/im-contract';
10
9
  import { formatCompact, getLogger } from '@zhin.js/logger';
11
10
 
12
11
  const logger = getLogger('lark');
13
12
 
14
- /** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
15
- export interface LarkAdapterConfig {
16
- readonly id?: string;
17
- readonly appId?: string;
18
- readonly appSecret?: string;
13
+ /** One endpoint config after AdapterIndex expands `plugins.<instanceKey>.endpoints`. */
14
+ export interface LarkEndpointConfig {
15
+ readonly id: string;
16
+ readonly appId: string;
17
+ readonly appSecret: string;
19
18
  readonly encryptKey?: string;
20
19
  readonly verificationToken?: string;
21
20
  readonly webhookPath?: string;
22
21
  readonly apiBaseUrl?: string;
23
22
  readonly isFeishu?: boolean;
24
- /** Transitional: legacy root `endpoints[]` with `context: lark`. */
25
- readonly endpoints?: ReadonlyArray<Partial<ResolvedLarkConfig> & {
26
- readonly context?: string;
27
- }>;
28
23
  }
29
24
 
30
25
  export interface ResolvedLarkConfig {
@@ -109,31 +104,20 @@ export interface LarkSendBody {
109
104
  readonly content: string;
110
105
  }
111
106
 
112
- export function resolveLarkConfig(config: LarkAdapterConfig = {}): ResolvedLarkConfig {
113
- const entry = config.endpoints?.find((item) => item.context === 'lark');
114
- const appId = config.appId ?? entry?.appId ?? process.env.LARK_APP_ID;
115
- const appSecret = config.appSecret ?? entry?.appSecret ?? process.env.LARK_APP_SECRET;
116
- if (!appId || !appSecret) {
117
- throw new TypeError(
118
- 'Lark adapter requires appId + appSecret (plugins.<key> or endpoints with context: lark)',
119
- );
120
- }
121
- const isFeishu = config.isFeishu ?? entry?.isFeishu ?? true;
122
- const id = (typeof config.id === 'string' && config.id)
123
- || (typeof entry?.id === 'string' && entry.id)
124
- || process.env.LARK_BOT_NAME
125
- || 'lark-bot';
126
- const webhookPath = normalizeWebhookPath(
127
- config.webhookPath ?? entry?.webhookPath ?? '/lark/webhook',
128
- );
107
+ export function resolveLarkConfig(config: LarkEndpointConfig): ResolvedLarkConfig {
108
+ const id = requiredEndpointField(config.id, 'id');
109
+ const appId = requiredEndpointField(config.appId, 'appId');
110
+ const appSecret = requiredEndpointField(config.appSecret, 'appSecret');
111
+ const isFeishu = config.isFeishu ?? true;
112
+ const webhookPath = normalizeWebhookPath(config.webhookPath ?? '/lark/webhook');
129
113
  const defaultBase = isFeishu
130
114
  ? 'https://open.feishu.cn/open-apis'
131
115
  : 'https://open.larksuite.com/open-apis';
132
116
  const apiBaseUrl = (
133
- config.apiBaseUrl ?? entry?.apiBaseUrl ?? defaultBase
117
+ config.apiBaseUrl ?? defaultBase
134
118
  ).replace(/\/$/, '');
135
- const encryptKey = config.encryptKey ?? entry?.encryptKey;
136
- const verificationToken = config.verificationToken ?? entry?.verificationToken;
119
+ const encryptKey = config.encryptKey;
120
+ const verificationToken = config.verificationToken;
137
121
  return {
138
122
  context: 'lark',
139
123
  id,
@@ -147,6 +131,16 @@ export function resolveLarkConfig(config: LarkAdapterConfig = {}): ResolvedLarkC
147
131
  };
148
132
  }
149
133
 
134
+ function requiredEndpointField(
135
+ value: unknown,
136
+ field: 'id' | 'appId' | 'appSecret',
137
+ ): string {
138
+ if (typeof value !== 'string' || !value.trim()) {
139
+ throw new TypeError(`Lark endpoint requires a non-empty ${field}`);
140
+ }
141
+ return value.trim();
142
+ }
143
+
150
144
  export function normalizeWebhookPath(path: string): string {
151
145
  const trimmed = path.trim() || '/lark/webhook';
152
146
  return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
@@ -1,89 +0,0 @@
1
- ---
2
- name: lark
3
- platforms:
4
- - lark
5
- description: >-
6
- 飞书/Lark 群聊管理能力。当用户在飞书中请求群管理(踢人、查成员、改群名)、
7
- 群聊创建/更新/解散、管理员设置/移除、用户查询或文件上传时使用。
8
- 即使用户没有提到飞书,只要上下文是 Lark 场景且涉及群聊或用户操作,就应触发。
9
- 仅有昵称时必须先 list_members 或 get_user 获取 user_id。
10
- keywords:
11
- - lark
12
- - 飞书
13
- - adapter:lark
14
- - 群管理
15
- - 管理员
16
- - 群聊
17
- - 文件上传
18
- - 解散
19
- - list_members
20
- tags:
21
- - group
22
- - management
23
- - im
24
- - enterprise
25
- tools:
26
- - lark_get_user
27
- - lark_create_chat
28
- - lark_update_chat
29
- - lark_add_members
30
- - lark_set_managers
31
- - lark_remove_managers
32
- - lark_dissolve_chat
33
- - lark_upload_file
34
- - lark_kick_member
35
- - lark_list_members
36
- - lark_get_group_info
37
- - lark_set_group_name
38
- ---
39
-
40
- # 飞书/Lark 群聊管理技能
41
-
42
- 飞书的群聊模型偏向企业场景,有群聊创建/解散的完整生命周期管理,以及文件上传能力。
43
-
44
- ## 核心原则
45
-
46
- ### 企业级 ID 体系
47
-
48
- 飞书的用户 ID 有三种形式(open_id / union_id / user_id),不同 API 可能需要不同 ID 类型。通过 `lark_get_user` 可以查询用户详情并获取各种 ID。
49
-
50
- ### 群聊生命周期
51
-
52
- 飞书支持完整的群聊生命周期管理:创建 → 添加成员 → 设管理员 → 正常使用 → 更新设置 → 解散。
53
-
54
- **Example — 创建项目群:**
55
- ```
56
- 步骤1: lark_create_chat(name="XX项目组", members=[user1, user2])
57
- 步骤2: lark_set_managers(chat_id, managers=[user1]) # 设管理员
58
- ```
59
-
60
- ## 工具分类
61
-
62
- ### 群聊管理
63
-
64
- | 工具 | 用途 | 说明 |
65
- |------|------|------|
66
- | `lark_create_chat` | 创建群聊 | 需指定群名 + 初始成员 |
67
- | `lark_update_chat` | 更新群设置 | 群名、群描述等 |
68
- | `lark_dissolve_chat` | 解散群聊 | **不可逆**,需群主权限 |
69
- | `lark_add_members` | 添加成员 | — |
70
- | `lark_kick_member` | 移除成员 | — |
71
- | `lark_set_managers` | 设管理员 | — |
72
- | `lark_remove_managers` | 移除管理员 | — |
73
- | `lark_set_group_name` | 改群名 | — |
74
- | `lark_list_members` | 成员列表 | — |
75
- | `lark_get_group_info` | 群信息 | — |
76
-
77
- ### 用户与文件
78
-
79
- | 工具 | 用途 | 说明 |
80
- |------|------|------|
81
- | `lark_get_user` | 查询用户信息 | 可获取多种 ID 形式 |
82
- | `lark_upload_file` | 上传文件 | 返回 file_key,可在消息中引用 |
83
-
84
- ## 易错点
85
-
86
- 1. **解散群聊不可逆**,需群主权限。确认用户意图后再执行。
87
- 2. **群聊创建至少需要群名和一个初始成员**。
88
- 3. **文件上传返回 file_key**,这个 key 用于在消息中引用文件,不是文件内容本身。
89
- 4. **飞书有 open_id / union_id / user_id 三种 ID**,操作时注意使用正确的 ID 类型。
@@ -1,3 +0,0 @@
1
- import { larkEndpointCommands } from '../../../src/lark-endpoint-commands.js';
2
-
3
- export default larkEndpointCommands.add;
@@ -1,3 +0,0 @@
1
- import { larkEndpointCommands } from '../../src/lark-endpoint-commands.js';
2
-
3
- export default larkEndpointCommands.list;
@@ -1,3 +0,0 @@
1
- import { larkEndpointCommands } from '../../../src/lark-endpoint-commands.js';
2
-
3
- export default larkEndpointCommands.remove;
@@ -1 +0,0 @@
1
- export declare const larkEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage, string | undefined>>>;
File without changes