# Adds setup_gate (+ optional probe / signup_block / add_people) to catalog templates. argv[1] = repo root, argv[2] = JSON spec file. # spec: {app: {"probe": {"url","field","done","why"} | null, "signup_block": "" | null, # "add_people": {"hu": "...", "en": "..."} | null, "why": ""}} import json, os, re, sys R, spec = sys.argv[1], json.load(open(sys.argv[2])) for app, sp in spec.items(): p = os.path.join(R, "templates", app, ".felhom.yml") s = open(p).read() if "\nsetup_gate:" in s: # replace the whole managed block s = re.sub(r"\n# --- The setup gate \(controller.*?(?=\n# --- App info|\napp_info:)", "", s, flags=re.S) block = ["", "# --- The setup gate (controller >= 0.281.0, `09` ยง3 decisions 46-47) ---", "# " + sp.get("why", "The first visitor would create the admin; a fresh install is closed to everyone but the household until the first setup is done."), "setup_gate: true"] pr = sp.get("probe") if pr: block += ["# " + pr["why"], "setup_done_probe:", f" url: {pr['url']}", f" field: {pr['field']}", f" done: \"{pr['done']}\""] if sp.get("signup_block"): block += ["# Decision 47: the app's own sign-up address is closed once the gate opens (" + sp.get("signup_why", "measured on 9202 2026-09-29") + ").", "signup_block: \"" + sp["signup_block"].replace('"', '\\"') + "\""] i = s.index("\n# --- App info") if "\n# --- App info" in s else s.index("\napp_info:") s = s[:i] + "\n".join(block) + "\n" + s[i:] ap = sp.get("add_people") if ap: # Hungarian: into app_info (after docs_url or default_creds or tagline line); English: into i18n.en.app_info s = re.sub(r"(\napp_info:\n(?: [^\n]*\n)*? tagline: [^\n]*\n)", lambda m: m.group(1) + " add_people: " + json.dumps(ap["hu"], ensure_ascii=False) + "\n", s, count=1) s = re.sub(r"(\n en:\n(?: [^\n]*\n)*? app_info:\n tagline: [^\n]*\n)", lambda m: m.group(1) + " add_people: " + json.dumps(ap["en"], ensure_ascii=False) + "\n", s, count=1) assert s.count("add_people:") == 2, app open(p, "w").write(s) print("patched", len(spec), "apps in", R)