opencode-feishu-bot 0.1.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 +314 -0
- package/bin/cli.js +3 -0
- package/dist/auth/whitelist.d.ts +25 -0
- package/dist/auth/whitelist.d.ts.map +1 -0
- package/dist/cli.d.ts +27 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/commands/handler.d.ts +51 -0
- package/dist/commands/handler.d.ts.map +1 -0
- package/dist/commands/parser.d.ts +24 -0
- package/dist/commands/parser.d.ts.map +1 -0
- package/dist/config.d.ts +44 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/database/index.d.ts +96 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/schema.sql +49 -0
- package/dist/events/handler.d.ts +13 -0
- package/dist/events/handler.d.ts.map +1 -0
- package/dist/feishu/client.d.ts +218 -0
- package/dist/feishu/client.d.ts.map +1 -0
- package/dist/feishu/formatter.d.ts +110 -0
- package/dist/feishu/formatter.d.ts.map +1 -0
- package/dist/feishu/menu.d.ts +44 -0
- package/dist/feishu/menu.d.ts.map +1 -0
- package/dist/feishu/question-card.d.ts +24 -0
- package/dist/feishu/question-card.d.ts.map +1 -0
- package/dist/feishu/streamer.d.ts +53 -0
- package/dist/feishu/streamer.d.ts.map +1 -0
- package/dist/feishu/welcome.d.ts +9 -0
- package/dist/feishu/welcome.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4034 -0
- package/dist/opencode/client.d.ts +86 -0
- package/dist/opencode/client.d.ts.map +1 -0
- package/dist/session/manager.d.ts +75 -0
- package/dist/session/manager.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +12 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/reconnect.d.ts +39 -0
- package/dist/utils/reconnect.d.ts.map +1 -0
- package/package.json +74 -0
package/README.md
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
# OpenCode 飞书机器人
|
|
2
|
+
|
|
3
|
+
一个飞书聊天机器人,用于与 OpenCode AI 编程助手集成,让你可以通过飞书与 OpenCode 进行交互。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- **会话群模式**:每个会话创建独立群组,群内无需 @机器人 即可对话
|
|
8
|
+
- **自动标题**:首条消息自动设置群组标题,格式 `o{会话ID}-{标题}`
|
|
9
|
+
- **会话隔离**:多个会话群互不干扰,用户退出或解散群时自动清理
|
|
10
|
+
- **开箱即用**:默认所有用户可用,无需配置白名单
|
|
11
|
+
- **菜单系统**:支持飞书应用菜单,快速创建会话、切换项目等
|
|
12
|
+
- **自动启动**:OpenCode 服务器随机器人自动启动,无需手动配置
|
|
13
|
+
- **流式响应**:实时卡片更新,具有打字效果
|
|
14
|
+
- **消息撤回**:用户撤回消息时自动中止任务并撤回 AI 响应
|
|
15
|
+
- **项目切换**:支持预配置项目列表,快速切换
|
|
16
|
+
- **模型切换**:动态切换 AI 模型
|
|
17
|
+
- **可选白名单**:支持启用白名单模式限制访问
|
|
18
|
+
- **命令系统**:内置常用操作命令
|
|
19
|
+
|
|
20
|
+
## 环境要求
|
|
21
|
+
|
|
22
|
+
- [Bun](https://bun.sh) v1.2.0 或更高版本
|
|
23
|
+
- 飞书企业应用(详细权限配置见 [飞书应用配置](#飞书应用配置) 章节)
|
|
24
|
+
|
|
25
|
+
## 安装
|
|
26
|
+
|
|
27
|
+
### 作为 npm 包安装
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# 全局安装
|
|
31
|
+
npm install -g opencode-feishu-bot
|
|
32
|
+
|
|
33
|
+
# 或使用 bun
|
|
34
|
+
bun add -g opencode-feishu-bot
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 从源码安装
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# 克隆仓库
|
|
41
|
+
git clone <repository-url>
|
|
42
|
+
cd opencode-feishu-bot
|
|
43
|
+
|
|
44
|
+
# 安装依赖
|
|
45
|
+
bun install
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 配置
|
|
49
|
+
|
|
50
|
+
基于 `.env.example` 创建 `.env` 文件:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
cp .env.example .env
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
配置以下环境变量:
|
|
57
|
+
|
|
58
|
+
| 变量 | 说明 | 必填 |
|
|
59
|
+
|------|------|------|
|
|
60
|
+
| `FEISHU_APP_ID` | 飞书开放平台的应用 ID | 是 |
|
|
61
|
+
| `FEISHU_APP_SECRET` | 飞书应用密钥 | 是 |
|
|
62
|
+
| `ADMIN_USER_IDS` | 管理员 open_id 列表(逗号分隔) | 否 |
|
|
63
|
+
| `ALLOW_ALL_USERS` | 是否允许所有用户(默认 `true`,设为 `false` 启用白名单模式) | 否 |
|
|
64
|
+
| `PROJECTS` | 预配置项目列表(格式:`路径:名称,路径:名称`) | 否 |
|
|
65
|
+
| `DATABASE_PATH` | SQLite 数据库路径 | 否(默认:`./data/bot.db`) |
|
|
66
|
+
| `LOG_LEVEL` | 日志级别(debug/info/warn/error) | 否(默认:`info`) |
|
|
67
|
+
| `DEFAULT_MODEL` | 默认模型(格式:`provider/model`) | 否 |
|
|
68
|
+
| `AVAILABLE_MODELS` | 可用模型列表(逗号分隔) | 否 |
|
|
69
|
+
|
|
70
|
+
> **注意**:OpenCode 服务器会随机器人自动启动(随机端口),无需手动配置。
|
|
71
|
+
> 默认项目目录为机器人启动时的**当前工作目录**。
|
|
72
|
+
|
|
73
|
+
## 使用方法
|
|
74
|
+
|
|
75
|
+
### 启动机器人
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# 在你的项目目录中启动
|
|
79
|
+
cd /path/to/your/project
|
|
80
|
+
opencode-feishu-bot
|
|
81
|
+
|
|
82
|
+
# 从源码运行 - 生产模式
|
|
83
|
+
bun run start
|
|
84
|
+
|
|
85
|
+
# 从源码运行 - 开发模式(热重载)
|
|
86
|
+
bun run dev
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### CLI 参数
|
|
90
|
+
|
|
91
|
+
| 参数 | 简写 | 说明 |
|
|
92
|
+
|------|------|------|
|
|
93
|
+
| `--model <id>` | `-m` | 设置默认模型(格式:provider/model) |
|
|
94
|
+
| `--project <path>` | `-p` | 设置默认项目目录 |
|
|
95
|
+
| `--log-level <level>` | `-l` | 日志级别(debug/info/warn/error) |
|
|
96
|
+
| `--list-models` | | 列出所有可用模型并退出 |
|
|
97
|
+
| `--help` | `-h` | 显示帮助信息 |
|
|
98
|
+
| `--version` | `-v` | 显示版本号 |
|
|
99
|
+
|
|
100
|
+
示例:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# 使用指定模型启动
|
|
104
|
+
opencode-feishu-bot --model anthropic/claude-sonnet-4-20250514
|
|
105
|
+
|
|
106
|
+
# 指定项目目录启动
|
|
107
|
+
opencode-feishu-bot -p /path/to/project
|
|
108
|
+
|
|
109
|
+
# 列出所有可用模型
|
|
110
|
+
opencode-feishu-bot --list-models
|
|
111
|
+
|
|
112
|
+
# 组合使用
|
|
113
|
+
opencode-feishu-bot -m anthropic/claude-sonnet-4-20250514 -p /path/to/project -l debug
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 可用命令
|
|
117
|
+
|
|
118
|
+
| 命令 | 说明 | 仅管理员 |
|
|
119
|
+
|------|------|----------|
|
|
120
|
+
| `/help` | 显示可用命令 | 否 |
|
|
121
|
+
| `/new <编号>` | 创建新会话群(私聊)/ 切换项目(会话群内) | 否 |
|
|
122
|
+
| `/model <编号或ID>` | 切换 AI 模型 | 否 |
|
|
123
|
+
| `/compact` | 压缩当前会话上下文 | 否 |
|
|
124
|
+
| `/clear` | 清除历史,创建新会话 | 否 |
|
|
125
|
+
| `/new_session` | 创建新的 OpenCode 会话 | 否 |
|
|
126
|
+
| `/switch_project <路径>` | 切换到不同的项目 | 否 |
|
|
127
|
+
| `/abort` | 中止当前运行的任务 | 否 |
|
|
128
|
+
| `/status` | 显示会话状态 | 否 |
|
|
129
|
+
| `/whitelist_add <用户ID>` | 将用户添加到白名单 | 是 |
|
|
130
|
+
| `/whitelist_remove <用户ID>` | 从白名单移除用户 | 是 |
|
|
131
|
+
| `/whitelist_list` | 列出所有白名单用户 | 是 |
|
|
132
|
+
|
|
133
|
+
### 与 OpenCode 交互
|
|
134
|
+
|
|
135
|
+
**会话群模式(推荐):**
|
|
136
|
+
|
|
137
|
+
1. 在私聊中向机器人发送 `/new <项目编号>` 创建新会话群
|
|
138
|
+
2. 机器人创建群组并拉你进群
|
|
139
|
+
3. 在群内直接发送消息与 AI 对话,无需 @机器人
|
|
140
|
+
4. 首条消息会自动设置群组标题(如 `o1a2b3c-实现登录功能`)
|
|
141
|
+
5. 退出群组或解散群时自动清理会话数据
|
|
142
|
+
|
|
143
|
+
**私聊模式:**
|
|
144
|
+
|
|
145
|
+
直接在私聊中向机器人发送消息,机器人会自动创建或复用会话。
|
|
146
|
+
|
|
147
|
+
**消息撤回**:如果在 AI 生成响应过程中撤回消息,机器人会自动中止任务并撤回已发送的响应。
|
|
148
|
+
|
|
149
|
+
## 开发
|
|
150
|
+
|
|
151
|
+
### 运行测试
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
bun test
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 项目结构
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
src/
|
|
161
|
+
├── index.ts # 应用入口
|
|
162
|
+
├── config.ts # 配置管理
|
|
163
|
+
├── cli.ts # CLI 参数解析
|
|
164
|
+
├── database/ # SQLite 数据库层
|
|
165
|
+
├── feishu/ # 飞书 SDK 集成
|
|
166
|
+
│ ├── client.ts # 飞书客户端封装
|
|
167
|
+
│ ├── formatter.ts # 消息格式化
|
|
168
|
+
│ ├── streamer.ts # 流式卡片更新
|
|
169
|
+
│ ├── welcome.ts # 欢迎卡片生成
|
|
170
|
+
│ └── menu.ts # 菜单交互卡片
|
|
171
|
+
├── events/ # 事件处理
|
|
172
|
+
│ └── handler.ts # 机器人进群、消息撤回、菜单点击等事件
|
|
173
|
+
├── opencode/ # OpenCode SDK 集成(自动启动服务器)
|
|
174
|
+
├── session/ # 会话管理
|
|
175
|
+
├── commands/ # 命令系统
|
|
176
|
+
├── auth/ # 认证/授权
|
|
177
|
+
├── utils/ # 工具函数(日志、重连)
|
|
178
|
+
└── __tests__/ # 测试文件
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## 架构
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
185
|
+
│ 飞书客户端 │────▶│ 会话管理器 │────▶│ OpenCode客户端 │
|
|
186
|
+
│ (WebSocket) │ │ │ │ (自动启动服务) │
|
|
187
|
+
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
188
|
+
│ │ │
|
|
189
|
+
▼ ▼ ▼
|
|
190
|
+
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
191
|
+
│ 消息处理器 │ │ 数据库 │ │ 事件流 │
|
|
192
|
+
│ │ │ (SQLite) │ │ │
|
|
193
|
+
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
194
|
+
│ │
|
|
195
|
+
▼ ▼
|
|
196
|
+
┌─────────────────┐ ┌─────────────────┐
|
|
197
|
+
│ 命令处理器 │ │ 卡片流式器 │
|
|
198
|
+
│ │ │ │
|
|
199
|
+
└─────────────────┘ └─────────────────┘
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## 飞书应用配置
|
|
203
|
+
|
|
204
|
+
1. 访问[飞书开放平台](https://open.feishu.cn/app)
|
|
205
|
+
2. 创建新的企业应用
|
|
206
|
+
|
|
207
|
+
### 权限配置
|
|
208
|
+
|
|
209
|
+
进入 **开发配置 > 权限管理**,开通以下权限:
|
|
210
|
+
|
|
211
|
+
#### 消息权限
|
|
212
|
+
|
|
213
|
+
| 权限名称 | 权限标识 | 用途 | 必需 |
|
|
214
|
+
|---------|---------|------|------|
|
|
215
|
+
| 获取与发送单聊、群组消息 | `im:message` | 发送消息、更新卡片 | ✅ |
|
|
216
|
+
| 获取用户发给机器人的单聊消息 | `im:message.p2p_msg:readonly` | 接收私聊消息 | ✅ |
|
|
217
|
+
| 获取群组中所有消息 | `im:message.group_msg:readonly` | 接收群聊消息 | ✅ |
|
|
218
|
+
| 获取与上传图片或文件资源 | `im:resource` | 获取用户发送的图片 | ✅ |
|
|
219
|
+
|
|
220
|
+
#### 群组权限
|
|
221
|
+
|
|
222
|
+
| 权限名称 | 权限标识 | 用途 | 必需 |
|
|
223
|
+
|---------|---------|------|------|
|
|
224
|
+
| 获取与更新群组信息 | `im:chat` | 创建群聊、更新群名、解散群 | ✅ |
|
|
225
|
+
| 获取群组信息 | `im:chat:readonly` | 获取群信息 | ✅ |
|
|
226
|
+
| 更新群置顶 | `im:chat.top_notice:write` | 置顶状态卡片 | 可选 |
|
|
227
|
+
|
|
228
|
+
#### 用户权限
|
|
229
|
+
|
|
230
|
+
| 权限名称 | 权限标识 | 用途 | 必需 |
|
|
231
|
+
|---------|---------|------|------|
|
|
232
|
+
| 通过手机号或邮箱获取用户 ID | `contact:user.id:readonly` | 白名单功能(通过用户 ID 识别) | 可选 |
|
|
233
|
+
|
|
234
|
+
### 事件订阅
|
|
235
|
+
|
|
236
|
+
进入 **开发配置 > 事件订阅**:
|
|
237
|
+
|
|
238
|
+
1. 选择 **长连接** 模式(无需配置服务器地址)
|
|
239
|
+
2. 添加以下事件:
|
|
240
|
+
|
|
241
|
+
| 事件名称 | 事件标识 | 用途 | 必需 |
|
|
242
|
+
|---------|---------|------|------|
|
|
243
|
+
| 接收消息 | `im.message.receive_v1` | 接收用户消息 | ✅ |
|
|
244
|
+
| 机器人进群 | `im.chat.member.bot.added_v1` | 发送欢迎卡片 | ✅ |
|
|
245
|
+
| 机器人被移出群 | `im.chat.member.bot.deleted_v1` | 清理会话数据 | ✅ |
|
|
246
|
+
| 用户退群 | `im.chat.member.user.deleted_v1` | 会话群自动清理 | ✅ |
|
|
247
|
+
| 群解散 | `im.chat.disbanded_v1` | 会话群自动清理 | ✅ |
|
|
248
|
+
| 消息撤回 | `im.message.recalled_v1` | 自动中止任务、撤回响应 | ✅ |
|
|
249
|
+
| 机器人菜单点击 | `application.bot.menu_v6` | 菜单功能 | 可选 |
|
|
250
|
+
| 卡片回传交互 | `card.action.trigger` | 卡片按钮点击(模型切换等) | ✅ |
|
|
251
|
+
|
|
252
|
+
### 机器人菜单(可选)
|
|
253
|
+
|
|
254
|
+
进入 **应用功能 > 机器人 > 机器人菜单**,添加以下菜单项:
|
|
255
|
+
|
|
256
|
+
| 菜单名称 | event_key |
|
|
257
|
+
|---------|-----------|
|
|
258
|
+
| 新建会话 | `new_session` |
|
|
259
|
+
| 切换模型 | `switch_model` |
|
|
260
|
+
| 压缩上下文 | `compact` |
|
|
261
|
+
| 清除历史 | `clear_history` |
|
|
262
|
+
| 查看状态 | `show_status` |
|
|
263
|
+
|
|
264
|
+
### 发布应用
|
|
265
|
+
|
|
266
|
+
完成以上配置后:
|
|
267
|
+
|
|
268
|
+
1. 进入 **应用发布 > 版本管理与发布**
|
|
269
|
+
2. 创建新版本,提交审核
|
|
270
|
+
3. 审核通过后发布应用
|
|
271
|
+
4. 将机器人添加到你的飞书工作区
|
|
272
|
+
|
|
273
|
+
## 故障排除
|
|
274
|
+
|
|
275
|
+
### 机器人收不到消息
|
|
276
|
+
- 确保在飞书应用设置中启用了长连接
|
|
277
|
+
- 检查所有必需权限是否已授予(见 [权限配置](#权限配置))
|
|
278
|
+
- 验证 `.env` 中的应用凭证
|
|
279
|
+
- 确认已订阅所需的事件(见 [事件订阅](#事件订阅))
|
|
280
|
+
|
|
281
|
+
### 无法创建会话群
|
|
282
|
+
- 确认已授予 `im:chat` 权限
|
|
283
|
+
- 确认应用已发布并通过审核
|
|
284
|
+
- 检查机器人是否有创建群聊的能力
|
|
285
|
+
|
|
286
|
+
### 会话群内消息无响应
|
|
287
|
+
- 确认群组是通过 `/new` 命令创建的会话群
|
|
288
|
+
- 普通群组需要 @机器人 才能触发响应
|
|
289
|
+
- 检查数据库中是否有该群的会话记录
|
|
290
|
+
|
|
291
|
+
### 权限被拒绝(白名单模式)
|
|
292
|
+
- 确认 `ALLOW_ALL_USERS` 是否设为 `false`
|
|
293
|
+
- 验证用户是管理员或已加入白名单
|
|
294
|
+
- 作为管理员使用 `/whitelist_add <用户ID>` 授予访问权限
|
|
295
|
+
|
|
296
|
+
### 消息撤回不生效
|
|
297
|
+
- 确认已订阅 `im.message.recalled_v1` 事件
|
|
298
|
+
- 机器人只能撤回 24 小时内发送的消息
|
|
299
|
+
|
|
300
|
+
### 卡片按钮点击无响应
|
|
301
|
+
- 确认已订阅 `card.action.trigger` 事件
|
|
302
|
+
- 检查日志中是否有卡片交互相关的错误
|
|
303
|
+
|
|
304
|
+
### 无法获取用户发送的图片
|
|
305
|
+
- 确认已授予 `im:resource` 权限
|
|
306
|
+
- 检查图片是否已过期(飞书图片有有效期)
|
|
307
|
+
|
|
308
|
+
### 无法置顶消息
|
|
309
|
+
- 确认已授予 `im:chat.top_notice:write` 权限
|
|
310
|
+
- 机器人需要是群管理员才能置顶消息
|
|
311
|
+
|
|
312
|
+
## 许可证
|
|
313
|
+
|
|
314
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 权限管理模块
|
|
3
|
+
* 管理管理员和白名单用户权限
|
|
4
|
+
*/
|
|
5
|
+
import type { BotDatabase } from '../database';
|
|
6
|
+
export interface AuthConfig {
|
|
7
|
+
adminUserIds: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare class AuthManager {
|
|
10
|
+
private db;
|
|
11
|
+
private config;
|
|
12
|
+
constructor(db: BotDatabase, config: AuthConfig);
|
|
13
|
+
isAdmin(userId: string): boolean;
|
|
14
|
+
isAuthorized(userId: string): boolean;
|
|
15
|
+
addToWhitelist(userId: string, addedBy: string): boolean;
|
|
16
|
+
removeFromWhitelist(userId: string, removedBy: string): boolean;
|
|
17
|
+
getWhitelistedUsers(): Array<{
|
|
18
|
+
user_id: string;
|
|
19
|
+
added_by: string;
|
|
20
|
+
added_at: string;
|
|
21
|
+
}>;
|
|
22
|
+
getAdminUserIds(): string[];
|
|
23
|
+
}
|
|
24
|
+
export declare function createAuthManager(db: BotDatabase, config: AuthConfig): AuthManager;
|
|
25
|
+
//# sourceMappingURL=whitelist.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whitelist.d.ts","sourceRoot":"","sources":["../../src/auth/whitelist.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,EAAE,CAAc;IACxB,OAAO,CAAC,MAAM,CAAa;gBAEf,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU;IAK/C,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIhC,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAOrC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAQxD,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAQ/D,mBAAmB,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAIrF,eAAe,IAAI,MAAM,EAAE;CAG5B;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,GAAG,WAAW,CAElF"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI 参数解析模块
|
|
3
|
+
* 支持命令行参数启动时配置默认模型、项目等
|
|
4
|
+
*/
|
|
5
|
+
export interface CliOptions {
|
|
6
|
+
/** 默认模型 ID (格式: provider/model) */
|
|
7
|
+
model?: string;
|
|
8
|
+
/** 默认项目目录 */
|
|
9
|
+
project?: string;
|
|
10
|
+
/** 日志级别 */
|
|
11
|
+
logLevel?: 'debug' | 'info' | 'warn' | 'error';
|
|
12
|
+
/** 显示帮助信息 */
|
|
13
|
+
help?: boolean;
|
|
14
|
+
/** 显示版本 */
|
|
15
|
+
version?: boolean;
|
|
16
|
+
/** 列出可用模型 */
|
|
17
|
+
listModels?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** 解析 CLI 参数 */
|
|
20
|
+
export declare function parseArgs(args?: string[]): CliOptions;
|
|
21
|
+
/** 格式化帮助信息 */
|
|
22
|
+
export declare function formatHelp(): string;
|
|
23
|
+
/** 获取版本号 */
|
|
24
|
+
export declare function getVersion(): string;
|
|
25
|
+
/** 验证日志级别 */
|
|
26
|
+
export declare function isValidLogLevel(level: string): level is 'debug' | 'info' | 'warn' | 'error';
|
|
27
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,UAAU;IACzB,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW;IACX,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC/C,aAAa;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW;IACX,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAmDD,gBAAgB;AAChB,wBAAgB,SAAS,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,UAAU,CAuD5E;AAoBD,cAAc;AACd,wBAAgB,UAAU,IAAI,MAAM,CAsCnC;AAED,YAAY;AACZ,wBAAgB,UAAU,IAAI,MAAM,CAOnC;AAED,aAAa;AACb,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAE3F"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 命令处理模块
|
|
3
|
+
* 处理用户命令并执行相应操作
|
|
4
|
+
*/
|
|
5
|
+
import type { BotDatabase } from '../database';
|
|
6
|
+
import type { FeishuClient } from '../feishu/client';
|
|
7
|
+
import type { SessionManager } from '../session/manager';
|
|
8
|
+
import type { OpencodeWrapper } from '../opencode/client';
|
|
9
|
+
import type { ProjectConfig } from '../config';
|
|
10
|
+
import type { ModelConfig } from '../config';
|
|
11
|
+
export interface CommandContext {
|
|
12
|
+
chatId: string;
|
|
13
|
+
userId: string;
|
|
14
|
+
isAdmin: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface CommandResult {
|
|
17
|
+
success: boolean;
|
|
18
|
+
message: string;
|
|
19
|
+
handled: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface CommandHandlerConfig {
|
|
22
|
+
projects: ProjectConfig[];
|
|
23
|
+
availableModels: ModelConfig[];
|
|
24
|
+
}
|
|
25
|
+
export declare class CommandHandler {
|
|
26
|
+
private db;
|
|
27
|
+
private feishuClient;
|
|
28
|
+
private sessionManager;
|
|
29
|
+
private opencodeClient;
|
|
30
|
+
private projects;
|
|
31
|
+
private availableModels;
|
|
32
|
+
private cachedModels;
|
|
33
|
+
constructor(db: BotDatabase, feishuClient: FeishuClient, sessionManager: SessionManager, opencodeClient: OpencodeWrapper, config: CommandHandlerConfig);
|
|
34
|
+
private getModels;
|
|
35
|
+
handleIfCommand(text: string, context: CommandContext): Promise<CommandResult>;
|
|
36
|
+
private executeCommand;
|
|
37
|
+
private handleHelp;
|
|
38
|
+
private handleSwitchProject;
|
|
39
|
+
private handleNewSession;
|
|
40
|
+
private handleAbort;
|
|
41
|
+
private handleStatus;
|
|
42
|
+
private handleWhitelistAdd;
|
|
43
|
+
private handleWhitelistRemove;
|
|
44
|
+
private handleWhitelistList;
|
|
45
|
+
private handleNew;
|
|
46
|
+
private handleModel;
|
|
47
|
+
private handleCompact;
|
|
48
|
+
private handleClear;
|
|
49
|
+
}
|
|
50
|
+
export declare function createCommandHandler(db: BotDatabase, feishuClient: FeishuClient, sessionManager: SessionManager, opencodeClient: OpencodeWrapper, config: CommandHandlerConfig): CommandHandler;
|
|
51
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/commands/handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAa7C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,eAAe,EAAE,WAAW,EAAE,CAAC;CAChC;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,EAAE,CAAc;IACxB,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,cAAc,CAAkB;IACxC,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,eAAe,CAAgB;IACvC,OAAO,CAAC,YAAY,CAAwE;gBAG1F,EAAE,EAAE,WAAW,EACf,YAAY,EAAE,YAAY,EAC1B,cAAc,EAAE,cAAc,EAC9B,cAAc,EAAE,eAAe,EAC/B,MAAM,EAAE,oBAAoB;YAUhB,SAAS;IAQjB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;YAwCtE,cAAc;IA6D5B,OAAO,CAAC,UAAU;YAKJ,mBAAmB;YAkBnB,gBAAgB;YAUhB,WAAW;YAkBX,YAAY;YAwBZ,kBAAkB;YA4BlB,qBAAqB;YA4BrB,mBAAmB;YAmBnB,SAAS;YA0HT,WAAW;YA8DX,aAAa;YA0Bb,WAAW;CAQ1B;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,WAAW,EACf,YAAY,EAAE,YAAY,EAC1B,cAAc,EAAE,cAAc,EAC9B,cAAc,EAAE,eAAe,EAC/B,MAAM,EAAE,oBAAoB,GAC3B,cAAc,CAEhB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 命令解析模块
|
|
3
|
+
* 定义和解析机器人命令
|
|
4
|
+
*/
|
|
5
|
+
export interface Command {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
usage: string;
|
|
9
|
+
adminOnly: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface ParsedCommand {
|
|
12
|
+
command: string;
|
|
13
|
+
args: string[];
|
|
14
|
+
rawArgs: string;
|
|
15
|
+
}
|
|
16
|
+
export declare const COMMANDS: Record<string, Command>;
|
|
17
|
+
export declare function isCommand(text: string): boolean;
|
|
18
|
+
export declare function parseCommand(text: string): ParsedCommand | null;
|
|
19
|
+
export declare function getCommand(name: string): Command | null;
|
|
20
|
+
export declare function getAvailableCommands(isAdmin: boolean): Command[];
|
|
21
|
+
export declare function formatHelpMessage(isAdmin: boolean): string;
|
|
22
|
+
export declare function formatCommandError(message: string): string;
|
|
23
|
+
export declare function formatCommandSuccess(message: string): string;
|
|
24
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/commands/parser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAyE5C,CAAC;AAEF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE/C;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAsB/D;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAEvD;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,CAEhE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAU1D;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE5D"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export interface ProjectConfig {
|
|
3
|
+
path: string;
|
|
4
|
+
name: string;
|
|
5
|
+
}
|
|
6
|
+
declare const envSchema: z.ZodObject<{
|
|
7
|
+
FEISHU_APP_ID: z.ZodString;
|
|
8
|
+
FEISHU_APP_SECRET: z.ZodString;
|
|
9
|
+
ADMIN_USER_IDS: z.ZodDefault<z.ZodString>;
|
|
10
|
+
DATABASE_PATH: z.ZodDefault<z.ZodString>;
|
|
11
|
+
LOG_LEVEL: z.ZodDefault<z.ZodEnum<{
|
|
12
|
+
debug: "debug";
|
|
13
|
+
info: "info";
|
|
14
|
+
warn: "warn";
|
|
15
|
+
error: "error";
|
|
16
|
+
}>>;
|
|
17
|
+
ALLOW_ALL_USERS: z.ZodDefault<z.ZodPipe<z.ZodTransform<boolean, unknown>, z.ZodBoolean>>;
|
|
18
|
+
PROJECTS: z.ZodDefault<z.ZodString>;
|
|
19
|
+
MENU_SERVER_URL: z.ZodOptional<z.ZodString>;
|
|
20
|
+
AVAILABLE_MODELS: z.ZodDefault<z.ZodString>;
|
|
21
|
+
DEFAULT_MODEL: z.ZodOptional<z.ZodString>;
|
|
22
|
+
}, z.core.$strip>;
|
|
23
|
+
export type Config = z.infer<typeof envSchema>;
|
|
24
|
+
export interface CliOverrides {
|
|
25
|
+
model?: string;
|
|
26
|
+
project?: string;
|
|
27
|
+
logLevel?: 'debug' | 'info' | 'warn' | 'error';
|
|
28
|
+
}
|
|
29
|
+
export declare function loadConfig(overrides?: CliOverrides): Config;
|
|
30
|
+
export declare function getAdminUserIds(config: Config): string[];
|
|
31
|
+
export declare function getDefaultProjectPath(override?: string): string;
|
|
32
|
+
export declare function getDefaultModel(config: Config): string | undefined;
|
|
33
|
+
export declare function getProjects(config: Config): ProjectConfig[];
|
|
34
|
+
export interface ModelConfig {
|
|
35
|
+
id: string;
|
|
36
|
+
name?: string;
|
|
37
|
+
}
|
|
38
|
+
export declare function getAvailableModels(config: Config): ModelConfig[];
|
|
39
|
+
export declare function filterModels<T extends {
|
|
40
|
+
id: string;
|
|
41
|
+
name: string;
|
|
42
|
+
}>(allModels: T[], configuredModels: ModelConfig[]): T[];
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,QAAA,MAAM,SAAS;;;;;;;;;;;;;;;;iBAuBb,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC;AAE/C,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;CAChD;AAED,wBAAgB,UAAU,CAAC,SAAS,CAAC,EAAE,YAAY,GAAG,MAAM,CAoB3D;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAKxD;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAElE;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE,CAa3D;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,EAAE,CAwBhE;AAED,wBAAgB,YAAY,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACjE,SAAS,EAAE,CAAC,EAAE,EACd,gBAAgB,EAAE,WAAW,EAAE,GAC9B,CAAC,EAAE,CAeL"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/** 用户会话记录 */
|
|
2
|
+
export interface UserSession {
|
|
3
|
+
chat_id: string;
|
|
4
|
+
session_id: string;
|
|
5
|
+
project_path: string;
|
|
6
|
+
created_at: string;
|
|
7
|
+
updated_at: string;
|
|
8
|
+
}
|
|
9
|
+
/** 白名单用户记录 */
|
|
10
|
+
export interface WhitelistUser {
|
|
11
|
+
user_id: string;
|
|
12
|
+
added_by: string;
|
|
13
|
+
added_at: string;
|
|
14
|
+
}
|
|
15
|
+
/** 项目路径映射 */
|
|
16
|
+
export interface ProjectMapping {
|
|
17
|
+
chat_id: string;
|
|
18
|
+
project_path: string;
|
|
19
|
+
updated_at: string;
|
|
20
|
+
}
|
|
21
|
+
/** 事件去重记录 */
|
|
22
|
+
export interface EventDedup {
|
|
23
|
+
event_id: string;
|
|
24
|
+
processed_at: string;
|
|
25
|
+
}
|
|
26
|
+
/** 消息映射记录 */
|
|
27
|
+
export interface MessageMapping {
|
|
28
|
+
user_message_id: string;
|
|
29
|
+
bot_message_id: string | null;
|
|
30
|
+
chat_id: string;
|
|
31
|
+
created_at: string;
|
|
32
|
+
}
|
|
33
|
+
/** 会话群记录 */
|
|
34
|
+
export interface SessionChat {
|
|
35
|
+
chat_id: string;
|
|
36
|
+
session_id: string;
|
|
37
|
+
owner_id: string;
|
|
38
|
+
project_path: string;
|
|
39
|
+
title: string | null;
|
|
40
|
+
title_set: boolean;
|
|
41
|
+
created_at: string;
|
|
42
|
+
updated_at: string;
|
|
43
|
+
}
|
|
44
|
+
/** 机器人数据库操作类 */
|
|
45
|
+
export declare class BotDatabase {
|
|
46
|
+
private db;
|
|
47
|
+
private dedupWindowMs;
|
|
48
|
+
constructor(dbPath: string, dedupWindowMs?: number);
|
|
49
|
+
/** 初始化数据库表结构 */
|
|
50
|
+
private initialize;
|
|
51
|
+
/** 获取用户会话 */
|
|
52
|
+
getSession(chatId: string): UserSession | null;
|
|
53
|
+
/** 创建或更新用户会话 */
|
|
54
|
+
upsertSession(chatId: string, sessionId: string, projectPath: string): void;
|
|
55
|
+
/** 删除用户会话 */
|
|
56
|
+
deleteSession(chatId: string): boolean;
|
|
57
|
+
/** 检查用户是否在白名单中 */
|
|
58
|
+
isUserWhitelisted(userId: string): boolean;
|
|
59
|
+
/** 添加用户到白名单 */
|
|
60
|
+
addToWhitelist(userId: string, addedBy: string): boolean;
|
|
61
|
+
/** 从白名单移除用户 */
|
|
62
|
+
removeFromWhitelist(userId: string): boolean;
|
|
63
|
+
/** 获取所有白名单用户 */
|
|
64
|
+
getWhitelistedUsers(): WhitelistUser[];
|
|
65
|
+
/** 获取聊天的项目路径 */
|
|
66
|
+
getProjectPath(chatId: string): string | null;
|
|
67
|
+
/** 设置聊天的项目路径 */
|
|
68
|
+
setProjectPath(chatId: string, projectPath: string): void;
|
|
69
|
+
/** 检查事件是否已处理(用于去重) */
|
|
70
|
+
isEventProcessed(eventId: string): boolean;
|
|
71
|
+
/** 标记事件为已处理 */
|
|
72
|
+
markEventProcessed(eventId: string): boolean;
|
|
73
|
+
/** 清理过期的事件记录 */
|
|
74
|
+
cleanupOldEvents(): number;
|
|
75
|
+
saveMessageMapping(userMessageId: string, chatId: string): void;
|
|
76
|
+
updateBotMessageId(userMessageId: string, botMessageId: string): void;
|
|
77
|
+
getMessageMapping(userMessageId: string): MessageMapping | null;
|
|
78
|
+
deleteMessageMapping(userMessageId: string): boolean;
|
|
79
|
+
getMessageMappingsAfter(userMessageId: string, chatId: string): MessageMapping[];
|
|
80
|
+
deleteMessageMappings(userMessageIds: string[]): number;
|
|
81
|
+
deleteMessageMappingsByChatId(chatId: string): number;
|
|
82
|
+
cleanupOldMessageMappings(maxAgeMs?: number): number;
|
|
83
|
+
createSessionChat(chatId: string, sessionId: string, ownerId: string, projectPath: string): void;
|
|
84
|
+
getSessionChat(chatId: string): SessionChat | null;
|
|
85
|
+
getSessionChatsByOwner(ownerId: string): SessionChat[];
|
|
86
|
+
updateSessionChatTitle(chatId: string, title: string): void;
|
|
87
|
+
deleteSessionChat(chatId: string): boolean;
|
|
88
|
+
isSessionChat(chatId: string): boolean;
|
|
89
|
+
/** 关闭数据库连接 */
|
|
90
|
+
close(): void;
|
|
91
|
+
}
|
|
92
|
+
/** 初始化数据库 */
|
|
93
|
+
export declare function initializeDatabase(dbPath: string): BotDatabase;
|
|
94
|
+
/** 获取默认数据库实例 */
|
|
95
|
+
export declare function getDatabase(): BotDatabase;
|
|
96
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/database/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS user_sessions (
|
|
2
|
+
chat_id TEXT PRIMARY KEY,
|
|
3
|
+
session_id TEXT NOT NULL,
|
|
4
|
+
project_path TEXT NOT NULL,
|
|
5
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
6
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
CREATE TABLE IF NOT EXISTS user_whitelist (
|
|
10
|
+
user_id TEXT PRIMARY KEY,
|
|
11
|
+
added_by TEXT NOT NULL,
|
|
12
|
+
added_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
CREATE TABLE IF NOT EXISTS project_mappings (
|
|
16
|
+
chat_id TEXT PRIMARY KEY,
|
|
17
|
+
project_path TEXT NOT NULL,
|
|
18
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
CREATE TABLE IF NOT EXISTS event_dedup (
|
|
22
|
+
event_id TEXT PRIMARY KEY,
|
|
23
|
+
processed_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
CREATE TABLE IF NOT EXISTS message_mappings (
|
|
27
|
+
user_message_id TEXT PRIMARY KEY,
|
|
28
|
+
bot_message_id TEXT,
|
|
29
|
+
chat_id TEXT NOT NULL,
|
|
30
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
-- 会话群:每个群对应一个独立的 OpenCode 会话
|
|
34
|
+
CREATE TABLE IF NOT EXISTS session_chats (
|
|
35
|
+
chat_id TEXT PRIMARY KEY,
|
|
36
|
+
session_id TEXT NOT NULL,
|
|
37
|
+
owner_id TEXT NOT NULL,
|
|
38
|
+
project_path TEXT NOT NULL,
|
|
39
|
+
title TEXT,
|
|
40
|
+
title_set BOOLEAN DEFAULT FALSE,
|
|
41
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
42
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
CREATE INDEX IF NOT EXISTS idx_event_dedup_processed_at ON event_dedup(processed_at);
|
|
46
|
+
CREATE INDEX IF NOT EXISTS idx_message_mappings_chat_id ON message_mappings(chat_id);
|
|
47
|
+
CREATE INDEX IF NOT EXISTS idx_message_mappings_created_at ON message_mappings(created_at);
|
|
48
|
+
CREATE INDEX IF NOT EXISTS idx_session_chats_owner_id ON session_chats(owner_id);
|
|
49
|
+
CREATE INDEX IF NOT EXISTS idx_session_chats_session_id ON session_chats(session_id);
|