"""프로젝트 간 공유되는 워크플로우 상태 유틸리티.""" import json import threading from pathlib import Path from typing import Any from common_util.common_util_json import atomic_write_json _WORKFLOW_LOCK = threading.Lock() def load_project_workflow(project_root: str | Path) -> dict[str, Any]: """프로젝트 루트의 workflow.json을 읽고 없으면 초기 상태를 반환한다.""" workflow_path = Path(project_root) / "workflow.json" if not workflow_path.exists(): return { "current_stage": "scan", "completed": [], "stale_from": None, "stage1_confirmed": None, } with workflow_path.open("r", encoding="utf-8") as workflow_file: workflow = json.load(workflow_file) if not isinstance(workflow, dict): raise ValueError("workflow.json의 최상위 값은 객체여야 합니다.") return workflow def patch_project_workflow_stale(project_root: str | Path, stale_from: str | None) -> None: """기존 workflow.json의 다른 상태를 보존하며 stale_from만 갱신한다.""" workflow_path = Path(project_root) / "workflow.json" if not workflow_path.exists(): return with _WORKFLOW_LOCK: workflow = load_project_workflow(project_root) if workflow.get("stale_from") == stale_from: return workflow["stale_from"] = stale_from atomic_write_json(workflow_path, workflow)