#!/usr/bin/env python3 """Cleanup stale Codex Launcher processes and artifacts — cross-platform. Kills registered process groups and removes stale PID/socket files left by previous Codex Launcher sessions. Windows: uses taskkill /F /T /PID Linux: uses kill -TERM -- -PGID """ import json, os, sys, subprocess, time from pathlib import Path IS_WINDOWS = sys.platform == "win32" if IS_WINDOWS: _local = os.environ.get("LOCALAPPDATA", str(Path.home() / "AppData" / "Local")) PID_REGISTRY = Path(_local) / "codex-proxy" / "pids.json" CODEX_DIR = Path.home() / ".codex" _local_share = Path(_local) _cache = Path(_local) else: PID_REGISTRY = Path.home() / ".cache" / "codex-proxy" / "pids.json" CODEX_DIR = Path.home() / ".codex" _local_share = Path.home() / ".local" / "share" _cache = Path.home() / ".cache" def kill_group(pid): if IS_WINDOWS: subprocess.run(["taskkill", "/F", "/T", "/PID", str(pid)], capture_output=True, timeout=10) else: import signal try: pgid = os.getpgid(pid) os.killpg(pgid, signal.SIGTERM) time.sleep(0.5) try: os.killpg(pgid, signal.SIGKILL) except OSError: pass except OSError: pass def main(): print("[cleanup] Cleaning up stale Codex Launcher processes...", file=sys.stderr) if PID_REGISTRY.exists(): try: with open(PID_REGISTRY) as f: registry = json.load(f) except Exception as e: print(f"[cleanup] Failed to read PID registry: {e}", file=sys.stderr) registry = {} for kind, info in registry.items(): pid = info.get("pid") if isinstance(info, dict) else info if pid and isinstance(pid, int): print(f"[cleanup] Killing {kind} (PID {pid})", file=sys.stderr) kill_group(pid) try: PID_REGISTRY.unlink() except OSError: pass else: print("[cleanup] No PID registry found — nothing to stop", file=sys.stderr) stale_files = [] if IS_WINDOWS: stale_files = [ _cache / "codex-desktop" / ".codex-desktop-pid", _cache / "codex-desktop" / ".webview-pid", ] else: stale_files = [ CODEX_DIR / ".launch-action-socket", CODEX_DIR / ".codex-desktop-launch-action", CODEX_DIR / ".codex-desktop-pid", CODEX_DIR / ".webview-pid", _local_share / "codex-desktop" / ".codex-desktop-pid", _local_share / "codex-desktop" / ".webview-pid", _cache / "codex-desktop" / ".codex-desktop-pid", _cache / "codex-desktop" / ".webview-pid", ] for fp in stale_files: try: if fp.exists(): fp.unlink() print(f"[cleanup] Removed {fp}", file=sys.stderr) except OSError: pass print("[cleanup] Done", file=sys.stderr) if __name__ == "__main__": main()