opencode-antigravity-auth 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/README.md +25 -8
- package/package.json +1 -1
- package/src/constants.ts +5 -0
- package/src/plugin/project.ts +15 -43
- package/src/plugin/request.ts +3 -30
- package/src/plugin.ts +0 -7
package/README.md
CHANGED
|
@@ -30,7 +30,6 @@ Enable Opencode to authenticate against **Antigravity** (Google's IDE) via OAuth
|
|
|
30
30
|
3) **Declare the models you want**
|
|
31
31
|
|
|
32
32
|
Add Antigravity models under the `provider.google.models` section of your config:
|
|
33
|
-
|
|
34
33
|
```json
|
|
35
34
|
{
|
|
36
35
|
"plugin": ["opencode-antigravity-auth"],
|
|
@@ -39,27 +38,45 @@ Add Antigravity models under the `provider.google.models` section of your config
|
|
|
39
38
|
"models": {
|
|
40
39
|
"gemini-3-pro-high": {
|
|
41
40
|
"name": "Gemini 3 Pro High (Antigravity)",
|
|
42
|
-
"limit": {
|
|
41
|
+
"limit": {
|
|
42
|
+
"context": 1048576,
|
|
43
|
+
"output": 65535
|
|
44
|
+
}
|
|
43
45
|
},
|
|
44
46
|
"gemini-3-pro-low": {
|
|
45
47
|
"name": "Gemini 3 Pro Low (Antigravity)",
|
|
46
|
-
"limit": {
|
|
48
|
+
"limit": {
|
|
49
|
+
"context": 1048576,
|
|
50
|
+
"output": 65535
|
|
51
|
+
}
|
|
47
52
|
},
|
|
48
53
|
"claude-sonnet-4-5": {
|
|
49
54
|
"name": "Claude Sonnet 4.5 (Antigravity)",
|
|
50
|
-
"limit": {
|
|
55
|
+
"limit": {
|
|
56
|
+
"context": 200000,
|
|
57
|
+
"output": 64000
|
|
58
|
+
}
|
|
51
59
|
},
|
|
52
60
|
"claude-sonnet-4-5-thinking": {
|
|
53
61
|
"name": "Claude Sonnet 4.5 Thinking (Antigravity)",
|
|
54
|
-
"limit": {
|
|
62
|
+
"limit": {
|
|
63
|
+
"context": 200000,
|
|
64
|
+
"output": 64000
|
|
65
|
+
}
|
|
55
66
|
},
|
|
56
67
|
"claude-opus-4-5-thinking": {
|
|
57
68
|
"name": "Claude Opus 4.5 Thinking (Antigravity)",
|
|
58
|
-
"limit": {
|
|
69
|
+
"limit": {
|
|
70
|
+
"context": 200000,
|
|
71
|
+
"output": 64000
|
|
72
|
+
}
|
|
59
73
|
},
|
|
60
74
|
"gpt-oss-120b-medium": {
|
|
61
75
|
"name": "GPT-OSS 120B Medium (Antigravity)",
|
|
62
|
-
"limit": {
|
|
76
|
+
"limit": {
|
|
77
|
+
"context": 131072,
|
|
78
|
+
"output": 32768
|
|
79
|
+
}
|
|
63
80
|
}
|
|
64
81
|
}
|
|
65
82
|
}
|
|
@@ -123,4 +140,4 @@ Use at your own risk. Proceed only if you understand and accept these risks.
|
|
|
123
140
|
## Credits
|
|
124
141
|
|
|
125
142
|
- Inspired by and different from [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) by [jenslys](https://github.com/jenslys). Thanks for the groundwork! 🚀
|
|
126
|
-
- Thanks to [CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI) for the inspiration.
|
|
143
|
+
- Thanks to [CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI) for the inspiration.
|
package/package.json
CHANGED
package/src/constants.ts
CHANGED
|
@@ -58,6 +58,11 @@ export const ANTIGRAVITY_LOAD_ENDPOINTS = [
|
|
|
58
58
|
*/
|
|
59
59
|
export const ANTIGRAVITY_ENDPOINT = ANTIGRAVITY_ENDPOINT_DAILY;
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Hardcoded project id used when Antigravity does not return one (e.g., business/workspace accounts).
|
|
63
|
+
*/
|
|
64
|
+
export const ANTIGRAVITY_DEFAULT_PROJECT_ID = "rising-fact-p41fc";
|
|
65
|
+
|
|
61
66
|
export const ANTIGRAVITY_HEADERS = {
|
|
62
67
|
"User-Agent": "antigravity/1.11.5 windows/amd64",
|
|
63
68
|
"X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
|
package/src/plugin/project.ts
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
ANTIGRAVITY_HEADERS,
|
|
3
3
|
ANTIGRAVITY_ENDPOINT_FALLBACKS,
|
|
4
4
|
ANTIGRAVITY_LOAD_ENDPOINTS,
|
|
5
|
-
|
|
5
|
+
ANTIGRAVITY_DEFAULT_PROJECT_ID,
|
|
6
6
|
} from "../constants";
|
|
7
7
|
import { formatRefreshParts, parseRefreshParts } from "./auth";
|
|
8
8
|
import type {
|
|
@@ -275,16 +275,14 @@ export async function ensureProjectContext(
|
|
|
275
275
|
return { auth, effectiveProjectId: parts.managedProjectId };
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
-
const
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
if (resolvedManagedProjectId) {
|
|
278
|
+
const fallbackProjectId = ANTIGRAVITY_DEFAULT_PROJECT_ID;
|
|
279
|
+
const persistManagedProject = async (managedProjectId: string): Promise<ProjectContextResult> => {
|
|
282
280
|
const updatedAuth: OAuthAuthDetails = {
|
|
283
281
|
...auth,
|
|
284
282
|
refresh: formatRefreshParts({
|
|
285
283
|
refreshToken: parts.refreshToken,
|
|
286
284
|
projectId: parts.projectId,
|
|
287
|
-
managedProjectId
|
|
285
|
+
managedProjectId,
|
|
288
286
|
}),
|
|
289
287
|
};
|
|
290
288
|
|
|
@@ -293,49 +291,23 @@ export async function ensureProjectContext(
|
|
|
293
291
|
body: updatedAuth,
|
|
294
292
|
});
|
|
295
293
|
|
|
296
|
-
return { auth: updatedAuth, effectiveProjectId:
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (parts.projectId) {
|
|
300
|
-
return { auth, effectiveProjectId: parts.projectId };
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
if (!loadPayload) {
|
|
304
|
-
throw new ProjectIdRequiredError();
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
const currentTierId = loadPayload.currentTier?.id ?? undefined;
|
|
308
|
-
if (currentTierId && currentTierId !== "FREE") {
|
|
309
|
-
throw new ProjectIdRequiredError();
|
|
310
|
-
}
|
|
294
|
+
return { auth: updatedAuth, effectiveProjectId: managedProjectId };
|
|
295
|
+
};
|
|
311
296
|
|
|
312
|
-
|
|
313
|
-
const
|
|
297
|
+
// Try to resolve a managed project from Antigravity if possible.
|
|
298
|
+
const loadPayload = await loadManagedProject(accessToken, parts.projectId ?? fallbackProjectId);
|
|
299
|
+
const resolvedManagedProjectId = extractManagedProjectId(loadPayload);
|
|
314
300
|
|
|
315
|
-
if (
|
|
316
|
-
|
|
301
|
+
if (resolvedManagedProjectId) {
|
|
302
|
+
return persistManagedProject(resolvedManagedProjectId);
|
|
317
303
|
}
|
|
318
304
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
const updatedAuth: OAuthAuthDetails = {
|
|
322
|
-
...auth,
|
|
323
|
-
refresh: formatRefreshParts({
|
|
324
|
-
refreshToken: parts.refreshToken,
|
|
325
|
-
projectId: parts.projectId,
|
|
326
|
-
managedProjectId: onboardedProjectId,
|
|
327
|
-
}),
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
await client.auth.set({
|
|
331
|
-
path: { id: providerId },
|
|
332
|
-
body: updatedAuth,
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
return { auth: updatedAuth, effectiveProjectId: onboardedProjectId };
|
|
305
|
+
if (parts.projectId) {
|
|
306
|
+
return { auth, effectiveProjectId: parts.projectId };
|
|
336
307
|
}
|
|
337
308
|
|
|
338
|
-
|
|
309
|
+
// No project id present in auth; fall back to the hardcoded id for requests.
|
|
310
|
+
return { auth, effectiveProjectId: fallbackProjectId };
|
|
339
311
|
};
|
|
340
312
|
|
|
341
313
|
if (!cacheKey) {
|
package/src/plugin/request.ts
CHANGED
|
@@ -23,35 +23,8 @@ function generateSyntheticProjectId(): string {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
const STREAM_ACTION = "streamGenerateContent";
|
|
26
|
-
const MODEL_FALLBACKS: Record<string, string> = {
|
|
27
|
-
"gemini-2.5-flash-image": "gemini-2.5-flash",
|
|
28
|
-
"gemini-2.5-flash": "gemini-3-pro-preview",
|
|
29
|
-
"models/gemini-2.5-flash": "gemini-3-pro-preview",
|
|
30
|
-
"gemini-3-pro-high": "gemini-3-pro-preview",
|
|
31
|
-
"gemini-3-pro-low": "gemini-3-pro-preview",
|
|
32
|
-
"claude-sonnet-4-5": "claude-4-5-sonnet",
|
|
33
|
-
"claude-sonnet-4-5-thinking": "claude-4-5-sonnet-thinking",
|
|
34
|
-
"claude-opus-4-5-thinking": "claude-4-5-opus-thinking",
|
|
35
|
-
"gpt-oss-120b-medium": "gpt-oss-120b-medium",
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
// Maps friendly/alias names to the upstream model IDs Antigravity expects.
|
|
39
|
-
const MODEL_UPSTREAM_ALIASES: Record<string, string> = {
|
|
40
|
-
"gemini-2.5-computer-use-preview-10-2025": "rev19-uic3-1p",
|
|
41
|
-
"gemini-3-pro-image-preview": "gemini-3-pro-image",
|
|
42
|
-
"gemini-3-pro-preview": "gemini-3-pro-high",
|
|
43
|
-
"gemini-claude-sonnet-4-5": "claude-sonnet-4-5",
|
|
44
|
-
"gemini-claude-sonnet-4-5-thinking": "claude-sonnet-4-5-thinking",
|
|
45
|
-
"gemini-claude-opus-4-5-thinking": "claude-opus-4-5-thinking",
|
|
46
|
-
// Anthropic model name normalization (order expected by Antigravity)
|
|
47
|
-
"claude-4-5-sonnet": "claude-sonnet-4-5",
|
|
48
|
-
"claude-4-5-sonnet-thinking": "claude-sonnet-4-5-thinking",
|
|
49
|
-
"claude-4-5-opus-thinking": "claude-opus-4-5-thinking",
|
|
50
|
-
};
|
|
51
|
-
|
|
52
26
|
/**
|
|
53
|
-
*
|
|
54
|
-
* Matches CLIProxy and Vibeproxy behavior
|
|
27
|
+
* Detects requests headed to the Google Generative Language API so we can intercept them.
|
|
55
28
|
*/
|
|
56
29
|
export function isGenerativeLanguageRequest(input: RequestInfo): input is string {
|
|
57
30
|
return typeof input === "string" && input.includes("generativelanguage.googleapis.com");
|
|
@@ -121,8 +94,8 @@ export function prepareAntigravityRequest(
|
|
|
121
94
|
}
|
|
122
95
|
|
|
123
96
|
const [, rawModel = "", rawAction = ""] = match;
|
|
124
|
-
const effectiveModel =
|
|
125
|
-
const upstreamModel =
|
|
97
|
+
const effectiveModel = rawModel;
|
|
98
|
+
const upstreamModel = rawModel;
|
|
126
99
|
const streaming = rawAction === STREAM_ACTION;
|
|
127
100
|
const baseEndpoint = endpointOverride ?? ANTIGRAVITY_ENDPOINT;
|
|
128
101
|
const transformedUrl = `${baseEndpoint}/v1internal:${rawAction}${
|
package/src/plugin.ts
CHANGED
|
@@ -222,7 +222,6 @@ export const createAntigravityPlugin = (providerId: string) => async (
|
|
|
222
222
|
label: "OAuth with Google (Antigravity)",
|
|
223
223
|
type: "oauth",
|
|
224
224
|
authorize: async () => {
|
|
225
|
-
console.log("\n=== Google Antigravity OAuth Setup ===");
|
|
226
225
|
|
|
227
226
|
const isHeadless = !!(
|
|
228
227
|
process.env.SSH_CONNECTION ||
|
|
@@ -252,7 +251,6 @@ export const createAntigravityPlugin = (providerId: string) => async (
|
|
|
252
251
|
} else {
|
|
253
252
|
exec(`xdg-open "${authorization.url}"`);
|
|
254
253
|
}
|
|
255
|
-
console.log("Opening your browser to authenticate...");
|
|
256
254
|
} catch (e) {
|
|
257
255
|
console.log("Could not open browser automatically. Please Copy/Paste the URL below.");
|
|
258
256
|
}
|
|
@@ -260,8 +258,6 @@ export const createAntigravityPlugin = (providerId: string) => async (
|
|
|
260
258
|
|
|
261
259
|
if (listener) {
|
|
262
260
|
const { host } = new URL(ANTIGRAVITY_REDIRECT_URI);
|
|
263
|
-
console.log(`1. We'll automatically capture the browser redirect on http://${host}.`);
|
|
264
|
-
console.log("2. Once you see the 'Authentication complete' page in your browser, return to this terminal.\n");
|
|
265
261
|
|
|
266
262
|
return {
|
|
267
263
|
url: authorization.url,
|
|
@@ -300,9 +296,6 @@ export const createAntigravityPlugin = (providerId: string) => async (
|
|
|
300
296
|
};
|
|
301
297
|
}
|
|
302
298
|
|
|
303
|
-
console.log("1. Visit the URL below to sign in.");
|
|
304
|
-
console.log("2. Copy the full redirected URL (localhost) and paste it back here.\n");
|
|
305
|
-
|
|
306
299
|
return {
|
|
307
300
|
url: authorization.url,
|
|
308
301
|
instructions:
|