"""Install and remove the GEWU instruction pack without replacing user files.""" from __future__ import annotations import argparse import hashlib import json import os import re import shutil import tempfile from pathlib import Path from typing import Any PACK_ROOT = Path(__file__).resolve().parents[1] PACK_DIR = Path(".agents/gewu") STATE_PATH = Path(".agents/gewu-install.json") MARKER = "" ROUTES = { "AGENTS.md": ( "For knowledge-base research, ingestion, curation, or synthesis, follow " "[the GEWU profile](.agents/gewu/AGENTS.md) and its applicable kb-* skill. " "Use this routing only for those research tasks." ), "CLAUDE.md": ( "For knowledge-base research, ingestion, curation, or synthesis, follow " "[the GEWU profile](.agents/gewu/AGENTS.md) and its applicable kb-* skill." ), "GEMINI.md": ( "For knowledge-base research, ingestion, curation, or synthesis, follow " "[the GEWU profile](.agents/gewu/AGENTS.md) and its applicable kb-* skill." ), } def digest(data: bytes) -> str: return hashlib.sha256(data).hexdigest() def _safe_regular(path: Path) -> bool: return not path.is_symlink() and (not path.exists() or path.is_file()) def _validated_state(state: object) -> dict[str, Any]: if not isinstance(state, dict) or set(state) != { "format", "mode", "pack_path", "files", "routes", }: raise ValueError("unrecognized GEWU installation state") if ( state.get("format") != "gewu-install-state@1" or state.get("mode") not in {"integrated", "dedicated"} or state.get("pack_path") != PACK_DIR.as_posix() ): raise ValueError("unrecognized GEWU installation state") files = state.get("files") if not isinstance(files, dict) or "manifest.json" not in files: raise ValueError("GEWU installation file list is invalid") for relative, expected in files.items(): if ( not isinstance(relative, str) or not relative or "\\" in relative or relative.startswith("/") or any(part in {"", ".", ".."} for part in relative.split("/")) or not isinstance(expected, str) or not re.fullmatch(r"[a-f0-9]{64}", expected) ): raise ValueError("GEWU installation file list is invalid") routes = state.get("routes") if not isinstance(routes, dict) or set(routes) != set(ROUTES): raise ValueError("GEWU installation routes are invalid") for name, route in routes.items(): if ( not isinstance(name, str) or not isinstance(route, dict) or set(route) != {"block_sha256"} or not isinstance(route.get("block_sha256"), str) or not re.fullmatch(r"[a-f0-9]{64}", route["block_sha256"]) ): raise ValueError("GEWU installation routes are invalid") return state def _routing_block(host_file: str, mode: str) -> bytes: qualifier = ( "This workspace is dedicated to research; use GEWU for research tasks." if mode == "dedicated" else ( "Keep existing development instructions; use GEWU only for research tasks." ) ) text = f"\n{MARKER}\n{qualifier} {ROUTES[host_file]}\n\n" return text.encode("utf-8") def _merge_route(existing: bytes, block: bytes) -> bytes: if MARKER.encode() in existing: raise ValueError( "GEWU routing marker already exists; uninstall the recorded installation first" ) return existing + block def _pack_files(source: Path) -> dict[str, Path]: result: dict[str, Path] = {} for path in source.rglob("*"): relative = path.relative_to(source) if any(part in {"__pycache__", ".git"} for part in relative.parts): continue if path.is_symlink(): raise ValueError(f"pack contains a symlink: {relative}") if path.is_file(): result[relative.as_posix()] = path if "manifest.json" not in result: raise ValueError("source is not a GEWU pack (manifest.json missing)") return result def _atomic_write(path: Path, content: bytes) -> None: path.parent.mkdir(parents=True, exist_ok=True) fd, temporary = tempfile.mkstemp(prefix=f".{path.name}.", dir=path.parent) try: with os.fdopen(fd, "wb") as stream: stream.write(content) stream.flush() os.fsync(stream.fileno()) os.replace(temporary, path) finally: if os.path.exists(temporary): os.unlink(temporary) def install(workspace: Path, source: Path = PACK_ROOT, mode: str = "integrated") -> dict[str, Any]: """Copy a pack and append reversible instruction pointers.""" workspace = workspace.resolve() if mode not in {"dedicated", "integrated"}: raise ValueError("mode must be dedicated or integrated") destination = workspace / PACK_DIR state_file = workspace / STATE_PATH agents_dir = workspace / ".agents" if agents_dir.is_symlink(): raise ValueError(".agents must not be a symlink") if ( destination.exists() or destination.is_symlink() or state_file.exists() or state_file.is_symlink() ): raise FileExistsError("GEWU is already installed or the managed destination is occupied") source_files = _pack_files(source.resolve()) targets = {name: workspace / name for name in ROUTES} for target in targets.values(): if not _safe_regular(target): raise ValueError(f"routing target is not a regular file: {target.name}") # Prepare all bytes and validate the destinations before mutating the workspace. copied = {name: path.read_bytes() for name, path in source_files.items()} route_originals = { name: target.read_bytes() if target.exists() else None for name, target in targets.items() } route_blocks = {name: _routing_block(name, mode) for name in ROUTES} route_results = { name: _merge_route(route_originals[name] or b"", route_blocks[name]) for name in ROUTES } state: dict[str, Any] = { "format": "gewu-install-state@1", "mode": mode, "pack_path": PACK_DIR.as_posix(), "files": {name: digest(content) for name, content in copied.items()}, "routes": { name: { "block_sha256": digest(route_blocks[name]), } for name in ROUTES }, } state_bytes = (json.dumps(state, sort_keys=True, indent=2) + "\n").encode() created_destination = False try: destination.mkdir(parents=True) created_destination = True for name, content in copied.items(): target = destination / name target.parent.mkdir(parents=True, exist_ok=True) _atomic_write(target, content) for name, content in route_results.items(): _atomic_write(targets[name], content) _atomic_write(state_file, state_bytes) except BaseException: # A racing installer that failed to create the destination owns nothing. if created_destination: for name, original in route_originals.items(): target = targets[name] if original is None: target.unlink(missing_ok=True) else: _atomic_write(target, original) shutil.rmtree(destination, ignore_errors=True) state_file.unlink(missing_ok=True) raise return state def uninstall(workspace: Path) -> None: """Remove unchanged GEWU-owned files and routing blocks; preserve edits.""" workspace = workspace.resolve() agents_dir = workspace / ".agents" if agents_dir.is_symlink(): raise ValueError(".agents must not be a symlink") state_file = workspace / STATE_PATH if not _safe_regular(state_file) or not state_file.is_file(): raise FileNotFoundError("GEWU installation state is missing or unsafe") if state_file.stat().st_size > 2_000_000: raise ValueError("GEWU installation state is too large") state = _validated_state(json.loads(state_file.read_text(encoding="utf-8"))) conflicts: list[str] = [] destination = workspace / PACK_DIR if destination.is_symlink() or not destination.is_dir(): raise ValueError("GEWU pack destination is missing or unsafe") for relative, expected in state.get("files", {}).items(): target = destination / relative parent = target.parent unsafe_parent = False while parent != destination.parent: if parent.is_symlink() or not parent.is_dir(): unsafe_parent = True break parent = parent.parent if ( unsafe_parent or not target.is_file() or target.is_symlink() or digest(target.read_bytes()) != expected ): conflicts.append(f"edited or missing pack file: {PACK_DIR / relative}") route_data: dict[str, bytes] = {} for name, _route in state.get("routes", {}).items(): target = workspace / name if not _safe_regular(target): conflicts.append(f"unsafe routing file: {name}") continue current = target.read_bytes() if target.exists() else b"" block = _routing_block(name, state["mode"]) if not target.exists() or not current.endswith(block): conflicts.append(f"edited routing block: {name}") route_data[name] = current if conflicts: raise ValueError("uninstall refused to remove changed content: " + "; ".join(conflicts)) # Verify ownership of the exact suffix before removing it. for name, route in state["routes"].items(): block = _routing_block(name, state["mode"]) current = route_data[name] if digest(block) != route["block_sha256"] or not current.endswith(block): raise ValueError(f"routing ownership check failed: {name}") for name, _route in state["routes"].items(): target = workspace / name current = route_data[name] original = current[: -len(_routing_block(name, state["mode"]))] if original: _atomic_write(target, original) else: target.unlink() for relative in sorted(state["files"], key=lambda item: len(Path(item).parts), reverse=True): (destination / relative).unlink() for directory in sorted( (path for path in destination.rglob("*") if path.is_dir() and not path.is_symlink()), key=lambda path: len(path.parts), reverse=True, ): try: directory.rmdir() except OSError: pass try: destination.rmdir() except OSError: pass state_file.unlink() for parent in (workspace / ".agents",): try: parent.rmdir() except OSError: pass def main() -> int: parser = argparse.ArgumentParser(description=__doc__) commands = parser.add_subparsers(dest="command", required=True) add = commands.add_parser("install") add.add_argument("workspace", type=Path) add.add_argument("--source", type=Path, default=PACK_ROOT) add.add_argument("--mode", choices=("dedicated", "integrated"), default="integrated") remove = commands.add_parser("uninstall") remove.add_argument("workspace", type=Path) arguments = parser.parse_args() try: if arguments.command == "install": install(arguments.workspace, arguments.source, arguments.mode) print(f"GEWU pack and reversible routing installed in {arguments.workspace.resolve()}") else: uninstall(arguments.workspace) print(f"GEWU-owned pack and routing removed from {arguments.workspace.resolve()}") except (OSError, ValueError, json.JSONDecodeError) as error: parser.error(str(error)) return 0 if __name__ == "__main__": raise SystemExit(main())