Skip to content

About

导出或迁移 ZCode 会话。 Export or migrate ZCode sessions.

Resources

Stars

8 stars

Watchers

0 watching

Forks

Latest commit

 

History

8 Commits

Folders and files

Repository files navigation

zcode-export

English

几个相互独立的小工具:zcode_export.py 把 ZCode 聊天历史导出为可读档案(Markdown / JSON);zcode_to_opencode.py 直接把 ZCode 会话迁移到 OpenCode。二者互不依赖。另有 zcode_import.py 负责把旧版 ZCode 会话快照恢复到现在版本(在这个脚本组中是用来把 zcode_export.py 导出的会话重新导入用的)。

背景

ZCode 与 OpenCode 的数据格式高度一致(会话/消息/部件三类表、sess_ / msg_ / part_ 的 ID 前缀、消息 JSON 结构几乎相同),因此可以直接复用 OpenCode 生态的存储与导入能力。本仓库提供三个脚本:

  • zcode_export.py:从 zcode 数据库只读导出会话,生成可读的 Markdown、结构化 JSON,或 opencode 原生导入格式。
  • zcode_to_opencode.py:把 zcode 会话导入 opencode(数据库 + 项目/目录绑定),并记录导入状态。
  • zcode_import.py:把旧版 ZCode 会话快照恢复到新版数据库(混合后端,官方插件优先、Python 移植回退)。

这些脚本都是纯 Python 标准库实现;只需 Python 3.7+ 。

数据来源

两个脚本都以只读方式(?mode=ro)连接 ZCode 的 SQLite 数据库:

~\.zcode\cli\db\db.sqlite

脚本不会写入或修改 ZCode 数据库。

环境要求

依赖 是否必需 用途
Python 3.7+ 必需 运行脚本(纯标准库,无第三方依赖)
opencode CLI 仅导入时必需 真正执行导入;导出脚本只用它读取版本号(缺失时自动回退为 "2")
git 仅 git 目录需要 仅当会话目录属于 git 仓库时,用于解析项目 ID

工具一:zcode_export.py —— 导出

python zcode_export.py list
python zcode_export.py export <编号|会话ID> [all] [-t <格式>] [--out <目录>]

列出会话

python zcode_export.py list

按时间升序列出全部会话:编号、时间、消息数、标题与 zcode 会话 ID。

导出

按编号或 ID 导出(可多个):

python zcode_export.py export 2 5
python zcode_export.py export all
python zcode_export.py export sess_4c94759e-b5f6-4d37-9124-abc69a65f643

用 -t / --type 选择输出格式(可多选,逗号或空格分隔;不给出时默认 md,json):

python zcode_export.py export 2 -t opencode
python zcode_export.py export all -t md,json
python zcode_export.py export 2 -t md,opencode --out D:\backup
python zcode_export.py export 2 -t snapshot

四种格式,每个会话生成同名前缀的一组文件:

格式 文件名 说明
md <时间>_<标题>.md 可读的完整对话记录,含思考过程(> THINKING: 引用块)与工具调用摘要
json <时间>_<标题>.json 完整结构化数据,保留每条消息原始信息和全部 part(含 part ID)
opencode <时间>_<标题>.opencode.json opencode 原生导入格式,便于将来从档案恢复会话;日常迁移请直接用 zcode_to_opencode.py
snapshot <workspaceHash>/<会话ID>.json ZCode 旧版快照格式(meta + messages),配合 zcode_import.py 恢复,见「工具三」

默认输出到命令执行时所在的工作目录;--out 可指定其他目录。snapshot 格式的 --out 目录即作为旧版快照根(--legacy-dir),便于直接交给 zcode_import.py 导入。

工具二:zcode_to_opencode.py —— 转换 ZCode 会话并导入 OpenCode

注意:zcode_to_opencode.py 是一个独立运行的转换脚本:它直接从 ZCode 数据库读取会话,一次性完成“格式转换 → opencode import → 项目/目录绑定”,无需事先运行 zcode_export.py。

python zcode_to_opencode.py list
python zcode_to_opencode.py import <编号|会话ID> [--with-children]
python zcode_to_opencode.py import all
python zcode_to_opencode.py status

查看导入状态

python zcode_to_opencode.py list      # 会话列表 + 是否已导入
python zcode_to_opencode.py status    # 查看 zcode ID → opencode ID 的完整映射

