openbird 1.0.0
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/.env.example +2 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- package/.github/ISSUE_TEMPLATE/custom.md +10 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/.github/dependabot.yml +13 -0
- package/.github/workflows/publish.yml +23 -0
- package/LICENSE +21 -0
- package/README.md +218 -0
- package/bin/openbird.js +26 -0
- package/docs/plans/2026-02-12-openbird-v1-design.md +281 -0
- package/examples/basic-usage.mjs +117 -0
- package/package.json +38 -0
- package/src/core/api.js +1182 -0
- package/src/core/auth.js +39 -0
- package/src/core/builders/header.js +560 -0
- package/src/core/builders/params.js +96 -0
- package/src/core/builders/proto.js +4432 -0
- package/src/core/builders/richtext.js +592 -0
- package/src/core/generated/proto.js +19041 -0
- package/src/core/generated/proto_pb.js +16469 -0
- package/src/core/proto/proto.proto +949 -0
- package/src/core/proto/proto_pb.d.ts +4383 -0
- package/src/core/proto/proto_pb.js +785 -0
- package/src/core/utils/cookie.js +58 -0
- package/src/core/utils/encryption.js +216 -0
- package/src/core/utils/time.js +79 -0
- package/src/core/utils/varint.js +31 -0
- package/src/core/websocket.js +311 -0
- package/src/index.js +68 -0
- package/src/logger.js +28 -0
- package/src/mcp/server.js +234 -0
- package/src/webhook/dispatcher.js +42 -0
- package/src/webhook/normalizer.js +86 -0
package/.env.example
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Create a report to help us improve
|
|
4
|
+
title: ''
|
|
5
|
+
labels: ''
|
|
6
|
+
assignees: ''
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
**Describe the bug**
|
|
11
|
+
A clear and concise description of what the bug is.
|
|
12
|
+
|
|
13
|
+
**To Reproduce**
|
|
14
|
+
Steps to reproduce the behavior:
|
|
15
|
+
1. Go to '...'
|
|
16
|
+
2. Click on '....'
|
|
17
|
+
3. Scroll down to '....'
|
|
18
|
+
4. See error
|
|
19
|
+
|
|
20
|
+
**Expected behavior**
|
|
21
|
+
A clear and concise description of what you expected to happen.
|
|
22
|
+
|
|
23
|
+
**Screenshots**
|
|
24
|
+
If applicable, add screenshots to help explain your problem.
|
|
25
|
+
|
|
26
|
+
**Desktop (please complete the following information):**
|
|
27
|
+
- OS: [e.g. iOS]
|
|
28
|
+
- Browser [e.g. chrome, safari]
|
|
29
|
+
- Version [e.g. 22]
|
|
30
|
+
|
|
31
|
+
**Smartphone (please complete the following information):**
|
|
32
|
+
- Device: [e.g. iPhone6]
|
|
33
|
+
- OS: [e.g. iOS8.1]
|
|
34
|
+
- Browser [e.g. stock browser, safari]
|
|
35
|
+
- Version [e.g. 22]
|
|
36
|
+
|
|
37
|
+
**Additional context**
|
|
38
|
+
Add any other context about the problem here.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest an idea for this project
|
|
4
|
+
title: ''
|
|
5
|
+
labels: ''
|
|
6
|
+
assignees: ''
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
**Is your feature request related to a problem? Please describe.**
|
|
11
|
+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
12
|
+
|
|
13
|
+
**Describe the solution you'd like**
|
|
14
|
+
A clear and concise description of what you want to happen.
|
|
15
|
+
|
|
16
|
+
**Describe alternatives you've considered**
|
|
17
|
+
A clear and concise description of any alternative solutions or features you've considered.
|
|
18
|
+
|
|
19
|
+
**Additional context**
|
|
20
|
+
Add any other context or screenshots about the feature request here.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "npm"
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "weekly"
|
|
7
|
+
open-pull-requests-limit: 10
|
|
8
|
+
|
|
9
|
+
- package-ecosystem: "github-actions"
|
|
10
|
+
directory: "/"
|
|
11
|
+
schedule:
|
|
12
|
+
interval: "weekly"
|
|
13
|
+
open-pull-requests-limit: 5
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: Publish to NPM
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- uses: actions/setup-node@v4
|
|
17
|
+
with:
|
|
18
|
+
node-version: '20'
|
|
19
|
+
registry-url: 'https://registry.npmjs.org'
|
|
20
|
+
|
|
21
|
+
- run: npm publish --access public
|
|
22
|
+
env:
|
|
23
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ztxtxwd
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# OpenBird
|
|
2
|
+
|
|
3
|
+
飞书(Lark)非官方基础设施服务,运行在本地,通过浏览器 cookie 连接飞书,提供两个核心能力:
|
|
4
|
+
|
|
5
|
+
1. **Webhook 转发** — 连接飞书 WebSocket,将消息标准化后 POST 到你配置的 webhook 地址
|
|
6
|
+
2. **MCP Server** — 通过 stdio 暴露 14 个飞书 API 工具,供 AI Agent 调用
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
飞书 WebSocket ──> OpenBird ──> Webhook URL(你的代码)
|
|
10
|
+
│
|
|
11
|
+
MCP stdio ──> AI Agent
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## 快速开始
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# 克隆并安装
|
|
18
|
+
git clone https://github.com/nickthecook/openbird.git
|
|
19
|
+
cd openbird
|
|
20
|
+
pnpm install
|
|
21
|
+
|
|
22
|
+
# 配置
|
|
23
|
+
cp .env.example .env
|
|
24
|
+
# 编辑 .env,粘贴你从浏览器 DevTools 复制的飞书 cookie
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 纯 MCP 模式
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
OPENBIRD_COOKIE="your_cookie_here" node bin/openbird.js
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
仅启动 MCP Server(stdio),不连接 WebSocket,不转发事件。
|
|
34
|
+
|
|
35
|
+
### Webhook + MCP 模式
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
OPENBIRD_COOKIE="your_cookie_here" \
|
|
39
|
+
OPENBIRD_WEBHOOK_URL="http://localhost:3000/webhook" \
|
|
40
|
+
node bin/openbird.js
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
连接飞书 WebSocket 并将所有事件转发到你的 webhook 地址,同时提供 MCP 工具。
|
|
44
|
+
|
|
45
|
+
### 运行示例
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# 在一个进程里同时启动 webhook 接收端和 MCP 客户端
|
|
49
|
+
node examples/basic-usage.mjs
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 配置
|
|
53
|
+
|
|
54
|
+
| 环境变量 | 必填 | 说明 |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `OPENBIRD_COOKIE` | 是 | 飞书浏览器 cookie 字符串 |
|
|
57
|
+
| `OPENBIRD_WEBHOOK_URL` | 否 | 接收事件的 webhook 地址,不设置则为纯 MCP 模式 |
|
|
58
|
+
| `OPENBIRD_DEBUG` | 否 | 设为 `true` 开启调试日志 |
|
|
59
|
+
|
|
60
|
+
支持 `.env` 文件配置。
|
|
61
|
+
|
|
62
|
+
## Webhook 事件
|
|
63
|
+
|
|
64
|
+
OpenBird 将飞书 WebSocket 消息标准化为稳定的事件格式:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"type": "im.message.receive_v1",
|
|
69
|
+
"event_id": "evt_7604769001905884091",
|
|
70
|
+
"timestamp": 1739347200000,
|
|
71
|
+
"data": {
|
|
72
|
+
"id": "7604769001905884091",
|
|
73
|
+
"conversation": {
|
|
74
|
+
"id": "7599271773103737795",
|
|
75
|
+
"type": "group"
|
|
76
|
+
},
|
|
77
|
+
"sender": {
|
|
78
|
+
"id": "7128839302827827201",
|
|
79
|
+
"type": "user"
|
|
80
|
+
},
|
|
81
|
+
"content": {
|
|
82
|
+
"type": "text",
|
|
83
|
+
"text": "hello"
|
|
84
|
+
},
|
|
85
|
+
"thread_id": null
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 事件类型
|
|
91
|
+
|
|
92
|
+
| 类型 | 说明 |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `im.message.receive_v1` | 聊天消息(文本、富文本、图片、卡片等) |
|
|
95
|
+
| `system.event.unknown` | 未识别的推送事件 |
|
|
96
|
+
|
|
97
|
+
### 交付语义
|
|
98
|
+
|
|
99
|
+
- 通过 HTTP POST 发送 JSON body
|
|
100
|
+
- `event_id` 全局唯一,可用于幂等判断
|
|
101
|
+
- 非 2xx 响应会指数退避重试,最多 5 次
|
|
102
|
+
|
|
103
|
+
### 接收事件
|
|
104
|
+
|
|
105
|
+
使用 [openbird-webhook-node](./webhooks/node/) 接收事件,无需手写 HTTP 服务:
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
import { createServer } from 'openbird-webhook-node'
|
|
109
|
+
|
|
110
|
+
createServer({
|
|
111
|
+
port: 3000,
|
|
112
|
+
onMessage(event) {
|
|
113
|
+
console.log(event.data.sender.id, event.data.content.text)
|
|
114
|
+
},
|
|
115
|
+
})
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## MCP 工具
|
|
119
|
+
|
|
120
|
+
通过 [Model Context Protocol](https://modelcontextprotocol.io/) 提供 14 个工具(stdio 通信)。
|
|
121
|
+
|
|
122
|
+
### 消息
|
|
123
|
+
|
|
124
|
+
| 工具 | 说明 |
|
|
125
|
+
|---|---|
|
|
126
|
+
| `send_message` | 发送消息(支持 Markdown) |
|
|
127
|
+
| `send_reply` | 回复指定消息(引用回复) |
|
|
128
|
+
| `add_reaction` | 添加表情回应 |
|
|
129
|
+
| `remove_reaction` | 移除表情回应 |
|
|
130
|
+
|
|
131
|
+
### 会话
|
|
132
|
+
|
|
133
|
+
| 工具 | 说明 |
|
|
134
|
+
|---|---|
|
|
135
|
+
| `get_chat_history` | 获取聊天历史消息 |
|
|
136
|
+
| `get_chat_meta` | 获取会话元信息(最后消息位置、已读位置等) |
|
|
137
|
+
| `create_chat` | 创建一对一会话 |
|
|
138
|
+
| `search` | 搜索用户和群组 |
|
|
139
|
+
|
|
140
|
+
### 用户
|
|
141
|
+
|
|
142
|
+
| 工具 | 说明 |
|
|
143
|
+
|---|---|
|
|
144
|
+
| `get_user_info` | 根据用户 ID 获取信息 |
|
|
145
|
+
| `get_user_profile_card` | 获取用户名片(头像、签名等) |
|
|
146
|
+
| `set_user_signature` | 设置当前用户签名 |
|
|
147
|
+
|
|
148
|
+
### 日历
|
|
149
|
+
|
|
150
|
+
| 工具 | 说明 |
|
|
151
|
+
|---|---|
|
|
152
|
+
| `get_calendar_events` | 获取日历事件列表 |
|
|
153
|
+
| `calendar_rsvp` | 回复日历邀请(接受/拒绝/待定) |
|
|
154
|
+
|
|
155
|
+
### 媒体
|
|
156
|
+
|
|
157
|
+
| 工具 | 说明 |
|
|
158
|
+
|---|---|
|
|
159
|
+
| `download_image` | 下载图片(支持解密) |
|
|
160
|
+
|
|
161
|
+
### 使用 MCP Inspector 测试
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
npx @modelcontextprotocol/inspector node bin/openbird.js
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## 项目结构
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
openbird/
|
|
171
|
+
├── bin/openbird.js # CLI 入口
|
|
172
|
+
├── src/
|
|
173
|
+
│ ├── index.js # 主入口
|
|
174
|
+
│ ├── logger.js # 日志(全部写 stderr,stdout 留给 MCP)
|
|
175
|
+
│ ├── core/ # 飞书协议实现
|
|
176
|
+
│ │ ├── api.js # HTTP API 客户端
|
|
177
|
+
│ │ ├── auth.js # Cookie 认证
|
|
178
|
+
│ │ ├── websocket.js # WebSocket 客户端
|
|
179
|
+
│ │ ├── builders/ # Protobuf 请求/响应构建
|
|
180
|
+
│ │ ├── proto/ # .proto 定义及生成代码
|
|
181
|
+
│ │ └── utils/ # Cookie、加密、varint 工具
|
|
182
|
+
│ ├── webhook/
|
|
183
|
+
│ │ ├── normalizer.js # WebSocket 消息 -> OpenBird 事件
|
|
184
|
+
│ │ └── dispatcher.js # HTTP POST 转发(含重试)
|
|
185
|
+
│ └── mcp/
|
|
186
|
+
│ └── server.js # MCP Server(14 个工具)
|
|
187
|
+
├── webhooks/
|
|
188
|
+
│ └── node/ # openbird-webhook-node(事件接收库)
|
|
189
|
+
├── examples/
|
|
190
|
+
│ └── basic-usage.mjs # 完整示例
|
|
191
|
+
└── docs/
|
|
192
|
+
└── plans/ # 设计文档
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## 开发
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# 安装依赖
|
|
199
|
+
pnpm install
|
|
200
|
+
|
|
201
|
+
# 修改 proto.proto 后重新生成代码
|
|
202
|
+
pnpm generate:proto
|
|
203
|
+
|
|
204
|
+
# 启动
|
|
205
|
+
node bin/openbird.js
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## 工作原理
|
|
209
|
+
|
|
210
|
+
OpenBird 逆向了飞书网页版的 WebSocket 协议和 HTTP API,使用你的浏览器 cookie 以你的用户身份认证——和浏览器使用的是同一个会话。
|
|
211
|
+
|
|
212
|
+
**获取 cookie**:打开飞书网页版(feishu.cn),打开浏览器开发者工具,从任意 `*.feishu.cn` 请求中复制完整的 `Cookie` 请求头的值。
|
|
213
|
+
|
|
214
|
+
**注意**:这是非官方工具。飞书可能随时修改协议,使用风险自负。
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
MIT
|
package/bin/openbird.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* OpenBird CLI entry point
|
|
5
|
+
*
|
|
6
|
+
* Safety net: redirect console.log/warn/error to stderr
|
|
7
|
+
* so third-party libs don't pollute stdout (used by MCP JSON-RPC).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const originalLog = console.log;
|
|
11
|
+
const originalWarn = console.warn;
|
|
12
|
+
const originalError = console.error;
|
|
13
|
+
|
|
14
|
+
console.log = (...args) => process.stderr.write(args.join(' ') + '\n');
|
|
15
|
+
console.warn = (...args) => process.stderr.write(args.join(' ') + '\n');
|
|
16
|
+
console.error = (...args) => process.stderr.write(args.join(' ') + '\n');
|
|
17
|
+
|
|
18
|
+
import { main } from '../src/index.js';
|
|
19
|
+
|
|
20
|
+
main().catch((err) => {
|
|
21
|
+
process.stderr.write(`[openbird] Fatal: ${err.message}\n`);
|
|
22
|
+
if (err.stack) {
|
|
23
|
+
process.stderr.write(err.stack + '\n');
|
|
24
|
+
}
|
|
25
|
+
process.exit(1);
|
|
26
|
+
});
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# OpenBird V1 Design
|
|
2
|
+
|
|
3
|
+
## 1. 定位
|
|
4
|
+
|
|
5
|
+
OpenBird 是一个独立运行的飞书非官方基础设施服务,通过 `npx openbird` 启动。
|
|
6
|
+
|
|
7
|
+
它做两件事:
|
|
8
|
+
|
|
9
|
+
1. **WebSocket -> Webhook**:连接飞书 WebSocket,将消息标准化后转发到用户配置的 webhook 地址
|
|
10
|
+
2. **MCP Server**:暴露飞书 API 操作为 MCP tool,供 Agent 调用
|
|
11
|
+
|
|
12
|
+
核心代码提取自 feishu-bot 项目的 `src/lib/`。
|
|
13
|
+
|
|
14
|
+
## 2. 架构
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
用户浏览器 cookie
|
|
18
|
+
|
|
|
19
|
+
v
|
|
20
|
+
+-------------------------------------+
|
|
21
|
+
| OpenBird |
|
|
22
|
+
| |
|
|
23
|
+
| +-------------+ +--------------+ |
|
|
24
|
+
| | WebSocket | | MCP Server | |
|
|
25
|
+
| | Listener | | (stdio) | |
|
|
26
|
+
| +------+------+ +--------------+ |
|
|
27
|
+
| | |
|
|
28
|
+
| +------v------+ |
|
|
29
|
+
| | Event | |
|
|
30
|
+
| | Normalizer | |
|
|
31
|
+
| +------+------+ |
|
|
32
|
+
| | |
|
|
33
|
+
| +------v------+ |
|
|
34
|
+
| | Webhook | |
|
|
35
|
+
| | Dispatcher | |
|
|
36
|
+
| +-------------+ |
|
|
37
|
+
+-------------------------------------+
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 3. 配置与启动
|
|
41
|
+
|
|
42
|
+
**启动**:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx openbird
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
启动后 WebSocket 监听 + Webhook 转发 + MCP Server 同时工作。
|
|
49
|
+
|
|
50
|
+
**配置**(环境变量或 `.env` 文件):
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
OPENBIRD_COOKIE="session=xxx; swp_csrf_token=xxx; ..."
|
|
54
|
+
OPENBIRD_WEBHOOK_URL="https://example.com/webhook"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## 4. Webhook 事件格式
|
|
58
|
+
|
|
59
|
+
### 4.1 事件结构
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"version": "1.0",
|
|
64
|
+
"event_id": "evt_7604769001905884091",
|
|
65
|
+
"event_type": "im.message.created",
|
|
66
|
+
"timestamp": 1739347200,
|
|
67
|
+
"platform": "lark",
|
|
68
|
+
"data": {
|
|
69
|
+
"id": "7604769001905884091",
|
|
70
|
+
"conversation": {
|
|
71
|
+
"id": "7599271773103737795",
|
|
72
|
+
"type": "group"
|
|
73
|
+
},
|
|
74
|
+
"sender": {
|
|
75
|
+
"id": "7128839302827827201",
|
|
76
|
+
"type": "user"
|
|
77
|
+
},
|
|
78
|
+
"content": {
|
|
79
|
+
"type": "text",
|
|
80
|
+
"text": "hello"
|
|
81
|
+
},
|
|
82
|
+
"thread_id": null,
|
|
83
|
+
"created_at": 1739347200
|
|
84
|
+
},
|
|
85
|
+
"extensions": {
|
|
86
|
+
"lark": {
|
|
87
|
+
"chat_type": 2,
|
|
88
|
+
"from_type": 1,
|
|
89
|
+
"message_type": 4
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"raw": {}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 4.2 event_type 规范
|
|
97
|
+
|
|
98
|
+
三段式:`<domain>.<resource>.<action>`
|
|
99
|
+
|
|
100
|
+
**domain 列表**(V1 重点支持 im 和 system):
|
|
101
|
+
|
|
102
|
+
| domain | 含义 |
|
|
103
|
+
|---|---|
|
|
104
|
+
| `im` | 即时通讯 |
|
|
105
|
+
| `contact` | 通讯录 |
|
|
106
|
+
| `calendar` | 日历 |
|
|
107
|
+
| `approval` | 审批 |
|
|
108
|
+
| `drive` | 云文档 |
|
|
109
|
+
| `bot` | 机器人 |
|
|
110
|
+
| `system` | 系统级 |
|
|
111
|
+
|
|
112
|
+
**action 枚举**(固定集合,禁止自造):
|
|
113
|
+
|
|
114
|
+
- `created`
|
|
115
|
+
- `updated`
|
|
116
|
+
- `deleted`
|
|
117
|
+
- `added`
|
|
118
|
+
- `removed`
|
|
119
|
+
- `unknown`(仅 system 使用)
|
|
120
|
+
|
|
121
|
+
**V1 事件类型**:
|
|
122
|
+
|
|
123
|
+
| event_type | 说明 |
|
|
124
|
+
|---|---|
|
|
125
|
+
| `im.message.created` | 新消息 |
|
|
126
|
+
| `im.message.updated` | 消息编辑 |
|
|
127
|
+
| `im.message.deleted` | 消息撤回 |
|
|
128
|
+
| `im.reaction.added` | 添加表情回应 |
|
|
129
|
+
| `im.reaction.removed` | 移除表情回应 |
|
|
130
|
+
| `im.member.added` | 成员加入会话 |
|
|
131
|
+
| `im.member.removed` | 成员离开会话 |
|
|
132
|
+
| `im.conversation.created` | 会话创建 |
|
|
133
|
+
| `im.conversation.updated` | 会话信息变更 |
|
|
134
|
+
| `contact.user.updated` | 用户状态/信息变更 |
|
|
135
|
+
| `calendar.event.created` | 日历事件 |
|
|
136
|
+
| `system.event.unknown` | 未识别的推送事件 |
|
|
137
|
+
|
|
138
|
+
### 4.3 data 字段规范
|
|
139
|
+
|
|
140
|
+
- `id` 永远叫 `id`,不暴露平台 ID 命名
|
|
141
|
+
- 所有嵌套对象都有 `id`
|
|
142
|
+
- 类型字段用枚举,不用自由文本
|
|
143
|
+
- `extensions` 放飞书特有字段,永远可选
|
|
144
|
+
- `raw` 保留原始结构,不保证稳定
|
|
145
|
+
|
|
146
|
+
### 4.4 Normalizer 映射规则
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
WebSocket decoded -> OpenBird event
|
|
150
|
+
---------------------------------------------------
|
|
151
|
+
command === 6 -> im.message.created
|
|
152
|
+
command !== 6 (已知类型) -> 对应的 event_type
|
|
153
|
+
command !== 6 (未知类型) -> system.event.unknown
|
|
154
|
+
|
|
155
|
+
messageId -> event_id ("evt_" + messageId)
|
|
156
|
+
-> data.id
|
|
157
|
+
chatId -> data.conversation.id
|
|
158
|
+
chatType (1/2/3) -> data.conversation.type (p2p/group/...)
|
|
159
|
+
fromId -> data.sender.id
|
|
160
|
+
fromType (1/2) -> data.sender.type (user/bot)
|
|
161
|
+
type (消息类型 2/4/...) -> data.content.type (text/rich/image/...)
|
|
162
|
+
content -> data.content.text
|
|
163
|
+
threadId -> data.thread_id
|
|
164
|
+
原始 decoded 对象 -> raw
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### 4.5 Webhook 交付语义
|
|
168
|
+
|
|
169
|
+
- `event_id` 全局唯一
|
|
170
|
+
- 允许重复投递,用户需自行幂等
|
|
171
|
+
- 非 2xx 响应指数退避重试,最多 5 次
|
|
172
|
+
|
|
173
|
+
## 5. MCP Server
|
|
174
|
+
|
|
175
|
+
通过 stdio 通信(标准 MCP 协议)。所有 tool 共享启动时传入的 cookie 认证。
|
|
176
|
+
|
|
177
|
+
### 5.1 消息操作
|
|
178
|
+
|
|
179
|
+
| tool 名 | 对应方法 | 描述 |
|
|
180
|
+
|---|---|---|
|
|
181
|
+
| `send_message` | `sendMessage` | 发送消息(支持 Markdown) |
|
|
182
|
+
| `send_reply` | `sendReply` | 回复指定消息(引用回复) |
|
|
183
|
+
| `add_reaction` | `addEmojiReaction` | 给消息添加表情回应 |
|
|
184
|
+
| `remove_reaction` | `removeEmojiReaction` | 移除表情回应 |
|
|
185
|
+
|
|
186
|
+
### 5.2 会话操作
|
|
187
|
+
|
|
188
|
+
| tool 名 | 对应方法 | 描述 |
|
|
189
|
+
|---|---|---|
|
|
190
|
+
| `get_chat_history` | `getChatHistory` | 获取聊天历史消息 |
|
|
191
|
+
| `get_chat_meta` | `getChatMeta` | 获取会话元信息 |
|
|
192
|
+
| `create_chat` | `createChat` | 创建一对一会话 |
|
|
193
|
+
| `search` | `searchSome` | 搜索用户和群组 |
|
|
194
|
+
|
|
195
|
+
### 5.3 用户操作
|
|
196
|
+
|
|
197
|
+
| tool 名 | 对应方法 | 描述 |
|
|
198
|
+
|---|---|---|
|
|
199
|
+
| `get_user_info` | `getUserInfoById` | 获取用户/机器人信息 |
|
|
200
|
+
| `get_user_profile_card` | `getUserProfileCard` | 获取用户名片(含签名) |
|
|
201
|
+
| `set_user_signature` | `setUserSignature` | 设置当前用户签名 |
|
|
202
|
+
|
|
203
|
+
### 5.4 日历操作
|
|
204
|
+
|
|
205
|
+
| tool 名 | 对应方法 | 描述 |
|
|
206
|
+
|---|---|---|
|
|
207
|
+
| `get_calendar_events` | `getCalendarEvents` | 获取日历事件列表 |
|
|
208
|
+
| `calendar_rsvp` | `calendarRsvp` | 回复日历邀请(接受/拒绝/待定) |
|
|
209
|
+
|
|
210
|
+
### 5.5 媒体操作
|
|
211
|
+
|
|
212
|
+
| tool 名 | 对应方法 | 描述 |
|
|
213
|
+
|---|---|---|
|
|
214
|
+
| `download_image` | `downloadImage` | 下载图片(支持解密) |
|
|
215
|
+
|
|
216
|
+
共 15 个 tools。
|
|
217
|
+
|
|
218
|
+
## 6. 目录结构
|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
openbird/
|
|
222
|
+
├── bin/
|
|
223
|
+
│ └── openbird.js # CLI 入口
|
|
224
|
+
├── src/
|
|
225
|
+
│ ├── core/ # 从 feishu-bot/lib 提取的核心能力
|
|
226
|
+
│ │ ├── api.js # HTTP API 客户端
|
|
227
|
+
│ │ ├── auth.js # Cookie 认证
|
|
228
|
+
│ │ ├── websocket.js # WebSocket 客户端
|
|
229
|
+
│ │ ├── builders/
|
|
230
|
+
│ │ │ ├── header.js
|
|
231
|
+
│ │ │ ├── params.js
|
|
232
|
+
│ │ │ ├── proto.js
|
|
233
|
+
│ │ │ └── richtext.js
|
|
234
|
+
│ │ ├── proto/
|
|
235
|
+
│ │ │ ├── proto.proto
|
|
236
|
+
│ │ │ └── proto_pb.js
|
|
237
|
+
│ │ ├── generated/
|
|
238
|
+
│ │ │ ├── proto.js
|
|
239
|
+
│ │ │ └── proto_pb.js
|
|
240
|
+
│ │ └── utils/
|
|
241
|
+
│ │ ├── cookie.js
|
|
242
|
+
│ │ ├── encryption.js
|
|
243
|
+
│ │ ├── time.js
|
|
244
|
+
│ │ └── varint.js
|
|
245
|
+
│ ├── webhook/
|
|
246
|
+
│ │ ├── normalizer.js # WebSocket 事件 -> OpenBird 标准格式
|
|
247
|
+
│ │ └── dispatcher.js # HTTP POST 转发到 webhook URL
|
|
248
|
+
│ ├── mcp/
|
|
249
|
+
│ │ └── server.js # MCP Server (stdio), 15 个 tools
|
|
250
|
+
│ └── index.js # 主入口:初始化 auth -> 启动 WS + MCP
|
|
251
|
+
├── package.json
|
|
252
|
+
├── .env.example
|
|
253
|
+
└── README.md
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### 6.1 从 feishu-bot 提取到 src/core/ 的文件
|
|
257
|
+
|
|
258
|
+
直接迁移 `feishu-bot/src/lib/` 的以下文件:
|
|
259
|
+
|
|
260
|
+
- `api.js`, `auth.js`, `websocket.js`
|
|
261
|
+
- `builders/header.js`, `builders/params.js`, `builders/proto.js`, `builders/richtext.js`
|
|
262
|
+
- `proto/proto.proto`, `proto/proto_pb.js`
|
|
263
|
+
- `generated/proto.js`, `generated/proto_pb.js`
|
|
264
|
+
- `utils/cookie.js`, `utils/encryption.js`, `utils/time.js`, `utils/varint.js`
|
|
265
|
+
|
|
266
|
+
不迁移(agent 专用):
|
|
267
|
+
|
|
268
|
+
- `utils/timestamp-enhancer.js`
|
|
269
|
+
- `utils/getAppKeyRemote.js`
|
|
270
|
+
- `tools/time.js`(LangChain tool)
|
|
271
|
+
|
|
272
|
+
## 7. V1 明确不做
|
|
273
|
+
|
|
274
|
+
- 多 webhook 目标
|
|
275
|
+
- 事件过滤/路由规则
|
|
276
|
+
- Webhook 签名验证
|
|
277
|
+
- 多平台适配
|
|
278
|
+
- 事件持久化/回放
|
|
279
|
+
- Agent Runtime
|
|
280
|
+
- 多租户
|
|
281
|
+
- UI
|