Spaces:
Running
Running
| /** | |
| * Antigravity Claude Proxy | |
| * Entry point - starts the proxy server | |
| */ | |
| // Initialize proxy support BEFORE any other imports that may use fetch | |
| import './utils/proxy.js'; | |
| import app, { accountManager } from './server.js'; | |
| import { DEFAULT_PORT } from './constants.js'; | |
| import { logger } from './utils/logger.js'; | |
| import { config } from './config.js'; | |
| import { getStrategyLabel, STRATEGY_NAMES, DEFAULT_STRATEGY } from './account-manager/strategies/index.js'; | |
| import { getPackageVersion } from './utils/helpers.js'; | |
| import path from 'path'; | |
| import os from 'os'; | |
| const packageVersion = getPackageVersion(); | |
| // Parse command line arguments | |
| const args = process.argv.slice(2); | |
| const isDebug = args.includes('--debug') || args.includes('--dev-mode') || process.env.DEBUG === 'true' || process.env.DEV_MODE === 'true'; | |
| const isFallbackEnabled = args.includes('--fallback') || process.env.FALLBACK === 'true'; | |
| // Parse --strategy flag (format: --strategy=sticky or --strategy sticky) | |
| let strategyOverride = null; | |
| for (let i = 0; i < args.length; i++) { | |
| if (args[i].startsWith('--strategy=')) { | |
| strategyOverride = args[i].split('=')[1]; | |
| } else if (args[i] === '--strategy' && args[i + 1]) { | |
| strategyOverride = args[i + 1]; | |
| } | |
| } | |
| // Validate strategy | |
| if (strategyOverride && !STRATEGY_NAMES.includes(strategyOverride.toLowerCase())) { | |
| logger.warn(`[Startup] Invalid strategy "${strategyOverride}". Valid options: ${STRATEGY_NAMES.join(', ')}. Using default.`); | |
| strategyOverride = null; | |
| } | |
| // Initialize logger and devMode | |
| logger.setDebug(isDebug); | |
| if (isDebug) { | |
| config.devMode = true; | |
| config.debug = true; | |
| logger.debug('Developer mode enabled'); | |
| } | |
| if (isFallbackEnabled) { | |
| logger.info('Model fallback mode enabled'); | |
| } | |
| if (!config.apiKey) { | |
| logger.error('[Startup] PROXY_API_KEY is not set. All /v1/* requests will be rejected until it is configured.'); | |
| } | |
| // Export fallback flag for server to use | |
| export const FALLBACK_ENABLED = isFallbackEnabled; | |
| const PORT = process.env.PORT || DEFAULT_PORT; | |
| const HOST = process.env.HOST || '0.0.0.0'; | |
| if (process.env.HOST) { | |
| logger.info(`[Startup] Using HOST environment variable: ${process.env.HOST}`); | |
| } | |
| // Home directory for account storage | |
| const HOME_DIR = os.homedir(); | |
| const CONFIG_DIR = path.join(HOME_DIR, '.antigravity-claude-proxy'); | |
| const server = app.listen(PORT, HOST, () => { | |
| // Get actual bound address | |
| const address = server.address(); | |
| const boundHost = typeof address === 'string' ? address : address.address; | |
| const boundPort = typeof address === 'string' ? null : address.port; | |
| // Clear console for a clean start | |
| console.clear(); | |
| const border = 'β'; | |
| // align for 2-space indent (60 chars), align4 for 4-space indent (58 chars) | |
| const align = (text) => text + ' '.repeat(Math.max(0, 60 - text.length)); | |
| const align4 = (text) => text + ' '.repeat(Math.max(0, 58 - text.length)); | |
| // Build Control section dynamically | |
| const strategyOptions = `(${STRATEGY_NAMES.join('/')})`; | |
| const strategyLine2 = ' ' + strategyOptions; | |
| let controlSection = 'β Control: β\n'; | |
| controlSection += 'β --strategy=<s> Set account selection strategy β\n'; | |
| controlSection += `${border} ${align(strategyLine2)}${border}\n`; | |
| if (!isDebug) { | |
| controlSection += 'β --dev-mode Enable developer mode β\n'; | |
| } | |
| if (!isFallbackEnabled) { | |
| controlSection += 'β --fallback Enable model fallback on quota exhaust β\n'; | |
| } | |
| controlSection += 'β Ctrl+C Stop server β'; | |
| // Get the strategy label (accountManager will be initialized by now) | |
| const strategyLabel = accountManager.getStrategyLabel(); | |
| // Build status section - always show strategy, plus any active modes | |
| let statusSection = 'β β\n'; | |
| statusSection += 'β Active Modes: β\n'; | |
| statusSection += `${border} ${align4(`β Strategy: ${strategyLabel}`)}${border}\n`; | |
| if (isDebug) { | |
| statusSection += 'β β Developer mode enabled β\n'; | |
| } | |
| if (isFallbackEnabled) { | |
| statusSection += 'β β Model fallback enabled β\n'; | |
| } | |
| if (process.env.CLAUDE_CONFIG_PATH) { | |
| statusSection += `${border} ${align4(`β Claude config: ${process.env.CLAUDE_CONFIG_PATH}`)}${border}\n`; | |
| } | |
| const environmentSection = `β Environment Variables: β | |
| β PORT Server port (default: 8080) β | |
| β PROXY_API_KEY OpenAI-compatible bearer key β | |
| β ACCOUNT_CONFIG_PATH Account storage path β | |
| β ENABLE_WEBUI Set false for headless mode β | |
| β HOST Bind address (default: 0.0.0.0) β | |
| β HTTP_PROXY Route requests through a proxy β | |
| β CLAUDE_CONFIG_PATH Path to .claude dir (for systemd) β | |
| β See README.md for detailed configuration examples β` | |
| logger.log(` | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β Antigravity Claude Proxy Server v${packageVersion} β | |
| β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£ | |
| β β | |
| ${border} ${align(`Server and WebUI running at: http://${HOST === '0.0.0.0' ? 'localhost' : HOST}:${PORT}`)}${border} | |
| ${border} ${align(`Bound to: ${boundHost}:${boundPort}`)}${border} | |
| ${statusSection}β β | |
| ${controlSection} | |
| β β | |
| β Endpoints: β | |
| β POST /v1/messages - Anthropic Messages API β | |
| β POST /v1/chat/completions - OpenAI Chat Completions β | |
| β GET /v1/models - List available models β | |
| β GET /health - Health check β | |
| β GET /account-limits - Account status & quotas β | |
| β POST /refresh-token - Force token refresh β | |
| β β | |
| ${border} ${align(`Configuration:`)}${border} | |
| ${border} ${align4(`Storage: ${CONFIG_DIR}`)}${border} | |
| β β | |
| β Usage with Claude Code: β | |
| ${border} ${align4(`export ANTHROPIC_BASE_URL=http://localhost:${PORT}`)}${border} | |
| ${border} ${align4(`export ANTHROPIC_API_KEY=${config.apiKey || 'dummy'}`)}${border} | |
| β claude β | |
| β β | |
| β Add Google accounts: β | |
| β npm run accounts β | |
| β β | |
| β Prerequisites (if no accounts configured): β | |
| β - Antigravity must be running β | |
| β - Have a chat panel open in Antigravity β | |
| β β | |
| ${environmentSection} | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| `); | |
| logger.success(`Server started successfully on port ${PORT}`); | |
| if (isDebug) { | |
| logger.warn('Running in DEVELOPER mode - verbose logs enabled'); | |
| } | |
| }); | |
| // Graceful shutdown | |
| const shutdown = () => { | |
| logger.info('Shutting down server...'); | |
| server.close(() => { | |
| logger.success('Server stopped'); | |
| process.exit(0); | |
| }); | |
| // Force close if it takes too long | |
| setTimeout(() => { | |
| logger.error('Could not close connections in time, forcefully shutting down'); | |
| process.exit(1); | |
| }, 10000); | |
| }; | |
| process.on('SIGTERM', shutdown); | |
| process.on('SIGINT', shutdown); |