## 功能
添加 Electron 应用的 E2E 测试启动框架,支持并行实例运行、CDP 调试、独立数据隔离、完善的故障检测和数据保护。
### 核心特性
#### 1. 可靠的端口扫描和预留机制
- 自动查找可用的 TCP 端口(默认从 9222 开始)
- **新增**:保持端口预留直到进程启动,防止 TOCTTOU 竞态
- 修复:递归逻辑中的 null + 1 bug
- 添加最大重试限制(100 次),防止无限递归
- 100ms 超时保护,快速检测端口占用
- 并发安全的 completed 标志和资源清理
#### 2. 正确的 CDP 端口配置
- 使用 --remote-debugging-port=<port> 命令行参数
- 移除无效的 REMOTE_DEBUGGING_PORT 环境变量
- 确保 E2E 客户端能正确连接调试器
#### 3. 完善的启动检测和错误处理
- 验证应用目录和 Electron 可执行文件存在性
- 捕获 spawn 错误事件并提供清晰错误信息
- 检测启动期间的早期退出(非零退出码)
- 检测信号终止的启动失败(SIGKILL、SIGTERM 等)
- 启动后立即抛出错误而不仅记录日志
- 避免连接到死进程,失败诊断清晰
#### 4. 并行实例隔离和数据保护
- 为每个 E2E 实例创建独立的用户数据目录
- 基于端口号生成唯一路径:`/tmp/chatlab-e2e-{port}`
- 通过环境变量 CHATLAB_E2E_USER_DATA_DIR 传递给主进程
- 主进程自动调用 app.setPath('userData', dir) 隔离存储
- **新增**:E2E 模式下跳过遗留数据迁移,保护用户真实数据
- 防止并发进程的状态泄漏、死锁、数据库冲突
#### 5. 优雅且高效的进程管理
- 防止多次调用 close() 导致的事件监听器泄漏
- 检查 proc.exitCode 和 proc.signalCode
- 已退出进程立即返回(无 5s 延迟)
- 使用 SIGTERM 允许进程正常清理资源
- 5 秒超时后强制 SIGKILL 防止僵尸进程
- 使用活力检查(proc.kill(0))替代 proc.killed
- 使用正确的 Node.js API signalCode(不是 signalDescription)
- 强制 SIGKILL 路径对 stubborn 进程有效
- 进程退出时立即清除超时定时器
#### 6. 并行实例支持
- 在主进程添加 TEST_MODE 环境变量检查
- 绕过单实例锁允许多个 Electron 实例
- 跳过遗留迁移保护用户数据
- 每个实例自动分配不同的 CDP 端口和数据目录
### 文件变更
- `electron/main/index.ts`:
* 添加 TEST_MODE 检查,绕过单实例锁
* 添加 CHATLAB_E2E_USER_DATA_DIR 读取和隔离
* **新增**:跳过 E2E 模式下的遗留迁移
- `tests/e2e/helpers/app-launcher.js`: 完整的应用启动管理模块(260+ 行)
* **新增**:port 预留机制,防止 TOCTTOU 竞态
### 使用示例
```javascript
const { launchApp } = require('./tests/e2e/helpers/app-launcher')
// 启动应用(自动查找可用端口和独立数据目录)
const app = await launchApp()
console.log('CDP 端口:', app.port)
// 运行测试...
// 关闭应用(已退出进程快速返回)
await app.close()
```
### 可配置选项
```javascript
await launchApp({
port: 9222, // 指定端口,默认自动查找(带预留)
userDataDir: '/custom/path', // 自定义用户数据目录
startupWaitTime: 2000 // 启动等待时间(毫秒),默认 2000
})
```
### 并行测试场景
✅ 多个实例同时运行(每个实例独立端口和数据目录)
✅ 自动端口分配(9222, 9223, 9224...)
✅ **端口预留防止竞态**(同时启动无冲突)
✅ 自动数据隔离(/tmp/chatlab-e2e-9222, /tmp/chatlab-e2e-9223...)
✅ 资源正确清理(无泄漏)
✅ 启动失败快速失败(清晰诊断)
✅ 进程强制清理(防止僵尸进程)
✅ 慢速 CI 环境中不挂起
✅ Stubborn 进程能被正确杀死
✅ 已退出进程快速检测和返回
✅ 信号退出的进程也能快速返回
✅ 无共享状态,支持真正的并行测试
✅ 用户数据受保护,不会被测试污染
### 修复的关键问题
**P1 问题:**
- 端口扫描超时导致的无限挂起
- 进程强制杀死被 proc.killed 误导的竞态条件
- 启动期间的早期退出未被检测
- 并行 E2E 实例共享 userData 导致冲突
- **新增**:遗留迁移在 E2E 模式下可能删除用户数据
- **新增**:端口分配 TOCTTOU 竞态导致启动冲突
**P2 问题:**
- 慢速 CI 中的 listen 回调延迟
- close() 对已退出进程的 5 秒不必要延迟
- signalCode API 错误
- 信号终止的启动失败未被检测
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Rediscover your social memories with private, AI-powered analysis.
Official Website · Download · Documentation · Roadmap · Issue Submission
ChatLab is an open-source desktop app for understanding your social conversations. It combines a flexible SQL engine with AI agents so you can explore patterns, ask better questions, and extract insights from chat data, all on your own machine.
Currently supported: WhatsApp, LINE, WeChat, QQ, Discord, Instagram, and Telegram. Coming next: iMessage, Messenger, and KakaoTalk.
Core Features
- 🚀 Built for large histories: Stream parsing and multi-worker processing keep imports and analysis responsive, even at million-message scale.
- 🔒 Private by default: Your chat data and settings stay local. No mandatory cloud upload of raw conversations.
- 🤖 AI that can actually operate on data: Agent + Function Calling workflows can search, summarize, and analyze chat records with context.
- 📊 Insight-rich visual views: See trends, time patterns, interaction frequency, rankings, and more in one place.
- 🧩 Cross-platform normalization: Different export formats are mapped into a unified model so you can analyze them consistently.
Usage Guides
Preview
For more previews, please visit the official website: chatlab.fun
System Architecture
Architecture Principles
- Local-first by default: Raw chat data, indexes, and settings remain on-device unless you explicitly choose otherwise.
- Streaming over buffering: Stream-first parsing and incremental processing keep large imports stable and memory-efficient.
- Composable intelligence: AI features are assembled through Agent + Tool Calling, not hard-coded into one model path.
- Schema-first evolution: Import, query, analysis, and visualization share a consistent data model that scales with new features.
Runtime Architecture
- Main Process (control plane):
electron/main/index.tshandles lifecycle and windows.electron/main/ipc/defines domain-scoped IPC, whileelectron/main/ai/andelectron/main/i18n/provide shared AI and localization services. - Worker Layer (compute plane):
electron/main/worker/runs import, indexing, and query tasks viaworkerManager, keeping CPU-heavy work off the UI thread. - Renderer Layer (interaction plane): Vue 3 + Nuxt UI + Tailwind CSS drive management, private chat, group chat, and analysis interfaces.
electron/preload/index.tsexposes tightly scoped APIs for secure process boundaries.
Data Pipeline
- Ingestion:
parser/detects file format and dispatches to the matching parser module. - Persistence: Stream-based writes populate core local entities: sessions, members, and messages.
- Indexing: Session- and time-oriented indexes are built for timeline navigation and retrieval.
- Query & Analysis:
worker/query/*powers activity metrics, interaction analysis, SQL Lab, and AI-assisted exploration. - Presentation: The renderer turns query output into charts, rankings, timelines, and conversational analysis flows.
Extensibility & Reliability
- Pluggable parser architecture: Adding a new import source is mostly an extension in
parser/formats/*, without reworking downstream query logic. - Full + incremental import paths:
streamImport.tsandincrementalImport.tssupport both first-time onboarding and ongoing updates. - Modular IPC boundaries: Domain-based IPC segmentation reduces cross-layer coupling and limits permission spread.
- Unified i18n evolution: Main and renderer processes share an i18n system that can evolve with product scope.
Local Development
Requirements
- Node.js >= 20
- pnpm
Setup
# install dependencies
pnpm install
# run electron app in dev mode
pnpm dev
If Electron encounters exceptions during startup, you can try using electron-fix:
npm install electron-fix -g
electron-fix start
Contributing
Please follow these principles before submitting a Pull Request:
- Obvious bug fixes can be submitted directly.
- For new features, please submit an Issue for discussion first; PRs submitted without prior discussion will be closed.
- Keep one PR focused on one task; if changes are extensive, consider splitting them into multiple independent PRs.
Privacy Policy & User Agreement
Before using this software, please read the Privacy Policy & User Agreement.
License
AGPL-3.0 License
