oh-my-opencode 1.1.9 → 1.2.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,1497 @@
1
+ // @bun
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
19
+ var __export = (target, all) => {
20
+ for (var name in all)
21
+ __defProp(target, name, {
22
+ get: all[name],
23
+ enumerable: true,
24
+ configurable: true,
25
+ set: (newValue) => all[name] = () => newValue
26
+ });
27
+ };
28
+ var __require = import.meta.require;
29
+ // src/auth/antigravity/constants.ts
30
+ var ANTIGRAVITY_CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com";
31
+ var ANTIGRAVITY_CLIENT_SECRET = "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";
32
+ var ANTIGRAVITY_CALLBACK_PORT = 51121;
33
+ var ANTIGRAVITY_REDIRECT_URI = `http://localhost:${ANTIGRAVITY_CALLBACK_PORT}/oauth-callback`;
34
+ var ANTIGRAVITY_SCOPES = [
35
+ "https://www.googleapis.com/auth/cloud-platform",
36
+ "https://www.googleapis.com/auth/userinfo.email",
37
+ "https://www.googleapis.com/auth/userinfo.profile",
38
+ "https://www.googleapis.com/auth/cclog",
39
+ "https://www.googleapis.com/auth/experimentsandconfigs"
40
+ ];
41
+ var ANTIGRAVITY_ENDPOINT_FALLBACKS = [
42
+ "https://daily-cloudcode-pa.sandbox.googleapis.com",
43
+ "https://autopush-cloudcode-pa.sandbox.googleapis.com",
44
+ "https://cloudcode-pa.googleapis.com"
45
+ ];
46
+ var ANTIGRAVITY_API_VERSION = "v1internal";
47
+ var ANTIGRAVITY_HEADERS = {
48
+ "User-Agent": "google-api-nodejs-client/9.15.1",
49
+ "X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
50
+ "Client-Metadata": JSON.stringify({
51
+ ideType: "IDE_UNSPECIFIED",
52
+ platform: "PLATFORM_UNSPECIFIED",
53
+ pluginType: "GEMINI"
54
+ })
55
+ };
56
+ var GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
57
+ var GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token";
58
+ var GOOGLE_USERINFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo";
59
+ var ANTIGRAVITY_TOKEN_REFRESH_BUFFER_MS = 60000;
60
+ var SKIP_THOUGHT_SIGNATURE_VALIDATOR = "skip_thought_signature_validator";
61
+ // node_modules/jose/dist/browser/lib/buffer_utils.js
62
+ var encoder = new TextEncoder;
63
+ var decoder = new TextDecoder;
64
+ var MAX_INT32 = 2 ** 32;
65
+
66
+ // node_modules/jose/dist/browser/runtime/base64url.js
67
+ var encodeBase64 = (input) => {
68
+ let unencoded = input;
69
+ if (typeof unencoded === "string") {
70
+ unencoded = encoder.encode(unencoded);
71
+ }
72
+ const CHUNK_SIZE = 32768;
73
+ const arr = [];
74
+ for (let i = 0;i < unencoded.length; i += CHUNK_SIZE) {
75
+ arr.push(String.fromCharCode.apply(null, unencoded.subarray(i, i + CHUNK_SIZE)));
76
+ }
77
+ return btoa(arr.join(""));
78
+ };
79
+ var encode = (input) => {
80
+ return encodeBase64(input).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
81
+ };
82
+ var decodeBase64 = (encoded) => {
83
+ const binary = atob(encoded);
84
+ const bytes = new Uint8Array(binary.length);
85
+ for (let i = 0;i < binary.length; i++) {
86
+ bytes[i] = binary.charCodeAt(i);
87
+ }
88
+ return bytes;
89
+ };
90
+ var decode = (input) => {
91
+ let encoded = input;
92
+ if (encoded instanceof Uint8Array) {
93
+ encoded = decoder.decode(encoded);
94
+ }
95
+ encoded = encoded.replace(/-/g, "+").replace(/_/g, "/").replace(/\s/g, "");
96
+ try {
97
+ return decodeBase64(encoded);
98
+ } catch {
99
+ throw new TypeError("The input to be decoded is not correctly encoded.");
100
+ }
101
+ };
102
+
103
+ // node_modules/jose/dist/browser/util/base64url.js
104
+ var exports_base64url = {};
105
+ __export(exports_base64url, {
106
+ encode: () => encode2,
107
+ decode: () => decode2
108
+ });
109
+ var encode2 = encode;
110
+ var decode2 = decode;
111
+ // node_modules/@openauthjs/openauth/dist/esm/pkce.js
112
+ function generateVerifier(length) {
113
+ const buffer = new Uint8Array(length);
114
+ crypto.getRandomValues(buffer);
115
+ return exports_base64url.encode(buffer);
116
+ }
117
+ async function generateChallenge(verifier, method) {
118
+ if (method === "plain")
119
+ return verifier;
120
+ const encoder2 = new TextEncoder;
121
+ const data = encoder2.encode(verifier);
122
+ const hash = await crypto.subtle.digest("SHA-256", data);
123
+ return exports_base64url.encode(new Uint8Array(hash));
124
+ }
125
+ async function generatePKCE(length = 64) {
126
+ if (length < 43 || length > 128) {
127
+ throw new Error("Code verifier length must be between 43 and 128 characters");
128
+ }
129
+ const verifier = generateVerifier(length);
130
+ const challenge = await generateChallenge(verifier, "S256");
131
+ return {
132
+ verifier,
133
+ challenge,
134
+ method: "S256"
135
+ };
136
+ }
137
+
138
+ // src/auth/antigravity/oauth.ts
139
+ async function generatePKCEPair() {
140
+ const pkce = await generatePKCE();
141
+ return {
142
+ verifier: pkce.verifier,
143
+ challenge: pkce.challenge,
144
+ method: pkce.method
145
+ };
146
+ }
147
+ function encodeState(state) {
148
+ const json = JSON.stringify(state);
149
+ return Buffer.from(json, "utf8").toString("base64url");
150
+ }
151
+ function decodeState(encoded) {
152
+ const normalized = encoded.replace(/-/g, "+").replace(/_/g, "/");
153
+ const padded = normalized.padEnd(normalized.length + (4 - normalized.length % 4) % 4, "=");
154
+ const json = Buffer.from(padded, "base64").toString("utf8");
155
+ const parsed = JSON.parse(json);
156
+ if (typeof parsed.verifier !== "string") {
157
+ throw new Error("Missing PKCE verifier in state");
158
+ }
159
+ return {
160
+ verifier: parsed.verifier,
161
+ projectId: typeof parsed.projectId === "string" ? parsed.projectId : undefined
162
+ };
163
+ }
164
+ async function buildAuthURL(projectId, clientId = ANTIGRAVITY_CLIENT_ID, port = ANTIGRAVITY_CALLBACK_PORT) {
165
+ const pkce = await generatePKCEPair();
166
+ const state = {
167
+ verifier: pkce.verifier,
168
+ projectId
169
+ };
170
+ const redirectUri = `http://localhost:${port}/oauth-callback`;
171
+ const url = new URL(GOOGLE_AUTH_URL);
172
+ url.searchParams.set("client_id", clientId);
173
+ url.searchParams.set("redirect_uri", redirectUri);
174
+ url.searchParams.set("response_type", "code");
175
+ url.searchParams.set("scope", ANTIGRAVITY_SCOPES.join(" "));
176
+ url.searchParams.set("state", encodeState(state));
177
+ url.searchParams.set("code_challenge", pkce.challenge);
178
+ url.searchParams.set("code_challenge_method", "S256");
179
+ url.searchParams.set("access_type", "offline");
180
+ url.searchParams.set("prompt", "consent");
181
+ return {
182
+ url: url.toString(),
183
+ verifier: pkce.verifier
184
+ };
185
+ }
186
+ async function exchangeCode(code, verifier, clientId = ANTIGRAVITY_CLIENT_ID, clientSecret = ANTIGRAVITY_CLIENT_SECRET, port = ANTIGRAVITY_CALLBACK_PORT) {
187
+ const redirectUri = `http://localhost:${port}/oauth-callback`;
188
+ const params = new URLSearchParams({
189
+ client_id: clientId,
190
+ client_secret: clientSecret,
191
+ code,
192
+ grant_type: "authorization_code",
193
+ redirect_uri: redirectUri,
194
+ code_verifier: verifier
195
+ });
196
+ const response = await fetch(GOOGLE_TOKEN_URL, {
197
+ method: "POST",
198
+ headers: {
199
+ "Content-Type": "application/x-www-form-urlencoded"
200
+ },
201
+ body: params
202
+ });
203
+ if (!response.ok) {
204
+ const errorText = await response.text();
205
+ throw new Error(`Token exchange failed: ${response.status} - ${errorText}`);
206
+ }
207
+ const data = await response.json();
208
+ return {
209
+ access_token: data.access_token,
210
+ refresh_token: data.refresh_token,
211
+ expires_in: data.expires_in,
212
+ token_type: data.token_type
213
+ };
214
+ }
215
+ async function fetchUserInfo(accessToken) {
216
+ const response = await fetch(`${GOOGLE_USERINFO_URL}?alt=json`, {
217
+ headers: {
218
+ Authorization: `Bearer ${accessToken}`
219
+ }
220
+ });
221
+ if (!response.ok) {
222
+ throw new Error(`Failed to fetch user info: ${response.status}`);
223
+ }
224
+ const data = await response.json();
225
+ return {
226
+ email: data.email || "",
227
+ name: data.name,
228
+ picture: data.picture
229
+ };
230
+ }
231
+ function startCallbackServer(timeoutMs = 5 * 60 * 1000) {
232
+ let server = null;
233
+ let timeoutId = null;
234
+ let resolveCallback = null;
235
+ let rejectCallback = null;
236
+ const cleanup = () => {
237
+ if (timeoutId) {
238
+ clearTimeout(timeoutId);
239
+ timeoutId = null;
240
+ }
241
+ if (server) {
242
+ server.stop();
243
+ server = null;
244
+ }
245
+ };
246
+ server = Bun.serve({
247
+ port: 0,
248
+ fetch(request) {
249
+ const url = new URL(request.url);
250
+ if (url.pathname === "/oauth-callback") {
251
+ const code = url.searchParams.get("code") || "";
252
+ const state = url.searchParams.get("state") || "";
253
+ const error = url.searchParams.get("error") || undefined;
254
+ let responseBody;
255
+ if (code && !error) {
256
+ responseBody = "<html><body><h1>Login successful</h1><p>You can close this window.</p></body></html>";
257
+ } else {
258
+ responseBody = "<html><body><h1>Login failed</h1><p>Please check the CLI output.</p></body></html>";
259
+ }
260
+ setTimeout(() => {
261
+ cleanup();
262
+ if (resolveCallback) {
263
+ resolveCallback({ code, state, error });
264
+ }
265
+ }, 100);
266
+ return new Response(responseBody, {
267
+ status: 200,
268
+ headers: { "Content-Type": "text/html" }
269
+ });
270
+ }
271
+ return new Response("Not Found", { status: 404 });
272
+ }
273
+ });
274
+ const actualPort = server.port;
275
+ const waitForCallback = () => {
276
+ return new Promise((resolve, reject) => {
277
+ resolveCallback = resolve;
278
+ rejectCallback = reject;
279
+ timeoutId = setTimeout(() => {
280
+ cleanup();
281
+ reject(new Error("OAuth callback timeout"));
282
+ }, timeoutMs);
283
+ });
284
+ };
285
+ return {
286
+ port: actualPort,
287
+ waitForCallback,
288
+ close: cleanup
289
+ };
290
+ }
291
+ // src/auth/antigravity/token.ts
292
+ function isTokenExpired(tokens) {
293
+ const expirationTime = tokens.timestamp + tokens.expires_in * 1000;
294
+ return Date.now() >= expirationTime - ANTIGRAVITY_TOKEN_REFRESH_BUFFER_MS;
295
+ }
296
+ async function refreshAccessToken(refreshToken, clientId = ANTIGRAVITY_CLIENT_ID, clientSecret = ANTIGRAVITY_CLIENT_SECRET) {
297
+ const params = new URLSearchParams({
298
+ grant_type: "refresh_token",
299
+ refresh_token: refreshToken,
300
+ client_id: clientId,
301
+ client_secret: clientSecret
302
+ });
303
+ const response = await fetch(GOOGLE_TOKEN_URL, {
304
+ method: "POST",
305
+ headers: {
306
+ "Content-Type": "application/x-www-form-urlencoded"
307
+ },
308
+ body: params
309
+ });
310
+ if (!response.ok) {
311
+ const errorText = await response.text().catch(() => "Unknown error");
312
+ throw new Error(`Token refresh failed: ${response.status} ${response.statusText} - ${errorText}`);
313
+ }
314
+ const data = await response.json();
315
+ return {
316
+ access_token: data.access_token,
317
+ refresh_token: data.refresh_token || refreshToken,
318
+ expires_in: data.expires_in,
319
+ token_type: data.token_type
320
+ };
321
+ }
322
+ function parseStoredToken(stored) {
323
+ const parts = stored.split("|");
324
+ const [refreshToken, projectId, managedProjectId] = parts;
325
+ return {
326
+ refreshToken: refreshToken || "",
327
+ projectId: projectId || undefined,
328
+ managedProjectId: managedProjectId || undefined
329
+ };
330
+ }
331
+ function formatTokenForStorage(refreshToken, projectId, managedProjectId) {
332
+ return `${refreshToken}|${projectId}|${managedProjectId || ""}`;
333
+ }
334
+ // src/auth/antigravity/project.ts
335
+ var projectContextCache = new Map;
336
+ var CODE_ASSIST_METADATA = {
337
+ ideType: "IDE_UNSPECIFIED",
338
+ platform: "PLATFORM_UNSPECIFIED",
339
+ pluginType: "GEMINI"
340
+ };
341
+ function extractProjectId(project) {
342
+ if (!project) {
343
+ return;
344
+ }
345
+ if (typeof project === "string") {
346
+ const trimmed = project.trim();
347
+ return trimmed || undefined;
348
+ }
349
+ if (typeof project === "object" && "id" in project) {
350
+ const id = project.id;
351
+ if (typeof id === "string") {
352
+ const trimmed = id.trim();
353
+ return trimmed || undefined;
354
+ }
355
+ }
356
+ return;
357
+ }
358
+ async function callLoadCodeAssistAPI(accessToken) {
359
+ const requestBody = {
360
+ metadata: CODE_ASSIST_METADATA
361
+ };
362
+ const headers = {
363
+ Authorization: `Bearer ${accessToken}`,
364
+ "Content-Type": "application/json",
365
+ "User-Agent": ANTIGRAVITY_HEADERS["User-Agent"],
366
+ "X-Goog-Api-Client": ANTIGRAVITY_HEADERS["X-Goog-Api-Client"],
367
+ "Client-Metadata": ANTIGRAVITY_HEADERS["Client-Metadata"]
368
+ };
369
+ for (const baseEndpoint of ANTIGRAVITY_ENDPOINT_FALLBACKS) {
370
+ const url = `${baseEndpoint}/${ANTIGRAVITY_API_VERSION}:loadCodeAssist`;
371
+ try {
372
+ const response = await fetch(url, {
373
+ method: "POST",
374
+ headers,
375
+ body: JSON.stringify(requestBody)
376
+ });
377
+ if (!response.ok) {
378
+ continue;
379
+ }
380
+ const data = await response.json();
381
+ return data;
382
+ } catch {
383
+ continue;
384
+ }
385
+ }
386
+ return null;
387
+ }
388
+ async function fetchProjectContext(accessToken) {
389
+ const cached = projectContextCache.get(accessToken);
390
+ if (cached) {
391
+ return cached;
392
+ }
393
+ const response = await callLoadCodeAssistAPI(accessToken);
394
+ const projectId = response ? extractProjectId(response.cloudaicompanionProject) : undefined;
395
+ const result = {
396
+ cloudaicompanionProject: projectId || ""
397
+ };
398
+ if (projectId) {
399
+ projectContextCache.set(accessToken, result);
400
+ }
401
+ return result;
402
+ }
403
+ function clearProjectContextCache(accessToken) {
404
+ if (accessToken) {
405
+ projectContextCache.delete(accessToken);
406
+ } else {
407
+ projectContextCache.clear();
408
+ }
409
+ }
410
+ // src/auth/antigravity/request.ts
411
+ function buildRequestHeaders(accessToken) {
412
+ return {
413
+ Authorization: `Bearer ${accessToken}`,
414
+ "Content-Type": "application/json",
415
+ "User-Agent": ANTIGRAVITY_HEADERS["User-Agent"],
416
+ "X-Goog-Api-Client": ANTIGRAVITY_HEADERS["X-Goog-Api-Client"],
417
+ "Client-Metadata": ANTIGRAVITY_HEADERS["Client-Metadata"]
418
+ };
419
+ }
420
+ function extractModelFromBody(body) {
421
+ const model = body.model;
422
+ if (typeof model === "string" && model.trim()) {
423
+ return model.trim();
424
+ }
425
+ return;
426
+ }
427
+ function extractModelFromUrl(url) {
428
+ const match = url.match(/\/models\/([^:]+):/);
429
+ if (match && match[1]) {
430
+ return match[1];
431
+ }
432
+ return;
433
+ }
434
+ function extractActionFromUrl(url) {
435
+ const match = url.match(/\/models\/[^:]+:(\w+)/);
436
+ if (match && match[1]) {
437
+ return match[1];
438
+ }
439
+ return;
440
+ }
441
+ function buildAntigravityUrl(baseEndpoint, action, streaming) {
442
+ const query = streaming ? "?alt=sse" : "";
443
+ return `${baseEndpoint}/${ANTIGRAVITY_API_VERSION}:${action}${query}`;
444
+ }
445
+ function getDefaultEndpoint() {
446
+ return ANTIGRAVITY_ENDPOINT_FALLBACKS[0];
447
+ }
448
+ function generateRequestId() {
449
+ return `agent-${crypto.randomUUID()}`;
450
+ }
451
+ function wrapRequestBody(body, projectId, modelName, sessionId) {
452
+ const requestPayload = { ...body };
453
+ delete requestPayload.model;
454
+ return {
455
+ project: projectId,
456
+ model: modelName,
457
+ userAgent: "antigravity",
458
+ requestId: generateRequestId(),
459
+ request: {
460
+ ...requestPayload,
461
+ sessionId
462
+ }
463
+ };
464
+ }
465
+ function debugLog(message) {
466
+ if (process.env.ANTIGRAVITY_DEBUG === "1") {
467
+ console.log(`[antigravity-request] ${message}`);
468
+ }
469
+ }
470
+ function injectThoughtSignatureIntoFunctionCalls(body, signature) {
471
+ const effectiveSignature = signature || SKIP_THOUGHT_SIGNATURE_VALIDATOR;
472
+ debugLog(`[TSIG][INJECT] signature=${effectiveSignature.substring(0, 30)}... (${signature ? "provided" : "default"})`);
473
+ debugLog(`[TSIG][INJECT] body keys: ${Object.keys(body).join(", ")}`);
474
+ const contents = body.contents;
475
+ if (!contents || !Array.isArray(contents)) {
476
+ debugLog(`[TSIG][INJECT] No contents array! Has messages: ${!!body.messages}`);
477
+ return body;
478
+ }
479
+ debugLog(`[TSIG][INJECT] Found ${contents.length} content blocks`);
480
+ let injectedCount = 0;
481
+ const modifiedContents = contents.map((content) => {
482
+ if (!content.parts || !Array.isArray(content.parts)) {
483
+ return content;
484
+ }
485
+ const modifiedParts = content.parts.map((part) => {
486
+ if (part.functionCall && !part.thoughtSignature) {
487
+ injectedCount++;
488
+ return {
489
+ ...part,
490
+ thoughtSignature: effectiveSignature
491
+ };
492
+ }
493
+ return part;
494
+ });
495
+ return { ...content, parts: modifiedParts };
496
+ });
497
+ debugLog(`[TSIG][INJECT] injected signature into ${injectedCount} functionCall(s)`);
498
+ return { ...body, contents: modifiedContents };
499
+ }
500
+ function isStreamingRequest(url, body) {
501
+ const action = extractActionFromUrl(url);
502
+ if (action === "streamGenerateContent") {
503
+ return true;
504
+ }
505
+ if (body.stream === true) {
506
+ return true;
507
+ }
508
+ return false;
509
+ }
510
+ function transformRequest(options) {
511
+ const {
512
+ url,
513
+ body,
514
+ accessToken,
515
+ projectId,
516
+ sessionId,
517
+ modelName,
518
+ endpointOverride,
519
+ thoughtSignature
520
+ } = options;
521
+ const effectiveModel = modelName || extractModelFromBody(body) || extractModelFromUrl(url) || "gemini-3-pro-preview";
522
+ const streaming = isStreamingRequest(url, body);
523
+ const action = streaming ? "streamGenerateContent" : "generateContent";
524
+ const endpoint = endpointOverride || getDefaultEndpoint();
525
+ const transformedUrl = buildAntigravityUrl(endpoint, action, streaming);
526
+ const headers = buildRequestHeaders(accessToken);
527
+ if (streaming) {
528
+ headers["Accept"] = "text/event-stream";
529
+ }
530
+ const bodyWithSignature = injectThoughtSignatureIntoFunctionCalls(body, thoughtSignature);
531
+ const wrappedBody = wrapRequestBody(bodyWithSignature, projectId, effectiveModel, sessionId);
532
+ return {
533
+ url: transformedUrl,
534
+ headers,
535
+ body: wrappedBody,
536
+ streaming
537
+ };
538
+ }
539
+ // src/auth/antigravity/response.ts
540
+ function extractUsageFromHeaders(headers) {
541
+ const cached = headers.get("x-antigravity-cached-content-token-count");
542
+ const total = headers.get("x-antigravity-total-token-count");
543
+ const prompt = headers.get("x-antigravity-prompt-token-count");
544
+ const candidates = headers.get("x-antigravity-candidates-token-count");
545
+ if (!cached && !total && !prompt && !candidates) {
546
+ return;
547
+ }
548
+ const usage = {};
549
+ if (cached) {
550
+ const parsed = parseInt(cached, 10);
551
+ if (!isNaN(parsed)) {
552
+ usage.cachedContentTokenCount = parsed;
553
+ }
554
+ }
555
+ if (total) {
556
+ const parsed = parseInt(total, 10);
557
+ if (!isNaN(parsed)) {
558
+ usage.totalTokenCount = parsed;
559
+ }
560
+ }
561
+ if (prompt) {
562
+ const parsed = parseInt(prompt, 10);
563
+ if (!isNaN(parsed)) {
564
+ usage.promptTokenCount = parsed;
565
+ }
566
+ }
567
+ if (candidates) {
568
+ const parsed = parseInt(candidates, 10);
569
+ if (!isNaN(parsed)) {
570
+ usage.candidatesTokenCount = parsed;
571
+ }
572
+ }
573
+ return Object.keys(usage).length > 0 ? usage : undefined;
574
+ }
575
+ function extractRetryAfterMs(response, errorBody) {
576
+ const retryAfterHeader = response.headers.get("Retry-After");
577
+ if (retryAfterHeader) {
578
+ const seconds = parseFloat(retryAfterHeader);
579
+ if (!isNaN(seconds) && seconds > 0) {
580
+ return Math.ceil(seconds * 1000);
581
+ }
582
+ }
583
+ const retryAfterMsHeader = response.headers.get("retry-after-ms");
584
+ if (retryAfterMsHeader) {
585
+ const ms = parseInt(retryAfterMsHeader, 10);
586
+ if (!isNaN(ms) && ms > 0) {
587
+ return ms;
588
+ }
589
+ }
590
+ if (!errorBody) {
591
+ return;
592
+ }
593
+ const error = errorBody.error;
594
+ if (!error?.details || !Array.isArray(error.details)) {
595
+ return;
596
+ }
597
+ const retryInfo = error.details.find((detail) => detail["@type"] === "type.googleapis.com/google.rpc.RetryInfo");
598
+ if (!retryInfo?.retryDelay || typeof retryInfo.retryDelay !== "string") {
599
+ return;
600
+ }
601
+ const match = retryInfo.retryDelay.match(/^([\d.]+)s$/);
602
+ if (match?.[1]) {
603
+ const seconds = parseFloat(match[1]);
604
+ if (!isNaN(seconds) && seconds > 0) {
605
+ return Math.ceil(seconds * 1000);
606
+ }
607
+ }
608
+ return;
609
+ }
610
+ function parseErrorBody(text) {
611
+ try {
612
+ const parsed = JSON.parse(text);
613
+ if (parsed.error && typeof parsed.error === "object") {
614
+ const errorObj = parsed.error;
615
+ return {
616
+ message: String(errorObj.message || "Unknown error"),
617
+ type: errorObj.type ? String(errorObj.type) : undefined,
618
+ code: errorObj.code
619
+ };
620
+ }
621
+ if (parsed.message && typeof parsed.message === "string") {
622
+ return {
623
+ message: parsed.message,
624
+ type: parsed.type ? String(parsed.type) : undefined,
625
+ code: parsed.code
626
+ };
627
+ }
628
+ return;
629
+ } catch {
630
+ return {
631
+ message: text || "Unknown error"
632
+ };
633
+ }
634
+ }
635
+ async function transformResponse(response) {
636
+ const headers = new Headers(response.headers);
637
+ const usage = extractUsageFromHeaders(headers);
638
+ if (!response.ok) {
639
+ const text = await response.text();
640
+ const error = parseErrorBody(text);
641
+ const retryAfterMs = extractRetryAfterMs(response, error ? { error } : undefined);
642
+ let errorBody;
643
+ try {
644
+ errorBody = JSON.parse(text);
645
+ } catch {
646
+ errorBody = { error: { message: text } };
647
+ }
648
+ const retryMs = extractRetryAfterMs(response, errorBody) ?? retryAfterMs;
649
+ if (retryMs) {
650
+ headers.set("Retry-After", String(Math.ceil(retryMs / 1000)));
651
+ headers.set("retry-after-ms", String(retryMs));
652
+ }
653
+ return {
654
+ response: new Response(text, {
655
+ status: response.status,
656
+ statusText: response.statusText,
657
+ headers
658
+ }),
659
+ usage,
660
+ retryAfterMs: retryMs,
661
+ error
662
+ };
663
+ }
664
+ const contentType = response.headers.get("content-type") ?? "";
665
+ const isJson = contentType.includes("application/json");
666
+ if (!isJson) {
667
+ return { response, usage };
668
+ }
669
+ try {
670
+ const text = await response.text();
671
+ const parsed = JSON.parse(text);
672
+ let transformedBody = parsed;
673
+ if (parsed.response !== undefined) {
674
+ transformedBody = parsed.response;
675
+ }
676
+ return {
677
+ response: new Response(JSON.stringify(transformedBody), {
678
+ status: response.status,
679
+ statusText: response.statusText,
680
+ headers
681
+ }),
682
+ usage
683
+ };
684
+ } catch {
685
+ return { response, usage };
686
+ }
687
+ }
688
+ function transformSseLine(line) {
689
+ if (!line.startsWith("data:")) {
690
+ return line;
691
+ }
692
+ const json = line.slice(5).trim();
693
+ if (!json || json === "[DONE]") {
694
+ return line;
695
+ }
696
+ try {
697
+ const parsed = JSON.parse(json);
698
+ if (parsed.response !== undefined) {
699
+ return `data: ${JSON.stringify(parsed.response)}`;
700
+ }
701
+ return line;
702
+ } catch {
703
+ return line;
704
+ }
705
+ }
706
+ function createSseTransformStream() {
707
+ const decoder2 = new TextDecoder;
708
+ const encoder2 = new TextEncoder;
709
+ let buffer = "";
710
+ return new TransformStream({
711
+ transform(chunk, controller) {
712
+ buffer += decoder2.decode(chunk, { stream: true });
713
+ const lines = buffer.split(`
714
+ `);
715
+ buffer = lines.pop() || "";
716
+ for (const line of lines) {
717
+ const transformed = transformSseLine(line);
718
+ controller.enqueue(encoder2.encode(transformed + `
719
+ `));
720
+ }
721
+ },
722
+ flush(controller) {
723
+ if (buffer) {
724
+ const transformed = transformSseLine(buffer);
725
+ controller.enqueue(encoder2.encode(transformed));
726
+ }
727
+ }
728
+ });
729
+ }
730
+ async function transformStreamingResponse(response) {
731
+ const headers = new Headers(response.headers);
732
+ const usage = extractUsageFromHeaders(headers);
733
+ if (!response.ok) {
734
+ const text = await response.text();
735
+ const error = parseErrorBody(text);
736
+ let errorBody;
737
+ try {
738
+ errorBody = JSON.parse(text);
739
+ } catch {
740
+ errorBody = { error: { message: text } };
741
+ }
742
+ const retryAfterMs = extractRetryAfterMs(response, errorBody);
743
+ if (retryAfterMs) {
744
+ headers.set("Retry-After", String(Math.ceil(retryAfterMs / 1000)));
745
+ headers.set("retry-after-ms", String(retryAfterMs));
746
+ }
747
+ return {
748
+ response: new Response(text, {
749
+ status: response.status,
750
+ statusText: response.statusText,
751
+ headers
752
+ }),
753
+ usage,
754
+ retryAfterMs,
755
+ error
756
+ };
757
+ }
758
+ const contentType = response.headers.get("content-type") ?? "";
759
+ const isEventStream = contentType.includes("text/event-stream") || response.url.includes("alt=sse");
760
+ if (!isEventStream) {
761
+ const text = await response.text();
762
+ try {
763
+ const parsed = JSON.parse(text);
764
+ let transformedBody2 = parsed;
765
+ if (parsed.response !== undefined) {
766
+ transformedBody2 = parsed.response;
767
+ }
768
+ return {
769
+ response: new Response(JSON.stringify(transformedBody2), {
770
+ status: response.status,
771
+ statusText: response.statusText,
772
+ headers
773
+ }),
774
+ usage
775
+ };
776
+ } catch {
777
+ return {
778
+ response: new Response(text, {
779
+ status: response.status,
780
+ statusText: response.statusText,
781
+ headers
782
+ }),
783
+ usage
784
+ };
785
+ }
786
+ }
787
+ if (!response.body) {
788
+ return { response, usage };
789
+ }
790
+ headers.delete("content-length");
791
+ headers.delete("content-encoding");
792
+ headers.set("content-type", "text/event-stream; charset=utf-8");
793
+ const transformStream = createSseTransformStream();
794
+ const transformedBody = response.body.pipeThrough(transformStream);
795
+ return {
796
+ response: new Response(transformedBody, {
797
+ status: response.status,
798
+ statusText: response.statusText,
799
+ headers
800
+ }),
801
+ usage
802
+ };
803
+ }
804
+ function isStreamingResponse(response) {
805
+ const contentType = response.headers.get("content-type") ?? "";
806
+ return contentType.includes("text/event-stream") || response.url.includes("alt=sse");
807
+ }
808
+ // src/auth/antigravity/tools.ts
809
+ function normalizeToolsForGemini(tools) {
810
+ if (!tools || tools.length === 0) {
811
+ return;
812
+ }
813
+ const functionDeclarations = [];
814
+ for (const tool of tools) {
815
+ if (!tool || typeof tool !== "object") {
816
+ continue;
817
+ }
818
+ const toolType = tool.type ?? "function";
819
+ if (toolType === "function" && tool.function) {
820
+ const declaration = {
821
+ name: tool.function.name
822
+ };
823
+ if (tool.function.description) {
824
+ declaration.description = tool.function.description;
825
+ }
826
+ if (tool.function.parameters) {
827
+ declaration.parameters = tool.function.parameters;
828
+ } else {
829
+ declaration.parameters = { type: "object", properties: {} };
830
+ }
831
+ functionDeclarations.push(declaration);
832
+ } else if (toolType !== "function" && process.env.ANTIGRAVITY_DEBUG === "1") {
833
+ console.warn(`[antigravity-tools] Unsupported tool type: "${toolType}". Tool will be skipped.`);
834
+ }
835
+ }
836
+ if (functionDeclarations.length === 0) {
837
+ return;
838
+ }
839
+ return { functionDeclarations };
840
+ }
841
+ // src/auth/antigravity/thinking.ts
842
+ function shouldIncludeThinking(model) {
843
+ if (!model || typeof model !== "string") {
844
+ return false;
845
+ }
846
+ const lowerModel = model.toLowerCase();
847
+ if (lowerModel.endsWith("-high")) {
848
+ return true;
849
+ }
850
+ if (lowerModel.includes("thinking")) {
851
+ return true;
852
+ }
853
+ return false;
854
+ }
855
+ function isThinkingPart(part) {
856
+ if (part.thought === true) {
857
+ return true;
858
+ }
859
+ if (part.type === "thinking" || part.type === "reasoning") {
860
+ return true;
861
+ }
862
+ return false;
863
+ }
864
+ function extractThinkingBlocks(response) {
865
+ const thinkingBlocks = [];
866
+ if (response.candidates && Array.isArray(response.candidates)) {
867
+ for (const candidate of response.candidates) {
868
+ const parts = candidate.content?.parts;
869
+ if (!parts || !Array.isArray(parts)) {
870
+ continue;
871
+ }
872
+ for (let i = 0;i < parts.length; i++) {
873
+ const part = parts[i];
874
+ if (!part || typeof part !== "object") {
875
+ continue;
876
+ }
877
+ if (isThinkingPart(part)) {
878
+ const block = {
879
+ text: part.text || "",
880
+ index: thinkingBlocks.length
881
+ };
882
+ if (part.thought === true && part.thoughtSignature) {
883
+ block.signature = part.thoughtSignature;
884
+ } else if (part.signature) {
885
+ block.signature = part.signature;
886
+ }
887
+ thinkingBlocks.push(block);
888
+ }
889
+ }
890
+ }
891
+ }
892
+ if (response.content && Array.isArray(response.content)) {
893
+ for (let i = 0;i < response.content.length; i++) {
894
+ const item = response.content[i];
895
+ if (!item || typeof item !== "object") {
896
+ continue;
897
+ }
898
+ if (item.type === "thinking" || item.type === "reasoning") {
899
+ thinkingBlocks.push({
900
+ text: item.text || "",
901
+ signature: item.signature,
902
+ index: thinkingBlocks.length
903
+ });
904
+ }
905
+ }
906
+ }
907
+ const combinedThinking = thinkingBlocks.map((b) => b.text).join(`
908
+
909
+ `);
910
+ return {
911
+ thinkingBlocks,
912
+ combinedThinking,
913
+ hasThinking: thinkingBlocks.length > 0
914
+ };
915
+ }
916
+ function transformCandidateThinking(candidate) {
917
+ if (!candidate || typeof candidate !== "object") {
918
+ return candidate;
919
+ }
920
+ const content = candidate.content;
921
+ if (!content || typeof content !== "object" || !Array.isArray(content.parts)) {
922
+ return candidate;
923
+ }
924
+ const thinkingTexts = [];
925
+ const transformedParts = content.parts.map((part) => {
926
+ if (part && typeof part === "object" && part.thought === true) {
927
+ thinkingTexts.push(part.text || "");
928
+ return {
929
+ ...part,
930
+ type: "reasoning",
931
+ thought: undefined
932
+ };
933
+ }
934
+ return part;
935
+ });
936
+ const result = {
937
+ ...candidate,
938
+ content: { ...content, parts: transformedParts }
939
+ };
940
+ if (thinkingTexts.length > 0) {
941
+ result.reasoning_content = thinkingTexts.join(`
942
+
943
+ `);
944
+ }
945
+ return result;
946
+ }
947
+ function transformAnthropicThinking(content) {
948
+ if (!content || !Array.isArray(content)) {
949
+ return content;
950
+ }
951
+ return content.map((block) => {
952
+ if (block && typeof block === "object" && block.type === "thinking") {
953
+ return {
954
+ type: "reasoning",
955
+ text: block.text || "",
956
+ ...block.signature ? { signature: block.signature } : {}
957
+ };
958
+ }
959
+ return block;
960
+ });
961
+ }
962
+ function transformResponseThinking(response) {
963
+ if (!response || typeof response !== "object") {
964
+ return response;
965
+ }
966
+ const result = { ...response };
967
+ if (Array.isArray(result.candidates)) {
968
+ result.candidates = result.candidates.map(transformCandidateThinking);
969
+ }
970
+ if (Array.isArray(result.content)) {
971
+ result.content = transformAnthropicThinking(result.content);
972
+ }
973
+ return result;
974
+ }
975
+ // src/auth/antigravity/thought-signature-store.ts
976
+ var signatureStore = new Map;
977
+ var sessionIdStore = new Map;
978
+ function setThoughtSignature(sessionKey, signature) {
979
+ if (sessionKey && signature) {
980
+ signatureStore.set(sessionKey, signature);
981
+ }
982
+ }
983
+ function getThoughtSignature(sessionKey) {
984
+ return signatureStore.get(sessionKey);
985
+ }
986
+ function getOrCreateSessionId(fetchInstanceId, sessionId) {
987
+ if (sessionId) {
988
+ sessionIdStore.set(fetchInstanceId, sessionId);
989
+ return sessionId;
990
+ }
991
+ const existing = sessionIdStore.get(fetchInstanceId);
992
+ if (existing) {
993
+ return existing;
994
+ }
995
+ const n = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
996
+ const newSessionId = `-${n}`;
997
+ sessionIdStore.set(fetchInstanceId, newSessionId);
998
+ return newSessionId;
999
+ }
1000
+ // src/auth/antigravity/message-converter.ts
1001
+ function debugLog2(message) {
1002
+ if (process.env.ANTIGRAVITY_DEBUG === "1") {
1003
+ console.log(`[antigravity-converter] ${message}`);
1004
+ }
1005
+ }
1006
+ function convertOpenAIToGemini(messages, thoughtSignature) {
1007
+ debugLog2(`Converting ${messages.length} messages, signature: ${thoughtSignature ? "present" : "none"}`);
1008
+ const contents = [];
1009
+ for (const msg of messages) {
1010
+ if (msg.role === "system") {
1011
+ contents.push({
1012
+ role: "user",
1013
+ parts: [{ text: typeof msg.content === "string" ? msg.content : "" }]
1014
+ });
1015
+ continue;
1016
+ }
1017
+ if (msg.role === "user") {
1018
+ const parts = convertContentToParts(msg.content);
1019
+ contents.push({ role: "user", parts });
1020
+ continue;
1021
+ }
1022
+ if (msg.role === "assistant") {
1023
+ const parts = [];
1024
+ if (msg.content) {
1025
+ parts.push(...convertContentToParts(msg.content));
1026
+ }
1027
+ if (msg.tool_calls && msg.tool_calls.length > 0) {
1028
+ for (const toolCall of msg.tool_calls) {
1029
+ let args = {};
1030
+ try {
1031
+ args = JSON.parse(toolCall.function.arguments);
1032
+ } catch {
1033
+ args = {};
1034
+ }
1035
+ const part = {
1036
+ functionCall: {
1037
+ name: toolCall.function.name,
1038
+ args
1039
+ }
1040
+ };
1041
+ part.thoughtSignature = thoughtSignature || SKIP_THOUGHT_SIGNATURE_VALIDATOR;
1042
+ debugLog2(`Injected signature into functionCall: ${toolCall.function.name} (${thoughtSignature ? "provided" : "default"})`);
1043
+ parts.push(part);
1044
+ }
1045
+ }
1046
+ if (parts.length > 0) {
1047
+ contents.push({ role: "model", parts });
1048
+ }
1049
+ continue;
1050
+ }
1051
+ if (msg.role === "tool") {
1052
+ let response = {};
1053
+ try {
1054
+ response = typeof msg.content === "string" ? JSON.parse(msg.content) : { result: msg.content };
1055
+ } catch {
1056
+ response = { result: msg.content };
1057
+ }
1058
+ const toolName = msg.name || "unknown";
1059
+ contents.push({
1060
+ role: "user",
1061
+ parts: [{
1062
+ functionResponse: {
1063
+ name: toolName,
1064
+ response
1065
+ }
1066
+ }]
1067
+ });
1068
+ continue;
1069
+ }
1070
+ }
1071
+ debugLog2(`Converted to ${contents.length} content blocks`);
1072
+ return contents;
1073
+ }
1074
+ function convertContentToParts(content) {
1075
+ if (!content) {
1076
+ return [{ text: "" }];
1077
+ }
1078
+ if (typeof content === "string") {
1079
+ return [{ text: content }];
1080
+ }
1081
+ const parts = [];
1082
+ for (const part of content) {
1083
+ if (part.type === "text" && part.text) {
1084
+ parts.push({ text: part.text });
1085
+ } else if (part.type === "image_url" && part.image_url?.url) {
1086
+ const url = part.image_url.url;
1087
+ if (url.startsWith("data:")) {
1088
+ const match = url.match(/^data:([^;]+);base64,(.+)$/);
1089
+ if (match) {
1090
+ parts.push({
1091
+ inlineData: {
1092
+ mimeType: match[1],
1093
+ data: match[2]
1094
+ }
1095
+ });
1096
+ }
1097
+ }
1098
+ }
1099
+ }
1100
+ return parts.length > 0 ? parts : [{ text: "" }];
1101
+ }
1102
+ function hasOpenAIMessages(body) {
1103
+ return Array.isArray(body.messages) && body.messages.length > 0;
1104
+ }
1105
+ function convertRequestBody(body, thoughtSignature) {
1106
+ if (!hasOpenAIMessages(body)) {
1107
+ debugLog2("No messages array found, returning body as-is");
1108
+ return body;
1109
+ }
1110
+ const messages = body.messages;
1111
+ const contents = convertOpenAIToGemini(messages, thoughtSignature);
1112
+ const converted = { ...body };
1113
+ delete converted.messages;
1114
+ converted.contents = contents;
1115
+ debugLog2(`Converted body: messages \u2192 contents (${contents.length} blocks)`);
1116
+ return converted;
1117
+ }
1118
+ // src/auth/antigravity/fetch.ts
1119
+ function debugLog3(message) {
1120
+ if (process.env.ANTIGRAVITY_DEBUG === "1") {
1121
+ console.log(`[antigravity-fetch] ${message}`);
1122
+ }
1123
+ }
1124
+ function isRetryableError(status) {
1125
+ if (status === 0)
1126
+ return true;
1127
+ if (status === 429)
1128
+ return true;
1129
+ if (status >= 500 && status < 600)
1130
+ return true;
1131
+ return false;
1132
+ }
1133
+ async function attemptFetch(options) {
1134
+ const { endpoint, url, init, accessToken, projectId, sessionId, modelName, thoughtSignature } = options;
1135
+ debugLog3(`Trying endpoint: ${endpoint}`);
1136
+ try {
1137
+ const rawBody = init.body;
1138
+ if (rawBody !== undefined && typeof rawBody !== "string") {
1139
+ debugLog3(`Non-string body detected (${typeof rawBody}), signaling pass-through`);
1140
+ return "pass-through";
1141
+ }
1142
+ let parsedBody = {};
1143
+ if (rawBody) {
1144
+ try {
1145
+ parsedBody = JSON.parse(rawBody);
1146
+ } catch {
1147
+ parsedBody = {};
1148
+ }
1149
+ }
1150
+ debugLog3(`[BODY] Keys: ${Object.keys(parsedBody).join(", ")}`);
1151
+ debugLog3(`[BODY] Has contents: ${!!parsedBody.contents}, Has messages: ${!!parsedBody.messages}`);
1152
+ if (parsedBody.contents) {
1153
+ const contents = parsedBody.contents;
1154
+ debugLog3(`[BODY] contents length: ${contents.length}`);
1155
+ contents.forEach((c, i) => {
1156
+ debugLog3(`[BODY] contents[${i}].role: ${c.role}, parts: ${JSON.stringify(c.parts).substring(0, 200)}`);
1157
+ });
1158
+ }
1159
+ if (parsedBody.tools && Array.isArray(parsedBody.tools)) {
1160
+ const normalizedTools = normalizeToolsForGemini(parsedBody.tools);
1161
+ if (normalizedTools) {
1162
+ parsedBody.tools = normalizedTools;
1163
+ }
1164
+ }
1165
+ if (hasOpenAIMessages(parsedBody)) {
1166
+ debugLog3(`[CONVERT] Converting OpenAI messages to Gemini contents`);
1167
+ parsedBody = convertRequestBody(parsedBody, thoughtSignature);
1168
+ debugLog3(`[CONVERT] After conversion - Has contents: ${!!parsedBody.contents}`);
1169
+ }
1170
+ const transformed = transformRequest({
1171
+ url,
1172
+ body: parsedBody,
1173
+ accessToken,
1174
+ projectId,
1175
+ sessionId,
1176
+ modelName,
1177
+ endpointOverride: endpoint,
1178
+ thoughtSignature
1179
+ });
1180
+ debugLog3(`[REQ] streaming=${transformed.streaming}, url=${transformed.url}`);
1181
+ const response = await fetch(transformed.url, {
1182
+ method: init.method || "POST",
1183
+ headers: transformed.headers,
1184
+ body: JSON.stringify(transformed.body),
1185
+ signal: init.signal
1186
+ });
1187
+ debugLog3(`[RESP] status=${response.status} content-type=${response.headers.get("content-type") ?? ""} url=${response.url}`);
1188
+ if (!response.ok && isRetryableError(response.status)) {
1189
+ debugLog3(`Endpoint failed: ${endpoint} (status: ${response.status}), trying next`);
1190
+ return null;
1191
+ }
1192
+ return response;
1193
+ } catch (error) {
1194
+ debugLog3(`Endpoint failed: ${endpoint} (${error instanceof Error ? error.message : "Unknown error"}), trying next`);
1195
+ return null;
1196
+ }
1197
+ }
1198
+ function extractSignatureFromResponse(parsed) {
1199
+ if (!parsed.candidates || !Array.isArray(parsed.candidates)) {
1200
+ return;
1201
+ }
1202
+ for (const candidate of parsed.candidates) {
1203
+ const parts = candidate.content?.parts;
1204
+ if (!parts || !Array.isArray(parts)) {
1205
+ continue;
1206
+ }
1207
+ for (const part of parts) {
1208
+ const sig = part.thoughtSignature || part.thought_signature;
1209
+ if (sig && typeof sig === "string") {
1210
+ return sig;
1211
+ }
1212
+ }
1213
+ }
1214
+ return;
1215
+ }
1216
+ async function transformResponseWithThinking(response, modelName, fetchInstanceId) {
1217
+ const streaming = isStreamingResponse(response);
1218
+ let result;
1219
+ if (streaming) {
1220
+ result = await transformStreamingResponse(response);
1221
+ } else {
1222
+ result = await transformResponse(response);
1223
+ }
1224
+ if (streaming) {
1225
+ return result.response;
1226
+ }
1227
+ try {
1228
+ const text = await result.response.clone().text();
1229
+ debugLog3(`[TSIG][RESP] Response text length: ${text.length}`);
1230
+ const parsed = JSON.parse(text);
1231
+ debugLog3(`[TSIG][RESP] Parsed keys: ${Object.keys(parsed).join(", ")}`);
1232
+ debugLog3(`[TSIG][RESP] Has candidates: ${!!parsed.candidates}, count: ${parsed.candidates?.length ?? 0}`);
1233
+ const signature = extractSignatureFromResponse(parsed);
1234
+ debugLog3(`[TSIG][RESP] Signature extracted: ${signature ? signature.substring(0, 30) + "..." : "NONE"}`);
1235
+ if (signature) {
1236
+ setThoughtSignature(fetchInstanceId, signature);
1237
+ debugLog3(`[TSIG][STORE] Stored signature for ${fetchInstanceId}`);
1238
+ } else {
1239
+ debugLog3(`[TSIG][WARN] No signature found in response!`);
1240
+ }
1241
+ if (shouldIncludeThinking(modelName)) {
1242
+ const thinkingResult = extractThinkingBlocks(parsed);
1243
+ if (thinkingResult.hasThinking) {
1244
+ const transformed = transformResponseThinking(parsed);
1245
+ return new Response(JSON.stringify(transformed), {
1246
+ status: result.response.status,
1247
+ statusText: result.response.statusText,
1248
+ headers: result.response.headers
1249
+ });
1250
+ }
1251
+ }
1252
+ } catch {}
1253
+ return result.response;
1254
+ }
1255
+ function createAntigravityFetch(getAuth, client, providerId, clientId, clientSecret) {
1256
+ let cachedTokens = null;
1257
+ let cachedProjectId = null;
1258
+ const fetchInstanceId = crypto.randomUUID();
1259
+ return async (url, init = {}) => {
1260
+ debugLog3(`Intercepting request to: ${url}`);
1261
+ const auth = await getAuth();
1262
+ if (!auth.access || !auth.refresh) {
1263
+ throw new Error("Antigravity: No authentication tokens available");
1264
+ }
1265
+ const refreshParts = parseStoredToken(auth.refresh);
1266
+ if (!cachedTokens) {
1267
+ cachedTokens = {
1268
+ type: "antigravity",
1269
+ access_token: auth.access,
1270
+ refresh_token: refreshParts.refreshToken,
1271
+ expires_in: auth.expires ? Math.floor((auth.expires - Date.now()) / 1000) : 3600,
1272
+ timestamp: auth.expires ? auth.expires - 3600 * 1000 : Date.now()
1273
+ };
1274
+ } else {
1275
+ cachedTokens.access_token = auth.access;
1276
+ cachedTokens.refresh_token = refreshParts.refreshToken;
1277
+ }
1278
+ if (isTokenExpired(cachedTokens)) {
1279
+ debugLog3("Token expired, refreshing...");
1280
+ try {
1281
+ const newTokens = await refreshAccessToken(refreshParts.refreshToken, clientId, clientSecret);
1282
+ cachedTokens = {
1283
+ type: "antigravity",
1284
+ access_token: newTokens.access_token,
1285
+ refresh_token: newTokens.refresh_token,
1286
+ expires_in: newTokens.expires_in,
1287
+ timestamp: Date.now()
1288
+ };
1289
+ clearProjectContextCache();
1290
+ const formattedRefresh = formatTokenForStorage(newTokens.refresh_token, refreshParts.projectId || "", refreshParts.managedProjectId);
1291
+ await client.set(providerId, {
1292
+ access: newTokens.access_token,
1293
+ refresh: formattedRefresh,
1294
+ expires: Date.now() + newTokens.expires_in * 1000
1295
+ });
1296
+ debugLog3("Token refreshed successfully");
1297
+ } catch (error) {
1298
+ throw new Error(`Antigravity: Token refresh failed: ${error instanceof Error ? error.message : "Unknown error"}`);
1299
+ }
1300
+ }
1301
+ if (!cachedProjectId) {
1302
+ const projectContext = await fetchProjectContext(cachedTokens.access_token);
1303
+ cachedProjectId = projectContext.cloudaicompanionProject || "";
1304
+ debugLog3(`[PROJECT] Fetched project ID: "${cachedProjectId}"`);
1305
+ }
1306
+ const projectId = cachedProjectId;
1307
+ debugLog3(`[PROJECT] Using project ID: "${projectId}"`);
1308
+ let modelName;
1309
+ if (init.body) {
1310
+ try {
1311
+ const body = typeof init.body === "string" ? JSON.parse(init.body) : init.body;
1312
+ if (typeof body.model === "string") {
1313
+ modelName = body.model;
1314
+ }
1315
+ } catch {}
1316
+ }
1317
+ const maxEndpoints = Math.min(ANTIGRAVITY_ENDPOINT_FALLBACKS.length, 3);
1318
+ const sessionId = getOrCreateSessionId(fetchInstanceId);
1319
+ const thoughtSignature = getThoughtSignature(fetchInstanceId);
1320
+ debugLog3(`[TSIG][GET] sessionId=${sessionId}, signature=${thoughtSignature ? thoughtSignature.substring(0, 20) + "..." : "none"}`);
1321
+ for (let i = 0;i < maxEndpoints; i++) {
1322
+ const endpoint = ANTIGRAVITY_ENDPOINT_FALLBACKS[i];
1323
+ const response = await attemptFetch({
1324
+ endpoint,
1325
+ url,
1326
+ init,
1327
+ accessToken: cachedTokens.access_token,
1328
+ projectId,
1329
+ sessionId,
1330
+ modelName,
1331
+ thoughtSignature
1332
+ });
1333
+ if (response === "pass-through") {
1334
+ debugLog3("Non-string body detected, passing through with auth headers");
1335
+ const headersWithAuth = {
1336
+ ...init.headers,
1337
+ Authorization: `Bearer ${cachedTokens.access_token}`
1338
+ };
1339
+ return fetch(url, { ...init, headers: headersWithAuth });
1340
+ }
1341
+ if (response) {
1342
+ debugLog3(`Success with endpoint: ${endpoint}`);
1343
+ const transformedResponse = await transformResponseWithThinking(response, modelName || "", fetchInstanceId);
1344
+ return transformedResponse;
1345
+ }
1346
+ }
1347
+ const errorMessage = `All Antigravity endpoints failed after ${maxEndpoints} attempts`;
1348
+ debugLog3(errorMessage);
1349
+ return new Response(JSON.stringify({
1350
+ error: {
1351
+ message: errorMessage,
1352
+ type: "endpoint_failure",
1353
+ code: "all_endpoints_failed"
1354
+ }
1355
+ }), {
1356
+ status: 503,
1357
+ statusText: "Service Unavailable",
1358
+ headers: { "Content-Type": "application/json" }
1359
+ });
1360
+ };
1361
+ }
1362
+ // src/auth/antigravity/plugin.ts
1363
+ var GOOGLE_PROVIDER_ID = "google";
1364
+ function isOAuthAuth(auth) {
1365
+ return auth.type === "oauth";
1366
+ }
1367
+ async function createGoogleAntigravityAuthPlugin({
1368
+ client
1369
+ }) {
1370
+ let cachedClientId = ANTIGRAVITY_CLIENT_ID;
1371
+ let cachedClientSecret = ANTIGRAVITY_CLIENT_SECRET;
1372
+ const authHook = {
1373
+ provider: GOOGLE_PROVIDER_ID,
1374
+ loader: async (auth, provider) => {
1375
+ const currentAuth = await auth();
1376
+ if (process.env.ANTIGRAVITY_DEBUG === "1") {
1377
+ console.log("[antigravity-plugin] loader called");
1378
+ console.log("[antigravity-plugin] auth type:", currentAuth?.type);
1379
+ console.log("[antigravity-plugin] auth keys:", Object.keys(currentAuth || {}));
1380
+ }
1381
+ if (!isOAuthAuth(currentAuth)) {
1382
+ if (process.env.ANTIGRAVITY_DEBUG === "1") {
1383
+ console.log("[antigravity-plugin] NOT OAuth auth, returning empty");
1384
+ }
1385
+ return {};
1386
+ }
1387
+ if (process.env.ANTIGRAVITY_DEBUG === "1") {
1388
+ console.log("[antigravity-plugin] OAuth auth detected, creating custom fetch");
1389
+ }
1390
+ cachedClientId = provider.options?.clientId || ANTIGRAVITY_CLIENT_ID;
1391
+ cachedClientSecret = provider.options?.clientSecret || ANTIGRAVITY_CLIENT_SECRET;
1392
+ if (process.env.ANTIGRAVITY_DEBUG === "1" && (cachedClientId !== ANTIGRAVITY_CLIENT_ID || cachedClientSecret !== ANTIGRAVITY_CLIENT_SECRET)) {
1393
+ console.log("[antigravity-plugin] Using custom credentials from provider.options");
1394
+ }
1395
+ const authClient = {
1396
+ set: async (providerId, authData) => {
1397
+ await client.auth.set({
1398
+ body: {
1399
+ type: "oauth",
1400
+ access: authData.access || "",
1401
+ refresh: authData.refresh || "",
1402
+ expires: authData.expires || 0
1403
+ },
1404
+ path: { id: providerId }
1405
+ });
1406
+ }
1407
+ };
1408
+ const getAuth = async () => {
1409
+ const authState = await auth();
1410
+ if (isOAuthAuth(authState)) {
1411
+ return {
1412
+ access: authState.access,
1413
+ refresh: authState.refresh,
1414
+ expires: authState.expires
1415
+ };
1416
+ }
1417
+ return {};
1418
+ };
1419
+ const antigravityFetch = createAntigravityFetch(getAuth, authClient, GOOGLE_PROVIDER_ID, cachedClientId, cachedClientSecret);
1420
+ return {
1421
+ fetch: antigravityFetch,
1422
+ apiKey: "antigravity-oauth"
1423
+ };
1424
+ },
1425
+ methods: [
1426
+ {
1427
+ type: "oauth",
1428
+ label: "OAuth with Google (Antigravity)",
1429
+ authorize: async () => {
1430
+ const serverHandle = startCallbackServer();
1431
+ const { url, verifier } = await buildAuthURL(undefined, cachedClientId, serverHandle.port);
1432
+ return {
1433
+ url,
1434
+ instructions: "Complete the sign-in in your browser. We'll automatically detect when you're done.",
1435
+ method: "auto",
1436
+ callback: async () => {
1437
+ try {
1438
+ const result = await serverHandle.waitForCallback();
1439
+ if (result.error) {
1440
+ if (process.env.ANTIGRAVITY_DEBUG === "1") {
1441
+ console.error(`[antigravity-plugin] OAuth error: ${result.error}`);
1442
+ }
1443
+ return { type: "failed" };
1444
+ }
1445
+ if (!result.code) {
1446
+ if (process.env.ANTIGRAVITY_DEBUG === "1") {
1447
+ console.error("[antigravity-plugin] No authorization code received");
1448
+ }
1449
+ return { type: "failed" };
1450
+ }
1451
+ const state = decodeState(result.state);
1452
+ if (state.verifier !== verifier) {
1453
+ if (process.env.ANTIGRAVITY_DEBUG === "1") {
1454
+ console.error("[antigravity-plugin] PKCE verifier mismatch");
1455
+ }
1456
+ return { type: "failed" };
1457
+ }
1458
+ const tokens = await exchangeCode(result.code, verifier, cachedClientId, cachedClientSecret, serverHandle.port);
1459
+ try {
1460
+ const userInfo = await fetchUserInfo(tokens.access_token);
1461
+ if (process.env.ANTIGRAVITY_DEBUG === "1") {
1462
+ console.log(`[antigravity-plugin] Authenticated as: ${userInfo.email}`);
1463
+ }
1464
+ } catch {}
1465
+ const projectContext = await fetchProjectContext(tokens.access_token);
1466
+ const formattedRefresh = formatTokenForStorage(tokens.refresh_token, projectContext.cloudaicompanionProject || "", projectContext.managedProjectId);
1467
+ return {
1468
+ type: "success",
1469
+ access: tokens.access_token,
1470
+ refresh: formattedRefresh,
1471
+ expires: Date.now() + tokens.expires_in * 1000
1472
+ };
1473
+ } catch (error) {
1474
+ serverHandle.close();
1475
+ if (process.env.ANTIGRAVITY_DEBUG === "1") {
1476
+ console.error(`[antigravity-plugin] OAuth flow failed: ${error instanceof Error ? error.message : "Unknown error"}`);
1477
+ }
1478
+ return { type: "failed" };
1479
+ }
1480
+ }
1481
+ };
1482
+ }
1483
+ }
1484
+ ]
1485
+ };
1486
+ return {
1487
+ auth: authHook
1488
+ };
1489
+ }
1490
+ // src/google-auth.ts
1491
+ var GoogleAntigravityAuthPlugin = async (ctx) => {
1492
+ return createGoogleAntigravityAuthPlugin(ctx);
1493
+ };
1494
+ var google_auth_default = GoogleAntigravityAuthPlugin;
1495
+ export {
1496
+ google_auth_default as default
1497
+ };