antigravity-claude-proxy 1.0.0

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.
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Constants for Antigravity Cloud Code API integration
3
+ * Based on: https://github.com/NoeFabris/opencode-antigravity-auth
4
+ */
5
+
6
+ import { homedir, platform, arch } from 'os';
7
+ import { join } from 'path';
8
+
9
+ /**
10
+ * Get the Antigravity database path based on the current platform.
11
+ * - macOS: ~/Library/Application Support/Antigravity/...
12
+ * - Windows: ~/AppData/Roaming/Antigravity/...
13
+ * - Linux/other: ~/.config/Antigravity/...
14
+ * @returns {string} Full path to the Antigravity state database
15
+ */
16
+ function getAntigravityDbPath() {
17
+ const home = homedir();
18
+ switch (platform()) {
19
+ case 'darwin':
20
+ return join(home, 'Library/Application Support/Antigravity/User/globalStorage/state.vscdb');
21
+ case 'win32':
22
+ return join(home, 'AppData/Roaming/Antigravity/User/globalStorage/state.vscdb');
23
+ default: // linux, freebsd, etc.
24
+ return join(home, '.config/Antigravity/User/globalStorage/state.vscdb');
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Generate platform-specific User-Agent string.
30
+ * @returns {string} User-Agent in format "antigravity/version os/arch"
31
+ */
32
+ function getPlatformUserAgent() {
33
+ const os = platform();
34
+ const architecture = arch();
35
+ return `antigravity/1.11.5 ${os}/${architecture}`;
36
+ }
37
+
38
+ // Cloud Code API endpoints (in fallback order)
39
+ const ANTIGRAVITY_ENDPOINT_DAILY = 'https://daily-cloudcode-pa.sandbox.googleapis.com';
40
+ const ANTIGRAVITY_ENDPOINT_PROD = 'https://cloudcode-pa.googleapis.com';
41
+
42
+ // Endpoint fallback order (daily → prod)
43
+ export const ANTIGRAVITY_ENDPOINT_FALLBACKS = [
44
+ ANTIGRAVITY_ENDPOINT_DAILY,
45
+ ANTIGRAVITY_ENDPOINT_PROD
46
+ ];
47
+
48
+ // Required headers for Antigravity API requests
49
+ export const ANTIGRAVITY_HEADERS = {
50
+ 'User-Agent': getPlatformUserAgent(),
51
+ 'X-Goog-Api-Client': 'google-cloud-sdk vscode_cloudshelleditor/0.1',
52
+ 'Client-Metadata': JSON.stringify({
53
+ ideType: 'IDE_UNSPECIFIED',
54
+ platform: 'PLATFORM_UNSPECIFIED',
55
+ pluginType: 'GEMINI'
56
+ })
57
+ };
58
+
59
+ // Model name mappings: Anthropic format → Antigravity format
60
+ export const MODEL_MAPPINGS = {
61
+ // Claude models
62
+ 'claude-3-opus-20240229': 'claude-opus-4-5-thinking',
63
+ 'claude-3-5-opus-20240229': 'claude-opus-4-5-thinking',
64
+ 'claude-3-5-sonnet-20241022': 'claude-sonnet-4-5',
65
+ 'claude-3-5-sonnet-20240620': 'claude-sonnet-4-5',
66
+ 'claude-3-sonnet-20240229': 'claude-sonnet-4-5',
67
+ 'claude-sonnet-4-5': 'claude-sonnet-4-5',
68
+ 'claude-sonnet-4-5-thinking': 'claude-sonnet-4-5-thinking',
69
+ 'claude-opus-4-5-thinking': 'claude-opus-4-5-thinking'
70
+ };
71
+
72
+ // Available models exposed by this proxy
73
+ export const AVAILABLE_MODELS = [
74
+ {
75
+ id: 'claude-sonnet-4-5',
76
+ name: 'Claude Sonnet 4.5 (Antigravity)',
77
+ description: 'Claude Sonnet 4.5 via Antigravity Cloud Code',
78
+ context: 200000,
79
+ output: 64000
80
+ },
81
+ {
82
+ id: 'claude-sonnet-4-5-thinking',
83
+ name: 'Claude Sonnet 4.5 Thinking (Antigravity)',
84
+ description: 'Claude Sonnet 4.5 with extended thinking via Antigravity',
85
+ context: 200000,
86
+ output: 64000
87
+ },
88
+ {
89
+ id: 'claude-opus-4-5-thinking',
90
+ name: 'Claude Opus 4.5 Thinking (Antigravity)',
91
+ description: 'Claude Opus 4.5 with extended thinking via Antigravity',
92
+ context: 200000,
93
+ output: 64000
94
+ }
95
+ ];
96
+
97
+ // Default project ID if none can be discovered
98
+ export const DEFAULT_PROJECT_ID = 'rising-fact-p41fc';
99
+
100
+ export const TOKEN_REFRESH_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
101
+ export const REQUEST_BODY_LIMIT = '50mb';
102
+ export const ANTIGRAVITY_AUTH_PORT = 9092;
103
+ export const DEFAULT_PORT = 8080;
104
+
105
+ // Multi-account configuration
106
+ export const ACCOUNT_CONFIG_PATH = join(
107
+ homedir(),
108
+ '.config/antigravity-proxy/accounts.json'
109
+ );
110
+
111
+ // Antigravity app database path (for legacy single-account token extraction)
112
+ // Uses platform-specific path detection
113
+ export const ANTIGRAVITY_DB_PATH = getAntigravityDbPath();
114
+
115
+ export const DEFAULT_COOLDOWN_MS = 60 * 1000; // 1 minute default cooldown
116
+ export const MAX_RETRIES = 5; // Max retry attempts across accounts
117
+ export const MAX_ACCOUNTS = 10; // Maximum number of accounts allowed
118
+
119
+ // Rate limit wait thresholds
120
+ export const MAX_WAIT_BEFORE_ERROR_MS = 120000; // 2 minutes - throw error if wait exceeds this
121
+
122
+ // Thinking model constants
123
+ export const CLAUDE_THINKING_MAX_OUTPUT_TOKENS = 64000; // Max output tokens for thinking models
124
+ export const MIN_SIGNATURE_LENGTH = 50; // Minimum valid thinking signature length
125
+
126
+ // Google OAuth configuration (from opencode-antigravity-auth)
127
+ export const OAUTH_CONFIG = {
128
+ clientId: '1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com',
129
+ clientSecret: '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',
130
+ authUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
131
+ tokenUrl: 'https://oauth2.googleapis.com/token',
132
+ userInfoUrl: 'https://www.googleapis.com/oauth2/v1/userinfo',
133
+ callbackPort: 51121,
134
+ scopes: [
135
+ 'https://www.googleapis.com/auth/cloud-platform',
136
+ 'https://www.googleapis.com/auth/userinfo.email',
137
+ 'https://www.googleapis.com/auth/userinfo.profile',
138
+ 'https://www.googleapis.com/auth/cclog',
139
+ 'https://www.googleapis.com/auth/experimentsandconfigs'
140
+ ]
141
+ };
142
+ export const OAUTH_REDIRECT_URI = `http://localhost:${OAUTH_CONFIG.callbackPort}/oauth-callback`;
143
+
144
+ export default {
145
+ ANTIGRAVITY_ENDPOINT_FALLBACKS,
146
+ ANTIGRAVITY_HEADERS,
147
+ MODEL_MAPPINGS,
148
+ AVAILABLE_MODELS,
149
+ DEFAULT_PROJECT_ID,
150
+ TOKEN_REFRESH_INTERVAL_MS,
151
+ REQUEST_BODY_LIMIT,
152
+ ANTIGRAVITY_AUTH_PORT,
153
+ DEFAULT_PORT,
154
+ ACCOUNT_CONFIG_PATH,
155
+ ANTIGRAVITY_DB_PATH,
156
+ DEFAULT_COOLDOWN_MS,
157
+ MAX_RETRIES,
158
+ MAX_ACCOUNTS,
159
+ MAX_WAIT_BEFORE_ERROR_MS,
160
+ CLAUDE_THINKING_MAX_OUTPUT_TOKENS,
161
+ MIN_SIGNATURE_LENGTH,
162
+ OAUTH_CONFIG,
163
+ OAUTH_REDIRECT_URI
164
+ };
package/src/errors.js ADDED
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Custom Error Classes
3
+ *
4
+ * Provides structured error types for better error handling and classification.
5
+ * Replaces string-based error detection with proper error class checking.
6
+ */
7
+
8
+ /**
9
+ * Base error class for Antigravity proxy errors
10
+ */
11
+ export class AntigravityError extends Error {
12
+ /**
13
+ * @param {string} message - Error message
14
+ * @param {string} code - Error code for programmatic handling
15
+ * @param {boolean} retryable - Whether the error is retryable
16
+ * @param {Object} metadata - Additional error metadata
17
+ */
18
+ constructor(message, code, retryable = false, metadata = {}) {
19
+ super(message);
20
+ this.name = 'AntigravityError';
21
+ this.code = code;
22
+ this.retryable = retryable;
23
+ this.metadata = metadata;
24
+ }
25
+
26
+ /**
27
+ * Convert to JSON for API responses
28
+ */
29
+ toJSON() {
30
+ return {
31
+ name: this.name,
32
+ code: this.code,
33
+ message: this.message,
34
+ retryable: this.retryable,
35
+ ...this.metadata
36
+ };
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Rate limit error (429 / RESOURCE_EXHAUSTED)
42
+ */
43
+ export class RateLimitError extends AntigravityError {
44
+ /**
45
+ * @param {string} message - Error message
46
+ * @param {number|null} resetMs - Time in ms until rate limit resets
47
+ * @param {string} accountEmail - Email of the rate-limited account
48
+ */
49
+ constructor(message, resetMs = null, accountEmail = null) {
50
+ super(message, 'RATE_LIMITED', true, { resetMs, accountEmail });
51
+ this.name = 'RateLimitError';
52
+ this.resetMs = resetMs;
53
+ this.accountEmail = accountEmail;
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Authentication error (invalid credentials, token expired, etc.)
59
+ */
60
+ export class AuthError extends AntigravityError {
61
+ /**
62
+ * @param {string} message - Error message
63
+ * @param {string} accountEmail - Email of the account with auth issues
64
+ * @param {string} reason - Specific reason for auth failure
65
+ */
66
+ constructor(message, accountEmail = null, reason = null) {
67
+ super(message, 'AUTH_INVALID', false, { accountEmail, reason });
68
+ this.name = 'AuthError';
69
+ this.accountEmail = accountEmail;
70
+ this.reason = reason;
71
+ }
72
+ }
73
+
74
+ /**
75
+ * No accounts available error
76
+ */
77
+ export class NoAccountsError extends AntigravityError {
78
+ /**
79
+ * @param {string} message - Error message
80
+ * @param {boolean} allRateLimited - Whether all accounts are rate limited
81
+ */
82
+ constructor(message = 'No accounts available', allRateLimited = false) {
83
+ super(message, 'NO_ACCOUNTS', allRateLimited, { allRateLimited });
84
+ this.name = 'NoAccountsError';
85
+ this.allRateLimited = allRateLimited;
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Max retries exceeded error
91
+ */
92
+ export class MaxRetriesError extends AntigravityError {
93
+ /**
94
+ * @param {string} message - Error message
95
+ * @param {number} attempts - Number of attempts made
96
+ */
97
+ constructor(message = 'Max retries exceeded', attempts = 0) {
98
+ super(message, 'MAX_RETRIES', false, { attempts });
99
+ this.name = 'MaxRetriesError';
100
+ this.attempts = attempts;
101
+ }
102
+ }
103
+
104
+ /**
105
+ * API error from upstream service
106
+ */
107
+ export class ApiError extends AntigravityError {
108
+ /**
109
+ * @param {string} message - Error message
110
+ * @param {number} statusCode - HTTP status code
111
+ * @param {string} errorType - Type of API error
112
+ */
113
+ constructor(message, statusCode = 500, errorType = 'api_error') {
114
+ super(message, errorType.toUpperCase(), statusCode >= 500, { statusCode, errorType });
115
+ this.name = 'ApiError';
116
+ this.statusCode = statusCode;
117
+ this.errorType = errorType;
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Check if an error is a rate limit error
123
+ * Works with both custom error classes and legacy string-based errors
124
+ * @param {Error} error - Error to check
125
+ * @returns {boolean}
126
+ */
127
+ export function isRateLimitError(error) {
128
+ if (error instanceof RateLimitError) return true;
129
+ const msg = (error.message || '').toLowerCase();
130
+ return msg.includes('429') ||
131
+ msg.includes('resource_exhausted') ||
132
+ msg.includes('quota_exhausted') ||
133
+ msg.includes('rate limit');
134
+ }
135
+
136
+ /**
137
+ * Check if an error is an authentication error
138
+ * Works with both custom error classes and legacy string-based errors
139
+ * @param {Error} error - Error to check
140
+ * @returns {boolean}
141
+ */
142
+ export function isAuthError(error) {
143
+ if (error instanceof AuthError) return true;
144
+ const msg = (error.message || '').toUpperCase();
145
+ return msg.includes('AUTH_INVALID') ||
146
+ msg.includes('INVALID_GRANT') ||
147
+ msg.includes('TOKEN REFRESH FAILED');
148
+ }
149
+
150
+ export default {
151
+ AntigravityError,
152
+ RateLimitError,
153
+ AuthError,
154
+ NoAccountsError,
155
+ MaxRetriesError,
156
+ ApiError,
157
+ isRateLimitError,
158
+ isAuthError
159
+ };