chattercatcher 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/AGENTS.md ADDED
@@ -0,0 +1,157 @@
1
+ # ChatterCatcher 项目协作规范
2
+
3
+ ## 项目使命
4
+
5
+ ChatterCatcher 是一个本地优先的家庭飞书/Lark 群知识机器人。它的职责是静默捕获日常聊天、文件、图片、链接和语音中的重要信息,在用户提问时用简短答案和可追溯引用回答。
6
+
7
+ 它不是自主 Agent。它不能代表用户执行任意外部操作。这个产品只做三件事:保存、检索、解释家庭知识。
8
+
9
+ ## 第一性原理
10
+
11
+ 任何产品和技术决策都必须回到这些基本事实:
12
+
13
+ 1. 家庭重要信息经常散落在闲聊里。
14
+ 2. 没有证据的回答不可信。
15
+ 3. 更新的信息通常更有用,但只有在明确是同一事实的更新时才应覆盖旧信息。
16
+ 4. 家庭聊天数据是隐私数据,默认必须本地掌控。
17
+ 5. 安装和维护必须足够简单,让家里一个懂技术的人能长期运行。
18
+ 6. 机器人应该减少打扰,而不是变成群里的噪音。
19
+
20
+ 取舍优先级:
21
+
22
+ 1. 正确性和来源可追溯。
23
+ 2. 隐私和本地数据控制。
24
+ 3. 端到端可用的 MVP。
25
+ 4. 运维简单。
26
+ 5. 长期可扩展。
27
+
28
+ ## RAG 强制原则
29
+
30
+ ChatterCatcher 必须使用 RAG。禁止把大量历史聊天、文件全文或任意长上下文直接堆给 LLM。
31
+
32
+ 所有问答必须走这个路径:
33
+
34
+ ```text
35
+ 问题理解 -> 检索 -> 证据重排 -> 冲突处理 -> 基于证据生成答案 -> 输出引用
36
+ ```
37
+
38
+ 硬性要求:
39
+
40
+ - LLM 回答只能基于检索出的证据块和必要系统提示。
41
+ - 检索证据必须保留来源元数据。
42
+ - 回答事实性问题时必须带引用。
43
+ - 如果检索不到证据,必须说不知道。
44
+ - 上下文窗口不是知识库,不能用“塞更多上下文”替代索引、检索和引用。
45
+
46
+ ## 开发流程
47
+
48
+ - 每次只做一个清晰的逻辑单元。
49
+ - 完成一个逻辑单元后必须自测。
50
+ - 自测通过后必须创建一次 git commit。
51
+ - 不要把无关改动混进同一个提交。
52
+ - 不要留下未说明的半成品行为。
53
+
54
+ 固定循环:
55
+
56
+ ```text
57
+ 理解 -> 实现 -> 自测 -> 修复 -> 提交 -> 汇报
58
+ ```
59
+
60
+ 如果测试无法运行,必须在最终回复里说明原因;如果和提交相关,也要体现在提交信息或后续说明里。
61
+
62
+ ## Git 规则
63
+
64
+ - 每完成一个任务或里程碑就提交一次。
65
+ - 提交信息优先使用简洁的 conventional commit:
66
+ - `docs: 中文化项目文档`
67
+ - `feat: 添加飞书网关`
68
+ - `fix: 处理空检索结果`
69
+ - `test: 覆盖冲突处理`
70
+ - 不得重写或丢弃用户已有改动,除非用户明确要求。
71
+ - 提交前必须检查 `git status --short`。
72
+ - 一个提交只包含当前任务相关文件。
73
+
74
+ ## 自测要求
75
+
76
+ 每次代码改动必须按风险选择合适的自测:
77
+
78
+ - CLI 改动:本地运行命令,或添加/更新自动化测试。
79
+ - Gateway 改动:验证启动、配置加载、优雅关闭。
80
+ - 飞书集成改动:单测使用 mock;真实飞书验证要记录手工验证步骤。
81
+ - RAG 改动:测试检索、引用、空结果行为,确保没有全量上下文堆叠。
82
+ - 冲突处理改动:测试旧事实、新事实、讨论语气、明确更新语气。
83
+ - 文件解析改动:至少为涉及格式准备一个代表性 fixture。
84
+ - Web UI 改动:运行构建检查,并本地查看受影响页面。
85
+
86
+ 项目脚手架完成后,最低自测命令应包括:
87
+
88
+ ```bash
89
+ npm run lint
90
+ npm run typecheck
91
+ npm test
92
+ npm run build
93
+ ```
94
+
95
+ 如果命令还不存在,要么补齐,要么明确说明项目尚未到该阶段。
96
+
97
+ ## 产品约束
98
+
99
+ - 默认本地部署。
100
+ - 默认 Web UI 只监听 `127.0.0.1`。
101
+ - 所有事实性回答必须有引用;除非机器人明确说不知道。
102
+ - 不得把闲聊建议当成确定事实。
103
+ - 新事实覆盖旧事实时,必须保留历史证据。
104
+ - 文件是一等知识源,和聊天消息同等重要。
105
+ - MVP 只支持飞书/Lark。
106
+ - MVP 的 LLM 和 embedding 提供商必须兼容 OpenAI API。
107
+
108
+ ## 架构约束
109
+
110
+ - 运行时:Node.js 20+。
111
+ - 语言:TypeScript。
112
+ - 产品入口:CLI 优先。
113
+ - 元数据存储:SQLite 起步。
114
+ - 向量存储:本地、适合 RAG。
115
+ - 关键词检索必须和向量检索并存。
116
+ - 后台任务必须能从 CLI 和 Web UI 观察。
117
+ - 核心本地运行不能依赖 SaaS-only 服务。
118
+
119
+ ## 文档规则
120
+
121
+ - 以后所有项目文档默认使用中文。
122
+ - 产品决策写入 `docs/PRD.md`。
123
+ - 里程碑和实施顺序写入 `docs/DEVELOPMENT_PLAN.md`。
124
+ - 架构和技术栈写入 `docs/TECHNICAL_ARCHITECTURE.md`。
125
+ - 行为或范围变化时同步更新文档。
126
+ - 优先写明确验收标准,不写空泛愿景。
127
+
128
+ ## 安全和隐私
129
+
130
+ - 不记录 secrets。
131
+ - 不打印完整 API Key、App Secret 或 token。
132
+ - secrets 必须和普通配置分开保存。
133
+ - 聊天历史、文件、OCR 结果、语音转写都视为隐私数据。
134
+ - 本地 Web UI 默认不得暴露到公网。
135
+ - 任何远程模型调用都必须能从配置中看出来。
136
+
137
+ ## 回答质量标准
138
+
139
+ 机器人回答应该:
140
+
141
+ - 简短。
142
+ - 直接。
143
+ - 有证据。
144
+ - 明确不确定性。
145
+ - 在新信息覆盖旧信息时说清楚。
146
+
147
+ 差回答:
148
+
149
+ ```text
150
+ 活动应该是 6 月 30 日。
151
+ ```
152
+
153
+ 好回答:
154
+
155
+ ```text
156
+ 端午活动目前是 2026/6/30。来源:老妈在 2026-xx-xx 说“改成 2026/6/30”。此前 2026/5/30 是旧信息。
157
+ ```
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 FlashingChen2024
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,331 @@
1
+ <p align="center">
2
+ <a href="https://github.com/FlashingChen2024/chattercatcher">
3
+ <img src="./assets/chattercatcher-hero.svg" alt="ChatterCatcher" />
4
+ </a>
5
+ </p>
6
+
7
+ <h1 align="center">ChatterCatcher</h1>
8
+
9
+ <p align="center">
10
+ <img src="./assets/chattercatcher-logo.png" alt="ChatterCatcher logo" width="128" />
11
+ </p>
12
+
13
+ <p align="center">
14
+ <strong>本地优先、证据驱动、面向飞书/Lark 家庭群的 RAG 记忆机器人。</strong>
15
+ </p>
16
+
17
+ <p align="center">
18
+ 静默保存家庭群里的重要消息和文件,被 @ 时用可追溯引用回答。
19
+ </p>
20
+
21
+ <p align="center">
22
+ <a href="https://www.npmjs.com/package/chattercatcher"><img alt="npm" src="https://img.shields.io/npm/v/chattercatcher?style=for-the-badge&logo=npm" /></a>
23
+ <a href="https://github.com/FlashingChen2024/chattercatcher"><img alt="GitHub stars" src="https://img.shields.io/github/stars/FlashingChen2024/chattercatcher?style=for-the-badge&logo=github" /></a>
24
+ <a href="./LICENSE"><img alt="License" src="https://img.shields.io/github/license/FlashingChen2024/chattercatcher?style=for-the-badge" /></a>
25
+ </p>
26
+
27
+ <p align="center">
28
+ <img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-6.x-3178c6?style=flat-square&logo=typescript&logoColor=white" />
29
+ <img alt="Node.js" src="https://img.shields.io/badge/Node.js-20+-339933?style=flat-square&logo=node.js&logoColor=white" />
30
+ <img alt="SQLite" src="https://img.shields.io/badge/SQLite-FTS5-003b57?style=flat-square&logo=sqlite&logoColor=white" />
31
+ <img alt="LanceDB" src="https://img.shields.io/badge/LanceDB-vector-2f8f83?style=flat-square" />
32
+ <img alt="Feishu" src="https://img.shields.io/badge/Feishu%20%2F%20Lark-MVP-3370ff?style=flat-square" />
33
+ </p>
34
+
35
+ ---
36
+
37
+ ## 项目状态
38
+
39
+ ChatterCatcher 是一个早期 MVP。它已经具备飞书长连接接入、本地消息存储、SQLite FTS、LanceDB 向量检索、OpenAI-compatible LLM/Embedding、CLI、本地 Web UI 和带引用回答。
40
+
41
+ 当前核心方向是:
42
+
43
+ - 让家庭群信息自然沉淀为本地知识库,而不是靠手动整理。
44
+ - 所有事实性回答必须先检索 RAG 证据,不能把大量历史聊天直接塞给 LLM。
45
+ - `@` 机器人的提问不进入知识库,避免污染检索结果。
46
+ - 回答必须能追溯到“谁在什么时候说了什么”。
47
+ - 新信息覆盖旧信息时保留历史证据,并优先使用明确、更新的证据。
48
+ - 默认本地部署,Web UI 默认只监听 `127.0.0.1`。
49
+
50
+ ---
51
+
52
+ ## 项目预览
53
+
54
+ <table>
55
+ <tr>
56
+ <td width="50%" valign="top">
57
+ <img src="./assets/readme/preview-chat.svg" alt="Feishu message capture preview" />
58
+ <br />
59
+ <strong>飞书群消息捕获</strong>
60
+ <br />
61
+ 普通群消息静默入库,保留发送人、群名、时间、原始平台元数据和文本内容。
62
+ </td>
63
+ <td width="50%" valign="top">
64
+ <img src="./assets/readme/preview-rag.svg" alt="RAG retrieval preview" />
65
+ <br />
66
+ <strong>本地 RAG 检索</strong>
67
+ <br />
68
+ SQLite FTS 与 LanceDB 向量检索并存,回答前必须先召回证据。
69
+ </td>
70
+ </tr>
71
+ <tr>
72
+ <td width="50%" valign="top">
73
+ <img src="./assets/readme/preview-answer.svg" alt="Cited answer preview" />
74
+ <br />
75
+ <strong>引用式回答</strong>
76
+ <br />
77
+ 被 @ 后先即时反馈,再基于证据回复原消息,并输出可读来源。
78
+ </td>
79
+ <td width="50%" valign="top">
80
+ <img src="./assets/readme/preview-web.svg" alt="Local Web UI preview" />
81
+ <br />
82
+ <strong>本地 Web UI</strong>
83
+ <br />
84
+ 查看 Gateway 状态、最近消息、群聊、文件库、解析任务和本地操作入口。
85
+ </td>
86
+ </tr>
87
+ </table>
88
+
89
+ ---
90
+
91
+ ## 核心能力
92
+
93
+ | 模块 | 能力 |
94
+ | --- | --- |
95
+ | 飞书 Gateway | 官方长连接、`im.message.receive_v1` 事件、重复投递保护、附件下载入口 |
96
+ | 消息入库 | 普通文本消息写入 SQLite;`@` 提问直接回答并跳过入库 |
97
+ | RAG 检索 | SQLite FTS 关键词检索、LanceDB 向量检索、混合重排、证据来源保留 |
98
+ | 问答 | OpenAI-compatible chat completions、证据不足时说不知道、回答带引用 |
99
+ | 引用格式 | 展示“谁在什么时候说了什么”,避免暴露 `ou_` / `oc_` 等 opaque id |
100
+ | 文件知识源 | 支持 txt、md、json、csv、tsv、log、docx、pdf 导入和解析 |
101
+ | CLI | setup、settings、doctor、gateway、process、index、files、export、restore |
102
+ | Web UI | 本地状态看板、自动刷新、最近消息、群聊、文件库和解析任务 |
103
+ | 隐私 | 配置与密钥分离;导出不包含 API Key、App Secret 或 token |
104
+ | 数据管理 | 本地导出/恢复、按消息/文件/群删除本地知识库数据 |
105
+
106
+ ---
107
+
108
+ ## 架构概览
109
+
110
+ ```mermaid
111
+ flowchart LR
112
+ Feishu["飞书/Lark 群"] --> Gateway["本地 Gateway"]
113
+ Gateway --> Router["消息路由"]
114
+
115
+ Router -->|"普通消息"| SQLite["SQLite messages"]
116
+ SQLite --> FTS["SQLite FTS5"]
117
+ SQLite --> Indexer["Embedding Indexer"]
118
+ Indexer --> LanceDB["LanceDB vectors"]
119
+
120
+ Router -->|"@ 提问"| QA["Question Handler"]
121
+ QA --> Hybrid["Hybrid Retriever"]
122
+ FTS --> Hybrid
123
+ LanceDB --> Hybrid
124
+ Hybrid --> LLM["OpenAI-compatible LLM"]
125
+ LLM --> Reply["带引用回复原消息"]
126
+ Reply --> Feishu
127
+
128
+ CLI["CLI"] --> SQLite
129
+ Web["Local Web UI"] --> SQLite
130
+ ```
131
+
132
+ ---
133
+
134
+ ## 从零开始搭建
135
+
136
+ ### 1. 环境要求
137
+
138
+ - Node.js 20 或更高
139
+ - npm 10 或更高
140
+ - 一个飞书/Lark 自建应用
141
+ - 一个 OpenAI-compatible LLM API Key
142
+ - 一个 OpenAI-compatible Embedding API Key,或复用 LLM API Key
143
+
144
+ ### 2. 安装
145
+
146
+ ```bash
147
+ npm install -g chattercatcher
148
+ ```
149
+
150
+ 检查 CLI:
151
+
152
+ ```bash
153
+ chattercatcher --help
154
+ ```
155
+
156
+ ### 3. 创建飞书应用
157
+
158
+ 1. 打开 [飞书应用创建入口](https://open.feishu.cn/page/launcher),创建一个自建应用。
159
+ 2. 在飞书开发者后台开通机器人能力。
160
+ 3. 把机器人加入目标家庭群。
161
+ 4. 在事件订阅里选择长连接模式。
162
+ 5. 订阅 `im.message.receive_v1`。
163
+ 6. 记录 App ID 和 App Secret。
164
+
165
+ ### 4. 配置 ChatterCatcher
166
+
167
+ ```bash
168
+ chattercatcher setup
169
+ ```
170
+
171
+ `setup` 会写入:
172
+
173
+ | 配置项 | 说明 |
174
+ | --- | --- |
175
+ | 飞书 App ID | 普通配置 |
176
+ | 飞书 App Secret | 写入 `secrets.json` |
177
+ | LLM Base URL | OpenAI-compatible chat completions endpoint |
178
+ | LLM API Key | 写入 `secrets.json` |
179
+ | LLM Model | 用于答案生成 |
180
+ | Embedding Base URL | 可复用 LLM Base URL |
181
+ | Embedding API Key | 留空可复用 LLM API Key |
182
+ | Embedding Model | 用于 LanceDB 语义检索 |
183
+ | Web UI Host/Port | 默认 `127.0.0.1:3878` |
184
+
185
+ ### 5. 检查配置
186
+
187
+ ```bash
188
+ chattercatcher doctor --online
189
+ ```
190
+
191
+ ### 6. 启动 Gateway 和 Web UI
192
+
193
+ ```bash
194
+ chattercatcher gateway start
195
+ ```
196
+
197
+ 默认 Web UI:
198
+
199
+ ```text
200
+ http://127.0.0.1:3878
201
+ ```
202
+
203
+ ---
204
+
205
+ ## 使用方式
206
+
207
+ 普通群消息会静默进入知识库:
208
+
209
+ ```text
210
+ 编程课的时间改成了后天13:40
211
+ ```
212
+
213
+ 提问时在群里 @ 机器人:
214
+
215
+ ```text
216
+ @小陈 最近一次编程课是什么时候
217
+ ```
218
+
219
+ 机器人会先即时反馈,再基于本地证据回答。提问本身不会入库。
220
+
221
+ 期望回答类似:
222
+
223
+ ```text
224
+ 后天 13:40 [S1]。
225
+
226
+ 引用:
227
+ [S1] 群成员在 2026-04-26 13:36 说:“编程课的时间改成了后天13:40”
228
+ ```
229
+
230
+ ---
231
+
232
+ ## 常用命令
233
+
234
+ | 命令 | 说明 |
235
+ | --- | --- |
236
+ | `chattercatcher setup` | 交互式初始化配置 |
237
+ | `chattercatcher settings show` | 查看脱敏配置 |
238
+ | `chattercatcher doctor --online` | 检查本地配置、存储和在线连通性 |
239
+ | `chattercatcher gateway start` | 启动飞书长连接 Gateway 和本地 Web UI |
240
+ | `chattercatcher gateway status` | 查看 Gateway 状态 |
241
+ | `chattercatcher gateway stop` | 停止 Gateway |
242
+ | `chattercatcher process messages` | 立即处理消息索引任务 |
243
+ | `chattercatcher index rebuild` | 重建 LanceDB 向量索引 |
244
+ | `chattercatcher files add <path...>` | 导入本地文件知识源 |
245
+ | `chattercatcher files jobs` | 查看文件解析任务 |
246
+ | `chattercatcher export --out <file>` | 导出本地知识库数据,不含密钥 |
247
+ | `chattercatcher restore <file>` | 从导出文件恢复 |
248
+
249
+ ---
250
+
251
+ ## 本地数据目录
252
+
253
+ 默认数据目录:
254
+
255
+ ```text
256
+ ~/.chattercatcher/
257
+ |-- config.json
258
+ |-- secrets.json
259
+ `-- data/
260
+ |-- chattercatcher.db
261
+ |-- files/
262
+ |-- exports/
263
+ `-- vector/
264
+ `-- lancedb/
265
+ ```
266
+
267
+ 这些内容不应该提交到 GitHub:
268
+
269
+ ```text
270
+ config/
271
+ data/
272
+ .env
273
+ node_modules/
274
+ dist/
275
+ ```
276
+
277
+ ---
278
+
279
+ ## 隐私与安全
280
+
281
+ - 默认本地部署。
282
+ - 默认 Web UI 只监听 `127.0.0.1`。
283
+ - 聊天记录、文件内容、OCR 结果和语音转写都视为隐私数据。
284
+ - App Secret、API Key 和 token 与普通配置分开保存。
285
+ - 导出文件不包含密钥。
286
+ - 事实性回答必须基于检索证据。
287
+ - 检索不到证据时必须说不知道。
288
+
289
+ ---
290
+
291
+ ## 本地开发
292
+
293
+ ```bash
294
+ npm install
295
+ npm run lint
296
+ npm run typecheck
297
+ npm test
298
+ npm run build
299
+ ```
300
+
301
+ 运行开发版 CLI:
302
+
303
+ ```bash
304
+ npm run dev -- --help
305
+ ```
306
+
307
+ ---
308
+
309
+ ## 常见问题
310
+
311
+ ### `@` 机器人的问题会进知识库吗?
312
+
313
+ 不会。`@` 提问是查询意图,不是家庭事实。ChatterCatcher 会直接回答并跳过入库,避免污染 RAG。
314
+
315
+ ### 没有 embedding 能用吗?
316
+
317
+ 可以保留 SQLite FTS 关键词检索,但语义检索需要配置 embedding。建议运行 `chattercatcher doctor --online` 确认维度和连通性。
318
+
319
+ ### 为什么要用 RAG?
320
+
321
+ 家庭聊天是长期知识库,不应该靠把全部历史消息塞进上下文。RAG 可以控制证据范围、保留来源、降低幻觉,并让回答可追溯。
322
+
323
+ ### Web UI 可以暴露到公网吗?
324
+
325
+ 默认不建议。ChatterCatcher 面向家庭隐私数据,默认只监听 `127.0.0.1`。
326
+
327
+ ---
328
+
329
+ ## License
330
+
331
+ This project is licensed under the [MIT License](./LICENSE).
@@ -0,0 +1,58 @@
1
+ <svg width="1536" height="864" viewBox="0 0 1536 864" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="title desc">
2
+ <title id="title">ChatterCatcher hero illustration</title>
3
+ <desc id="desc">Local-first family chat knowledge bot with message capture, local storage, RAG retrieval, and cited answers.</desc>
4
+ <rect width="1536" height="864" fill="#F6F2EA"/>
5
+ <rect x="88" y="92" width="1360" height="680" rx="40" fill="#FFFDF8" stroke="#D8D1C5" stroke-width="2"/>
6
+ <circle cx="1280" cy="182" r="130" fill="#D9EEE8"/>
7
+ <circle cx="1254" cy="196" r="76" fill="#2F8F83" opacity="0.16"/>
8
+ <path d="M164 632C252 544 356 526 476 578C588 626 694 642 814 588C978 514 1104 534 1240 620C1304 660 1374 666 1448 636V772H164V632Z" fill="#EAE3D5"/>
9
+
10
+ <g transform="translate(164 154)">
11
+ <text x="0" y="0" fill="#14202B" font-family="Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" font-size="78" font-weight="800">ChatterCatcher</text>
12
+ <text x="4" y="58" fill="#56657A" font-family="Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" font-size="30" font-weight="500">Local-first RAG memory for Feishu family groups</text>
13
+ <text x="4" y="112" fill="#14202B" font-family="Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" font-size="26">Capture family chat facts, retrieve evidence, answer with citations.</text>
14
+
15
+ <g transform="translate(0 170)">
16
+ <rect width="412" height="324" rx="24" fill="#17212D"/>
17
+ <rect x="26" y="28" width="172" height="30" rx="15" fill="#2F8F83"/>
18
+ <rect x="26" y="80" width="312" height="50" rx="18" fill="#263545"/>
19
+ <rect x="26" y="150" width="260" height="50" rx="18" fill="#263545"/>
20
+ <rect x="126" y="220" width="260" height="50" rx="18" fill="#2F6FED"/>
21
+ <text x="48" y="114" fill="#E9F0F2" font-family="Inter, ui-sans-serif, system-ui, sans-serif" font-size="21">编程课改到后天 13:40</text>
22
+ <text x="148" y="254" fill="#FFFFFF" font-family="Inter, ui-sans-serif, system-ui, sans-serif" font-size="21">@小陈 最近一次编程课?</text>
23
+ <circle cx="360" cy="54" r="18" fill="#F7C948"/>
24
+ </g>
25
+
26
+ <g transform="translate(468 192)">
27
+ <path d="M0 118H96" stroke="#2F8F83" stroke-width="8" stroke-linecap="round"/>
28
+ <path d="M68 88L104 118L68 148" stroke="#2F8F83" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
29
+ </g>
30
+
31
+ <g transform="translate(590 152)">
32
+ <rect width="268" height="240" rx="24" fill="#ECF7F4" stroke="#9CCFC5" stroke-width="2"/>
33
+ <rect x="42" y="48" width="184" height="52" rx="16" fill="#2F8F83"/>
34
+ <rect x="42" y="120" width="184" height="24" rx="12" fill="#B9DED6"/>
35
+ <rect x="42" y="160" width="140" height="24" rx="12" fill="#B9DED6"/>
36
+ <text x="54" y="82" fill="#FFFFFF" font-family="Inter, ui-sans-serif, system-ui, sans-serif" font-size="24" font-weight="700">SQLite</text>
37
+ <text x="54" y="205" fill="#2F5F59" font-family="Inter, ui-sans-serif, system-ui, sans-serif" font-size="24" font-weight="700">LanceDB</text>
38
+ </g>
39
+
40
+ <g transform="translate(908 192)">
41
+ <path d="M0 118H96" stroke="#2F8F83" stroke-width="8" stroke-linecap="round"/>
42
+ <path d="M68 88L104 118L68 148" stroke="#2F8F83" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
43
+ </g>
44
+
45
+ <g transform="translate(1030 132)">
46
+ <rect width="308" height="300" rx="28" fill="#FFFFFF" stroke="#D8D1C5" stroke-width="2"/>
47
+ <rect x="34" y="34" width="118" height="34" rx="17" fill="#14202B"/>
48
+ <text x="50" y="58" fill="#FFFFFF" font-family="Inter, ui-sans-serif, system-ui, sans-serif" font-size="18" font-weight="700">Answer</text>
49
+ <text x="34" y="112" fill="#14202B" font-family="Inter, ui-sans-serif, system-ui, sans-serif" font-size="25" font-weight="800">后天 13:40</text>
50
+ <rect x="34" y="146" width="236" height="44" rx="14" fill="#F2EEE5"/>
51
+ <rect x="34" y="206" width="210" height="44" rx="14" fill="#F2EEE5"/>
52
+ <text x="52" y="174" fill="#56657A" font-family="Inter, ui-sans-serif, system-ui, sans-serif" font-size="18">[S1] 群成员 13:36</text>
53
+ <text x="52" y="234" fill="#56657A" font-family="Inter, ui-sans-serif, system-ui, sans-serif" font-size="18">可追溯引用</text>
54
+ <circle cx="250" cy="62" r="28" fill="#2F8F83"/>
55
+ <path d="M238 62L248 72L264 52" stroke="#FFFFFF" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
56
+ </g>
57
+ </g>
58
+ </svg>
Binary file
@@ -0,0 +1,12 @@
1
+ <svg width="720" height="420" viewBox="0 0 720 420" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="720" height="420" rx="24" fill="#FFFDF8"/>
3
+ <rect x="54" y="54" width="612" height="292" rx="28" fill="#FFFFFF" stroke="#D8D1C5" stroke-width="2"/>
4
+ <rect x="84" y="84" width="142" height="36" rx="18" fill="#14202B"/>
5
+ <text x="104" y="109" fill="#FFFFFF" font-family="Inter, ui-sans-serif, system-ui" font-size="18" font-weight="700">小陈</text>
6
+ <text x="84" y="164" fill="#14202B" font-family="Inter, ui-sans-serif, system-ui" font-size="32" font-weight="800">后天 13:40 [S1]</text>
7
+ <text x="84" y="218" fill="#56657A" font-family="Inter, ui-sans-serif, system-ui" font-size="22">引用:</text>
8
+ <rect x="84" y="240" width="502" height="62" rx="18" fill="#F2EEE5"/>
9
+ <text x="108" y="278" fill="#56657A" font-family="Inter, ui-sans-serif, system-ui" font-size="21">[S1] 群成员在 2026-04-26 13:36 说...</text>
10
+ <circle cx="606" cy="102" r="28" fill="#2F8F83"/>
11
+ <path d="M594 102L604 112L622 92" stroke="#FFFFFF" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
12
+ </svg>
@@ -0,0 +1,13 @@
1
+ <svg width="720" height="420" viewBox="0 0 720 420" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="720" height="420" rx="24" fill="#17212D"/>
3
+ <rect x="36" y="34" width="210" height="34" rx="17" fill="#2F8F83"/>
4
+ <text x="56" y="58" fill="#fff" font-family="Inter, ui-sans-serif, system-ui" font-size="18" font-weight="700">Feishu group</text>
5
+ <rect x="54" y="104" width="394" height="54" rx="20" fill="#263545"/>
6
+ <rect x="54" y="184" width="326" height="54" rx="20" fill="#263545"/>
7
+ <rect x="258" y="264" width="386" height="54" rx="20" fill="#2F6FED"/>
8
+ <text x="78" y="138" fill="#E9F0F2" font-family="Inter, ui-sans-serif, system-ui" font-size="22">明天要上编程课,时间是13:20</text>
9
+ <text x="78" y="218" fill="#E9F0F2" font-family="Inter, ui-sans-serif, system-ui" font-size="22">编程课的时间改成了后天13:40</text>
10
+ <text x="282" y="298" fill="#FFFFFF" font-family="Inter, ui-sans-serif, system-ui" font-size="22">@小陈 最近一次编程课是什么时候</text>
11
+ <circle cx="606" cy="70" r="22" fill="#F7C948"/>
12
+ <text x="54" y="370" fill="#9FB2C7" font-family="Inter, ui-sans-serif, system-ui" font-size="20">普通消息入库;@ 提问跳过入库</text>
13
+ </svg>
@@ -0,0 +1,18 @@
1
+ <svg width="720" height="420" viewBox="0 0 720 420" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="720" height="420" rx="24" fill="#F6F2EA"/>
3
+ <rect x="54" y="74" width="180" height="230" rx="24" fill="#FFFFFF" stroke="#D8D1C5" stroke-width="2"/>
4
+ <rect x="270" y="74" width="180" height="230" rx="24" fill="#ECF7F4" stroke="#9CCFC5" stroke-width="2"/>
5
+ <rect x="486" y="74" width="180" height="230" rx="24" fill="#FFFFFF" stroke="#D8D1C5" stroke-width="2"/>
6
+ <text x="94" y="126" fill="#14202B" font-family="Inter, ui-sans-serif, system-ui" font-size="28" font-weight="800">SQLite</text>
7
+ <text x="109" y="166" fill="#56657A" font-family="Inter, ui-sans-serif, system-ui" font-size="20">FTS5</text>
8
+ <text x="306" y="126" fill="#14202B" font-family="Inter, ui-sans-serif, system-ui" font-size="28" font-weight="800">LanceDB</text>
9
+ <text x="314" y="166" fill="#56657A" font-family="Inter, ui-sans-serif, system-ui" font-size="20">vectors</text>
10
+ <text x="526" y="126" fill="#14202B" font-family="Inter, ui-sans-serif, system-ui" font-size="28" font-weight="800">Hybrid</text>
11
+ <text x="526" y="166" fill="#56657A" font-family="Inter, ui-sans-serif, system-ui" font-size="20">rerank</text>
12
+ <path d="M234 190H270" stroke="#2F8F83" stroke-width="8" stroke-linecap="round"/>
13
+ <path d="M450 190H486" stroke="#2F8F83" stroke-width="8" stroke-linecap="round"/>
14
+ <rect x="90" y="220" width="108" height="20" rx="10" fill="#EAE3D5"/>
15
+ <rect x="306" y="220" width="108" height="20" rx="10" fill="#B9DED6"/>
16
+ <rect x="522" y="220" width="108" height="20" rx="10" fill="#EAE3D5"/>
17
+ <text x="54" y="360" fill="#14202B" font-family="Inter, ui-sans-serif, system-ui" font-size="22">关键词检索 + 语义检索,共同召回可引用证据</text>
18
+ </svg>
@@ -0,0 +1,20 @@
1
+ <svg width="720" height="420" viewBox="0 0 720 420" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="720" height="420" rx="24" fill="#F6F2EA"/>
3
+ <text x="48" y="64" fill="#14202B" font-family="Inter, ui-sans-serif, system-ui" font-size="34" font-weight="800">ChatterCatcher</text>
4
+ <rect x="48" y="96" width="140" height="96" rx="18" fill="#FFFFFF" stroke="#D8D1C5"/>
5
+ <rect x="208" y="96" width="140" height="96" rx="18" fill="#FFFFFF" stroke="#D8D1C5"/>
6
+ <rect x="368" y="96" width="140" height="96" rx="18" fill="#FFFFFF" stroke="#D8D1C5"/>
7
+ <rect x="528" y="96" width="140" height="96" rx="18" fill="#FFFFFF" stroke="#D8D1C5"/>
8
+ <text x="72" y="134" fill="#56657A" font-family="Inter, ui-sans-serif, system-ui" font-size="18">Gateway</text>
9
+ <text x="72" y="170" fill="#2F8F83" font-family="Inter, ui-sans-serif, system-ui" font-size="28" font-weight="800">运行中</text>
10
+ <text x="232" y="134" fill="#56657A" font-family="Inter, ui-sans-serif, system-ui" font-size="18">群聊</text>
11
+ <text x="232" y="170" fill="#14202B" font-family="Inter, ui-sans-serif, system-ui" font-size="32" font-weight="800">2</text>
12
+ <text x="392" y="134" fill="#56657A" font-family="Inter, ui-sans-serif, system-ui" font-size="18">消息</text>
13
+ <text x="392" y="170" fill="#14202B" font-family="Inter, ui-sans-serif, system-ui" font-size="32" font-weight="800">128</text>
14
+ <text x="552" y="134" fill="#56657A" font-family="Inter, ui-sans-serif, system-ui" font-size="18">文件</text>
15
+ <text x="552" y="170" fill="#14202B" font-family="Inter, ui-sans-serif, system-ui" font-size="32" font-weight="800">8</text>
16
+ <rect x="48" y="236" width="620" height="108" rx="20" fill="#FFFFFF"/>
17
+ <rect x="80" y="270" width="180" height="18" rx="9" fill="#EAE3D5"/>
18
+ <rect x="80" y="306" width="470" height="18" rx="9" fill="#EAE3D5"/>
19
+ <rect x="574" y="266" width="58" height="34" rx="17" fill="#2F8F83"/>
20
+ </svg>
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node