1from __future__ import annotations2import hashlib, json, subprocess3from pathlib import Path456def sha256_text(s: str) -> str:7 return hashlib.sha256(s.encode()).hexdigest()8910def stable_json(obj) -> str:11 return json.dumps(obj, sort_keys=True, default=str, separators=(",", ":"))121314def git_revision(path: str | Path | None = None) -> str:15 try:16 out = subprocess.run(["git", "rev-parse", "--short", "HEAD"], cwd=path, capture_output=True, text=True, timeout=5)17 dirty = subprocess.run(["git", "status", "--porcelain"], cwd=path, capture_output=True, text=True, timeout=5)18 rev = out.stdout.strip() or "unknown"19 return rev + ("-dirty" if dirty.stdout.strip() else "")20 except Exception:21 return "unknown"22