utils/repo_contract/isolate.py
Krzysztof kuhy Rudnicki a0fb279b1b agent_ready: AgentReady v2.0 checker + repo_contract web-site gate
New agent_ready/ package (dist and live-url modes, 100% branch coverage)
checks robots, sitemap, llms.txt, ai-catalog, 404, no-JS text, markdown
mirrors and JSON-LD. repo_contract gains web-repo detection and installs the
agent-ready pre-commit hook, CI workflow and check_agent_ready.sh shim;
scripts/check_agent_ready.sh is the shared entry point.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBScELfMUiieK9ManFbS3Y
2026-10-22 21:18:49 +02:00

54 lines
1.9 KiB
Python

"""A throwaway copy of a repo's working tree to run the site build in.
Why: kcd2-dice-solver (and personal-website) bind-mount `dist/` into the live
Caddy container, so a gate that ran `pnpm run build` in the repo emptied the
live site on every commit (Vite's emptyOutDir) and shipped the uncommitted
tree. Building in a copy means no build command, prerender step or outDir
setting can ever write the configured live `dist`.
The copy is the git working tree (tracked + untracked, minus ignored files, so
a stale `dist/` never leaks in) with `node_modules` symlinked, not copied.
Outside git (tests, a bare dir) everything but node_modules/.git is copied.
"""
from __future__ import annotations
import shutil
import subprocess
from pathlib import Path
SKIP = ("node_modules", ".git")
def _git_files(repo: Path) -> list[str]:
"""Working-tree files git would see: tracked + untracked, not ignored."""
out = subprocess.run(
["git", "-C", str(repo), "ls-files", "-z", "--cached", "--others"]
+ ["--exclude-standard"],
capture_output=True,
check=True,
).stdout
return sorted({f.decode() for f in out.split(b"\0") if f})
def populate(repo: Path, dest: Path) -> None:
"""Fill the empty dir `dest` with a build-ready copy of `repo`."""
if (repo / ".git").exists():
for rel in _git_files(repo):
src = repo / rel
if not src.is_file() or rel.split("/")[0] in SKIP:
continue # deleted in the worktree, or a submodule/dep dir
target = dest / rel
target.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(src, target, follow_symlinks=False)
else:
shutil.copytree(
repo,
dest,
symlinks=True,
ignore=shutil.ignore_patterns(*SKIP),
dirs_exist_ok=True,
)
if (repo / "node_modules").is_dir():
(dest / "node_modules").symlink_to(repo / "node_modules")