Refactor Gemini model display: filter old versions, group low/high pкo, and improve naming (#114)

* Refactor Gemini model display: filter old versions, group low/high pro, and improve naming

* Fix potential negative minutes and refine Gemini 3 Pro grouping logic based on PR feedback

* The account change process has been sped up

* Address PR review: enhance error message and parameterize polling interval in process handler

* Address PR review: fix potential race condition in database backup logic

* fix: prevent renderer white screen and harden sentry gating

* feat:  localize model labels

* chore: enable hoisted node-linker

* chore: ignore .agent/.claude/.codex in prettier

---------

Co-authored-by: Draculabo <[email protected]>
This commit is contained in:
AngeloooooandDraculabo authored and GitHub committed 2026-02-19 19:37:30 +08:00
1 parent b9497648c6
commit 8ed4593f73
162 files changed
+2981 -2541

No files matched your search

+29 -28
View File
@@ -197,20 +197,25 @@ export async function switchCloudAccount(accountId: string): Promise<void> {
account.device_profile = generated;
}
// 1. Ensure token is fresh before injecting
const now = Math.floor(Date.now() / 1000);
if (account.token.expiry_timestamp < now + 300) {
logger.info(`Token for ${account.email} near expiry, refreshing before switch...`);
try {
const newTokenData = await GoogleAPIService.refreshAccessToken(account.token.refresh_token);
account.token.access_token = newTokenData.access_token;
account.token.expires_in = newTokenData.expires_in;
account.token.expiry_timestamp = now + newTokenData.expires_in;
await CloudAccountRepo.updateToken(account.id, account.token);
} catch (e) {
logger.warn('Failed to refresh token before switch, trying with existing token', e);
// 1. Prepare token refresh promise (start it in parallel with process exit)
const tokenRefreshPromise = (async () => {
const now = Math.floor(Date.now() / 1000);
if (account.token.expiry_timestamp < now + 1200) { // Increased buffer to 20m
logger.info(`Token for ${account.email} near expiry, refreshing in parallel...`);
try {
const newTokenData = await GoogleAPIService.refreshAccessToken(
account.token.refresh_token,
);
account.token.access_token = newTokenData.access_token;
account.token.expires_in = newTokenData.expires_in;
account.token.expiry_timestamp = now + newTokenData.expires_in;
await CloudAccountRepo.updateToken(account.id, account.token);
logger.info(`Token refreshed for ${account.email}`);
} catch (e) {
logger.warn('Failed to refresh token in parallel, will try to use existing', e);
}
}
}
})();
await executeSwitchFlow({
scope: 'cloud',
@@ -218,29 +223,25 @@ export async function switchCloudAccount(accountId: string): Promise<void> {
applyFingerprint: isIdentityProfileApplyEnabled(),
processExitTimeoutMs: 10000,
performSwitch: async () => {
// 3. Backup Database (New Logic)
const dbPaths = getAntigravityDbPaths();
// Find the valid DB path
let dbPath: string | null = null;
for (const p of dbPaths) {
if (fs.existsSync(p)) {
dbPath = p;
break;
}
}
// Wait for token refresh to complete before injection if it was started
await tokenRefreshPromise;
if (dbPath) {
// 3. Backup Database (Optimized to avoid race conditions)
const dbPaths = getAntigravityDbPaths();
for (const dbPath of dbPaths) {
try {
const backupPath = `${dbPath}.backup`;
fs.copyFileSync(dbPath, backupPath);
await fs.promises.copyFile(dbPath, backupPath);
logger.info(`Backed up database to ${backupPath}`);
} catch (e) {
logger.error('Failed to backup database', e);
break; // Success, stop trying other paths
} catch (e: any) {
// If file not found, just try the next path
if (e.code === 'ENOENT') continue;
logger.error(`Failed to backup database at ${dbPath}`, e);
}
}
// 4. Inject Token
// injectedCloudToken uses direct DB/FS access which is sync better-sqlite3.
CloudAccountRepo.injectCloudToken(account);
// 5. Update usage and active status