# /athena-migrate (Codex) — v9.5 → v9.6 迁移 参考 CC 版 `~/.claude/skills/athena-migrate/SKILL.md`. 算法一致 (因为 schema 跨平台相同, 这是铁律 6). Codex 端差异: - 用 python3 替代 node 生成 `_index.md` (Codex 默认有 python3) - 检测 `cx_version` 写入 `platform_features.cx_version`, **不写** cc_version ## 备份脚本 ```bash mkdir -p .ai_state/.legacy-v9.5 cp -r .ai_state/{tasks.md,design.md,progress.md,lessons.md,handoff.md,project.json,reviews,hook-trace.jsonl} .ai_state/.legacy-v9.5/ 2>/dev/null || true ``` ## 创建 details/ ```bash mkdir -p .ai_state/details/reviews .ai_state/details/tasks-archive ``` ## 平移 ```bash [ -f .ai_state/tasks.md ] && mv .ai_state/tasks.md .ai_state/details/tasks-current.md for f in design.md progress.md lessons.md handoff.md; do [ -f .ai_state/$f ] && mv .ai_state/$f .ai_state/details/$f done [ -d .ai_state/reviews ] && mv .ai_state/reviews .ai_state/details/reviews [ -f .ai_state/compact-snapshot.json ] && rm .ai_state/compact-snapshot.json # Codex 无 compact 也能有的旧文件 ``` ## 生成 _index.md (python3) ```bash python3 << 'PY' import json, os, re, sys proj = {} try: with open('.ai_state/.legacy-v9.5/project.json') as f: proj = json.load(f) except FileNotFoundError: pass def count_match(path, pattern): try: with open(path) as f: return len(re.findall(pattern, f.read(), re.MULTILINE)) except FileNotFoundError: return 0 def last_section_line(path, head_prefix='## '): try: lines = open(path).read().split('\n') for i in range(len(lines) - 1, -1, -1): if lines[i].startswith(head_prefix): return i + 1 except FileNotFoundError: pass return 0 def last_nonempty_line(path): try: lines = open(path).read().split('\n') for i in range(len(lines) - 1, -1, -1): stripped = lines[i].strip() if stripped and not stripped.startswith('