when-does-my-quota-refresh 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{auth-S43EEJYA.js → auth-K5ETZYGY.js} +2 -2
- package/dist/{chunk-YZVX5QIP.js → chunk-24ILGZJ2.js} +2 -3
- package/dist/chunk-24ILGZJ2.js.map +1 -0
- package/dist/cli/index.js +2 -2
- package/dist/sdk/index.js +1 -2
- package/dist/sdk/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-YZVX5QIP.js.map +0 -1
- /package/dist/{auth-S43EEJYA.js.map → auth-K5ETZYGY.js.map} +0 -0
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
completeManualLogin,
|
|
4
4
|
getManualLoginUrl,
|
|
5
5
|
loginAccount
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-24ILGZJ2.js";
|
|
7
7
|
export {
|
|
8
8
|
completeManualLogin,
|
|
9
9
|
getManualLoginUrl,
|
|
10
10
|
loginAccount
|
|
11
11
|
};
|
|
12
|
-
//# sourceMappingURL=auth-
|
|
12
|
+
//# sourceMappingURL=auth-K5ETZYGY.js.map
|
|
@@ -28,8 +28,7 @@ var CLOUD_CODE_DEFAULT_BODY = {
|
|
|
28
28
|
var OAUTH_CLIENT_ID = "764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com";
|
|
29
29
|
var OAUTH_CLIENT_SECRET = "d-FL95Q19q7MQmFpd7hHD0Ty";
|
|
30
30
|
var OAUTH_SCOPES = [
|
|
31
|
-
"https://www.googleapis.com/auth/cloud-platform"
|
|
32
|
-
"https://www.googleapis.com/auth/cloudcode"
|
|
31
|
+
"https://www.googleapis.com/auth/cloud-platform"
|
|
33
32
|
].join(" ");
|
|
34
33
|
|
|
35
34
|
// src/sources/oauth/client.ts
|
|
@@ -484,4 +483,4 @@ export {
|
|
|
484
483
|
getManualLoginUrl,
|
|
485
484
|
completeManualLogin
|
|
486
485
|
};
|
|
487
|
-
//# sourceMappingURL=chunk-
|
|
486
|
+
//# sourceMappingURL=chunk-24ILGZJ2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sources/oauth/client.ts","../src/sources/cloud-code-api.ts","../src/sdk/accounts/storage.ts","../src/core/config.ts","../src/core/logger.ts","../src/core/errors.ts","../src/sdk/accounts/auth.ts"],"sourcesContent":["/**\n * Google OAuth client for Cloud Code API\n *\n * Handles the OAuth2 flow for remote quota fetching.\n */\n\nimport https from 'https'\nimport http from 'http'\nimport { URL } from 'url'\nimport { debug } from '../../core/logger.js'\nimport type { OAuthTokenResponse, StoredTokens } from '../../sdk/types.js'\nimport {\n CLOUD_CODE_ENDPOINTS,\n CLOUD_CODE_DEFAULT_BODY,\n OAUTH_CLIENT_ID,\n OAUTH_CLIENT_SECRET,\n OAUTH_SCOPES,\n} from '../cloud-code-api.js'\n\nexport class OAuthClient {\n private tokens: StoredTokens | null = null\n\n constructor(tokens?: StoredTokens) {\n this.tokens = tokens || null\n }\n\n /**\n * Generate the OAuth authorization URL for user login\n */\n getAuthUrl(): string {\n const params = new URLSearchParams({\n client_id: OAUTH_CLIENT_ID,\n redirect_uri: 'http://127.0.0.1:0/callback',\n response_type: 'code',\n scope: OAUTH_SCOPES,\n access_type: 'offline',\n prompt: 'consent',\n })\n return `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`\n }\n\n /**\n * Exchange an authorization code for tokens\n */\n async exchangeCode(code: string): Promise<StoredTokens> {\n const body = new URLSearchParams({\n code,\n client_id: OAUTH_CLIENT_ID,\n client_secret: OAUTH_CLIENT_SECRET,\n redirect_uri: 'http://127.0.0.1:0/callback',\n grant_type: 'authorization_code',\n })\n\n const response = await this.postUrlEncoded('https://oauth2.googleapis.com/token', body)\n const data = response as OAuthTokenResponse\n\n this.tokens = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token || '',\n expiresAt: Date.now() + data.expires_in * 1000,\n }\n\n return this.tokens\n }\n\n /**\n * Refresh the access token\n */\n async refreshAccessToken(): Promise<StoredTokens> {\n if (!this.tokens?.refreshToken) {\n throw new Error('No refresh token available')\n }\n\n const body = new URLSearchParams({\n client_id: OAUTH_CLIENT_ID,\n client_secret: OAUTH_CLIENT_SECRET,\n refresh_token: this.tokens.refreshToken,\n grant_type: 'refresh_token',\n })\n\n const response = await this.postUrlEncoded('https://oauth2.googleapis.com/token', body)\n const data = response as OAuthTokenResponse\n\n this.tokens = {\n ...this.tokens,\n accessToken: data.access_token,\n expiresAt: Date.now() + data.expires_in * 1000,\n }\n\n return this.tokens\n }\n\n /**\n * Get a valid access token, refreshing if necessary\n */\n async getAccessToken(): Promise<string> {\n if (!this.tokens) throw new Error('Not authenticated')\n if (Date.now() >= this.tokens.expiresAt - 60000) {\n await this.refreshAccessToken()\n }\n return this.tokens.accessToken!\n }\n\n /**\n * Get stored tokens\n */\n getTokens(): StoredTokens | null {\n return this.tokens\n }\n\n /**\n * Make an authenticated POST request to the Cloud Code API\n */\n async fetchQuotaSummary(): Promise<unknown> {\n const token = await this.getAccessToken()\n return this.authenticatedPost(\n CLOUD_CODE_ENDPOINTS.retrieveUserQuotaSummary,\n CLOUD_CODE_DEFAULT_BODY,\n token\n )\n }\n\n async fetchUserStatus(): Promise<unknown> {\n const token = await this.getAccessToken()\n return this.authenticatedPost(\n CLOUD_CODE_ENDPOINTS.loadCodeAssist,\n CLOUD_CODE_DEFAULT_BODY,\n token\n )\n }\n\n async fetchAvailableModels(): Promise<unknown> {\n const token = await this.getAccessToken()\n return this.authenticatedPost(\n CLOUD_CODE_ENDPOINTS.fetchAvailableModels,\n CLOUD_CODE_DEFAULT_BODY,\n token\n )\n }\n\n // ── HTTP Helpers ────────────────────────────────────────────────\n\n private authenticatedPost(url: string, body: unknown, token: string): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const parsed = new URL(url)\n const data = JSON.stringify(body)\n const options: http.RequestOptions = {\n hostname: parsed.hostname,\n path: parsed.pathname,\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`,\n 'Content-Length': Buffer.byteLength(data),\n },\n timeout: 10000,\n }\n\n const req = https.request(options, (res) => {\n let responseData = ''\n res.on('data', (chunk: Buffer) => { responseData += chunk })\n res.on('end', () => {\n try {\n resolve(JSON.parse(responseData))\n } catch {\n reject(new Error(`Invalid JSON: ${responseData.slice(0, 200)}`))\n }\n })\n })\n req.on('error', reject)\n req.on('timeout', () => { req.destroy(); reject(new Error('Timeout')) })\n req.write(data)\n req.end()\n })\n }\n\n private postUrlEncoded(url: string, body: URLSearchParams): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const parsed = new URL(url)\n const data = body.toString()\n const options: http.RequestOptions = {\n hostname: parsed.hostname,\n path: parsed.pathname,\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n 'Content-Length': Buffer.byteLength(data),\n },\n timeout: 10000,\n }\n\n const req = https.request(options, (res) => {\n let responseData = ''\n res.on('data', (chunk: Buffer) => { responseData += chunk })\n res.on('end', () => {\n try {\n resolve(JSON.parse(responseData))\n } catch {\n reject(new Error(`Invalid JSON: ${responseData.slice(0, 200)}`))\n }\n })\n })\n req.on('error', reject)\n req.on('timeout', () => { req.destroy(); reject(new Error('Timeout')) })\n req.write(data)\n req.end()\n })\n }\n}\n","/**\n * Google Cloud Code API endpoints for remote quota fetching\n *\n * Used as fallback when local sources are unavailable.\n * Requires OAuth authentication.\n */\n\nexport const CLOUD_CODE_ENDPOINTS = {\n /** Load code assist configuration */\n loadCodeAssist: 'https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist',\n\n /** Onboard a new user */\n onboardUser: 'https://cloudcode-pa.googleapis.com/v1internal:onboardUser',\n\n /** Fetch available models for the account */\n fetchAvailableModels: 'https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels',\n\n /** Fetch raw quota data */\n retrieveUserQuota: 'https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuota',\n\n /** Fetch quota summary with weekly + session buckets */\n retrieveUserQuotaSummary: 'https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuotaSummary',\n} as const\n\nexport const CLOUD_CODE_DEFAULT_BODY = {\n metadata: {\n ideName: 'antigravity',\n extensionName: 'antigravity',\n locale: 'en',\n ideVersion: 'unknown',\n },\n}\n\nexport const OAUTH_CLIENT_ID = '764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com'\nexport const OAUTH_CLIENT_SECRET = 'd-FL95Q19q7MQmFpd7hHD0Ty'\nexport const OAUTH_SCOPES = [\n 'https://www.googleapis.com/auth/cloud-platform',\n].join(' ')\nexport const OAUTH_REDIRECT_URI = 'http://127.0.0.1:0/callback'\n","/**\n * Token storage for account credentials\n *\n * Stores OAuth tokens locally in the config directory.\n * Tokens are stored as plain JSON (local machine only).\n */\n\nimport { readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs'\nimport { join } from 'path'\nimport type { StoredTokens } from '../types.js'\nimport { getConfigDirPath, ensureDirs } from '../../core/config.js'\nimport { debug } from '../../core/logger.js'\n\nconst TOKENS_DIR = 'accounts'\n\ninterface TokenAccount {\n email: string\n tokens: StoredTokens\n addedAt: string\n}\n\ninterface TokenStore {\n accounts: TokenAccount[]\n activeEmail?: string\n}\n\nfunction getStorePath(): string {\n return join(getConfigDirPath(), TOKENS_DIR, 'tokens.json')\n}\n\nfunction loadStore(): TokenStore {\n const path = getStorePath()\n if (!existsSync(path)) return { accounts: [] }\n try {\n return JSON.parse(readFileSync(path, 'utf-8'))\n } catch {\n return { accounts: [] }\n }\n}\n\nfunction saveStore(store: TokenStore): void {\n ensureDirs()\n writeFileSync(getStorePath(), JSON.stringify(store, null, 2))\n debug('account-storage', `Saved ${store.accounts.length} account(s)`)\n}\n\n/**\n * Save tokens for an account\n */\nexport function saveAccountTokens(email: string, tokens: StoredTokens): void {\n const store = loadStore()\n const existing = store.accounts.findIndex(a => a.email === email)\n const account: TokenAccount = {\n email,\n tokens,\n addedAt: new Date().toISOString(),\n }\n\n if (existing >= 0) {\n store.accounts[existing] = account\n } else {\n store.accounts.push(account)\n }\n\n // Set as active if it's the only one\n if (store.accounts.length === 1) {\n store.activeEmail = email\n }\n\n saveStore(store)\n}\n\n/**\n * Get tokens for a specific account\n */\nexport function getAccountTokens(email: string): StoredTokens | null {\n const store = loadStore()\n const account = store.accounts.find(a => a.email === email)\n return account?.tokens || null\n}\n\n/**\n * Get the active account's tokens\n */\nexport function getActiveAccountTokens(): StoredTokens | null {\n const store = loadStore()\n if (!store.activeEmail) return null\n const account = store.accounts.find(a => a.email === store.activeEmail)\n return account?.tokens || null\n}\n\n/**\n * Set the active account\n */\nexport function setActiveAccount(email: string): boolean {\n const store = loadStore()\n if (!store.accounts.find(a => a.email === email)) return false\n store.activeEmail = email\n saveStore(store)\n return true\n}\n\n/**\n * Remove an account\n */\nexport function removeAccount(email: string): boolean {\n const store = loadStore()\n const idx = store.accounts.findIndex(a => a.email === email)\n if (idx < 0) return false\n store.accounts.splice(idx, 1)\n if (store.activeEmail === email) {\n store.activeEmail = store.accounts[0]?.email\n }\n saveStore(store)\n return true\n}\n\n/**\n * List all stored accounts\n */\nexport function listAccounts(): Array<{ email: string; isActive: boolean; addedAt: string }> {\n const store = loadStore()\n return store.accounts.map(a => ({\n email: a.email,\n isActive: a.email === store.activeEmail,\n addedAt: a.addedAt,\n }))\n}\n\n/**\n * Get all stored tokens (for multi-account fetch)\n */\nexport function getAllAccountTokens(): StoredTokens[] {\n const store = loadStore()\n return store.accounts.map(a => a.tokens)\n}\n","/**\n * Config file management — reads/writes app configuration\n */\n\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs'\nimport { join } from 'path'\nimport { homedir } from 'os'\nimport type { AppConfig } from '../sdk/types.js'\nimport { debug } from './logger.js'\n\nconst CONFIG_DIR_NAME = 'when-does-my-quota-refresh'\n\nconst DEFAULT_CONFIG: AppConfig = {\n defaultMode: 'local',\n cacheTtlMs: 5 * 60 * 1000, // 5 minutes\n refreshIntervalMs: 5 * 60 * 1000,\n wakeupModels: ['claude-sonnet-4-5', 'gemini-3-flash', 'gemini-3-pro-low'],\n wakeupAccounts: [],\n notifications: true,\n plugins: [],\n daemon: {\n pollIntervalMs: 60 * 1000,\n enabled: false,\n },\n}\n\nfunction getConfigDir(): string {\n const home = homedir()\n switch (process.platform) {\n case 'darwin':\n return join(home, 'Library', 'Application Support', CONFIG_DIR_NAME)\n case 'win32':\n return join(process.env.APPDATA || join(home, 'AppData', 'Roaming'), CONFIG_DIR_NAME)\n default:\n return join(home, '.config', CONFIG_DIR_NAME)\n }\n}\n\nfunction getConfigPath(): string {\n return join(getConfigDir(), 'config.json')\n}\n\nfunction getDataDir(): string {\n return join(getConfigDir(), 'data')\n}\n\nexport function ensureDirs(): void {\n const configDir = getConfigDir()\n const dataDir = getDataDir()\n if (!existsSync(configDir)) mkdirSync(configDir, { recursive: true })\n if (!existsSync(dataDir)) mkdirSync(dataDir, { recursive: true })\n}\n\nexport function loadConfig(): AppConfig {\n try {\n const path = getConfigPath()\n if (!existsSync(path)) return DEFAULT_CONFIG\n const raw = readFileSync(path, 'utf-8')\n const parsed = JSON.parse(raw)\n debug('config', `Loaded config from ${path}`)\n return { ...DEFAULT_CONFIG, ...parsed }\n } catch (err) {\n debug('config', 'Failed to load config, using defaults', err)\n return DEFAULT_CONFIG\n }\n}\n\nexport function saveConfig(config: AppConfig): void {\n ensureDirs()\n const path = getConfigPath()\n writeFileSync(path, JSON.stringify(config, null, 2))\n debug('config', `Saved config to ${path}`)\n}\n\nexport function getConfigDirPath(): string {\n return getConfigDir()\n}\n\nexport function getDataDirPath(): string {\n return getDataDir()\n}\n\nexport { DEFAULT_CONFIG }\n","/**\n * Simple logger with debug flag\n */\n\nlet _verbose = false\n\nexport function setVerbose(verbose: boolean): void {\n _verbose = verbose\n}\n\nexport function debug(module: string, msg: string, data?: unknown): void {\n if (!_verbose) return\n const prefix = `[${module}]`\n if (data !== undefined) {\n console.error(`${prefix} ${msg}`, data)\n } else {\n console.error(`${prefix} ${msg}`)\n }\n}\n\nexport function info(msg: string): void {\n console.error(msg)\n}\n\nexport function warn(msg: string): void {\n console.error(`⚠ ${msg}`)\n}\n","/**\n * Custom error types for when-does-my-quota-refresh\n */\n\nexport class SourceUnavailableError extends Error {\n constructor(source: string, reason?: string) {\n super(`Source \"${source}\" unavailable${reason ? `: ${reason}` : ''}`)\n this.name = 'SourceUnavailableError'\n }\n}\n\nexport class AuthError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'AuthError'\n }\n}\n\nexport class QuotaFetchError extends Error {\n constructor(source: string, reason?: string) {\n super(`Failed to fetch quota from \"${source}\"${reason ? `: ${reason}` : ''}`)\n this.name = 'QuotaFetchError'\n }\n}\n\nexport class ProcessNotFoundError extends Error {\n constructor() {\n super('Antigravity language server process not found')\n this.name = 'ProcessNotFoundError'\n }\n}\n\nexport class PortDiscoveryError extends Error {\n constructor(pid: number, platform: string) {\n super(`Failed to discover ports for PID ${pid} on ${platform}`)\n this.name = 'PortDiscoveryError'\n }\n}\n","/**\n * OAuth authentication flow for Google accounts\n */\n\nimport { OAuthClient } from '../../sources/oauth/client.js'\nimport { saveAccountTokens, setActiveAccount } from './storage.js'\nimport { debug } from '../../core/logger.js'\nimport { AuthError } from '../../core/errors.js'\nimport open from 'open'\nimport http from 'http'\nimport { URL } from 'url'\n\n/**\n * Start an interactive OAuth login flow\n *\n * Opens the browser for Google login, then captures the redirect\n * to exchange the authorization code for tokens.\n */\nexport async function loginAccount(): Promise<string> {\n const client = new OAuthClient()\n const authUrl = client.getAuthUrl()\n\n debug('auth', 'Starting OAuth login flow')\n\n // Start a temporary local server to catch the redirect\n const code = await new Promise<string>((resolve, reject) => {\n const server = http.createServer(async (req, res) => {\n const url = new URL(req.url || '/', `http://127.0.0.1`)\n const code = url.searchParams.get('code')\n\n if (code) {\n res.writeHead(200, { 'Content-Type': 'text/html' })\n res.end(`\n <html><body style=\"font-family: sans-serif; text-align: center; padding: 50px;\">\n <h1>✅ Login successful!</h1>\n <p>You can close this tab and return to the terminal.</p>\n </body></html>\n `)\n server.close()\n resolve(code)\n } else {\n const error = url.searchParams.get('error')\n if (error) {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n res.end(`<h1>Login failed: ${error}</h1>`)\n server.close()\n reject(new AuthError(`OAuth error: ${error}`))\n } else {\n res.writeHead(404)\n res.end('Waiting for OAuth callback...')\n }\n }\n })\n\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address()\n if (typeof addr === 'object' && addr) {\n // Update redirect URI with actual port\n debug('auth', `Callback server on port ${addr.port}`)\n\n // Open browser\n open(authUrl).catch(() => {\n console.log(`\\nOpen this URL in your browser:\\n\\n${authUrl}\\n`)\n })\n }\n })\n\n // Timeout after 5 minutes\n setTimeout(() => {\n server.close()\n reject(new AuthError('Login timed out after 5 minutes'))\n }, 5 * 60 * 1000)\n })\n\n // Exchange code for tokens\n const tokens = await client.exchangeCode(code)\n\n // Get user email\n const email = tokens.email || 'unknown@gmail.com'\n tokens.email = email\n\n // Store tokens\n saveAccountTokens(email, tokens)\n setActiveAccount(email)\n\n debug('auth', `Logged in as ${email}`)\n return email\n}\n\n/**\n * Perform a manual login (headless/SSH mode)\n * Returns the auth URL for the user to open manually\n */\nexport function getManualLoginUrl(): string {\n const client = new OAuthClient()\n return client.getAuthUrl()\n}\n\n/**\n * Complete manual login with an authorization code\n */\nexport async function completeManualLogin(code: string): Promise<string> {\n const client = new OAuthClient()\n const tokens = await client.exchangeCode(code)\n const email = tokens.email || 'unknown@gmail.com'\n tokens.email = email\n saveAccountTokens(email, tokens)\n setActiveAccount(email)\n return email\n}\n"],"mappings":"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","names":["readFileSync","writeFileSync","existsSync","join","join","existsSync","readFileSync","writeFileSync","URL","code"]}
|
package/dist/cli/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
saveConfig,
|
|
16
16
|
setActiveAccount,
|
|
17
17
|
setVerbose
|
|
18
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-24ILGZJ2.js";
|
|
19
19
|
|
|
20
20
|
// src/cli/index.ts
|
|
21
21
|
import { Command } from "commander";
|
|
@@ -1659,7 +1659,7 @@ function registerAccountsCommand(program2) {
|
|
|
1659
1659
|
accounts.command("add").description("Login a new Google account").option("--manual", "Manual login for headless/SSH (get URL instead of browser)").action(async (opts) => {
|
|
1660
1660
|
try {
|
|
1661
1661
|
if (opts.manual) {
|
|
1662
|
-
const { getManualLoginUrl: getManualLoginUrl2, completeManualLogin: completeManualLogin2 } = await import("../auth-
|
|
1662
|
+
const { getManualLoginUrl: getManualLoginUrl2, completeManualLogin: completeManualLogin2 } = await import("../auth-K5ETZYGY.js");
|
|
1663
1663
|
const url = getManualLoginUrl2();
|
|
1664
1664
|
console.log(chalk6.bold("\nOpen this URL in your browser:\n"));
|
|
1665
1665
|
console.log(chalk6.cyan(url));
|
package/dist/sdk/index.js
CHANGED
|
@@ -986,8 +986,7 @@ var CLOUD_CODE_DEFAULT_BODY = {
|
|
|
986
986
|
var OAUTH_CLIENT_ID = "764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com";
|
|
987
987
|
var OAUTH_CLIENT_SECRET = "d-FL95Q19q7MQmFpd7hHD0Ty";
|
|
988
988
|
var OAUTH_SCOPES = [
|
|
989
|
-
"https://www.googleapis.com/auth/cloud-platform"
|
|
990
|
-
"https://www.googleapis.com/auth/cloudcode"
|
|
989
|
+
"https://www.googleapis.com/auth/cloud-platform"
|
|
991
990
|
].join(" ");
|
|
992
991
|
|
|
993
992
|
// src/sources/oauth/client.ts
|
package/dist/sdk/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/logger.ts","../../src/core/errors.ts","../../src/core/platform.ts","../../src/sources/local/process-detector.ts","../../src/sources/local/port-detective.ts","../../src/sources/local/connect-client.ts","../../src/sources/local/parser.ts","../../src/sources/local/index.ts","../../src/sources/cli/index.ts","../../src/sources/oauth/index.ts","../../src/sources/oauth/client.ts","../../src/sources/cloud-code-api.ts","../../src/sources/index.ts","../../src/sdk/cache.ts","../../src/sdk/store.ts","../../src/core/config.ts","../../src/sdk/accounts/storage.ts","../../src/sdk/accounts/auth.ts","../../src/sdk/quota.ts","../../src/sdk/index.ts"],"sourcesContent":["/**\n * Simple logger with debug flag\n */\n\nlet _verbose = false\n\nexport function setVerbose(verbose: boolean): void {\n _verbose = verbose\n}\n\nexport function debug(module: string, msg: string, data?: unknown): void {\n if (!_verbose) return\n const prefix = `[${module}]`\n if (data !== undefined) {\n console.error(`${prefix} ${msg}`, data)\n } else {\n console.error(`${prefix} ${msg}`)\n }\n}\n\nexport function info(msg: string): void {\n console.error(msg)\n}\n\nexport function warn(msg: string): void {\n console.error(`⚠ ${msg}`)\n}\n","/**\n * Custom error types for when-does-my-quota-refresh\n */\n\nexport class SourceUnavailableError extends Error {\n constructor(source: string, reason?: string) {\n super(`Source \"${source}\" unavailable${reason ? `: ${reason}` : ''}`)\n this.name = 'SourceUnavailableError'\n }\n}\n\nexport class AuthError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'AuthError'\n }\n}\n\nexport class QuotaFetchError extends Error {\n constructor(source: string, reason?: string) {\n super(`Failed to fetch quota from \"${source}\"${reason ? `: ${reason}` : ''}`)\n this.name = 'QuotaFetchError'\n }\n}\n\nexport class ProcessNotFoundError extends Error {\n constructor() {\n super('Antigravity language server process not found')\n this.name = 'ProcessNotFoundError'\n }\n}\n\nexport class PortDiscoveryError extends Error {\n constructor(pid: number, platform: string) {\n super(`Failed to discover ports for PID ${pid} on ${platform}`)\n this.name = 'PortDiscoveryError'\n }\n}\n","/**\n * Cross-platform platform detection and utilities\n */\n\nimport { exec } from 'child_process'\nimport { promisify } from 'util'\n\nconst execAsync = promisify(exec)\n\nexport type Platform = 'darwin' | 'linux' | 'win32'\n\nexport function getPlatform(): Platform {\n return process.platform as Platform\n}\n\nexport function isWindows(): boolean {\n return process.platform === 'win32'\n}\n\nexport function isMacOS(): boolean {\n return process.platform === 'darwin'\n}\n\nexport function isLinux(): boolean {\n return process.platform === 'linux'\n}\n\n/**\n * Run a shell command and return stdout\n */\nexport async function runCommand(cmd: string): Promise<string> {\n try {\n const { stdout } = await execAsync(cmd, { timeout: 10000 })\n return stdout\n } catch {\n return ''\n }\n}\n\n/**\n * Format milliseconds as human-readable countdown\n */\nexport function formatCountdown(ms: number): string {\n if (ms <= 0) return 'now'\n const totalMinutes = Math.floor(ms / 60000)\n const hours = Math.floor(totalMinutes / 60)\n const minutes = totalMinutes % 60\n if (hours > 0) return `${hours}h ${minutes}m`\n return `${minutes}m`\n}\n\n/**\n * Format a fraction (0–1) as a percentage string\n */\nexport function formatPercentage(fraction: number): string {\n return `${Math.round(fraction * 100)}%`\n}\n\n/**\n * Clamp a number between min and max\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max)\n}\n","/**\n * Cross-platform process detection for Antigravity language server\n *\n * Fixes the Windows detection bug in antigravity-usage by using\n * multiple detection strategies per platform.\n */\n\nimport { runCommand, isWindows, isMacOS, isLinux } from '../../core/platform.js'\nimport { debug } from '../../core/logger.js'\nimport type { ProcessInfo } from '../../sdk/types.js'\n\nconst ANTIMATTER_MARKERS = [\n 'antigravity',\n 'language_server',\n 'language-server',\n 'antigravity-cli',\n 'antigravity_cli',\n 'agy',\n]\n\nconst ANTIMATTER_PATH_MARKERS = [\n '/antigravity/',\n 'Antigravity',\n 'antigravity.app',\n 'AntigravityStatusProbe',\n 'app_data_dir antigravity',\n]\n\n/**\n * Detect all running Antigravity language server processes\n */\nexport async function detectAntigravityProcesses(): Promise<ProcessInfo[]> {\n debug('process-detector', `Detecting on platform: ${process.platform}`)\n\n let processes: ProcessInfo[] = []\n\n if (isMacOS()) {\n processes = await detectOnMacOS()\n } else if (isLinux()) {\n processes = await detectOnLinux()\n } else if (isWindows()) {\n processes = await detectOnWindows()\n }\n\n debug('process-detector', `Found ${processes.length} process(es)`)\n return processes\n}\n\n/**\n * macOS: ps -ax with command line parsing\n */\nasync function detectOnMacOS(): Promise<ProcessInfo[]> {\n const output = await runCommand('ps -ax -o pid=,comm=,args=')\n return parsePsOutput(output)\n}\n\n/**\n * Linux: ps with full command line\n */\nasync function detectOnLinux(): Promise<ProcessInfo[]> {\n const output = await runCommand('ps -eo pid,comm,args --no-headers')\n return parsePsOutput(output)\n}\n\n/**\n * Windows: Multiple strategies combined\n * 1. wmic for process listing with command lines\n * 2. PowerShell Get-CimInstance as fallback\n * 3. tasklist as last resort\n */\nasync function detectOnWindows(): Promise<ProcessInfo[]> {\n // Strategy 1: wmic\n let output = await runCommand(\n 'wmic process where \"name like \\'%language%\\' or commandline like \\'%antigravity%\\'\" get ProcessId,Name,CommandLine /format:csv'\n )\n let processes = parseWmicOutput(output)\n if (processes.length > 0) return processes\n\n // Strategy 2: PowerShell\n output = await runCommand(\n 'powershell -Command \"Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -match \\'antigravity|language.server\\' } | Select-Object ProcessId,Name,CommandLine | Format-Table -AutoSize\"'\n )\n processes = parsePowerShellOutput(output)\n if (processes.length > 0) return processes\n\n // Strategy 3: netstat scan for known port patterns (fallback)\n // This won't identify the process but can help with port discovery\n debug('process-detector', 'Windows: Falling back to port-based detection')\n return []\n}\n\n/**\n * Parse ps output (macOS/Linux)\n */\nfunction parsePsOutput(output: string): ProcessInfo[] {\n const processes: ProcessInfo[] = []\n const lines = output.split('\\n').filter(Boolean)\n\n for (const line of lines) {\n const trimmed = line.trim()\n if (!trimmed) continue\n\n // ps output format: PID COMM ARGS\n // comm is the short name, args is the full command line\n const parts = trimmed.split(/\\s+/)\n const pid = parseInt(parts[0], 10)\n if (isNaN(pid)) continue\n\n // The rest after PID is comm + args\n const rest = parts.slice(1).join(' ')\n\n if (matchesAntigravity(rest)) {\n processes.push({\n pid,\n name: parts[1] || 'unknown',\n commandLine: rest,\n scope: classifyProcess(rest),\n })\n }\n }\n\n return processes\n}\n\n/**\n * Parse wmic CSV output (Windows)\n */\nfunction parseWmicOutput(output: string): ProcessInfo[] {\n const processes: ProcessInfo[] = []\n const lines = output.split('\\n').filter(Boolean)\n\n for (const line of lines) {\n // wmic CSV format: Node,CommandLine,Name,ProcessId\n const parts = line.split(',').map(p => p.trim().replace(/\"/g, ''))\n if (parts.length < 4) continue\n\n const pid = parseInt(parts[3], 10)\n if (isNaN(pid)) continue\n\n const commandLine = parts[1] || ''\n const name = parts[2] || ''\n\n if (matchesAntigravity(commandLine) || matchesAntigravity(name)) {\n processes.push({\n pid,\n name,\n commandLine,\n scope: classifyProcess(commandLine),\n })\n }\n }\n\n return processes\n}\n\n/**\n * Parse PowerShell output (Windows)\n */\nfunction parsePowerShellOutput(output: string): ProcessInfo[] {\n const processes: ProcessInfo[] = []\n const lines = output.split('\\n').filter(Boolean)\n\n for (const line of lines) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith('---') || trimmed.startsWith('ProcessId')) continue\n\n // PowerShell table format: PID Name CommandLine (whitespace-separated)\n const match = trimmed.match(/^\\s*(\\d+)\\s+(\\S+)\\s+(.*)$/)\n if (!match) continue\n\n const pid = parseInt(match[1], 10)\n const name = match[2]\n const commandLine = match[3]\n\n if (matchesAntigravity(commandLine) || matchesAntigravity(name)) {\n processes.push({\n pid,\n name,\n commandLine,\n scope: classifyProcess(commandLine),\n })\n }\n }\n\n return processes\n}\n\n/**\n * Check if a string matches Antigravity markers\n */\nfunction matchesAntigravity(text: string): boolean {\n const lower = text.toLowerCase()\n return ANTIMATTER_PATH_MARKERS.some(marker =>\n lower.includes(marker.toLowerCase())\n ) || (\n lower.includes('language') &&\n lower.includes('server') &&\n ANTIMATTER_MARKERS.some(m => lower.includes(m))\n )\n}\n\n/**\n * Classify process by its command line flags\n */\nfunction classifyProcess(commandLine: string): ProcessInfo['scope'] {\n const lower = commandLine.toLowerCase()\n if (lower.includes('antigravity-cli') || lower.includes('antigravity_cli') || lower.includes('agy')) {\n return 'cli'\n }\n if (lower.includes('antigravity ide') || lower.includes('antigravity-ide') || lower.includes('extensions/antigravity')) {\n return 'ide'\n }\n if (lower.includes('app_data_dir antigravity') || lower.includes('antigravity.app')) {\n return 'app'\n }\n return 'unknown'\n}\n\n/**\n * Extract command-line flags from process command line\n */\nexport function extractFlags(commandLine: string): Map<string, string> {\n const flags = new Map<string, string>()\n if (!commandLine) return flags\n\n // Match --flag value patterns\n const flagRegex = /--(\\S+)\\s+([^\\s-][^\\s]*)/g\n let match\n while ((match = flagRegex.exec(commandLine)) !== null) {\n flags.set(match[1], match[2])\n }\n\n return flags\n}\n","/**\n * Cross-platform port discovery for Antigravity language server\n *\n * Improved Windows support: netstat + PowerShell + port range scanning\n */\n\nimport { runCommand, isWindows, isMacOS, isLinux } from '../../core/platform.js'\nimport { debug } from '../../core/logger.js'\n\n/**\n * Discover all listening ports for a given process PID\n */\nexport async function discoverPorts(pid: number): Promise<number[]> {\n debug('port-detective', `Discovering ports for PID ${pid} on ${process.platform}`)\n\n if (isWindows()) {\n return discoverPortsOnWindows(pid)\n } else if (isMacOS()) {\n return discoverPortsOnMacOS(pid)\n } else {\n return discoverPortsOnLinux(pid)\n }\n}\n\n/**\n * macOS: lsof\n */\nasync function discoverPortsOnMacOS(pid: number): Promise<number[]> {\n try {\n const output = await runCommand(`lsof -nP -iTCP -sTCP:LISTEN -a -p ${pid}`)\n const ports: number[] = []\n for (const line of output.split('\\n')) {\n const match = line.match(/:(\\d+)\\s+\\(LISTEN\\)/)\n if (match) {\n const port = parseInt(match[1], 10)\n if (!isNaN(port) && !ports.includes(port)) {\n ports.push(port)\n }\n }\n }\n debug('port-detective', `macOS ports: ${ports.join(', ')}`)\n return ports\n } catch {\n return []\n }\n}\n\n/**\n * Linux: ss with netstat fallback\n */\nasync function discoverPortsOnLinux(pid: number): Promise<number[]> {\n // Try ss first\n try {\n const output = await runCommand(`ss -tlnp | grep \"pid=${pid},\"`)\n const ports = parseListenPorts(output)\n if (ports.length > 0) {\n debug('port-detective', `Linux ports (ss): ${ports.join(', ')}`)\n return ports\n }\n } catch { /* fall through */ }\n\n // Fallback to netstat\n try {\n const output = await runCommand(`netstat -tlnp 2>/dev/null | grep \"${pid}/\"`)\n const ports = parseListenPorts(output)\n debug('port-detective', `Linux ports (netstat): ${ports.join(', ')}`)\n return ports\n } catch {\n return []\n }\n}\n\n/**\n * Windows: netstat + PowerShell Get-NetTCPConnection\n */\nasync function discoverPortsOnWindows(pid: number): Promise<number[]> {\n // Strategy 1: netstat -ano\n try {\n const output = await runCommand('netstat -ano')\n const ports: number[] = []\n for (const line of output.split('\\n')) {\n if (!line.includes('LISTENING')) continue\n const parts = line.trim().split(/\\s+/)\n const linePid = parseInt(parts[parts.length - 1], 10)\n if (linePid === pid) {\n const localAddr = parts[1]\n const portMatch = localAddr.match(/:(\\d+)$/)\n if (portMatch) {\n const port = parseInt(portMatch[1], 10)\n if (!isNaN(port) && !ports.includes(port)) {\n ports.push(port)\n }\n }\n }\n }\n if (ports.length > 0) {\n debug('port-detective', `Windows ports (netstat): ${ports.join(', ')}`)\n return ports\n }\n } catch { /* fall through */ }\n\n // Strategy 2: PowerShell Get-NetTCPConnection\n try {\n const output = await runCommand(\n `powershell -Command \"Get-NetTCPConnection -OwningProcess ${pid} -State Listen -ErrorAction SilentlyContinue | Select-Object LocalPort | Format-Table -AutoSize\"`\n )\n const ports: number[] = []\n for (const line of output.split('\\n')) {\n const match = line.match(/^\\s*(\\d+)\\s*$/)\n if (match) {\n const port = parseInt(match[1], 10)\n if (!isNaN(port) && !ports.includes(port)) {\n ports.push(port)\n }\n }\n }\n if (ports.length > 0) {\n debug('port-detective', `Windows ports (PowerShell): ${ports.join(', ')}`)\n return ports\n }\n } catch { /* fall through */ }\n\n // Strategy 3: Extract port from process command-line flags\n // The --extension_server_port flag tells us the port directly\n debug('port-detective', 'Windows: Could not find ports via system commands')\n return []\n}\n\n/**\n * Parse port numbers from ss/netstat output lines\n */\nfunction parseListenPorts(output: string): number[] {\n const ports: number[] = []\n for (const line of output.split('\\n')) {\n const match = line.match(/:(\\d+)\\s/)\n if (match) {\n const port = parseInt(match[1], 10)\n if (!isNaN(port) && !ports.includes(port)) {\n ports.push(port)\n }\n }\n }\n return ports\n}\n\n/**\n * Scan a range of ports on localhost to find HTTPS Antigravity servers\n * Last resort for Windows when process-based detection fails\n */\nexport async function scanPortRange(\n startPort: number = 8000,\n endPort: number = 9500\n): Promise<number[]> {\n debug('port-detective', `Scanning port range ${startPort}-${endPort}`)\n const foundPorts: number[] = []\n\n // Use netstat to find all LISTENING ports in the range\n if (isWindows()) {\n const output = await runCommand('netstat -ano')\n for (const line of output.split('\\n')) {\n if (!line.includes('LISTENING')) continue\n const parts = line.trim().split(/\\s+/)\n const localAddr = parts[1]\n const portMatch = localAddr.match(/:(\\d+)$/)\n if (portMatch) {\n const port = parseInt(portMatch[1], 10)\n if (port >= startPort && port <= endPort) {\n foundPorts.push(port)\n }\n }\n }\n } else {\n const cmd = isMacOS()\n ? `lsof -nP -iTCP -sTCP:LISTEN`\n : `ss -tlnp`\n const output = await runCommand(cmd)\n for (const line of output.split('\\n')) {\n const match = line.match(/:(\\d+)\\s/)\n if (match) {\n const port = parseInt(match[1], 10)\n if (port >= startPort && port <= endPort && !foundPorts.includes(port)) {\n foundPorts.push(port)\n }\n }\n }\n }\n\n debug('port-detective', `Found ${foundPorts.length} ports in range`)\n return foundPorts\n}\n","/**\n * Connect RPC client for Antigravity language server\n *\n * Communicates with the local Antigravity server using the Connect protocol\n * to fetch quota data via RetrieveUserQuotaSummary and GetUserStatus endpoints.\n */\n\nimport https from 'https'\nimport http from 'http'\nimport { debug } from '../../core/logger.js'\n\nexport interface ConnectUserStatus {\n isAuthenticated?: boolean\n email?: string\n planType?: string\n quota?: {\n promptCredits?: {\n used?: number\n limit?: number\n remaining?: number\n }\n models?: Array<{\n modelId: string\n displayName?: string\n label?: string\n quota?: {\n remaining?: number\n limit?: number\n usedPercentage?: number\n remainingPercentage?: number\n resetTime?: string\n timeUntilResetMs?: number\n }\n isExhausted?: boolean\n }>\n }\n raw?: unknown\n}\n\nexport interface QuotaSummaryGroup {\n displayName: string\n buckets: QuotaSummaryBucket[]\n}\n\nexport interface QuotaSummaryBucket {\n bucketId: string\n displayName: string\n description: string\n remainingFraction: number\n resetTime?: string\n}\n\nexport interface QuotaSummaryResponse {\n groups: QuotaSummaryGroup[]\n raw?: unknown\n}\n\nconst ENDPOINTS = {\n quotaSummary: '/exa.language_server_pb.LanguageServerService/RetrieveUserQuotaSummary',\n userStatus: '/exa.language_server_pb.LanguageServerService/GetUserStatus',\n modelConfigs: '/exa.language_server_pb.LanguageServerService/GetCommandModelConfigs',\n unleash: '/exa.language_server_pb.LanguageServerService/GetUnleashData',\n availableModels: '/exa.language_server_pb.LanguageServerService/GetAvailableModels',\n}\n\nexport class ConnectClient {\n private baseUrl: string\n private csrfToken: string | undefined\n private isHttps: boolean\n\n constructor(baseUrl: string, csrfToken?: string) {\n this.baseUrl = baseUrl\n this.csrfToken = csrfToken\n this.isHttps = baseUrl.startsWith('https://')\n debug('connect-client', `Init: ${baseUrl}, hasToken: ${!!csrfToken}`)\n }\n\n /**\n * Test if this server is reachable and speaks Connect protocol\n */\n async probe(): Promise<boolean> {\n try {\n await this.request('POST', ENDPOINTS.unleash, {})\n return true\n } catch {\n return false\n }\n }\n\n /**\n * Fetch quota summary (richest data: weekly + session buckets)\n */\n async fetchQuotaSummary(): Promise<QuotaSummaryResponse | null> {\n debug('connect-client', 'Fetching RetrieveUserQuotaSummary')\n try {\n const response = await this.request('POST', ENDPOINTS.quotaSummary, {\n metadata: {\n ideName: 'antigravity',\n extensionName: 'antigravity',\n locale: 'en',\n },\n })\n if (response) {\n return this.parseQuotaSummary(response)\n }\n } catch (err) {\n debug('connect-client', `QuotaSummary failed: ${err}`)\n }\n return null\n }\n\n /**\n * Fetch user status (fallback for older servers)\n */\n async fetchUserStatus(): Promise<ConnectUserStatus | null> {\n debug('connect-client', 'Fetching GetUserStatus')\n try {\n const response = await this.request('POST', ENDPOINTS.userStatus, {\n metadata: {\n ideName: 'antigravity',\n extensionName: 'antigravity',\n locale: 'en',\n },\n })\n if (response) {\n return this.parseUserStatus(response)\n }\n } catch (err) {\n debug('connect-client', `UserStatus failed: ${err}`)\n }\n return null\n }\n\n /**\n * Fetch model configs (last-resort fallback)\n */\n async fetchModelConfigs(): Promise<unknown> {\n debug('connect-client', 'Fetching GetCascadeModelConfigData')\n try {\n return await this.request('POST', ENDPOINTS.modelConfigs, {\n metadata: {\n ideName: 'antigravity',\n extensionName: 'antigravity',\n locale: 'en',\n },\n })\n } catch (err) {\n debug('connect-client', `ModelConfigs failed: ${err}`)\n return null\n }\n }\n\n /**\n * Make a Connect protocol HTTP(S) request\n */\n private request(method: string, path: string, body?: unknown): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const url = new URL(path, this.baseUrl)\n const headers: Record<string, string> = {\n 'Accept': 'application/json',\n 'Content-Type': 'application/json',\n 'Connect-Protocol-Version': '1',\n }\n if (this.csrfToken) {\n headers['X-Codeium-Csrf-Token'] = this.csrfToken\n }\n\n const options = {\n hostname: url.hostname,\n port: url.port,\n path: url.pathname,\n method,\n headers,\n timeout: 5000,\n rejectUnauthorized: false,\n } as https.RequestOptions\n\n const protocol = this.isHttps ? https : http\n const req = protocol.request(options, (res) => {\n let data = ''\n res.on('data', (chunk: Buffer) => { data += chunk })\n res.on('end', () => {\n if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {\n try {\n resolve(JSON.parse(data))\n } catch {\n resolve(data)\n }\n } else if (res.statusCode === 404) {\n reject(new Error(`404: ${path}`))\n } else {\n reject(new Error(`HTTP ${res.statusCode}: ${data.slice(0, 200)}`))\n }\n })\n })\n req.on('error', reject)\n req.on('timeout', () => { req.destroy(); reject(new Error('Timeout')) })\n if (body) req.write(JSON.stringify(body))\n req.end()\n })\n }\n\n /**\n * Parse RetrieveUserQuotaSummary response\n */\n private parseQuotaSummary(response: unknown): QuotaSummaryResponse {\n const result: QuotaSummaryResponse = { groups: [], raw: response }\n\n if (typeof response !== 'object' || response === null) return result\n const data = response as Record<string, unknown>\n\n // Try both response.groups and response.userStatus.groups patterns\n const userStatus = data.userStatus as Record<string, unknown> | undefined\n const groups = (data.groups || userStatus?.groups) as Array<Record<string, unknown>> | undefined\n\n if (Array.isArray(groups)) {\n result.groups = groups.map((group): QuotaSummaryGroup => {\n const buckets = Array.isArray(group.buckets)\n ? group.buckets.map((b: Record<string, unknown>): QuotaSummaryBucket => ({\n bucketId: String(b.bucketId || ''),\n displayName: String(b.displayName || ''),\n description: String(b.description || ''),\n remainingFraction: typeof (b as any).remaining?.remainingFraction === 'number'\n ? (b as any).remaining.remainingFraction as number\n : typeof (b as any).remainingFraction === 'number'\n ? (b as any).remainingFraction as number\n : 1,\n resetTime: typeof b.resetTime === 'string' ? b.resetTime : undefined,\n }))\n : []\n return {\n displayName: String(group.displayName || ''),\n buckets,\n }\n })\n }\n\n debug('connect-client', `Parsed ${result.groups.length} groups from quota summary`)\n return result\n }\n\n /**\n * Parse GetUserStatus response (legacy fallback)\n */\n private parseUserStatus(response: unknown): ConnectUserStatus {\n const status: ConnectUserStatus = { raw: response }\n if (typeof response !== 'object' || response === null) return status\n\n const data = response as Record<string, unknown>\n const userStatus = (data.userStatus as Record<string, unknown>) || data\n\n if (typeof userStatus.email === 'string') status.email = userStatus.email\n if (typeof userStatus.isAuthenticated === 'boolean') status.isAuthenticated = userStatus.isAuthenticated\n if (typeof userStatus.planType === 'string') status.planType = userStatus.planType\n\n // Extract plan/prompt credits\n const planStatus = userStatus.planStatus as Record<string, unknown> | undefined\n if (planStatus) {\n const available = planStatus.availablePromptCredits as number | undefined\n const planInfo = planStatus.planInfo as Record<string, unknown> | undefined\n const monthly = planInfo?.monthlyPromptCredits as number | undefined\n if (typeof available === 'number' && typeof monthly === 'number') {\n status.quota = {\n promptCredits: {\n used: monthly - available,\n limit: monthly,\n remaining: available,\n },\n }\n }\n }\n\n // Extract models from cascadeModelConfigData\n const cascadeData = userStatus.cascadeModelConfigData as Record<string, unknown> | undefined\n const clientModelConfigs = cascadeData?.clientModelConfigs as Array<Record<string, unknown>> | undefined\n if (Array.isArray(clientModelConfigs)) {\n status.quota = status.quota || {}\n status.quota.models = clientModelConfigs.map((m) => {\n const modelOrAlias = m.modelOrAlias as Record<string, unknown> | undefined\n const modelId = typeof modelOrAlias?.model === 'string' ? modelOrAlias.model : 'unknown'\n const quotaInfo = m.quotaInfo as Record<string, unknown> | undefined\n const remainingFraction = typeof quotaInfo?.remainingFraction === 'number' ? quotaInfo.remainingFraction : undefined\n const resetTime = typeof quotaInfo?.resetTime === 'string' ? quotaInfo.resetTime : undefined\n\n return {\n modelId,\n displayName: typeof m.label === 'string' ? m.label : undefined,\n label: typeof m.label === 'string' ? m.label : undefined,\n quota: {\n remainingPercentage: remainingFraction,\n resetTime,\n timeUntilResetMs: resetTime ? new Date(resetTime).getTime() - Date.now() : undefined,\n },\n isExhausted: remainingFraction === 0,\n }\n })\n }\n\n return status\n }\n}\n","/**\n * Parse Connect API responses into SDK QuotaSnapshot format\n */\n\nimport type {\n QuotaSnapshot,\n QuotaGroup,\n QuotaBucket,\n ModelQuotaInfo,\n PromptCreditsInfo,\n} from '../../sdk/types.js'\nimport type { ConnectUserStatus, QuotaSummaryResponse } from './connect-client.js'\nimport { debug } from '../../core/logger.js'\n\n/**\n * Parse RetrieveUserQuotaSummary response (preferred — has weekly + session buckets)\n */\nexport function parseQuotaSummary(\n summary: QuotaSummaryResponse,\n email?: string\n): QuotaSnapshot {\n debug('parser', `Parsing quota summary: ${summary.groups.length} groups`)\n\n return {\n timestamp: new Date().toISOString(),\n method: 'local',\n email,\n groups: summary.groups.map((g): QuotaGroup => ({\n displayName: g.displayName,\n buckets: g.buckets.map((b): QuotaBucket => ({\n bucketId: b.bucketId,\n displayName: b.displayName,\n description: b.description,\n remainingFraction: clampFraction(b.remainingFraction),\n resetTime: b.resetTime,\n timeUntilResetMs: b.resetTime\n ? Math.max(0, new Date(b.resetTime).getTime() - Date.now())\n : undefined,\n })),\n })),\n }\n}\n\n/**\n * Parse GetUserStatus response (fallback — legacy model-level data)\n */\nexport function parseUserStatus(userStatus: ConnectUserStatus): QuotaSnapshot {\n debug('parser', 'Parsing GetUserStatus fallback')\n\n const snapshot: QuotaSnapshot = {\n timestamp: new Date().toISOString(),\n method: 'local',\n email: userStatus.email,\n groups: [],\n }\n\n // Parse prompt credits\n if (userStatus.quota?.promptCredits) {\n snapshot.promptCredits = parsePromptCredits(userStatus.quota.promptCredits)\n }\n\n // Group models into Gemini and Claude+GPT buckets (simulating quota groups)\n if (userStatus.quota?.models) {\n const geminiModels: ModelQuotaInfo[] = []\n const claudeModels: ModelQuotaInfo[] = []\n\n for (const model of userStatus.quota.models) {\n const info: ModelQuotaInfo = {\n label: model.label || model.displayName || model.modelId,\n modelId: model.modelId,\n remainingPercentage: model.quota?.remainingPercentage,\n isExhausted: model.isExhausted ?? (model.quota?.remainingPercentage === 0),\n resetTime: model.quota?.resetTime,\n timeUntilResetMs: model.quota?.timeUntilResetMs,\n isAutocompleteOnly: detectAutocomplete(model.modelId, model.label),\n }\n\n if (info.isAutocompleteOnly) continue\n\n if (isGeminiModel(model.modelId)) {\n geminiModels.push(info)\n } else {\n claudeModels.push(info)\n }\n }\n\n // Create synthetic quota groups from model data\n if (geminiModels.length > 0) {\n snapshot.groups.push(createGroupFromModels('Gemini Models', geminiModels))\n }\n if (claudeModels.length > 0) {\n snapshot.groups.push(createGroupFromModels('Claude + GPT Models', claudeModels))\n }\n }\n\n return snapshot\n}\n\n// ── Helpers ────────────────────────────────────────────────────────\n\nfunction parsePromptCredits(credits: NonNullable<ConnectUserStatus['quota']>['promptCredits']): PromptCreditsInfo | undefined {\n if (!credits) return undefined\n const limit = credits.limit ?? 0\n const remaining = credits.remaining ?? limit\n const used = credits.used ?? (limit - remaining)\n if (limit === 0) return undefined\n return {\n available: remaining,\n monthly: limit,\n usedPercentage: limit > 0 ? used / limit : 0,\n remainingPercentage: limit > 0 ? remaining / limit : 1,\n }\n}\n\nfunction createGroupFromModels(displayName: string, models: ModelQuotaInfo[]): QuotaGroup {\n // Find the best session/reset bucket from available models\n const bestModel = models.reduce((best, m) => {\n const remaining = m.remainingPercentage ?? 1\n const bestRemaining = best.remainingPercentage ?? 1\n return remaining < bestRemaining ? m : best\n }, models[0])\n\n const bucket: QuotaBucket = {\n bucketId: 'session',\n displayName: 'Session (5-hour)',\n description: bestModel.resetTime\n ? `Resets at ${new Date(bestModel.resetTime).toLocaleTimeString()}`\n : '5-hour session window',\n remainingFraction: bestModel.remainingPercentage ?? 1,\n resetTime: bestModel.resetTime,\n timeUntilResetMs: bestModel.timeUntilResetMs,\n }\n\n return {\n displayName,\n buckets: [bucket],\n }\n}\n\nfunction isGeminiModel(modelId: string): boolean {\n const lower = modelId.toLowerCase()\n return lower.includes('gemini')\n}\n\nfunction detectAutocomplete(modelId: string, label?: string): boolean {\n const text = `${modelId} ${label || ''}`.toLowerCase()\n return text.includes('autocomplete') ||\n text.includes('gemini-2.5') ||\n text.includes('gemini 2.5')\n}\n\nfunction clampFraction(value: number | undefined): number {\n if (value === undefined || value === null) return 1\n return Math.max(0, Math.min(1, value))\n}\n","/**\n * Local data source adapter — connects to Antigravity's local language server\n *\n * This is the preferred source: fast, offline, no login needed.\n * Uses a multi-strategy approach: detect process → discover port → probe → fetch quota.\n */\n\nimport type { DataSourceAdapter, QuotaSnapshot } from '../../sdk/types.js'\nimport { debug } from '../../core/logger.js'\nimport { detectAntigravityProcesses, extractFlags } from './process-detector.js'\nimport { discoverPorts, scanPortRange } from './port-detective.js'\nimport { ConnectClient } from './connect-client.js'\nimport { parseQuotaSummary, parseUserStatus } from './parser.js'\nimport { SourceUnavailableError } from '../../core/errors.js'\n\nexport class LocalSource implements DataSourceAdapter {\n readonly name = 'local' as const\n readonly priority = 1\n\n async isAvailable(): Promise<boolean> {\n try {\n const processes = await detectAntigravityProcesses()\n return processes.length > 0\n } catch {\n return false\n }\n }\n\n async fetchQuota(): Promise<QuotaSnapshot> {\n debug('local', 'Starting local fetch')\n\n // Step 1: Detect processes\n const processes = await detectAntigravityProcesses()\n if (processes.length === 0) {\n throw new SourceUnavailableError('local', 'No Antigravity process found')\n }\n\n // Step 2: Try each process until we get quota data\n for (const proc of processes) {\n debug('local', `Trying PID ${proc.pid} (${proc.scope})`)\n\n // Extract port from command line flags first (most reliable on Windows)\n const flags = extractFlags(proc.commandLine || '')\n let ports: number[] = []\n\n // If --extension_server_port is in command line, use it directly\n const directPort = flags.get('extension_server_port')\n if (directPort) {\n const portNum = parseInt(directPort, 10)\n if (!isNaN(portNum)) {\n ports.push(portNum)\n debug('local', `Found port from command line: ${portNum}`)\n }\n }\n\n // Also discover ports via OS tools\n const discoveredPorts = await discoverPorts(proc.pid)\n for (const p of discoveredPorts) {\n if (!ports.includes(p)) ports.push(p)\n }\n\n // Get CSRF token from command line\n const csrfToken = flags.get('csrf_token') || flags.get('extension_server_csrf_token')\n\n // Step 3: Probe each port\n for (const port of ports) {\n const quota = await this.probePort(port, csrfToken)\n if (quota) return quota\n }\n }\n\n // Step 4: Last resort — scan common port ranges\n debug('local', 'Direct detection failed, scanning port range')\n const scannedPorts = await scanPortRange(8000, 9500)\n for (const port of scannedPorts) {\n const quota = await this.probePort(port)\n if (quota) return quota\n }\n\n throw new SourceUnavailableError('local', 'Could not connect to any local server')\n }\n\n /**\n * Probe a single port and try to fetch quota\n */\n private async probePort(port: number, csrfToken?: string): Promise<QuotaSnapshot | null> {\n for (const scheme of ['https', 'http']) {\n const baseUrl = `${scheme}://127.0.0.1:${port}`\n const client = new ConnectClient(baseUrl, csrfToken)\n\n // Check if server responds\n const reachable = await client.probe()\n if (!reachable) continue\n\n debug('local', `Probing ${baseUrl}`)\n\n // Try quota summary first (richest data)\n const summary = await client.fetchQuotaSummary()\n if (summary && summary.groups.length > 0) {\n const email = (await client.fetchUserStatus())?.email\n debug('local', `Got quota summary from ${baseUrl}`)\n return parseQuotaSummary(summary, email)\n }\n\n // Fallback: GetUserStatus (legacy)\n const userStatus = await client.fetchUserStatus()\n if (userStatus) {\n debug('local', `Got user status from ${baseUrl}`)\n return parseUserStatus(userStatus)\n }\n }\n\n return null\n }\n}\n","/**\n * agy CLI data source adapter\n *\n * When the Antigravity desktop app isn't running, we can launch the agy CLI\n * and use its embedded HTTPS server to fetch quota data.\n * This source requires a signed-in agy session.\n */\n\nimport type { DataSourceAdapter, QuotaSnapshot } from '../../sdk/types.js'\nimport { debug } from '../../core/logger.js'\nimport { ConnectClient } from '../local/connect-client.js'\nimport { parseQuotaSummary, parseUserStatus } from '../local/parser.js'\nimport { discoverPorts } from '../local/port-detective.js'\nimport { SourceUnavailableError } from '../../core/errors.js'\nimport { runCommand, isWindows } from '../../core/platform.js'\nimport { exec, type ChildProcess } from 'child_process'\nimport { promisify } from 'util'\n\nconst execAsync = promisify(exec)\n\nexport class CliSource implements DataSourceAdapter {\n readonly name = 'cli' as const\n readonly priority = 2\n\n private agyProcess: ChildProcess | null = null\n\n async isAvailable(): Promise<boolean> {\n const path = await findAgyBinary()\n return path !== null\n }\n\n async fetchQuota(): Promise<QuotaSnapshot> {\n debug('cli', 'Starting CLI source fetch')\n\n const agyPath = await findAgyBinary()\n if (!agyPath) {\n throw new SourceUnavailableError('cli', 'agy binary not found')\n }\n\n // Try to find an already-running agy first\n const existingQuota = await this.tryExistingAgy()\n if (existingQuota) return existingQuota\n\n // Launch agy and connect\n return await this.launchAndFetch(agyPath)\n }\n\n /**\n * Check if there's already a running agy instance we can reuse\n */\n private async tryExistingAgy(): Promise<QuotaSnapshot | null> {\n // Find agy processes\n const cmd = isWindows()\n ? 'wmic process where \"commandline like \\'%agy%\\'\" get ProcessId,CommandLine /format:csv'\n : 'ps -ax -o pid=,args='\n\n const output = await runCommand(cmd)\n const pids = output.split('\\n')\n .map(line => {\n const match = line.match(/^\\s*(\\d+)/)\n return match ? parseInt(match[1], 10) : NaN\n })\n .filter(p => !isNaN(p))\n\n for (const pid of pids) {\n const ports = await discoverPorts(pid)\n for (const port of ports) {\n const quota = await this.probePort(port)\n if (quota) return quota\n }\n }\n\n return null\n }\n\n /**\n * Launch agy and wait for its server, then fetch quota\n */\n private async launchAndFetch(agyPath: string): Promise<QuotaSnapshot> {\n debug('cli', `Launching agy: ${agyPath}`)\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.agyProcess?.kill()\n reject(new SourceUnavailableError('cli', 'agy startup timed out'))\n }, 15000)\n\n this.agyProcess = exec(agyPath, { env: { ...process.env, NO_COLOR: '1' } })\n\n // Poll for the agy server to come up\n const pollInterval = setInterval(async () => {\n try {\n // agy typically binds to a high port\n if (!this.agyProcess?.pid) return\n const ports = await discoverPorts(this.agyProcess.pid)\n for (const port of ports) {\n const quota = await this.probePort(port)\n if (quota) {\n clearTimeout(timeout)\n clearInterval(pollInterval)\n this.agyProcess?.kill()\n resolve(quota)\n return\n }\n }\n } catch { /* keep trying */ }\n }, 1000)\n\n this.agyProcess.on('error', (err) => {\n clearTimeout(timeout)\n clearInterval(pollInterval)\n reject(new SourceUnavailableError('cli', `agy failed: ${err.message}`))\n })\n\n this.agyProcess.on('exit', () => {\n clearTimeout(timeout)\n clearInterval(pollInterval)\n })\n })\n }\n\n /**\n * Probe a port for quota data\n */\n private async probePort(port: number): Promise<QuotaSnapshot | null> {\n for (const scheme of ['https', 'http']) {\n const baseUrl = `${scheme}://127.0.0.1:${port}`\n const client = new ConnectClient(baseUrl) // agy doesn't need CSRF token\n\n try {\n const reachable = await client.probe()\n if (!reachable) continue\n\n const summary = await client.fetchQuotaSummary()\n if (summary && summary.groups.length > 0) {\n const email = (await client.fetchUserStatus())?.email\n return parseQuotaSummary(summary, email)\n }\n\n const userStatus = await client.fetchUserStatus()\n if (userStatus) return parseUserStatus(userStatus)\n } catch { /* try next */ }\n }\n return null\n }\n\n destroy(): void {\n this.agyProcess?.kill()\n this.agyProcess = null\n }\n}\n\n/**\n * Find the agy binary on PATH or common locations\n */\nasync function findAgyBinary(): Promise<string | null> {\n // Check env override\n if (process.env.ANTIGRAVITY_CLI_PATH) {\n return process.env.ANTIGRAVITY_CLI_PATH\n }\n\n // Check PATH\n try {\n const cmd = isWindows() ? 'where agy' : 'which agy'\n const output = await execAsync(cmd)\n const path = output.stdout.trim()\n if (path) return path\n } catch { /* not on PATH */ }\n\n // Check common locations\n const commonPaths = isWindows()\n ? [\n `${process.env.LOCALAPPDATA || ''}/antigravity-cli/agy.exe`,\n `${process.env.PROGRAMFILES || ''}/antigravity-cli/agy.exe`,\n ]\n : [\n `${process.env.HOME}/.local/bin/agy`,\n '/opt/homebrew/bin/agy',\n '/usr/local/bin/agy',\n ]\n\n for (const p of commonPaths) {\n if (!p) continue\n try {\n await execAsync(`test -x \"${p}\"`)\n return p\n } catch { /* not there */ }\n }\n\n return null\n}\n","/**\n * OAuth/Cloud Code API data source adapter\n *\n * Fetches quota remotely via Google Cloud Code API.\n * Requires a valid OAuth token.\n */\n\nimport type { DataSourceAdapter, QuotaSnapshot } from '../../sdk/types.js'\nimport { debug } from '../../core/logger.js'\nimport { OAuthClient } from './client.js'\nimport { parseQuotaSummary, parseUserStatus } from '../local/parser.js'\nimport { SourceUnavailableError } from '../../core/errors.js'\nimport type { QuotaSummaryResponse, ConnectUserStatus } from '../local/connect-client.js'\n\nexport class OAuthSource implements DataSourceAdapter {\n readonly name = 'oauth' as const\n readonly priority = 3\n\n private client: OAuthClient\n\n constructor(client: OAuthClient) {\n this.client = client\n }\n\n async isAvailable(): Promise<boolean> {\n try {\n await this.client.getAccessToken()\n return true\n } catch {\n return false\n }\n }\n\n async fetchQuota(): Promise<QuotaSnapshot> {\n debug('oauth', 'Fetching quota via Cloud Code API')\n\n try {\n // Try quota summary first\n const summaryRaw = await this.client.fetchQuotaSummary()\n const summary = this.parseRemoteSummary(summaryRaw)\n if (summary && summary.groups.length > 0) {\n // Get email from user status\n const statusRaw = await this.client.fetchUserStatus()\n const email = this.extractEmail(statusRaw)\n debug('oauth', 'Got quota summary via OAuth')\n return parseQuotaSummary(summary, email)\n }\n\n // Fallback: loadCodeAssist for basic info\n const statusRaw = await this.client.fetchUserStatus()\n const status = this.parseRemoteStatus(statusRaw)\n if (status) {\n debug('oauth', 'Got user status via OAuth')\n return parseUserStatus(status)\n }\n } catch (err) {\n debug('oauth', `Fetch failed: ${err}`)\n }\n\n throw new SourceUnavailableError('oauth', 'Could not fetch quota via Cloud Code API')\n }\n\n /**\n * Parse remote summary response into QuotaSummaryResponse format\n */\n private parseRemoteSummary(raw: unknown): QuotaSummaryResponse | null {\n if (typeof raw !== 'object' || raw === null) return null\n const data = raw as Record<string, unknown>\n\n // The response might be wrapped\n const groups = data.groups as Array<Record<string, unknown>> | undefined\n if (!Array.isArray(groups)) return null\n\n return {\n groups: groups.map(g => ({\n displayName: String(g.displayName || ''),\n buckets: Array.isArray(g.buckets)\n ? g.buckets.map((b: Record<string, unknown>) => ({\n bucketId: String(b.bucketId || ''),\n displayName: String(b.displayName || ''),\n description: String(b.description || ''),\n remainingFraction: typeof (b as any).remaining?.remainingFraction === 'number'\n ? (b as any).remaining.remainingFraction as number\n : typeof (b as any).remainingFraction === 'number'\n ? (b as any).remainingFraction as number\n : 1,\n resetTime: typeof b.resetTime === 'string' ? b.resetTime : undefined,\n }))\n : [],\n })),\n raw,\n }\n }\n\n /**\n * Parse remote user status response\n */\n private parseRemoteStatus(raw: unknown): ConnectUserStatus | null {\n if (typeof raw !== 'object' || raw === null) return null\n return { raw }\n }\n\n private extractEmail(raw: unknown): string | undefined {\n if (typeof raw !== 'object' || raw === null) return undefined\n const data = raw as Record<string, unknown>\n const userStatus = data.userStatus as Record<string, unknown> | undefined\n return (userStatus?.email || data.email) as string | undefined\n }\n}\n","/**\n * Google OAuth client for Cloud Code API\n *\n * Handles the OAuth2 flow for remote quota fetching.\n */\n\nimport https from 'https'\nimport http from 'http'\nimport { URL } from 'url'\nimport { debug } from '../../core/logger.js'\nimport type { OAuthTokenResponse, StoredTokens } from '../../sdk/types.js'\nimport {\n CLOUD_CODE_ENDPOINTS,\n CLOUD_CODE_DEFAULT_BODY,\n OAUTH_CLIENT_ID,\n OAUTH_CLIENT_SECRET,\n OAUTH_SCOPES,\n} from '../cloud-code-api.js'\n\nexport class OAuthClient {\n private tokens: StoredTokens | null = null\n\n constructor(tokens?: StoredTokens) {\n this.tokens = tokens || null\n }\n\n /**\n * Generate the OAuth authorization URL for user login\n */\n getAuthUrl(): string {\n const params = new URLSearchParams({\n client_id: OAUTH_CLIENT_ID,\n redirect_uri: 'http://127.0.0.1:0/callback',\n response_type: 'code',\n scope: OAUTH_SCOPES,\n access_type: 'offline',\n prompt: 'consent',\n })\n return `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`\n }\n\n /**\n * Exchange an authorization code for tokens\n */\n async exchangeCode(code: string): Promise<StoredTokens> {\n const body = new URLSearchParams({\n code,\n client_id: OAUTH_CLIENT_ID,\n client_secret: OAUTH_CLIENT_SECRET,\n redirect_uri: 'http://127.0.0.1:0/callback',\n grant_type: 'authorization_code',\n })\n\n const response = await this.postUrlEncoded('https://oauth2.googleapis.com/token', body)\n const data = response as OAuthTokenResponse\n\n this.tokens = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token || '',\n expiresAt: Date.now() + data.expires_in * 1000,\n }\n\n return this.tokens\n }\n\n /**\n * Refresh the access token\n */\n async refreshAccessToken(): Promise<StoredTokens> {\n if (!this.tokens?.refreshToken) {\n throw new Error('No refresh token available')\n }\n\n const body = new URLSearchParams({\n client_id: OAUTH_CLIENT_ID,\n client_secret: OAUTH_CLIENT_SECRET,\n refresh_token: this.tokens.refreshToken,\n grant_type: 'refresh_token',\n })\n\n const response = await this.postUrlEncoded('https://oauth2.googleapis.com/token', body)\n const data = response as OAuthTokenResponse\n\n this.tokens = {\n ...this.tokens,\n accessToken: data.access_token,\n expiresAt: Date.now() + data.expires_in * 1000,\n }\n\n return this.tokens\n }\n\n /**\n * Get a valid access token, refreshing if necessary\n */\n async getAccessToken(): Promise<string> {\n if (!this.tokens) throw new Error('Not authenticated')\n if (Date.now() >= this.tokens.expiresAt - 60000) {\n await this.refreshAccessToken()\n }\n return this.tokens.accessToken!\n }\n\n /**\n * Get stored tokens\n */\n getTokens(): StoredTokens | null {\n return this.tokens\n }\n\n /**\n * Make an authenticated POST request to the Cloud Code API\n */\n async fetchQuotaSummary(): Promise<unknown> {\n const token = await this.getAccessToken()\n return this.authenticatedPost(\n CLOUD_CODE_ENDPOINTS.retrieveUserQuotaSummary,\n CLOUD_CODE_DEFAULT_BODY,\n token\n )\n }\n\n async fetchUserStatus(): Promise<unknown> {\n const token = await this.getAccessToken()\n return this.authenticatedPost(\n CLOUD_CODE_ENDPOINTS.loadCodeAssist,\n CLOUD_CODE_DEFAULT_BODY,\n token\n )\n }\n\n async fetchAvailableModels(): Promise<unknown> {\n const token = await this.getAccessToken()\n return this.authenticatedPost(\n CLOUD_CODE_ENDPOINTS.fetchAvailableModels,\n CLOUD_CODE_DEFAULT_BODY,\n token\n )\n }\n\n // ── HTTP Helpers ────────────────────────────────────────────────\n\n private authenticatedPost(url: string, body: unknown, token: string): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const parsed = new URL(url)\n const data = JSON.stringify(body)\n const options: http.RequestOptions = {\n hostname: parsed.hostname,\n path: parsed.pathname,\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`,\n 'Content-Length': Buffer.byteLength(data),\n },\n timeout: 10000,\n }\n\n const req = https.request(options, (res) => {\n let responseData = ''\n res.on('data', (chunk: Buffer) => { responseData += chunk })\n res.on('end', () => {\n try {\n resolve(JSON.parse(responseData))\n } catch {\n reject(new Error(`Invalid JSON: ${responseData.slice(0, 200)}`))\n }\n })\n })\n req.on('error', reject)\n req.on('timeout', () => { req.destroy(); reject(new Error('Timeout')) })\n req.write(data)\n req.end()\n })\n }\n\n private postUrlEncoded(url: string, body: URLSearchParams): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const parsed = new URL(url)\n const data = body.toString()\n const options: http.RequestOptions = {\n hostname: parsed.hostname,\n path: parsed.pathname,\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n 'Content-Length': Buffer.byteLength(data),\n },\n timeout: 10000,\n }\n\n const req = https.request(options, (res) => {\n let responseData = ''\n res.on('data', (chunk: Buffer) => { responseData += chunk })\n res.on('end', () => {\n try {\n resolve(JSON.parse(responseData))\n } catch {\n reject(new Error(`Invalid JSON: ${responseData.slice(0, 200)}`))\n }\n })\n })\n req.on('error', reject)\n req.on('timeout', () => { req.destroy(); reject(new Error('Timeout')) })\n req.write(data)\n req.end()\n })\n }\n}\n","/**\n * Google Cloud Code API endpoints for remote quota fetching\n *\n * Used as fallback when local sources are unavailable.\n * Requires OAuth authentication.\n */\n\nexport const CLOUD_CODE_ENDPOINTS = {\n /** Load code assist configuration */\n loadCodeAssist: 'https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist',\n\n /** Onboard a new user */\n onboardUser: 'https://cloudcode-pa.googleapis.com/v1internal:onboardUser',\n\n /** Fetch available models for the account */\n fetchAvailableModels: 'https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels',\n\n /** Fetch raw quota data */\n retrieveUserQuota: 'https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuota',\n\n /** Fetch quota summary with weekly + session buckets */\n retrieveUserQuotaSummary: 'https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuotaSummary',\n} as const\n\nexport const CLOUD_CODE_DEFAULT_BODY = {\n metadata: {\n ideName: 'antigravity',\n extensionName: 'antigravity',\n locale: 'en',\n ideVersion: 'unknown',\n },\n}\n\nexport const OAUTH_CLIENT_ID = '764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com'\nexport const OAUTH_CLIENT_SECRET = 'd-FL95Q19q7MQmFpd7hHD0Ty'\nexport const OAUTH_SCOPES = [\n 'https://www.googleapis.com/auth/cloud-platform',\n 'https://www.googleapis.com/auth/cloudcode',\n].join(' ')\nexport const OAUTH_REDIRECT_URI = 'http://127.0.0.1:0/callback'\n","/**\n * Source registry — manages data source adapters and implements the fallback chain\n *\n * Priority order:\n * 1. Local (Antigravity app language server) — fastest, offline\n * 2. CLI (agy CLI HTTPS server) — no app needed, requires signed-in agy\n * 3. OAuth (Google Cloud Code API) — works anywhere, requires login\n */\n\nimport type { DataSourceAdapter, QuotaSnapshot, DataSource } from '../sdk/types.js'\nimport { debug } from '../core/logger.js'\nimport { SourceUnavailableError } from '../core/errors.js'\nimport { LocalSource } from './local/index.js'\nimport { CliSource } from './cli/index.js'\n\nexport { LocalSource } from './local/index.js'\nexport { CliSource } from './cli/index.js'\nexport { OAuthSource } from './oauth/index.js'\nexport { OAuthClient } from './oauth/client.js'\n\nexport class SourceRegistry {\n private sources: DataSourceAdapter[] = []\n private health: Map<DataSource, { available: boolean; lastCheck: number }> = new Map()\n\n constructor() {\n // Register built-in sources in priority order\n this.sources.push(new LocalSource())\n this.sources.push(new CliSource())\n // OAuth source is added manually when credentials are available\n }\n\n /**\n * Register an additional data source (e.g., OAuth)\n */\n addSource(source: DataSourceAdapter): void {\n // Insert in priority order\n const idx = this.sources.findIndex(s => s.priority > source.priority)\n if (idx === -1) {\n this.sources.push(source)\n } else {\n this.sources.splice(idx, 0, source)\n }\n debug('registry', `Registered source: ${source.name} (priority ${source.priority})`)\n }\n\n /**\n * Remove a source by name\n */\n removeSource(name: DataSource): void {\n this.sources = this.sources.filter(s => s.name !== name)\n }\n\n /**\n * Fetch quota using the best available source\n *\n * @param preferredSource Force a specific source\n */\n async fetchQuota(preferredSource?: DataSource): Promise<QuotaSnapshot> {\n // If a specific source is requested, use only that\n if (preferredSource) {\n const source = this.sources.find(s => s.name === preferredSource)\n if (!source) throw new Error(`Source \"${preferredSource}\" not registered`)\n const snapshot = await source.fetchQuota()\n this.health.set(preferredSource, { available: true, lastCheck: Date.now() })\n return snapshot\n }\n\n // Otherwise, try sources in priority order\n const errors: string[] = []\n\n for (const source of this.sources) {\n debug('registry', `Trying source: ${source.name}`)\n\n try {\n const available = await source.isAvailable()\n if (!available) {\n debug('registry', `Source ${source.name} not available`)\n this.health.set(source.name, { available: false, lastCheck: Date.now() })\n continue\n }\n\n const snapshot = await source.fetchQuota()\n this.health.set(source.name, { available: true, lastCheck: Date.now() })\n debug('registry', `Success with source: ${source.name}`)\n return snapshot\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n errors.push(`${source.name}: ${msg}`)\n this.health.set(source.name, { available: false, lastCheck: Date.now() })\n debug('registry', `Source ${source.name} failed: ${msg}`)\n }\n }\n\n throw new SourceUnavailableError('all', `No sources available:\\n${errors.map(e => ` • ${e}`).join('\\n')}`)\n }\n\n /**\n * Get health status of all sources\n */\n getHealth(): Map<DataSource, { available: boolean; lastCheck: number }> {\n return new Map(this.health)\n }\n\n /**\n * Get registered source names\n */\n getSourceNames(): DataSource[] {\n return this.sources.map(s => s.name)\n }\n}\n","/**\n * Smart caching layer for quota data\n *\n * Caches quota snapshots to avoid hitting API rate limits.\n * Cache is keyed by email + source combination.\n */\n\nimport { debug } from '../core/logger.js'\nimport type { QuotaSnapshot } from './types.js'\n\ninterface CacheEntry {\n snapshot: QuotaSnapshot\n cachedAt: number\n}\n\nexport class QuotaCache {\n private cache: Map<string, CacheEntry> = new Map()\n private ttlMs: number\n\n constructor(ttlMs: number = 5 * 60 * 1000) {\n this.ttlMs = ttlMs\n }\n\n /**\n * Get cached quota if available and not expired\n */\n get(email: string, source: string): QuotaSnapshot | null {\n const key = `${email}:${source}`\n const entry = this.cache.get(key)\n if (!entry) return null\n\n const age = Date.now() - entry.cachedAt\n if (age > this.ttlMs) {\n this.cache.delete(key)\n debug('cache', `Expired entry for ${email} (age: ${Math.round(age / 1000)}s)`)\n return null\n }\n\n debug('cache', `Cache hit for ${email} (age: ${Math.round(age / 1000)}s)`)\n return entry.snapshot\n }\n\n /**\n * Store a quota snapshot in cache\n */\n set(email: string, source: string, snapshot: QuotaSnapshot): void {\n const key = `${email}:${source}`\n this.cache.set(key, {\n snapshot,\n cachedAt: Date.now(),\n })\n debug('cache', `Cached snapshot for ${email}`)\n }\n\n /**\n * Check if a cached entry is still fresh\n */\n isFresh(email: string, source: string): boolean {\n const key = `${email}:${source}`\n const entry = this.cache.get(key)\n if (!entry) return false\n return (Date.now() - entry.cachedAt) <= this.ttlMs\n }\n\n /**\n * Clear all cached entries\n */\n clear(): void {\n this.cache.clear()\n debug('cache', 'Cleared all cache entries')\n }\n\n /**\n * Get cache age in seconds for a key\n */\n getAgeMs(email: string, source: string): number | null {\n const key = `${email}:${source}`\n const entry = this.cache.get(key)\n if (!entry) return null\n return Date.now() - entry.cachedAt\n }\n}\n","/**\n * SQLite storage for usage history and analytics\n */\n\nimport Database from 'better-sqlite3'\nimport { join } from 'path'\nimport { getDataDirPath, ensureDirs } from '../core/config.js'\nimport { debug } from '../core/logger.js'\nimport type { UsageRecord, QuotaSnapshot } from './types.js'\n\nlet db: Database.Database | null = null\n\nfunction getDb(): Database.Database {\n if (db) return db\n ensureDirs()\n const dbPath = join(getDataDirPath(), 'history.db')\n db = new Database(dbPath)\n db.pragma('journal_mode = WAL')\n initSchema(db)\n debug('store', `Opened database at ${dbPath}`)\n return db\n}\n\nfunction initSchema(database: Database.Database): void {\n database.exec(`\n CREATE TABLE IF NOT EXISTS quota_snapshots (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp TEXT NOT NULL,\n email TEXT NOT NULL,\n method TEXT NOT NULL,\n gemini_weekly_remaining REAL,\n gemini_session_remaining REAL,\n claude_weekly_remaining REAL,\n claude_session_remaining REAL,\n raw_json TEXT\n );\n\n CREATE INDEX IF NOT EXISTS idx_snapshots_email_ts\n ON quota_snapshots(email, timestamp);\n `)\n}\n\n/**\n * Store a quota snapshot for history tracking\n */\nexport function storeSnapshot(snapshot: QuotaSnapshot): void {\n const database = getDb()\n\n // Extract group data\n let geminiWeekly: number | null = null\n let geminiSession: number | null = null\n let claudeWeekly: number | null = null\n let claudeSession: number | null = null\n\n for (const group of snapshot.groups) {\n const lower = group.displayName.toLowerCase()\n for (const bucket of group.buckets) {\n const bucketLower = bucket.displayName.toLowerCase()\n if (lower.includes('gemini')) {\n if (bucketLower.includes('weekly') || bucketLower.includes('week')) {\n geminiWeekly = bucket.remainingFraction\n } else {\n geminiSession = bucket.remainingFraction\n }\n } else if (lower.includes('claude') || lower.includes('gpt')) {\n if (bucketLower.includes('weekly') || bucketLower.includes('week')) {\n claudeWeekly = bucket.remainingFraction\n } else {\n claudeSession = bucket.remainingFraction\n }\n }\n }\n }\n\n const stmt = database.prepare(`\n INSERT INTO quota_snapshots\n (timestamp, email, method, gemini_weekly_remaining, gemini_session_remaining,\n claude_weekly_remaining, claude_session_remaining, raw_json)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `)\n\n stmt.run(\n snapshot.timestamp,\n snapshot.email || 'unknown',\n snapshot.method,\n geminiWeekly,\n geminiSession,\n claudeWeekly,\n claudeSession,\n JSON.stringify(snapshot),\n )\n\n debug('store', `Stored snapshot for ${snapshot.email}`)\n}\n\n/**\n * Retrieve usage history for an account\n */\nexport function getHistory(\n email: string,\n options?: { days?: number; limit?: number }\n): UsageRecord[] {\n const database = getDb()\n const days = options?.days || 7\n const limit = options?.limit || 1000\n\n const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString()\n\n const stmt = database.prepare(`\n SELECT timestamp, email, gemini_weekly_remaining, gemini_session_remaining,\n claude_weekly_remaining, claude_session_remaining\n FROM quota_snapshots\n WHERE email = ? AND timestamp >= ?\n ORDER BY timestamp DESC\n LIMIT ?\n `)\n\n const rows = stmt.all(email, since, limit) as Array<Record<string, unknown>>\n\n return rows.map((row): UsageRecord => ({\n timestamp: String(row.timestamp),\n email: String(row.email),\n geminiWeeklyRemaining: row.gemini_weekly_remaining as number | null,\n geminiSessionRemaining: row.gemini_session_remaining as number | null,\n claudeWeeklyRemaining: row.claude_weekly_remaining as number | null,\n claudeSessionRemaining: row.claude_session_remaining as number | null,\n }))\n}\n\n/**\n * Get the most recent snapshot for an account\n */\nexport function getLatestSnapshot(email: string): UsageRecord | null {\n const history = getHistory(email, { limit: 1 })\n return history[0] || null\n}\n\n/**\n * Get daily usage summary (average remaining per day)\n */\nexport function getDailySummary(email: string, days: number = 7): Array<{\n date: string\n geminiWeeklyAvg: number | null\n geminiSessionAvg: number | null\n claudeWeeklyAvg: number | null\n claudeSessionAvg: number | null\n count: number\n}> {\n const database = getDb()\n const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString()\n\n const stmt = database.prepare(`\n SELECT\n date(timestamp) as date,\n AVG(gemini_weekly_remaining) as gemini_weekly_avg,\n AVG(gemini_session_remaining) as gemini_session_avg,\n AVG(claude_weekly_remaining) as claude_weekly_avg,\n AVG(claude_session_remaining) as claude_session_avg,\n COUNT(*) as count\n FROM quota_snapshots\n WHERE email = ? AND timestamp >= ?\n GROUP BY date(timestamp)\n ORDER BY date(timestamp) ASC\n `)\n\n const rows = stmt.all(email, since) as Array<Record<string, unknown>>\n\n return rows.map(row => ({\n date: String(row.date),\n geminiWeeklyAvg: row.gemini_weekly_avg as number | null,\n geminiSessionAvg: row.gemini_session_avg as number | null,\n claudeWeeklyAvg: row.claude_weekly_avg as number | null,\n claudeSessionAvg: row.claude_session_avg as number | null,\n count: Number(row.count),\n }))\n}\n\n/**\n * Clean up old snapshots (older than N days)\n */\nexport function cleanupHistory(keepDays: number = 90): number {\n const database = getDb()\n const cutoff = new Date(Date.now() - keepDays * 24 * 60 * 60 * 1000).toISOString()\n const result = database.prepare(\n 'DELETE FROM quota_snapshots WHERE timestamp < ?'\n ).run(cutoff)\n return result.changes\n}\n\n/**\n * Close the database connection\n */\nexport function closeStore(): void {\n if (db) {\n db.close()\n db = null\n debug('store', 'Database closed')\n }\n}\n","/**\n * Config file management — reads/writes app configuration\n */\n\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs'\nimport { join } from 'path'\nimport { homedir } from 'os'\nimport type { AppConfig } from '../sdk/types.js'\nimport { debug } from './logger.js'\n\nconst CONFIG_DIR_NAME = 'when-does-my-quota-refresh'\n\nconst DEFAULT_CONFIG: AppConfig = {\n defaultMode: 'local',\n cacheTtlMs: 5 * 60 * 1000, // 5 minutes\n refreshIntervalMs: 5 * 60 * 1000,\n wakeupModels: ['claude-sonnet-4-5', 'gemini-3-flash', 'gemini-3-pro-low'],\n wakeupAccounts: [],\n notifications: true,\n plugins: [],\n daemon: {\n pollIntervalMs: 60 * 1000,\n enabled: false,\n },\n}\n\nfunction getConfigDir(): string {\n const home = homedir()\n switch (process.platform) {\n case 'darwin':\n return join(home, 'Library', 'Application Support', CONFIG_DIR_NAME)\n case 'win32':\n return join(process.env.APPDATA || join(home, 'AppData', 'Roaming'), CONFIG_DIR_NAME)\n default:\n return join(home, '.config', CONFIG_DIR_NAME)\n }\n}\n\nfunction getConfigPath(): string {\n return join(getConfigDir(), 'config.json')\n}\n\nfunction getDataDir(): string {\n return join(getConfigDir(), 'data')\n}\n\nexport function ensureDirs(): void {\n const configDir = getConfigDir()\n const dataDir = getDataDir()\n if (!existsSync(configDir)) mkdirSync(configDir, { recursive: true })\n if (!existsSync(dataDir)) mkdirSync(dataDir, { recursive: true })\n}\n\nexport function loadConfig(): AppConfig {\n try {\n const path = getConfigPath()\n if (!existsSync(path)) return DEFAULT_CONFIG\n const raw = readFileSync(path, 'utf-8')\n const parsed = JSON.parse(raw)\n debug('config', `Loaded config from ${path}`)\n return { ...DEFAULT_CONFIG, ...parsed }\n } catch (err) {\n debug('config', 'Failed to load config, using defaults', err)\n return DEFAULT_CONFIG\n }\n}\n\nexport function saveConfig(config: AppConfig): void {\n ensureDirs()\n const path = getConfigPath()\n writeFileSync(path, JSON.stringify(config, null, 2))\n debug('config', `Saved config to ${path}`)\n}\n\nexport function getConfigDirPath(): string {\n return getConfigDir()\n}\n\nexport function getDataDirPath(): string {\n return getDataDir()\n}\n\nexport { DEFAULT_CONFIG }\n","/**\n * Token storage for account credentials\n *\n * Stores OAuth tokens locally in the config directory.\n * Tokens are stored as plain JSON (local machine only).\n */\n\nimport { readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs'\nimport { join } from 'path'\nimport type { StoredTokens } from '../types.js'\nimport { getConfigDirPath, ensureDirs } from '../../core/config.js'\nimport { debug } from '../../core/logger.js'\n\nconst TOKENS_DIR = 'accounts'\n\ninterface TokenAccount {\n email: string\n tokens: StoredTokens\n addedAt: string\n}\n\ninterface TokenStore {\n accounts: TokenAccount[]\n activeEmail?: string\n}\n\nfunction getStorePath(): string {\n return join(getConfigDirPath(), TOKENS_DIR, 'tokens.json')\n}\n\nfunction loadStore(): TokenStore {\n const path = getStorePath()\n if (!existsSync(path)) return { accounts: [] }\n try {\n return JSON.parse(readFileSync(path, 'utf-8'))\n } catch {\n return { accounts: [] }\n }\n}\n\nfunction saveStore(store: TokenStore): void {\n ensureDirs()\n writeFileSync(getStorePath(), JSON.stringify(store, null, 2))\n debug('account-storage', `Saved ${store.accounts.length} account(s)`)\n}\n\n/**\n * Save tokens for an account\n */\nexport function saveAccountTokens(email: string, tokens: StoredTokens): void {\n const store = loadStore()\n const existing = store.accounts.findIndex(a => a.email === email)\n const account: TokenAccount = {\n email,\n tokens,\n addedAt: new Date().toISOString(),\n }\n\n if (existing >= 0) {\n store.accounts[existing] = account\n } else {\n store.accounts.push(account)\n }\n\n // Set as active if it's the only one\n if (store.accounts.length === 1) {\n store.activeEmail = email\n }\n\n saveStore(store)\n}\n\n/**\n * Get tokens for a specific account\n */\nexport function getAccountTokens(email: string): StoredTokens | null {\n const store = loadStore()\n const account = store.accounts.find(a => a.email === email)\n return account?.tokens || null\n}\n\n/**\n * Get the active account's tokens\n */\nexport function getActiveAccountTokens(): StoredTokens | null {\n const store = loadStore()\n if (!store.activeEmail) return null\n const account = store.accounts.find(a => a.email === store.activeEmail)\n return account?.tokens || null\n}\n\n/**\n * Set the active account\n */\nexport function setActiveAccount(email: string): boolean {\n const store = loadStore()\n if (!store.accounts.find(a => a.email === email)) return false\n store.activeEmail = email\n saveStore(store)\n return true\n}\n\n/**\n * Remove an account\n */\nexport function removeAccount(email: string): boolean {\n const store = loadStore()\n const idx = store.accounts.findIndex(a => a.email === email)\n if (idx < 0) return false\n store.accounts.splice(idx, 1)\n if (store.activeEmail === email) {\n store.activeEmail = store.accounts[0]?.email\n }\n saveStore(store)\n return true\n}\n\n/**\n * List all stored accounts\n */\nexport function listAccounts(): Array<{ email: string; isActive: boolean; addedAt: string }> {\n const store = loadStore()\n return store.accounts.map(a => ({\n email: a.email,\n isActive: a.email === store.activeEmail,\n addedAt: a.addedAt,\n }))\n}\n\n/**\n * Get all stored tokens (for multi-account fetch)\n */\nexport function getAllAccountTokens(): StoredTokens[] {\n const store = loadStore()\n return store.accounts.map(a => a.tokens)\n}\n","/**\n * OAuth authentication flow for Google accounts\n */\n\nimport { OAuthClient } from '../../sources/oauth/client.js'\nimport { saveAccountTokens, setActiveAccount } from './storage.js'\nimport { debug } from '../../core/logger.js'\nimport { AuthError } from '../../core/errors.js'\nimport open from 'open'\nimport http from 'http'\nimport { URL } from 'url'\n\n/**\n * Start an interactive OAuth login flow\n *\n * Opens the browser for Google login, then captures the redirect\n * to exchange the authorization code for tokens.\n */\nexport async function loginAccount(): Promise<string> {\n const client = new OAuthClient()\n const authUrl = client.getAuthUrl()\n\n debug('auth', 'Starting OAuth login flow')\n\n // Start a temporary local server to catch the redirect\n const code = await new Promise<string>((resolve, reject) => {\n const server = http.createServer(async (req, res) => {\n const url = new URL(req.url || '/', `http://127.0.0.1`)\n const code = url.searchParams.get('code')\n\n if (code) {\n res.writeHead(200, { 'Content-Type': 'text/html' })\n res.end(`\n <html><body style=\"font-family: sans-serif; text-align: center; padding: 50px;\">\n <h1>✅ Login successful!</h1>\n <p>You can close this tab and return to the terminal.</p>\n </body></html>\n `)\n server.close()\n resolve(code)\n } else {\n const error = url.searchParams.get('error')\n if (error) {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n res.end(`<h1>Login failed: ${error}</h1>`)\n server.close()\n reject(new AuthError(`OAuth error: ${error}`))\n } else {\n res.writeHead(404)\n res.end('Waiting for OAuth callback...')\n }\n }\n })\n\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address()\n if (typeof addr === 'object' && addr) {\n // Update redirect URI with actual port\n debug('auth', `Callback server on port ${addr.port}`)\n\n // Open browser\n open(authUrl).catch(() => {\n console.log(`\\nOpen this URL in your browser:\\n\\n${authUrl}\\n`)\n })\n }\n })\n\n // Timeout after 5 minutes\n setTimeout(() => {\n server.close()\n reject(new AuthError('Login timed out after 5 minutes'))\n }, 5 * 60 * 1000)\n })\n\n // Exchange code for tokens\n const tokens = await client.exchangeCode(code)\n\n // Get user email\n const email = tokens.email || 'unknown@gmail.com'\n tokens.email = email\n\n // Store tokens\n saveAccountTokens(email, tokens)\n setActiveAccount(email)\n\n debug('auth', `Logged in as ${email}`)\n return email\n}\n\n/**\n * Perform a manual login (headless/SSH mode)\n * Returns the auth URL for the user to open manually\n */\nexport function getManualLoginUrl(): string {\n const client = new OAuthClient()\n return client.getAuthUrl()\n}\n\n/**\n * Complete manual login with an authorization code\n */\nexport async function completeManualLogin(code: string): Promise<string> {\n const client = new OAuthClient()\n const tokens = await client.exchangeCode(code)\n const email = tokens.email || 'unknown@gmail.com'\n tokens.email = email\n saveAccountTokens(email, tokens)\n setActiveAccount(email)\n return email\n}\n","/**\n * Quota fetching orchestration\n *\n * Coordinates between the source registry, cache, storage, and plugins\n * to provide a unified quota fetching experience.\n */\n\nimport type { QuotaSnapshot, DataSource, ClientOptions, UsageRecord } from './types.js'\nimport { SourceRegistry } from '../sources/index.js'\nimport { QuotaCache } from './cache.js'\nimport { storeSnapshot, getHistory, getDailySummary } from './store.js'\nimport { getAllAccountTokens } from './accounts/index.js'\nimport { OAuthClient } from '../sources/oauth/client.js'\nimport { OAuthSource } from '../sources/oauth/index.js'\nimport { loadConfig } from '../core/config.js'\nimport { debug } from '../core/logger.js'\nimport { setVerbose } from '../core/logger.js'\n\nexport class QuotaClient {\n private registry: SourceRegistry\n private cache: QuotaCache\n private verbose: boolean\n\n constructor(options?: ClientOptions) {\n this.verbose = options?.verbose || false\n setVerbose(this.verbose)\n\n const config = loadConfig()\n this.registry = new SourceRegistry()\n this.cache = new QuotaCache(options?.cacheTtlMs || config.cacheTtlMs)\n\n // Register OAuth sources for all stored accounts\n this.registerOAuthSources()\n }\n\n /**\n * Fetch quota for the active account (or all accounts)\n */\n async fetchQuota(options?: {\n source?: DataSource\n refresh?: boolean\n allAccounts?: boolean\n }): Promise<QuotaSnapshot | QuotaSnapshot[]> {\n if (options?.allAccounts) {\n return this.fetchAllAccounts(options)\n }\n\n // Check cache first (unless refresh requested)\n if (!options?.refresh) {\n // We need the email from any cached entry\n // For now, just try the fetch directly\n }\n\n const snapshot = await this.registry.fetchQuota(options?.source)\n\n // Store in cache and history\n if (snapshot.email) {\n this.cache.set(snapshot.email, snapshot.method, snapshot)\n storeSnapshot(snapshot)\n }\n\n return snapshot\n }\n\n /**\n * Fetch quota for all stored accounts\n */\n private async fetchAllAccounts(options?: {\n source?: DataSource\n refresh?: boolean\n }): Promise<QuotaSnapshot[]> {\n const tokens = getAllAccountTokens()\n const snapshots: QuotaSnapshot[] = []\n\n // Fetch active account via normal registry\n try {\n const snapshot = await this.registry.fetchQuota(options?.source)\n snapshots.push(snapshot)\n } catch (err) {\n debug('quota', `Active account fetch failed: ${err}`)\n }\n\n // Fetch other accounts via their OAuth tokens\n for (const token of tokens) {\n if (!token.email) continue\n // Skip if we already have this email\n if (snapshots.some(s => s.email === token.email)) continue\n\n try {\n const client = new OAuthClient(token)\n const source = new OAuthSource(client)\n const snapshot = await source.fetchQuota()\n snapshots.push(snapshot)\n } catch (err) {\n debug('quota', `Failed to fetch for ${token.email}: ${err}`)\n }\n }\n\n return snapshots\n }\n\n /**\n * Get the full dashboard data for all accounts\n */\n async getFullDashboard(): Promise<{\n snapshots: QuotaSnapshot[]\n history: Record<string, UsageRecord[]>\n dailySummary: Record<string, ReturnType<typeof getDailySummary>>\n }> {\n const snapshots = await this.fetchAllAccounts()\n const history: Record<string, UsageRecord[]> = {}\n const dailySummary: Record<string, ReturnType<typeof getDailySummary>> = {}\n\n for (const snapshot of snapshots) {\n if (!snapshot.email) continue\n history[snapshot.email] = getHistory(snapshot.email, { days: 1, limit: 50 })\n dailySummary[snapshot.email] = getDailySummary(snapshot.email, 7)\n }\n\n return { snapshots, history, dailySummary }\n }\n\n /**\n * Get usage history for an account\n */\n getHistory(email: string, days?: number): UsageRecord[] {\n return getHistory(email, { days })\n }\n\n /**\n * Get daily summary for an account\n */\n getDailySummary(email: string, days?: number) {\n return getDailySummary(email, days)\n }\n\n /**\n * Register OAuth sources for all stored accounts\n */\n private registerOAuthSources(): void {\n const tokens = getAllAccountTokens()\n for (const token of tokens) {\n if (!token.accessToken) continue\n try {\n const client = new OAuthClient(token)\n const source = new OAuthSource(client)\n this.registry.addSource(source)\n debug('quota', `Registered OAuth source for ${token.email}`)\n } catch (err) {\n debug('quota', `Failed to register OAuth for ${token.email}: ${err}`)\n }\n }\n }\n\n /**\n * Get the source registry (for doctor/status checks)\n */\n getRegistry(): SourceRegistry {\n return this.registry\n }\n}\n","/**\n * when-does-my-quota-refresh SDK\n *\n * Core library for fetching and managing Antigravity AI model quotas.\n * Import this for programmatic use in your own tools and extensions.\n *\n * @example\n * ```typescript\n * import { createClient } from 'when-does-my-quota-refresh'\n *\n * const client = createClient()\n * const snapshot = await client.fetchQuota()\n * console.log(snapshot.groups)\n * ```\n */\n\n// Client\nexport { QuotaClient } from './quota.js'\n\n// Types\nexport type {\n QuotaSnapshot,\n QuotaGroup,\n QuotaBucket,\n PromptCreditsInfo,\n DataSource,\n ModelQuotaInfo,\n AccountInfo,\n Plugin,\n UsageRecord,\n ClientOptions,\n} from './types.js'\n\n// Cache\nexport { QuotaCache } from './cache.js'\n\n// Storage\nexport {\n storeSnapshot,\n getHistory,\n getDailySummary,\n getLatestSnapshot,\n cleanupHistory,\n closeStore,\n} from './store.js'\n\n// Accounts\nexport {\n listAccounts,\n setActiveAccount,\n removeAccount,\n getAccountTokens,\n getActiveAccountTokens,\n loginAccount,\n} from './accounts/index.js'\n\n// Sources\nexport { SourceRegistry } from '../sources/index.js'\n\n// Config\nexport { loadConfig, saveConfig, getConfigDirPath, getDataDirPath } from '../core/config.js'\n\n// Errors\nexport {\n SourceUnavailableError,\n AuthError,\n QuotaFetchError,\n} from '../core/errors.js'\n\n// ── Convenience constructor ────────────────────────────────────────\n\nimport type { ClientOptions } from './types.js'\nimport { QuotaClient } from './quota.js'\n\n/**\n * Create a new when-does-my-quota-refresh client\n */\nexport function createClient(options?: ClientOptions): QuotaClient {\n return new QuotaClient(options)\n}\n"],"mappings":"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","names":["exec","promisify","execAsync","statusRaw","https","URL","URL","https","join","join","readFileSync","writeFileSync","existsSync","join","join","existsSync","readFileSync","writeFileSync","http","URL","code"]}
|
|
1
|
+
{"version":3,"sources":["../../src/core/logger.ts","../../src/core/errors.ts","../../src/core/platform.ts","../../src/sources/local/process-detector.ts","../../src/sources/local/port-detective.ts","../../src/sources/local/connect-client.ts","../../src/sources/local/parser.ts","../../src/sources/local/index.ts","../../src/sources/cli/index.ts","../../src/sources/oauth/index.ts","../../src/sources/oauth/client.ts","../../src/sources/cloud-code-api.ts","../../src/sources/index.ts","../../src/sdk/cache.ts","../../src/sdk/store.ts","../../src/core/config.ts","../../src/sdk/accounts/storage.ts","../../src/sdk/accounts/auth.ts","../../src/sdk/quota.ts","../../src/sdk/index.ts"],"sourcesContent":["/**\n * Simple logger with debug flag\n */\n\nlet _verbose = false\n\nexport function setVerbose(verbose: boolean): void {\n _verbose = verbose\n}\n\nexport function debug(module: string, msg: string, data?: unknown): void {\n if (!_verbose) return\n const prefix = `[${module}]`\n if (data !== undefined) {\n console.error(`${prefix} ${msg}`, data)\n } else {\n console.error(`${prefix} ${msg}`)\n }\n}\n\nexport function info(msg: string): void {\n console.error(msg)\n}\n\nexport function warn(msg: string): void {\n console.error(`⚠ ${msg}`)\n}\n","/**\n * Custom error types for when-does-my-quota-refresh\n */\n\nexport class SourceUnavailableError extends Error {\n constructor(source: string, reason?: string) {\n super(`Source \"${source}\" unavailable${reason ? `: ${reason}` : ''}`)\n this.name = 'SourceUnavailableError'\n }\n}\n\nexport class AuthError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'AuthError'\n }\n}\n\nexport class QuotaFetchError extends Error {\n constructor(source: string, reason?: string) {\n super(`Failed to fetch quota from \"${source}\"${reason ? `: ${reason}` : ''}`)\n this.name = 'QuotaFetchError'\n }\n}\n\nexport class ProcessNotFoundError extends Error {\n constructor() {\n super('Antigravity language server process not found')\n this.name = 'ProcessNotFoundError'\n }\n}\n\nexport class PortDiscoveryError extends Error {\n constructor(pid: number, platform: string) {\n super(`Failed to discover ports for PID ${pid} on ${platform}`)\n this.name = 'PortDiscoveryError'\n }\n}\n","/**\n * Cross-platform platform detection and utilities\n */\n\nimport { exec } from 'child_process'\nimport { promisify } from 'util'\n\nconst execAsync = promisify(exec)\n\nexport type Platform = 'darwin' | 'linux' | 'win32'\n\nexport function getPlatform(): Platform {\n return process.platform as Platform\n}\n\nexport function isWindows(): boolean {\n return process.platform === 'win32'\n}\n\nexport function isMacOS(): boolean {\n return process.platform === 'darwin'\n}\n\nexport function isLinux(): boolean {\n return process.platform === 'linux'\n}\n\n/**\n * Run a shell command and return stdout\n */\nexport async function runCommand(cmd: string): Promise<string> {\n try {\n const { stdout } = await execAsync(cmd, { timeout: 10000 })\n return stdout\n } catch {\n return ''\n }\n}\n\n/**\n * Format milliseconds as human-readable countdown\n */\nexport function formatCountdown(ms: number): string {\n if (ms <= 0) return 'now'\n const totalMinutes = Math.floor(ms / 60000)\n const hours = Math.floor(totalMinutes / 60)\n const minutes = totalMinutes % 60\n if (hours > 0) return `${hours}h ${minutes}m`\n return `${minutes}m`\n}\n\n/**\n * Format a fraction (0–1) as a percentage string\n */\nexport function formatPercentage(fraction: number): string {\n return `${Math.round(fraction * 100)}%`\n}\n\n/**\n * Clamp a number between min and max\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max)\n}\n","/**\n * Cross-platform process detection for Antigravity language server\n *\n * Fixes the Windows detection bug in antigravity-usage by using\n * multiple detection strategies per platform.\n */\n\nimport { runCommand, isWindows, isMacOS, isLinux } from '../../core/platform.js'\nimport { debug } from '../../core/logger.js'\nimport type { ProcessInfo } from '../../sdk/types.js'\n\nconst ANTIMATTER_MARKERS = [\n 'antigravity',\n 'language_server',\n 'language-server',\n 'antigravity-cli',\n 'antigravity_cli',\n 'agy',\n]\n\nconst ANTIMATTER_PATH_MARKERS = [\n '/antigravity/',\n 'Antigravity',\n 'antigravity.app',\n 'AntigravityStatusProbe',\n 'app_data_dir antigravity',\n]\n\n/**\n * Detect all running Antigravity language server processes\n */\nexport async function detectAntigravityProcesses(): Promise<ProcessInfo[]> {\n debug('process-detector', `Detecting on platform: ${process.platform}`)\n\n let processes: ProcessInfo[] = []\n\n if (isMacOS()) {\n processes = await detectOnMacOS()\n } else if (isLinux()) {\n processes = await detectOnLinux()\n } else if (isWindows()) {\n processes = await detectOnWindows()\n }\n\n debug('process-detector', `Found ${processes.length} process(es)`)\n return processes\n}\n\n/**\n * macOS: ps -ax with command line parsing\n */\nasync function detectOnMacOS(): Promise<ProcessInfo[]> {\n const output = await runCommand('ps -ax -o pid=,comm=,args=')\n return parsePsOutput(output)\n}\n\n/**\n * Linux: ps with full command line\n */\nasync function detectOnLinux(): Promise<ProcessInfo[]> {\n const output = await runCommand('ps -eo pid,comm,args --no-headers')\n return parsePsOutput(output)\n}\n\n/**\n * Windows: Multiple strategies combined\n * 1. wmic for process listing with command lines\n * 2. PowerShell Get-CimInstance as fallback\n * 3. tasklist as last resort\n */\nasync function detectOnWindows(): Promise<ProcessInfo[]> {\n // Strategy 1: wmic\n let output = await runCommand(\n 'wmic process where \"name like \\'%language%\\' or commandline like \\'%antigravity%\\'\" get ProcessId,Name,CommandLine /format:csv'\n )\n let processes = parseWmicOutput(output)\n if (processes.length > 0) return processes\n\n // Strategy 2: PowerShell\n output = await runCommand(\n 'powershell -Command \"Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -match \\'antigravity|language.server\\' } | Select-Object ProcessId,Name,CommandLine | Format-Table -AutoSize\"'\n )\n processes = parsePowerShellOutput(output)\n if (processes.length > 0) return processes\n\n // Strategy 3: netstat scan for known port patterns (fallback)\n // This won't identify the process but can help with port discovery\n debug('process-detector', 'Windows: Falling back to port-based detection')\n return []\n}\n\n/**\n * Parse ps output (macOS/Linux)\n */\nfunction parsePsOutput(output: string): ProcessInfo[] {\n const processes: ProcessInfo[] = []\n const lines = output.split('\\n').filter(Boolean)\n\n for (const line of lines) {\n const trimmed = line.trim()\n if (!trimmed) continue\n\n // ps output format: PID COMM ARGS\n // comm is the short name, args is the full command line\n const parts = trimmed.split(/\\s+/)\n const pid = parseInt(parts[0], 10)\n if (isNaN(pid)) continue\n\n // The rest after PID is comm + args\n const rest = parts.slice(1).join(' ')\n\n if (matchesAntigravity(rest)) {\n processes.push({\n pid,\n name: parts[1] || 'unknown',\n commandLine: rest,\n scope: classifyProcess(rest),\n })\n }\n }\n\n return processes\n}\n\n/**\n * Parse wmic CSV output (Windows)\n */\nfunction parseWmicOutput(output: string): ProcessInfo[] {\n const processes: ProcessInfo[] = []\n const lines = output.split('\\n').filter(Boolean)\n\n for (const line of lines) {\n // wmic CSV format: Node,CommandLine,Name,ProcessId\n const parts = line.split(',').map(p => p.trim().replace(/\"/g, ''))\n if (parts.length < 4) continue\n\n const pid = parseInt(parts[3], 10)\n if (isNaN(pid)) continue\n\n const commandLine = parts[1] || ''\n const name = parts[2] || ''\n\n if (matchesAntigravity(commandLine) || matchesAntigravity(name)) {\n processes.push({\n pid,\n name,\n commandLine,\n scope: classifyProcess(commandLine),\n })\n }\n }\n\n return processes\n}\n\n/**\n * Parse PowerShell output (Windows)\n */\nfunction parsePowerShellOutput(output: string): ProcessInfo[] {\n const processes: ProcessInfo[] = []\n const lines = output.split('\\n').filter(Boolean)\n\n for (const line of lines) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith('---') || trimmed.startsWith('ProcessId')) continue\n\n // PowerShell table format: PID Name CommandLine (whitespace-separated)\n const match = trimmed.match(/^\\s*(\\d+)\\s+(\\S+)\\s+(.*)$/)\n if (!match) continue\n\n const pid = parseInt(match[1], 10)\n const name = match[2]\n const commandLine = match[3]\n\n if (matchesAntigravity(commandLine) || matchesAntigravity(name)) {\n processes.push({\n pid,\n name,\n commandLine,\n scope: classifyProcess(commandLine),\n })\n }\n }\n\n return processes\n}\n\n/**\n * Check if a string matches Antigravity markers\n */\nfunction matchesAntigravity(text: string): boolean {\n const lower = text.toLowerCase()\n return ANTIMATTER_PATH_MARKERS.some(marker =>\n lower.includes(marker.toLowerCase())\n ) || (\n lower.includes('language') &&\n lower.includes('server') &&\n ANTIMATTER_MARKERS.some(m => lower.includes(m))\n )\n}\n\n/**\n * Classify process by its command line flags\n */\nfunction classifyProcess(commandLine: string): ProcessInfo['scope'] {\n const lower = commandLine.toLowerCase()\n if (lower.includes('antigravity-cli') || lower.includes('antigravity_cli') || lower.includes('agy')) {\n return 'cli'\n }\n if (lower.includes('antigravity ide') || lower.includes('antigravity-ide') || lower.includes('extensions/antigravity')) {\n return 'ide'\n }\n if (lower.includes('app_data_dir antigravity') || lower.includes('antigravity.app')) {\n return 'app'\n }\n return 'unknown'\n}\n\n/**\n * Extract command-line flags from process command line\n */\nexport function extractFlags(commandLine: string): Map<string, string> {\n const flags = new Map<string, string>()\n if (!commandLine) return flags\n\n // Match --flag value patterns\n const flagRegex = /--(\\S+)\\s+([^\\s-][^\\s]*)/g\n let match\n while ((match = flagRegex.exec(commandLine)) !== null) {\n flags.set(match[1], match[2])\n }\n\n return flags\n}\n","/**\n * Cross-platform port discovery for Antigravity language server\n *\n * Improved Windows support: netstat + PowerShell + port range scanning\n */\n\nimport { runCommand, isWindows, isMacOS, isLinux } from '../../core/platform.js'\nimport { debug } from '../../core/logger.js'\n\n/**\n * Discover all listening ports for a given process PID\n */\nexport async function discoverPorts(pid: number): Promise<number[]> {\n debug('port-detective', `Discovering ports for PID ${pid} on ${process.platform}`)\n\n if (isWindows()) {\n return discoverPortsOnWindows(pid)\n } else if (isMacOS()) {\n return discoverPortsOnMacOS(pid)\n } else {\n return discoverPortsOnLinux(pid)\n }\n}\n\n/**\n * macOS: lsof\n */\nasync function discoverPortsOnMacOS(pid: number): Promise<number[]> {\n try {\n const output = await runCommand(`lsof -nP -iTCP -sTCP:LISTEN -a -p ${pid}`)\n const ports: number[] = []\n for (const line of output.split('\\n')) {\n const match = line.match(/:(\\d+)\\s+\\(LISTEN\\)/)\n if (match) {\n const port = parseInt(match[1], 10)\n if (!isNaN(port) && !ports.includes(port)) {\n ports.push(port)\n }\n }\n }\n debug('port-detective', `macOS ports: ${ports.join(', ')}`)\n return ports\n } catch {\n return []\n }\n}\n\n/**\n * Linux: ss with netstat fallback\n */\nasync function discoverPortsOnLinux(pid: number): Promise<number[]> {\n // Try ss first\n try {\n const output = await runCommand(`ss -tlnp | grep \"pid=${pid},\"`)\n const ports = parseListenPorts(output)\n if (ports.length > 0) {\n debug('port-detective', `Linux ports (ss): ${ports.join(', ')}`)\n return ports\n }\n } catch { /* fall through */ }\n\n // Fallback to netstat\n try {\n const output = await runCommand(`netstat -tlnp 2>/dev/null | grep \"${pid}/\"`)\n const ports = parseListenPorts(output)\n debug('port-detective', `Linux ports (netstat): ${ports.join(', ')}`)\n return ports\n } catch {\n return []\n }\n}\n\n/**\n * Windows: netstat + PowerShell Get-NetTCPConnection\n */\nasync function discoverPortsOnWindows(pid: number): Promise<number[]> {\n // Strategy 1: netstat -ano\n try {\n const output = await runCommand('netstat -ano')\n const ports: number[] = []\n for (const line of output.split('\\n')) {\n if (!line.includes('LISTENING')) continue\n const parts = line.trim().split(/\\s+/)\n const linePid = parseInt(parts[parts.length - 1], 10)\n if (linePid === pid) {\n const localAddr = parts[1]\n const portMatch = localAddr.match(/:(\\d+)$/)\n if (portMatch) {\n const port = parseInt(portMatch[1], 10)\n if (!isNaN(port) && !ports.includes(port)) {\n ports.push(port)\n }\n }\n }\n }\n if (ports.length > 0) {\n debug('port-detective', `Windows ports (netstat): ${ports.join(', ')}`)\n return ports\n }\n } catch { /* fall through */ }\n\n // Strategy 2: PowerShell Get-NetTCPConnection\n try {\n const output = await runCommand(\n `powershell -Command \"Get-NetTCPConnection -OwningProcess ${pid} -State Listen -ErrorAction SilentlyContinue | Select-Object LocalPort | Format-Table -AutoSize\"`\n )\n const ports: number[] = []\n for (const line of output.split('\\n')) {\n const match = line.match(/^\\s*(\\d+)\\s*$/)\n if (match) {\n const port = parseInt(match[1], 10)\n if (!isNaN(port) && !ports.includes(port)) {\n ports.push(port)\n }\n }\n }\n if (ports.length > 0) {\n debug('port-detective', `Windows ports (PowerShell): ${ports.join(', ')}`)\n return ports\n }\n } catch { /* fall through */ }\n\n // Strategy 3: Extract port from process command-line flags\n // The --extension_server_port flag tells us the port directly\n debug('port-detective', 'Windows: Could not find ports via system commands')\n return []\n}\n\n/**\n * Parse port numbers from ss/netstat output lines\n */\nfunction parseListenPorts(output: string): number[] {\n const ports: number[] = []\n for (const line of output.split('\\n')) {\n const match = line.match(/:(\\d+)\\s/)\n if (match) {\n const port = parseInt(match[1], 10)\n if (!isNaN(port) && !ports.includes(port)) {\n ports.push(port)\n }\n }\n }\n return ports\n}\n\n/**\n * Scan a range of ports on localhost to find HTTPS Antigravity servers\n * Last resort for Windows when process-based detection fails\n */\nexport async function scanPortRange(\n startPort: number = 8000,\n endPort: number = 9500\n): Promise<number[]> {\n debug('port-detective', `Scanning port range ${startPort}-${endPort}`)\n const foundPorts: number[] = []\n\n // Use netstat to find all LISTENING ports in the range\n if (isWindows()) {\n const output = await runCommand('netstat -ano')\n for (const line of output.split('\\n')) {\n if (!line.includes('LISTENING')) continue\n const parts = line.trim().split(/\\s+/)\n const localAddr = parts[1]\n const portMatch = localAddr.match(/:(\\d+)$/)\n if (portMatch) {\n const port = parseInt(portMatch[1], 10)\n if (port >= startPort && port <= endPort) {\n foundPorts.push(port)\n }\n }\n }\n } else {\n const cmd = isMacOS()\n ? `lsof -nP -iTCP -sTCP:LISTEN`\n : `ss -tlnp`\n const output = await runCommand(cmd)\n for (const line of output.split('\\n')) {\n const match = line.match(/:(\\d+)\\s/)\n if (match) {\n const port = parseInt(match[1], 10)\n if (port >= startPort && port <= endPort && !foundPorts.includes(port)) {\n foundPorts.push(port)\n }\n }\n }\n }\n\n debug('port-detective', `Found ${foundPorts.length} ports in range`)\n return foundPorts\n}\n","/**\n * Connect RPC client for Antigravity language server\n *\n * Communicates with the local Antigravity server using the Connect protocol\n * to fetch quota data via RetrieveUserQuotaSummary and GetUserStatus endpoints.\n */\n\nimport https from 'https'\nimport http from 'http'\nimport { debug } from '../../core/logger.js'\n\nexport interface ConnectUserStatus {\n isAuthenticated?: boolean\n email?: string\n planType?: string\n quota?: {\n promptCredits?: {\n used?: number\n limit?: number\n remaining?: number\n }\n models?: Array<{\n modelId: string\n displayName?: string\n label?: string\n quota?: {\n remaining?: number\n limit?: number\n usedPercentage?: number\n remainingPercentage?: number\n resetTime?: string\n timeUntilResetMs?: number\n }\n isExhausted?: boolean\n }>\n }\n raw?: unknown\n}\n\nexport interface QuotaSummaryGroup {\n displayName: string\n buckets: QuotaSummaryBucket[]\n}\n\nexport interface QuotaSummaryBucket {\n bucketId: string\n displayName: string\n description: string\n remainingFraction: number\n resetTime?: string\n}\n\nexport interface QuotaSummaryResponse {\n groups: QuotaSummaryGroup[]\n raw?: unknown\n}\n\nconst ENDPOINTS = {\n quotaSummary: '/exa.language_server_pb.LanguageServerService/RetrieveUserQuotaSummary',\n userStatus: '/exa.language_server_pb.LanguageServerService/GetUserStatus',\n modelConfigs: '/exa.language_server_pb.LanguageServerService/GetCommandModelConfigs',\n unleash: '/exa.language_server_pb.LanguageServerService/GetUnleashData',\n availableModels: '/exa.language_server_pb.LanguageServerService/GetAvailableModels',\n}\n\nexport class ConnectClient {\n private baseUrl: string\n private csrfToken: string | undefined\n private isHttps: boolean\n\n constructor(baseUrl: string, csrfToken?: string) {\n this.baseUrl = baseUrl\n this.csrfToken = csrfToken\n this.isHttps = baseUrl.startsWith('https://')\n debug('connect-client', `Init: ${baseUrl}, hasToken: ${!!csrfToken}`)\n }\n\n /**\n * Test if this server is reachable and speaks Connect protocol\n */\n async probe(): Promise<boolean> {\n try {\n await this.request('POST', ENDPOINTS.unleash, {})\n return true\n } catch {\n return false\n }\n }\n\n /**\n * Fetch quota summary (richest data: weekly + session buckets)\n */\n async fetchQuotaSummary(): Promise<QuotaSummaryResponse | null> {\n debug('connect-client', 'Fetching RetrieveUserQuotaSummary')\n try {\n const response = await this.request('POST', ENDPOINTS.quotaSummary, {\n metadata: {\n ideName: 'antigravity',\n extensionName: 'antigravity',\n locale: 'en',\n },\n })\n if (response) {\n return this.parseQuotaSummary(response)\n }\n } catch (err) {\n debug('connect-client', `QuotaSummary failed: ${err}`)\n }\n return null\n }\n\n /**\n * Fetch user status (fallback for older servers)\n */\n async fetchUserStatus(): Promise<ConnectUserStatus | null> {\n debug('connect-client', 'Fetching GetUserStatus')\n try {\n const response = await this.request('POST', ENDPOINTS.userStatus, {\n metadata: {\n ideName: 'antigravity',\n extensionName: 'antigravity',\n locale: 'en',\n },\n })\n if (response) {\n return this.parseUserStatus(response)\n }\n } catch (err) {\n debug('connect-client', `UserStatus failed: ${err}`)\n }\n return null\n }\n\n /**\n * Fetch model configs (last-resort fallback)\n */\n async fetchModelConfigs(): Promise<unknown> {\n debug('connect-client', 'Fetching GetCascadeModelConfigData')\n try {\n return await this.request('POST', ENDPOINTS.modelConfigs, {\n metadata: {\n ideName: 'antigravity',\n extensionName: 'antigravity',\n locale: 'en',\n },\n })\n } catch (err) {\n debug('connect-client', `ModelConfigs failed: ${err}`)\n return null\n }\n }\n\n /**\n * Make a Connect protocol HTTP(S) request\n */\n private request(method: string, path: string, body?: unknown): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const url = new URL(path, this.baseUrl)\n const headers: Record<string, string> = {\n 'Accept': 'application/json',\n 'Content-Type': 'application/json',\n 'Connect-Protocol-Version': '1',\n }\n if (this.csrfToken) {\n headers['X-Codeium-Csrf-Token'] = this.csrfToken\n }\n\n const options = {\n hostname: url.hostname,\n port: url.port,\n path: url.pathname,\n method,\n headers,\n timeout: 5000,\n rejectUnauthorized: false,\n } as https.RequestOptions\n\n const protocol = this.isHttps ? https : http\n const req = protocol.request(options, (res) => {\n let data = ''\n res.on('data', (chunk: Buffer) => { data += chunk })\n res.on('end', () => {\n if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {\n try {\n resolve(JSON.parse(data))\n } catch {\n resolve(data)\n }\n } else if (res.statusCode === 404) {\n reject(new Error(`404: ${path}`))\n } else {\n reject(new Error(`HTTP ${res.statusCode}: ${data.slice(0, 200)}`))\n }\n })\n })\n req.on('error', reject)\n req.on('timeout', () => { req.destroy(); reject(new Error('Timeout')) })\n if (body) req.write(JSON.stringify(body))\n req.end()\n })\n }\n\n /**\n * Parse RetrieveUserQuotaSummary response\n */\n private parseQuotaSummary(response: unknown): QuotaSummaryResponse {\n const result: QuotaSummaryResponse = { groups: [], raw: response }\n\n if (typeof response !== 'object' || response === null) return result\n const data = response as Record<string, unknown>\n\n // Try both response.groups and response.userStatus.groups patterns\n const userStatus = data.userStatus as Record<string, unknown> | undefined\n const groups = (data.groups || userStatus?.groups) as Array<Record<string, unknown>> | undefined\n\n if (Array.isArray(groups)) {\n result.groups = groups.map((group): QuotaSummaryGroup => {\n const buckets = Array.isArray(group.buckets)\n ? group.buckets.map((b: Record<string, unknown>): QuotaSummaryBucket => ({\n bucketId: String(b.bucketId || ''),\n displayName: String(b.displayName || ''),\n description: String(b.description || ''),\n remainingFraction: typeof (b as any).remaining?.remainingFraction === 'number'\n ? (b as any).remaining.remainingFraction as number\n : typeof (b as any).remainingFraction === 'number'\n ? (b as any).remainingFraction as number\n : 1,\n resetTime: typeof b.resetTime === 'string' ? b.resetTime : undefined,\n }))\n : []\n return {\n displayName: String(group.displayName || ''),\n buckets,\n }\n })\n }\n\n debug('connect-client', `Parsed ${result.groups.length} groups from quota summary`)\n return result\n }\n\n /**\n * Parse GetUserStatus response (legacy fallback)\n */\n private parseUserStatus(response: unknown): ConnectUserStatus {\n const status: ConnectUserStatus = { raw: response }\n if (typeof response !== 'object' || response === null) return status\n\n const data = response as Record<string, unknown>\n const userStatus = (data.userStatus as Record<string, unknown>) || data\n\n if (typeof userStatus.email === 'string') status.email = userStatus.email\n if (typeof userStatus.isAuthenticated === 'boolean') status.isAuthenticated = userStatus.isAuthenticated\n if (typeof userStatus.planType === 'string') status.planType = userStatus.planType\n\n // Extract plan/prompt credits\n const planStatus = userStatus.planStatus as Record<string, unknown> | undefined\n if (planStatus) {\n const available = planStatus.availablePromptCredits as number | undefined\n const planInfo = planStatus.planInfo as Record<string, unknown> | undefined\n const monthly = planInfo?.monthlyPromptCredits as number | undefined\n if (typeof available === 'number' && typeof monthly === 'number') {\n status.quota = {\n promptCredits: {\n used: monthly - available,\n limit: monthly,\n remaining: available,\n },\n }\n }\n }\n\n // Extract models from cascadeModelConfigData\n const cascadeData = userStatus.cascadeModelConfigData as Record<string, unknown> | undefined\n const clientModelConfigs = cascadeData?.clientModelConfigs as Array<Record<string, unknown>> | undefined\n if (Array.isArray(clientModelConfigs)) {\n status.quota = status.quota || {}\n status.quota.models = clientModelConfigs.map((m) => {\n const modelOrAlias = m.modelOrAlias as Record<string, unknown> | undefined\n const modelId = typeof modelOrAlias?.model === 'string' ? modelOrAlias.model : 'unknown'\n const quotaInfo = m.quotaInfo as Record<string, unknown> | undefined\n const remainingFraction = typeof quotaInfo?.remainingFraction === 'number' ? quotaInfo.remainingFraction : undefined\n const resetTime = typeof quotaInfo?.resetTime === 'string' ? quotaInfo.resetTime : undefined\n\n return {\n modelId,\n displayName: typeof m.label === 'string' ? m.label : undefined,\n label: typeof m.label === 'string' ? m.label : undefined,\n quota: {\n remainingPercentage: remainingFraction,\n resetTime,\n timeUntilResetMs: resetTime ? new Date(resetTime).getTime() - Date.now() : undefined,\n },\n isExhausted: remainingFraction === 0,\n }\n })\n }\n\n return status\n }\n}\n","/**\n * Parse Connect API responses into SDK QuotaSnapshot format\n */\n\nimport type {\n QuotaSnapshot,\n QuotaGroup,\n QuotaBucket,\n ModelQuotaInfo,\n PromptCreditsInfo,\n} from '../../sdk/types.js'\nimport type { ConnectUserStatus, QuotaSummaryResponse } from './connect-client.js'\nimport { debug } from '../../core/logger.js'\n\n/**\n * Parse RetrieveUserQuotaSummary response (preferred — has weekly + session buckets)\n */\nexport function parseQuotaSummary(\n summary: QuotaSummaryResponse,\n email?: string\n): QuotaSnapshot {\n debug('parser', `Parsing quota summary: ${summary.groups.length} groups`)\n\n return {\n timestamp: new Date().toISOString(),\n method: 'local',\n email,\n groups: summary.groups.map((g): QuotaGroup => ({\n displayName: g.displayName,\n buckets: g.buckets.map((b): QuotaBucket => ({\n bucketId: b.bucketId,\n displayName: b.displayName,\n description: b.description,\n remainingFraction: clampFraction(b.remainingFraction),\n resetTime: b.resetTime,\n timeUntilResetMs: b.resetTime\n ? Math.max(0, new Date(b.resetTime).getTime() - Date.now())\n : undefined,\n })),\n })),\n }\n}\n\n/**\n * Parse GetUserStatus response (fallback — legacy model-level data)\n */\nexport function parseUserStatus(userStatus: ConnectUserStatus): QuotaSnapshot {\n debug('parser', 'Parsing GetUserStatus fallback')\n\n const snapshot: QuotaSnapshot = {\n timestamp: new Date().toISOString(),\n method: 'local',\n email: userStatus.email,\n groups: [],\n }\n\n // Parse prompt credits\n if (userStatus.quota?.promptCredits) {\n snapshot.promptCredits = parsePromptCredits(userStatus.quota.promptCredits)\n }\n\n // Group models into Gemini and Claude+GPT buckets (simulating quota groups)\n if (userStatus.quota?.models) {\n const geminiModels: ModelQuotaInfo[] = []\n const claudeModels: ModelQuotaInfo[] = []\n\n for (const model of userStatus.quota.models) {\n const info: ModelQuotaInfo = {\n label: model.label || model.displayName || model.modelId,\n modelId: model.modelId,\n remainingPercentage: model.quota?.remainingPercentage,\n isExhausted: model.isExhausted ?? (model.quota?.remainingPercentage === 0),\n resetTime: model.quota?.resetTime,\n timeUntilResetMs: model.quota?.timeUntilResetMs,\n isAutocompleteOnly: detectAutocomplete(model.modelId, model.label),\n }\n\n if (info.isAutocompleteOnly) continue\n\n if (isGeminiModel(model.modelId)) {\n geminiModels.push(info)\n } else {\n claudeModels.push(info)\n }\n }\n\n // Create synthetic quota groups from model data\n if (geminiModels.length > 0) {\n snapshot.groups.push(createGroupFromModels('Gemini Models', geminiModels))\n }\n if (claudeModels.length > 0) {\n snapshot.groups.push(createGroupFromModels('Claude + GPT Models', claudeModels))\n }\n }\n\n return snapshot\n}\n\n// ── Helpers ────────────────────────────────────────────────────────\n\nfunction parsePromptCredits(credits: NonNullable<ConnectUserStatus['quota']>['promptCredits']): PromptCreditsInfo | undefined {\n if (!credits) return undefined\n const limit = credits.limit ?? 0\n const remaining = credits.remaining ?? limit\n const used = credits.used ?? (limit - remaining)\n if (limit === 0) return undefined\n return {\n available: remaining,\n monthly: limit,\n usedPercentage: limit > 0 ? used / limit : 0,\n remainingPercentage: limit > 0 ? remaining / limit : 1,\n }\n}\n\nfunction createGroupFromModels(displayName: string, models: ModelQuotaInfo[]): QuotaGroup {\n // Find the best session/reset bucket from available models\n const bestModel = models.reduce((best, m) => {\n const remaining = m.remainingPercentage ?? 1\n const bestRemaining = best.remainingPercentage ?? 1\n return remaining < bestRemaining ? m : best\n }, models[0])\n\n const bucket: QuotaBucket = {\n bucketId: 'session',\n displayName: 'Session (5-hour)',\n description: bestModel.resetTime\n ? `Resets at ${new Date(bestModel.resetTime).toLocaleTimeString()}`\n : '5-hour session window',\n remainingFraction: bestModel.remainingPercentage ?? 1,\n resetTime: bestModel.resetTime,\n timeUntilResetMs: bestModel.timeUntilResetMs,\n }\n\n return {\n displayName,\n buckets: [bucket],\n }\n}\n\nfunction isGeminiModel(modelId: string): boolean {\n const lower = modelId.toLowerCase()\n return lower.includes('gemini')\n}\n\nfunction detectAutocomplete(modelId: string, label?: string): boolean {\n const text = `${modelId} ${label || ''}`.toLowerCase()\n return text.includes('autocomplete') ||\n text.includes('gemini-2.5') ||\n text.includes('gemini 2.5')\n}\n\nfunction clampFraction(value: number | undefined): number {\n if (value === undefined || value === null) return 1\n return Math.max(0, Math.min(1, value))\n}\n","/**\n * Local data source adapter — connects to Antigravity's local language server\n *\n * This is the preferred source: fast, offline, no login needed.\n * Uses a multi-strategy approach: detect process → discover port → probe → fetch quota.\n */\n\nimport type { DataSourceAdapter, QuotaSnapshot } from '../../sdk/types.js'\nimport { debug } from '../../core/logger.js'\nimport { detectAntigravityProcesses, extractFlags } from './process-detector.js'\nimport { discoverPorts, scanPortRange } from './port-detective.js'\nimport { ConnectClient } from './connect-client.js'\nimport { parseQuotaSummary, parseUserStatus } from './parser.js'\nimport { SourceUnavailableError } from '../../core/errors.js'\n\nexport class LocalSource implements DataSourceAdapter {\n readonly name = 'local' as const\n readonly priority = 1\n\n async isAvailable(): Promise<boolean> {\n try {\n const processes = await detectAntigravityProcesses()\n return processes.length > 0\n } catch {\n return false\n }\n }\n\n async fetchQuota(): Promise<QuotaSnapshot> {\n debug('local', 'Starting local fetch')\n\n // Step 1: Detect processes\n const processes = await detectAntigravityProcesses()\n if (processes.length === 0) {\n throw new SourceUnavailableError('local', 'No Antigravity process found')\n }\n\n // Step 2: Try each process until we get quota data\n for (const proc of processes) {\n debug('local', `Trying PID ${proc.pid} (${proc.scope})`)\n\n // Extract port from command line flags first (most reliable on Windows)\n const flags = extractFlags(proc.commandLine || '')\n let ports: number[] = []\n\n // If --extension_server_port is in command line, use it directly\n const directPort = flags.get('extension_server_port')\n if (directPort) {\n const portNum = parseInt(directPort, 10)\n if (!isNaN(portNum)) {\n ports.push(portNum)\n debug('local', `Found port from command line: ${portNum}`)\n }\n }\n\n // Also discover ports via OS tools\n const discoveredPorts = await discoverPorts(proc.pid)\n for (const p of discoveredPorts) {\n if (!ports.includes(p)) ports.push(p)\n }\n\n // Get CSRF token from command line\n const csrfToken = flags.get('csrf_token') || flags.get('extension_server_csrf_token')\n\n // Step 3: Probe each port\n for (const port of ports) {\n const quota = await this.probePort(port, csrfToken)\n if (quota) return quota\n }\n }\n\n // Step 4: Last resort — scan common port ranges\n debug('local', 'Direct detection failed, scanning port range')\n const scannedPorts = await scanPortRange(8000, 9500)\n for (const port of scannedPorts) {\n const quota = await this.probePort(port)\n if (quota) return quota\n }\n\n throw new SourceUnavailableError('local', 'Could not connect to any local server')\n }\n\n /**\n * Probe a single port and try to fetch quota\n */\n private async probePort(port: number, csrfToken?: string): Promise<QuotaSnapshot | null> {\n for (const scheme of ['https', 'http']) {\n const baseUrl = `${scheme}://127.0.0.1:${port}`\n const client = new ConnectClient(baseUrl, csrfToken)\n\n // Check if server responds\n const reachable = await client.probe()\n if (!reachable) continue\n\n debug('local', `Probing ${baseUrl}`)\n\n // Try quota summary first (richest data)\n const summary = await client.fetchQuotaSummary()\n if (summary && summary.groups.length > 0) {\n const email = (await client.fetchUserStatus())?.email\n debug('local', `Got quota summary from ${baseUrl}`)\n return parseQuotaSummary(summary, email)\n }\n\n // Fallback: GetUserStatus (legacy)\n const userStatus = await client.fetchUserStatus()\n if (userStatus) {\n debug('local', `Got user status from ${baseUrl}`)\n return parseUserStatus(userStatus)\n }\n }\n\n return null\n }\n}\n","/**\n * agy CLI data source adapter\n *\n * When the Antigravity desktop app isn't running, we can launch the agy CLI\n * and use its embedded HTTPS server to fetch quota data.\n * This source requires a signed-in agy session.\n */\n\nimport type { DataSourceAdapter, QuotaSnapshot } from '../../sdk/types.js'\nimport { debug } from '../../core/logger.js'\nimport { ConnectClient } from '../local/connect-client.js'\nimport { parseQuotaSummary, parseUserStatus } from '../local/parser.js'\nimport { discoverPorts } from '../local/port-detective.js'\nimport { SourceUnavailableError } from '../../core/errors.js'\nimport { runCommand, isWindows } from '../../core/platform.js'\nimport { exec, type ChildProcess } from 'child_process'\nimport { promisify } from 'util'\n\nconst execAsync = promisify(exec)\n\nexport class CliSource implements DataSourceAdapter {\n readonly name = 'cli' as const\n readonly priority = 2\n\n private agyProcess: ChildProcess | null = null\n\n async isAvailable(): Promise<boolean> {\n const path = await findAgyBinary()\n return path !== null\n }\n\n async fetchQuota(): Promise<QuotaSnapshot> {\n debug('cli', 'Starting CLI source fetch')\n\n const agyPath = await findAgyBinary()\n if (!agyPath) {\n throw new SourceUnavailableError('cli', 'agy binary not found')\n }\n\n // Try to find an already-running agy first\n const existingQuota = await this.tryExistingAgy()\n if (existingQuota) return existingQuota\n\n // Launch agy and connect\n return await this.launchAndFetch(agyPath)\n }\n\n /**\n * Check if there's already a running agy instance we can reuse\n */\n private async tryExistingAgy(): Promise<QuotaSnapshot | null> {\n // Find agy processes\n const cmd = isWindows()\n ? 'wmic process where \"commandline like \\'%agy%\\'\" get ProcessId,CommandLine /format:csv'\n : 'ps -ax -o pid=,args='\n\n const output = await runCommand(cmd)\n const pids = output.split('\\n')\n .map(line => {\n const match = line.match(/^\\s*(\\d+)/)\n return match ? parseInt(match[1], 10) : NaN\n })\n .filter(p => !isNaN(p))\n\n for (const pid of pids) {\n const ports = await discoverPorts(pid)\n for (const port of ports) {\n const quota = await this.probePort(port)\n if (quota) return quota\n }\n }\n\n return null\n }\n\n /**\n * Launch agy and wait for its server, then fetch quota\n */\n private async launchAndFetch(agyPath: string): Promise<QuotaSnapshot> {\n debug('cli', `Launching agy: ${agyPath}`)\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.agyProcess?.kill()\n reject(new SourceUnavailableError('cli', 'agy startup timed out'))\n }, 15000)\n\n this.agyProcess = exec(agyPath, { env: { ...process.env, NO_COLOR: '1' } })\n\n // Poll for the agy server to come up\n const pollInterval = setInterval(async () => {\n try {\n // agy typically binds to a high port\n if (!this.agyProcess?.pid) return\n const ports = await discoverPorts(this.agyProcess.pid)\n for (const port of ports) {\n const quota = await this.probePort(port)\n if (quota) {\n clearTimeout(timeout)\n clearInterval(pollInterval)\n this.agyProcess?.kill()\n resolve(quota)\n return\n }\n }\n } catch { /* keep trying */ }\n }, 1000)\n\n this.agyProcess.on('error', (err) => {\n clearTimeout(timeout)\n clearInterval(pollInterval)\n reject(new SourceUnavailableError('cli', `agy failed: ${err.message}`))\n })\n\n this.agyProcess.on('exit', () => {\n clearTimeout(timeout)\n clearInterval(pollInterval)\n })\n })\n }\n\n /**\n * Probe a port for quota data\n */\n private async probePort(port: number): Promise<QuotaSnapshot | null> {\n for (const scheme of ['https', 'http']) {\n const baseUrl = `${scheme}://127.0.0.1:${port}`\n const client = new ConnectClient(baseUrl) // agy doesn't need CSRF token\n\n try {\n const reachable = await client.probe()\n if (!reachable) continue\n\n const summary = await client.fetchQuotaSummary()\n if (summary && summary.groups.length > 0) {\n const email = (await client.fetchUserStatus())?.email\n return parseQuotaSummary(summary, email)\n }\n\n const userStatus = await client.fetchUserStatus()\n if (userStatus) return parseUserStatus(userStatus)\n } catch { /* try next */ }\n }\n return null\n }\n\n destroy(): void {\n this.agyProcess?.kill()\n this.agyProcess = null\n }\n}\n\n/**\n * Find the agy binary on PATH or common locations\n */\nasync function findAgyBinary(): Promise<string | null> {\n // Check env override\n if (process.env.ANTIGRAVITY_CLI_PATH) {\n return process.env.ANTIGRAVITY_CLI_PATH\n }\n\n // Check PATH\n try {\n const cmd = isWindows() ? 'where agy' : 'which agy'\n const output = await execAsync(cmd)\n const path = output.stdout.trim()\n if (path) return path\n } catch { /* not on PATH */ }\n\n // Check common locations\n const commonPaths = isWindows()\n ? [\n `${process.env.LOCALAPPDATA || ''}/antigravity-cli/agy.exe`,\n `${process.env.PROGRAMFILES || ''}/antigravity-cli/agy.exe`,\n ]\n : [\n `${process.env.HOME}/.local/bin/agy`,\n '/opt/homebrew/bin/agy',\n '/usr/local/bin/agy',\n ]\n\n for (const p of commonPaths) {\n if (!p) continue\n try {\n await execAsync(`test -x \"${p}\"`)\n return p\n } catch { /* not there */ }\n }\n\n return null\n}\n","/**\n * OAuth/Cloud Code API data source adapter\n *\n * Fetches quota remotely via Google Cloud Code API.\n * Requires a valid OAuth token.\n */\n\nimport type { DataSourceAdapter, QuotaSnapshot } from '../../sdk/types.js'\nimport { debug } from '../../core/logger.js'\nimport { OAuthClient } from './client.js'\nimport { parseQuotaSummary, parseUserStatus } from '../local/parser.js'\nimport { SourceUnavailableError } from '../../core/errors.js'\nimport type { QuotaSummaryResponse, ConnectUserStatus } from '../local/connect-client.js'\n\nexport class OAuthSource implements DataSourceAdapter {\n readonly name = 'oauth' as const\n readonly priority = 3\n\n private client: OAuthClient\n\n constructor(client: OAuthClient) {\n this.client = client\n }\n\n async isAvailable(): Promise<boolean> {\n try {\n await this.client.getAccessToken()\n return true\n } catch {\n return false\n }\n }\n\n async fetchQuota(): Promise<QuotaSnapshot> {\n debug('oauth', 'Fetching quota via Cloud Code API')\n\n try {\n // Try quota summary first\n const summaryRaw = await this.client.fetchQuotaSummary()\n const summary = this.parseRemoteSummary(summaryRaw)\n if (summary && summary.groups.length > 0) {\n // Get email from user status\n const statusRaw = await this.client.fetchUserStatus()\n const email = this.extractEmail(statusRaw)\n debug('oauth', 'Got quota summary via OAuth')\n return parseQuotaSummary(summary, email)\n }\n\n // Fallback: loadCodeAssist for basic info\n const statusRaw = await this.client.fetchUserStatus()\n const status = this.parseRemoteStatus(statusRaw)\n if (status) {\n debug('oauth', 'Got user status via OAuth')\n return parseUserStatus(status)\n }\n } catch (err) {\n debug('oauth', `Fetch failed: ${err}`)\n }\n\n throw new SourceUnavailableError('oauth', 'Could not fetch quota via Cloud Code API')\n }\n\n /**\n * Parse remote summary response into QuotaSummaryResponse format\n */\n private parseRemoteSummary(raw: unknown): QuotaSummaryResponse | null {\n if (typeof raw !== 'object' || raw === null) return null\n const data = raw as Record<string, unknown>\n\n // The response might be wrapped\n const groups = data.groups as Array<Record<string, unknown>> | undefined\n if (!Array.isArray(groups)) return null\n\n return {\n groups: groups.map(g => ({\n displayName: String(g.displayName || ''),\n buckets: Array.isArray(g.buckets)\n ? g.buckets.map((b: Record<string, unknown>) => ({\n bucketId: String(b.bucketId || ''),\n displayName: String(b.displayName || ''),\n description: String(b.description || ''),\n remainingFraction: typeof (b as any).remaining?.remainingFraction === 'number'\n ? (b as any).remaining.remainingFraction as number\n : typeof (b as any).remainingFraction === 'number'\n ? (b as any).remainingFraction as number\n : 1,\n resetTime: typeof b.resetTime === 'string' ? b.resetTime : undefined,\n }))\n : [],\n })),\n raw,\n }\n }\n\n /**\n * Parse remote user status response\n */\n private parseRemoteStatus(raw: unknown): ConnectUserStatus | null {\n if (typeof raw !== 'object' || raw === null) return null\n return { raw }\n }\n\n private extractEmail(raw: unknown): string | undefined {\n if (typeof raw !== 'object' || raw === null) return undefined\n const data = raw as Record<string, unknown>\n const userStatus = data.userStatus as Record<string, unknown> | undefined\n return (userStatus?.email || data.email) as string | undefined\n }\n}\n","/**\n * Google OAuth client for Cloud Code API\n *\n * Handles the OAuth2 flow for remote quota fetching.\n */\n\nimport https from 'https'\nimport http from 'http'\nimport { URL } from 'url'\nimport { debug } from '../../core/logger.js'\nimport type { OAuthTokenResponse, StoredTokens } from '../../sdk/types.js'\nimport {\n CLOUD_CODE_ENDPOINTS,\n CLOUD_CODE_DEFAULT_BODY,\n OAUTH_CLIENT_ID,\n OAUTH_CLIENT_SECRET,\n OAUTH_SCOPES,\n} from '../cloud-code-api.js'\n\nexport class OAuthClient {\n private tokens: StoredTokens | null = null\n\n constructor(tokens?: StoredTokens) {\n this.tokens = tokens || null\n }\n\n /**\n * Generate the OAuth authorization URL for user login\n */\n getAuthUrl(): string {\n const params = new URLSearchParams({\n client_id: OAUTH_CLIENT_ID,\n redirect_uri: 'http://127.0.0.1:0/callback',\n response_type: 'code',\n scope: OAUTH_SCOPES,\n access_type: 'offline',\n prompt: 'consent',\n })\n return `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`\n }\n\n /**\n * Exchange an authorization code for tokens\n */\n async exchangeCode(code: string): Promise<StoredTokens> {\n const body = new URLSearchParams({\n code,\n client_id: OAUTH_CLIENT_ID,\n client_secret: OAUTH_CLIENT_SECRET,\n redirect_uri: 'http://127.0.0.1:0/callback',\n grant_type: 'authorization_code',\n })\n\n const response = await this.postUrlEncoded('https://oauth2.googleapis.com/token', body)\n const data = response as OAuthTokenResponse\n\n this.tokens = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token || '',\n expiresAt: Date.now() + data.expires_in * 1000,\n }\n\n return this.tokens\n }\n\n /**\n * Refresh the access token\n */\n async refreshAccessToken(): Promise<StoredTokens> {\n if (!this.tokens?.refreshToken) {\n throw new Error('No refresh token available')\n }\n\n const body = new URLSearchParams({\n client_id: OAUTH_CLIENT_ID,\n client_secret: OAUTH_CLIENT_SECRET,\n refresh_token: this.tokens.refreshToken,\n grant_type: 'refresh_token',\n })\n\n const response = await this.postUrlEncoded('https://oauth2.googleapis.com/token', body)\n const data = response as OAuthTokenResponse\n\n this.tokens = {\n ...this.tokens,\n accessToken: data.access_token,\n expiresAt: Date.now() + data.expires_in * 1000,\n }\n\n return this.tokens\n }\n\n /**\n * Get a valid access token, refreshing if necessary\n */\n async getAccessToken(): Promise<string> {\n if (!this.tokens) throw new Error('Not authenticated')\n if (Date.now() >= this.tokens.expiresAt - 60000) {\n await this.refreshAccessToken()\n }\n return this.tokens.accessToken!\n }\n\n /**\n * Get stored tokens\n */\n getTokens(): StoredTokens | null {\n return this.tokens\n }\n\n /**\n * Make an authenticated POST request to the Cloud Code API\n */\n async fetchQuotaSummary(): Promise<unknown> {\n const token = await this.getAccessToken()\n return this.authenticatedPost(\n CLOUD_CODE_ENDPOINTS.retrieveUserQuotaSummary,\n CLOUD_CODE_DEFAULT_BODY,\n token\n )\n }\n\n async fetchUserStatus(): Promise<unknown> {\n const token = await this.getAccessToken()\n return this.authenticatedPost(\n CLOUD_CODE_ENDPOINTS.loadCodeAssist,\n CLOUD_CODE_DEFAULT_BODY,\n token\n )\n }\n\n async fetchAvailableModels(): Promise<unknown> {\n const token = await this.getAccessToken()\n return this.authenticatedPost(\n CLOUD_CODE_ENDPOINTS.fetchAvailableModels,\n CLOUD_CODE_DEFAULT_BODY,\n token\n )\n }\n\n // ── HTTP Helpers ────────────────────────────────────────────────\n\n private authenticatedPost(url: string, body: unknown, token: string): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const parsed = new URL(url)\n const data = JSON.stringify(body)\n const options: http.RequestOptions = {\n hostname: parsed.hostname,\n path: parsed.pathname,\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`,\n 'Content-Length': Buffer.byteLength(data),\n },\n timeout: 10000,\n }\n\n const req = https.request(options, (res) => {\n let responseData = ''\n res.on('data', (chunk: Buffer) => { responseData += chunk })\n res.on('end', () => {\n try {\n resolve(JSON.parse(responseData))\n } catch {\n reject(new Error(`Invalid JSON: ${responseData.slice(0, 200)}`))\n }\n })\n })\n req.on('error', reject)\n req.on('timeout', () => { req.destroy(); reject(new Error('Timeout')) })\n req.write(data)\n req.end()\n })\n }\n\n private postUrlEncoded(url: string, body: URLSearchParams): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const parsed = new URL(url)\n const data = body.toString()\n const options: http.RequestOptions = {\n hostname: parsed.hostname,\n path: parsed.pathname,\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n 'Content-Length': Buffer.byteLength(data),\n },\n timeout: 10000,\n }\n\n const req = https.request(options, (res) => {\n let responseData = ''\n res.on('data', (chunk: Buffer) => { responseData += chunk })\n res.on('end', () => {\n try {\n resolve(JSON.parse(responseData))\n } catch {\n reject(new Error(`Invalid JSON: ${responseData.slice(0, 200)}`))\n }\n })\n })\n req.on('error', reject)\n req.on('timeout', () => { req.destroy(); reject(new Error('Timeout')) })\n req.write(data)\n req.end()\n })\n }\n}\n","/**\n * Google Cloud Code API endpoints for remote quota fetching\n *\n * Used as fallback when local sources are unavailable.\n * Requires OAuth authentication.\n */\n\nexport const CLOUD_CODE_ENDPOINTS = {\n /** Load code assist configuration */\n loadCodeAssist: 'https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist',\n\n /** Onboard a new user */\n onboardUser: 'https://cloudcode-pa.googleapis.com/v1internal:onboardUser',\n\n /** Fetch available models for the account */\n fetchAvailableModels: 'https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels',\n\n /** Fetch raw quota data */\n retrieveUserQuota: 'https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuota',\n\n /** Fetch quota summary with weekly + session buckets */\n retrieveUserQuotaSummary: 'https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuotaSummary',\n} as const\n\nexport const CLOUD_CODE_DEFAULT_BODY = {\n metadata: {\n ideName: 'antigravity',\n extensionName: 'antigravity',\n locale: 'en',\n ideVersion: 'unknown',\n },\n}\n\nexport const OAUTH_CLIENT_ID = '764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com'\nexport const OAUTH_CLIENT_SECRET = 'd-FL95Q19q7MQmFpd7hHD0Ty'\nexport const OAUTH_SCOPES = [\n 'https://www.googleapis.com/auth/cloud-platform',\n].join(' ')\nexport const OAUTH_REDIRECT_URI = 'http://127.0.0.1:0/callback'\n","/**\n * Source registry — manages data source adapters and implements the fallback chain\n *\n * Priority order:\n * 1. Local (Antigravity app language server) — fastest, offline\n * 2. CLI (agy CLI HTTPS server) — no app needed, requires signed-in agy\n * 3. OAuth (Google Cloud Code API) — works anywhere, requires login\n */\n\nimport type { DataSourceAdapter, QuotaSnapshot, DataSource } from '../sdk/types.js'\nimport { debug } from '../core/logger.js'\nimport { SourceUnavailableError } from '../core/errors.js'\nimport { LocalSource } from './local/index.js'\nimport { CliSource } from './cli/index.js'\n\nexport { LocalSource } from './local/index.js'\nexport { CliSource } from './cli/index.js'\nexport { OAuthSource } from './oauth/index.js'\nexport { OAuthClient } from './oauth/client.js'\n\nexport class SourceRegistry {\n private sources: DataSourceAdapter[] = []\n private health: Map<DataSource, { available: boolean; lastCheck: number }> = new Map()\n\n constructor() {\n // Register built-in sources in priority order\n this.sources.push(new LocalSource())\n this.sources.push(new CliSource())\n // OAuth source is added manually when credentials are available\n }\n\n /**\n * Register an additional data source (e.g., OAuth)\n */\n addSource(source: DataSourceAdapter): void {\n // Insert in priority order\n const idx = this.sources.findIndex(s => s.priority > source.priority)\n if (idx === -1) {\n this.sources.push(source)\n } else {\n this.sources.splice(idx, 0, source)\n }\n debug('registry', `Registered source: ${source.name} (priority ${source.priority})`)\n }\n\n /**\n * Remove a source by name\n */\n removeSource(name: DataSource): void {\n this.sources = this.sources.filter(s => s.name !== name)\n }\n\n /**\n * Fetch quota using the best available source\n *\n * @param preferredSource Force a specific source\n */\n async fetchQuota(preferredSource?: DataSource): Promise<QuotaSnapshot> {\n // If a specific source is requested, use only that\n if (preferredSource) {\n const source = this.sources.find(s => s.name === preferredSource)\n if (!source) throw new Error(`Source \"${preferredSource}\" not registered`)\n const snapshot = await source.fetchQuota()\n this.health.set(preferredSource, { available: true, lastCheck: Date.now() })\n return snapshot\n }\n\n // Otherwise, try sources in priority order\n const errors: string[] = []\n\n for (const source of this.sources) {\n debug('registry', `Trying source: ${source.name}`)\n\n try {\n const available = await source.isAvailable()\n if (!available) {\n debug('registry', `Source ${source.name} not available`)\n this.health.set(source.name, { available: false, lastCheck: Date.now() })\n continue\n }\n\n const snapshot = await source.fetchQuota()\n this.health.set(source.name, { available: true, lastCheck: Date.now() })\n debug('registry', `Success with source: ${source.name}`)\n return snapshot\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n errors.push(`${source.name}: ${msg}`)\n this.health.set(source.name, { available: false, lastCheck: Date.now() })\n debug('registry', `Source ${source.name} failed: ${msg}`)\n }\n }\n\n throw new SourceUnavailableError('all', `No sources available:\\n${errors.map(e => ` • ${e}`).join('\\n')}`)\n }\n\n /**\n * Get health status of all sources\n */\n getHealth(): Map<DataSource, { available: boolean; lastCheck: number }> {\n return new Map(this.health)\n }\n\n /**\n * Get registered source names\n */\n getSourceNames(): DataSource[] {\n return this.sources.map(s => s.name)\n }\n}\n","/**\n * Smart caching layer for quota data\n *\n * Caches quota snapshots to avoid hitting API rate limits.\n * Cache is keyed by email + source combination.\n */\n\nimport { debug } from '../core/logger.js'\nimport type { QuotaSnapshot } from './types.js'\n\ninterface CacheEntry {\n snapshot: QuotaSnapshot\n cachedAt: number\n}\n\nexport class QuotaCache {\n private cache: Map<string, CacheEntry> = new Map()\n private ttlMs: number\n\n constructor(ttlMs: number = 5 * 60 * 1000) {\n this.ttlMs = ttlMs\n }\n\n /**\n * Get cached quota if available and not expired\n */\n get(email: string, source: string): QuotaSnapshot | null {\n const key = `${email}:${source}`\n const entry = this.cache.get(key)\n if (!entry) return null\n\n const age = Date.now() - entry.cachedAt\n if (age > this.ttlMs) {\n this.cache.delete(key)\n debug('cache', `Expired entry for ${email} (age: ${Math.round(age / 1000)}s)`)\n return null\n }\n\n debug('cache', `Cache hit for ${email} (age: ${Math.round(age / 1000)}s)`)\n return entry.snapshot\n }\n\n /**\n * Store a quota snapshot in cache\n */\n set(email: string, source: string, snapshot: QuotaSnapshot): void {\n const key = `${email}:${source}`\n this.cache.set(key, {\n snapshot,\n cachedAt: Date.now(),\n })\n debug('cache', `Cached snapshot for ${email}`)\n }\n\n /**\n * Check if a cached entry is still fresh\n */\n isFresh(email: string, source: string): boolean {\n const key = `${email}:${source}`\n const entry = this.cache.get(key)\n if (!entry) return false\n return (Date.now() - entry.cachedAt) <= this.ttlMs\n }\n\n /**\n * Clear all cached entries\n */\n clear(): void {\n this.cache.clear()\n debug('cache', 'Cleared all cache entries')\n }\n\n /**\n * Get cache age in seconds for a key\n */\n getAgeMs(email: string, source: string): number | null {\n const key = `${email}:${source}`\n const entry = this.cache.get(key)\n if (!entry) return null\n return Date.now() - entry.cachedAt\n }\n}\n","/**\n * SQLite storage for usage history and analytics\n */\n\nimport Database from 'better-sqlite3'\nimport { join } from 'path'\nimport { getDataDirPath, ensureDirs } from '../core/config.js'\nimport { debug } from '../core/logger.js'\nimport type { UsageRecord, QuotaSnapshot } from './types.js'\n\nlet db: Database.Database | null = null\n\nfunction getDb(): Database.Database {\n if (db) return db\n ensureDirs()\n const dbPath = join(getDataDirPath(), 'history.db')\n db = new Database(dbPath)\n db.pragma('journal_mode = WAL')\n initSchema(db)\n debug('store', `Opened database at ${dbPath}`)\n return db\n}\n\nfunction initSchema(database: Database.Database): void {\n database.exec(`\n CREATE TABLE IF NOT EXISTS quota_snapshots (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n timestamp TEXT NOT NULL,\n email TEXT NOT NULL,\n method TEXT NOT NULL,\n gemini_weekly_remaining REAL,\n gemini_session_remaining REAL,\n claude_weekly_remaining REAL,\n claude_session_remaining REAL,\n raw_json TEXT\n );\n\n CREATE INDEX IF NOT EXISTS idx_snapshots_email_ts\n ON quota_snapshots(email, timestamp);\n `)\n}\n\n/**\n * Store a quota snapshot for history tracking\n */\nexport function storeSnapshot(snapshot: QuotaSnapshot): void {\n const database = getDb()\n\n // Extract group data\n let geminiWeekly: number | null = null\n let geminiSession: number | null = null\n let claudeWeekly: number | null = null\n let claudeSession: number | null = null\n\n for (const group of snapshot.groups) {\n const lower = group.displayName.toLowerCase()\n for (const bucket of group.buckets) {\n const bucketLower = bucket.displayName.toLowerCase()\n if (lower.includes('gemini')) {\n if (bucketLower.includes('weekly') || bucketLower.includes('week')) {\n geminiWeekly = bucket.remainingFraction\n } else {\n geminiSession = bucket.remainingFraction\n }\n } else if (lower.includes('claude') || lower.includes('gpt')) {\n if (bucketLower.includes('weekly') || bucketLower.includes('week')) {\n claudeWeekly = bucket.remainingFraction\n } else {\n claudeSession = bucket.remainingFraction\n }\n }\n }\n }\n\n const stmt = database.prepare(`\n INSERT INTO quota_snapshots\n (timestamp, email, method, gemini_weekly_remaining, gemini_session_remaining,\n claude_weekly_remaining, claude_session_remaining, raw_json)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `)\n\n stmt.run(\n snapshot.timestamp,\n snapshot.email || 'unknown',\n snapshot.method,\n geminiWeekly,\n geminiSession,\n claudeWeekly,\n claudeSession,\n JSON.stringify(snapshot),\n )\n\n debug('store', `Stored snapshot for ${snapshot.email}`)\n}\n\n/**\n * Retrieve usage history for an account\n */\nexport function getHistory(\n email: string,\n options?: { days?: number; limit?: number }\n): UsageRecord[] {\n const database = getDb()\n const days = options?.days || 7\n const limit = options?.limit || 1000\n\n const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString()\n\n const stmt = database.prepare(`\n SELECT timestamp, email, gemini_weekly_remaining, gemini_session_remaining,\n claude_weekly_remaining, claude_session_remaining\n FROM quota_snapshots\n WHERE email = ? AND timestamp >= ?\n ORDER BY timestamp DESC\n LIMIT ?\n `)\n\n const rows = stmt.all(email, since, limit) as Array<Record<string, unknown>>\n\n return rows.map((row): UsageRecord => ({\n timestamp: String(row.timestamp),\n email: String(row.email),\n geminiWeeklyRemaining: row.gemini_weekly_remaining as number | null,\n geminiSessionRemaining: row.gemini_session_remaining as number | null,\n claudeWeeklyRemaining: row.claude_weekly_remaining as number | null,\n claudeSessionRemaining: row.claude_session_remaining as number | null,\n }))\n}\n\n/**\n * Get the most recent snapshot for an account\n */\nexport function getLatestSnapshot(email: string): UsageRecord | null {\n const history = getHistory(email, { limit: 1 })\n return history[0] || null\n}\n\n/**\n * Get daily usage summary (average remaining per day)\n */\nexport function getDailySummary(email: string, days: number = 7): Array<{\n date: string\n geminiWeeklyAvg: number | null\n geminiSessionAvg: number | null\n claudeWeeklyAvg: number | null\n claudeSessionAvg: number | null\n count: number\n}> {\n const database = getDb()\n const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString()\n\n const stmt = database.prepare(`\n SELECT\n date(timestamp) as date,\n AVG(gemini_weekly_remaining) as gemini_weekly_avg,\n AVG(gemini_session_remaining) as gemini_session_avg,\n AVG(claude_weekly_remaining) as claude_weekly_avg,\n AVG(claude_session_remaining) as claude_session_avg,\n COUNT(*) as count\n FROM quota_snapshots\n WHERE email = ? AND timestamp >= ?\n GROUP BY date(timestamp)\n ORDER BY date(timestamp) ASC\n `)\n\n const rows = stmt.all(email, since) as Array<Record<string, unknown>>\n\n return rows.map(row => ({\n date: String(row.date),\n geminiWeeklyAvg: row.gemini_weekly_avg as number | null,\n geminiSessionAvg: row.gemini_session_avg as number | null,\n claudeWeeklyAvg: row.claude_weekly_avg as number | null,\n claudeSessionAvg: row.claude_session_avg as number | null,\n count: Number(row.count),\n }))\n}\n\n/**\n * Clean up old snapshots (older than N days)\n */\nexport function cleanupHistory(keepDays: number = 90): number {\n const database = getDb()\n const cutoff = new Date(Date.now() - keepDays * 24 * 60 * 60 * 1000).toISOString()\n const result = database.prepare(\n 'DELETE FROM quota_snapshots WHERE timestamp < ?'\n ).run(cutoff)\n return result.changes\n}\n\n/**\n * Close the database connection\n */\nexport function closeStore(): void {\n if (db) {\n db.close()\n db = null\n debug('store', 'Database closed')\n }\n}\n","/**\n * Config file management — reads/writes app configuration\n */\n\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs'\nimport { join } from 'path'\nimport { homedir } from 'os'\nimport type { AppConfig } from '../sdk/types.js'\nimport { debug } from './logger.js'\n\nconst CONFIG_DIR_NAME = 'when-does-my-quota-refresh'\n\nconst DEFAULT_CONFIG: AppConfig = {\n defaultMode: 'local',\n cacheTtlMs: 5 * 60 * 1000, // 5 minutes\n refreshIntervalMs: 5 * 60 * 1000,\n wakeupModels: ['claude-sonnet-4-5', 'gemini-3-flash', 'gemini-3-pro-low'],\n wakeupAccounts: [],\n notifications: true,\n plugins: [],\n daemon: {\n pollIntervalMs: 60 * 1000,\n enabled: false,\n },\n}\n\nfunction getConfigDir(): string {\n const home = homedir()\n switch (process.platform) {\n case 'darwin':\n return join(home, 'Library', 'Application Support', CONFIG_DIR_NAME)\n case 'win32':\n return join(process.env.APPDATA || join(home, 'AppData', 'Roaming'), CONFIG_DIR_NAME)\n default:\n return join(home, '.config', CONFIG_DIR_NAME)\n }\n}\n\nfunction getConfigPath(): string {\n return join(getConfigDir(), 'config.json')\n}\n\nfunction getDataDir(): string {\n return join(getConfigDir(), 'data')\n}\n\nexport function ensureDirs(): void {\n const configDir = getConfigDir()\n const dataDir = getDataDir()\n if (!existsSync(configDir)) mkdirSync(configDir, { recursive: true })\n if (!existsSync(dataDir)) mkdirSync(dataDir, { recursive: true })\n}\n\nexport function loadConfig(): AppConfig {\n try {\n const path = getConfigPath()\n if (!existsSync(path)) return DEFAULT_CONFIG\n const raw = readFileSync(path, 'utf-8')\n const parsed = JSON.parse(raw)\n debug('config', `Loaded config from ${path}`)\n return { ...DEFAULT_CONFIG, ...parsed }\n } catch (err) {\n debug('config', 'Failed to load config, using defaults', err)\n return DEFAULT_CONFIG\n }\n}\n\nexport function saveConfig(config: AppConfig): void {\n ensureDirs()\n const path = getConfigPath()\n writeFileSync(path, JSON.stringify(config, null, 2))\n debug('config', `Saved config to ${path}`)\n}\n\nexport function getConfigDirPath(): string {\n return getConfigDir()\n}\n\nexport function getDataDirPath(): string {\n return getDataDir()\n}\n\nexport { DEFAULT_CONFIG }\n","/**\n * Token storage for account credentials\n *\n * Stores OAuth tokens locally in the config directory.\n * Tokens are stored as plain JSON (local machine only).\n */\n\nimport { readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs'\nimport { join } from 'path'\nimport type { StoredTokens } from '../types.js'\nimport { getConfigDirPath, ensureDirs } from '../../core/config.js'\nimport { debug } from '../../core/logger.js'\n\nconst TOKENS_DIR = 'accounts'\n\ninterface TokenAccount {\n email: string\n tokens: StoredTokens\n addedAt: string\n}\n\ninterface TokenStore {\n accounts: TokenAccount[]\n activeEmail?: string\n}\n\nfunction getStorePath(): string {\n return join(getConfigDirPath(), TOKENS_DIR, 'tokens.json')\n}\n\nfunction loadStore(): TokenStore {\n const path = getStorePath()\n if (!existsSync(path)) return { accounts: [] }\n try {\n return JSON.parse(readFileSync(path, 'utf-8'))\n } catch {\n return { accounts: [] }\n }\n}\n\nfunction saveStore(store: TokenStore): void {\n ensureDirs()\n writeFileSync(getStorePath(), JSON.stringify(store, null, 2))\n debug('account-storage', `Saved ${store.accounts.length} account(s)`)\n}\n\n/**\n * Save tokens for an account\n */\nexport function saveAccountTokens(email: string, tokens: StoredTokens): void {\n const store = loadStore()\n const existing = store.accounts.findIndex(a => a.email === email)\n const account: TokenAccount = {\n email,\n tokens,\n addedAt: new Date().toISOString(),\n }\n\n if (existing >= 0) {\n store.accounts[existing] = account\n } else {\n store.accounts.push(account)\n }\n\n // Set as active if it's the only one\n if (store.accounts.length === 1) {\n store.activeEmail = email\n }\n\n saveStore(store)\n}\n\n/**\n * Get tokens for a specific account\n */\nexport function getAccountTokens(email: string): StoredTokens | null {\n const store = loadStore()\n const account = store.accounts.find(a => a.email === email)\n return account?.tokens || null\n}\n\n/**\n * Get the active account's tokens\n */\nexport function getActiveAccountTokens(): StoredTokens | null {\n const store = loadStore()\n if (!store.activeEmail) return null\n const account = store.accounts.find(a => a.email === store.activeEmail)\n return account?.tokens || null\n}\n\n/**\n * Set the active account\n */\nexport function setActiveAccount(email: string): boolean {\n const store = loadStore()\n if (!store.accounts.find(a => a.email === email)) return false\n store.activeEmail = email\n saveStore(store)\n return true\n}\n\n/**\n * Remove an account\n */\nexport function removeAccount(email: string): boolean {\n const store = loadStore()\n const idx = store.accounts.findIndex(a => a.email === email)\n if (idx < 0) return false\n store.accounts.splice(idx, 1)\n if (store.activeEmail === email) {\n store.activeEmail = store.accounts[0]?.email\n }\n saveStore(store)\n return true\n}\n\n/**\n * List all stored accounts\n */\nexport function listAccounts(): Array<{ email: string; isActive: boolean; addedAt: string }> {\n const store = loadStore()\n return store.accounts.map(a => ({\n email: a.email,\n isActive: a.email === store.activeEmail,\n addedAt: a.addedAt,\n }))\n}\n\n/**\n * Get all stored tokens (for multi-account fetch)\n */\nexport function getAllAccountTokens(): StoredTokens[] {\n const store = loadStore()\n return store.accounts.map(a => a.tokens)\n}\n","/**\n * OAuth authentication flow for Google accounts\n */\n\nimport { OAuthClient } from '../../sources/oauth/client.js'\nimport { saveAccountTokens, setActiveAccount } from './storage.js'\nimport { debug } from '../../core/logger.js'\nimport { AuthError } from '../../core/errors.js'\nimport open from 'open'\nimport http from 'http'\nimport { URL } from 'url'\n\n/**\n * Start an interactive OAuth login flow\n *\n * Opens the browser for Google login, then captures the redirect\n * to exchange the authorization code for tokens.\n */\nexport async function loginAccount(): Promise<string> {\n const client = new OAuthClient()\n const authUrl = client.getAuthUrl()\n\n debug('auth', 'Starting OAuth login flow')\n\n // Start a temporary local server to catch the redirect\n const code = await new Promise<string>((resolve, reject) => {\n const server = http.createServer(async (req, res) => {\n const url = new URL(req.url || '/', `http://127.0.0.1`)\n const code = url.searchParams.get('code')\n\n if (code) {\n res.writeHead(200, { 'Content-Type': 'text/html' })\n res.end(`\n <html><body style=\"font-family: sans-serif; text-align: center; padding: 50px;\">\n <h1>✅ Login successful!</h1>\n <p>You can close this tab and return to the terminal.</p>\n </body></html>\n `)\n server.close()\n resolve(code)\n } else {\n const error = url.searchParams.get('error')\n if (error) {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n res.end(`<h1>Login failed: ${error}</h1>`)\n server.close()\n reject(new AuthError(`OAuth error: ${error}`))\n } else {\n res.writeHead(404)\n res.end('Waiting for OAuth callback...')\n }\n }\n })\n\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address()\n if (typeof addr === 'object' && addr) {\n // Update redirect URI with actual port\n debug('auth', `Callback server on port ${addr.port}`)\n\n // Open browser\n open(authUrl).catch(() => {\n console.log(`\\nOpen this URL in your browser:\\n\\n${authUrl}\\n`)\n })\n }\n })\n\n // Timeout after 5 minutes\n setTimeout(() => {\n server.close()\n reject(new AuthError('Login timed out after 5 minutes'))\n }, 5 * 60 * 1000)\n })\n\n // Exchange code for tokens\n const tokens = await client.exchangeCode(code)\n\n // Get user email\n const email = tokens.email || 'unknown@gmail.com'\n tokens.email = email\n\n // Store tokens\n saveAccountTokens(email, tokens)\n setActiveAccount(email)\n\n debug('auth', `Logged in as ${email}`)\n return email\n}\n\n/**\n * Perform a manual login (headless/SSH mode)\n * Returns the auth URL for the user to open manually\n */\nexport function getManualLoginUrl(): string {\n const client = new OAuthClient()\n return client.getAuthUrl()\n}\n\n/**\n * Complete manual login with an authorization code\n */\nexport async function completeManualLogin(code: string): Promise<string> {\n const client = new OAuthClient()\n const tokens = await client.exchangeCode(code)\n const email = tokens.email || 'unknown@gmail.com'\n tokens.email = email\n saveAccountTokens(email, tokens)\n setActiveAccount(email)\n return email\n}\n","/**\n * Quota fetching orchestration\n *\n * Coordinates between the source registry, cache, storage, and plugins\n * to provide a unified quota fetching experience.\n */\n\nimport type { QuotaSnapshot, DataSource, ClientOptions, UsageRecord } from './types.js'\nimport { SourceRegistry } from '../sources/index.js'\nimport { QuotaCache } from './cache.js'\nimport { storeSnapshot, getHistory, getDailySummary } from './store.js'\nimport { getAllAccountTokens } from './accounts/index.js'\nimport { OAuthClient } from '../sources/oauth/client.js'\nimport { OAuthSource } from '../sources/oauth/index.js'\nimport { loadConfig } from '../core/config.js'\nimport { debug } from '../core/logger.js'\nimport { setVerbose } from '../core/logger.js'\n\nexport class QuotaClient {\n private registry: SourceRegistry\n private cache: QuotaCache\n private verbose: boolean\n\n constructor(options?: ClientOptions) {\n this.verbose = options?.verbose || false\n setVerbose(this.verbose)\n\n const config = loadConfig()\n this.registry = new SourceRegistry()\n this.cache = new QuotaCache(options?.cacheTtlMs || config.cacheTtlMs)\n\n // Register OAuth sources for all stored accounts\n this.registerOAuthSources()\n }\n\n /**\n * Fetch quota for the active account (or all accounts)\n */\n async fetchQuota(options?: {\n source?: DataSource\n refresh?: boolean\n allAccounts?: boolean\n }): Promise<QuotaSnapshot | QuotaSnapshot[]> {\n if (options?.allAccounts) {\n return this.fetchAllAccounts(options)\n }\n\n // Check cache first (unless refresh requested)\n if (!options?.refresh) {\n // We need the email from any cached entry\n // For now, just try the fetch directly\n }\n\n const snapshot = await this.registry.fetchQuota(options?.source)\n\n // Store in cache and history\n if (snapshot.email) {\n this.cache.set(snapshot.email, snapshot.method, snapshot)\n storeSnapshot(snapshot)\n }\n\n return snapshot\n }\n\n /**\n * Fetch quota for all stored accounts\n */\n private async fetchAllAccounts(options?: {\n source?: DataSource\n refresh?: boolean\n }): Promise<QuotaSnapshot[]> {\n const tokens = getAllAccountTokens()\n const snapshots: QuotaSnapshot[] = []\n\n // Fetch active account via normal registry\n try {\n const snapshot = await this.registry.fetchQuota(options?.source)\n snapshots.push(snapshot)\n } catch (err) {\n debug('quota', `Active account fetch failed: ${err}`)\n }\n\n // Fetch other accounts via their OAuth tokens\n for (const token of tokens) {\n if (!token.email) continue\n // Skip if we already have this email\n if (snapshots.some(s => s.email === token.email)) continue\n\n try {\n const client = new OAuthClient(token)\n const source = new OAuthSource(client)\n const snapshot = await source.fetchQuota()\n snapshots.push(snapshot)\n } catch (err) {\n debug('quota', `Failed to fetch for ${token.email}: ${err}`)\n }\n }\n\n return snapshots\n }\n\n /**\n * Get the full dashboard data for all accounts\n */\n async getFullDashboard(): Promise<{\n snapshots: QuotaSnapshot[]\n history: Record<string, UsageRecord[]>\n dailySummary: Record<string, ReturnType<typeof getDailySummary>>\n }> {\n const snapshots = await this.fetchAllAccounts()\n const history: Record<string, UsageRecord[]> = {}\n const dailySummary: Record<string, ReturnType<typeof getDailySummary>> = {}\n\n for (const snapshot of snapshots) {\n if (!snapshot.email) continue\n history[snapshot.email] = getHistory(snapshot.email, { days: 1, limit: 50 })\n dailySummary[snapshot.email] = getDailySummary(snapshot.email, 7)\n }\n\n return { snapshots, history, dailySummary }\n }\n\n /**\n * Get usage history for an account\n */\n getHistory(email: string, days?: number): UsageRecord[] {\n return getHistory(email, { days })\n }\n\n /**\n * Get daily summary for an account\n */\n getDailySummary(email: string, days?: number) {\n return getDailySummary(email, days)\n }\n\n /**\n * Register OAuth sources for all stored accounts\n */\n private registerOAuthSources(): void {\n const tokens = getAllAccountTokens()\n for (const token of tokens) {\n if (!token.accessToken) continue\n try {\n const client = new OAuthClient(token)\n const source = new OAuthSource(client)\n this.registry.addSource(source)\n debug('quota', `Registered OAuth source for ${token.email}`)\n } catch (err) {\n debug('quota', `Failed to register OAuth for ${token.email}: ${err}`)\n }\n }\n }\n\n /**\n * Get the source registry (for doctor/status checks)\n */\n getRegistry(): SourceRegistry {\n return this.registry\n }\n}\n","/**\n * when-does-my-quota-refresh SDK\n *\n * Core library for fetching and managing Antigravity AI model quotas.\n * Import this for programmatic use in your own tools and extensions.\n *\n * @example\n * ```typescript\n * import { createClient } from 'when-does-my-quota-refresh'\n *\n * const client = createClient()\n * const snapshot = await client.fetchQuota()\n * console.log(snapshot.groups)\n * ```\n */\n\n// Client\nexport { QuotaClient } from './quota.js'\n\n// Types\nexport type {\n QuotaSnapshot,\n QuotaGroup,\n QuotaBucket,\n PromptCreditsInfo,\n DataSource,\n ModelQuotaInfo,\n AccountInfo,\n Plugin,\n UsageRecord,\n ClientOptions,\n} from './types.js'\n\n// Cache\nexport { QuotaCache } from './cache.js'\n\n// Storage\nexport {\n storeSnapshot,\n getHistory,\n getDailySummary,\n getLatestSnapshot,\n cleanupHistory,\n closeStore,\n} from './store.js'\n\n// Accounts\nexport {\n listAccounts,\n setActiveAccount,\n removeAccount,\n getAccountTokens,\n getActiveAccountTokens,\n loginAccount,\n} from './accounts/index.js'\n\n// Sources\nexport { SourceRegistry } from '../sources/index.js'\n\n// Config\nexport { loadConfig, saveConfig, getConfigDirPath, getDataDirPath } from '../core/config.js'\n\n// Errors\nexport {\n SourceUnavailableError,\n AuthError,\n QuotaFetchError,\n} from '../core/errors.js'\n\n// ── Convenience constructor ────────────────────────────────────────\n\nimport type { ClientOptions } from './types.js'\nimport { QuotaClient } from './quota.js'\n\n/**\n * Create a new when-does-my-quota-refresh client\n */\nexport function createClient(options?: ClientOptions): QuotaClient {\n return new QuotaClient(options)\n}\n"],"mappings":"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","names":["exec","promisify","execAsync","statusRaw","https","URL","URL","https","join","join","readFileSync","writeFileSync","existsSync","join","join","existsSync","readFileSync","writeFileSync","http","URL","code"]}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sources/oauth/client.ts","../src/sources/cloud-code-api.ts","../src/sdk/accounts/storage.ts","../src/core/config.ts","../src/core/logger.ts","../src/core/errors.ts","../src/sdk/accounts/auth.ts"],"sourcesContent":["/**\n * Google OAuth client for Cloud Code API\n *\n * Handles the OAuth2 flow for remote quota fetching.\n */\n\nimport https from 'https'\nimport http from 'http'\nimport { URL } from 'url'\nimport { debug } from '../../core/logger.js'\nimport type { OAuthTokenResponse, StoredTokens } from '../../sdk/types.js'\nimport {\n CLOUD_CODE_ENDPOINTS,\n CLOUD_CODE_DEFAULT_BODY,\n OAUTH_CLIENT_ID,\n OAUTH_CLIENT_SECRET,\n OAUTH_SCOPES,\n} from '../cloud-code-api.js'\n\nexport class OAuthClient {\n private tokens: StoredTokens | null = null\n\n constructor(tokens?: StoredTokens) {\n this.tokens = tokens || null\n }\n\n /**\n * Generate the OAuth authorization URL for user login\n */\n getAuthUrl(): string {\n const params = new URLSearchParams({\n client_id: OAUTH_CLIENT_ID,\n redirect_uri: 'http://127.0.0.1:0/callback',\n response_type: 'code',\n scope: OAUTH_SCOPES,\n access_type: 'offline',\n prompt: 'consent',\n })\n return `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`\n }\n\n /**\n * Exchange an authorization code for tokens\n */\n async exchangeCode(code: string): Promise<StoredTokens> {\n const body = new URLSearchParams({\n code,\n client_id: OAUTH_CLIENT_ID,\n client_secret: OAUTH_CLIENT_SECRET,\n redirect_uri: 'http://127.0.0.1:0/callback',\n grant_type: 'authorization_code',\n })\n\n const response = await this.postUrlEncoded('https://oauth2.googleapis.com/token', body)\n const data = response as OAuthTokenResponse\n\n this.tokens = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token || '',\n expiresAt: Date.now() + data.expires_in * 1000,\n }\n\n return this.tokens\n }\n\n /**\n * Refresh the access token\n */\n async refreshAccessToken(): Promise<StoredTokens> {\n if (!this.tokens?.refreshToken) {\n throw new Error('No refresh token available')\n }\n\n const body = new URLSearchParams({\n client_id: OAUTH_CLIENT_ID,\n client_secret: OAUTH_CLIENT_SECRET,\n refresh_token: this.tokens.refreshToken,\n grant_type: 'refresh_token',\n })\n\n const response = await this.postUrlEncoded('https://oauth2.googleapis.com/token', body)\n const data = response as OAuthTokenResponse\n\n this.tokens = {\n ...this.tokens,\n accessToken: data.access_token,\n expiresAt: Date.now() + data.expires_in * 1000,\n }\n\n return this.tokens\n }\n\n /**\n * Get a valid access token, refreshing if necessary\n */\n async getAccessToken(): Promise<string> {\n if (!this.tokens) throw new Error('Not authenticated')\n if (Date.now() >= this.tokens.expiresAt - 60000) {\n await this.refreshAccessToken()\n }\n return this.tokens.accessToken!\n }\n\n /**\n * Get stored tokens\n */\n getTokens(): StoredTokens | null {\n return this.tokens\n }\n\n /**\n * Make an authenticated POST request to the Cloud Code API\n */\n async fetchQuotaSummary(): Promise<unknown> {\n const token = await this.getAccessToken()\n return this.authenticatedPost(\n CLOUD_CODE_ENDPOINTS.retrieveUserQuotaSummary,\n CLOUD_CODE_DEFAULT_BODY,\n token\n )\n }\n\n async fetchUserStatus(): Promise<unknown> {\n const token = await this.getAccessToken()\n return this.authenticatedPost(\n CLOUD_CODE_ENDPOINTS.loadCodeAssist,\n CLOUD_CODE_DEFAULT_BODY,\n token\n )\n }\n\n async fetchAvailableModels(): Promise<unknown> {\n const token = await this.getAccessToken()\n return this.authenticatedPost(\n CLOUD_CODE_ENDPOINTS.fetchAvailableModels,\n CLOUD_CODE_DEFAULT_BODY,\n token\n )\n }\n\n // ── HTTP Helpers ────────────────────────────────────────────────\n\n private authenticatedPost(url: string, body: unknown, token: string): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const parsed = new URL(url)\n const data = JSON.stringify(body)\n const options: http.RequestOptions = {\n hostname: parsed.hostname,\n path: parsed.pathname,\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`,\n 'Content-Length': Buffer.byteLength(data),\n },\n timeout: 10000,\n }\n\n const req = https.request(options, (res) => {\n let responseData = ''\n res.on('data', (chunk: Buffer) => { responseData += chunk })\n res.on('end', () => {\n try {\n resolve(JSON.parse(responseData))\n } catch {\n reject(new Error(`Invalid JSON: ${responseData.slice(0, 200)}`))\n }\n })\n })\n req.on('error', reject)\n req.on('timeout', () => { req.destroy(); reject(new Error('Timeout')) })\n req.write(data)\n req.end()\n })\n }\n\n private postUrlEncoded(url: string, body: URLSearchParams): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const parsed = new URL(url)\n const data = body.toString()\n const options: http.RequestOptions = {\n hostname: parsed.hostname,\n path: parsed.pathname,\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n 'Content-Length': Buffer.byteLength(data),\n },\n timeout: 10000,\n }\n\n const req = https.request(options, (res) => {\n let responseData = ''\n res.on('data', (chunk: Buffer) => { responseData += chunk })\n res.on('end', () => {\n try {\n resolve(JSON.parse(responseData))\n } catch {\n reject(new Error(`Invalid JSON: ${responseData.slice(0, 200)}`))\n }\n })\n })\n req.on('error', reject)\n req.on('timeout', () => { req.destroy(); reject(new Error('Timeout')) })\n req.write(data)\n req.end()\n })\n }\n}\n","/**\n * Google Cloud Code API endpoints for remote quota fetching\n *\n * Used as fallback when local sources are unavailable.\n * Requires OAuth authentication.\n */\n\nexport const CLOUD_CODE_ENDPOINTS = {\n /** Load code assist configuration */\n loadCodeAssist: 'https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist',\n\n /** Onboard a new user */\n onboardUser: 'https://cloudcode-pa.googleapis.com/v1internal:onboardUser',\n\n /** Fetch available models for the account */\n fetchAvailableModels: 'https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels',\n\n /** Fetch raw quota data */\n retrieveUserQuota: 'https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuota',\n\n /** Fetch quota summary with weekly + session buckets */\n retrieveUserQuotaSummary: 'https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuotaSummary',\n} as const\n\nexport const CLOUD_CODE_DEFAULT_BODY = {\n metadata: {\n ideName: 'antigravity',\n extensionName: 'antigravity',\n locale: 'en',\n ideVersion: 'unknown',\n },\n}\n\nexport const OAUTH_CLIENT_ID = '764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com'\nexport const OAUTH_CLIENT_SECRET = 'd-FL95Q19q7MQmFpd7hHD0Ty'\nexport const OAUTH_SCOPES = [\n 'https://www.googleapis.com/auth/cloud-platform',\n 'https://www.googleapis.com/auth/cloudcode',\n].join(' ')\nexport const OAUTH_REDIRECT_URI = 'http://127.0.0.1:0/callback'\n","/**\n * Token storage for account credentials\n *\n * Stores OAuth tokens locally in the config directory.\n * Tokens are stored as plain JSON (local machine only).\n */\n\nimport { readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs'\nimport { join } from 'path'\nimport type { StoredTokens } from '../types.js'\nimport { getConfigDirPath, ensureDirs } from '../../core/config.js'\nimport { debug } from '../../core/logger.js'\n\nconst TOKENS_DIR = 'accounts'\n\ninterface TokenAccount {\n email: string\n tokens: StoredTokens\n addedAt: string\n}\n\ninterface TokenStore {\n accounts: TokenAccount[]\n activeEmail?: string\n}\n\nfunction getStorePath(): string {\n return join(getConfigDirPath(), TOKENS_DIR, 'tokens.json')\n}\n\nfunction loadStore(): TokenStore {\n const path = getStorePath()\n if (!existsSync(path)) return { accounts: [] }\n try {\n return JSON.parse(readFileSync(path, 'utf-8'))\n } catch {\n return { accounts: [] }\n }\n}\n\nfunction saveStore(store: TokenStore): void {\n ensureDirs()\n writeFileSync(getStorePath(), JSON.stringify(store, null, 2))\n debug('account-storage', `Saved ${store.accounts.length} account(s)`)\n}\n\n/**\n * Save tokens for an account\n */\nexport function saveAccountTokens(email: string, tokens: StoredTokens): void {\n const store = loadStore()\n const existing = store.accounts.findIndex(a => a.email === email)\n const account: TokenAccount = {\n email,\n tokens,\n addedAt: new Date().toISOString(),\n }\n\n if (existing >= 0) {\n store.accounts[existing] = account\n } else {\n store.accounts.push(account)\n }\n\n // Set as active if it's the only one\n if (store.accounts.length === 1) {\n store.activeEmail = email\n }\n\n saveStore(store)\n}\n\n/**\n * Get tokens for a specific account\n */\nexport function getAccountTokens(email: string): StoredTokens | null {\n const store = loadStore()\n const account = store.accounts.find(a => a.email === email)\n return account?.tokens || null\n}\n\n/**\n * Get the active account's tokens\n */\nexport function getActiveAccountTokens(): StoredTokens | null {\n const store = loadStore()\n if (!store.activeEmail) return null\n const account = store.accounts.find(a => a.email === store.activeEmail)\n return account?.tokens || null\n}\n\n/**\n * Set the active account\n */\nexport function setActiveAccount(email: string): boolean {\n const store = loadStore()\n if (!store.accounts.find(a => a.email === email)) return false\n store.activeEmail = email\n saveStore(store)\n return true\n}\n\n/**\n * Remove an account\n */\nexport function removeAccount(email: string): boolean {\n const store = loadStore()\n const idx = store.accounts.findIndex(a => a.email === email)\n if (idx < 0) return false\n store.accounts.splice(idx, 1)\n if (store.activeEmail === email) {\n store.activeEmail = store.accounts[0]?.email\n }\n saveStore(store)\n return true\n}\n\n/**\n * List all stored accounts\n */\nexport function listAccounts(): Array<{ email: string; isActive: boolean; addedAt: string }> {\n const store = loadStore()\n return store.accounts.map(a => ({\n email: a.email,\n isActive: a.email === store.activeEmail,\n addedAt: a.addedAt,\n }))\n}\n\n/**\n * Get all stored tokens (for multi-account fetch)\n */\nexport function getAllAccountTokens(): StoredTokens[] {\n const store = loadStore()\n return store.accounts.map(a => a.tokens)\n}\n","/**\n * Config file management — reads/writes app configuration\n */\n\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs'\nimport { join } from 'path'\nimport { homedir } from 'os'\nimport type { AppConfig } from '../sdk/types.js'\nimport { debug } from './logger.js'\n\nconst CONFIG_DIR_NAME = 'when-does-my-quota-refresh'\n\nconst DEFAULT_CONFIG: AppConfig = {\n defaultMode: 'local',\n cacheTtlMs: 5 * 60 * 1000, // 5 minutes\n refreshIntervalMs: 5 * 60 * 1000,\n wakeupModels: ['claude-sonnet-4-5', 'gemini-3-flash', 'gemini-3-pro-low'],\n wakeupAccounts: [],\n notifications: true,\n plugins: [],\n daemon: {\n pollIntervalMs: 60 * 1000,\n enabled: false,\n },\n}\n\nfunction getConfigDir(): string {\n const home = homedir()\n switch (process.platform) {\n case 'darwin':\n return join(home, 'Library', 'Application Support', CONFIG_DIR_NAME)\n case 'win32':\n return join(process.env.APPDATA || join(home, 'AppData', 'Roaming'), CONFIG_DIR_NAME)\n default:\n return join(home, '.config', CONFIG_DIR_NAME)\n }\n}\n\nfunction getConfigPath(): string {\n return join(getConfigDir(), 'config.json')\n}\n\nfunction getDataDir(): string {\n return join(getConfigDir(), 'data')\n}\n\nexport function ensureDirs(): void {\n const configDir = getConfigDir()\n const dataDir = getDataDir()\n if (!existsSync(configDir)) mkdirSync(configDir, { recursive: true })\n if (!existsSync(dataDir)) mkdirSync(dataDir, { recursive: true })\n}\n\nexport function loadConfig(): AppConfig {\n try {\n const path = getConfigPath()\n if (!existsSync(path)) return DEFAULT_CONFIG\n const raw = readFileSync(path, 'utf-8')\n const parsed = JSON.parse(raw)\n debug('config', `Loaded config from ${path}`)\n return { ...DEFAULT_CONFIG, ...parsed }\n } catch (err) {\n debug('config', 'Failed to load config, using defaults', err)\n return DEFAULT_CONFIG\n }\n}\n\nexport function saveConfig(config: AppConfig): void {\n ensureDirs()\n const path = getConfigPath()\n writeFileSync(path, JSON.stringify(config, null, 2))\n debug('config', `Saved config to ${path}`)\n}\n\nexport function getConfigDirPath(): string {\n return getConfigDir()\n}\n\nexport function getDataDirPath(): string {\n return getDataDir()\n}\n\nexport { DEFAULT_CONFIG }\n","/**\n * Simple logger with debug flag\n */\n\nlet _verbose = false\n\nexport function setVerbose(verbose: boolean): void {\n _verbose = verbose\n}\n\nexport function debug(module: string, msg: string, data?: unknown): void {\n if (!_verbose) return\n const prefix = `[${module}]`\n if (data !== undefined) {\n console.error(`${prefix} ${msg}`, data)\n } else {\n console.error(`${prefix} ${msg}`)\n }\n}\n\nexport function info(msg: string): void {\n console.error(msg)\n}\n\nexport function warn(msg: string): void {\n console.error(`⚠ ${msg}`)\n}\n","/**\n * Custom error types for when-does-my-quota-refresh\n */\n\nexport class SourceUnavailableError extends Error {\n constructor(source: string, reason?: string) {\n super(`Source \"${source}\" unavailable${reason ? `: ${reason}` : ''}`)\n this.name = 'SourceUnavailableError'\n }\n}\n\nexport class AuthError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'AuthError'\n }\n}\n\nexport class QuotaFetchError extends Error {\n constructor(source: string, reason?: string) {\n super(`Failed to fetch quota from \"${source}\"${reason ? `: ${reason}` : ''}`)\n this.name = 'QuotaFetchError'\n }\n}\n\nexport class ProcessNotFoundError extends Error {\n constructor() {\n super('Antigravity language server process not found')\n this.name = 'ProcessNotFoundError'\n }\n}\n\nexport class PortDiscoveryError extends Error {\n constructor(pid: number, platform: string) {\n super(`Failed to discover ports for PID ${pid} on ${platform}`)\n this.name = 'PortDiscoveryError'\n }\n}\n","/**\n * OAuth authentication flow for Google accounts\n */\n\nimport { OAuthClient } from '../../sources/oauth/client.js'\nimport { saveAccountTokens, setActiveAccount } from './storage.js'\nimport { debug } from '../../core/logger.js'\nimport { AuthError } from '../../core/errors.js'\nimport open from 'open'\nimport http from 'http'\nimport { URL } from 'url'\n\n/**\n * Start an interactive OAuth login flow\n *\n * Opens the browser for Google login, then captures the redirect\n * to exchange the authorization code for tokens.\n */\nexport async function loginAccount(): Promise<string> {\n const client = new OAuthClient()\n const authUrl = client.getAuthUrl()\n\n debug('auth', 'Starting OAuth login flow')\n\n // Start a temporary local server to catch the redirect\n const code = await new Promise<string>((resolve, reject) => {\n const server = http.createServer(async (req, res) => {\n const url = new URL(req.url || '/', `http://127.0.0.1`)\n const code = url.searchParams.get('code')\n\n if (code) {\n res.writeHead(200, { 'Content-Type': 'text/html' })\n res.end(`\n <html><body style=\"font-family: sans-serif; text-align: center; padding: 50px;\">\n <h1>✅ Login successful!</h1>\n <p>You can close this tab and return to the terminal.</p>\n </body></html>\n `)\n server.close()\n resolve(code)\n } else {\n const error = url.searchParams.get('error')\n if (error) {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n res.end(`<h1>Login failed: ${error}</h1>`)\n server.close()\n reject(new AuthError(`OAuth error: ${error}`))\n } else {\n res.writeHead(404)\n res.end('Waiting for OAuth callback...')\n }\n }\n })\n\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address()\n if (typeof addr === 'object' && addr) {\n // Update redirect URI with actual port\n debug('auth', `Callback server on port ${addr.port}`)\n\n // Open browser\n open(authUrl).catch(() => {\n console.log(`\\nOpen this URL in your browser:\\n\\n${authUrl}\\n`)\n })\n }\n })\n\n // Timeout after 5 minutes\n setTimeout(() => {\n server.close()\n reject(new AuthError('Login timed out after 5 minutes'))\n }, 5 * 60 * 1000)\n })\n\n // Exchange code for tokens\n const tokens = await client.exchangeCode(code)\n\n // Get user email\n const email = tokens.email || 'unknown@gmail.com'\n tokens.email = email\n\n // Store tokens\n saveAccountTokens(email, tokens)\n setActiveAccount(email)\n\n debug('auth', `Logged in as ${email}`)\n return email\n}\n\n/**\n * Perform a manual login (headless/SSH mode)\n * Returns the auth URL for the user to open manually\n */\nexport function getManualLoginUrl(): string {\n const client = new OAuthClient()\n return client.getAuthUrl()\n}\n\n/**\n * Complete manual login with an authorization code\n */\nexport async function completeManualLogin(code: string): Promise<string> {\n const client = new OAuthClient()\n const tokens = await client.exchangeCode(code)\n const email = tokens.email || 'unknown@gmail.com'\n tokens.email = email\n saveAccountTokens(email, tokens)\n setActiveAccount(email)\n return email\n}\n"],"mappings":"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","names":["readFileSync","writeFileSync","existsSync","join","join","existsSync","readFileSync","writeFileSync","URL","code"]}
|
|
File without changes
|