#!/usr/bin/env python3 """Junta as partes de uma estratégia de marca num único markdown. Uso: montar.py --partes DIR --intro intro.md --briefing briefing-llm.md --config marca.json --out estrategia.md [--glossario glossario.md] [--complementos complementos.md] [--historico historico.md] - DIR contém parte-I.md ... parte-VIII.md (só os capítulos, `## N. Título`). - intro.md: resumo executivo + "Sobre este documento" (títulos `# ...`). - briefing-llm.md: a secção `## BRIEFING-LLM` completa (fica sempre em último). - marca.json: chaves `frontmatter` (dict) e, opcional, `partes` ([[romano, nome], ...]). Gera o anexo A (pontos a validar) a partir das marcas `[a validar: ...]`. """ import argparse, json, os, re, sys PARTES = [["I", "Contexto"], ["II", "Fundamentos da marca"], ["III", "Públicos"], ["IV", "Identidade e expressão"], ["V", "Oferta e venda"], ["VI", "Comunicação e canais"], ["VII", "Crescimento"], ["VIII", "Medição e implementação"]] def yaml_value(v): if isinstance(v, list): return "[" + ", ".join(str(x) for x in v) + "]" s = str(v) return '"' + s.replace('"', '\\"') + '"' if re.search(r"[:#®·\-]", s) else s def main(): ap = argparse.ArgumentParser() ap.add_argument("--partes", required=True) ap.add_argument("--intro", required=True) ap.add_argument("--briefing", required=True) ap.add_argument("--config", required=True) ap.add_argument("--out", required=True) ap.add_argument("--glossario") ap.add_argument("--complementos") ap.add_argument("--historico") a = ap.parse_args() cfg = json.load(open(a.config, encoding="utf-8")) fm = "---\n" + "".join(f"{k}: {yaml_value(v)}\n" for k, v in cfg.get("frontmatter", {}).items()) + "---\n\n" doc = [fm, open(a.intro, encoding="utf-8").read().rstrip() + "\n\n"] for rom, nome in cfg.get("partes", PARTES): p = os.path.join(a.partes, f"parte-{rom}.md") if not os.path.exists(p): sys.exit(f"Falta {p}") t = open(p, encoding="utf-8").read().strip() if re.search(r"^# ", t, re.M): sys.exit(f"{p} tem títulos de nível 1; só o montar.py escreve as Partes") doc.append(f"# Parte {rom}. {nome}\n\n{t}\n\n") full = "".join(doc) pend, cap, seen, rows = [], None, set(), [] for line in full.split("\n"): m = re.match(r"^## (\d+)\. ", line) if m: cap = int(m.group(1)) for v in re.findall(r"\[a validar:\s*([^\]]+)\]", line): pend.append((cap or 0, v.strip().rstrip("."))) for c, v in pend: if (c, v.lower()) in seen: continue seen.add((c, v.lower())) rows.append(f"| {c or '—'} | {v[0].upper() + v[1:]} |") anexos = ["# Anexos\n\n## A. Pontos a validar\n\n", f"{len(rows)} pontos, por capítulo. Cada ponto fechado corrige-se no capítulo e sai desta lista.\n\n", "| Cap. | O que falta confirmar |\n| --- | --- |\n", "\n".join(rows) or "| — | Nenhum |", "\n\n"] extras = [(t, f) for t, f in [("Glossário", a.glossario), ("Complementos do sector", a.complementos), ("Histórico de alterações", a.historico)] if f] for letra, (titulo, f) in zip("BCD", extras): anexos.append(f"## {letra}. {titulo}\n\n" + open(f, encoding="utf-8").read().strip() + "\n\n") full += "".join(anexos) br = open(a.briefing, encoding="utf-8").read().strip() if not br.startswith("## BRIEFING-LLM"): sys.exit("briefing-llm.md tem de começar por '## BRIEFING-LLM'") full += br + "\n" open(a.out, "w", encoding="utf-8").write(full) caps = len(re.findall(r"^## \d+\. ", full, re.M)) print(f"{a.out}: {len(full.split())} palavras, {caps} capítulos, {len(rows)} pontos a validar") if __name__ == "__main__": main()