diff --git a/src/ipc/cloud/handler.ts b/src/ipc/cloud/handler.ts index 579d4a0..7574433 100644 --- a/src/ipc/cloud/handler.ts +++ b/src/ipc/cloud/handler.ts @@ -6,7 +6,7 @@ import { logger } from '../../utils/logger'; import { shell } from 'electron'; import fs from 'fs'; -import { closeAntigravity, startAntigravity } from '../../ipc/process/handler'; +import { closeAntigravity, startAntigravity, _waitForProcessExit } from '../../ipc/process/handler'; import { updateTrayMenu } from '../../ipc/tray/handler'; import { getAntigravityDbPaths } from '../../utils/paths'; @@ -189,7 +189,12 @@ export async function switchCloudAccount(accountId: string): Promise { } // 2. Stop Antigravity Process - await closeAntigravity(); // This waits for it to close + await closeAntigravity(); + try { + await _waitForProcessExit(10000); // Wait up to 10s for it to truly vanish + } catch (e) { + logger.warn('Process did not exit cleanly within timeout, but proceeding...', e); + } // 3. Backup Database (New Logic) const dbPaths = getAntigravityDbPaths(); @@ -214,7 +219,7 @@ export async function switchCloudAccount(accountId: string): Promise { // 3. Inject Token // injectedCloudToken uses direct DB/FS access which is sync better-sqlite3. - CloudAccountRepo.injectCloudToken(account.token); + CloudAccountRepo.injectCloudToken(account); // 4. Update usage and active status CloudAccountRepo.updateLastUsed(account.id); diff --git a/src/ipc/database/cloudHandler.ts b/src/ipc/database/cloudHandler.ts index 5fdb4e4..9d6027e 100644 --- a/src/ipc/database/cloudHandler.ts +++ b/src/ipc/database/cloudHandler.ts @@ -291,7 +291,7 @@ export class CloudAccountRepo { } } - static injectCloudToken(token: CloudAccount['token']): void { + static injectCloudToken(account: CloudAccount): void { const dbPaths = getAntigravityDbPaths(); let dbPath: string | null = null; @@ -325,9 +325,9 @@ export class CloudAccountRepo { // 3. Create New Field 6 const newField = ProtobufUtils.createOAuthTokenInfo( - token.access_token, - token.refresh_token, - token.expiry_timestamp, + account.token.access_token, + account.token.refresh_token, + account.token.expiry_timestamp, ); // 4. Concatenate @@ -344,13 +344,33 @@ export class CloudAccountRepo { 'jetskiStateSync.agentManagerInitState', ); - // 7. Inject Onboarding Flag (Missing in initial port) + // 7. Inject Onboarding Flag db.prepare('INSERT OR REPLACE INTO ItemTable (key, value) VALUES (?, ?)').run( 'antigravityOnboarding', 'true', ); - logger.info(`Successfully injected cloud token into Antigravity database at ${dbPath}.`); + // 8. Update Auth Status (Fix for switching issue) + // This ensures the UI reflects the user we just switched to + const authStatus = { + name: account.name || account.email, + email: account.email, + apiKey: account.token.access_token, // Critical for session recognition + // userStatusProtoBinaryBase64: ... // We cannot generate this easily, hoping IDE fetches it + }; + + db.prepare('INSERT OR REPLACE INTO ItemTable (key, value) VALUES (?, ?)').run( + 'antigravityAuthStatus', + JSON.stringify(authStatus), + ); + + // 9. Remove google.antigravity to prevent conflicts + // This key often holds old state that might override our injected state + db.prepare('DELETE FROM ItemTable WHERE key = ?').run('google.antigravity'); + + logger.info( + `Successfully injected cloud token and identity for ${account.email} into Antigravity database at ${dbPath}.`, + ); } finally { db.close(); } diff --git a/src/ipc/process/handler.ts b/src/ipc/process/handler.ts index 656d030..62befad 100644 --- a/src/ipc/process/handler.ts +++ b/src/ipc/process/handler.ts @@ -108,33 +108,67 @@ export async function closeAntigravity(): Promise { // Helper to list processes const getProcesses = (): { pid: number; name: string; cmd: string }[] => { try { - let cmd = ''; + let output = ''; if (platform === 'win32') { - // Use wmic to get process info - cmd = 'wmic process get ProcessId,Name,CommandLine /FORMAT:CSV'; + const psCommand = (cmdlet: string) => + `powershell -NoProfile -Command "${cmdlet} Win32_Process -Filter \\"Name like 'Antigravity%'\\" | Select-Object ProcessId, Name, CommandLine | ConvertTo-Csv -NoTypeInformation"`; + + try { + output = execSync(psCommand('Get-CimInstance'), { + encoding: 'utf-8', + maxBuffer: 1024 * 1024 * 10, + stdio: ['pipe', 'pipe', 'ignore'], + }); + } catch (e) { + // CIM failed (likely older OS), try WMI + try { + output = execSync(psCommand('Get-WmiObject'), { + encoding: 'utf-8', + maxBuffer: 1024 * 1024 * 10, + }); + } catch (innerE) { + // Both failed, throw original or log? Throwing lets the outer catch handle it (returning empty list) + throw e; + } + } } else { // Unix/Linux/macOS - cmd = 'ps -A -o pid,comm,args'; + output = execSync('ps -A -o pid,comm,args', { + encoding: 'utf-8', + maxBuffer: 1024 * 1024 * 10, + }); } - const output = execSync(cmd, { encoding: 'utf-8' }); - const lines = output.split('\n'); - const processList = []; + const processList: { pid: number; name: string; cmd: string }[] = []; - for (const line of lines) { - const parts = line.trim().split(/\s+/); - if (parts.length < 2) continue; - - if (platform === 'win32') { - // CSV format parsing would be better, but simple check for now - if (line.includes('Antigravity')) { - // Extract PID (usually last or second to last in CSV) - const match = line.match(/(\d+)(?:\s*$)/); - if (match) { - processList.push({ pid: parseInt(match[1]), name: 'Antigravity', cmd: line }); - } + if (platform === 'win32') { + // Parse CSV Output + const lines = output.trim().split(/\r?\n/); + // First line is headers "ProcessId","Name","CommandLine" + // We start from index 1 + for (let i = 1; i < lines.length; i++) { + const line = lines[i]; + if (!line) { + continue; } - } else { + + // Regex to match CSV fields: "val1","val2","val3" + const match = line.match(/^"(\d+)","(.*?)","(.*?)"$/); + + if (match) { + const pid = parseInt(match[1]); + const name = match[2]; + const cmdLine = match[3]; + + processList.push({ pid, name, cmd: cmdLine || name }); + } + } + } else { + const lines = output.split('\n'); + for (const line of lines) { + const parts = line.trim().split(/\s+/); + if (parts.length < 2) continue; + const pid = parseInt(parts[0]); if (isNaN(pid)) continue; const rest = parts.slice(1).join(' ');