#!/usr/bin/env python3 """Render a project-specific controller prompt from the reusable template.""" from __future__ import annotations import argparse import json from pathlib import Path import re import sys TEMPLATE = Path(__file__).resolve().parent.parent / "templates/ORCHESTRATOR-PROMPT.template.md" PLACEHOLDER = re.compile(r"\{\{([A-Z][A-Z0-9_]*)\}\}") def render(template: str, profile: dict[str, str]) -> str: keys = set(PLACEHOLDER.findall(template)) missing = sorted(keys - profile.keys()) if missing: raise ValueError("missing profile values: " + ", ".join(missing)) for key in keys: if not isinstance(profile[key], str) or not profile[key].strip(): raise ValueError(f"{key} must be a nonempty string") result = PLACEHOLDER.sub(lambda match: profile[match.group(1)], template) if PLACEHOLDER.search(result): raise ValueError("profile values must not contain template placeholders") return result def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("profile", type=Path) parser.add_argument("--output", type=Path) args = parser.parse_args() profile = json.loads(args.profile.read_text()) if not isinstance(profile, dict): parser.error("profile must be a JSON object") content = render(TEMPLATE.read_text(), profile) if args.output: args.output.write_text(content) print(args.output) else: sys.stdout.write(content) return 0 if __name__ == "__main__": raise SystemExit(main())