Skip to content

feat(antigravity): add Antigravity CLI account switching and switch-and-run support - #2335

Draft
yaobii-lab wants to merge 1 commit into
jlcodes99:mainfrom
yaobii-lab:feat/antigravity-cli-account-switch
Draft

yaobii-lab wants to merge 1 commit into
jlcodes99:mainfrom
yaobii-lab:feat/antigravity-cli-account-switch

Conversation

@yaobii-lab

Copy link
Copy Markdown
Contributor

Summary

This PR adds support for the Antigravity CLI (agy) runtime target alongside existing antigravity (legacy) and antigravity_ide (IDE) runtimes in Cockpit Tools. It introduces transactional account switching with rollback protection, cross-process concurrency locking, UI integration in Accounts and Dashboard, and full CLI support via cockpit-cli for account listing, inspection, switching, and single-command switch-and-run.


Architecture & SSoT Alignment

  • Single Source of Truth: Strictly adheres to the Antigravity multi-runtime specification.
  • Shared Account Store: Reuses the existing Antigravity Account[] database without duplicating account stores or creating parallel OAuth systems.
  • Target Independence: Each runtime target (antigravity, antigravity_ide, antigravity_cli) independently maintains its current active account binding.

Multi-Runtime Model

  • Three distinct runtime targets are recognized:
    1. antigravity (Legacy branch)
    2. antigravity_ide (IDE branch)
    3. antigravity_cli (CLI branch for agy)
  • Target-specific current account state is managed via provider_current_state.rs under the key antigravity_cli.
  • Switching accounts on antigravity_cli does not alter or disrupt the active accounts bound to antigravity or antigravity_ide.

Transaction & Rollback Design

Account switching uses a deterministic 5-step transaction:

  1. Prepare/Refresh: Proactively refreshes token if nearing expiration.
  2. Snapshot: Takes an in-memory snapshot of the existing system credential.
  3. Write: Updates system credential authority (gemini:antigravity).
  4. Verify: Reads back credential to guarantee that the stored credential matches the target account.
  5. Commit: Commits the new account ID to the provider current state binding.

If verification or any intermediate step fails, the transaction automatically restores the snapshot and returns a fail-closed error (CREDENTIAL_VERIFY_FAILED).


Cross-Process Locking

  • Cross-process file locking (CrossProcessSwitchLock) implemented via flock (LOCK_EX | LOCK_NB with polling timeout) on Unix platforms and LockFileEx on Windows.
  • Prevents race conditions between GUI and CLI child processes attempting concurrent switches against the shared OS credential authority.
  • Guarantees the critical invariant: credential active account == provider current account.

Switch-and-Run Decoupled Design

  • The credential switch transaction is decoupled from process launch.
  • If process launch fails (e.g. invalid working directory or terminal failure) after a successful credential switch, the account binding is preserved (CLI_LAUNCH_FAILED), avoiding unintended rollback of an authenticated credential.
  • cockpit-cli provides single-command switch-and-run:
    cockpit-cli run agy --account <account-id-or-email> -- <args>

Platform Status

Platform Implementation Status Verification Status Notes
macOS IMPLEMENTED VERIFIED Keychain access, native agy interaction, and cross-process tests verified
Windows IMPLEMENTED NOT VERIFIED Win32 Credential Manager API implemented, fail-closed
Linux IMPLEMENTED NOT VERIFIED Secret Service (secret-tool) implemented, fail-closed on missing daemon

Verification Evidence

  • Rust Integration Tests (antigravity_cli_integration_test.rs):
    • test_cli_account_switch_persistence_and_native_recognition: PASS
    • test_switch_and_run_decoupled_launch_failure: PASS
    • test_rollback_on_verify_failure: PASS
    • test_multi_runtime_target_state_isolation: PASS
    • test_concurrent_ab_switches_serialized: PASS
    • test_cross_process_concurrent_switch: PASS
  • Frontend Unit Tests:
    • src/utils/antigravityRuntimeTarget.test.ts: 5/5 tests PASS
  • TypeScript Typecheck:
    • npm run typecheck: PASS (0 errors)
  • CLI Commands Verified Live:
    • cockpit-cli accounts agy
    • cockpit-cli current agy
    • cockpit-cli switch agy <account>
    • cockpit-cli run agy --account <account> -- <args>

Security & Privacy Statement

  • Zero hardcoded personal identifiers, email addresses, or secrets in source code, tests, or documentation.
  • Integration tests dynamically read accounts from the local test environment.
  • System credential snapshots are maintained strictly in-memory during transaction lifecycles.

- Add antigravity_cli runtime target alongside antigravity (legacy) and antigravity_ide
- Share existing Antigravity Account[] storage without duplicate databases
- Implement transactional account switching with rollback protection (prepare -> snapshot -> write -> verify -> commit)
- Implement cross-process switch lock (flock / LockFileEx) to prevent concurrent switching races
- Decouple switch transaction from CLI process launch
- Add cockpit-cli support for list, current, switch, and switch-and-run (cockpit-cli run agy --account <acc> -- <args>)
- Add UI controls for Antigravity CLI runtime in AccountsPage and Dashboard
- Add integration tests covering switch persistence, launch failure decoupling, rollback, multi-runtime isolation, and cross-process concurrency
Comment on lines +148 to +150
" Current Acct: {} ({})",
email.green(),
status.current_account_id.as_deref().unwrap_or("")
let target = match target {
Some(a) => a,
None => {
println!("{} Antigravity account not found: {}", "Error:".red(), account);
Comment on lines +198 to +201
"{} Successfully switched Antigravity CLI account to {} ({})",
"Success:".green(),
switched.email,
switched.id
Comment on lines +247 to +250
"{} Antigravity CLI launched with account {} ({})",
"Success:".green(),
res.email,
res.account_id
println!("[Test 1] agy last auth log: {:?}", last_auth_line);
assert!(
last_auth_line.as_ref().map(|l| l.contains(account_b_email)).unwrap_or(false),
"Expected agy to authenticate as Account B ({})", account_b_email
Comment on lines +265 to +267
"Keychain credential must match the final bound account (ID: {}, err: {:?})",
final_bound_id,
verify_res.err()
Comment on lines +327 to +329
"Cross-process invariant failed! Credential in Keychain must match provider current account: final_bound_id={}, verify_err={:?}",
final_bound_id,
verify_res.err()

This branch has not been deployed

No deployments
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.

2 participants