opencode-feishu 0.2.0 → 0.3.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/README.md +219 -178
- package/dist/index.js +102438 -90
- package/dist/index.js.map +1 -1
- package/package.json +50 -59
- package/LICENSE +0 -21
package/README.md
CHANGED
|
@@ -1,79 +1,127 @@
|
|
|
1
1
|
# OpenCode 飞书插件
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**opencode-feishu** 是 [OpenCode](https://github.com/anomalyco/opencode) 的官方飞书插件(不是独立服务),通过飞书 WebSocket 长连接将飞书消息接入 OpenCode AI 对话。插件作为**消息中继**:所有消息(包括以 `/` 开头的命令)原样转发给 OpenCode,不解析命令、不选择模型或 Agent。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
npm 包地址:[https://www.npmjs.com/package/opencode-feishu](https://www.npmjs.com/package/opencode-feishu)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 主要能力
|
|
10
|
+
|
|
11
|
+
- **飞书 WebSocket 长连接**:使用飞书「事件与回调」的「长连接」模式接收消息,无需配置公网 Webhook 地址。
|
|
12
|
+
- **OpenCode 对话中继**:将飞书消息转为 OpenCode 会话的 prompt,通过轮询获取回复并回写到飞书。
|
|
9
13
|
- **群聊静默监听**:始终将群消息转发给 OpenCode 积累上下文,仅在 bot 被直接 @提及时才回复,避免刷屏。
|
|
10
|
-
- **入群上下文摄入**:bot
|
|
11
|
-
-
|
|
14
|
+
- **入群上下文摄入**:bot 被拉入群聊时,自动读取最近 50 条历史消息作为 OpenCode 对话上下文。
|
|
15
|
+
- **事件流实时更新**:通过插件 `event` 钩子接收 `message.part.updated` 事件,实时更新「正在思考…」占位消息。
|
|
12
16
|
|
|
13
17
|
---
|
|
14
18
|
|
|
15
|
-
##
|
|
19
|
+
## 快速开始
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
### 前置条件
|
|
22
|
+
|
|
23
|
+
- **Node.js** >= 20.0.0
|
|
24
|
+
- **OpenCode**:已安装并能正常使用(参见 [OpenCode 文档](https://github.com/anomalyco/opencode))
|
|
25
|
+
- **飞书自建应用**:在 [飞书开放平台](https://open.feishu.cn/app) 创建应用,获取 App ID 和 App Secret
|
|
26
|
+
|
|
27
|
+
### 方式一:从 npm 安装(推荐)
|
|
28
|
+
|
|
29
|
+
在 OpenCode 插件目录下安装:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# OpenCode 插件目录(Linux/macOS)
|
|
33
|
+
cd ~/.config/opencode/plugins
|
|
34
|
+
|
|
35
|
+
# 创建插件目录并安装
|
|
36
|
+
mkdir -p opencode-feishu
|
|
37
|
+
cd opencode-feishu
|
|
38
|
+
npm install opencode-feishu
|
|
32
39
|
```
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
- **静默监听**:群聊中未被 @提及的消息通过 `noReply: true` 发送给 OpenCode,仅记录上下文但不触发 AI 回复。
|
|
36
|
-
- **入群摄入**:`im.chat.member.bot.added_v1` 事件触发后,`history.ts` 拉取群聊历史消息并以 `noReply: true` 注入 OpenCode。
|
|
37
|
-
- **事件流**:`events.ts` 与 OpenCode 保持 SSE 连接,收到 `message.part.updated` 等事件时更新对应会话的飞书占位消息,断线后 5 秒重连。
|
|
41
|
+
### 方式二:从源码构建
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
```bash
|
|
44
|
+
git clone https://github.com/your-org/opencode-feishu.git
|
|
45
|
+
cd opencode-feishu
|
|
46
|
+
npm install
|
|
47
|
+
npm run build
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 本地开发安装(junction/symlink)
|
|
51
|
+
|
|
52
|
+
构建完成后,将项目目录链接到 OpenCode 插件目录,避免每次修改都需要重新复制文件。
|
|
53
|
+
|
|
54
|
+
**Windows(使用 junction,无需管理员权限):**
|
|
40
55
|
|
|
41
|
-
|
|
56
|
+
```powershell
|
|
57
|
+
$source = "D:\path\to\opencode-feishu"
|
|
58
|
+
$target = "$env:USERPROFILE\.config\opencode\plugins\opencode-feishu"
|
|
59
|
+
New-Item -ItemType Junction -Path $target -Target $source
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Linux/macOS(使用 symlink):**
|
|
42
63
|
|
|
43
|
-
|
|
44
|
-
-
|
|
45
|
-
|
|
64
|
+
```bash
|
|
65
|
+
ln -s /path/to/opencode-feishu ~/.config/opencode/plugins/opencode-feishu
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 配置 OpenCode 加载插件
|
|
69
|
+
|
|
70
|
+
在 OpenCode 配置文件(`~/.config/opencode/opencode.json`)中声明插件:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"plugin": ["opencode-feishu"]
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 创建飞书配置文件
|
|
79
|
+
|
|
80
|
+
在以下路径创建配置文件:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
~/.config/opencode/plugins/feishu.json
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
内容示例:
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"appId": "cli_xxxxxxxxxxxx",
|
|
91
|
+
"appSecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
配置文件中必须包含 `appId` 和 `appSecret`,其余字段均有默认值(见[配置说明](#配置说明))。
|
|
46
96
|
|
|
47
97
|
---
|
|
48
98
|
|
|
49
|
-
##
|
|
99
|
+
## 飞书开放平台配置
|
|
50
100
|
|
|
51
|
-
###
|
|
101
|
+
### 创建或打开应用
|
|
52
102
|
|
|
53
|
-
在浏览器打开 [飞书开放平台 - 应用列表](https://open.feishu.cn/app),创建或打开你的自建应用,记下 **App ID** 和 **App Secret
|
|
103
|
+
在浏览器打开 [飞书开放平台 - 应用列表](https://open.feishu.cn/app),创建或打开你的自建应用,记下 **App ID** 和 **App Secret**(在「凭证与基础信息」页面)。
|
|
54
104
|
|
|
55
|
-
###
|
|
105
|
+
### 添加机器人能力
|
|
56
106
|
|
|
57
107
|
进入该应用 → 左侧「添加应用能力」→ 添加「机器人」。若已添加则跳过。
|
|
58
108
|
|
|
59
|
-
###
|
|
109
|
+
### 配置事件订阅
|
|
60
110
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
111
|
+
进入「事件与回调」页面,**不需要**填写「请求地址」:本插件使用 **WebSocket 长连接**接收消息,而非 Webhook。
|
|
112
|
+
|
|
113
|
+
在「事件订阅」中添加以下事件:
|
|
64
114
|
|
|
65
115
|
| 事件 | 说明 |
|
|
66
116
|
|------|------|
|
|
67
117
|
| `im.message.receive_v1` | 接收单聊与群聊消息 |
|
|
68
118
|
| `im.chat.member.bot.added_v1` | 机器人进群(触发历史上下文摄入) |
|
|
69
119
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
### 4.4 订阅方式:长连接(必选)
|
|
120
|
+
### 订阅方式:长连接(必选)
|
|
73
121
|
|
|
74
|
-
|
|
122
|
+
在「事件与回调」中,将**订阅方式**设置为「使用长连接接收事件/回调」。使用 Webhook 模式将无法收到消息。
|
|
75
123
|
|
|
76
|
-
###
|
|
124
|
+
### 配置权限
|
|
77
125
|
|
|
78
126
|
进入「权限管理」,搜索并开通以下权限:
|
|
79
127
|
|
|
@@ -82,151 +130,111 @@ flowchart LR
|
|
|
82
130
|
| `im:message` | 获取与发送单聊、群组消息 |
|
|
83
131
|
| `im:message:send_as_bot` | 以应用身份发消息 |
|
|
84
132
|
| `im:chat` | 获取群组信息(群聊场景需要) |
|
|
85
|
-
| `im:message:readonly
|
|
133
|
+
| `im:message:readonly` | 获取群组中所有消息(入群历史摄入需要) |
|
|
86
134
|
|
|
87
135
|
保存后若有权限变更,需在「版本管理与发布」中重新发布。
|
|
88
136
|
|
|
89
|
-
###
|
|
137
|
+
### 发布应用
|
|
90
138
|
|
|
91
|
-
进入「版本管理与发布」→ 创建版本 → 提交审核 →
|
|
139
|
+
进入「版本管理与发布」→ 创建版本 → 提交审核 → 发布。企业内自建应用通常可即时通过。
|
|
92
140
|
|
|
93
141
|
---
|
|
94
142
|
|
|
95
|
-
##
|
|
96
|
-
|
|
97
|
-
### 5.1 环境变量
|
|
98
|
-
|
|
99
|
-
复制项目根目录下的 `.env.example` 为 `.env`,按需填写。所有项均可通过环境变量覆盖配置文件中的同名字段。
|
|
100
|
-
|
|
101
|
-
**必填:**
|
|
102
|
-
|
|
103
|
-
| 变量 | 说明 |
|
|
104
|
-
|------|------|
|
|
105
|
-
| `FEISHU_APP_ID` | 飞书应用 App ID |
|
|
106
|
-
| `FEISHU_APP_SECRET` | 飞书应用 App Secret |
|
|
107
|
-
|
|
108
|
-
**OpenCode:**
|
|
143
|
+
## 架构概览
|
|
109
144
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
145
|
+
```mermaid
|
|
146
|
+
flowchart LR
|
|
147
|
+
FeishuApp["飞书客户端"] -->|"WebSocket 长连接"| Gateway["gateway.ts\n(飞书网关)"]
|
|
148
|
+
Gateway --> Dedup["dedup.ts\n(消息去重)"]
|
|
149
|
+
Gateway --> GroupFilter["group-filter.ts\n(@提及检测)"]
|
|
150
|
+
Gateway -->|"bot.added 事件"| History["history.ts\n(历史摄入)"]
|
|
151
|
+
Gateway -->|"im.message.receive_v1"| Chat["chat.ts\n(对话处理)"]
|
|
152
|
+
Chat --> Session["session.ts\n(会话管理)"]
|
|
153
|
+
Chat -->|"prompt/messages"| OpenCodeAPI["OpenCode SDK"]
|
|
154
|
+
History -->|"noReply: true"| OpenCodeAPI
|
|
155
|
+
OpenCodeAPI --> EventHook["event 钩子\n(message.part.updated)"]
|
|
156
|
+
EventHook --> EventHandler["event.ts\n(事件处理)"]
|
|
157
|
+
EventHandler -->|"实时更新占位"| Sender["sender.ts\n(消息发送)"]
|
|
158
|
+
Chat -->|"最终回复"| Sender
|
|
159
|
+
Sender --> FeishuApp
|
|
160
|
+
```
|
|
113
161
|
|
|
114
|
-
|
|
162
|
+
**主要流程说明:**
|
|
115
163
|
|
|
116
|
-
|
|
164
|
+
- **对话路径**:用户消息 → `gateway.ts` 接收 → `dedup.ts` 去重 → `group-filter.ts` 判断是否回复 → `chat.ts` 获取/创建 OpenCode 会话 → 发送 prompt → 轮询消息 → `sender.ts` 回写飞书
|
|
165
|
+
- **实时更新**:`chat.ts` 发送 prompt 后创建占位消息,OpenCode 通过 `event` 钩子推送 `message.part.updated` 事件,`event.ts` 处理后实时更新飞书占位消息内容
|
|
166
|
+
- **静默监听**:群聊中未被 @提及的消息通过 `noReply: true` 发送给 OpenCode,仅记录上下文但不触发 AI 回复
|
|
167
|
+
- **入群摄入**:`im.chat.member.bot.added_v1` 事件触发后,`history.ts` 拉取群聊最近 50 条历史消息并以 `noReply: true` 注入 OpenCode
|
|
117
168
|
|
|
118
|
-
|
|
119
|
-
|------|------|--------|------|
|
|
120
|
-
| `BOT_THINKING_DELAY` | number | 2500 | 发送「正在思考…」前的延迟(毫秒) |
|
|
121
|
-
| `BOT_ENABLE_STREAMING` | boolean | true | 是否启用流式更新占位消息 |
|
|
122
|
-
| `BOT_STREAM_INTERVAL` | number | 1000 | 流式更新间隔(毫秒) |
|
|
169
|
+
---
|
|
123
170
|
|
|
124
|
-
|
|
171
|
+
## 配置说明
|
|
125
172
|
|
|
126
|
-
|
|
173
|
+
配置文件路径:`~/.config/opencode/plugins/feishu.json`
|
|
127
174
|
|
|
128
|
-
|
|
129
|
-
|
|
175
|
+
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|
|
176
|
+
|------|------|:----:|--------|------|
|
|
177
|
+
| `appId` | string | 是 | — | 飞书应用 App ID |
|
|
178
|
+
| `appSecret` | string | 是 | — | 飞书应用 App Secret |
|
|
179
|
+
| `timeout` | number | 否 | `120000` | 单次对话超时时间(毫秒) |
|
|
180
|
+
| `thinkingDelay` | number | 否 | `2500` | 发送「正在思考…」前的延迟(毫秒),设为 0 可禁用占位消息 |
|
|
181
|
+
| `proxy` | string | 否 | — | HTTP/HTTPS 代理地址(如 `http://127.0.0.1:7890`) |
|
|
130
182
|
|
|
131
|
-
|
|
183
|
+
完整配置示例:
|
|
132
184
|
|
|
133
185
|
```json
|
|
134
186
|
{
|
|
135
|
-
"
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
"opencode": {
|
|
140
|
-
"timeout": 120000
|
|
141
|
-
},
|
|
142
|
-
"bot": {
|
|
143
|
-
"thinkingDelay": 2500,
|
|
144
|
-
"enableStreaming": true,
|
|
145
|
-
"streamInterval": 1000
|
|
146
|
-
}
|
|
187
|
+
"appId": "cli_xxxxxxxxxxxx",
|
|
188
|
+
"appSecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
|
189
|
+
"timeout": 120000,
|
|
190
|
+
"thinkingDelay": 2500
|
|
147
191
|
}
|
|
148
192
|
```
|
|
149
193
|
|
|
150
|
-
环境变量会覆盖上述文件中同名字段。
|
|
151
|
-
|
|
152
194
|
---
|
|
153
195
|
|
|
154
|
-
##
|
|
196
|
+
## 日志
|
|
155
197
|
|
|
156
|
-
|
|
157
|
-
npm install
|
|
158
|
-
npm run build
|
|
159
|
-
npm start
|
|
160
|
-
```
|
|
198
|
+
### Debug 日志文件
|
|
161
199
|
|
|
162
|
-
|
|
200
|
+
插件每次初始化时会创建(并覆盖)以下文件:
|
|
163
201
|
|
|
164
|
-
```bash
|
|
165
|
-
npm run dev
|
|
166
202
|
```
|
|
167
|
-
|
|
168
|
-
另开终端运行 `node dist/index.js`。启动成功后,日志中应依次出现:
|
|
169
|
-
|
|
170
|
-
| 日志内容 | 含义 |
|
|
171
|
-
|----------|------|
|
|
172
|
-
| `配置加载成功` | 环境变量/配置文件已加载 |
|
|
173
|
-
| `Bot open_id 获取成功` | 成功获取 bot 身份信息(用于 @提及检测) |
|
|
174
|
-
| `OpenCode 连接状态 healthy: true` | OpenCode 服务可达 |
|
|
175
|
-
| `OpenCode 事件流连接中…` | 正在连接 OpenCode SSE |
|
|
176
|
-
| `Feishu WebSocket gateway started` | 飞书 WebSocket 网关已启动 |
|
|
177
|
-
| `服务就绪:飞书网关已连接` | 可正常收发消息 |
|
|
178
|
-
|
|
179
|
-
---
|
|
180
|
-
|
|
181
|
-
## 本地打包与安装
|
|
182
|
-
|
|
183
|
-
### 打包为 tarball
|
|
184
|
-
|
|
185
|
-
```bash
|
|
186
|
-
npm run build
|
|
187
|
-
npm pack
|
|
203
|
+
~/feishu-debug.log
|
|
188
204
|
```
|
|
189
205
|
|
|
190
|
-
|
|
206
|
+
该文件记录插件初始化过程中的详细信息,包含配置加载、bot open_id 获取、WebSocket 连接诊断等,排查问题时首先查看此文件。
|
|
191
207
|
|
|
192
|
-
###
|
|
208
|
+
### OpenCode 日志系统
|
|
193
209
|
|
|
194
|
-
|
|
195
|
-
# 从 tarball 安装
|
|
196
|
-
npm install -g ./opencode-feishu-0.1.0.tgz
|
|
197
|
-
|
|
198
|
-
# 或开发模式(链接本地目录)
|
|
199
|
-
npm link
|
|
200
|
-
```
|
|
210
|
+
插件通过 `client.app.log()` 将结构化日志输出到 OpenCode 日志系统:
|
|
201
211
|
|
|
202
|
-
|
|
212
|
+
- **service**:`opencode-feishu`
|
|
213
|
+
- **level**:`info`、`warn`、`error`
|
|
214
|
+
- 可在 OpenCode 的日志界面中按 service 过滤查看
|
|
203
215
|
|
|
204
|
-
###
|
|
216
|
+
### Fallback 行为
|
|
205
217
|
|
|
206
|
-
|
|
207
|
-
npm install /path/to/opencode-feishu-0.1.0.tgz
|
|
208
|
-
```
|
|
218
|
+
若 `client.app.log()` 调用失败(如 OpenCode 版本不兼容),插件会降级到 `console.log`/`console.error` 输出,日志格式为 JSON 行。
|
|
209
219
|
|
|
210
220
|
---
|
|
211
221
|
|
|
212
222
|
## 对话流程说明
|
|
213
223
|
|
|
214
|
-
- **会话获取/创建**:按飞书会话键(单聊 `feishu-p2p-<userId>`,群聊 `feishu-group-<chatId
|
|
215
|
-
- **「正在思考…」**:发送用户消息后,延迟 `
|
|
216
|
-
- **轮询**:每
|
|
217
|
-
-
|
|
218
|
-
- **超时**:若在 `
|
|
224
|
+
- **会话获取/创建**:按飞书会话键(单聊 `feishu-p2p-<userId>`,群聊 `feishu-group-<chatId>`)查找已有 OpenCode 会话(按标题前缀匹配),若无则新建。
|
|
225
|
+
- **「正在思考…」**:发送用户消息后,延迟 `thinkingDelay`(默认 2500ms)再在飞书发送「正在思考…」占位消息;等待期间通过事件钩子实时更新内容,回复就绪后更新为最终内容。
|
|
226
|
+
- **轮询**:每 1500ms 拉取一次该 OpenCode 会话的消息列表,取最后一条 assistant 文本;若连续 2 次内容相同则视为稳定,结束轮询。
|
|
227
|
+
- **实时更新**:插件 `event` 钩子接收 `message.part.updated` 事件,实时将累积的回复内容更新到飞书占位消息。
|
|
228
|
+
- **超时**:若在 `timeout`(默认 120 秒)内未得到稳定回复,将返回「⚠️ 响应超时」并结束等待。
|
|
219
229
|
- **纯中继**:所有消息(包括以 `/` 开头的文本)均原样转发给 OpenCode,由 OpenCode 决定模型、Agent 与行为。
|
|
220
230
|
|
|
221
231
|
---
|
|
222
232
|
|
|
223
233
|
## 群聊行为
|
|
224
234
|
|
|
225
|
-
Bot 在群聊中始终以**静默监听模式**运行:
|
|
226
|
-
|
|
227
235
|
### 静默监听
|
|
228
236
|
|
|
229
|
-
- 群聊中的**所有文本消息**都会转发给 OpenCode 作为对话上下文(使用 `noReply: true`,不触发 AI
|
|
237
|
+
- 群聊中的**所有文本消息**都会转发给 OpenCode 作为对话上下文(使用 `noReply: true`,不触发 AI 回复,不消耗 AI tokens)。
|
|
230
238
|
- 仅在 bot 被**直接 @提及**时,才触发正常的 AI 对话并在飞书群内回复。
|
|
231
239
|
- 未被 @提及的消息在飞书侧完全无感——不会产生任何回复或可见的 bot 行为。
|
|
232
240
|
|
|
@@ -243,11 +251,11 @@ Bot 在群聊中始终以**静默监听模式**运行:
|
|
|
243
251
|
| 单聊(私聊) | 是 | 否 | 是 |
|
|
244
252
|
| 群聊 + bot 被 @提及 | 是 | 否 | 是 |
|
|
245
253
|
| 群聊 + bot 未被 @提及 | 是 | **是** | **否** |
|
|
246
|
-
| bot
|
|
254
|
+
| bot 首次入群(历史摄入) | 历史消息 | **是** | **否** |
|
|
247
255
|
|
|
248
256
|
### 群聊发送者身份
|
|
249
257
|
|
|
250
|
-
发往 OpenCode
|
|
258
|
+
发往 OpenCode 的群聊消息会带上发送者身份前缀,便于 AI 区分是谁在说话:
|
|
251
259
|
|
|
252
260
|
```
|
|
253
261
|
[ou_xxxxxxxxxxxx]: 帮我看一下这个 bug
|
|
@@ -260,31 +268,52 @@ Bot 在群聊中始终以**静默监听模式**运行:
|
|
|
260
268
|
## 会话管理
|
|
261
269
|
|
|
262
270
|
- **会话键**:单聊为 `feishu-p2p-<发送者 userId>`,群聊为 `feishu-group-<群 chatId>`。
|
|
263
|
-
- **OpenCode
|
|
264
|
-
-
|
|
265
|
-
-
|
|
271
|
+
- **OpenCode 会话标题**:格式为 `Feishu-<sessionKey>-<时间戳>`,用于进程重启后按标题前缀恢复会话。
|
|
272
|
+
- **恢复**:进程重启后,通过「列出 OpenCode 会话 + 按标题前缀匹配」恢复对应飞书会话的 OpenCode 会话,找不到则新建。
|
|
273
|
+
- **注意**:若手动修改了 OpenCode 会话标题,重启后将无法恢复该会话,会自动新建一个。
|
|
266
274
|
|
|
267
275
|
---
|
|
268
276
|
|
|
269
|
-
##
|
|
277
|
+
## 开发指南
|
|
270
278
|
|
|
271
|
-
|
|
272
|
-
- **日志**:标准输出为 JSON 行日志,可按需重定向或接入日志系统。
|
|
273
|
-
- **健康检查**:可直接请求 OpenCode 的 v2 健康检查接口(若需自建探活)。
|
|
279
|
+
### 构建命令
|
|
274
280
|
|
|
275
|
-
|
|
281
|
+
```bash
|
|
282
|
+
# 安装依赖
|
|
283
|
+
npm install
|
|
276
284
|
|
|
277
|
-
|
|
285
|
+
# 一次性构建(生成 dist/)
|
|
286
|
+
npm run build
|
|
278
287
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
+
# 开发模式(监听文件变更并自动重新构建)
|
|
289
|
+
npm run dev
|
|
290
|
+
|
|
291
|
+
# 仅做类型检查,不生成文件
|
|
292
|
+
npm run typecheck
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### 开发流程
|
|
296
|
+
|
|
297
|
+
1. 修改 `src/` 下的源文件
|
|
298
|
+
2. 运行 `npm run dev` 保持后台自动构建
|
|
299
|
+
3. 重启 OpenCode 使插件重新加载
|
|
300
|
+
4. 查看 `~/feishu-debug.log` 排查初始化问题
|
|
301
|
+
5. 在 OpenCode 日志界面按 `service=opencode-feishu` 过滤查看运行日志
|
|
302
|
+
|
|
303
|
+
### 添加新的事件处理器
|
|
304
|
+
|
|
305
|
+
1. 在 `src/feishu/gateway.ts` 中注册新的飞书事件类型
|
|
306
|
+
2. 在 `src/handler/` 中添加对应处理逻辑
|
|
307
|
+
3. 在 `src/index.ts` 中连接处理器到网关回调
|
|
308
|
+
|
|
309
|
+
### 调整轮询行为
|
|
310
|
+
|
|
311
|
+
在 `src/handler/chat.ts` 中修改以下常量:
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
const POLL_INTERVAL_MS = 1500 // 轮询间隔
|
|
315
|
+
const STABLE_POLLS = 2 // 连续多少次相同内容视为稳定
|
|
316
|
+
```
|
|
288
317
|
|
|
289
318
|
---
|
|
290
319
|
|
|
@@ -293,23 +322,19 @@ Bot 在群聊中始终以**静默监听模式**运行:
|
|
|
293
322
|
```
|
|
294
323
|
opencode-feishu/
|
|
295
324
|
├── src/
|
|
296
|
-
│ ├── index.ts
|
|
297
|
-
│ ├──
|
|
298
|
-
│ ├── types.ts
|
|
325
|
+
│ ├── index.ts # 插件入口:导出 FeishuPlugin,初始化配置/网关
|
|
326
|
+
│ ├── types.ts # 类型定义(FeishuPluginConfig, ResolvedConfig, LogFn)
|
|
327
|
+
│ ├── types/ws.d.ts # WebSocket 类型声明
|
|
328
|
+
│ ├── session.ts # 会话管理(查找/创建 OpenCode 会话,标题前缀匹配)
|
|
299
329
|
│ ├── feishu/
|
|
300
|
-
│ │ ├── gateway.ts
|
|
301
|
-
│ │ ├── sender.ts
|
|
302
|
-
│ │ ├── dedup.ts
|
|
303
|
-
│ │ ├── group-filter.ts
|
|
304
|
-
│ │ └── history.ts
|
|
305
|
-
│
|
|
306
|
-
│
|
|
307
|
-
│
|
|
308
|
-
│ │ ├── client.ts # OpenCode SDK 封装(会话、消息、健康、SSE、noReply)
|
|
309
|
-
│ │ └── events.ts # OpenCode SSE 订阅与占位实时更新
|
|
310
|
-
│ └── session/
|
|
311
|
-
│ └── manager.ts # 飞书会话键与 OpenCode 会话的映射与恢复
|
|
312
|
-
├── .env.example
|
|
330
|
+
│ │ ├── gateway.ts # 飞书 WebSocket 网关、消息回调与 bot 入群事件
|
|
331
|
+
│ │ ├── sender.ts # 飞书消息发送、更新、删除
|
|
332
|
+
│ │ ├── dedup.ts # 消息去重(10 分钟窗口)
|
|
333
|
+
│ │ ├── group-filter.ts # 群聊 @提及检测(仅在 bot 被直接 @时回复)
|
|
334
|
+
│ │ └── history.ts # 入群历史上下文摄入
|
|
335
|
+
│ └── handler/
|
|
336
|
+
│ ├── chat.ts # 对话处理(prompt、轮询、回复)
|
|
337
|
+
│ └── event.ts # OpenCode 事件处理(message.part.updated 实时更新)
|
|
313
338
|
├── package.json
|
|
314
339
|
├── tsup.config.ts
|
|
315
340
|
└── README.md
|
|
@@ -317,6 +342,22 @@ opencode-feishu/
|
|
|
317
342
|
|
|
318
343
|
---
|
|
319
344
|
|
|
345
|
+
## 常见问题与排查
|
|
346
|
+
|
|
347
|
+
| 现象 | 可能原因 | 处理 |
|
|
348
|
+
|------|----------|------|
|
|
349
|
+
| 启动报错「缺少飞书配置文件」 | 未创建配置文件或路径不对 | 在 `~/.config/opencode/plugins/feishu.json` 创建配置文件 |
|
|
350
|
+
| 启动报错「飞书配置不完整」 | `appId` 或 `appSecret` 字段缺失 | 检查配置文件中是否包含这两个字段 |
|
|
351
|
+
| 日志中「Bot open_id 为空」或「fallback 模式」 | bot info API 调用失败 | 检查飞书 App ID/Secret 是否正确;fallback 模式下任何 @提及都会触发回复 |
|
|
352
|
+
| 群聊中不回复 | 未 @提及 bot,或未使用长连接订阅方式 | 在群中 @bot 后发送消息;确认飞书开放平台订阅方式为「长连接」 |
|
|
353
|
+
| 入群后未摄入历史 | 未订阅 `im.chat.member.bot.added_v1` 事件,或缺少群消息读取权限 | 在飞书开放平台添加事件订阅并开通 `im:message:readonly` 权限 |
|
|
354
|
+
| 回复显示「⚠️ 响应超时」 | 等待时间超过 `timeout`,或 OpenCode/模型响应过慢 | 适当增大配置文件中的 `timeout` 值,或检查 OpenCode 与模型状态 |
|
|
355
|
+
| 同一条消息被处理多次 | 飞书 WebSocket 重复投递 | 插件对同一 `messageId` 在 10 分钟内自动去重,一般无需处理;如仍异常可查看 `feishu-debug.log` |
|
|
356
|
+
| 看不到插件日志 | OpenCode 版本不支持 `client.app.log()` | 插件会降级到 console 输出,查看 OpenCode 进程的标准输出 |
|
|
357
|
+
| 插件未被 OpenCode 加载 | `opencode.json` 未声明插件,或插件目录路径错误 | 确认 `~/.config/opencode/opencode.json` 中 `"plugin"` 数组包含 `"opencode-feishu"` |
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
320
361
|
## 许可证
|
|
321
362
|
|
|
322
363
|
MIT
|