chore: merge windows/ into src/ and remove duplicate folder

Cross-platform support lives in src/ via _IS_WINDOWS checks.
Merges latest upstream additions from windows/ (OAuth secrets,
ANTIGRAVITY_MODELS, changelog v3.10.5) into src/ files, then
removes the redundant windows/ folder.
This commit is contained in:
cobra91
2026-05-25 15:09:07 +02:00
Unverified
parent c203cabb01
commit 17126bc111
4 changed files with 206 additions and 4878 deletions

View File

@@ -30,7 +30,8 @@ from codex_launcher_lib import (
IS_WINDOWS, HOME, CONFIG, CONFIG_BAK, CONFIG_TXN,
ENDPOINTS_FILE, BGP_POOLS_FILE, LAUNCH_LOG, LOG_DIR,
PROXY_CONFIG_DIR, BIN_DIR, PROXY, CLEANUP, PID_REGISTRY,
PROVIDER_PRESETS, CHANGELOG, DEFAULT_CONFIG,
PROVIDER_PRESETS, CHANGELOG, DEFAULT_CONFIG, OAUTH_SECRETS_PATH,
ANTIGRAVITY_MODELS,
safe_name, label_for_backend, normalize_model_id, normalize_base_url,
parse_model_list, now_utc_iso, apply_provider_preset,
load_endpoints, save_endpoints, load_bgp_pools, save_bgp_pools,
@@ -48,6 +49,7 @@ from codex_launcher_lib import (
load_incident_store, save_incident_store, load_usage_stats,
monitoring_log,
IncidentStore, AIDiagnosticAgent, HealthWatcher,
load_oauth_secrets, save_oauth_secrets,
_usage_theme, UA,
)
@@ -378,9 +380,11 @@ class EditEndpointDialog:
is_antigravity = oauth_provider == "google-antigravity"
token_path = str(PROXY_CONFIG_DIR / ("google-antigravity-oauth-token.json" if is_antigravity else "google-cli-oauth-token.json"))
_sec = load_oauth_secrets().get("antigravity" if is_antigravity else "gemini_cli", {})
CLIENT_ID = _sec.get("client_id", "")
CLIENT_SECRET = _sec.get("client_secret", "")
if is_antigravity:
CLIENT_ID = ""
CLIENT_SECRET = ""
SCOPES = [
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/userinfo.email",
@@ -393,8 +397,6 @@ class EditEndpointDialog:
callback_path = "/oauth-callback"
provider_kind = "antigravity"
else:
CLIENT_ID = ""
CLIENT_SECRET = ""
SCOPES = [
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/userinfo.email",
@@ -436,7 +438,7 @@ class EditEndpointDialog:
oauth_dlg.grab_set()
tk.Label(oauth_dlg, text="Sign in with Google", font=("Segoe UI", 11, "bold")).pack(padx=16, pady=(12, 0), anchor="w")
tk.Label(oauth_dlg, text="Emulating Gemini CLI OAuth -- no client_secret.json needed.").pack(padx=16, anchor="w")
tk.Label(oauth_dlg, text=f"Using OAuth credentials from {OAUTH_SECRETS_PATH}").pack(padx=16, anchor="w")
link_lbl = tk.Label(oauth_dlg, text="Click here to open Google authorization", fg="blue", cursor="hand2")
link_lbl.pack(padx=16, pady=(8, 0), anchor="w")
@@ -535,12 +537,7 @@ class EditEndpointDialog:
found_models = []
if is_antigravity:
found_models = [
"gemini-2.5-flash", "gemini-2.5-pro",
"gemini-3-flash-preview", "gemini-3-pro-preview", "gemini-3.1-pro-preview",
"antigravity-gemini-3-flash", "antigravity-gemini-3-pro",
"antigravity-claude-sonnet-4-6", "antigravity-claude-opus-4-6-thinking",
]
found_models = list(ANTIGRAVITY_MODELS)
else:
found_models = ["gemini-2.5-flash", "gemini-2.5-pro"]
if found_models:
@@ -1944,21 +1941,20 @@ class BenchmarkWindow:
class LauncherWin:
def __init__(self, root):
self._root = root
self._root.title("Codex Launcher")
self._root.geometry("580x520")
self._root.minsize(480, 400)
self._proc = None
self._endpoints_data = load_endpoints()
self._refresh_running = False
recover_config_if_needed()
main = ttk.Frame(root, padding=12)
main = ttk.Frame(root, padding=16)
main.pack(fill="both", expand=True)
main.pack_propagate(False)
# Title
hdr = ttk.Frame(main)
hdr.pack(fill="x")
ttk.Label(hdr, text="Codex Launcher v3.8.1", font=("Segoe UI", 13, "bold")).pack(side="left")
ttk.Label(hdr, text=f"Codex Launcher v{CHANGELOG[0][0]}", font=("Segoe UI", 13, "bold")).pack(side="left")
# Toolbar — two rows to fit all buttons
tb1 = ttk.Frame(main)
@@ -1969,6 +1965,7 @@ class LauncherWin:
ttk.Button(tb1, text="Usage", command=self._open_usage).pack(side="left", padx=(6, 0))
ttk.Button(tb1, text="Benchmark", command=self._open_benchmark).pack(side="left", padx=(6, 0))
ttk.Button(tb1, text="History", command=self._open_history).pack(side="left", padx=(6, 0))
ttk.Button(tb1, text="OAuth Secrets", command=self._edit_oauth_secrets).pack(side="left", padx=(6, 0))
ttk.Button(tb1, text="Changelog", command=self._show_changelog).pack(side="right")
# Detection status — one row per item so long paths don't truncate
@@ -2054,8 +2051,8 @@ class LauncherWin:
self._btn_codex_cli.pack(side="left", fill="x", expand=True)
# Log area
self._log_text = scrolledtext.ScrolledText(main, height=8, state="disabled", wrap="word",
font=("Consolas", 9))
self._log_text = scrolledtext.ScrolledText(main, height=10, state="disabled", wrap="word",
font=("Consolas", 9))
self._log_text.pack(fill="both", expand=True, pady=(8, 0))
# Bottom bar
@@ -2199,6 +2196,92 @@ class LauncherWin:
if Path(assist_path).exists():
subprocess.Popen([sys.executable, assist_path], creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if IS_WINDOWS else 0)
def _edit_oauth_secrets(self):
data = load_oauth_secrets()
if not data:
data = {"antigravity": {"client_id": "", "client_secret": ""},
"gemini_cli": {"client_id": "", "client_secret": ""}}
dlg = tk.Toplevel(self._root)
dlg.title("OAuth 2.0 Client Secrets")
dlg.geometry("600x450")
dlg.transient(self._root)
dlg.grab_set()
frame = ttk.Frame(dlg, padding=16)
frame.pack(fill="both", expand=True)
ttk.Label(frame, text="Google OAuth 2.0 credentials", font=("Segoe UI", 10, "bold")).pack(anchor="w")
ttk.Label(frame, text=f"Stored locally in {OAUTH_SECRETS_PATH}", foreground="gray").pack(anchor="w", pady=(0, 8))
fields = {}
nf = ttk.Frame(frame)
nf.pack(fill="x")
row = 0
for section_key, section_label in [("antigravity", "Antigravity (CloudCode)"), ("gemini_cli", "Gemini CLI")]:
ttk.Label(nf, text=f"\n{section_label}", font=("Segoe UI", 9, "bold")).grid(row=row, column=0, columnspan=3, sticky="w", pady=(8, 2))
row += 1
sec = data.get(section_key, {})
import_btn = ttk.Button(nf, text="Import JSON",
command=lambda sk=section_key: self._import_oauth_json(fields, sk))
import_btn.grid(row=row, column=2, padx=(4, 0), pady=2, sticky="e")
for fk, fl in [("client_id", "Client ID"), ("client_secret", "Client Secret")]:
ttk.Label(nf, text=fl + ":").grid(row=row, column=0, sticky="w", padx=(8, 4), pady=2)
entry = ttk.Entry(nf, width=60)
entry.insert(0, sec.get(fk, ""))
entry.grid(row=row, column=1, sticky="ew", pady=2)
if fk == "client_secret":
entry.configure(show="*")
fields[(section_key, fk)] = entry
row += 1
nf.columnconfigure(1, weight=1)
ttk.Label(frame, text="\nImport a client_secret_*.json from Google Cloud Console\nconsole.cloud.google.com → Credentials", foreground="gray").pack(anchor="w")
btnf = ttk.Frame(frame)
btnf.pack(fill="x", pady=(12, 0))
ttk.Button(btnf, text="Cancel", command=dlg.destroy).pack(side="right", padx=(4, 0))
save_btn = ttk.Button(btnf, text="Save")
save_btn.pack(side="right", padx=(4, 0))
def _save():
for (sk, fk), entry in fields.items():
if sk not in data:
data[sk] = {}
data[sk][fk] = entry.get().strip()
try:
save_oauth_secrets(data)
except Exception as e:
messagebox.showerror("Save failed", str(e), parent=dlg)
return
dlg.destroy()
save_btn.configure(command=_save)
def _import_oauth_json(self, fields, section_key):
path = filedialog.askopenfilename(
title="Import Google OAuth Client Secret JSON",
filetypes=[("JSON files", "*.json")])
if not path:
return
try:
with open(path, encoding="utf-8") as f:
raw = json.load(f)
creds = raw.get("installed") or raw.get("web") or raw
cid = creds.get("client_id", "")
csec = creds.get("client_secret", "")
if not cid or not csec:
raise ValueError("JSON does not contain client_id and client_secret")
if (section_key, "client_id") in fields:
fields[(section_key, "client_id")].delete(0, "end")
fields[(section_key, "client_id")].insert(0, cid)
if (section_key, "client_secret") in fields:
fields[(section_key, "client_secret")].delete(0, "end")
fields[(section_key, "client_secret")].insert(0, csec)
except Exception as e:
messagebox.showerror("Import failed", str(e))
# ── Watcher ──────────────────────────────────────────────────────
def _start_watcher(self):
@@ -2696,5 +2779,8 @@ if __name__ == "__main__":
create_default_endpoints()
root = tk.Tk()
root.title("Codex Launcher")
root.geometry("800x680")
root.minsize(640, 520)
app = LauncherWin(root)
root.mainloop()