Skip to content

feat: switch-while-running, re-auth in-place, startup settings, stability fixes#111

Open
rushiranpise wants to merge 1 commit into
Lampese:mainfrom
rushiranpise:pr/dev-improvements
Open

feat: switch-while-running, re-auth in-place, startup settings, stability fixes#111
rushiranpise wants to merge 1 commit into
Lampese:mainfrom
rushiranpise:pr/dev-improvements

Conversation

@rushiranpise

Copy link
Copy Markdown
Contributor

A collection of reliability improvements, new user-facing features,
and bug fixes

New features

Switch accounts while Codex is running
The Switch button now stays active when Codex is running. Clicking it
opens a confirmation dialog warning that unsaved work may be lost,
then force-closes Codex and switches. Previously the button was
disabled with no action.

Re-authenticate expired accounts in-place
When a usage error indicates an expired/invalid session, an amber
banner with a "Re-authenticate" button appears on the account card.
This runs a fresh OAuth flow and replaces the tokens in-place —
the account name and settings are preserved, no delete/re-add needed.

"Open Codex" in both tray menus
Added to the native right-click tray menu (between "Open Codex
Switcher" and "Quit") and to the React tray popup footer.

Open Codex automatically after switching
New "Open Codex after switch" toggle in the Settings dropdown. When
enabled, Codex launches after every successful account switch.

Launch at Login / Start Minimized
Two new toggles in the Settings dropdown (Tauri only):

  • Launch at Login via tauri-plugin-autostart
  • Start Minimized hides the main window on startup so the app runs
    silently in the tray

Warmup and refresh failure details

  • Warm-up all: toast now lists each failed account name and error
    reason instead of just a count. Multi-line toasts stay for 8 s.
  • Refresh all: shows per-account errors on failure instead of always
    showing a generic success message.

Active account pinned at top in both tray menus
Both the native right-click menu and the React tray popup always show
the active account first with a separator below it.

Bug fixes

Atomic accounts.json / settings.json write
Both files now write to a .tmp first then rename atomically.
A crash mid-write can no longer corrupt the file
(fixes "malformed fragment at the end" parse errors).

refresh_token_reused errors eliminated
Two root causes fixed:

  1. Before writing auth.json on switch, the app reads the current
    file and absorbs any fresher tokens Codex has already rotated,
    preventing stale-token overwrites.
  2. Single-instance enforcement (flock on Unix, exclusive file-lock
    on Windows) prevents concurrent token refreshes across multiple
    app instances.

Token refresh stability

  • Expiry skew raised from 60 s to 5 min — tokens only refresh when
    genuinely close to expiry, not on every 60-second usage poll.
  • Per-account in-process refresh lock prevents concurrent warmup and
    usage polling from both triggering a token refresh for the same
    account simultaneously.

UI polish

  • Switch button: whitespace-nowrap prevents text wrapping in narrow
    grid cards; label shortened to "Switch & Close"
  • "Account" dropdown renamed to "Settings"

REF: #107 #105 #100 #97 #37

## New Features

### Switch accounts while Codex is running
Previously the Switch button was disabled when Codex was running.
It now shows an amber 'Switch & Close' button and opens a warning
dialog before force-closing and switching. Covers both main window
and tray-initiated switches.

### Open Codex after switching
New 'Open Codex after switch' toggle in the Settings menu (Tauri only).
When enabled, Codex launches automatically after every successful
account switch. Setting is persisted in localStorage.

### Launch at Login and Start Minimized
Two new toggles in Settings (Tauri only):
- Launch at Login: registers with OS autostart via tauri-plugin-autostart
  (LaunchAgent on macOS, registry on Windows, XDG on Linux)
- Start Minimized: hides the main window at startup so the app runs
  silently in the tray without showing a window

### Re-authenticate expired accounts in-place
When a usage error indicates an expired/invalid session, an amber
'Re-authenticate' banner appears on the account card. Clicking it
runs a fresh OAuth flow and replaces the tokens in-place. The account
name, settings, and history are preserved — no need to delete and
re-add.

### Open Codex button in both tray menus
'Open Codex' added to both the native right-click tray menu (between
'Open Codex Switcher' and 'Quit') and the React tray popup footer.

### Warmup and refresh failure details
- Warm-up all: toast now lists each failed account with its error reason
  instead of just a count. Multi-line error toasts stay for 8 seconds.
- Refresh all: shows per-account errors when any usage fetch fails
  instead of always showing a generic success message.

### Active account pinned at top in both tray menus
Both the native right-click menu and the React tray popup always
show the active account first, separated from the rest by a divider.
Previously the order depended on account creation order.

## Bug Fixes

### Cloudflare 403 on chatgpt.com backend API
All requests to chatgpt.com/backend-api now use a real Chrome
User-Agent and standard browser headers (Accept, Accept-Language,
Origin, Referer, sec-fetch-*) to bypass Cloudflare bot detection.
The 403 error message no longer blames stale tokens or suggests
removing the account.

### refresh_token_reused errors eliminated
Two root causes fixed:
1. Token sync on switch: before writing auth.json, the app reads the
   current file and absorbs any fresher tokens Codex rotated since the
   last switch, preventing stale token overwrites.
2. Single-instance enforcement: uses flock (Unix) / exclusive file
   lock (Windows) to prevent multiple app instances from concurrently
   refreshing tokens and triggering refresh_token_reused.

### Token refresh stability
- Expiry skew increased from 60s to 5 minutes so tokens are only
  refreshed when genuinely close to expiry, not on every 60-second
  usage poll.
- Per-account refresh lock (LazyLock<Mutex<HashSet>>) prevents
  concurrent warmup and usage polling from both triggering a token
  refresh for the same account simultaneously.

### Atomic accounts.json write
save_accounts() and save_app_settings() now write to a .tmp file
then rename atomically, so a crash mid-write can never corrupt the
accounts file (fixes 'malformed fragment at the end' parse errors).

## UI Polish
- Switch button: whitespace-nowrap prevents wrapping in narrow cards;
  label shortened to 'Switch & Close'
- 'Account' dropdown renamed to 'Settings' (it now manages startup
  behaviour, import/export, and other settings beyond accounts)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant