diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..35e930b
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,15 @@
+# Changelog
+
+## v2.0.0 (2026-05-19)
+
+- Initial release: multi-provider Codex Launcher
+- Translation proxy: Responses API to Chat Completions + Anthropic Messages
+- GTK endpoint manager with 10+ provider presets
+- Codex Default mode (built-in OAuth, zero config)
+- Browser UA injection for Cloudflare-protected providers (OpenCode)
+- Streaming SSE, tool calls, reasoning content support
+- Profile backup/import, model auto-fetch, bulk import
+- Refresh Models in background thread
+- URL normalization to prevent double-path bugs
+- Config backup/restore around sessions
+- .deb installer package
diff --git a/codex-launcher_2.0.0_all.deb b/codex-launcher_2.0.0_all.deb
index 2d19861..72613b1 100644
Binary files a/codex-launcher_2.0.0_all.deb and b/codex-launcher_2.0.0_all.deb differ
diff --git a/src/codex-launcher-gui b/src/codex-launcher-gui
index b99f8bc..a7bf22e 100755
--- a/src/codex-launcher-gui
+++ b/src/codex-launcher-gui
@@ -23,6 +23,22 @@ model_provider = ""
model_catalog_json = ""
"""
+CHANGELOG = [
+ ("2.0.0", "2026-05-19", [
+ "Initial release: multi-provider Codex Launcher",
+ "Translation proxy: Responses API to Chat Completions + Anthropic Messages",
+ "GTK endpoint manager with 10+ provider presets",
+ "Codex Default mode (built-in OAuth, zero config)",
+ "Browser UA injection for Cloudflare-protected providers (OpenCode)",
+ "Streaming SSE, tool calls, reasoning content support",
+ "Profile backup/import, model auto-fetch, bulk import",
+ "Refresh Models in background thread",
+ "URL normalization to prevent double-path bugs",
+ "Config backup/restore around sessions",
+ ".deb installer package",
+ ]),
+]
+
PROVIDER_PRESETS = {
"Custom": {
"backend_type": "openai-compat",
@@ -432,9 +448,12 @@ class LauncherWin(Gtk.Window):
# header row
hdr = Gtk.Box(spacing=8)
vbox.pack_start(hdr, False, False, 0)
- lbl = Gtk.Label(label="Codex Launcher")
+ lbl = Gtk.Label(label="Codex Launcher v2.0.0")
lbl.set_use_markup(True)
hdr.pack_start(lbl, False, False, 0)
+ changelog_btn = Gtk.Button(label="Changelog")
+ changelog_btn.connect("clicked", lambda b: self._show_changelog())
+ hdr.pack_end(changelog_btn, False, False, 0)
mgr_btn = Gtk.Button(label="Manage Endpoints")
mgr_btn.connect("clicked", lambda b: self._open_mgr())
hdr.pack_end(mgr_btn, False, False, 0)
@@ -697,6 +716,36 @@ class LauncherWin(Gtk.Window):
d.run()
d.destroy()
+ def _show_changelog(self):
+ d = Gtk.Dialog(title="Changelog", transient_for=self, modal=True)
+ d.set_default_size(520, 480)
+ d.add_button("Close", Gtk.ResponseType.CLOSE)
+ area = d.get_content_area()
+ area.set_margin_start(12)
+ area.set_margin_end(12)
+ area.set_margin_top(12)
+ area.set_margin_bottom(12)
+ sw = Gtk.ScrolledWindow()
+ sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+ area.pack_start(sw, True, True, 0)
+ buf = Gtk.TextBuffer()
+ tv = Gtk.TextView(buffer=buf)
+ tv.set_editable(False)
+ tv.set_cursor_visible(False)
+ tv.set_wrap_mode(Gtk.WrapMode.WORD_CHAR)
+ sw.add(tv)
+ lines = []
+ for ver, date, items in CHANGELOG:
+ lines.append(f"v{ver} ({date})")
+ for item in items:
+ lines.append(f" \u2022 {item}")
+ lines.append("")
+ txt = "\n".join(lines).strip()
+ buf.insert(buf.get_end_iter(), txt)
+ d.show_all()
+ d.run()
+ d.destroy()
+
# ── launch ───────────────────────────────────────────────────
def _launch(self, target):