5.7 KiB
5.7 KiB
v1 → v2 迁移 — 开发指南
如何测试、开发和调试迁移流程。
快速入门
# 完整周期:重置 → 迁移 → Claude 完成
bash migrate-v2-reset.sh && bash migrate-v2.sh
架构
两部分迁移:
-
migrate-v2.sh——确定性 bash 脚本。处理前提条件、DB 种子、文件拷贝、频道安装、容器构建、服务切换。写入logs/setup-migration/handoff.json,然后exec到 Claude 中。 -
/migrate-from-v1技能——由 Claude 驱动。读取交接文件,种子 owner/roles,清理 CLAUDE.local.md,验证容器配置,移植 fork 定制。
文件布局
migrate-v2.sh # 入口点
migrate-v2-reset.sh # 清除 v2 状态以重新测试
setup/migrate-v2/
env.ts # 阶段 1a:合并 .env
db.ts # 阶段 1b:种子 v2 DB
groups.ts # 阶段 1c:拷贝 group 目录 + container.json
sessions.ts # 阶段 1d:拷贝 session 并设置续接
tasks.ts # 阶段 1e:移植计划任务
channel-auth.ts # 阶段 2b:拷贝频道认证状态
select-channels.ts # 阶段 2a:clack 多选
switchover-prompt.ts # 服务切换提示
setup/migrate-v2/shared.ts # 共享辅助函数(JID 解析、触发器映射等)
.claude/skills/migrate-from-v1/ # Claude 技能
logs/setup-migration/handoff.json # 由 migrate-v2.sh 写入,由技能读取
logs/migrate-steps/*.log # 每个步骤的原始输出
开发循环
# 重置 v2 到干净状态(保留 node_modules)
bash migrate-v2-reset.sh
# 以非交互式频道选择运行迁移
NANOCLAW_CHANNELS="telegram" bash migrate-v2.sh
# 或以交互方式运行(clack 多选)
bash migrate-v2.sh
migrate-v2-reset.sh 清除:data/、logs/、.env、groups/(恢复 git 跟踪的)、container/skills/(恢复 git 跟踪的)、src/channels/(恢复 git 跟踪的)。
它不清除 node_modules/(重新安装成本高昂)。
测试单个步骤
每个步骤是一个独立的 TypeScript 文件:
# 运行单个步骤(在 pnpm install 之后)
pnpm exec tsx setup/migrate-v2/env.ts /path/to/v1
pnpm exec tsx setup/migrate-v2/db.ts /path/to/v1
pnpm exec tsx setup/migrate-v2/groups.ts /path/to/v1
pnpm exec tsx setup/migrate-v2/sessions.ts /path/to/v1
pnpm exec tsx setup/migrate-v2/tasks.ts /path/to/v1
pnpm exec tsx setup/migrate-v2/channel-auth.ts /path/to/v1 telegram discord
每个步骤向 stdout 打印 OK:<details>、SKIPPED:<reason> 或错误。成功/跳过时退出 0,失败时退出非零值。
调试
检查已迁移的内容
# Agent groups
sqlite3 data/v2.db "SELECT * FROM agent_groups"
# Messaging groups + 连线
sqlite3 data/v2.db "SELECT mg.id, mg.channel_type, mg.platform_id, mg.unknown_sender_policy, mga.engage_mode, mga.engage_pattern FROM messaging_groups mg JOIN messaging_group_agents mga ON mga.messaging_group_id = mg.id"
# Sessions
sqlite3 data/v2.db "SELECT * FROM sessions"
# 用户和角色
sqlite3 data/v2.db "SELECT * FROM users"
sqlite3 data/v2.db "SELECT * FROM user_roles"
# Session 续接(哪个 Claude Code session 将被恢复)
AG_ID=$(sqlite3 data/v2.db "SELECT id FROM agent_groups LIMIT 1")
SESS_ID=$(sqlite3 data/v2.db "SELECT id FROM sessions LIMIT 1")
sqlite3 data/v2-sessions/$AG_ID/$SESS_ID/outbound.db "SELECT * FROM session_state"
# 计划任务
sqlite3 data/v2-sessions/$AG_ID/$SESS_ID/inbound.db "SELECT id, kind, recurrence, status FROM messages_in WHERE kind='task'"
检查交接文件
python3 -m json.tool logs/setup-migration/handoff.json
常见问题
切换后 bot 不响应:
- 检查两个服务都没有运行:
systemctl --user list-units 'nanoclaw*' - 检查错误日志:
tail logs/nanoclaw.error.log - 检查发送者策略:
sqlite3 data/v2.db "SELECT unknown_sender_policy FROM messaging_groups"——在 owner 被种子之前必须是public - 检查触发模式:
sqlite3 data/v2.db "SELECT engage_mode, engage_pattern FROM messaging_group_agents"——应为pattern/.用于响应所有内容
Session 未从 v1 续接:
- 检查是否设置了续接:见上方的"Session 续接"查询
- 检查 JSONL 是否在正确路径下:
ls data/v2-sessions/<ag_id>/.claude-shared/projects/-workspace-agent/ - v1 session JSONL 应从
-workspace-group/拷贝到-workspace-agent/(v2 容器 CWD 为/workspace/agent)
服务切换回退不起作用:
- v2 服务名称为
nanoclaw-v2-<hash>——找到它:systemctl --user list-units 'nanoclaw*' - 手动停止:
systemctl --user stop <unit> && systemctl --user disable <unit> - 重启 v1:
systemctl --user start nanoclaw
步骤日志
每个步骤将原始输出写入 logs/migrate-steps/<step>.log。当某个步骤失败时读取这些日志:
cat logs/migrate-steps/1b-db.log
cat logs/migrate-steps/1d-sessions.log
关键决策
unknown_sender_policy在迁移期间设置为public,以便 bot 立即响应。/migrate-from-v1技能在种子 owner 后收紧此设置。- v1 中
requires_trigger=0优先于非空的trigger_pattern——它意味着"响应所有内容"。 - v1
container_config.additionalMounts直接写入 v2container.json(相同格式)。 - v1 Claude Code session 从
-workspace-group/拷贝到-workspace-agent/,session ID 以continuation:claude写入outbound.db,以便 agent-runner 恢复同一对话。 - 结尾的
exec claude "/migrate-from-v1"替换了 bash 进程——write_handoff在exec之前显式调用,因为 EXIT 陷阱不会在exec时触发。