Skip to content

fix: resolve current account switching issue for agy CLI and target environments#3186

Open
fedorovmv wants to merge 7 commits into
lbjlaq:mainfrom
fedorovmv:fix/agy-account-switch
Open

fix: resolve current account switching issue for agy CLI and target environments#3186
fedorovmv wants to merge 7 commits into
lbjlaq:mainfrom
fedorovmv:fix/agy-account-switch

Conversation

@fedorovmv

@fedorovmv fedorovmv commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR addresses an issue where switching the active account for the agy CLI (or custom IDE targets) is immediately reverted or lost in the Manager's UI due to background database synchronization (sync_account_from_db).

Root Cause

  1. Previously, the AccountIndex structure only stored current_account_id globally, without any concept of which target IDE or CLI environment was active.
  2. When the user switched accounts for the agy CLI, the Manager successfully updated the system Keyring and set the global current_account_id to the new account.
  3. However, because the agy CLI has no local SQLite database (state.vscdb), the classic VS Code SQLite database remained on the old account.
  4. The background auto-sync loop (sync_account_from_db) periodically polled the classic SQLite database. Seeing a mismatch between the Manager's global active account (newly switched for agy) and the classic database (old account), it erroneously concluded that the user switched accounts inside VS Code, and reverted current_account_id back to the old account.

Solution

To fix this, we introduced the concept of target IDE context into the Manager's state and enhanced the system keyring synchronization workflow:

  1. Added current_target_ide field to the AccountIndex model (None / Some("classic"), Some("ide"), or Some("agy")).
  2. Updated Switch Logic: The switch_account core logic now captures and persists the target environment (target_ide) of the user's last action in current_target_ide. If the switch target is None (e.g., switched from the main dashboard), the Manager preserves the currently active CLI target (like agy) instead of discarding it.
  3. Target-Aware Sync:
    • If the active target environment is Some("agy") (CLI), the background sync task is skipped because agy uses the system Keyring rather than a database file.
    • If the active target is Some("ide"), the sync process reads the Antigravity IDE database.
    • Otherwise, it syncs with the classic VS Code database.
  4. Automatic Keyring Sync: Introduced a synchronize_keyring helper to coordinate system keyring writes/deletions. The keyring is automatically updated during:
    • Account switching (set_current_account_id_with_target).
    • Adding the first account (add_account).
    • Deleting the active account (delete_account, delete_accounts).
  5. Token Refresh Keyring Sync: Automatically synchronizes updated credentials to the system keyring in TokenManager::save_refreshed_token whenever the refreshed token belongs to the active active account. This ensures CLI clients (like agy) always have fresh, non-expired credentials.
  6. Concurrency & Lock Optimization: Refactored TokenManager::save_refreshed_token to clone the account path and release the DashMap read-lock immediately before performing blocking disk IO and keyring command executions, resolving potential shard lock contention.
  7. Deduplication: Removed redundant keyring updates in on_account_switch to avoid double-writing during switches.
  8. Testing: Added a unit test (test_set_current_account_id_with_target) that isolates file operations and verifies target-aware account and environment state changes.

Why not sync the CLI by reading the Keyring?

Reading from the macOS Keychain (and some Linux Keyrings) inside a background loop is highly problematic:

  • If the credentials in the keyring were created/modified by a different process (such as the agy CLI binary), attempting to read them programmatically via Tauri or CLI tools frequently triggers system-level security prompts (OS keychain dialogs asking the user for their password or to click "Allow").
  • Frequent background checks would result in a disruptive user experience with constant OS popup requests. Hence, Keyring integration is kept write-only (push model).

How is the IDE Database checked?

  • When the active target is Some("ide"), the database path helper (db::get_db_path) is called with the target parameter, which maps to the Antigravity IDE data directory (e.g., ~/Library/Application Support/Antigravity IDE/...) instead of the default Antigravity directory.
  • The sync function extracts the refresh token from this target-specific SQLite database to detect account switches within the custom IDE.

Why this approach?

Instead of completely redesigning the UI to show multiple current accounts per environment (which would require a massive overhaul of the frontend components and state), tracking the user's last-switched target context (current_target_ide) is:

  • Risk-free & Backward-Compatible: No data schema migration is needed; existing accounts.json configs parse correctly.
  • Prevents UI Cross-Talk: Avoids misleading the user where switching accounts in one IDE silently changes the active account display for the CLI, preventing accidental actions on the wrong account in other environments.

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