copilot-api-plus 1.0.10 → 1.0.12
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/README.md +14 -6
- package/dist/auth-Cm_0h9bp.js.map +1 -1
- package/dist/get-models-Bbb8B5jI.js.map +1 -1
- package/dist/main.js +841 -523
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -507,11 +507,14 @@ curl http://localhost:4141/v1/messages \
|
|
|
507
507
|
|
|
508
508
|
### logout 命令参数
|
|
509
509
|
|
|
510
|
-
| 参数 | 说明 |
|
|
511
|
-
|
|
512
|
-
| `--
|
|
513
|
-
| `--
|
|
514
|
-
| `--
|
|
510
|
+
| 参数 | 别名 | 说明 |
|
|
511
|
+
|------|------|------|
|
|
512
|
+
| `--github` | `-g` | 仅清除 GitHub Copilot 凭证 |
|
|
513
|
+
| `--zen` | `-z` | 仅清除 Zen 凭证 |
|
|
514
|
+
| `--antigravity` | - | 仅清除 Antigravity 凭证 |
|
|
515
|
+
| `--all` | `-a` | 清除所有凭证 |
|
|
516
|
+
|
|
517
|
+
> **提示**:不带参数运行 `logout` 会显示交互式菜单供选择。
|
|
515
518
|
|
|
516
519
|
---
|
|
517
520
|
|
|
@@ -582,9 +585,14 @@ docker run -p 4141:4141 \
|
|
|
582
585
|
### 切换账户
|
|
583
586
|
|
|
584
587
|
```bash
|
|
585
|
-
#
|
|
588
|
+
# 交互式选择要清除的凭证
|
|
586
589
|
npx copilot-api-plus@latest logout
|
|
587
590
|
|
|
591
|
+
# 仅清除 GitHub Copilot 凭证
|
|
592
|
+
npx copilot-api-plus@latest logout --github
|
|
593
|
+
# 或简写
|
|
594
|
+
npx copilot-api-plus@latest logout -g
|
|
595
|
+
|
|
588
596
|
# 清除 Zen 凭证
|
|
589
597
|
npx copilot-api-plus@latest logout --zen
|
|
590
598
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-Cm_0h9bp.js","names":[],"sources":["../src/services/antigravity/auth.ts"],"sourcesContent":["/**\n * Google Antigravity Authentication\n *\n * Handles OAuth token management for Google Antigravity API.\n * Supports multiple accounts with auto-rotation and token refresh.\n */\n\nimport consola from \"consola\"\n\nimport { PATHS, ensurePaths } from \"~/lib/paths\"\n\nexport interface AntigravityAccount {\n access_token: string\n refresh_token: string\n expires_in: number\n timestamp: number\n enable: boolean\n project_id?: string\n}\n\nexport interface AntigravityAuth {\n accounts: Array<AntigravityAccount>\n currentIndex: number\n}\n\nconst ANTIGRAVITY_AUTH_FILENAME = \"antigravity-accounts.json\"\n\n// Google OAuth credentials\n// These are the same public credentials used by antigravity2api-nodejs\n// These are public OAuth client credentials embedded in the official Antigravity client\n// Obfuscated to avoid false positives from secret scanners\nconst _d = (s: string) => s.split(\"\").map((c, i) => String.fromCharCode(c.charCodeAt(0) - (i % 3))).join(\"\")\nconst GOOGLE_CLIENT_ID =\n process.env.ANTIGRAVITY_CLIENT_ID ||\n _d(\"9582:895427;-f:rdlg48v5nguqv4ivc9mfl1k5sl:c87.brpt0gpqgmgutgrdqnugnu0cpo\")\nconst GOOGLE_CLIENT_SECRET =\n process.env.ANTIGRAVITY_CLIENT_SECRET ||\n _d(\"GPESQZ-9fPsMZCyYWHD69k1lfXtn3ek8MCo\")\nconst GOOGLE_REDIRECT_URI = \"http://localhost:8046/callback\"\n\n/**\n * Get the path to the Antigravity auth file\n */\nexport function getAntigravityAuthPath(): string {\n return `${PATHS.DATA_DIR}/${ANTIGRAVITY_AUTH_FILENAME}`\n}\n\n/**\n * Save Antigravity accounts to file\n */\nexport async function saveAntigravityAuth(\n auth: AntigravityAuth,\n): Promise<void> {\n await ensurePaths()\n const authPath = getAntigravityAuthPath()\n await Bun.write(authPath, JSON.stringify(auth, null, 2))\n consola.success(\"Antigravity accounts saved to\", authPath)\n}\n\n/**\n * Load Antigravity accounts from file\n */\nexport async function loadAntigravityAuth(): Promise<AntigravityAuth | null> {\n try {\n const authPath = getAntigravityAuthPath()\n const file = Bun.file(authPath)\n\n if (!(await file.exists())) {\n return null\n }\n\n const content = await file.text()\n const data = JSON.parse(content)\n\n // Handle both array format (legacy) and object format\n if (Array.isArray(data)) {\n return {\n accounts: data,\n currentIndex: 0,\n }\n }\n\n return data as AntigravityAuth\n } catch {\n return null\n }\n}\n\n/**\n * Clear Antigravity accounts\n */\nexport async function clearAntigravityAuth(): Promise<void> {\n try {\n const authPath = getAntigravityAuthPath()\n const fs = await import(\"node:fs/promises\")\n await fs.unlink(authPath)\n consola.success(\"Antigravity accounts cleared\")\n } catch {\n // File might not exist, ignore\n }\n}\n\n/**\n * Add a new account to Antigravity auth\n */\nexport async function addAntigravityAccount(\n account: AntigravityAccount,\n): Promise<void> {\n let auth = await loadAntigravityAuth()\n\n if (!auth) {\n auth = {\n accounts: [],\n currentIndex: 0,\n }\n }\n\n auth.accounts.push(account)\n await saveAntigravityAuth(auth)\n consola.success(\"Added new Antigravity account\")\n}\n\n/**\n * Get the current active account\n */\nexport async function getCurrentAccount(): Promise<AntigravityAccount | null> {\n const auth = await loadAntigravityAuth()\n\n if (!auth || auth.accounts.length === 0) {\n return null\n }\n\n // Find enabled account starting from current index\n const enabledAccounts = auth.accounts.filter((a) => a.enable)\n\n if (enabledAccounts.length === 0) {\n return null\n }\n\n // Get current account or first enabled one\n const currentAccount = auth.accounts[auth.currentIndex]\n if (currentAccount && currentAccount.enable) {\n return currentAccount\n }\n\n return enabledAccounts[0]\n}\n\n/**\n * Rotate to the next account\n */\nexport async function rotateAccount(): Promise<void> {\n const auth = await loadAntigravityAuth()\n\n if (!auth || auth.accounts.length <= 1) {\n return\n }\n\n // Find next enabled account\n let nextIndex = (auth.currentIndex + 1) % auth.accounts.length\n let attempts = 0\n\n while (!auth.accounts[nextIndex].enable && attempts < auth.accounts.length) {\n nextIndex = (nextIndex + 1) % auth.accounts.length\n attempts++\n }\n\n auth.currentIndex = nextIndex\n await saveAntigravityAuth(auth)\n consola.info(`Rotated to account ${nextIndex}`)\n}\n\n/**\n * Disable current account\n */\nexport async function disableCurrentAccount(): Promise<void> {\n const auth = await loadAntigravityAuth()\n\n if (!auth || auth.accounts.length === 0) {\n return\n }\n\n auth.accounts[auth.currentIndex].enable = false\n await saveAntigravityAuth(auth)\n consola.warn(`Disabled account ${auth.currentIndex}`)\n\n // Rotate to next account\n await rotateAccount()\n}\n\n/**\n * Refresh access token using refresh token\n */\nexport async function refreshAccessToken(\n account: AntigravityAccount,\n): Promise<AntigravityAccount | null> {\n try {\n const response = await fetch(\"https://oauth2.googleapis.com/token\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: new URLSearchParams({\n client_id: GOOGLE_CLIENT_ID,\n client_secret: GOOGLE_CLIENT_SECRET,\n refresh_token: account.refresh_token,\n grant_type: \"refresh_token\",\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n consola.error(\"Token refresh failed:\", error)\n return null\n }\n\n const data = (await response.json()) as {\n access_token: string\n expires_in: number\n }\n\n return {\n ...account,\n access_token: data.access_token,\n expires_in: data.expires_in,\n timestamp: Date.now(),\n }\n } catch (error) {\n consola.error(\"Token refresh error:\", error)\n return null\n }\n}\n\n/**\n * Check if token is expired\n */\nexport function isTokenExpired(account: AntigravityAccount): boolean {\n const expirationTime = account.timestamp + account.expires_in * 1000\n // Refresh 5 minutes before expiration\n return Date.now() > expirationTime - 5 * 60 * 1000\n}\n\n/**\n * Get valid access token, refreshing if needed\n */\nexport async function getValidAccessToken(): Promise<string | null> {\n const auth = await loadAntigravityAuth()\n\n if (!auth || auth.accounts.length === 0) {\n return null\n }\n\n let account = auth.accounts[auth.currentIndex]\n\n if (!account || !account.enable) {\n const enabledAccount = auth.accounts.find((a) => a.enable)\n if (!enabledAccount) {\n return null\n }\n account = enabledAccount\n }\n\n // Check if token needs refresh\n if (isTokenExpired(account)) {\n consola.info(\"Access token expired, refreshing...\")\n const refreshedAccount = await refreshAccessToken(account)\n\n if (!refreshedAccount) {\n consola.error(\"Token refresh failed, disabling account\")\n await disableCurrentAccount()\n return getValidAccessToken() // Try next account\n }\n\n // Update account in storage\n auth.accounts[auth.currentIndex] = refreshedAccount\n await saveAntigravityAuth(auth)\n\n return refreshedAccount.access_token\n }\n\n return account.access_token\n}\n\n/**\n * Generate a random project ID for Pro accounts\n */\nexport function generateRandomProjectId(): string {\n const chars = \"0123456789\"\n let projectId = \"\"\n for (let i = 0; i < 12; i++) {\n projectId += chars.charAt(Math.floor(Math.random() * chars.length))\n }\n return projectId\n}\n\n/**\n * Get OAuth authorization URL\n */\nexport function getOAuthUrl(): string {\n const params = new URLSearchParams({\n client_id: GOOGLE_CLIENT_ID,\n redirect_uri: GOOGLE_REDIRECT_URI,\n response_type: \"code\",\n scope: \"openid email profile\",\n access_type: \"offline\",\n prompt: \"consent\",\n })\n\n return `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`\n}\n\n/**\n * Exchange authorization code for tokens\n */\nexport async function exchangeCodeForTokens(\n code: string,\n): Promise<AntigravityAccount | null> {\n try {\n const response = await fetch(\"https://oauth2.googleapis.com/token\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: new URLSearchParams({\n client_id: GOOGLE_CLIENT_ID,\n client_secret: GOOGLE_CLIENT_SECRET,\n code,\n redirect_uri: GOOGLE_REDIRECT_URI,\n grant_type: \"authorization_code\",\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n consola.error(\"Token exchange failed:\", error)\n return null\n }\n\n const data = (await response.json()) as {\n access_token: string\n refresh_token: string\n expires_in: number\n }\n\n return {\n access_token: data.access_token,\n refresh_token: data.refresh_token,\n expires_in: data.expires_in,\n timestamp: Date.now(),\n enable: true,\n project_id: generateRandomProjectId(),\n }\n } catch (error) {\n consola.error(\"Token exchange error:\", error)\n return null\n }\n}\n\n/**\n * Setup Antigravity interactively\n */\nexport async function setupAntigravity(): Promise<void> {\n const auth = await loadAntigravityAuth()\n\n if (auth && auth.accounts.length > 0) {\n const enabledCount = auth.accounts.filter((a) => a.enable).length\n consola.info(\n `Found ${auth.accounts.length} Antigravity accounts (${enabledCount} enabled)`,\n )\n\n const addMore = await consola.prompt(\"Add another account?\", {\n type: \"confirm\",\n initial: false,\n })\n\n if (!addMore) {\n return\n }\n }\n\n consola.info(\"\")\n consola.info(\"Google Antigravity OAuth Setup\")\n consola.info(\"==============================\")\n consola.info(\"\")\n consola.info(\"You need to authorize with Google to use Antigravity API.\")\n consola.info(\"Please follow these steps:\")\n consola.info(\"\")\n consola.info(\"1. Open this URL in your browser:\")\n consola.info(` ${getOAuthUrl()}`)\n consola.info(\"\")\n consola.info(\"2. Complete the Google sign-in process\")\n consola.info(\"3. After authorization, you'll be redirected to a callback URL\")\n consola.info(\"4. Copy the full callback URL and paste it below\")\n consola.info(\"\")\n\n const callbackUrl = await consola.prompt(\"Enter the callback URL:\", {\n type: \"text\",\n })\n\n if (!callbackUrl || typeof callbackUrl !== \"string\") {\n throw new Error(\"Callback URL is required\")\n }\n\n // Extract code from callback URL\n const url = new URL(callbackUrl)\n const code = url.searchParams.get(\"code\")\n\n if (!code) {\n throw new Error(\"Authorization code not found in URL\")\n }\n\n consola.info(\"Exchanging authorization code for tokens...\")\n\n const account = await exchangeCodeForTokens(code)\n\n if (!account) {\n throw new Error(\"Failed to exchange authorization code\")\n }\n\n await addAntigravityAccount(account)\n consola.success(\"Antigravity account added successfully!\")\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auth-Cm_0h9bp.js","names":[],"sources":["../src/services/antigravity/auth.ts"],"sourcesContent":["/**\n * Google Antigravity Authentication\n *\n * Handles OAuth token management for Google Antigravity API.\n * Supports multiple accounts with auto-rotation and token refresh.\n */\n\n/* eslint-disable unicorn/prefer-code-point */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unnecessary-condition */\n\nimport consola from \"consola\"\n\nimport { PATHS, ensurePaths } from \"~/lib/paths\"\n\nexport interface AntigravityAccount {\n access_token: string\n refresh_token: string\n expires_in: number\n timestamp: number\n enable: boolean\n project_id?: string\n}\n\nexport interface AntigravityAuth {\n accounts: Array<AntigravityAccount>\n currentIndex: number\n}\n\nconst ANTIGRAVITY_AUTH_FILENAME = \"antigravity-accounts.json\"\n\n// Google OAuth credentials\n// These are the same public credentials used by antigravity2api-nodejs\n// These are public OAuth client credentials embedded in the official Antigravity client\n// Obfuscated to avoid false positives from secret scanners\nconst _d = (s: string) =>\n s\n .split(\"\")\n .map((c, i) => String.fromCharCode(c.charCodeAt(0) - (i % 3)))\n .join(\"\")\nconst GOOGLE_CLIENT_ID =\n process.env.ANTIGRAVITY_CLIENT_ID\n || _d(\n \"9582:895427;-f:rdlg48v5nguqv4ivc9mfl1k5sl:c87.brpt0gpqgmgutgrdqnugnu0cpo\",\n )\nconst GOOGLE_CLIENT_SECRET =\n process.env.ANTIGRAVITY_CLIENT_SECRET\n || _d(\"GPESQZ-9fPsMZCyYWHD69k1lfXtn3ek8MCo\")\nconst GOOGLE_REDIRECT_URI = \"http://localhost:8046/callback\"\n\n/**\n * Get the path to the Antigravity auth file\n */\nexport function getAntigravityAuthPath(): string {\n return `${PATHS.DATA_DIR}/${ANTIGRAVITY_AUTH_FILENAME}`\n}\n\n/**\n * Save Antigravity accounts to file\n */\nexport async function saveAntigravityAuth(\n auth: AntigravityAuth,\n): Promise<void> {\n await ensurePaths()\n const authPath = getAntigravityAuthPath()\n await Bun.write(authPath, JSON.stringify(auth, null, 2))\n consola.success(\"Antigravity accounts saved to\", authPath)\n}\n\n/**\n * Load Antigravity accounts from file\n */\nexport async function loadAntigravityAuth(): Promise<AntigravityAuth | null> {\n try {\n const authPath = getAntigravityAuthPath()\n const file = Bun.file(authPath)\n\n if (!(await file.exists())) {\n return null\n }\n\n const content = await file.text()\n const data = JSON.parse(content)\n\n // Handle both array format (legacy) and object format\n if (Array.isArray(data)) {\n return {\n accounts: data,\n currentIndex: 0,\n }\n }\n\n return data as AntigravityAuth\n } catch {\n return null\n }\n}\n\n/**\n * Clear Antigravity accounts\n */\nexport async function clearAntigravityAuth(): Promise<void> {\n try {\n const authPath = getAntigravityAuthPath()\n const fs = await import(\"node:fs/promises\")\n await fs.unlink(authPath)\n consola.success(\"Antigravity accounts cleared\")\n } catch {\n // File might not exist, ignore\n }\n}\n\n/**\n * Add a new account to Antigravity auth\n */\nexport async function addAntigravityAccount(\n account: AntigravityAccount,\n): Promise<void> {\n let auth = await loadAntigravityAuth()\n\n if (!auth) {\n auth = {\n accounts: [],\n currentIndex: 0,\n }\n }\n\n auth.accounts.push(account)\n await saveAntigravityAuth(auth)\n consola.success(\"Added new Antigravity account\")\n}\n\n/**\n * Get the current active account\n */\nexport async function getCurrentAccount(): Promise<AntigravityAccount | null> {\n const auth = await loadAntigravityAuth()\n\n if (!auth || auth.accounts.length === 0) {\n return null\n }\n\n // Find enabled account starting from current index\n const enabledAccounts = auth.accounts.filter((a) => a.enable)\n\n if (enabledAccounts.length === 0) {\n return null\n }\n\n // Get current account or first enabled one\n const currentAccount = auth.accounts[auth.currentIndex]\n if (currentAccount && currentAccount.enable) {\n return currentAccount\n }\n\n return enabledAccounts[0]\n}\n\n/**\n * Rotate to the next account\n */\nexport async function rotateAccount(): Promise<void> {\n const auth = await loadAntigravityAuth()\n\n if (!auth || auth.accounts.length <= 1) {\n return\n }\n\n // Find next enabled account\n let nextIndex = (auth.currentIndex + 1) % auth.accounts.length\n let attempts = 0\n\n while (!auth.accounts[nextIndex].enable && attempts < auth.accounts.length) {\n nextIndex = (nextIndex + 1) % auth.accounts.length\n attempts++\n }\n\n auth.currentIndex = nextIndex\n await saveAntigravityAuth(auth)\n consola.info(`Rotated to account ${nextIndex}`)\n}\n\n/**\n * Disable current account\n */\nexport async function disableCurrentAccount(): Promise<void> {\n const auth = await loadAntigravityAuth()\n\n if (!auth || auth.accounts.length === 0) {\n return\n }\n\n auth.accounts[auth.currentIndex].enable = false\n await saveAntigravityAuth(auth)\n consola.warn(`Disabled account ${auth.currentIndex}`)\n\n // Rotate to next account\n await rotateAccount()\n}\n\n/**\n * Refresh access token using refresh token\n */\nexport async function refreshAccessToken(\n account: AntigravityAccount,\n): Promise<AntigravityAccount | null> {\n try {\n const response = await fetch(\"https://oauth2.googleapis.com/token\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: new URLSearchParams({\n client_id: GOOGLE_CLIENT_ID,\n client_secret: GOOGLE_CLIENT_SECRET,\n refresh_token: account.refresh_token,\n grant_type: \"refresh_token\",\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n consola.error(\"Token refresh failed:\", error)\n return null\n }\n\n const data = (await response.json()) as {\n access_token: string\n expires_in: number\n }\n\n return {\n ...account,\n access_token: data.access_token,\n expires_in: data.expires_in,\n timestamp: Date.now(),\n }\n } catch (error) {\n consola.error(\"Token refresh error:\", error)\n return null\n }\n}\n\n/**\n * Check if token is expired\n */\nexport function isTokenExpired(account: AntigravityAccount): boolean {\n const expirationTime = account.timestamp + account.expires_in * 1000\n // Refresh 5 minutes before expiration\n return Date.now() > expirationTime - 5 * 60 * 1000\n}\n\n/**\n * Get valid access token, refreshing if needed\n */\nexport async function getValidAccessToken(): Promise<string | null> {\n const auth = await loadAntigravityAuth()\n\n if (!auth || auth.accounts.length === 0) {\n return null\n }\n\n let account = auth.accounts[auth.currentIndex]\n\n if (!account || !account.enable) {\n const enabledAccount = auth.accounts.find((a) => a.enable)\n if (!enabledAccount) {\n return null\n }\n account = enabledAccount\n }\n\n // Check if token needs refresh\n if (isTokenExpired(account)) {\n consola.info(\"Access token expired, refreshing...\")\n const refreshedAccount = await refreshAccessToken(account)\n\n if (!refreshedAccount) {\n consola.error(\"Token refresh failed, disabling account\")\n await disableCurrentAccount()\n return getValidAccessToken() // Try next account\n }\n\n // Update account in storage\n auth.accounts[auth.currentIndex] = refreshedAccount\n await saveAntigravityAuth(auth)\n\n return refreshedAccount.access_token\n }\n\n return account.access_token\n}\n\n/**\n * Generate a random project ID for Pro accounts\n */\nexport function generateRandomProjectId(): string {\n const chars = \"0123456789\"\n let projectId = \"\"\n for (let i = 0; i < 12; i++) {\n projectId += chars.charAt(Math.floor(Math.random() * chars.length))\n }\n return projectId\n}\n\n/**\n * Get OAuth authorization URL\n */\nexport function getOAuthUrl(): string {\n const params = new URLSearchParams({\n client_id: GOOGLE_CLIENT_ID,\n redirect_uri: GOOGLE_REDIRECT_URI,\n response_type: \"code\",\n scope: \"openid email profile\",\n access_type: \"offline\",\n prompt: \"consent\",\n })\n\n return `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`\n}\n\n/**\n * Exchange authorization code for tokens\n */\nexport async function exchangeCodeForTokens(\n code: string,\n): Promise<AntigravityAccount | null> {\n try {\n const response = await fetch(\"https://oauth2.googleapis.com/token\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: new URLSearchParams({\n client_id: GOOGLE_CLIENT_ID,\n client_secret: GOOGLE_CLIENT_SECRET,\n code,\n redirect_uri: GOOGLE_REDIRECT_URI,\n grant_type: \"authorization_code\",\n }),\n })\n\n if (!response.ok) {\n const error = await response.text()\n consola.error(\"Token exchange failed:\", error)\n return null\n }\n\n const data = (await response.json()) as {\n access_token: string\n refresh_token: string\n expires_in: number\n }\n\n return {\n access_token: data.access_token,\n refresh_token: data.refresh_token,\n expires_in: data.expires_in,\n timestamp: Date.now(),\n enable: true,\n project_id: generateRandomProjectId(),\n }\n } catch (error) {\n consola.error(\"Token exchange error:\", error)\n return null\n }\n}\n\n/**\n * Setup Antigravity interactively\n */\nexport async function setupAntigravity(): Promise<void> {\n const auth = await loadAntigravityAuth()\n\n if (auth && auth.accounts.length > 0) {\n const enabledCount = auth.accounts.filter((a) => a.enable).length\n consola.info(\n `Found ${auth.accounts.length} Antigravity accounts (${enabledCount} enabled)`,\n )\n\n const addMore = await consola.prompt(\"Add another account?\", {\n type: \"confirm\",\n initial: false,\n })\n\n if (!addMore) {\n return\n }\n }\n\n consola.info(\"\")\n consola.info(\"Google Antigravity OAuth Setup\")\n consola.info(\"==============================\")\n consola.info(\"\")\n consola.info(\"You need to authorize with Google to use Antigravity API.\")\n consola.info(\"Please follow these steps:\")\n consola.info(\"\")\n consola.info(\"1. Open this URL in your browser:\")\n consola.info(` ${getOAuthUrl()}`)\n consola.info(\"\")\n consola.info(\"2. Complete the Google sign-in process\")\n consola.info(\"3. After authorization, you'll be redirected to a callback URL\")\n consola.info(\"4. Copy the full callback URL and paste it below\")\n consola.info(\"\")\n\n const callbackUrl = await consola.prompt(\"Enter the callback URL:\", {\n type: \"text\",\n })\n\n if (!callbackUrl || typeof callbackUrl !== \"string\") {\n throw new Error(\"Callback URL is required\")\n }\n\n // Extract code from callback URL\n const url = new URL(callbackUrl)\n const code = url.searchParams.get(\"code\")\n\n if (!code) {\n throw new Error(\"Authorization code not found in URL\")\n }\n\n consola.info(\"Exchanging authorization code for tokens...\")\n\n const account = await exchangeCodeForTokens(code)\n\n if (!account) {\n throw new Error(\"Failed to exchange authorization code\")\n }\n\n await addAntigravityAccount(account)\n consola.success(\"Antigravity account added successfully!\")\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-models-Bbb8B5jI.js","names":["FALLBACK_MODELS: Array<AntigravityModel>","cachedModels: Array<AntigravityModel> | null","cacheTimestamp: number","models: Array<AntigravityModel>"],"sources":["../src/services/antigravity/get-models.ts"],"sourcesContent":["/**\n * Google Antigravity Models\n *\n * Provides list of available models from Antigravity.\n * Based on: https://github.com/liuw1535/antigravity2api-nodejs\n */\n\nimport consola from \"consola\"\n\nimport { getValidAccessToken } from \"./auth\"\n\n// Antigravity API endpoints\nconst ANTIGRAVITY_API_HOST = \"daily-cloudcode-pa.sandbox.googleapis.com\"\nconst ANTIGRAVITY_MODELS_URL = `https://${ANTIGRAVITY_API_HOST}/v1internal:fetchAvailableModels`\nconst ANTIGRAVITY_USER_AGENT = \"antigravity/1.11.3 windows/amd64\"\n\nexport interface AntigravityModel {\n id: string\n object: string\n created: number\n owned_by: string\n}\n\nexport interface AntigravityModelsResponse {\n object: string\n data: Array<AntigravityModel>\n}\n\n/**\n * Fallback Antigravity models when API is unavailable\n * Based on antigravity2api-nodejs model list\n */\nconst FALLBACK_MODELS: Array<AntigravityModel> = [\n // Gemini models\n {\n id: \"gemini-2.5-pro-exp-03-25\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.5-pro-preview-05-06\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.0-flash-exp\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.0-flash-001\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.0-flash-thinking-exp-1219\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.0-flash-thinking-exp\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.0-flash-thinking-exp-01-21\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.0-pro-exp-02-05\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-1.5-pro\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-1.5-flash\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-1.5-flash-8b\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-exp-1206\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"learnlm-1.5-pro-experimental\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n\n // Claude models (via Antigravity)\n {\n id: \"claude-opus-4-5\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n {\n id: \"claude-sonnet-4-5\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n {\n id: \"claude-3-5-sonnet-20241022\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n {\n id: \"claude-3-5-haiku-20241022\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n {\n id: \"claude-3-opus-20240229\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n {\n id: \"claude-3-sonnet-20240229\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n {\n id: \"claude-3-haiku-20240307\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n]\n\n// Cache for fetched models\nlet cachedModels: Array<AntigravityModel> | null = null\nlet cacheTimestamp: number = 0\nconst CACHE_TTL = 5 * 60 * 1000 // 5 minutes\n\n/**\n * Fetch models from Antigravity API\n */\nasync function fetchModelsFromApi(): Promise<Array<AntigravityModel> | null> {\n const accessToken = await getValidAccessToken()\n\n if (!accessToken) {\n consola.debug(\"No access token available, using fallback models\")\n return null\n }\n\n try {\n const response = await fetch(ANTIGRAVITY_MODELS_URL, {\n method: \"POST\",\n headers: {\n Host: ANTIGRAVITY_API_HOST,\n \"User-Agent\": ANTIGRAVITY_USER_AGENT,\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n \"Accept-Encoding\": \"gzip\",\n },\n body: JSON.stringify({}),\n })\n\n if (!response.ok) {\n consola.warn(`Failed to fetch Antigravity models: ${response.status}`)\n return null\n }\n\n const data = (await response.json()) as {\n models?: Array<{\n name: string\n quotaInfo?: {\n remainingFraction?: number\n resetTime?: string\n }\n }>\n }\n\n if (!data.models || !Array.isArray(data.models)) {\n return null\n }\n\n // Convert to OpenAI format\n const models: Array<AntigravityModel> = data.models\n .filter((m) => {\n // Filter out models with no remaining quota\n const remaining = m.quotaInfo?.remainingFraction ?? 1\n return remaining > 0\n })\n .map((m) => {\n // Extract model ID from name (e.g., \"models/gemini-2.0-flash\" -> \"gemini-2.0-flash\")\n const modelId = m.name.replace(\"models/\", \"\")\n const isGoogle =\n modelId.startsWith(\"gemini\") || modelId.startsWith(\"learnlm\")\n\n return {\n id: modelId,\n object: \"model\",\n created: 1700000000,\n owned_by: isGoogle ? \"google\" : \"anthropic\",\n }\n })\n\n consola.debug(`Fetched ${models.length} models from Antigravity API`)\n return models\n } catch (error) {\n consola.warn(\"Error fetching Antigravity models:\", error)\n return null\n }\n}\n\n/**\n * Get available Antigravity models\n */\nexport async function getAntigravityModels(): Promise<AntigravityModelsResponse> {\n // Check cache\n if (cachedModels && Date.now() - cacheTimestamp < CACHE_TTL) {\n consola.debug(`Returning ${cachedModels.length} cached Antigravity models`)\n return {\n object: \"list\",\n data: cachedModels,\n }\n }\n\n // Try to fetch from API\n const apiModels = await fetchModelsFromApi()\n\n if (apiModels && apiModels.length > 0) {\n cachedModels = apiModels\n cacheTimestamp = Date.now()\n\n return {\n object: \"list\",\n data: apiModels,\n }\n }\n\n // Use fallback models\n consola.debug(\n `Returning ${FALLBACK_MODELS.length} fallback Antigravity models`,\n )\n\n return {\n object: \"list\",\n data: FALLBACK_MODELS,\n }\n}\n\n/**\n * Check if a model is a Claude model\n */\nexport function isClaudeModel(modelId: string): boolean {\n return modelId.startsWith(\"claude-\")\n}\n\n/**\n * Check if a model is a thinking/reasoning model\n */\nexport function isThinkingModel(modelId: string): boolean {\n return modelId.includes(\"thinking\")\n}\n\n/**\n * Check if a model is an image generation model\n */\nexport function isImageModel(modelId: string): boolean {\n return modelId.includes(\"image\")\n}\n"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"get-models-Bbb8B5jI.js","names":["FALLBACK_MODELS: Array<AntigravityModel>","cachedModels: Array<AntigravityModel> | null","cacheTimestamp: number","models: Array<AntigravityModel>"],"sources":["../src/services/antigravity/get-models.ts"],"sourcesContent":["/**\n * Google Antigravity Models\n *\n * Provides list of available models from Antigravity.\n * Based on: https://github.com/liuw1535/antigravity2api-nodejs\n */\n\n/* eslint-disable require-atomic-updates */\n\nimport consola from \"consola\"\n\nimport { getValidAccessToken } from \"./auth\"\n\n// Antigravity API endpoints\nconst ANTIGRAVITY_API_HOST = \"daily-cloudcode-pa.sandbox.googleapis.com\"\nconst ANTIGRAVITY_MODELS_URL = `https://${ANTIGRAVITY_API_HOST}/v1internal:fetchAvailableModels`\nconst ANTIGRAVITY_USER_AGENT = \"antigravity/1.11.3 windows/amd64\"\n\nexport interface AntigravityModel {\n id: string\n object: string\n created: number\n owned_by: string\n}\n\nexport interface AntigravityModelsResponse {\n object: string\n data: Array<AntigravityModel>\n}\n\n/**\n * Fallback Antigravity models when API is unavailable\n * Based on antigravity2api-nodejs model list\n */\nconst FALLBACK_MODELS: Array<AntigravityModel> = [\n // Gemini models\n {\n id: \"gemini-2.5-pro-exp-03-25\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.5-pro-preview-05-06\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.0-flash-exp\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.0-flash-001\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.0-flash-thinking-exp-1219\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.0-flash-thinking-exp\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.0-flash-thinking-exp-01-21\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.0-pro-exp-02-05\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-1.5-pro\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-1.5-flash\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-1.5-flash-8b\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-exp-1206\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"learnlm-1.5-pro-experimental\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n\n // Claude models (via Antigravity)\n {\n id: \"claude-opus-4-5\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n {\n id: \"claude-sonnet-4-5\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n {\n id: \"claude-3-5-sonnet-20241022\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n {\n id: \"claude-3-5-haiku-20241022\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n {\n id: \"claude-3-opus-20240229\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n {\n id: \"claude-3-sonnet-20240229\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n {\n id: \"claude-3-haiku-20240307\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n]\n\n// Cache for fetched models\nlet cachedModels: Array<AntigravityModel> | null = null\nlet cacheTimestamp: number = 0\nconst CACHE_TTL = 5 * 60 * 1000 // 5 minutes\n\n/**\n * Fetch models from Antigravity API\n */\nasync function fetchModelsFromApi(): Promise<Array<AntigravityModel> | null> {\n const accessToken = await getValidAccessToken()\n\n if (!accessToken) {\n consola.debug(\"No access token available, using fallback models\")\n return null\n }\n\n try {\n const response = await fetch(ANTIGRAVITY_MODELS_URL, {\n method: \"POST\",\n headers: {\n Host: ANTIGRAVITY_API_HOST,\n \"User-Agent\": ANTIGRAVITY_USER_AGENT,\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n \"Accept-Encoding\": \"gzip\",\n },\n body: JSON.stringify({}),\n })\n\n if (!response.ok) {\n consola.warn(`Failed to fetch Antigravity models: ${response.status}`)\n return null\n }\n\n const data = (await response.json()) as {\n models?: Array<{\n name: string\n quotaInfo?: {\n remainingFraction?: number\n resetTime?: string\n }\n }>\n }\n\n if (!data.models || !Array.isArray(data.models)) {\n return null\n }\n\n // Convert to OpenAI format\n const models: Array<AntigravityModel> = data.models\n .filter((m) => {\n // Filter out models with no remaining quota\n const remaining = m.quotaInfo?.remainingFraction ?? 1\n return remaining > 0\n })\n .map((m) => {\n // Extract model ID from name (e.g., \"models/gemini-2.0-flash\" -> \"gemini-2.0-flash\")\n const modelId = m.name.replace(\"models/\", \"\")\n const isGoogle =\n modelId.startsWith(\"gemini\") || modelId.startsWith(\"learnlm\")\n\n return {\n id: modelId,\n object: \"model\",\n created: 1700000000,\n owned_by: isGoogle ? \"google\" : \"anthropic\",\n }\n })\n\n consola.debug(`Fetched ${models.length} models from Antigravity API`)\n return models\n } catch (error) {\n consola.warn(\"Error fetching Antigravity models:\", error)\n return null\n }\n}\n\n/**\n * Get available Antigravity models\n */\nexport async function getAntigravityModels(): Promise<AntigravityModelsResponse> {\n // Check cache\n if (cachedModels && Date.now() - cacheTimestamp < CACHE_TTL) {\n consola.debug(`Returning ${cachedModels.length} cached Antigravity models`)\n return {\n object: \"list\",\n data: cachedModels,\n }\n }\n\n // Try to fetch from API\n const apiModels = await fetchModelsFromApi()\n\n if (apiModels && apiModels.length > 0) {\n cachedModels = apiModels\n cacheTimestamp = Date.now()\n\n return {\n object: \"list\",\n data: apiModels,\n }\n }\n\n // Use fallback models\n consola.debug(\n `Returning ${FALLBACK_MODELS.length} fallback Antigravity models`,\n )\n\n return {\n object: \"list\",\n data: FALLBACK_MODELS,\n }\n}\n\n/**\n * Check if a model is a Claude model\n */\nexport function isClaudeModel(modelId: string): boolean {\n return modelId.startsWith(\"claude-\")\n}\n\n/**\n * Check if a model is a thinking/reasoning model\n */\nexport function isThinkingModel(modelId: string): boolean {\n return modelId.includes(\"thinking\")\n}\n\n/**\n * Check if a model is an image generation model\n */\nexport function isImageModel(modelId: string): boolean {\n return modelId.includes(\"image\")\n}\n"],"mappings":"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"}
|