Based on v3.10.4 upstream. New files: - src/codex-launcher-gui.py: full tkinter GUI (10 classes) replacing GTK on Windows - src/codex_launcher_lib.py: shared cross-platform module (~1870 lines) - src/cleanup-codex-stale.py: cross-platform process cleanup translate-proxy.py Windows adaptations: - Platform-aware paths: %LOCALAPPDATA% for cache, %APPDATA% for config - Platform-aware credentials, signals, memory reporting, shell commands - UTF-8 encoding on all file writes (Windows cp1252 default) - FORCE_MODEL: proxy overrides Codex Desktop model selection - DeepSeek reasoning_content round-trip for multi-turn tool sessions - Cleanup orphan .tmp files at startup - requests.log rotation (2000 lines cap) - User-Agent: codex-launcher/1.0 in outbound HTTP requests
102 lines
3.0 KiB
Python
102 lines
3.0 KiB
Python
#!/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-launcher" / "pids.json"
|
|
CODEX_DIR = Path.home() / ".codex"
|
|
_local_share = Path(_local)
|
|
_cache = Path(_local)
|
|
else:
|
|
PID_REGISTRY = Path.home() / ".cache" / "codex-launcher" / "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()
|