#!/usr/bin/env python3 """Install the Codex native adapter files into hidden project directories. The Codex desktop sandbox may block agent-created writes into `.codex` and `.agents/skills`. Run this script locally from the repository root when that happens. """ from __future__ import annotations import argparse import shutil from pathlib import Path REPO_ROOT = Path(__file__).resolve().parent.parent TEMPLATE_ROOT = REPO_ROOT / "codex_adapter_templates" / "codex" CODEX_ROOT = REPO_ROOT / ".codex" AGENTS_SKILLS = REPO_ROOT / ".agents" / "skills" OPENCODE_SKILLS = REPO_ROOT / ".opencode" / "skills" def copy_tree_contents(src: Path, dst: Path, *, force: bool) -> list[Path]: written: list[Path] = [] if not src.exists(): raise SystemExit(f"template source not found: {src}") dst.mkdir(parents=True, exist_ok=True) for item in src.rglob("*"): rel = item.relative_to(src) target = dst / rel if item.is_dir(): target.mkdir(parents=True, exist_ok=True) continue if target.exists() and not force: continue target.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(item, target) written.append(target) return written def main() -> int: parser = argparse.ArgumentParser(description="Install Codex native adapter") parser.add_argument("--force", action="store_true", help="overwrite existing adapter files") parser.add_argument("--skip-skills", action="store_true", help="do not copy .opencode/skills to .agents/skills") args = parser.parse_args() codex_written = copy_tree_contents(TEMPLATE_ROOT, CODEX_ROOT, force=args.force) skills_written: list[Path] = [] if not args.skip_skills: skills_written = copy_tree_contents(OPENCODE_SKILLS, AGENTS_SKILLS, force=args.force) print("Codex adapter installed.") print(f" .codex files written: {len(codex_written)}") print(f" .agents skills files written: {len(skills_written)}") if codex_written: for path in codex_written: print(f" {path.relative_to(REPO_ROOT)}") return 0 if __name__ == "__main__": raise SystemExit(main())