@zhin.js/adapter-dingtalk 1.1.0 → 1.1.3

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 (48) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/README.md +7 -7
  3. package/adapters/{dingtalk.js → dingtalk/index.js} +6 -6
  4. package/adapters/{dingtalk.ts → dingtalk/index.ts} +9 -9
  5. package/agents/dingtalk/agent.json +20 -0
  6. package/agents/dingtalk/boundaries.md +3 -0
  7. package/agents/dingtalk/conventions.md +3 -0
  8. package/agents/dingtalk/skills/dingtalk/SKILL.md +26 -0
  9. package/agents/dingtalk/skills/dingtalk/tools/add_chat_members/index.js +19 -0
  10. package/{agent/tools/add_chat_members.ts → agents/dingtalk/skills/dingtalk/tools/add_chat_members/index.ts} +3 -3
  11. package/agents/dingtalk/skills/dingtalk/tools/create_chat/index.js +20 -0
  12. package/{agent/tools/create_chat.ts → agents/dingtalk/skills/dingtalk/tools/create_chat/index.ts} +3 -3
  13. package/agents/dingtalk/skills/dingtalk/tools/dept_info/index.js +15 -0
  14. package/{agent/tools/dept_info.ts → agents/dingtalk/skills/dingtalk/tools/dept_info/index.ts} +1 -1
  15. package/agents/dingtalk/skills/dingtalk/tools/get_dept_users/index.js +16 -0
  16. package/{agent/tools/get_dept_users.ts → agents/dingtalk/skills/dingtalk/tools/get_dept_users/index.ts} +1 -1
  17. package/agents/dingtalk/skills/dingtalk/tools/get_user/index.js +15 -0
  18. package/{agent/tools/get_user.ts → agents/dingtalk/skills/dingtalk/tools/get_user/index.ts} +1 -1
  19. package/agents/dingtalk/skills/dingtalk/tools/list_departments/index.js +16 -0
  20. package/{agent/tools/list_departments.ts → agents/dingtalk/skills/dingtalk/tools/list_departments/index.ts} +1 -1
  21. package/agents/dingtalk/skills/dingtalk/tools/send_work_notice/index.js +18 -0
  22. package/{agent/tools/send_work_notice.ts → agents/dingtalk/skills/dingtalk/tools/send_work_notice/index.ts} +1 -1
  23. package/agents/dingtalk/skills/dingtalk/tools/update_chat/index.js +29 -0
  24. package/{agent/tools/update_chat.ts → agents/dingtalk/skills/dingtalk/tools/update_chat/index.ts} +1 -1
  25. package/agents/dingtalk/system.md +3 -0
  26. package/commands/{endpoint/add/[id].js → dingtalk/endpoint/add/[id]/index.js} +1 -1
  27. package/commands/dingtalk/endpoint/add/[id]/index.ts +3 -0
  28. package/{lib/dingtalk-endpoint-commands.js → commands/dingtalk/endpoint/definition.js} +4 -3
  29. package/{src/dingtalk-endpoint-commands.ts → commands/dingtalk/endpoint/definition.ts} +3 -3
  30. package/commands/{endpoint/list.js → dingtalk/endpoint/list/index.js} +1 -1
  31. package/commands/dingtalk/endpoint/list/index.ts +3 -0
  32. package/commands/{endpoint/remove/[id].js → dingtalk/endpoint/remove/[id]/index.js} +1 -1
  33. package/commands/dingtalk/endpoint/remove/[id]/index.ts +3 -0
  34. package/lib/dingtalk-runtime-state.js +1 -1
  35. package/lib/index.d.ts +1 -1
  36. package/lib/protocol.d.ts +7 -11
  37. package/lib/protocol.js +14 -15
  38. package/package.json +32 -21
  39. package/schema.json +9 -4
  40. package/src/dingtalk-runtime-state.ts +1 -1
  41. package/src/index.ts +1 -1
  42. package/src/protocol.ts +23 -31
  43. package/agent/skills/dingtalk.md +0 -91
  44. package/commands/endpoint/add/[id].ts +0 -3
  45. package/commands/endpoint/list.ts +0 -3
  46. package/commands/endpoint/remove/[id].ts +0 -3
  47. package/lib/dingtalk-endpoint-commands.d.ts +0 -1
  48. /package/{agent/PERMITS.md → PERMITS.md} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,112 @@
1
1
  # @zhin.js/adapter-dingtalk
2
2
 
