"""Nova init scaffolding logic (P1, REQ-325). Creates .nova/ directory structure + secrets-exclusion .gitignore lines in the current working directory. nova/init.py delegates here so the subcommand stays thin (≤50 lines, ≤3 functions). """ from __future__ import annotations from pathlib import Path SECRETS_IGNORE_LINES = ( "~/.nova/credentials.json", ".nova/credentials.json", "*.pem", "*.key", ".env", ".env.*", ) def _ensure_gitignore(root: Path, force: bool) -> None: gi = root / ".gitignore" existing = gi.read_text().splitlines() if gi.is_file() else [] additions = [ln for ln in SECRETS_IGNORE_LINES if ln not in existing] if not additions: return blob = gi.read_text() if gi.is_file() else "" if blob and not blob.endswith("\n"): blob += "\n" blob += "\n".join(additions) + "\n" gi.write_text(blob) def scaffold(root: Path | None = None, force: bool = False) -> int: """Create .nova/ + .nova/contract.yml.attestations/ + .gitignore lines.""" root = root or Path.cwd() nova_dir = root / ".nova" attest_dir = nova_dir / "contract.yml.attestations" if nova_dir.exists() and not force: print(f"refusing: {nova_dir} already exists (use --force to overwrite)") return 1 nova_dir.mkdir(parents=True, exist_ok=True) attest_dir.mkdir(parents=True, exist_ok=True) _ensure_gitignore(root, force) print(f"scaffolded: {nova_dir} (+ {attest_dir.name}/, .gitignore secrets)") return 0 if __name__ == "__main__": raise SystemExit(scaffold())