# 多版本数据迁移

[README](../README.md) · [English](migrations.md)

DSH **设置 → FileSnap → 数据迁移** 是各版本共用的入口。选择任务，点击“扫描旧版数据”，检查会话清单，再点击确认。关闭设置不会撤销已经完成的文件迁移；如中断，重新扫描即可判断剩余工作。


从 0.3.1 起，插件加载时默认自动执行注册的迁移任务（`autoMigrate: true`）。已兼容数据跳过；正在使用的会话留待下一次启动或手动重试。设置页展示本次启动的内存结果，不向对话追加自定义操作日志。共享同一日志目录的多个 DSH 进程应先停止其他实例，或设置 `autoMigrate: false` 后统一手动迁移。

`branch-status-titles-v1` 将会话自身最新的旧 `↩` 标题转为 `🔴 Inactive ·`，通过追加 DSH 原生 `session/title` 事件完成，保留既有事件与分支边界。没有可靠状态信息的普通标题不会被推测为 Active；之后成功的回退与 redo 会设置两端的红绿灯状态。

![数据迁移：选择红绿灯标记迁移任务，扫描后确认会话清单（0.4.0）](../assets/screenshots/v0.4.0/08-migrations.png)

*截图为 0.4.0 演示环境，特意关闭自动迁移以保留待迁移样例。正常安装默认开启自动迁移；图中“自动迁移未运行”不代表默认设置。*

## 本版任务

`legacy-session-events-v1`：旧版插件及早期预览版 → 0.3.0+ 的会话兼容迁移。

旧版把 `filesnap/point`、`filesnap/rewound`、`filesnap/redone` 写进会话，早期文件预览版还写入 `filesnap/reply`。宿主在插件缺席时可能拒绝这些未知事件。迁移为这些历史事件补上 `ignorable: true`，不改变消息、序号、分支继承边界或其他插件的事件。旧记录保留是为维持已有引用；本版不会继续写这些事件，也不会另外保存操作流水。

扫描当前宿主持久化服务中的会话，只支持 JSONL 与 `.jsonl.zstd` 后端。手动扫描不写文件；启动时的自动任务会继续执行带备份的迁移。清单包含待迁移、已加载、失败和不支持的项目；本来就兼容的会话自动跳过。

## 确认与备份

- 确认令牌五分钟有效，只能使用一次。确认时再次核对文件摘要，扫描后变化的日志要求重新扫描。
- 已加载会话不迁移。关闭后重新扫描；如果仍占用，重启 DSH 后先打开设置。迁移期间也会阻止目标会话被同时加载。
- 每份修改过的日志旁保留 `.before-filesnap-migration-<id>` 原始备份。先写临时文件并同步，再原子替换。
- Zstd 日志保留独立的头部压缩帧；不会把多帧日志当成一段文本截断。
- 每个会话单独报告成功、跳过或失败。成功后可再次扫描验证；已完成的任务是幂等的。
- 如需回滚，先停止使用该存储的 DSH，再用所报告的备份替换对应原文件。不要在宿主运行时手工覆盖日志。

## 后续版本如何接入

迁移任务统一注册在 [`src/migrations.ts`](../src/migrations.ts)。每项有稳定任务 id、适用来源/目标版本和幂等变换函数。新增版本迁移复用同一个界面的任务列表、扫描、确认、备份及结果流程，不另加散落按钮。

目前执行器处理独立的会话 JSONL 文件；未来若迁移快照引擎格式或其他存储后端，需要为该数据源增加相应的适配和验证，不能把它冒充成会话日志修复。

## 界面无法启动时

本包还带独立的离线修复工具，不需要加载插件即可处理旧会话。先停止所有使用同一会话目录的 DSH 进程。`--root` 是 **DSH 会话日志目录**，不是 FileSnap 快照目录。

```sh
node lib/migrate-session-logs.js --root /path/to/dsh/sessions
node lib/migrate-session-logs.js --root /path/to/dsh/sessions --write --dsh-stopped
```

第一条只扫描，第二条备份并修复。工具位于已安装插件的 `lib/` 下；也可以在源码仓库运行 `npm run build` 后执行。
