antigravity-claude-proxy 2.7.5 → 2.7.7

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 CHANGED
@@ -192,8 +192,8 @@ Or to use Gemini models:
192
192
  "env": {
193
193
  "ANTHROPIC_AUTH_TOKEN": "test",
194
194
  "ANTHROPIC_BASE_URL": "http://localhost:8080",
195
- "ANTHROPIC_MODEL": "gemini-3-pro-high[1m]",
196
- "ANTHROPIC_DEFAULT_OPUS_MODEL": "gemini-3-pro-high[1m]",
195
+ "ANTHROPIC_MODEL": "gemini-3.1-pro-high[1m]",
196
+ "ANTHROPIC_DEFAULT_OPUS_MODEL": "gemini-3.1-pro-high[1m]",
197
197
  "ANTHROPIC_DEFAULT_SONNET_MODEL": "gemini-3-flash[1m]",
198
198
  "ANTHROPIC_DEFAULT_HAIKU_MODEL": "gemini-3-flash[1m]",
199
199
  "CLAUDE_CODE_SUBAGENT_MODEL": "gemini-3-flash[1m]",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "antigravity-claude-proxy",
3
- "version": "2.7.5",
3
+ "version": "2.7.7",
4
4
  "description": "Proxy server to use Antigravity's Claude models with Claude Code CLI",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -63,8 +63,7 @@
63
63
  "better-sqlite3": "^12.5.0",
64
64
  "cors": "^2.8.5",
65
65
  "express": "^4.18.2",
66
- "undici": "^7.20.0",
67
- "wreq-js": "^2.0.1"
66
+ "undici": "^7.20.0"
68
67
  },