导入状态保存在 zcode-import-state.json,脚本会记录每个会话的导入结果,已导入的会话自动跳过,重复执行也不会产生重复数据。

导入

python zcode_to_opencode.py import 2 5
python zcode_to_opencode.py import all
  • 支持 --with-children:subagent_child 类型的会话会与其父会话一并导入,并保持父子嵌套关系。
  • 每个目标会话独立处理(try/except 隔离),单个失败不影响其他会话。

导入做了什么

  1. 读取会话消息,构造 opencode 原生导入 JSON(生成 ses_/msg_/prt_ 形式的 ID,沿用原 msg_ ID,重排 part ID)。
  2. 调用 opencode import 写入 opencode 数据库。
  3. 立即把导入结果写入状态文件,就算后续步骤中途失败,也不会重复导入。
  4. 按 move-session 规则重绑项目的 project_id / directory / path。

工具三:zcode_import.py —— 导入会话到 ZCode

zcode_import.py 把 ZCode 旧版 ACP 时代的会话快照(sess_*.json,通常在 ~/.zcode/v2/sessions 或导出根目录下)恢复到新版 ZCode 的数据库(tasks-index + CLI session 库)。它是混合后端:默认优先调用官方插件的 node 脚本,环境不可用时自动回退到内置的纯 Python 移植(行为与官方几乎一致)。纯 Python 后端只需 Python 3.7+ 标准库。

python zcode_import.py list [--legacy-dir DIR] [--agent A] [--workspace W]
                            [--query Q] [--conversation ID] [--limit N] [--json]
python zcode_import.py status [同 list 的过滤/目录选项]
python zcode_import.py import <快照路径, ...> | <序号, ...> | <目录> | all
                             [--legacy-dir DIR] [--task-index PATH] [--cli-db PATH]
                             [--dry-run] [--show] [--no-show] [--backup]
python zcode_import.py unarchive <taskId, ...> | all [--task-index PATH]

核心概念:固定编号

list 的 # 列是一个与过滤无关的全局编号,它对 --legacy-dir 下全部快照按 updatedAt 降序统一编号(跨官方 / python 后端一致)。因此:

  • import <n> 直接用这个编号定位快照,不受任何过滤 / --limit 影响。即便先用了 --query / --agent 筛选,import 的序号仍指"全库第 n 个",可稳定依赖。
  • 带过滤时列表可能跳号(比如只显示 2, 5, 8),这是有意设计:编号始终指全局位置。
  • 序号、文件路径、目录、all 四种目标可混合使用。

列出 / 查看状态

python zcode_import.py list                          # 会话列表(含全局 # 与各会话状态)
python zcode_import.py list --query "testfile"       # 按标题/消息内容/ID 过滤
python zcode_import.py list --limit 10 --json        # 截断显示 / JSON 输出
python zcode_import.py status                        # 汇总:按 agent 与恢复状态分组

每一行会显示该会话的恢复状态:ready(双库就绪)、needs-cli-db / needs-task-index / needs-full-import(缺哪补哪)。

导入

python zcode_import.py import 1                     # 按全局编号导入第 1 个快照
python zcode_import.py import 1 3 5                 # 多个
python zcode_import.py import a7b9685c5488          # 直接给工作区目录(递归展开 sess_*.json)
python zcode_import.py import .                     # 导出根目录(多工作区 hash 子目录)
python zcode_import.py import all                   # 全部
python zcode_import.py import sess_xxx.json         # 或直接给单个快照文件

几个关键选项:

  • --dry-run:只打印将要执行的内容,不写任何库。
  • --show / --no-show(默认 --show):导入成功后自动把任务设为可见(archived=0, deleted=0, pinned=0, unread_at=now)。ZCode 的任务列表只显示 deleted=0 的行,且会自动归档旧的已完成会话,所以不加可见处理会让刚恢复的老会话从 App 里"消失"。--no-show 关闭。
  • --backup(默认关闭):保留导入前对两个数据库的时间戳备份。官方后端每次导入本就强制生成备份——不加 --backup 时会在导入成功后删除本次生成的备份(如同从未备份),导入失败时则保留;加 --backup 则始终保留。Python 后端不加 --backup 时根本不生成备份。
  • --legacy-dir DIR:快照根目录(默认 ~/.zcode/v2/sessions),import 的序号 / 目录展开基于它。

先导出,再导入(往返迁移)

