68 lines
3.1 KiB
Python
68 lines
3.1 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
import json
|
||
|
|
import os
|
||
|
|
import shutil
|
||
|
|
import stat
|
||
|
|
import tempfile
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
THREAD_ID = "01a04eae-6afc-7733-be52-96ddaf6176a1"
|
||
|
|
STATE = Path("/Users/bingshuolingdianyuanhe/.codex/.codex-global-state.json")
|
||
|
|
ARTIFACT = Path("/Volumes/JZAO/铸渊-ICE-GL-ZY001/ZCODE-DEV-20260830/zcode-zc001-legacy-thread-closeout-20260830")
|
||
|
|
BACKUP = ARTIFACT / "codex-global-state.before-projectless-repair.json"
|
||
|
|
|
||
|
|
OLD_ROOT = "/Users/bingshuolingdianyuanhe/Documents/Codex"
|
||
|
|
OLD_OUTPUT = "/Users/bingshuolingdianyuanhe/Documents/Codex/2026-08-30/new-chat/outputs"
|
||
|
|
NEW_ROOT = "/Volumes/JZAO/冰朔-应用数据/Codex-文稿工作区"
|
||
|
|
NEW_OUTPUT = "/Volumes/JZAO/冰朔-应用数据/Codex-文稿工作区/2026-08-30/new-chat/outputs"
|
||
|
|
|
||
|
|
for path in (NEW_ROOT, NEW_OUTPUT):
|
||
|
|
if not os.path.isdir(path):
|
||
|
|
raise SystemExit(f"target is not a directory: {path}")
|
||
|
|
if os.path.realpath(path) != path:
|
||
|
|
raise SystemExit(f"target is not a canonical real path: {path} -> {os.path.realpath(path)}")
|
||
|
|
|
||
|
|
raw = STATE.read_text()
|
||
|
|
data = json.loads(raw)
|
||
|
|
electron = data.get("electron-persisted-atom-state", {})
|
||
|
|
roots_container = electron if "thread-workspace-root-hints" in electron else data
|
||
|
|
outputs_container = electron if "thread-projectless-output-directories" in electron else data
|
||
|
|
roots = roots_container["thread-workspace-root-hints"]
|
||
|
|
outputs = outputs_container["thread-projectless-output-directories"]
|
||
|
|
|
||
|
|
before = {"workspace_root": roots.get(THREAD_ID), "output_directory": outputs.get(THREAD_ID)}
|
||
|
|
if before == {"workspace_root": NEW_ROOT, "output_directory": NEW_OUTPUT}:
|
||
|
|
print(json.dumps({"outcome": "ALREADY_REPAIRED", "thread_id": THREAD_ID, "mapping": before}, ensure_ascii=False))
|
||
|
|
raise SystemExit(0)
|
||
|
|
if before != {"workspace_root": OLD_ROOT, "output_directory": OLD_OUTPUT}:
|
||
|
|
raise SystemExit(f"unexpected mapping; refusing overwrite: {before!r}")
|
||
|
|
|
||
|
|
ARTIFACT.mkdir(parents=True, exist_ok=True)
|
||
|
|
if not BACKUP.exists():
|
||
|
|
shutil.copy2(STATE, BACKUP)
|
||
|
|
|
||
|
|
roots[THREAD_ID] = NEW_ROOT
|
||
|
|
outputs[THREAD_ID] = NEW_OUTPUT
|
||
|
|
|
||
|
|
mode = stat.S_IMODE(STATE.stat().st_mode)
|
||
|
|
fd, temp_name = tempfile.mkstemp(prefix=".codex-global-state.projectless-repair-", dir=STATE.parent)
|
||
|
|
try:
|
||
|
|
with os.fdopen(fd, "w") as stream:
|
||
|
|
json.dump(data, stream, ensure_ascii=False, separators=(",", ":"))
|
||
|
|
stream.flush()
|
||
|
|
os.fsync(stream.fileno())
|
||
|
|
os.chmod(temp_name, mode)
|
||
|
|
os.replace(temp_name, STATE)
|
||
|
|
finally:
|
||
|
|
if os.path.exists(temp_name):
|
||
|
|
os.unlink(temp_name)
|
||
|
|
|
||
|
|
check = json.loads(STATE.read_text())
|
||
|
|
check_electron = check.get("electron-persisted-atom-state", {})
|
||
|
|
check_roots = check_electron if "thread-workspace-root-hints" in check_electron else check
|
||
|
|
check_outputs = check_electron if "thread-projectless-output-directories" in check_electron else check
|
||
|
|
after = {
|
||
|
|
"workspace_root": check_roots["thread-workspace-root-hints"].get(THREAD_ID),
|
||
|
|
"output_directory": check_outputs["thread-projectless-output-directories"].get(THREAD_ID),
|
||
|
|
}
|
||
|
|
print(json.dumps({"outcome": "REPAIRED", "thread_id": THREAD_ID, "before": before, "after": after, "backup": str(BACKUP)}, ensure_ascii=False, indent=2))
|