#!/usr/bin/env python3 """Export a clean Antigravity-only workspace from a full checkout.""" from __future__ import annotations import argparse import shutil from pathlib import Path REPO_ROOT = Path(__file__).resolve().parent.parent FILES = [ "AGENTS.md", "GEMINI.md", "README.md", "docs/antigravity-clean-workspace.md", "docs/platform-adapters.md", "docs/platform-branch-strategy.md", "scripts/dr.py", "scripts/deploy_adapters.py", "scripts/update_platform_envs.py", ] DIRS = [ "configs", "scripts/runtime", "scripts/reporting", ] ANTIGRAVITY_AGENT_SRC = REPO_ROOT / "platform_adapters" / "antigravity" / "agent" EMPTY_DIRS = [ "projects", ] EXCLUDED_NAMES = { "__pycache__", ".pytest_cache", } def copy_file(src: Path, dst: Path, *, dry_run: bool) -> None: if dry_run: print(f"file {src.relative_to(REPO_ROOT)} -> {dst}") return dst.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(src, dst) def ignore_names(_: str, names: list[str]) -> set[str]: return {name for name in names if name in EXCLUDED_NAMES} def copy_dir(src: Path, dst: Path, *, dry_run: bool) -> None: if dry_run: print(f"dir {src.relative_to(REPO_ROOT)} -> {dst}") return if dst.exists(): shutil.rmtree(dst) shutil.copytree(src, dst, ignore=ignore_names) def export_workspace(target: Path, *, force: bool, dry_run: bool) -> None: target = target.expanduser().resolve() if target == REPO_ROOT: raise SystemExit("target must not be the full repository root") if target.exists() and any(target.iterdir()) and not force: raise SystemExit(f"target is not empty: {target}; use --force to replace managed files") if not dry_run: target.mkdir(parents=True, exist_ok=True) for rel in FILES: src = REPO_ROOT / rel if not src.exists(): raise FileNotFoundError(src) copy_file(src, target / rel, dry_run=dry_run) for rel in DIRS: src = REPO_ROOT / rel if not src.exists(): raise FileNotFoundError(src) copy_dir(src, target / rel, dry_run=dry_run) if not ANTIGRAVITY_AGENT_SRC.exists(): raise FileNotFoundError(ANTIGRAVITY_AGENT_SRC) copy_dir(ANTIGRAVITY_AGENT_SRC, target / ".agent", dry_run=dry_run) for rel in EMPTY_DIRS: if dry_run: print(f"dir {rel} -> {target / rel}") else: (target / rel).mkdir(parents=True, exist_ok=True) keep = target / rel / ".gitkeep" keep.touch(exist_ok=True) if not dry_run: print(f"exported clean Antigravity workspace: {target}") print("open this target directory in Antigravity") def build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(description="Export a clean Antigravity-only workspace") parser.add_argument("--target", required=True, type=Path, help="output workspace directory") parser.add_argument("--force", action="store_true", help="replace managed files in a non-empty target") parser.add_argument("--dry-run", action="store_true", help="show what would be copied") return parser def main() -> int: args = build_parser().parse_args() export_workspace(args.target, force=args.force, dry_run=args.dry_run) return 0 if __name__ == "__main__": raise SystemExit(main())