43 lines
1.4 KiB
Python
43 lines
1.4 KiB
Python
"""프로젝트 간 공유되는 워크플로우 상태 유틸리티."""
|
|
|
|
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)
|