69
68
  "devDependencies": {
70
69
  "@tailwindcss/forms": "^0.5.7",
@@ -438,8 +438,8 @@ document.addEventListener('alpine:init', () => {
438
438
  'claude-opus-4-6-thinking',
439
439
  'claude-sonnet-4-5-thinking',
440
440
  'claude-sonnet-4-5',
441
- 'gemini-3-pro-high',
442
- 'gemini-3-pro-low',
441
+ 'gemini-3.1-pro-high',
442
+ 'gemini-3.1-pro-low',
443
443
  'gemini-3-flash'
444
444
  ];
445
445
 
@@ -329,7 +329,7 @@ window.translations.en = {
329
329
  mcpCliDesc: "Enables experimental MCP integration for reliable tool usage with reduced context consumption.",
330
330
  gemini1mMode: "Gemini 1M Context Mode",
331
331
  gemini1mDesc: "Appends [1m] suffix to Gemini models for 1M context window support.",
332
- gemini1mWarning: "⚠ Large context may reduce Gemini-3-Pro performance.",
332
+ gemini1mWarning: "⚠ Large context may reduce Gemini performance.",
333
333
  clickToSet: "Click to configure...",
334
334
  none: "None",
335
335
  // Quota Distribution
@@ -368,7 +368,7 @@ window.translations.id = {
368
368
  mcpCliDesc: "Aktifkan integrasi MCP eksperimental untuk penggunaan tool yang lebih stabil dengan konsumsi konteks lebih rendah.",
369
369
  gemini1mMode: "Mode Konteks Gemini 1M",
370
370
  gemini1mDesc: "Tambahkan suffix [1m] ke model Gemini untuk context window 1M.",
371
- gemini1mWarning: "⚠ Konteks besar dapat menurunkan performa Gemini-3-Pro.",
371
+ gemini1mWarning: "⚠ Konteks besar dapat menurunkan performa Gemini-3.",
372
372
  clickToSet: "Klik untuk atur...",
373
373
 
374
374
  // Quota Distribution
@@ -307,7 +307,7 @@ window.translations.pt = {
307
307
  mcpCliDesc: "Habilita integração MCP experimental para uso confiável de ferramentas com consumo reduzido de contexto.",
308
308
  gemini1mMode: "Modo de Contexto Gemini 1M",
309
309
  gemini1mDesc: "Adiciona sufixo [1m] aos modelos Gemini para suporte a janela de contexto de 1M.",
310
- gemini1mWarning: "⚠ Contexto grande pode reduzir o desempenho do Gemini-3-Pro.",
310
+ gemini1mWarning: "⚠ Contexto grande pode reduzir o desempenho do Gemini.",
311
311
  clickToSet: "Clique para configurar...",
312
312
  none: "Nenhum",
313
313
  // Quota Distribution
@@ -311,7 +311,7 @@ window.translations.tr = {
311
311
  mcpCliDesc: "Daha az bağlam tüketimi ile güvenilir araç kullanımı için deneysel MCP entegrasyonunu etkinleştirir.",
312
312
  gemini1mMode: "Gemini 1M Bağlam Modu",
313
313
  gemini1mDesc: "1M bağlam penceresi desteği için Gemini modellerine [1m] son eki ekler.",
314
- gemini1mWarning: "⚠ Büyük bağlam, Gemini-3-Pro performansını düşürebilir.",
314
+ gemini1mWarning: "⚠ Büyük bağlam, Gemini performansını düşürebilir.",
315
315
  clickToSet: "Yapılandırmak için tıklayın...",
316
316
  none: "Hiçbiri",
317
317
  // Quota Distribution
@@ -329,7 +329,7 @@ window.translations.zh = {
329
329
  mcpCliDesc: "启用实验性 MCP 集成,减少上下文消耗,提高工具调用可靠性。",
330
330
  gemini1mMode: "Gemini 1M 上下文模式",
331
331
  gemini1mDesc: "为 Gemini 模型添加 [1m] 后缀以支持 1M 上下文窗口。",
332
- gemini1mWarning: "⚠ 大上下文可能降低 Gemini-3-Pro 性能。",
332
+ gemini1mWarning: "⚠ 大上下文可能降低 Gemini 性能。",
333
333
  clickToSet: "点击进行配置...",
334
334
  none: "无",
335
335
  // Quota Distribution
@@ -747,7 +747,7 @@
747
747
  Appends [1m] suffix to Gemini models for 1M context window support.
748
748
  </span>
749
749
  <span class="text-[10px] text-yellow-500/80" x-text="$store.global.t('gemini1mWarning')">
750
- ⚠ Large context may reduce Gemini-3-Pro performance.
750
+ ⚠ Large context may reduce Gemini performance.
751
751
  </span>
752
752
  </div>
753
753
  <label class="relative inline-flex items-center cursor-pointer">
@@ -157,7 +157,7 @@ export async function sendMessage(anthropicRequest, accountManager, fallbackEnab
157
157
 
158
158
  const response = await throttledFetch(url, {
159
159
  method: 'POST',
160
- headers: buildHeaders(token, model, isThinking ? 'text/event-stream' : 'application/json'),
160
+ headers: buildHeaders(token, model, isThinking ? 'text/event-stream' : 'application/json', payload.request.sessionId),
161
161
  body: JSON.stringify(payload)
162
162
  });
163
163
 
@@ -70,15 +70,21 @@ export function buildCloudCodeRequest(anthropicRequest, projectId, accountEmail)
70
70
  * @param {string} token - OAuth access token
71
71
  * @param {string} model - Model name
72
72
  * @param {string} accept - Accept header value (default: 'application/json')
73
+ * @param {string} [sessionId] - Optional session ID for X-Machine-Session-Id header
73
74
  * @returns {Object} Headers object
74
75
  */
75
- export function buildHeaders(token, model, accept = 'application/json') {
76
+ export function buildHeaders(token, model, accept = 'application/json', sessionId) {
76
77
  const headers = {
77
78
  'Authorization': `Bearer ${token}`,
78
79
  'Content-Type': 'application/json',
79
80
  ...ANTIGRAVITY_HEADERS
80
81
  };
81
82
 
83
+ // Add session ID header if provided (matches Antigravity binary behavior)
84
+ if (sessionId) {
85
+ headers['X-Machine-Session-Id'] = sessionId;
86
+ }
87
+
82
88
  const modelFamily = getModelFamily(model);
83
89
 
84
90
  // Add interleaved thinking header only for Claude thinking models
@@ -155,7 +155,7 @@ export async function* sendMessageStream(anthropicRequest, accountManager, fallb
155
155
 
156
156
  const response = await throttledFetch(url, {
157
157
  method: 'POST',
158
- headers: buildHeaders(token, model, 'text/event-stream'),
158
+ headers: buildHeaders(token, model, 'text/event-stream', payload.request.sessionId),
159
159
  body: JSON.stringify(payload)
160
160
  });
161
161
 
@@ -336,7 +336,7 @@ export async function* sendMessageStream(anthropicRequest, accountManager, fallb
336
336
  // Refetch the response
337
337
  currentResponse = await throttledFetch(url, {
338
338
  method: 'POST',
339
- headers: buildHeaders(token, model, 'text/event-stream'),
339
+ headers: buildHeaders(token, model, 'text/event-stream', payload.request.sessionId),
340
340
  body: JSON.stringify(payload)
341
341
  });
342
342
 
package/src/constants.js CHANGED
@@ -6,6 +6,7 @@
6
6
  import { homedir, platform, arch } from 'os';
7
7
  import { join } from 'path';
8
8
  import { config } from './config.js';
9
+ import { generateSmartUserAgent } from './utils/version-detector.js';
9
10
 
10
11
  /**
11
12
  * Get the Antigravity database path based on the current platform.
@@ -31,9 +32,7 @@ function getAntigravityDbPath() {
31
32
  * @returns {string} User-Agent in format "antigravity/version os/arch"
32
33
  */
33
34
  export function getPlatformUserAgent() {
34
- const os = platform();
35
- const architecture = arch();
36
- return `antigravity/1.16.5 ${os}/${architecture}`;
35
+ return generateSmartUserAgent();
37
36
  }
38
37
 
39
38
  // IDE Type enum (numeric values as expected by Cloud Code API)
@@ -103,7 +102,10 @@ export const ANTIGRAVITY_ENDPOINT_FALLBACKS = [
103
102
  // Strictly matches the generic 'u' method in main.js
104
103
  export const ANTIGRAVITY_HEADERS = {
105
104
  'User-Agent': getPlatformUserAgent(),
106
- 'Content-Type': 'application/json'
105
+ 'Content-Type': 'application/json',
106
+ 'X-Client-Name': 'antigravity',
107
+ 'X-Client-Version': '1.107.0', // Match product.json version
108
+ 'x-goog-api-client': 'gl-node/18.18.2 fire/0.8.6 grpc/1.10.x' // Simulate Google Node.js client environment
107
109
  };
108
110
 
109
111
  // Endpoint order for loadCodeAssist (prod first)
@@ -275,10 +277,10 @@ export const ANTIGRAVITY_SYSTEM_INSTRUCTION = `You are Antigravity, a powerful a
275
277
 
276
278
  // Model fallback mapping - maps primary model to fallback when quota exhausted
277
279
  export const MODEL_FALLBACK_MAP = {
278
- 'gemini-3-pro-high': 'claude-opus-4-6-thinking',
279
- 'gemini-3-pro-low': 'claude-sonnet-4-5',
280
+ 'gemini-3.1-pro-high': 'claude-opus-4-6-thinking',
281
+ 'gemini-3.1-pro-low': 'claude-sonnet-4-5',
280
282
  'gemini-3-flash': 'claude-sonnet-4-5-thinking',
281
- 'claude-opus-4-6-thinking': 'gemini-3-pro-high',
283
+ 'claude-opus-4-6-thinking': 'gemini-3.1-pro-high',
282
284
  'claude-sonnet-4-5-thinking': 'gemini-3-flash',
283
285
  'claude-sonnet-4-5': 'gemini-3-flash'
284
286
  };
@@ -309,11 +311,11 @@ export const DEFAULT_PRESETS = [
309
311
  config: {
310
312
  ANTHROPIC_AUTH_TOKEN: 'test',
311
313
  ANTHROPIC_BASE_URL: 'http://localhost:8080',
312
- ANTHROPIC_MODEL: 'gemini-3-pro-high[1m]',
313
- ANTHROPIC_DEFAULT_OPUS_MODEL: 'gemini-3-pro-high[1m]',
314
- ANTHROPIC_DEFAULT_SONNET_MODEL: 'gemini-3-flash[1m]',
315
- ANTHROPIC_DEFAULT_HAIKU_MODEL: 'gemini-3-flash[1m]',
316
- CLAUDE_CODE_SUBAGENT_MODEL: 'gemini-3-flash[1m]',
314
+ ANTHROPIC_MODEL: 'gemini-3.1-pro-high[1m]',
315
+ ANTHROPIC_DEFAULT_OPUS_MODEL: 'gemini-3.1-pro-high[1m]',
316
+ ANTHROPIC_DEFAULT_SONNET_MODEL: 'gemini-3.1-flash[1m]',
317
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: 'gemini-3.1-flash[1m]',
318
+ CLAUDE_CODE_SUBAGENT_MODEL: 'gemini-3.1-flash[1m]',
317
319
  ENABLE_EXPERIMENTAL_MCP_CLI: 'true'
318
320
  }
319
321
  }
package/src/index.js CHANGED
@@ -12,7 +12,6 @@ import { logger } from './utils/logger.js';
12
12
  import { config } from './config.js';
13
13
  import { getStrategyLabel, STRATEGY_NAMES, DEFAULT_STRATEGY } from './account-manager/strategies/index.js';
14
14
  import { getPackageVersion } from './utils/helpers.js';
15
- import tlsClient from './utils/tls-client.js';
16
15
  import path from 'path';
17
16
  import os from 'os';
18
17
 
@@ -160,15 +159,8 @@ ${environmentSection}
160
159
  });
161
160
 
162
161
  // Graceful shutdown
163
- const shutdown = async () => {
162
+ const shutdown = () => {
164
163
  logger.info('Shutting down server...');
165
-
166
- try {
167
- await tlsClient.exit();
168
- } catch (err) {
169
- logger.error('Error shutting down TLS client:', err);
170
- }
171
-
172
164
  server.close(() => {
173
165
  logger.success('Server stopped');
174
166
  process.exit(0);
package/src/server.js CHANGED
@@ -571,6 +571,7 @@ app.get('/account-limits', async (req, res) => {
571
571
  projectId: metadata.projectId || null,
572
572
  isInvalid: metadata.isInvalid || false,
573
573
  invalidReason: metadata.invalidReason || null,
574
+ verifyUrl: metadata.verifyUrl || null,
574
575
  lastUsed: metadata.lastUsed || null,
575
576
  modelRateLimits: metadata.modelRateLimits || {},
576
577
  // Quota threshold settings
@@ -2,7 +2,6 @@ import { readFileSync } from 'fs';
2
2
  import { fileURLToPath } from 'url';
3
3
  import path from 'path';
4
4
  import { config } from '../config.js';
5
- import tlsClient from './tls-client.js';
6
5
 
7
6
  /**
8
7
  * Shared Utility Functions
@@ -87,7 +86,7 @@ export async function throttledFetch(url, options) {
87
86
  await sleep(delayMs);
88
87
  }
89
88
  }
90
- return tlsClient.fetch(url, options);
89
+ return fetch(url, options);
91
90
  }
92
91
 
93
92
  /**
@@ -0,0 +1,134 @@
1
+ import { execSync } from 'child_process';
2
+ import { platform, homedir } from 'os';
3
+ import { join } from 'path';
4
+ import { existsSync } from 'fs';
5
+
6
+ /**
7
+ * Intelligent Version Detection for Antigravity
8
+ * Attempts to find the local installation and extract its version.
9
+ * Falls back to hard-coded stable versions if detection fails.
10
+ */
11
+
12
+ // Fallback constant
13
+ const FALLBACK_ANTIGRAVITY_VERSION = '1.18.3';
14
+
15
+ // Cache for the generated User-Agent string
16
+ let cachedUserAgent = null;
17
+
18
+ /**
19
+ * Compares two semver-ish version strings (X.Y.Z).
20
+ * @param {string} v1 - Version string 1
21
+ * @param {string} v2 - Version string 2
22
+ * @returns {boolean} True if v1 > v2
23
+ */
24
+ function isVersionHigher(v1, v2) {
25
+ const parts1 = v1.split('.').map(Number);
26
+ const parts2 = v2.split('.').map(Number);
27
+
28
+ for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
29
+ const p1 = parts1[i] || 0;
30
+ const p2 = parts2[i] || 0;
31
+ if (p1 > p2) return true;
32
+ if (p1 < p2) return false;
33
+ }
34
+ return false;
35
+ }
36
+
37
+ /**
38
+ * Gets the version config (version, source)
39
+ * @returns {{ version: string, source: string }}
40
+ */
41
+ function getVersionConfig() {
42
+ const os = platform();
43
+ let detectedVersion = null;
44
+ let finalVersion = FALLBACK_ANTIGRAVITY_VERSION;
45
+ let source = 'fallback';
46
+
47
+ try {
48
+ if (os === 'darwin') {
49
+ detectedVersion = getVersionMacos();
50
+ } else if (os === 'win32') {
51
+ detectedVersion = getVersionWindows();
52
+ }
53
+ } catch (error) {
54
+ // Silently fail and use fallback
55
+ }
56
+
57
+ // Only use detected version if it's higher than the fallback version
58
+ if (detectedVersion && isVersionHigher(detectedVersion, FALLBACK_ANTIGRAVITY_VERSION)) {
59
+ finalVersion = detectedVersion;
60
+ source = 'local';
61
+ }
62
+
63
+ return {
64
+ version: finalVersion,
65
+ source
66
+ };
67
+ }
68
+
69
+ /**
70
+ * Generate a simplified User-Agent string used by the Antigravity binary.
71
+ * Format: "antigravity/version os/arch"
72
+ * @returns {string} The User-Agent string
73
+ */
74
+ export function generateSmartUserAgent() {
75
+ if (cachedUserAgent) return cachedUserAgent;
76
+
77
+ const { version } = getVersionConfig();
78
+ const os = platform();
79
+ const architecture = process.arch;
80
+
81
+ // Map Node.js platform names to binary-friendly names
82
+ const osName = os === 'darwin' ? 'darwin' : (os === 'win32' ? 'win32' : 'linux');
83
+
84
+ cachedUserAgent = `antigravity/${version} ${osName}/${architecture}`;
85
+ return cachedUserAgent;
86
+ }
87
+
88
+ /**
89
+ * MacOS-specific version detection using plutil
90
+ */
91
+ function getVersionMacos() {
92
+ const appPath = '/Applications/Antigravity.app';
93
+ const plistPath = join(appPath, 'Contents/Info.plist');
94
+
95
+ if (!existsSync(plistPath)) return null;
96
+
97
+ try {
98
+ const version = execSync(`plutil -extract CFBundleShortVersionString raw "${plistPath}"`, { encoding: 'utf8' }).trim();
99
+ if (/^\d+\.\d+\.\d+/.test(version)) {
100
+ return version;
101
+ }
102
+ } catch (e) {
103
+ // plutil failed or file not found
104
+ }
105
+ return null;
106
+ }
107
+
108
+ /**
109
+ * Windows-specific version detection using PowerShell
110
+ */
111
+ function getVersionWindows() {
112
+ try {
113
+ const localAppData = process.env.LOCALAPPDATA;
114
+ const programFiles = process.env.ProgramFiles || 'C:\\Program Files';
115
+
116
+ const possiblePaths = [
117
+ join(localAppData, 'Programs', 'Antigravity', 'Antigravity.exe'),
118
+ join(programFiles, 'Antigravity', 'Antigravity.exe')
119
+ ];
120
+
121
+ for (const exePath of possiblePaths) {
122
+ if (existsSync(exePath)) {
123
+ const cmd = `powershell -Command "(Get-Item '${exePath}').VersionInfo.FileVersion"`;
124
+ const version = execSync(cmd, { encoding: 'utf8' }).trim();
125
+ const match = version.match(/^(\d+\.\d+\.\d+)/);
126
+ if (match) return match[1];
127
+ }
128
+ }
129
+ } catch (e) {
130
+ // PowerShell or path issues
131
+ }
132
+ return null;
133
+ }
134
+
@@ -1,102 +0,0 @@
1
- import { createRequire } from 'module';
2
- import { Readable } from 'stream';
3
- import { getPlatformUserAgent } from '../constants.js';
4
-
5
- const require = createRequire(import.meta.url);
6
- const { createSession } = require('wreq-js');
7
-
8
- class TlsClient {
9
- constructor() {
10
- this.userAgent = getPlatformUserAgent();
11
- this.session = null;
12
- }
13
-
14
- async getSession() {
15
- if (this.session) return this.session;
16
- this.session = await createSession({
17
- browser: 'chrome_124',
18
- os: 'macos',
19
- userAgent: this.userAgent
20
- });
21
- return this.session;
22
- }
23
-
24
- async fetch(url, options = {}) {
25
- const session = await this.getSession();
26
- const method = (options.method || 'GET').toUpperCase();
27
-
28
- const wreqOptions = {
29
- method,
30
- headers: options.headers,
31
- body: options.body,
32
- redirect: options.redirect === 'manual' ? 'manual' : 'follow',
33
- };
34
-
35
- try {
36
- const response = await session.fetch(url, wreqOptions);
37
- return new ResponseWrapper(response);
38
- } catch (error) {
39
- console.error('wreq-js fetch failed:', error);
40
- throw error;
41
- }
42
- }
43
-
44
- async exit() {
45
- if (this.session) {
46
- await this.session.close();
47
- this.session = null;
48
- }
49
- }
50
- }
51
-
52
- class ResponseWrapper {
53
- constructor(wreqResponse) {
54
- this.status = wreqResponse.status;
55
- this.statusText = wreqResponse.statusText || (this.status === 200 ? 'OK' : `Status ${this.status}`);
56
- this.headers = new Headers(wreqResponse.headers);
57
- this.url = wreqResponse.url;
58
- this.ok = this.status >= 200 && this.status < 300;
59
-
60
- if (wreqResponse.body) {
61
- if (typeof wreqResponse.body.getReader === 'function') {
62
- this.body = wreqResponse.body;
63
- } else {
64
- this.body = Readable.toWeb(wreqResponse.body);
65
- }
66
- } else {
67
- this.body = null;
68
- }
69
- }
70
-
71
- async text() {
72
- if (!this.body) return '';
73
- const reader = this.body.getReader();
74
- const chunks = [];
75
- while (true) {
76
- const { done, value } = await reader.read();
77
- if (done) break;
78
- chunks.push(typeof value === 'string' ? Buffer.from(value) : value);
79
- }
80
- return Buffer.concat(chunks).toString('utf8');
81
- }
82
-
83
- async json() {
84
- const text = await this.text();
85
- return JSON.parse(text);
86
- }
87
- }
88
-
89
- class Headers {
90
- constructor(headersObj = {}) {
91
- this.map = new Map();
92
- for (const [key, value] of Object.entries(headersObj)) {
93
- this.map.set(key.toLowerCase(), Array.isArray(value) ? value.join(', ') : value);
94
- }
95
- }
96
-
97
- get(name) { return this.map.get(name.toLowerCase()) || null; }
98
- has(name) { return this.map.has(name.toLowerCase()); }
99
- forEach(callback) { this.map.forEach(callback); }
100
- }
101
-
102
- export default new TlsClient();