3
+ ## 1.1.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [5b5d270]
8
+ - Updated dependencies [36c2eb9]
9
+ - @zhin.js/im-contract@1.1.2
10
+ - @zhin.js/core@1.1.38
11
+ - @zhin.js/adapter@1.1.15
12
+ - @zhin.js/host-http@1.1.2
13
+ - @zhin.js/agent-feature@1.1.2
14
+ - @zhin.js/feature-kit@1.1.2
15
+ - @zhin.js/skill@1.1.2
16
+ - @zhin.js/tool@1.1.2
17
+
18
+ ## 1.1.2
19
+
20
+ ### Patch Changes
21
+
22
+ - 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`.
23
+ - 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.
24
+
25
+ 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.
26
+
27
+ 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.
28
+
29
+ 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.
30
+
31
+ 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`.
32
+
33
+ - 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.
34
+ - 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.
35
+ - 4380cf9: Colocate adapter command definitions and Agent Skill handlers with their owning capabilities, and provide a shared validated platform permission constructor.
36
+ - ab6bde9: Require the canonical expanded DingTalk 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 `DingTalkEndpointConfig`; optional webhook and robot fields are no longer incorrectly required by the schema.
37
+ - 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.
38
+ - 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.
39
+ - Updated dependencies [c861789]
40
+ - Updated dependencies [1414ccb]
41
+ - Updated dependencies [743d470]
42
+ - Updated dependencies [62dee52]
43
+ - Updated dependencies [cd54131]
44
+ - Updated dependencies [244e475]
45
+ - Updated dependencies [a9e4a40]
46
+ - Updated dependencies [5855db7]
47
+ - Updated dependencies [ec921d2]
48
+ - Updated dependencies [8740059]
49
+ - Updated dependencies [63d1f7a]
50
+ - Updated dependencies [25a845a]
51
+ - Updated dependencies [103f2c3]
52
+ - Updated dependencies [9110ab8]
53
+ - Updated dependencies [cd2a888]
54
+ - Updated dependencies [eb3227a]
55
+ - Updated dependencies [b853dba]
56
+ - Updated dependencies [e561309]
57
+ - Updated dependencies [d4c6175]
58
+ - Updated dependencies [7a0e1ca]
59
+ - Updated dependencies [103b5d3]
60
+ - Updated dependencies [5a7a7f7]
61
+ - Updated dependencies [b076eae]
62
+ - Updated dependencies [535fed1]
63
+ - Updated dependencies [73a24b7]
64
+ - Updated dependencies [2dbbc15]
65
+ - Updated dependencies [1cb1163]
66
+ - Updated dependencies [be3061e]
67
+ - Updated dependencies [75f8332]
68
+ - Updated dependencies [81935e2]
69
+ - Updated dependencies [f9ed01b]
70
+ - Updated dependencies [ac0ab50]
71
+ - Updated dependencies [5140ce1]
72
+ - Updated dependencies [522d75f]
73
+ - Updated dependencies [a7611b3]
74
+ - Updated dependencies [8823044]
75
+ - Updated dependencies [379439b]
76
+ - Updated dependencies [11c9352]
77
+ - Updated dependencies [6b70e46]
78
+ - Updated dependencies [135ac91]
79
+ - Updated dependencies [140cf0f]
80
+ - Updated dependencies [251e4d2]
81
+ - Updated dependencies [203ad34]
82
+ - Updated dependencies [e6c5113]
83
+ - Updated dependencies [e0f6478]
84
+ - Updated dependencies [baef56b]
85
+ - Updated dependencies [698f16f]
86
+ - Updated dependencies [da0a8e3]
87
+ - Updated dependencies [2fd8017]
88
+ - Updated dependencies [5c3858e]
89
+ - Updated dependencies [33ea736]
90
+ - Updated dependencies [507d602]
91
+ - Updated dependencies [df9f76b]
92
+ - @zhin.js/core@1.1.37
93
+ - @zhin.js/tool@1.1.1
94
+ - @zhin.js/host-http@1.1.1
95
+ - @zhin.js/adapter@1.1.14
96
+ - @zhin.js/feature-kit@1.1.1
97
+ - @zhin.js/agent-feature@1.1.1
98
+ - @zhin.js/skill@1.1.1
99
+ - @zhin.js/logger@1.1.1
100
+ - @zhin.js/im-contract@1.1.1
101
+
102
+ ## 1.1.1
103
+
104
+ ### Patch Changes
105
+
106
+ - Updated dependencies [769e67f]
107
+ - @zhin.js/adapter@1.1.13
108
+ - @zhin.js/core@1.1.36
109
+
3
110
  ## 1.1.0
4
111
 
5
112
  ### Minor Changes
package/README.md CHANGED
@@ -18,7 +18,7 @@ pnpm add @zhin.js/adapter-dingtalk
18
18
 
19
19
  ## Plugin Runtime
20
20
 
21
- - `@zhin.js/adapter` — 约定式薄入口 `adapters/dingtalk.ts`(`defineAdapter`)
21
+ - `@zhin.js/adapter` — 约定式薄入口 `adapters/dingtalk/index.ts`(`defineAdapter`)
22
22
  - 实现:`src/endpoint.ts`(生命周期/出站/OpenAPI)、`src/webhook.ts`(验签入站)、`src/protocol.ts`
23
23
  - `@zhin.js/core` — `Endpoint.emit(...)` 入站、`outboundMessageToken` 出站
24
24
  - `@zhin.js/host-http` — `httpHostToken` 注册 Webhook 路由(**非** legacy host-router/Koa)
@@ -35,7 +35,7 @@ pnpm add @zhin.js/adapter-dingtalk
35
35
  3. 设置消息接收 URL 为 `https://your-domain/dingtalk/webhook`
36
36
  4. Runtime Host(`http`)须已 listen,Webhook 才可达
37
37
 
38
- 必填字段(`endpoints[i]`):`name`、`appKey`、`appSecret`、`webhookPath`、`robotCode`。
38
+ 必填字段(`endpoints[i]`):`id`、`appKey`、`appSecret`。
39
39
 
40
40
  ## 最小配置
41
41
 
@@ -45,7 +45,7 @@ plugins:
45
45
  dingtalk:
46
46
  apiBaseUrl: https://oapi.dingtalk.com # 可选,顶层共享
47
47
  endpoints:
48
- - name: my-dingtalk-bot
48
+ - id: my-dingtalk-bot
49
49
  appKey: ${DINGTALK_APP_KEY}
50
50
  appSecret: ${DINGTALK_APP_SECRET}
51
51
  robotCode: ${DINGTALK_ROBOT_CODE}
@@ -58,9 +58,9 @@ plugins:
58
58
 
59
59
  | 变量 | 说明 |
60
60
  |------|------|
61
- | `DINGTALK_APP_KEY` | 应用 AppKey |
62
- | `DINGTALK_APP_SECRET` | 应用 AppSecret |
63
- | `DINGTALK_ROBOT_CODE` | RobotCode(主动发送 `/robot/send`) |
61
+ | `DINGTALK_APP_KEY` | 示例中由 YAML `${DINGTALK_APP_KEY}` 引用的 AppKey;变量名可自行定义 |
62
+ | `DINGTALK_APP_SECRET` | 示例中由 YAML `${DINGTALK_APP_SECRET}` 引用的 AppSecret;变量名可自行定义 |
63
+ | `DINGTALK_ROBOT_CODE` | 示例中由 YAML `${DINGTALK_ROBOT_CODE}` 引用的 RobotCode;变量名可自行定义 |
64
64
 
65
65
  ## 消息类型映射
66
66
 
@@ -75,7 +75,7 @@ plugins:
75
75
 
