fix(quota): fetch quota for paused accounts + simplify exhausted display

- Remove early return for paused accounts in quota fetcher
- Check both auth/ and auth-paused/ directories when reading auth data
- Allows users to see quota status of paused accounts to know when to unpause
- Remove "Exhausted" text in tooltip, just show 0% in red (saves width)
This commit is contained in:
kaitranntt
2026-01-25 17:12:45 -05:00
parent b2b8a85af6
commit 27e8813cae
3 changed files with 45 additions and 56 deletions
+43 -54
View File
@@ -11,7 +11,7 @@ import { getAuthDir } from './config-generator';
import { CLIProxyProvider } from './types';
import {
getProviderAccounts,
isAccountPaused,
getPausedDir,
setAccountTier,
type AccountInfo,
type AccountTier,
@@ -242,59 +242,60 @@ async function refreshAccessToken(
* Read auth data from auth file (access token, project_id, expiry status)
*/
function readAuthData(provider: CLIProxyProvider, accountId: string): AuthData | null {
const authDir = getAuthDir();
// Check if auth directory exists
if (!fs.existsSync(authDir)) {
return null;
}
// Check both active and paused auth directories (quota needed for paused accounts too)
const authDirs = [getAuthDir(), getPausedDir()];
// Sanitize accountId (email) to match auth file naming: @ and . → _
const sanitizedId = sanitizeEmail(accountId);
const prefix = provider === 'agy' ? 'antigravity-' : `${provider}-`;
const expectedFile = `${prefix}${sanitizedId}.json`;
const filePath = path.join(authDir, expectedFile);
// Direct file access (most common case)
if (fs.existsSync(filePath)) {
try {
const content = fs.readFileSync(filePath, 'utf-8');
const data = JSON.parse(content) as AntigravityAuthFile;
if (!data.access_token) return null;
return {
accessToken: data.access_token,
refreshToken: data.refresh_token || null,
projectId: data.project_id || null,
isExpired: isTokenExpired(data.expired),
expiresAt: data.expired || null,
};
} catch {
return null;
}
}
for (const authDir of authDirs) {
if (!fs.existsSync(authDir)) continue;
// Fallback: scan directory for matching email in file content
const files = fs.readdirSync(authDir);
for (const file of files) {
if (file.startsWith(prefix) && file.endsWith('.json')) {
const candidatePath = path.join(authDir, file);
const filePath = path.join(authDir, expectedFile);
// Direct file access (most common case)
if (fs.existsSync(filePath)) {
try {
const content = fs.readFileSync(candidatePath, 'utf-8');
const content = fs.readFileSync(filePath, 'utf-8');
const data = JSON.parse(content) as AntigravityAuthFile;
// Match by email field inside the auth file
if (data.email === accountId && data.access_token) {
return {
accessToken: data.access_token,
refreshToken: data.refresh_token || null,
projectId: data.project_id || null,
isExpired: isTokenExpired(data.expired),
expiresAt: data.expired || null,
};
}
if (!data.access_token) continue;
return {
accessToken: data.access_token,
refreshToken: data.refresh_token || null,
projectId: data.project_id || null,
isExpired: isTokenExpired(data.expired),
expiresAt: data.expired || null,
};
} catch {
continue;
}
}
// Fallback: scan directory for matching email in file content
const files = fs.readdirSync(authDir);
for (const file of files) {
if (file.startsWith(prefix) && file.endsWith('.json')) {
const candidatePath = path.join(authDir, file);
try {
const content = fs.readFileSync(candidatePath, 'utf-8');
const data = JSON.parse(content) as AntigravityAuthFile;
// Match by email field inside the auth file
if (data.email === accountId && data.access_token) {
return {
accessToken: data.access_token,
refreshToken: data.refresh_token || null,
projectId: data.project_id || null,
isExpired: isTokenExpired(data.expired),
expiresAt: data.expired || null,
};
}
} catch {
continue;
}
}
}
}
return null;
@@ -554,19 +555,7 @@ export async function fetchAccountQuota(
};
}
// Check if account is paused (token moved to auth-paused/ directory)
if (isAccountPaused(provider, accountId)) {
const error = 'Account is paused';
if (verbose) console.error(`[i] ${error}`);
return {
success: false,
models: [],
lastUpdated: Date.now(),
error,
};
}
// Read auth data from auth file
// Read auth data from auth file (checks both active and paused directories)
const authData = readAuthData(provider, accountId);
if (!authData) {
const error = 'Auth file not found for account';
@@ -240,7 +240,7 @@ export function AccountCard({
{m.displayName}
</span>
<span className={cn('font-mono', m.exhausted && 'text-red-500')}>
{m.exhausted ? 'Exhausted' : `${m.percentage}%`}
{m.percentage}%
</span>
</div>
))}
@@ -370,7 +370,7 @@ export function AccountItem({
{m.displayName}
</span>
<span className={cn('font-mono', m.exhausted && 'text-red-500')}>
{m.exhausted ? 'Exhausted' : `${m.percentage}%`}
{m.percentage}%
</span>
</div>
))}