历史迁徙记录
本文档描述了发生在 v7.1.0(2025 年 12 月)的 PM2 到 Bun 的迁移。如果您是第一次安装 claude-mem,这次迁移已经完成,您可以使用主指南中记录的当前基于 Bun 的系统。
此文档为从 v7.1.0 之前版本升级的用户保留。
PM2到Bun的迁移:完整技术文档
版本: 7.1.0 日期:2025年12月 迁移类型:流程管理(PM2 → Bun) 数据库驱动(better-sqlite3 → bun:sqlite)
执行摘要
Claude-mem 版本 7.1.0 引入了两个主要的架构迁移:
- 进程管理:PM2 → 基于自定义 Bun 的进程管理器
- 数据库驱动:better-sqlite3 npm 包 → bun:sqlite 运行时模块
这两次迁移对最终用户来说都是自动且透明的。在更新到 7.1.0 后第一次触发钩子时,系统会对旧的 PM2 进程执行一次性清理,并过渡到新的架构。
主要好处
- 简化的依赖:移除 PM2 和 better-sqlite3 npm 包
- 改进的跨平台支持:更好的 Windows 兼容性
- 更快的安装:无需本地模块编译
- 内置运行时:利用 Bun 的内置进程管理和 SQLite
- 降低复杂性:自定义 ProcessManager 比 PM2 集成更简单
迁移影响
- 数据保留:用户数据、设置和数据库保持不变
- 自动清理:旧的 PM2 进程自动终止(所有平台)
- 无需用户操作:迁移将在第一次触发挂钩时自动进行
- 向后兼容:SQLite 数据库格式保持不变(仅驱动更改)
架构比较
旧系统(基于 PM2)
组件:PM2(进程管理器 2)
- 软件包:
pm2npm 依赖 - 进程名称:
claude-mem-worker - 管理:外部 PM2 守护进程管理生命周期
- 发现:
pm2 list,pm2 describe命令 - 自动重启:PM2 在崩溃时会自动重启
- 日志:
~/.pm2/logs/claude-mem-worker-*.log - PID 文件:
~/.pm2/pids/claude-mem-worker.pid
生命周期命令:
pm2 start <script> # Start worker
pm2 stop claude-mem-worker # Stop worker
pm2 restart claude-mem-worker # Restart worker
pm2 delete claude-mem-worker # Remove from PM2
pm2 logs claude-mem-worker # View logs痛点:
- 需要额外的 npm 依赖
- PM2 守护进程必须正在运行
- 可能与其他 PM2 进程冲突
- Windows 兼容性问题
- 用于简单用例的复杂配置
组件:better-sqlite3
- 包:
better-sqlite3npm 包(本地模块) - 安装:需要本地编译(node-gyp)
- Windows:需要 Visual Studio 构建工具 Python
- 导入:
import Database from 'better-sqlite3'
安装要求:
- Node.js 开发头文件
- C 编译器(Mac/Linux 上的 gcc/clang,Windows 上的 MSVC)
- Python(用于 node-gyp)
- Windows:Visual Studio 构建工具
新系统(基于 Bun)
组件:自定义 ProcessManager (src/services/process/ProcessManager.ts)
- 包:内置 Bun API(无需外部依赖)
- 进程生成:
Bun.spawn()使用分离模式 - 管理:通过 PID 文件直接控制进程
- 发现:PID 文件 进程存在检查 HTTP 健康检查
- 自动重启:在检测到故障时触发钩子重启
- 日志:
~/.claude-mem/logs/worker-YYYY-MM-DD.log - PID 文件:
~/.claude-mem/.worker.pid - 端口文件:
~/.claude-mem/.worker.port(新建)
生命周期命令:
npm run worker:start # Start worker
npm run worker:stop # Stop worker
npm run worker:restart # Restart worker
npm run worker:status # Check status
npm run worker:logs # View logs核心机制:
PID 文件管理:
- 文件:
~/.claude-mem/.worker.pid - 内容:进程 ID(例如,“35557”)
- 验证:通过
kill(pid, 0)信号检测进程存在
- 文件:
端口文件管理:
- 文件:
~/.claude-mem/.worker.port - 内容:两行(端口号,进程ID)
- 目的:跟踪端口绑定并验证 PID 匹配
- 文件:
健康检查:
- 第1层:PID 文件存在吗?
- 第2层:进程存活吗?(
kill(pid, 0)) - 第3层:HTTP 健康检查 (
GET /health) - 三项都必须通过才能获得“健康”状态
优势:
- 无外部依赖
- 更简单的代码库(直接控制)
- 更好的错误处理和验证
- 平台无关(Bun 处理平台差异)
组件: bun:sqlite
- 软件包:内置于 Bun 运行时(无需 npm 软件包)
- 安装:无需安装(随 Bun ≥1.0 提供)
- 平台:在 Bun 可运行的任何地方均可使用
- 导入:
import { Database } from 'bun:sqlite' - API:类似于 better-sqlite3(同步)
安装要求:
- Bun ≥1.0(如果缺失会自动安装)
- 不需要本地编译
- 无需特定平台的构建工具
兼容性:
- SQLite 数据库格式:未改变
- 数据库文件:
~/.claude-mem/claude-mem.db(相同位置) - 查询语法:相同(两者都使用 SQLite SQL)
迁移机制
一次性PM2清理
迁移系统使用基于标记的方法来确保 PM2 清理仅执行一次。
实施: src/shared/worker-utils.ts:73-86
// Clean up legacy PM2 (one-time migration)
const pm2MigratedMarker = join(DATA_DIR, '.pm2-migrated');
if (!existsSync(pm2MigratedMarker)) {
try {
spawnSync('pm2', ['delete', 'claude-mem-worker'], { stdio: 'ignore' });
// Mark migration as complete
writeFileSync(pm2MigratedMarker, new Date().toISOString(), 'utf-8');
logger.debug('SYSTEM', 'PM2 cleanup completed and marked');
} catch {
// PM2 not installed or process doesn't exist - still mark as migrated
writeFileSync(pm2MigratedMarker, new Date().toISOString(), 'utf-8');
}
}迁移触发点
SessionStart、UserPromptSubmit 或 PostToolUse 钩子使用新的 7.1.0 代码执行
ensureWorkerRunning() 检查 ~/.claude-mem/.worker.pid 是否存在(在更新后的第一次运行中不存在)
Worker 进程未运行 → 调用 startWorker()
检查 ~/.claude-mem/.pm2-migrated 是否存在
执行 pm2 delete claude-mem-worker(忽略错误),创建标记文件
生成新的由 Bun 管理的工作进程,并创建 PID 和端口文件
标记文件
地点: ~/.claude-mem/.pm2-migrated
内容:ISO 8601 时间戳
2025-12-13T00:18:39.673Z目的:
- 一次性迁移标志
- 防止每次启动时重复清理 PM2
- 在重启和重新启动后仍然存在
生命周期:
- 创建:更新到 7.1.0 后的第一个钩子触发(所有平台)
- 更新:从未
- 已删除:从不(用户可以手动删除以强制重新迁移)
用户体验时间线
更新后的第一次会话
这是关键的迁移时刻。该过程大约需要2到5秒。
逐步执行:
- 钩子触发(SessionStart 最常见)
- 工作进程状态检查:没有 PID 文件 → 工作进程未运行
- 迁移检查:没有标记文件 → 运行 PM2 清理
- PM2 清理:
pm2 delete claude-mem-worker(旧工作进程已终止) - 标记创建:带有时间戳的
~/.claude-mem/.pm2-migrated - 新员工开始:Bun 进程已启动,已创建 PID/端口 文件
- 验证:流程检查 HTTP 健康检查
- 钩子完成:Claude Code 会话正常开始
用户可观察行为:
- 首次启动略有延迟(PM2 清理 新工作进程生成)
- 没有错误信息(清理失败将被静默处理)
- Worker 似乎正在通过
npm run worker:status跑动 - 旧的 PM2 工作进程不再在
pm2 list中
后续会议
迁移完成后,每个钩子触发都会遵循快速路径:
- PID 文件存在吗?是
- 进程还活着吗?是
- HTTP 健康检查?成功
- 结果:工作进程已在运行,完成(约50毫秒)
后续会话中不会运行迁移逻辑。
特定平台行为
平台比较
| 功能 | macOS | Linux | Windows |
|---|---|---|---|
| PM2 清理 | 已尝试 | 已尝试 | 已尝试 |
| 标记文件 | 创建 | 创建 | 创建 |
| 进程信号 | POSIX(本地) | POSIX(本地) | Bun 抽象 |
| 臀部支撑 | 全部 | 全部 | 全部 |
| PID 文件 | 是 | 是 | 是 |
| 端口文件 | 是 | 是 | 是 |
| 健康检查 | HTTP | HTTP | HTTP |
| 迁移延迟 | 首次约2-5秒 | 首次约2-5秒 | 首次约2-5秒 |
平台说明
POSIX 信号处理本地支持
Bun 完全支持
不需要特定平台的解决方法
与 macOS 完全相同的行为
POSIX 信号处理
适用于 Ubuntu、Debian、RHEL、CentOS、Arch
Alpine 可能需要 glibc(而不是 musl)
PM2 清理现在运行(由于 try/catch,安全)
Bun 抽象信号处理的差异
Path 模块处理 Windows 分隔符
由 SQLite 处理的文件锁定
可观察到的变化
命令更改
| 旧的 (PM2) | 新的 (Bun) | 备注 |
|---|---|---|
pm2 list | npm run worker:status | 显示 Worker 状态 |
pm2 start <script> | npm run worker:start | 启动 Worker |
pm2 stop claude-mem-worker | npm run worker:stop | 停止 Worker |
pm2 restart claude-mem-worker | npm run worker:restart | 重启工作进程 |
pm2 delete claude-mem-worker | npm run worker:stop | 移除 Worker |
pm2 logs claude-mem-worker | npm run worker:logs | 查看日志 |
pm2 describe claude-mem-worker | npm run worker:status | 详细状态 |
pm2 monit | 无对应项 | PM2特定监控 |
文件位置更改
日志:
Old: ~/.pm2/logs/claude-mem-worker-out.log
~/.pm2/logs/claude-mem-worker-error.log
New: ~/.claude-mem/logs/worker-YYYY-MM-DD.logPID 文件:
Old: ~/.pm2/pids/claude-mem-worker.pid
New: ~/.claude-mem/.worker.pid进程状态:
Old: PM2 daemon memory (pm2 save)
New: ~/.claude-mem/.worker.pid
~/.claude-mem/.worker.port
~/.claude-mem/.pm2-migrated (all platforms)数据库(不变):
Same: ~/.claude-mem/claude-mem.db用户可见的更改
更新前:
$ pm2 list
┌────┬────────────────────┬─────────┬─────────┬──────────┐
│ id │ name │ status │ restart │ uptime │
├────┼────────────────────┼─────────┼─────────┼──────────┤
│ 0 │ claude-mem-worker │ online │ 0 │ 2d 5h │
└────┴────────────────────┴─────────┴─────────┴──────────┘更新后:
$ pm2 list
# Empty - worker no longer managed by PM2
$ npm run worker:status
Worker is running
PID: 35557
Port: 37777
Uptime: 2h 15m孤立文件
迁移后,这些 PM2 文件可能仍然存在(可以安全删除):
~/.pm2/ # Entire PM2 directory
~/.pm2/logs/ # Old logs
~/.pm2/pids/ # Old PID files
~/.pm2/pm2.log # PM2 daemon log
~/.pm2/dump.pm2 # PM2 process dump清理(可选):
# Remove PM2 entirely (if not used for other processes)
pm2 kill
rm -rf ~/.pm2
# Or just remove claude-mem logs
rm -f ~/.pm2/logs/claude-mem-worker-*.log
rm -f ~/.pm2/pids/claude-mem-worker.pid文件系统状态
州目录结构
迁移前(PM2 系统):
~/.claude-mem/
├── claude-mem.db # Database (unchanged)
├── chroma/ # Vector embeddings (unchanged)
├── logs/ # Application logs (unchanged)
└── settings.json # User settings (unchanged)
~/.pm2/
├── logs/
│ ├── claude-mem-worker-out.log
│ └── claude-mem-worker-error.log
├── pids/
│ └── claude-mem-worker.pid
└── pm2.log迁移后(Bun 系统):
~/.claude-mem/
├── claude-mem.db # Database (same file)
├── chroma/ # Vector embeddings (unchanged)
├── logs/
│ └── worker-2025-12-13.log # New log format
├── settings.json # User settings (unchanged)
├── .worker.pid # NEW: Process ID
├── .worker.port # NEW: Port + PID
└── .pm2-migrated # NEW: Migration marker (all platforms)
~/.pm2/ # Orphaned (safe to delete)
├── logs/ # Old logs (no longer written)
├── pids/ # Old PID (no longer updated)
└── pm2.log # PM2 daemon log (not used)边缘情况与故障排除
场景1:迁移失败(PM2仍在运行)
这很少见,但如果 PM2 启用了监视模式或进程被手动重启,就有可能发生。
症状:
pm2 list仍然显示claude-mem-worker- 日志中的端口冲突错误
- Worker 进程无法启动
解析度:
# Manual cleanup
pm2 delete claude-mem-worker
pm2 save # Persist the deletion
# Force re-migration (optional)
rm ~/.claude-mem/.pm2-migrated
# Restart worker
npm run worker:restart场景 2:陈旧的 PID 文件(进程已死)
症状:
npm run worker:status显示“未运行”.worker.pid文件存在- 进程ID不存在
自动恢复:下一个钩子触发器检测到已终止的进程并启动一个新的工作进程。
手动解决:
rm ~/.claude-mem/.worker.pid
rm ~/.claude-mem/.worker.port
npm run worker:start场景 3:端口已被占用
错误: EADDRINUSE: address already in use
解析度:
# Check what's using the port
lsof -i :37777
# Kill the process
kill -9 <PID>
# Restart worker
npm run worker:restart常见错误信息
| 错误 | 原因 | 解决方法 |
|---|---|---|
EADDRINUSE | 端口已被占用 | lsof -i :37777 然后终止冲突的进程 |
No such process | 过期的 PID 文件 | 下次钩子触发时自动清理 |
pm2: command not found | PM2 未安装 | 不需要(错误会被捕获并忽略) |
Invalid port X | 端口验证失败 | 在设置中更新 CLAUDE_MEM_WORKER_PORT |
开发者笔记
测试迁移
# 1. Install old version (with PM2)
git checkout <pre-7.1.0-tag>
npm install && npm run build && npm run sync-marketplace
# 2. Start PM2 worker
pm2 start plugin/scripts/worker-cli.js --name claude-mem-worker
# 3. Update to new version
git checkout main
npm install && npm run build && npm run sync-marketplace
# 4. Trigger hook
node plugin/scripts/session-start-hook.js
# 5. Verify migration
pm2 list # Should NOT show claude-mem-worker
cat ~/.claude-mem/.pm2-migrated # Should exist
npm run worker:status # Should show Bun worker running架构决策
为什么使用自定义 ProcessManager 而不是 PM2?
- 简洁:直接控制,无需外部守护进程
- 依赖项:移除 npm 依赖
- 跨平台:Bun 处理平台差异
- 包大小:减少插件包的大小
- 控制:细粒度的错误处理和验证
为什么使用一次性标记而不是一直运行 PM2 删除?
- 性能:避免不必要的进程生成
- 幂等性:迁移只运行一次
- 调试:时间戳显示迁移发生的时间
- 简洁:清晰的迁移状态
为什么在所有平台上运行 PM2 清理?
- 质量迁移:清理孤立的进程
- 一致性:在所有平台上的行为相同
- 安全性:错误处理已到位(try/catch)
- 没有负面影响:如果未安装 PM2,错误会被捕获并忽略
摘要
从 PM2 迁移到基于 Bun 的进程管理器是一次一次性、自动、透明的过渡,其特点是:
- 移除外部依赖(PM2、better-sqlite3)
- 简化架构(直接过程控制)
- 改善跨平台支持(尤其是 Windows)
- 保留用户数据(数据库、设置、日志保持不变)
- 无需用户操作(首次挂钩触发时自动执行)
关键迁移时刻:更新到 7.1.0 后的首次钩子触发 持续时间:约2-5秒(一次性延迟) 影响:无缝过渡,对用户不可见 回滚:不需要(迁移仅向前,安全)
对于大多数用户来说,迁移将是完全透明的——他们不会看到任何错误,也不会有数据丢失,并且将体验到更高的可靠性和更简单的故障排除。