diff --git a/src/codex-launcher-gui b/src/codex-launcher-gui
index dfe59b4..9bbf7bc 100755
--- a/src/codex-launcher-gui
+++ b/src/codex-launcher-gui
@@ -2790,6 +2790,64 @@ class LauncherWin(Gtk.Window):
_stop_proxy()
Gtk.main_quit()
+ def _edit_oauth_secrets(self):
+ secrets_path = os.path.expanduser("~/.config/codex-launcher/oauth-secrets.json")
+ try:
+ with open(secrets_path) as f:
+ data = json.load(f)
+ except Exception:
+ data = {"antigravity": {"client_id": "", "client_secret": ""},
+ "gemini_cli": {"client_id": "", "client_secret": ""}}
+
+ dlg = Gtk.Dialog(title="OAuth 2.0 Client Secrets", parent=self, modal=True)
+ dlg.add_button("Cancel", Gtk.ResponseType.CANCEL)
+ dlg.add_button("Save", Gtk.ResponseType.OK)
+ dlg.set_default_size(520, 340)
+ area = dlg.get_content_area()
+ area.set_margin_start(16)
+ area.set_margin_end(16)
+ area.set_margin_top(12)
+ area.set_margin_bottom(12)
+ area.set_spacing(6)
+
+ area.pack_start(Gtk.Label(label="Google OAuth 2.0 credentials\nStored locally in ~/.config/codex-launcher/oauth-secrets.json", use_markup=True, xalign=0), False, False, 4)
+
+ fields = {}
+ for section_key, section_label in [("antigravity", "Antigravity (CloudCode)"), ("gemini_cli", "Gemini CLI")]:
+ area.pack_start(Gtk.Label(label=f"\n{section_label}", use_markup=True, xalign=0), False, False, 2)
+ sec = data.get(section_key, {})
+ for fk, fl in [("client_id", "Client ID"), ("client_secret", "Client Secret")]:
+ row = Gtk.Box(spacing=6)
+ lbl = Gtk.Label(label=fl + ":", xalign=0)
+ lbl.set_size_request(100, -1)
+ entry = Gtk.Entry()
+ entry.set_text(sec.get(fk, ""))
+ entry.set_size_request(380, -1)
+ if fk == "client_secret":
+ entry.set_visibility(False)
+ entry.set_invisible_char("*")
+ row.pack_start(lbl, False, False, 0)
+ row.pack_start(entry, True, True, 0)
+ area.pack_start(row, False, False, 2)
+ fields[(section_key, fk)] = entry
+
+ area.pack_start(Gtk.Label(label="\nGet credentials from console.cloud.google.com → APIs & Services → Credentials", use_markup=True, xalign=0), False, False, 4)
+ area.show_all()
+
+ if dlg.run() == Gtk.ResponseType.OK:
+ for (sk, fk), entry in fields.items():
+ if sk not in data:
+ data[sk] = {}
+ data[sk][fk] = entry.get_text().strip()
+ try:
+ os.makedirs(os.path.dirname(secrets_path), exist_ok=True)
+ with open(secrets_path, "w") as f:
+ json.dump(data, f, indent=2)
+ os.chmod(secrets_path, 0o600)
+ except Exception as e:
+ self._show_error_dialog("Save failed", str(e))
+ dlg.destroy()
+
# ═══════════════════════════════════════════════════════════════════
# Endpoint manager dialog
# ═══════════════════════════════════════════════════════════════════
@@ -3267,64 +3325,6 @@ class EditEndpointDialog(Gtk.Dialog):
else:
self._lbl_reasoning.set_markup('OFF')
- def _edit_oauth_secrets(self):
- secrets_path = os.path.expanduser("~/.config/codex-launcher/oauth-secrets.json")
- try:
- with open(secrets_path) as f:
- data = json.load(f)
- except Exception:
- data = {"antigravity": {"client_id": "", "client_secret": ""},
- "gemini_cli": {"client_id": "", "client_secret": ""}}
-
- dlg = Gtk.Dialog(title="OAuth 2.0 Client Secrets", parent=self, modal=True)
- dlg.add_button("Cancel", Gtk.ResponseType.CANCEL)
- dlg.add_button("Save", Gtk.ResponseType.OK)
- dlg.set_default_size(520, 340)
- area = dlg.get_content_area()
- area.set_margin_start(16)
- area.set_margin_end(16)
- area.set_margin_top(12)
- area.set_margin_bottom(12)
- area.set_spacing(6)
-
- area.pack_start(Gtk.Label(label="Google OAuth 2.0 credentials\nStored locally in ~/.config/codex-launcher/oauth-secrets.json", use_markup=True, xalign=0), False, False, 4)
-
- fields = {}
- for section_key, section_label in [("antigravity", "Antigravity (CloudCode)"), ("gemini_cli", "Gemini CLI")]:
- area.pack_start(Gtk.Label(label=f"\n{section_label}", use_markup=True, xalign=0), False, False, 2)
- sec = data.get(section_key, {})
- for fk, fl in [("client_id", "Client ID"), ("client_secret", "Client Secret")]:
- row = Gtk.Box(spacing=6)
- lbl = Gtk.Label(label=fl + ":", xalign=0)
- lbl.set_size_request(100, -1)
- entry = Gtk.Entry()
- entry.set_text(sec.get(fk, ""))
- entry.set_size_request(380, -1)
- if fk == "client_secret":
- entry.set_visibility(False)
- entry.set_invisible_char("*")
- row.pack_start(lbl, False, False, 0)
- row.pack_start(entry, True, True, 0)
- area.pack_start(row, False, False, 2)
- fields[(section_key, fk)] = entry
-
- area.pack_start(Gtk.Label(label="\nGet credentials from console.cloud.google.com → APIs & Services → Credentials", use_markup=True, xalign=0), False, False, 4)
- area.show_all()
-
- if dlg.run() == Gtk.ResponseType.OK:
- for (sk, fk), entry in fields.items():
- if sk not in data:
- data[sk] = {}
- data[sk][fk] = entry.get_text().strip()
- try:
- os.makedirs(os.path.dirname(secrets_path), exist_ok=True)
- with open(secrets_path, "w") as f:
- json.dump(data, f, indent=2)
- os.chmod(secrets_path, 0o600)
- except Exception as e:
- self._show_error_dialog("Save failed", str(e))
- dlg.destroy()
-
def _do_oauth_login(self):
preset_name = self._combo_preset.get_active_text() or "Custom"
preset = PROVIDER_PRESETS.get(preset_name, {})