zcode_import.py 既能恢复官方旧库里的原生快照,也能导入 zcode_export.py 导出的 snapshot 格式,从而形成完整的备份 / 迁移闭环:

python zcode_export.py export 2 5 -t snapshot            # 1. 先把会话导出为旧版快照
python zcode_import.py import <导出目录> --legacy-dir .  # 2. 再把快照恢复到新版 ZCode 。

要点:

  • zcode_export.py -t snapshot 的产出布局是 <workspaceHash>/<会话>.json,正是 zcode_import.py import <目录> 可直接递归展开的形式,也是官方 scanner 扫描的两层结构。
  • zcode_export.py --with-children 会连同 subagent_child 后代一并导出;snapshot 格式保留 forkedFromTaskId,保证分叉树在新库中完整重建。
  • 因此仓库内 export 与 import 互为逆操作,适合备份、迁移与换机场合。
  • zcode_export.py 一般输出目录是当前目录,而 zcode_import.py 脚本默认从 ZCode 的旧版会话目录读取,需要 --legacy-dir . 选项指定程序从当前目录读取。

取消隐藏

默认导入时会自动取消隐藏,如果导入后找不到可以尝试手动。

python zcode_import.py unarchive all                        # 把任务索引里所有任务设为可见
python zcode_import.py unarchive sess_xxx...                # 只处理指定 taskId

unarchive 只清理任务索引里已有的隐藏标记,不做任何导入。

有关 OpenCode 的核心机制

转换为 opencode 导入格式

opencode import 只能识别 opencode 原生导出结构:

{
  "info": { "id": "ses_...", "slug": "...", "title": "...", "version": "...", "time": {...}, ... },
  "messages": [
    { "info": { "id": "msg_...", "sessionID": "ses_...", ... },
      "parts": [ { "id": "prt_...", "sessionID": "ses_...", "messageID": "msg_...", ... } ] }
  ]
}

转换时自动处理这些差异:

  • ID 前缀:消息必须以 msg_ 开头(zcode 原 ID 即可),part 必须以 prt_ 开头(zcode 的是 part_,需重排),会话必须以 ses_ 开头。
  • 未知 part 类型:zcode 的 timeline、compaction 等不符合 opencode schema,导入时被过滤,只保留 text / reasoning / tool / step-start / step-finish。
  • error 字段:zcode 标记失败尝试的错误对象(如 AiSdkModelAdapterError)会让 schema 校验失败,导入前删除。
  • 任一消息或 part 校验不通过,整个导入会失败,因此转换严格对齐 schema。

项目 / 目录绑定(move-session 规则)

opencode import 会把会话绑定到执行命令时的当前目录,而不是文件里写的目录。因此导入脚本在写入后立即重绑。绑定规则:

  • 会话 path = 目录去掉盘符后的正斜杠路径。

  • 非 git 目录 → 项目为 global,path 为相对路径。

  • git 目录 → 按优先级解析项目:

    1. 已存在且 worktree 相同的项目;
    2. sha1("git-remote:<标准化后的 remote>");
    3. .git/opencode 缓存;
    4. 仓库根提交哈希。

    项目行缺失时自动注册。

会话层级

  • zcode 的普通会话(interactive)和分叉会话(fork)导入 OpenCode 后为根会话,出现在 /session 顶层列表。
  • 子代理会话(subagent_child)保留 parentID 嵌套在父会话下,不在顶层列表显示——这与 opencode 原生行为一致。

注意事项

  • 建议导入前完全退出相应程序的实例。运行中的旧实例会缓存数据并在退出时回写,可能覆盖或"复活"刚导入/删除的会话。
  • Windows 下 Python 的 subprocess 找不到 opencode 时,请确保 opencode.exe 或 opencode.cmd 在 PATH 中。
  • zcode_import.py 如果使用官方导入脚本作为后端,需要 node 版本 >= 22.5 。

目录结构

zcode-export/
├── README.md
├── zcode_export.py           # 导出脚本(md / json / opencode)
├── zcode_to_opencode.py      # 导入脚本(zcode → opencode)
├── zcode_import.py           # 恢复脚本(旧版快照 → 新版 ZCode)
└── zcode-import-state.json   # 导入状态(用于避免重复导入,已 gitignore)

About

导出或迁移 ZCode 会话。 Export or migrate ZCode sessions.

Resources

Stars

8 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages