#!/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" RUNTIME_DIR = TEMPLATE.parent / "runtime" 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 select_runtime(template: str, runtime: str) -> str: if runtime == "service": return template marker = "# 27. HOST CONTROLLER RUNTIME" if template.count(marker) != 1: raise ValueError("controller runtime section is missing or duplicated") prefix = template.split(marker, 1)[0].rstrip() overlay = (RUNTIME_DIR / f"{runtime}.md").read_text().strip() return prefix + "\n\n" + overlay + "\n" def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("profile", type=Path) parser.add_argument("--runtime", choices=("service", "terminal"), default="service") 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(select_runtime(TEMPLATE.read_text(), args.runtime), 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())