#!/usr/bin/env python3 import json, datetime, sys p = json.load(open("projects.json")) today = datetime.date.today().isoformat() def norm(s): return (s or "").strip() projects = p.get("projects", []) if not isinstance(projects, list): print("ERROR: projects.json must contain a top-level 'projects' array", file=sys.stderr) sys.exit(2) for i, pr in enumerate(projects): if not isinstance(pr, dict): raise SystemExit(f"ERROR: project[{i}] is not an object") if not norm(pr.get("name")): raise SystemExit(f"ERROR: project[{i}] missing name") st = norm(pr.get("status")) if st not in ("active","paused","archived"): raise SystemExit(f"ERROR: invalid status '{st}' for {pr.get('name')} (allowed: active|paused|archived)") p["last_updated"] = today def section(title, items): out = [f"## {title}\n\n"] if not items: out.append("- (none)\n\n") return out for pr in sorted(items, key=lambda x: x["name"].lower()): out.append(f"- Project: {pr['name']}\n") out.append(f" Status: {pr.get('status','')}\n") if pr.get("type"): out.append(f" Type: {pr['type']}\n") if pr.get("repo"): out.append(f" Repo: {pr['repo']}\n") if pr.get("local_path"): out.append(f" Local Path: {pr['local_path']}\n") if pr.get("notes"): out.append(f" Notes: {pr['notes']}\n") out.append("\n") return out active = [x for x in projects if x.get("status") == "active"] paused = [x for x in projects if x.get("status") == "paused"] archived = [x for x in projects if x.get("status") == "archived"] md = [] md.append("# Projects Index\n\n") md.append("This file is generated from projects.json. Do not edit manually.\n\n") md.append(f"Last Updated: {p['last_updated']}\n\n") md += section("Active Projects", active) md += section("Paused Projects", paused) md += section("Archived Projects", archived) open("PROJECTS_INDEX.md","w").write("".join(md)) json.dump(p, open("projects.json","w"), indent=2, sort_keys=False) print("OK: rendered PROJECTS_INDEX.md")