Files
nanoclaw/docs/zh/migration-dev.md
2026-05-12 13:14:17 +00:00

140 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# v1 → v2 迁移 — 开发指南
如何测试、开发和调试迁移流程。
## 快速入门
```bash
# 完整周期:重置 → 迁移 → Claude 完成
bash migrate-v2-reset.sh && bash migrate-v2.sh
```
## 架构
两部分迁移:
1. **`migrate-v2.sh`**——确定性 bash 脚本。处理前提条件、DB 种子、文件拷贝、频道安装、容器构建、服务切换。写入 `logs/setup-migration/handoff.json`,然后 `exec` 到 Claude 中。
2. **`/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 # 阶段 2aclack 多选
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 # 每个步骤的原始输出
```
## 开发循环
```bash
# 重置 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 文件:
```bash
# 运行单个步骤(在 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失败时退出非零值。
## 调试
### 检查已迁移的内容
```bash
# 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'"
```
### 检查交接文件
```bash
python3 -m json.tool logs/setup-migration/handoff.json
```
### 常见问题
**切换后 bot 不响应:**
1. 检查两个服务都没有运行:`systemctl --user list-units 'nanoclaw*'`
2. 检查错误日志:`tail logs/nanoclaw.error.log`
3. 检查发送者策略:`sqlite3 data/v2.db "SELECT unknown_sender_policy FROM messaging_groups"`——在 owner 被种子之前必须是 `public`
4. 检查触发模式:`sqlite3 data/v2.db "SELECT engage_mode, engage_pattern FROM messaging_group_agents"`——应为 `pattern` / `.` 用于响应所有内容
**Session 未从 v1 续接:**
1. 检查是否设置了续接:见上方的"Session 续接"查询
2. 检查 JSONL 是否在正确路径下:`ls data/v2-sessions/<ag_id>/.claude-shared/projects/-workspace-agent/`
3. v1 session JSONL 应从 `-workspace-group/` 拷贝到 `-workspace-agent/`v2 容器 CWD 为 `/workspace/agent`
**服务切换回退不起作用:**
1. v2 服务名称为 `nanoclaw-v2-<hash>`——找到它:`systemctl --user list-units 'nanoclaw*'`
2. 手动停止:`systemctl --user stop <unit> && systemctl --user disable <unit>`
3. 重启 v1`systemctl --user start nanoclaw`
### 步骤日志
每个步骤将原始输出写入 `logs/migrate-steps/<step>.log`。当某个步骤失败时读取这些日志:
```bash
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` 直接写入 v2 `container.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` 时触发。