@zhin.js/adapter-wecom 0.0.1 → 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.
- package/CHANGELOG.md +716 -0
- package/{skills/wecom/PERMITS.md → PERMITS.md} +1 -1
- package/README.md +83 -215
- package/adapters/wecom/index.js +34 -0
- package/adapters/wecom/index.ts +39 -0
- package/agents/wecom/agent.json +20 -0
- package/agents/wecom/boundaries.md +3 -0
- package/agents/wecom/conventions.md +3 -0
- package/{skills → agents/wecom/skills}/wecom/SKILL.md +4 -4
- package/agents/wecom/skills/wecom/tools/get_dept_users/index.js +16 -0
- package/agents/wecom/skills/wecom/tools/get_dept_users/index.ts +16 -0
- package/agents/wecom/skills/wecom/tools/get_user/index.js +15 -0
- package/agents/wecom/skills/wecom/tools/get_user/index.ts +15 -0
- package/agents/wecom/skills/wecom/tools/list_departments/index.js +16 -0
- package/agents/wecom/skills/wecom/tools/list_departments/index.ts +16 -0
- package/agents/wecom/skills/wecom/tools/send_text/index.js +17 -0
- package/agents/wecom/skills/wecom/tools/send_text/index.ts +17 -0
- package/agents/wecom/system.md +3 -0
- package/commands/wecom/endpoint/add/[id]/index.js +3 -0
- package/commands/wecom/endpoint/add/[id]/index.ts +3 -0
- package/commands/wecom/endpoint/definition.js +20 -0
- package/commands/wecom/endpoint/definition.ts +20 -0
- package/commands/wecom/endpoint/list/index.js +3 -0
- package/commands/wecom/endpoint/list/index.ts +3 -0
- package/commands/wecom/endpoint/remove/[id]/index.js +3 -0
- package/commands/wecom/endpoint/remove/[id]/index.ts +3 -0
- package/lib/client.d.ts +12 -0
- package/lib/client.js +2 -0
- package/lib/endpoint.d.ts +55 -37
- package/lib/endpoint.js +247 -516
- package/lib/index.d.ts +6 -15
- package/lib/index.js +6 -115
- package/lib/media-upload.d.ts +23 -0
- package/lib/media-upload.js +58 -0
- package/lib/platform-permit.d.ts +2 -4
- package/lib/platform-permit.js +5 -11
- package/lib/protocol.d.ts +98 -0
- package/lib/protocol.js +267 -0
- package/lib/side-event-dispatch.d.ts +4 -0
- package/lib/side-event-dispatch.js +63 -0
- package/lib/webhook.d.ts +14 -0
- package/lib/webhook.js +86 -0
- package/lib/wecom-runtime-state.d.ts +1 -0
- package/lib/wecom-runtime-state.js +6 -0
- package/package.json +77 -17
- package/plugin.js +19 -0
- package/schema.json +106 -0
- package/src/client.ts +16 -0
- package/src/endpoint.ts +311 -559
- package/src/index.ts +52 -131
- package/src/media-upload.ts +79 -0
- package/src/platform-permit.ts +6 -11
- package/src/protocol.ts +377 -0
- package/src/side-event-dispatch.ts +70 -0
- package/src/webhook.ts +130 -0
- package/src/wecom-runtime-state.ts +7 -0
- package/lib/adapter.d.ts +0 -15
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js +0 -20
- package/lib/adapter.js.map +0 -1
- package/lib/endpoint.d.ts.map +0 -1
- package/lib/endpoint.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/platform-permit.d.ts.map +0 -1
- package/lib/platform-permit.js.map +0 -1
- package/lib/types.d.ts +0 -48
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js +0 -5
- package/lib/types.js.map +0 -1
- package/plugin.yml +0 -3
- package/src/adapter.ts +0 -26
- package/src/types.ts +0 -51
package/README.md
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
# @zhin.js/adapter-wecom
|
|
2
2
|
|
|
3
|
-
Zhin.js 企业微信(WeCom
|
|
3
|
+
Zhin.js 企业微信(WeCom)适配器(Plugin Runtime),通过 Runtime Host HTTP Webhook 收发消息。
|
|
4
|
+
|
|
5
|
+
## 功能
|
|
6
|
+
|
|
7
|
+
- Webhook 事件接收(`httpHostToken` GET 验签解密 + POST 消息)
|
|
8
|
+
- AES-256-CBC 消息加解密与 SHA1 签名验证
|
|
9
|
+
- Access Token 自动刷新
|
|
10
|
+
- 约定式 `defineAdapter` / `definePlugin`(无需 `usePlugin`)
|
|
4
11
|
|
|
5
12
|
## 安装
|
|
6
13
|
|
|
@@ -8,255 +15,116 @@ Zhin.js 企业微信(WeCom)适配器,支持企业内部应用机器人开
|
|
|
8
15
|
pnpm add @zhin.js/adapter-wecom
|
|
9
16
|
```
|
|
10
17
|
|
|
11
|
-
##
|
|
18
|
+
## Plugin Runtime
|
|
12
19
|
|
|
13
|
-
|
|
20
|
+
- `@zhin.js/adapter` — 约定式 `adapters/wecom/index.ts`(`defineAdapter`)
|
|
21
|
+
- `@zhin.js/core` — `Endpoint.emit(...)` 入站、`outboundMessageToken` 出站
|
|
22
|
+
- `@zhin.js/host-http` — `httpHostToken` 注册 Webhook 路由(**非** legacy host-router/Koa)
|
|
23
|
+
- `zhin.js` — `plugin.ts`(`definePlugin`)
|
|
24
|
+
- 配置经插件 `schema.json` 落到 `plugins.<instanceKey>`
|
|
14
25
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- 使用管理员账号登录
|
|
26
|
+
入站:`gateway.receive({ conversation, message: { conversation, id: MsgId }, content: text, sender, metadata })`(`conversation` 为 `ConversationRef`,`@chatroom` → kind `group`,其余 → kind `private`)
|
|
27
|
+
出站:`send({ conversation, payload })` → 企业微信 `message/send` API
|
|
18
28
|
|
|
19
|
-
|
|
20
|
-
- 进入「应用管理」→「自建」
|
|
21
|
-
- 点击「创建应用」
|
|
22
|
-
- 填写应用名称、上传 Logo、选择可见范围
|
|
29
|
+
入站 `metadata.mentioned`:**未接线**。企业微信应用消息回调的 XML 事件不含 mentions/@ 字段,回调里的 `ToUserName` 是 CorpID(企业 ID)而非可比较的 bot 用户 id,配置中也没有 bot id/name 可作可靠判据,故无法可靠识别 @ 机器人。
|
|
23
30
|
|
|
24
|
-
|
|
25
|
-
- 在应用详情页面获取:
|
|
26
|
-
- **CorpId**(企业 ID):在「我的企业」→「企业信息」中查看
|
|
27
|
-
- **AgentId**(应用 AgentId):在应用详情页面
|
|
28
|
-
- **Secret**(应用 Secret):在应用详情页面
|
|
31
|
+
## 前置条件
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
- 在应用详情页面,进入「接收消息」设置
|
|
32
|
-
- 设置 **URL**:`https://yourdomain.com/wecom/callback`
|
|
33
|
-
- 设置 **Token**:自定义字符串(用于签名验证)
|
|
34
|
-
- 设置 **EncodingAESKey**:点击「随机获取」(用于消息加解密)
|
|
35
|
-
- 点击「保存」,企业微信会发送验证请求
|
|
33
|
+
### 企业微信管理后台配置
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
1. 登录 [企业微信管理后台](https://work.weixin.qq.com/wework_admin/frame)
|
|
36
|
+
2. 「应用管理」→「自建」→ 创建应用,获取 **CorpId**、**AgentId**、**Secret**
|
|
37
|
+
3. 「接收消息」设置:
|
|
38
|
+
- **URL**:`https://yourdomain.com/wecom/callback`
|
|
39
|
+
- **Token** / **EncodingAESKey** 与配置一致
|
|
40
|
+
4. Runtime Host(`http`)须已 listen,Webhook 才可达
|
|
42
41
|
|
|
43
|
-
|
|
42
|
+
必填字段(`endpoints[i]`):`id`、`corpId`、`agentSecret`、`token`、`encodingAESKey`。
|
|
43
|
+
运行时由 AdapterIndex 把实例级默认值与每个 endpoint 合并;协议实现只接收一份展开后的
|
|
44
|
+
endpoint 配置。
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
## 最小配置
|
|
46
47
|
|
|
47
48
|
```yaml
|
|
48
|
-
|
|
49
|
-
- name: wecom-bot
|
|
50
|
-
context: wecom
|
|
51
|
-
corpId: "ww1234567890abcdef"
|
|
52
|
-
agentSecret: "your-agent-secret"
|
|
53
|
-
token: "your-verify-token"
|
|
54
|
-
encodingAESKey: "your-43-char-encoding-aes-key"
|
|
55
|
-
webhookPath: "/wecom/callback"
|
|
56
|
-
|
|
49
|
+
# zhin.config.yml(Plugin Runtime)
|
|
57
50
|
plugins:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
context: wecom
|
|
68
|
-
corpId: "ww1234567890abcdef"
|
|
69
|
-
agentSecret: "your-agent-secret"
|
|
70
|
-
token: "your-verify-token"
|
|
71
|
-
encodingAESKey: "your-43-char-encoding-aes-key"
|
|
72
|
-
webhookPath: "/wecom/callback"
|
|
73
|
-
apiBaseUrl: "https://qyapi.weixin.qq.com" # 可选,默认值
|
|
51
|
+
wecom:
|
|
52
|
+
webhookPath: /wecom/callback # 可选,默认 /wecom/callback
|
|
53
|
+
apiBaseUrl: https://qyapi.weixin.qq.com # 可选
|
|
54
|
+
endpoints:
|
|
55
|
+
- id: wecom-bot
|
|
56
|
+
corpId: ${WECOM_CORP_ID}
|
|
57
|
+
agentSecret: ${WECOM_AGENT_SECRET}
|
|
58
|
+
token: ${WECOM_TOKEN}
|
|
59
|
+
encodingAESKey: ${WECOM_AES_KEY}
|
|
74
60
|
```
|
|
75
61
|
|
|
76
|
-
|
|
62
|
+
根插件 `zhin.plugins`(或项目图)需引用 `@zhin.js/adapter-wecom`(`instanceKey: wecom`)。
|
|
77
63
|
|
|
78
|
-
|
|
79
|
-
|------|------|------|
|
|
80
|
-
| `corpId` | 是 | 企业 ID,在管理后台「我的企业」查看 |
|
|
81
|
-
| `agentSecret` | 是 | 应用 Secret,在应用详情页获取 |
|
|
82
|
-
| `token` | 是 | 用于签名验证,需与管理后台「接收消息」设置中的 Token 一致 |
|
|
83
|
-
| `encodingAESKey` | 是 | 用于消息加解密,需与管理后台一致(43 字符) |
|
|
84
|
-
| `webhookPath` | 否 | Webhook 回调路径,默认 `/wecom/callback` |
|
|
85
|
-
| `apiBaseUrl` | 否 | 企业微信 API 地址,默认 `https://qyapi.weixin.qq.com` |
|
|
64
|
+
## 环境变量
|
|
86
65
|
|
|
87
|
-
|
|
66
|
+
环境变量通过 `zhin.config.yml` 的 `${...}` 引用解析;适配器协议层不会直接读取它们。
|
|
88
67
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
token: "${WECOM_TOKEN}"
|
|
96
|
-
encodingAESKey: "${WECOM_AES_KEY}"
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## 使用示例
|
|
100
|
-
|
|
101
|
-
### 接收和发送消息
|
|
102
|
-
|
|
103
|
-
```typescript
|
|
104
|
-
import { usePlugin, MessageCommand } from 'zhin.js'
|
|
105
|
-
|
|
106
|
-
const { addCommand, logger } = usePlugin()
|
|
107
|
-
|
|
108
|
-
// 定义命令
|
|
109
|
-
addCommand(new MessageCommand('hello <name:text>')
|
|
110
|
-
.action(async (message, result) => {
|
|
111
|
-
logger.info(`收到问候: ${result.params.name}`)
|
|
112
|
-
return `你好,${result.params.name}!欢迎使用企业微信机器人。`
|
|
113
|
-
})
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
// 监听所有消息
|
|
117
|
-
import { onMessage } from 'zhin.js'
|
|
118
|
-
|
|
119
|
-
onMessage(async (message) => {
|
|
120
|
-
logger.info(`收到消息:${JSON.stringify(message.$content)}`)
|
|
121
|
-
logger.info(`发送者:${message.$sender.name}`)
|
|
122
|
-
logger.info(`会话类型:${message.$channel.type}`)
|
|
123
|
-
})
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### 发送富文本消息
|
|
127
|
-
|
|
128
|
-
```typescript
|
|
129
|
-
addCommand(new MessageCommand('info')
|
|
130
|
-
.action(async (message) => {
|
|
131
|
-
return [
|
|
132
|
-
{
|
|
133
|
-
type: 'markdown',
|
|
134
|
-
data: {
|
|
135
|
-
content: `# 系统信息\n\n- 服务器: 运行正常\n- 版本: v1.0.0\n- 状态: 在线`
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
]
|
|
139
|
-
})
|
|
140
|
-
)
|
|
141
|
-
```
|
|
68
|
+
| 变量 | 说明 |
|
|
69
|
+
|------|------|
|
|
70
|
+
| `WECOM_CORP_ID` | 企业 ID |
|
|
71
|
+
| `WECOM_AGENT_SECRET` | 应用 Secret |
|
|
72
|
+
| `WECOM_TOKEN` | 回调签名 Token |
|
|
73
|
+
| `WECOM_AES_KEY` | EncodingAESKey(43 字符) |
|
|
142
74
|
|
|
143
75
|
## 消息类型支持
|
|
144
76
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
|
148
|
-
|
|
149
|
-
|
|
|
150
|
-
|
|
|
151
|
-
|
|
|
152
|
-
|
|
|
153
|
-
|
|
|
154
|
-
|
|
155
|
-
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
|
160
|
-
|
|
161
|
-
| 文本消息 | 支持 | 支持 @ 提醒 |
|
|
162
|
-
| 图片消息 | 支持 | 需要 media_id |
|
|
163
|
-
| Markdown 消息 | 支持 | 企业微信原生 Markdown |
|
|
164
|
-
| 图文消息 | 支持 | news 类型 |
|
|
165
|
-
| 撤回消息 | 不支持 | 企业微信机器人不支持撤回 |
|
|
77
|
+
| 入站类型 | content 摘要 |
|
|
78
|
+
|----------|--------------|
|
|
79
|
+
| text | 原文 |
|
|
80
|
+
| image | `[image: url]` |
|
|
81
|
+
| voice | 识别结果或 `[voice]` |
|
|
82
|
+
| video / shortvideo | `[video]` |
|
|
83
|
+
| location | `[位置] …` |
|
|
84
|
+
| link | `[link: …]` |
|
|
85
|
+
| event | `[事件] …` |
|
|
86
|
+
|
|
87
|
+
| 出站 wire | 说明 |
|
|
88
|
+
|-----------|------|
|
|
89
|
+
| text | 支持 `<@userid>` |
|
|
90
|
+
| image | 需 `media_id` |
|
|
91
|
+
| markdown | 企业微信原生 Markdown |
|
|
92
|
+
| news | link 段映射 |
|
|
166
93
|
|
|
167
94
|
## 安全说明
|
|
168
95
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
企业微信使用 AES-256-CBC 加密算法对回调消息进行加密:
|
|
172
|
-
|
|
173
|
-
- **签名验证**:SHA1 排序拼接 `[token, timestamp, nonce, encrypt]`
|
|
174
|
-
- **解密流程**:
|
|
175
|
-
1. Base64 解码加密消息
|
|
176
|
-
2. AES-256-CBC 解密(Key: `encodingAESKey` + `=` 的 Base64 解码,IV: Key 的前 16 字节)
|
|
177
|
-
3. PKCS7 去填充
|
|
178
|
-
4. 提取:16 字节随机数 + 4 字节消息长度 + 消息体 + CorpId
|
|
179
|
-
|
|
180
|
-
适配器自动处理所有加解密,无需手动处理。
|
|
181
|
-
|
|
182
|
-
### Token 管理
|
|
183
|
-
|
|
184
|
-
适配器会自动管理 access_token:
|
|
185
|
-
- 首次连接时获取 token
|
|
186
|
-
- Token 过期前 5 分钟自动刷新
|
|
187
|
-
- 所有 API 请求自动携带有效 token
|
|
188
|
-
|
|
189
|
-
## API 方法
|
|
190
|
-
|
|
191
|
-
### 获取用户信息
|
|
192
|
-
|
|
193
|
-
```typescript
|
|
194
|
-
const endpoint = app.adapters.get('wecom')?.endpoints.get('wecom-bot')
|
|
195
|
-
if (endpoint) {
|
|
196
|
-
const userInfo = await endpoint.getUserInfo('user-id')
|
|
197
|
-
console.log(userInfo)
|
|
198
|
-
}
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### 获取部门用户列表
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
const users = await endpoint.getDepartmentUsers(1) // 部门 ID
|
|
205
|
-
console.log(users)
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
### 获取部门列表
|
|
96
|
+
企业微信回调始终加密:
|
|
209
97
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
console.log(departments)
|
|
213
|
-
```
|
|
98
|
+
- **签名**:SHA1 排序拼接 `[token, timestamp, nonce, encrypt]`
|
|
99
|
+
- **解密**:AES-256-CBC(Key = `encodingAESKey` + `=` 的 Base64,IV = Key 前 16 字节)
|
|
214
100
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
```typescript
|
|
218
|
-
const success = await endpoint.sendTextMessage('user-id', '这是一条测试消息')
|
|
219
|
-
```
|
|
101
|
+
Access Token 在过期前 5 分钟自动刷新。
|
|
220
102
|
|
|
221
103
|
## 故障排查
|
|
222
104
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
3. 服务器是否可从公网访问
|
|
229
|
-
4. 服务器是否返回了正确的验证响应(解密后的 echostr)
|
|
230
|
-
|
|
231
|
-
### Q: 收不到消息回调?
|
|
232
|
-
|
|
233
|
-
A: 可能的原因:
|
|
234
|
-
1. 应用未启用「接收消息」功能
|
|
235
|
-
2. Webhook URL 配置错误或不可达
|
|
236
|
-
3. 应用可见范围未包含发送消息的用户
|
|
237
|
-
4. 服务器日志中是否有签名验证失败的警告
|
|
105
|
+
| 现象 | 排查 |
|
|
106
|
+
|------|------|
|
|
107
|
+
| URL 验证失败 | `token` / `encodingAESKey` / `corpId` 与管理后台一致;Host 已 listen 且公网可达 |
|
|
108
|
+
| 收不到消息 | 应用已启用接收消息;可见范围包含发送者;endpoint 已 `open()` |
|
|
109
|
+
| 发送失败 | `corpId` + `agentSecret` 可换取 token;接收者在可见范围 |
|
|
238
110
|
|
|
239
|
-
|
|
111
|
+
## AI 工具
|
|
240
112
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
113
|
+
| 类别 | 路径 |
|
|
114
|
+
|------|------|
|
|
115
|
+
| Permit 词汇 | `PERMITS.md` |
|
|
116
|
+
| 平台工具(4 个) | `tools/` |
|
|
117
|
+
| 技能说明 | `agents/wecom/skills/wecom/SKILL.md` |
|
|
246
118
|
|
|
247
|
-
|
|
119
|
+
## 平台权限(platform permit)
|
|
248
120
|
|
|
249
|
-
|
|
250
|
-
1. CorpId 是否正确
|
|
251
|
-
2. agentSecret 是否是应用 Secret(不是应用的 AgentId 数字)
|
|
252
|
-
3. 企业微信 API 是否可访问
|
|
121
|
+
`plugin.ts` 在 generation setup 注册 `src/platform-permit.ts` checker,并在 dispose 注销;CapabilityIngress 与 ToolSystem 统一经 Core `canAccessTool()` 消费工具权限。
|
|
253
122
|
|
|
254
123
|
## 相关链接
|
|
255
124
|
|
|
256
125
|
- [企业微信开发文档](https://developer.work.weixin.qq.com/document/)
|
|
257
|
-
- [
|
|
258
|
-
- [
|
|
259
|
-
- [Zhin.js 官方文档](https://github.com/zhinjs/zhin)
|
|
126
|
+
- [接收消息](https://developer.work.weixin.qq.com/document/path/90930)
|
|
127
|
+
- [发送应用消息](https://developer.work.weixin.qq.com/document/path/90236)
|
|
260
128
|
|
|
261
129
|
## 许可证
|
|
262
130
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
/**
|
|
3
|
+
* Convention entry: discover `adapters/wecom/index.ts` → defineAdapter.
|
|
4
|
+
* Implementation lives under `src/` (endpoint / webhook / protocol).
|
|
5
|
+
*/
|
|
6
|
+
import { defineAdapter } from 'zhin.js/adapter';
|
|
7
|
+
import { httpHostToken } from '@zhin.js/host-http';
|
|
8
|
+
import { WecomEndpoint } from "../../lib/endpoint.js";
|
|
9
|
+
import { resolveWecomConfig, } from "../../lib/protocol.js";
|
|
10
|
+
import { wecomRuntimeStateToken } from "../../lib/wecom-runtime-state.js";
|
|
11
|
+
export { WecomEndpoint } from "../../lib/endpoint.js";
|
|
12
|
+
export default defineAdapter({
|
|
13
|
+
capabilities: ['inbound', 'outbound'],
|
|
14
|
+
operations: ['recall'],
|
|
15
|
+
// image 段全部经 /cgi-bin/media/upload 物化为 media_id(url 下载后上传、
|
|
16
|
+
// base64/path 直接上传、file 引用直用 media_id);无卡片交互面,交互段降级纯文本。
|
|
17
|
+
segments: {
|
|
18
|
+
outboundMedia: ['upload'],
|
|
19
|
+
interactive: 'text',
|
|
20
|
+
},
|
|
21
|
+
create(context) {
|
|
22
|
+
const config = resolveWecomConfig(context.config);
|
|
23
|
+
// 注册到插件运行时状态(wecom endpoint list 的"运行中"数据源)
|
|
24
|
+
context.use(wecomRuntimeStateToken).endpoints.set(config.id, {
|
|
25
|
+
id: config.id,
|
|
26
|
+
mode: 'webhook',
|
|
27
|
+
});
|
|
28
|
+
return new WecomEndpoint({
|
|
29
|
+
id: context.id,
|
|
30
|
+
http: context.use(httpHostToken),
|
|
31
|
+
config,
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convention entry: discover `adapters/wecom/index.ts` → defineAdapter.
|
|
3
|
+
* Implementation lives under `src/` (endpoint / webhook / protocol).
|
|
4
|
+
*/
|
|
5
|
+
import { defineAdapter } from 'zhin.js/adapter';
|
|
6
|
+
import { httpHostToken } from '@zhin.js/host-http';
|
|
7
|
+
import { WecomEndpoint } from '../../src/endpoint.js';
|
|
8
|
+
import {
|
|
9
|
+
resolveWecomConfig,
|
|
10
|
+
type WecomEndpointConfig,
|
|
11
|
+
} from '../../src/protocol.js';
|
|
12
|
+
import { wecomRuntimeStateToken } from '../../src/wecom-runtime-state.js';
|
|
13
|
+
|
|
14
|
+
export { WecomEndpoint } from '../../src/endpoint.js';
|
|
15
|
+
export type { WecomEndpointOptions, WecomFetch } from '../../src/endpoint.js';
|
|
16
|
+
|
|
17
|
+
export default defineAdapter<WecomEndpointConfig>({
|
|
18
|
+
capabilities: ['inbound', 'outbound'],
|
|
19
|
+
operations: ['recall'],
|
|
20
|
+
// image 段全部经 /cgi-bin/media/upload 物化为 media_id(url 下载后上传、
|
|
21
|
+
// base64/path 直接上传、file 引用直用 media_id);无卡片交互面,交互段降级纯文本。
|
|
22
|
+
segments: {
|
|
23
|
+
outboundMedia: ['upload'],
|
|
24
|
+
interactive: 'text',
|
|
25
|
+
},
|
|
26
|
+
create(context) {
|
|
27
|
+
const config = resolveWecomConfig(context.config);
|
|
28
|
+
// 注册到插件运行时状态(wecom endpoint list 的"运行中"数据源)
|
|
29
|
+
context.use(wecomRuntimeStateToken).endpoints.set(config.id, {
|
|
30
|
+
id: config.id,
|
|
31
|
+
mode: 'webhook',
|
|
32
|
+
});
|
|
33
|
+
return new WecomEndpoint({
|
|
34
|
+
id: context.id,
|
|
35
|
+
http: context.use(httpHostToken),
|
|
36
|
+
config,
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "WECOM Platform Agent",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Handles wecom platform-specific operations and progressively loads only the required platform Skill.",
|
|
5
|
+
"trigger_rules": {
|
|
6
|
+
"file_patterns": [],
|
|
7
|
+
"keywords": [
|
|
8
|
+
"wecom",
|
|
9
|
+
"adapter:wecom"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"entry_points": [
|
|
13
|
+
"system.md",
|
|
14
|
+
"boundaries.md",
|
|
15
|
+
"conventions.md"
|
|
16
|
+
],
|
|
17
|
+
"platforms": [
|
|
18
|
+
"wecom"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -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: 'wecom',
|
|
10
|
+
tags: ['wecom'],
|
|
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
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export default defineAgentTool<{ dept_id: string }>({
|
|
4
|
+
description: '获取企业微信部门用户列表',
|
|
5
|
+
inputSchema: z.object({
|
|
6
|
+
dept_id: z.string().describe('部门 ID'),
|
|
7
|
+
}),
|
|
8
|
+
adapter: 'wecom',
|
|
9
|
+
tags: ['wecom'],
|
|
10
|
+
async execute({ dept_id }: { dept_id: string }, context) {
|
|
11
|
+
const endpoint = context.$client;
|
|
12
|
+
const users = await endpoint.getDepartmentUsers(Number(dept_id));
|
|
13
|
+
return { users, count: users.length };
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
@@ -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: 'wecom',
|
|
10
|
+
tags: ['wecom'],
|
|
11
|
+
async execute({ user_id }, context) {
|
|
12
|
+
const endpoint = context.$client;
|
|
13
|
+
return await endpoint.getUserInfo(user_id);
|
|
14
|
+
},
|
|
15
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export default defineAgentTool<{ user_id: string }>({
|
|
4
|
+
description: '获取企业微信用户信息',
|
|
5
|
+
inputSchema: z.object({
|
|
6
|
+
user_id: z.string().describe('用户 ID'),
|
|
7
|
+
}),
|
|
8
|
+
adapter: 'wecom',
|
|
9
|
+
tags: ['wecom'],
|
|
10
|
+
async execute({ user_id }: { user_id: string }, context) {
|
|
11
|
+
const endpoint = context.$client;
|
|
12
|
+
return await endpoint.getUserInfo(user_id);
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
|
|
@@ -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: 'wecom',
|
|
10
|
+
tags: ['wecom'],
|
|
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
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export default defineAgentTool<{ dept_id?: string }>({
|
|
4
|
+
description: '获取企业微信部门列表',
|
|
5
|
+
inputSchema: z.object({
|
|
6
|
+
dept_id: z.string().optional().describe('父部门 ID,默认 1(根部门)'),
|
|
7
|
+
}),
|
|
8
|
+
adapter: 'wecom',
|
|
9
|
+
tags: ['wecom'],
|
|
10
|
+
async execute({ dept_id }: { dept_id?: string }, context) {
|
|
11
|
+
const endpoint = context.$client;
|
|
12
|
+
const departments = await endpoint.getDepartmentList(Number(dept_id) || 1);
|
|
13
|
+
return { departments, count: departments.length };
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
@@ -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: '向指定企业微信用户发送文本消息',
|
|
6
|
+
inputSchema: z.object({
|
|
7
|
+
user_id: z.string().describe('用户 ID'),
|
|
8
|
+
content: z.string().describe('消息内容'),
|
|
9
|
+
}),
|
|
10
|
+
adapter: 'wecom',
|
|
11
|
+
tags: ['wecom'],
|
|
12
|
+
async execute({ user_id, content }, context) {
|
|
13
|
+
const endpoint = context.$client;
|
|
14
|
+
const success = await endpoint.sendTextMessage(user_id, content);
|
|
15
|
+
return { success, message: success ? '消息已发送' : '发送失败' };
|
|
16
|
+
},
|
|
17
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export default defineAgentTool<{ user_id: string; content: string }>({
|
|
4
|
+
description: '向指定企业微信用户发送文本消息',
|
|
5
|
+
inputSchema: z.object({
|
|
6
|
+
user_id: z.string().describe('用户 ID'),
|
|
7
|
+
content: z.string().describe('消息内容'),
|
|
8
|
+
}),
|
|
9
|
+
adapter: 'wecom',
|
|
10
|
+
tags: ['wecom'],
|
|
11
|
+
async execute({ user_id, content }: { user_id: string; content: string }, context) {
|
|
12
|
+
const endpoint = context.$client;
|
|
13
|
+
const success = await endpoint.sendTextMessage(user_id, content);
|
|
14
|
+
return { success, message: success ? '消息已发送' : '发送失败' };
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
/**
|
|
3
|
+
* `wecom endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
|
|
4
|
+
* commands/wecom/endpoint/ 下的 list / add / remove 直接默认导出这三项。
|
|
5
|
+
*/
|
|
6
|
+
import { createEndpointCommands } from 'zhin.js/adapter';
|
|
7
|
+
import { defineCommand } from 'zhin.js/command';
|
|
8
|
+
import { wecomRuntimeStateToken } from "../../../lib/wecom-runtime-state.js";
|
|
9
|
+
export const wecomEndpointCommands = createEndpointCommands({
|
|
10
|
+
adapterKey: 'wecom',
|
|
11
|
+
adapterDisplayName: 'WeCom',
|
|
12
|
+
fields: [
|
|
13
|
+
{ key: 'corpId', required: true, env: true, description: '企业 corpId' },
|
|
14
|
+
{ key: 'agentSecret', required: true, env: true, description: '应用 secret' },
|
|
15
|
+
{ key: 'token', required: true, env: true, description: '回调 token' },
|
|
16
|
+
{ key: 'encodingAESKey', required: true, env: true, description: '回调加解密 key' },
|
|
17
|
+
],
|
|
18
|
+
running: (use) => use(wecomRuntimeStateToken).endpoints.values(),
|
|
19
|
+
describeEntry: (entry) => `corpId: ${String(entry.corpId)}`,
|
|
20
|
+
}, defineCommand);
|