fix: default provider policy, anti-stall self-kill, _schema NameError (cobra PR #17)

This commit is contained in:
Roman | RyzenAdvanced
2026-05-27 14:48:44 +04:00
Unverified
parent 6a50714da6
commit f7baff7425
3 changed files with 150 additions and 59 deletions

View File

@@ -41,7 +41,7 @@ from codex_launcher_lib import (
recover_config_if_needed, write_config_for_native, write_config_for_translated,
endpoint_models_url, endpoint_model_headers, fetch_models_for_endpoint,
refresh_endpoint_models, run_endpoint_doctor,
detect_codex_cli, detect_codex_desktop, check_codex_auth,
detect_codex_cli, detect_codex_desktop, launch_codex_desktop, is_codex_desktop_running, check_codex_auth,
last_log_lines, kill_existing_desktop, safe_cleanup_owned,
start_proxy_for, stop_proxy, start_bgp_proxy, get_proxy_state, set_proxy_state,
detect_terminal, open_url, open_file, write_secure_text,
@@ -2338,9 +2338,10 @@ class LauncherWin:
desk_row = ttk.Frame(main)
desk_row.pack(fill="x", pady=(2, 0))
if self._desktop_info:
if self._desktop_info[0]:
label = "MSIX (Store)" if self._desktop_info[1] else self._desktop_info[0]
ttk.Label(desk_row, text="✓ Codex Desktop", foreground="#2ea043").pack(side="left")
ttk.Label(desk_row, text=f" ({self._desktop_info})", foreground="gray").pack(side="left")
ttk.Label(desk_row, text=f" ({label})", foreground="gray").pack(side="left")
else:
ttk.Label(desk_row, text="✗ Codex Desktop -- not found", foreground="#d29922").pack(side="left")
ttk.Button(desk_row, text="Install", command=lambda: self._show_install_guide("desktop")).pack(side="left", padx=(6, 0))
@@ -2348,7 +2349,7 @@ class LauncherWin:
self._missing = []
if not self._cli_info:
self._missing.append("cli")
if not self._desktop_info:
if not self._desktop_info[0]:
self._missing.append("desktop")
# Auth status
@@ -2461,8 +2462,9 @@ class LauncherWin:
self.log(f"✓ Codex CLI detected ({ver})")
else:
self.log("✗ Codex CLI NOT found -- CLI launch disabled.")
if self._desktop_info:
self.log(f"✓ Codex Desktop detected ({self._desktop_info})")
if self._desktop_info[0]:
label = "MSIX (Store)" if self._desktop_info[1] else self._desktop_info[0]
self.log(f"✓ Codex Desktop detected ({label})")
else:
self.log("✗ Codex Desktop NOT found -- Desktop launch disabled.")
if self._missing:
@@ -3132,7 +3134,7 @@ class LauncherWin:
# ── Launch ───────────────────────────────────────────────────────
def _set_busy(self, busy):
def _set_busy(self, busy, proxy_alive=False):
has_cli = "cli" not in self._missing
has_desk = "desktop" not in self._missing
def _update():
@@ -3140,8 +3142,8 @@ class LauncherWin:
self._btn_cli.configure(state="disabled" if busy or not has_cli else "normal")
self._btn_codex_desktop.configure(state="disabled" if busy or not has_desk else "normal")
self._btn_codex_cli.configure(state="disabled" if busy or not has_cli else "normal")
self._kill_btn.configure(state="normal" if busy else "disabled")
self._restart_btn.configure(state="normal" if busy else "disabled")
self._kill_btn.configure(state="normal" if busy or proxy_alive else "disabled")
self._restart_btn.configure(state="normal" if busy or proxy_alive else "disabled")
self._root.after(0, _update)
def _launch(self, target):
@@ -3228,7 +3230,7 @@ class LauncherWin:
finally:
if keep_session_alive:
self.log("Warm-start handoff detected; keeping proxy/config active for running Desktop.")
self._set_busy(False)
self._set_busy(False, proxy_alive=True)
self.log("Ready. Use Kill && Cleanup when finished.")
else:
stop_proxy()
@@ -3292,25 +3294,31 @@ class LauncherWin:
self.log("Ready.")
def _launch_desktop(self, ep, model):
desktop_path = self._desktop_info
if not desktop_path:
if not self._desktop_info[0]:
self.log("ERROR: Codex Desktop not found")
return False
if IS_WINDOWS:
self._proc = subprocess.Popen(
[desktop_path],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
else:
self._proc = subprocess.Popen(
[desktop_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
preexec_fn=os.setsid)
_, is_msix = self._desktop_info
self._proc = launch_codex_desktop(self._desktop_info)
if not self._proc:
self.log("ERROR: Failed to launch Codex Desktop")
return False
pid = self._proc.pid
self.log(f"Desktop started (PID {pid})")
self.log(f"Log: {LAUNCH_LOG}")
# MSIX: cmd.exe exits immediately, monitor via tasklist instead
if is_msix and IS_WINDOWS:
time.sleep(3)
if not is_codex_desktop_running():
self.log("ERROR: Codex Desktop did not start")
self._proc = None
return False
self.log("Codex Desktop is running (MSIX)")
self._proc = None
return True
t0 = time.time()
stall_warned = False
while self._proc and self._proc.poll() is None:
@@ -3366,18 +3374,13 @@ class LauncherWin:
def _launch_desktop_direct(self):
self.log("Launching Codex Desktop (default OAuth)...")
desktop_path = self._desktop_info
if not desktop_path:
if not self._desktop_info[0]:
self.log("ERROR: Codex Desktop not found")
return
if IS_WINDOWS:
self._proc = subprocess.Popen(
[desktop_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
else:
self._proc = subprocess.Popen(
[desktop_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
preexec_fn=os.setsid)
self._proc = launch_codex_desktop(self._desktop_info)
if not self._proc:
self.log("ERROR: Failed to launch Codex Desktop")
return
pid = self._proc.pid
self.log(f"Desktop started (PID {pid})")

View File

@@ -1729,6 +1729,12 @@ def detect_codex_cli():
def detect_codex_desktop():
"""Detect Codex Desktop installation.
Returns (path_or_aumid, is_msix) tuple on Windows, path string on Linux.
For MSIX installs, returns the AppUserModelId since the exe cannot be
launched directly via subprocess from WindowsApps.
"""
if IS_WINDOWS:
la = os.environ.get("LOCALAPPDATA", "")
pf = os.environ.get("PROGRAMFILES", "")
@@ -1741,8 +1747,8 @@ def detect_codex_desktop():
]
for p in desktop_paths:
if p.exists():
return str(p)
# MSIX / Microsoft Store install: locate via Get-AppxPackage
return str(p), False
# MSIX / Microsoft Store install
try:
r = subprocess.run(
["powershell", "-NoProfile", "-Command",
@@ -1753,13 +1759,70 @@ def detect_codex_desktop():
if loc:
msix_exe = Path(loc) / "app" / "Codex.exe"
if msix_exe.exists():
return str(msix_exe)
r2 = subprocess.run(
["powershell", "-NoProfile", "-Command",
"(Get-AppxPackage *OpenAI.Codex*).PackageFamilyName"],
capture_output=True, text=True, timeout=10,
)
family = r2.stdout.strip() if r2.returncode == 0 else ""
if family:
return f"{family}!App", True
except Exception:
pass
return None
return None, False
if START_SH and START_SH.exists():
return str(START_SH)
return None
return str(START_SH), False
return None, False
def launch_codex_desktop(desktop_info):
"""Launch Codex Desktop process.
Args:
desktop_info: (path_or_aumid, is_msix) tuple from detect_codex_desktop()
Returns:
subprocess.Popen object or None
"""
path, is_msix = desktop_info
if IS_WINDOWS:
if is_msix:
return subprocess.Popen(
["cmd", "/c", "start", "", f"shell:AppsFolder\\{path}"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
return subprocess.Popen(
[path],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
else:
return subprocess.Popen(
[path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
preexec_fn=os.setsid)
def is_codex_desktop_running():
"""Check if Codex Desktop (or MSIX Codex) is currently running."""
if IS_WINDOWS:
try:
for name in ("Codex Desktop.exe", "Codex.exe"):
out = subprocess.run(
["tasklist", "/FI", f"IMAGENAME eq {name}", "/FO", "CSV", "/NH"],
capture_output=True, text=True, timeout=5,
)
for line in out.stdout.strip().splitlines():
parts = line.split(",")
if len(parts) >= 2 and parts[1].strip('"').isdigit():
return True
except Exception:
pass
return False
else:
try:
out = subprocess.run(["pgrep", "-f", "/opt/codex-desktop/electron"], capture_output=True, text=True, timeout=5)
return bool(out.stdout.strip())
except Exception:
return False
def check_codex_auth():
@@ -1802,24 +1865,25 @@ def last_log_lines(n=15):
def kill_existing_desktop(logfn=None):
if IS_WINDOWS:
try:
out = subprocess.run(
["tasklist", "/FI", "IMAGENAME eq Codex Desktop.exe", "/FO", "CSV", "/NH"],
capture_output=True, text=True, timeout=5,
)
for line in out.stdout.strip().splitlines():
parts = line.split(",")
if len(parts) >= 2:
pid_str = parts[1].strip('"')
if pid_str.isdigit():
pid = int(pid_str)
_kill_process_group(pid)
if logfn:
logfn(f"Killed existing Codex Desktop (pid {pid})")
time.sleep(2)
except Exception as e:
if logfn:
logfn(f"Note: could not kill existing Desktop: {e}")
for img in ("Codex Desktop.exe", "Codex.exe"):
try:
out = subprocess.run(
["tasklist", "/FI", f"IMAGENAME eq {img}", "/FO", "CSV", "/NH"],
capture_output=True, text=True, timeout=5,
)
for line in out.stdout.strip().splitlines():
parts = line.split(",")
if len(parts) >= 2:
pid_str = parts[1].strip('"')
if pid_str.isdigit():
pid = int(pid_str)
_kill_process_group(pid)
if logfn:
logfn(f"Killed existing Codex Desktop (pid {pid})")
time.sleep(2)
except Exception as e:
if logfn:
logfn(f"Note: could not kill existing Desktop: {e}")
else:
try:
out = subprocess.run(["pgrep", "-f", "/opt/codex-desktop/electron"], capture_output=True, text=True, timeout=5)