76
76
  ## Agent 工具
77
77
 
78
- `agent/` 目录保留(get_user、部门、群聊、工作通知等)。工具声明 `adapter: 'dingtalk'` 后,通过惰性的 `context.$client` 自动取得当前操作的 `DingTalkClient`;无需把 Endpoint id 暴露给模型。
78
+ `agents/dingtalk/skills/dingtalk/tools/` 在 DingTalk Skill 激活后提供 get_user、部门、群聊、工作通知等 Tool。工具声明 `adapter: 'dingtalk'` 后,通过惰性的 `context.$client` 自动取得当前操作的 `DingTalkClient`;无需把 Endpoint id 暴露给模型。
79
79
 
80
80
  ## 平台权限(platform permit)
81
81
 
@@ -1,13 +1,13 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  /**
3
- * Convention entry: discover `adapters/dingtalk.ts` → defineAdapter.
3
+ * Convention entry: discover `adapters/dingtalk/index.ts` → defineAdapter.
4
4
  */
5
5
  import { defineAdapter } from 'zhin.js/adapter';
6
6
  import { httpHostToken } from '@zhin.js/host-http';
7
- import { DingTalkEndpoint } from "../lib/endpoint.js";
8
- import { resolveDingTalkConfig, } from "../lib/protocol.js";
9
- import { dingtalkRuntimeStateToken } from "../lib/dingtalk-runtime-state.js";
10
- export { DingTalkEndpoint } from "../lib/endpoint.js";
7
+ import { DingTalkEndpoint } from "../../lib/endpoint.js";
8
+ import { resolveDingTalkConfig, } from "../../lib/protocol.js";
9
+ import { dingtalkRuntimeStateToken } from "../../lib/dingtalk-runtime-state.js";
10
+ export { DingTalkEndpoint } from "../../lib/endpoint.js";
11
11
  export default defineAdapter({
12
12
  capabilities: ['inbound', 'outbound'],
13
13
  // 钉钉机器人媒体消息仅消费远程 URL;Markdown 走原生 msgtype;
@@ -19,7 +19,7 @@ export default defineAdapter({
19
19
  },
20
20
  create(context) {
21
21
  const config = resolveDingTalkConfig(context.config);
22
- // 注册到插件运行时状态(dingtalk.endpoint list 的"运行中"数据源)
22
+ // 注册到插件运行时状态(dingtalk endpoint list 的"运行中"数据源)
23
23
  context.use(dingtalkRuntimeStateToken).endpoints.set(config.id, {
24
24
  id: config.id,
25
25
  mode: 'webhook',
@@ -1,19 +1,19 @@
1
1
  /**
2
- * Convention entry: discover `adapters/dingtalk.ts` → defineAdapter.
2
+ * Convention entry: discover `adapters/dingtalk/index.ts` → defineAdapter.
3
3
  */
4
4
  import { defineAdapter } from 'zhin.js/adapter';
5
5
  import { httpHostToken } from '@zhin.js/host-http';
6
- import { DingTalkEndpoint } from '../src/endpoint.js';
6
+ import { DingTalkEndpoint } from '../../src/endpoint.js';
7
7
  import {
8
8
  resolveDingTalkConfig,
9
- type DingTalkAdapterConfig,
10
- } from '../src/protocol.js';
11
- import { dingtalkRuntimeStateToken } from '../src/dingtalk-runtime-state.js';
9
+ type DingTalkEndpointConfig,
10
+ } from '../../src/protocol.js';
11
+ import { dingtalkRuntimeStateToken } from '../../src/dingtalk-runtime-state.js';
12
12
 
13
- export { DingTalkEndpoint } from '../src/endpoint.js';
14
- export type { DingTalkEndpointOptions, DingTalkFetch } from '../src/endpoint.js';
13
+ export { DingTalkEndpoint } from '../../src/endpoint.js';
14
+ export type { DingTalkEndpointOptions, DingTalkFetch } from '../../src/endpoint.js';
15
15
 
16
- export default defineAdapter<DingTalkAdapterConfig>({
16
+ export default defineAdapter<DingTalkEndpointConfig>({
17
17
  capabilities: ['inbound', 'outbound'],
18
18
  // 钉钉机器人媒体消息仅消费远程 URL;Markdown 走原生 msgtype;
19
19
  // 无按钮交互面,交互段降级纯文本。
@@ -24,7 +24,7 @@ export default defineAdapter<DingTalkAdapterConfig>({
24
24
  },
25
25
  create(context) {
26
26
  const config = resolveDingTalkConfig(context.config);
27
- // 注册到插件运行时状态(dingtalk.endpoint list 的"运行中"数据源)
27
+ // 注册到插件运行时状态(dingtalk endpoint list 的"运行中"数据源)
28
28
  context.use(dingtalkRuntimeStateToken).endpoints.set(config.id, {
29
29
  id: config.id,
30
30
  mode: 'webhook',
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "DINGTALK Platform Agent",
3
+ "version": "1.0.0",
4
+ "description": "Handles dingtalk platform-specific operations and progressively loads only the required platform Skill.",
5
+ "trigger_rules": {
6
+ "file_patterns": [],
7
+ "keywords": [
8
+ "dingtalk",
9
+ "adapter:dingtalk"
10
+ ]
11
+ },
12
+ "entry_points": [
13
+ "system.md",
14
+ "boundaries.md",
15
+ "conventions.md"
16
+ ],
17
+ "platforms": [
18
+ "dingtalk"
19
+ ]
20
+ }
@@ -0,0 +1,3 @@
1
+ # Boundaries
2
+
3
+ Operate only on the active dingtalk 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,26 @@
1
+ ---
2
+ name: dingtalk
3
+ platforms: [dingtalk]
4
+ description: 钉钉组织查询、工作通知和群聊创建维护能力。
5
+ keywords: [dingtalk, 钉钉, 部门, 用户, 工作通知, 群聊]
6
+ tags: [adapter, collaboration]
7
+ tools:
8
+ - get_user
9
+ - get_dept_users
10
+ - list_departments
11
+ - send_work_notice
12
+ - create_chat
13
+ - add_chat_members
14
+ - dept_info
15
+ - update_chat
16
+ ---
17
+
18
+ # 钉钉
19
+
20
+ 用户或部门信息不完整时,先查询再执行写操作:
21
+
22
+ 1. 用 `list_departments` / `dept_info` 确认部门。
23
+ 2. 用 `get_dept_users` / `get_user` 解析稳定的用户 ID。
24
+ 3. 发送工作通知,或创建、更新群聊并添加成员。
25
+
26
+ 不要把昵称直接当作用户 ID。当前 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('要添加的用户 ID 列表,逗号分隔'),
10
+ }),
11
+ adapter: 'dingtalk',
12
+ tags: ['dingtalk'],
13
+ permissions: [platformPermission('dingtalk', 'chat_admin')],
14
+ async execute({ chat_id, user_ids }, context) {
15
+ const endpoint = context.$client;
16
+ const success = await endpoint.updateChat(chat_id, { add_useridlist: 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,7 +10,7 @@ export default defineAgentTool<{ chat_id: string; user_ids: string }>({
10
10
  }),
11
11
  adapter: 'dingtalk',
12
12
  tags: ['dingtalk'],
13
- permissions: [platformPermit('chat_admin')],
13
+ permissions: [platformPermission('dingtalk', '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.updateChat(chat_id, { add_useridlist: user_ids.split(',') });
@@ -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
+ name: z.string().describe('群名'),
9
+ owner: z.string().describe('群主用户 ID'),
10
+ members: z.string().describe('成员用户 ID 列表,逗号分隔'),
11
+ }),
12
+ adapter: 'dingtalk',
13
+ tags: ['dingtalk'],
14
+ permissions: [platformPermission('dingtalk', 'chat_owner')],
15
+ async execute({ name, owner, members }, context) {
16
+ const endpoint = context.$client;
17
+ const chatId = await endpoint.createChat(name, owner, members.split(','));
18
+ return { success: !!chatId, chat_id: chatId, message: chatId ? `群聊创建成功: ${chatId}` : '创建失败' };
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<{ name: string; owner: string; members: string }>({
6
6
  description: '创建钉钉群聊',
@@ -11,7 +11,7 @@ export default defineAgentTool<{ name: string; owner: string; members: string }>
11
11
  }),
12
12
  adapter: 'dingtalk',
13
13
  tags: ['dingtalk'],
14
- permissions: [platformPermit('chat_owner')],
14
+ permissions: [platformPermission('dingtalk', 'chat_owner')],
15
15
  async execute({ name, owner, members }: { name: string; owner: string; members: string }, context) {
16
16
  const endpoint = context.$client;
17
17
  const chatId = await endpoint.createChat(name, owner, members.split(','));
@@ -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
+ dept_id: z.string().describe('部门 ID'),
8
+ }),
9
+ adapter: 'dingtalk',
10
+ tags: ['dingtalk'],
11
+ async execute({ dept_id }, context) {
12
+ const endpoint = context.$client;
13
+ return await endpoint.getDepartmentInfo(Number(dept_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
  export default defineAgentTool<{ dept_id: 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
+ dept_id: z.string().describe('部门 ID'),
8
+ }),
9
+ adapter: 'dingtalk',
10
+ tags: ['dingtalk'],
11
+ async execute({ dept_id }, context) {
12
+ const endpoint = context.$client;
13
+ const users = await endpoint.getDepartmentUsers(Number(dept_id));
14
+ return { users, count: users.length };
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<{ dept_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'),
8
+ }),
9
+ adapter: 'dingtalk',
10
+ tags: ['dingtalk'],
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
  export default defineAgentTool<{ user_id: 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
+ dept_id: z.string().optional().describe('父部门 ID,默认 1(根部门)'),
8
+ }),
9
+ adapter: 'dingtalk',
10
+ tags: ['dingtalk'],
11
+ async execute({ dept_id }, context) {
12
+ const endpoint = context.$client;
13
+ const departments = await endpoint.getDepartmentList(Number(dept_id || '1'));
14
+ return { departments, count: departments.length };
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<{ dept_id?: string }>({
4
4
  description: '获取钉钉部门列表',
@@ -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
+ user_ids: z.string().describe('用户 ID 列表,逗号分隔'),
8
+ content: z.string().describe('通知内容'),
9
+ }),
10
+ adapter: 'dingtalk',
11
+ tags: ['dingtalk'],
12
+ async execute({ user_ids, content }, context) {
13
+ const endpoint = context.$client;
14
+ const msgContent = { msgtype: 'text', text: { content } };
15
+ const success = await endpoint.sendWorkNotice(user_ids.split(','), msgContent);
16
+ return { success, message: success ? '工作通知已发送' : '发送失败' };
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<{ user_ids: string; content: string }>({
4
4
  description: '向指定用户发送钉钉工作通知',
@@ -0,0 +1,29 @@
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
+ name: z.string().optional().describe('新群名(可选)'),
9
+ owner: z.string().optional().describe('新群主 userId(可选)'),
10
+ add_members: z.string().optional().describe('要添加的成员 userId,逗号分隔(可选)'),
11
+ remove_members: z.string().optional().describe('要移除的成员 userId,逗号分隔(可选)'),
12
+ }),
13
+ adapter: 'dingtalk',
14
+ tags: ['dingtalk'],
15
+ async execute({ chat_id, name, owner, add_members, remove_members }, context) {
16
+ const endpoint = context.$client;
17
+ const options = {};
18
+ if (name)
19
+ options.name = name;
20
+ if (owner)
21
+ options.owner = owner;
22
+ if (add_members)
23
+ options.add_useridlist = add_members.split(',').map((s) => s.trim());
24
+ if (remove_members)
25
+ options.del_useridlist = remove_members.split(',').map((s) => s.trim());
26
+ await endpoint.updateChat(chat_id, options);
27
+ return { success: true, message: '群聊设置已更新' };
28
+ },
29
+ });
@@ -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; name?: string; owner?: string; add_members?: string; remove_members?: string }>({
4
4
  description: '更新钉钉群聊设置(改名、换群主、增减成员)',
@@ -0,0 +1,3 @@
1
+ # DINGTALK Platform Agent
2
+
3
+ You are the dingtalk platform specialist. Interpret requests in the current dingtalk 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 { dingtalkEndpointCommands } from "../../../lib/dingtalk-endpoint-commands.js";
2
+ import { dingtalkEndpointCommands } from '../../definition.js';
3
3
  export default dingtalkEndpointCommands.add;
@@ -0,0 +1,3 @@
1
+ import { dingtalkEndpointCommands } from '../../definition.js';
2
+
3
+ export default dingtalkEndpointCommands.add;
@@ -1,10 +1,11 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
1
2
  /**
2
- * `dingtalk.endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
3
- * commands/endpoint/ 下的 list / add / remove 直接默认导出这三项。
3
+ * `dingtalk endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
4
+ * commands/dingtalk/endpoint/ 下的 list / add / remove 直接默认导出这三项。
4
5
  */
5
6
  import { createEndpointCommands } from 'zhin.js/adapter';
6
7
  import { defineCommand } from 'zhin.js/command';
7
- import { dingtalkRuntimeStateToken } from './dingtalk-runtime-state.js';
8
+ import { dingtalkRuntimeStateToken } from "../../../lib/dingtalk-runtime-state.js";
8
9
  export const dingtalkEndpointCommands = createEndpointCommands({
9
10
  adapterKey: 'dingtalk',
10
11
  adapterDisplayName: 'DingTalk',
@@ -1,10 +1,10 @@
1
1
  /**
2
- * `dingtalk.endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
3
- * commands/endpoint/ 下的 list / add / remove 直接默认导出这三项。
2
+ * `dingtalk endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
3
+ * commands/dingtalk/endpoint/ 下的 list / add / remove 直接默认导出这三项。
4
4
  */
5
5
  import { createEndpointCommands } from 'zhin.js/adapter';
6
6
  import { defineCommand } from 'zhin.js/command';
7
- import { dingtalkRuntimeStateToken } from './dingtalk-runtime-state.js';
7
+ import { dingtalkRuntimeStateToken } from '../../../src/dingtalk-runtime-state.js';
8
8
 
9
9
  export const dingtalkEndpointCommands = createEndpointCommands({
10
10
  adapterKey: 'dingtalk',
@@ -1,3 +1,3 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
- import { dingtalkEndpointCommands } from "../../lib/dingtalk-endpoint-commands.js";
2
+ import { dingtalkEndpointCommands } from '../definition.js';
3
3
  export default dingtalkEndpointCommands.list;
@@ -0,0 +1,3 @@
1
+ import { dingtalkEndpointCommands } from '../definition.js';
2
+
3
+ export default dingtalkEndpointCommands.list;
@@ -1,3 +1,3 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
- import { dingtalkEndpointCommands } from "../../../lib/dingtalk-endpoint-commands.js";
2
+ import { dingtalkEndpointCommands } from '../../definition.js';
3
3
  export default dingtalkEndpointCommands.remove;
@@ -0,0 +1,3 @@
1
+ import { dingtalkEndpointCommands } from '../../definition.js';
2
+
3
+ export default dingtalkEndpointCommands.remove;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * DingTalk 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
3
- * 由 plugin.ts setup() provide,adapter create 与 `dingtalk.endpoint` 命令共享(同一 owner generation)。
3
+ * 由 plugin.ts setup() provide,adapter create 与 `dingtalk endpoint` 命令共享(同一 owner generation)。
4
4
  */
5
5
  import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
6
6
  export const dingtalkRuntimeStateToken = defineEndpointRuntimeStateToken('dingtalk');
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { dingtalkInboundConversation, formatInboundContent, formatOutboundBody, generateMessageId, headerValue, normalizeWebhookPath, readTextBody, resolveChatType, resolveDingTalkConfig, resolveSender, verifySignature, type AccessToken, type DingTalkAdapterConfig, type DingTalkApiResponse, type DingTalkEvent, type DingTalkMessage, type DingTalkSendBody, type DingTalkWireSegment, type ResolvedDingTalkConfig, } from './protocol.js';
1
+ export { dingtalkInboundConversation, formatInboundContent, formatOutboundBody, generateMessageId, headerValue, normalizeWebhookPath, readTextBody, resolveChatType, resolveDingTalkConfig, resolveSender, verifySignature, type AccessToken, type DingTalkEndpointConfig, type DingTalkApiResponse, type DingTalkEvent, type DingTalkMessage, type DingTalkSendBody, type DingTalkWireSegment, type ResolvedDingTalkConfig, } from './protocol.js';
2
2
  export { DingTalkClient, DingTalkEndpoint, type DingTalkClientApi, type DingTalkEndpointOptions, type DingTalkFetch, } from './endpoint.js';
3
3
  export { registerDingTalkWebhookRoutes, handleDingTalkWebhookRequest, type DingTalkWebhookHandler, } from './webhook.js';
4
4
  export { dingtalkClient, type DingtalkClientEventMap } from './client.js';
package/lib/protocol.d.ts CHANGED
@@ -3,19 +3,15 @@
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 DingTalkAdapterConfig {
9
- readonly id?: string;
10
- readonly appKey?: 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 DingTalkEndpointConfig {
9
+ readonly id: string;
10
+ readonly appKey: string;
11
+ readonly appSecret: string;
12
12
  readonly webhookPath?: string;
13
13
  readonly robotCode?: string;
14
14
  readonly apiBaseUrl?: string;
15
- /** Transitional: legacy root `endpoints[]` with `context: dingtalk`. */
16
- readonly endpoints?: ReadonlyArray<Partial<ResolvedDingTalkConfig> & {
17
- readonly context?: string;
18
- }>;
19
15
  }
20
16
  export interface ResolvedDingTalkConfig {
21
17
  readonly context: 'dingtalk';
@@ -102,7 +98,7 @@ export interface DingTalkSendBody {
102
98
  };
103
99
  readonly robotCode?: string;
104
100
  }
105
- export declare function resolveDingTalkConfig(config?: DingTalkAdapterConfig): ResolvedDingTalkConfig;
101
+ export declare function resolveDingTalkConfig(config: DingTalkEndpointConfig): ResolvedDingTalkConfig;
106
102
  export declare function normalizeWebhookPath(path: string): string;
107
103
  export declare function resolveChatType(conversationType?: string): 'group' | 'private';
108
104
  /**
package/lib/protocol.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * Canonicalization is owned by gateway/core before endpoint.send.
4
4
  */
5
5
  import { createHmac, 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('dingtalk');
9
9
  /**
@@ -22,20 +22,13 @@ export function isDingtalkBotMentioned(event, robotCode) {
22
22
  }
23
23
  return (event.atUsers ?? []).some((user) => user.dingtalkId === robotCode);
24
24
  }
25
- export function resolveDingTalkConfig(config = {}) {
26
- const entry = config.endpoints?.find((item) => item.context === 'dingtalk');
27
- const appKey = config.appKey ?? entry?.appKey ?? process.env.DINGTALK_APP_KEY;
28
- const appSecret = config.appSecret ?? entry?.appSecret ?? process.env.DINGTALK_APP_SECRET;
29
- if (!appKey || !appSecret) {
30
- throw new TypeError('DingTalk adapter requires appKey + appSecret (plugins.<key> or endpoints with context: dingtalk)');
31
- }
32
- const id = (typeof config.id === 'string' && config.id)
33
- || (typeof entry?.id === 'string' && entry.id)
34
- || process.env.DINGTALK_BOT_NAME
35
- || 'dingtalk-bot';
36
- const webhookPath = normalizeWebhookPath(config.webhookPath ?? entry?.webhookPath ?? '/dingtalk/webhook');
37
- const apiBaseUrl = (config.apiBaseUrl ?? entry?.apiBaseUrl ?? 'https://oapi.dingtalk.com').replace(/\/$/, '');
38
- const robotCode = config.robotCode ?? entry?.robotCode;
25
+ export function resolveDingTalkConfig(config) {
26
+ const id = requiredEndpointField(config.id, 'id');
27
+ const appKey = requiredEndpointField(config.appKey, 'appKey');
28
+ const appSecret = requiredEndpointField(config.appSecret, 'appSecret');
29
+ const webhookPath = normalizeWebhookPath(config.webhookPath ?? '/dingtalk/webhook');
30
+ const apiBaseUrl = (config.apiBaseUrl ?? 'https://oapi.dingtalk.com').replace(/\/$/, '');
31
+ const robotCode = config.robotCode;
39
32
  return {
40
33
  context: 'dingtalk',
41
34
  id,
@@ -46,6 +39,12 @@ export function resolveDingTalkConfig(config = {}) {
46
39
  apiBaseUrl,
47
40
  };
48
41
  }
42
+ function requiredEndpointField(value, field) {
43
+ if (typeof value !== 'string' || !value.trim()) {
44
+ throw new TypeError(`DingTalk endpoint requires a non-empty ${field}`);
45
+ }
46
+ return value.trim();
47
+ }
49
48
  export function normalizeWebhookPath(path) {
50
49
  const trimmed = path.trim() || '/dingtalk/webhook';
51
50
  return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-dingtalk",
3
- "version": "1.1.0",
3
+ "version": "1.1.3",
4
4
  "description": "Zhin.js DingTalk (钉钉) adapter for Plugin Runtime (HTTP webhook)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -33,27 +33,26 @@
33
33
  "directory": "plugins/adapters/dingtalk"
34
34
  },
35
35
  "dependencies": {
36
- "@zhin.js/adapter": "1.1.12",
37
- "@zhin.js/core": "1.1.35",
38
- "@zhin.js/feature-kit": "1.1.0",
39
- "@zhin.js/host-http": "1.1.0",
40
- "@zhin.js/im-contract": "1.1.0",
41
- "@zhin.js/logger": "1.1.0"
36
+ "@zhin.js/adapter": "1.1.15",
37
+ "@zhin.js/agent-feature": "1.1.2",
38
+ "@zhin.js/core": "1.1.38",
39
+ "@zhin.js/feature-kit": "1.1.2",
40
+ "@zhin.js/host-http": "1.1.2",
41
+ "@zhin.js/im-contract": "1.1.2",
42
+ "@zhin.js/logger": "1.1.1",
43
+ "@zhin.js/skill": "1.1.2",
44
+ "@zhin.js/tool": "1.1.2"
42
45
  },
43
46
  "peerDependencies": {
44
47
  "zod": "^4.0.0",
45
- "@zhin.js/adapter": "^1.1.12",
46
- "@zhin.js/agent": "^1.1.23",
47
- "@zhin.js/command": "^1.1.0",
48
- "@zhin.js/core": "^1.1.35",
49
- "@zhin.js/host-http": "^1.1.0",
50
- "@zhin.js/permission": "^1.1.0",
51
- "zhin.js": "^1.1.0"
48
+ "@zhin.js/adapter": "^1.1.15",
49
+ "@zhin.js/command": "^1.1.2",
50
+ "@zhin.js/core": "^1.1.38",
51
+ "@zhin.js/host-http": "^1.1.2",
52
+ "@zhin.js/permission": "^1.1.2",
53
+ "zhin.js": "^1.1.3"
52
54
  },
53
55
  "peerDependenciesMeta": {
54
- "@zhin.js/agent": {
55
- "optional": true
56
- },
57
56
  "@zhin.js/command": {
58
57
  "optional": true
59
58
  },
@@ -69,8 +68,7 @@
69
68
  "typescript": "^6.0.3",
70
69
  "vitest": "^4.1.10",
71
70
  "zod": "^4.4.3",
72
- "@zhin.js/agent": "1.1.23",
73
- "zhin.js": "1.1.0"
71
+ "zhin.js": "1.1.3"
74
72
  },
75
73
  "files": [
76
74
  "adapters",
@@ -79,9 +77,10 @@
79
77
  "schema.json",
80
78
  "src",
81
79
  "lib",
82
- "agent",
80
+ "agents",
83
81
  "README.md",
84
- "CHANGELOG.md"
82
+ "CHANGELOG.md",
83
+ "PERMITS.md"
85
84
  ],
86
85
  "publishConfig": {
87
86
  "access": "public",
@@ -104,6 +103,18 @@
104
103
  {
105
104
  "package": "@zhin.js/command",
106
105
  "api": "^1.0.0"
106
+ },
107
+ {
108
+ "package": "@zhin.js/tool",
109
+ "api": "^1.0.0"
110
+ },
111
+ {
112
+ "package": "@zhin.js/skill",
113
+ "api": "^1.0.0"
114
+ },
115
+ {
116
+ "package": "@zhin.js/agent-feature",
117
+ "api": "^1.0.0"
107
118
  }
108
119
  ],
109
120
  "plugins": []
package/schema.json CHANGED
@@ -27,10 +27,11 @@
27
27
  },
28
28
  "endpoints": {
29
29
  "type": "array",
30
+ "minItems": 1,
30
31
  "description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(id 必填,其余覆盖顶层)",
31
32
  "items": {
32
33
  "type": "object",
33
- "additionalProperties": true,
34
+ "additionalProperties": false,
34
35
  "properties": {
35
36
  "master": {
36
37
  "type": [
@@ -66,6 +67,12 @@
66
67
  "type": "string",
67
68
  "description": "Dingtalk robot code"
68
69
  },
70
+ "apiBaseUrl": {
71
+ "type": "string"
72
+ },
73
+ "commandPrefix": {
74
+ "type": "string"
75
+ },
69
76
  "id": {
70
77
  "type": "string",
71
78
  "description": "Dingtalk bot name"
@@ -74,9 +81,7 @@
74
81
  "required": [
75
82
  "id",
76
83
  "appKey",
77
- "appSecret",
78
- "webhookPath",
79
- "robotCode"
84
+ "appSecret"
80
85
  ]
81
86
  }
82
87
  },
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * DingTalk 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
3
- * 由 plugin.ts setup() provide,adapter create 与 `dingtalk.endpoint` 命令共享(同一 owner generation)。
3
+ * 由 plugin.ts setup() provide,adapter create 与 `dingtalk endpoint` 命令共享(同一 owner generation)。
4
4
  */
5
5
  import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
6
6
 
package/src/index.ts CHANGED
@@ -11,7 +11,7 @@ export {
11
11
  resolveSender,
12
12
  verifySignature,
13
13
  type AccessToken,
14
- type DingTalkAdapterConfig,
14
+ type DingTalkEndpointConfig,
15
15
  type DingTalkApiResponse,
16
16
  type DingTalkEvent,
17
17
  type DingTalkMessage,
package/src/protocol.ts CHANGED
@@ -6,24 +6,19 @@
6
6
  import { createHmac, timingSafeEqual } from 'node:crypto';
7
7
  import type { IncomingMessage } from 'node:http';
8
8
 
9
- import { isMediaRef } from '@zhin.js/core';
10
- import type { ConversationRef } from '@zhin.js/im-contract';
9
+ import { isMediaRef, type ConversationRef } from '@zhin.js/im-contract';
11
10
  import { formatCompact, getLogger } from '@zhin.js/logger';
12
11
 
13
12
  const logger = getLogger('dingtalk');
14
13
 
15
- /** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
16
- export interface DingTalkAdapterConfig {
17
- readonly id?: string;
18
- readonly appKey?: string;
19
- readonly appSecret?: string;
14
+ /** One endpoint config after AdapterIndex expands `plugins.<instanceKey>.endpoints`. */
15
+ export interface DingTalkEndpointConfig {
16
+ readonly id: string;
17
+ readonly appKey: string;
18
+ readonly appSecret: string;
20
19
  readonly webhookPath?: string;
21
20
  readonly robotCode?: string;
22
21
  readonly apiBaseUrl?: string;
23
- /** Transitional: legacy root `endpoints[]` with `context: dingtalk`. */
24
- readonly endpoints?: ReadonlyArray<Partial<ResolvedDingTalkConfig> & {
25
- readonly context?: string;
26
- }>;
27
22
  }
28
23
 
29
24
  export interface ResolvedDingTalkConfig {
@@ -115,26 +110,13 @@ export interface DingTalkSendBody {
115
110
  readonly robotCode?: string;
116
111
  }
117
112
 
118
- export function resolveDingTalkConfig(config: DingTalkAdapterConfig = {}): ResolvedDingTalkConfig {
119
- const entry = config.endpoints?.find((item) => item.context === 'dingtalk');
120
- const appKey = config.appKey ?? entry?.appKey ?? process.env.DINGTALK_APP_KEY;
121
- const appSecret = config.appSecret ?? entry?.appSecret ?? process.env.DINGTALK_APP_SECRET;
122
- if (!appKey || !appSecret) {
123
- throw new TypeError(
124
- 'DingTalk adapter requires appKey + appSecret (plugins.<key> or endpoints with context: dingtalk)',
125
- );
126
- }
127
- const id = (typeof config.id === 'string' && config.id)
128
- || (typeof entry?.id === 'string' && entry.id)
129
- || process.env.DINGTALK_BOT_NAME
130
- || 'dingtalk-bot';
131
- const webhookPath = normalizeWebhookPath(
132
- config.webhookPath ?? entry?.webhookPath ?? '/dingtalk/webhook',
133
- );
134
- const apiBaseUrl = (
135
- config.apiBaseUrl ?? entry?.apiBaseUrl ?? 'https://oapi.dingtalk.com'
136
- ).replace(/\/$/, '');
137
- const robotCode = config.robotCode ?? entry?.robotCode;
113
+ export function resolveDingTalkConfig(config: DingTalkEndpointConfig): ResolvedDingTalkConfig {
114
+ const id = requiredEndpointField(config.id, 'id');
115
+ const appKey = requiredEndpointField(config.appKey, 'appKey');
116
+ const appSecret = requiredEndpointField(config.appSecret, 'appSecret');
117
+ const webhookPath = normalizeWebhookPath(config.webhookPath ?? '/dingtalk/webhook');
118
+ const apiBaseUrl = (config.apiBaseUrl ?? 'https://oapi.dingtalk.com').replace(/\/$/, '');
119
+ const robotCode = config.robotCode;
138
120
  return {
139
121
  context: 'dingtalk',
140
122
  id,
@@ -146,6 +128,16 @@ export function resolveDingTalkConfig(config: DingTalkAdapterConfig = {}): Resol
146
128
  };
147
129
  }
148
130
 
131
+ function requiredEndpointField(
132
+ value: unknown,
133
+ field: 'id' | 'appKey' | 'appSecret',
134
+ ): string {
135
+ if (typeof value !== 'string' || !value.trim()) {
136
+ throw new TypeError(`DingTalk endpoint requires a non-empty ${field}`);
137
+ }
138
+ return value.trim();
139
+ }
140
+
149
141
  export function normalizeWebhookPath(path: string): string {
150
142
  const trimmed = path.trim() || '/dingtalk/webhook';
151
143
  return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
@@ -1,91 +0,0 @@
1
- ---
2
- name: dingtalk
3
- platforms:
4
- - dingtalk
5
- description: >-
6
- 钉钉平台管理能力。当用户在钉钉中请求群管理(踢人、改群名、查群信息)、
7
- 组织架构查询(部门/用户查询)、发送工作通知、创建或管理群聊时使用。
8
- 即使用户没有提到钉钉,只要上下文是钉钉/DingTalk 场景且涉及群管理、
9
- 组织架构或工作通知,就应触发。仅有昵称时先查部门用户列表获取 user_id。
10
- keywords:
11
- - dingtalk
12
- - 钉钉
13
- - adapter:dingtalk
14
- - 群管理
15
- - 部门
16
- - 工作通知
17
- - 组织架构
18
- - 企业
19
- - list_members
20
- tags:
21
- - group
22
- - management
23
- - im
24
- - enterprise
25
- tools:
26
- - dingtalk_get_user
27
- - dingtalk_get_dept_users
28
- - dingtalk_list_departments
29
- - dingtalk_send_work_notice
30
- - dingtalk_create_chat
31
- - dingtalk_add_chat_members
32
- - dingtalk_dept_info
33
- - dingtalk_update_chat
34
- - dingtalk_kick_member
35
- - dingtalk_set_group_name
36
- - dingtalk_get_group_info
37
- ---
38
-
39
- # 钉钉群聊与组织管理技能
40
-
41
- 钉钉是企业 IM 平台,特有组织架构(部门树)和工作通知能力,区别于个人社交类 IM。
42
-
43
- ## 核心原则
44
-
45
- ### 组织架构是核心
46
-
47
- 钉钉的用户隶属于部门树,很多操作需要从组织架构出发:
48
- ```
49
- dingtalk_list_departments → 获取部门列表(根部门 ID=1)
50
- dingtalk_get_dept_users(dept_id) → 获取部门下的用户列表
51
- dingtalk_get_user(user_id) → 获取用户详情
52
- ```
53
-
54
- ### 工作通知 ≠ 群消息
55
-
56
- `dingtalk_send_work_notice` 是直接发给个人的企业通知,出现在钉钉的「工作通知」入口,不需要群聊。用户说「通知一下张三」,如果是正式的企业通知,用 `send_work_notice`;如果只是聊天消息,用普通消息发送。
57
-
58
- ## 工具分类
59
-
60
- ### 群聊管理
61
-
62
- | 工具 | 用途 | 说明 |
63
- |------|------|------|
64
- | `dingtalk_kick_member` | 踢出成员 | — |
65
- | `dingtalk_set_group_name` | 改群名 | — |
66
- | `dingtalk_get_group_info` | 群信息 | — |
67
- | `dingtalk_create_chat` | 创建群聊 | 需群主 userId + 至少一个成员 |
68
- | `dingtalk_add_chat_members` | 添加成员 | — |
69
- | `dingtalk_update_chat` | 更新群设置 | 改名、换群主、增减成员 |
70
-
71
- ### 组织架构
72
-
73
- | 工具 | 用途 | 说明 |
74
- |------|------|------|
75
- | `dingtalk_list_departments` | 部门列表 | 默认从根部门 ID=1 开始 |
76
- | `dingtalk_dept_info` | 部门详情 | — |
77
- | `dingtalk_get_dept_users` | 部门用户列表 | — |
78
- | `dingtalk_get_user` | 用户详情 | — |
79
-
80
- ### 通知
81
-
82
- | 工具 | 用途 | 说明 |
83
- |------|------|------|
84
- | `dingtalk_send_work_notice` | 工作通知 | 发给指定用户列表,不需要群 |
85
-
86
- ## 易错点
87
-
88
- 1. **部门查询从根部门 ID=1 开始**。不知道部门 ID 时先 `list_departments` 获取整棵部门树。
89
- 2. **群聊创建需要群主 userId 和至少一个成员**,不能创建空群。
90
- 3. **工作通知是独立于群聊的**,它发到个人的钉钉「工作通知」入口,不要与群消息混淆。
91
- 4. **操作成员需要钉钉 userId**,仅有昵称时先通过 `get_dept_users` 或 `get_group_info` 查找。
@@ -1,3 +0,0 @@
1
- import { dingtalkEndpointCommands } from '../../../src/dingtalk-endpoint-commands.js';
2
-
3
- export default dingtalkEndpointCommands.add;
@@ -1,3 +0,0 @@
1
- import { dingtalkEndpointCommands } from '../../src/dingtalk-endpoint-commands.js';
2
-
3
- export default dingtalkEndpointCommands.list;
@@ -1,3 +0,0 @@
1
- import { dingtalkEndpointCommands } from '../../../src/dingtalk-endpoint-commands.js';
2
-
3
- export default dingtalkEndpointCommands.remove;
@@ -1 +0,0 @@
1
- export declare const dingtalkEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage, string | undefined>>>;
File without changes