@cortexkit/opencode-antigravity-auth 1.0.0 → 1.1.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.
- package/README.md +24 -8
- package/dist/index.js +1450 -467
- package/dist/index.js.map +4 -4
- package/dist/src/plugin/accounts.d.ts +36 -9
- package/dist/src/plugin/accounts.d.ts.map +1 -1
- package/dist/src/plugin/accounts.js +269 -57
- package/dist/src/plugin/accounts.js.map +1 -1
- package/dist/src/plugin/agy-request-metadata.d.ts +2 -0
- package/dist/src/plugin/agy-request-metadata.d.ts.map +1 -0
- package/dist/src/plugin/agy-request-metadata.js +2 -0
- package/dist/src/plugin/agy-request-metadata.js.map +1 -0
- package/dist/src/plugin/auth-doctor.d.ts +1 -1
- package/dist/src/plugin/auth-doctor.d.ts.map +1 -1
- package/dist/src/plugin/auth-doctor.js +9 -0
- package/dist/src/plugin/auth-doctor.js.map +1 -1
- package/dist/src/plugin/debug.d.ts.map +1 -1
- package/dist/src/plugin/debug.js +3 -2
- package/dist/src/plugin/debug.js.map +1 -1
- package/dist/src/plugin/gemini-dump.d.ts.map +1 -1
- package/dist/src/plugin/gemini-dump.js +8 -4
- package/dist/src/plugin/gemini-dump.js.map +1 -1
- package/dist/src/plugin/image-saver.d.ts +2 -21
- package/dist/src/plugin/image-saver.d.ts.map +1 -1
- package/dist/src/plugin/image-saver.js +29 -63
- package/dist/src/plugin/image-saver.js.map +1 -1
- package/dist/src/plugin/request-helpers.d.ts +1 -0
- package/dist/src/plugin/request-helpers.d.ts.map +1 -1
- package/dist/src/plugin/request-helpers.js +9 -4
- package/dist/src/plugin/request-helpers.js.map +1 -1
- package/dist/src/plugin/request.d.ts +15 -4
- package/dist/src/plugin/request.d.ts.map +1 -1
- package/dist/src/plugin/request.js +255 -71
- package/dist/src/plugin/request.js.map +1 -1
- package/dist/src/plugin/session-context.d.ts +21 -0
- package/dist/src/plugin/session-context.d.ts.map +1 -0
- package/dist/src/plugin/session-context.js +63 -0
- package/dist/src/plugin/session-context.js.map +1 -0
- package/dist/src/plugin/storage.d.ts +6 -0
- package/dist/src/plugin/storage.d.ts.map +1 -1
- package/dist/src/plugin/storage.js +27 -6
- package/dist/src/plugin/storage.js.map +1 -1
- package/dist/src/plugin/ui/auth-menu.d.ts +1 -1
- package/dist/src/plugin/ui/auth-menu.d.ts.map +1 -1
- package/dist/src/plugin/ui/auth-menu.js +3 -1
- package/dist/src/plugin/ui/auth-menu.js.map +1 -1
- package/dist/src/plugin/ui/quota-status.d.ts.map +1 -1
- package/dist/src/plugin/ui/quota-status.js +2 -1
- package/dist/src/plugin/ui/quota-status.js.map +1 -1
- package/dist/src/plugin.d.ts +16 -0
- package/dist/src/plugin.d.ts.map +1 -1
- package/dist/src/plugin.js +288 -102
- package/dist/src/plugin.js.map +1 -1
- package/package.json +2 -2
- package/dist/src/plugin/transform/claude.d.ts +0 -92
- package/dist/src/plugin/transform/claude.d.ts.map +0 -1
- package/dist/src/plugin/transform/claude.js +0 -280
- package/dist/src/plugin/transform/claude.js.map +0 -1
- package/dist/src/plugin/transform/gemini.d.ts +0 -100
- package/dist/src/plugin/transform/gemini.d.ts.map +0 -1
- package/dist/src/plugin/transform/gemini.js +0 -446
- package/dist/src/plugin/transform/gemini.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -7,7 +7,6 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
7
7
|
|
|
8
8
|
// src/plugin.ts
|
|
9
9
|
import { exec } from "node:child_process";
|
|
10
|
-
import crypto4 from "node:crypto";
|
|
11
10
|
|
|
12
11
|
// ../../node_modules/@opencode-ai/plugin/dist/tool.js
|
|
13
12
|
import { z } from "zod";
|
|
@@ -67,6 +66,90 @@ function createLogger(module) {
|
|
|
67
66
|
};
|
|
68
67
|
}
|
|
69
68
|
|
|
69
|
+
// ../core/dist/fingerprint.js
|
|
70
|
+
import * as crypto from "node:crypto";
|
|
71
|
+
var AGY_CLI_VERSION = "1.1.5";
|
|
72
|
+
var ANTIGRAVITY_API_CLIENT = "antigravity-cli";
|
|
73
|
+
var MAX_FINGERPRINT_HISTORY = 5;
|
|
74
|
+
function normalizeHarnessPlatform(platform = process.platform) {
|
|
75
|
+
return platform === "win32" ? "windows" : platform || "unknown";
|
|
76
|
+
}
|
|
77
|
+
function normalizeHarnessArch(arch = process.arch) {
|
|
78
|
+
switch (arch) {
|
|
79
|
+
case "x64":
|
|
80
|
+
return "amd64";
|
|
81
|
+
case "ia32":
|
|
82
|
+
return "386";
|
|
83
|
+
default:
|
|
84
|
+
return arch || "unknown";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function buildAntigravityHarnessUserAgent(version = AGY_CLI_VERSION, platform = process.platform, arch = process.arch, authMethod = "consumer") {
|
|
88
|
+
const osType = normalizeHarnessPlatform(platform);
|
|
89
|
+
const normalizedArch = normalizeHarnessArch(arch);
|
|
90
|
+
return `antigravity/cli/${version} (aidev_client; os_type=${osType}; arch=${normalizedArch}; auth_method=${authMethod})`;
|
|
91
|
+
}
|
|
92
|
+
function buildAntigravityHarnessLoadCodeAssistUserAgent(version = AGY_CLI_VERSION) {
|
|
93
|
+
return buildAntigravityHarnessUserAgent(version);
|
|
94
|
+
}
|
|
95
|
+
function platformToMetadataPlatform(platform = process.platform) {
|
|
96
|
+
return platform === "win32" ? "WINDOWS" : "MACOS";
|
|
97
|
+
}
|
|
98
|
+
function buildAntigravityLoadCodeAssistMetadata() {
|
|
99
|
+
return { ideType: "ANTIGRAVITY" };
|
|
100
|
+
}
|
|
101
|
+
function buildAntigravityHarnessBootstrapHeaders(accessToken) {
|
|
102
|
+
return {
|
|
103
|
+
"User-Agent": buildAntigravityHarnessLoadCodeAssistUserAgent(),
|
|
104
|
+
Authorization: `Bearer ${accessToken}`,
|
|
105
|
+
"Content-Type": "application/json",
|
|
106
|
+
"Accept-Encoding": "gzip"
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function generateDeviceId() {
|
|
110
|
+
return crypto.randomUUID();
|
|
111
|
+
}
|
|
112
|
+
function generateSessionToken() {
|
|
113
|
+
return crypto.randomBytes(16).toString("hex");
|
|
114
|
+
}
|
|
115
|
+
function generateFingerprint() {
|
|
116
|
+
return {
|
|
117
|
+
deviceId: generateDeviceId(),
|
|
118
|
+
sessionToken: generateSessionToken(),
|
|
119
|
+
userAgent: buildAntigravityHarnessUserAgent(),
|
|
120
|
+
apiClient: ANTIGRAVITY_API_CLIENT,
|
|
121
|
+
clientMetadata: {
|
|
122
|
+
ideType: "ANTIGRAVITY",
|
|
123
|
+
platform: platformToMetadataPlatform(),
|
|
124
|
+
pluginType: "GEMINI"
|
|
125
|
+
},
|
|
126
|
+
createdAt: Date.now()
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function updateFingerprintVersion(fingerprint) {
|
|
130
|
+
const userAgent = buildAntigravityHarnessUserAgent();
|
|
131
|
+
if (fingerprint.userAgent === userAgent) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
fingerprint.userAgent = userAgent;
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
function buildFingerprintHeaders(fingerprint) {
|
|
138
|
+
if (!fingerprint) {
|
|
139
|
+
return {};
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
"User-Agent": fingerprint.userAgent
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
var sessionFingerprint = null;
|
|
146
|
+
function getSessionFingerprint() {
|
|
147
|
+
if (!sessionFingerprint) {
|
|
148
|
+
sessionFingerprint = generateFingerprint();
|
|
149
|
+
}
|
|
150
|
+
return sessionFingerprint;
|
|
151
|
+
}
|
|
152
|
+
|
|
70
153
|
// ../core/dist/constants.js
|
|
71
154
|
var ANTIGRAVITY_CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com";
|
|
72
155
|
var ANTIGRAVITY_CLIENT_SECRET = "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";
|
|
@@ -122,11 +205,6 @@ var GEMINI_CLI_HEADERS = {
|
|
|
122
205
|
"X-Goog-Api-Client": "gl-node/22.17.0",
|
|
123
206
|
"Client-Metadata": "ideType=IDE_UNSPECIFIED,platform=PLATFORM_UNSPECIFIED,pluginType=GEMINI"
|
|
124
207
|
};
|
|
125
|
-
function buildAntigravityPlatformArch() {
|
|
126
|
-
const platform = process.platform === "win32" ? "windows" : process.platform || "unknown";
|
|
127
|
-
const arch = process.arch === "x64" ? "amd64" : process.arch === "ia32" ? "386" : process.arch || "unknown";
|
|
128
|
-
return `${platform}/${arch}`;
|
|
129
|
-
}
|
|
130
208
|
function getRandomizedHeaders(style, model) {
|
|
131
209
|
if (style === "gemini-cli") {
|
|
132
210
|
return {
|
|
@@ -135,9 +213,8 @@ function getRandomizedHeaders(style, model) {
|
|
|
135
213
|
"Client-Metadata": GEMINI_CLI_HEADERS["Client-Metadata"]
|
|
136
214
|
};
|
|
137
215
|
}
|
|
138
|
-
const platform = buildAntigravityPlatformArch();
|
|
139
216
|
return {
|
|
140
|
-
"User-Agent":
|
|
217
|
+
"User-Agent": buildAntigravityHarnessUserAgent()
|
|
141
218
|
};
|
|
142
219
|
}
|
|
143
220
|
var ANTIGRAVITY_PROVIDER_ID = "google";
|
|
@@ -205,91 +282,6 @@ function calculateTokenExpiry(requestTimeMs, expiresInSeconds) {
|
|
|
205
282
|
return requestTimeMs + seconds * 1e3;
|
|
206
283
|
}
|
|
207
284
|
|
|
208
|
-
// ../core/dist/fingerprint.js
|
|
209
|
-
import * as crypto from "node:crypto";
|
|
210
|
-
var AGY_CLI_VERSION = "1.0.4";
|
|
211
|
-
var ANTIGRAVITY_API_CLIENT = "antigravity-cli";
|
|
212
|
-
var MAX_FINGERPRINT_HISTORY = 5;
|
|
213
|
-
function normalizeHarnessPlatform(platform = process.platform) {
|
|
214
|
-
return platform === "win32" ? "windows" : platform || "unknown";
|
|
215
|
-
}
|
|
216
|
-
function normalizeHarnessArch(arch = process.arch) {
|
|
217
|
-
switch (arch) {
|
|
218
|
-
case "x64":
|
|
219
|
-
return "amd64";
|
|
220
|
-
case "ia32":
|
|
221
|
-
return "386";
|
|
222
|
-
default:
|
|
223
|
-
return arch || "unknown";
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
function buildAntigravityHarnessPlatformArch(platform = process.platform, arch = process.arch) {
|
|
227
|
-
return `${normalizeHarnessPlatform(platform)}/${normalizeHarnessArch(arch)}`;
|
|
228
|
-
}
|
|
229
|
-
function buildAntigravityHarnessUserAgent(version = AGY_CLI_VERSION, platform = process.platform, arch = process.arch) {
|
|
230
|
-
return `antigravity/cli/${version} ${buildAntigravityHarnessPlatformArch(platform, arch)}`;
|
|
231
|
-
}
|
|
232
|
-
function buildAntigravityHarnessLoadCodeAssistUserAgent(version = AGY_CLI_VERSION) {
|
|
233
|
-
return buildAntigravityHarnessUserAgent(version);
|
|
234
|
-
}
|
|
235
|
-
function platformToMetadataPlatform(platform = process.platform) {
|
|
236
|
-
return platform === "win32" ? "WINDOWS" : "MACOS";
|
|
237
|
-
}
|
|
238
|
-
function buildAntigravityLoadCodeAssistMetadata() {
|
|
239
|
-
return { ideType: "ANTIGRAVITY" };
|
|
240
|
-
}
|
|
241
|
-
function buildAntigravityHarnessBootstrapHeaders(accessToken) {
|
|
242
|
-
return {
|
|
243
|
-
"User-Agent": buildAntigravityHarnessLoadCodeAssistUserAgent(),
|
|
244
|
-
Authorization: `Bearer ${accessToken}`,
|
|
245
|
-
"Content-Type": "application/json",
|
|
246
|
-
"Accept-Encoding": "gzip"
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
function generateDeviceId() {
|
|
250
|
-
return crypto.randomUUID();
|
|
251
|
-
}
|
|
252
|
-
function generateSessionToken() {
|
|
253
|
-
return crypto.randomBytes(16).toString("hex");
|
|
254
|
-
}
|
|
255
|
-
function generateFingerprint() {
|
|
256
|
-
return {
|
|
257
|
-
deviceId: generateDeviceId(),
|
|
258
|
-
sessionToken: generateSessionToken(),
|
|
259
|
-
userAgent: buildAntigravityHarnessUserAgent(),
|
|
260
|
-
apiClient: ANTIGRAVITY_API_CLIENT,
|
|
261
|
-
clientMetadata: {
|
|
262
|
-
ideType: "ANTIGRAVITY",
|
|
263
|
-
platform: platformToMetadataPlatform(),
|
|
264
|
-
pluginType: "GEMINI"
|
|
265
|
-
},
|
|
266
|
-
createdAt: Date.now()
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
function updateFingerprintVersion(fingerprint) {
|
|
270
|
-
const userAgent = buildAntigravityHarnessUserAgent();
|
|
271
|
-
if (fingerprint.userAgent === userAgent) {
|
|
272
|
-
return false;
|
|
273
|
-
}
|
|
274
|
-
fingerprint.userAgent = userAgent;
|
|
275
|
-
return true;
|
|
276
|
-
}
|
|
277
|
-
function buildFingerprintHeaders(fingerprint) {
|
|
278
|
-
if (!fingerprint) {
|
|
279
|
-
return {};
|
|
280
|
-
}
|
|
281
|
-
return {
|
|
282
|
-
"User-Agent": fingerprint.userAgent
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
var sessionFingerprint = null;
|
|
286
|
-
function getSessionFingerprint() {
|
|
287
|
-
if (!sessionFingerprint) {
|
|
288
|
-
sessionFingerprint = generateFingerprint();
|
|
289
|
-
}
|
|
290
|
-
return sessionFingerprint;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
285
|
// ../core/dist/agy-transport.js
|
|
294
286
|
import * as net from "node:net";
|
|
295
287
|
import * as tls from "node:tls";
|
|
@@ -299,6 +291,7 @@ import { createGunzip } from "node:zlib";
|
|
|
299
291
|
var DEFAULT_HTTPS_PORT = 443;
|
|
300
292
|
var DEFAULT_PROXY_PORT = 8080;
|
|
301
293
|
var DEFAULT_AGY_RESPONSE_HEADER_TIMEOUT_MS = 18e4;
|
|
294
|
+
var DEFAULT_AGY_IDLE_TIMEOUT_MS = 18e4;
|
|
302
295
|
function headersToRecord(headers) {
|
|
303
296
|
const result = {};
|
|
304
297
|
if (!headers)
|
|
@@ -331,7 +324,7 @@ function buildAgyCliHeaderPairs(url, init = {}) {
|
|
|
331
324
|
const headers = headersToRecord(init.headers);
|
|
332
325
|
const body = bodyToBuffer(init.body);
|
|
333
326
|
const host = parsedUrl.port ? `${parsedUrl.hostname}:${parsedUrl.port}` : parsedUrl.hostname;
|
|
334
|
-
const userAgent = getHeader(headers, "User-Agent") ??
|
|
327
|
+
const userAgent = getHeader(headers, "User-Agent") ?? buildAntigravityHarnessUserAgent();
|
|
335
328
|
const authorization = getHeader(headers, "Authorization");
|
|
336
329
|
const contentType = getHeader(headers, "Content-Type") ?? "application/json";
|
|
337
330
|
const acceptEncoding = getHeader(headers, "Accept-Encoding") ?? "gzip";
|
|
@@ -380,7 +373,7 @@ function getHttpsProxy(url) {
|
|
|
380
373
|
}
|
|
381
374
|
}
|
|
382
375
|
function waitForHead(socket, timeoutMs, onTimeout) {
|
|
383
|
-
return new Promise((
|
|
376
|
+
return new Promise((resolve2, reject) => {
|
|
384
377
|
let buffer = Buffer2.alloc(0);
|
|
385
378
|
const timeout = setTimeout(() => {
|
|
386
379
|
onTimeout();
|
|
@@ -400,7 +393,7 @@ function waitForHead(socket, timeoutMs, onTimeout) {
|
|
|
400
393
|
return;
|
|
401
394
|
const head = buffer.subarray(0, marker).toString("latin1");
|
|
402
395
|
const leftover = buffer.subarray(marker + 4);
|
|
403
|
-
cleanup(() =>
|
|
396
|
+
cleanup(() => resolve2({ head, leftover }));
|
|
404
397
|
};
|
|
405
398
|
socket.on("data", onData);
|
|
406
399
|
socket.once("error", onError);
|
|
@@ -411,7 +404,7 @@ async function connectViaProxy(proxyUrl, targetUrl, timeoutMs, onDebug) {
|
|
|
411
404
|
host: proxyUrl.hostname,
|
|
412
405
|
port: Number(proxyUrl.port || DEFAULT_PROXY_PORT)
|
|
413
406
|
});
|
|
414
|
-
await new Promise((
|
|
407
|
+
await new Promise((resolve2, reject) => {
|
|
415
408
|
const timeout = setTimeout(() => {
|
|
416
409
|
onDebug?.(`agy transport proxy connect timeout after ${timeoutMs}ms`);
|
|
417
410
|
proxySocket.destroy();
|
|
@@ -420,7 +413,7 @@ async function connectViaProxy(proxyUrl, targetUrl, timeoutMs, onDebug) {
|
|
|
420
413
|
const cleanup = () => clearTimeout(timeout);
|
|
421
414
|
proxySocket.once("connect", () => {
|
|
422
415
|
cleanup();
|
|
423
|
-
|
|
416
|
+
resolve2();
|
|
424
417
|
});
|
|
425
418
|
proxySocket.once("error", (error) => {
|
|
426
419
|
cleanup();
|
|
@@ -445,7 +438,7 @@ Host: ${targetHost}:${targetPort}\r
|
|
|
445
438
|
if (leftover.length > 0) {
|
|
446
439
|
proxySocket.unshift(leftover);
|
|
447
440
|
}
|
|
448
|
-
return await new Promise((
|
|
441
|
+
return await new Promise((resolve2, reject) => {
|
|
449
442
|
const tlsSocket = tls.connect({ socket: proxySocket, servername: targetHost });
|
|
450
443
|
const timeout = setTimeout(() => {
|
|
451
444
|
onDebug?.(`agy transport proxy TLS handshake timeout after ${timeoutMs}ms`);
|
|
@@ -455,7 +448,7 @@ Host: ${targetHost}:${targetPort}\r
|
|
|
455
448
|
const cleanup = () => clearTimeout(timeout);
|
|
456
449
|
tlsSocket.once("secureConnect", () => {
|
|
457
450
|
cleanup();
|
|
458
|
-
|
|
451
|
+
resolve2(tlsSocket);
|
|
459
452
|
});
|
|
460
453
|
tlsSocket.once("error", (error) => {
|
|
461
454
|
cleanup();
|
|
@@ -464,7 +457,7 @@ Host: ${targetHost}:${targetPort}\r
|
|
|
464
457
|
});
|
|
465
458
|
}
|
|
466
459
|
async function connectDirect(targetUrl, timeoutMs, onDebug) {
|
|
467
|
-
return await new Promise((
|
|
460
|
+
return await new Promise((resolve2, reject) => {
|
|
468
461
|
const socket = tls.connect({
|
|
469
462
|
host: targetUrl.hostname,
|
|
470
463
|
port: Number(targetUrl.port || DEFAULT_HTTPS_PORT),
|
|
@@ -478,7 +471,7 @@ async function connectDirect(targetUrl, timeoutMs, onDebug) {
|
|
|
478
471
|
const cleanup = () => clearTimeout(timeout);
|
|
479
472
|
socket.once("secureConnect", () => {
|
|
480
473
|
cleanup();
|
|
481
|
-
|
|
474
|
+
resolve2(socket);
|
|
482
475
|
});
|
|
483
476
|
socket.once("error", (error) => {
|
|
484
477
|
cleanup();
|
|
@@ -492,9 +485,9 @@ async function connectTls(targetUrl, timeoutMs, onDebug) {
|
|
|
492
485
|
}
|
|
493
486
|
function serializeRequest(url, init, body) {
|
|
494
487
|
const method = init.method ?? "POST";
|
|
495
|
-
const
|
|
488
|
+
const path4 = `${url.pathname}${url.search}`;
|
|
496
489
|
const headerLines = buildAgyCliHeaderPairs(url.toString(), init).map(([key, value]) => `${key}: ${value}`).join("\r\n");
|
|
497
|
-
const head = Buffer2.from(`${method} ${
|
|
490
|
+
const head = Buffer2.from(`${method} ${path4} HTTP/1.1\r
|
|
498
491
|
${headerLines}\r
|
|
499
492
|
\r
|
|
500
493
|
`);
|
|
@@ -522,6 +515,7 @@ function parseResponseHead(head) {
|
|
|
522
515
|
const headers = new Headers();
|
|
523
516
|
let chunked = false;
|
|
524
517
|
let gzip = false;
|
|
518
|
+
let contentLength;
|
|
525
519
|
for (const line of lines) {
|
|
526
520
|
const index = line.indexOf(":");
|
|
527
521
|
if (index <= 0)
|
|
@@ -538,8 +532,13 @@ function parseResponseHead(head) {
|
|
|
538
532
|
gzip = true;
|
|
539
533
|
continue;
|
|
540
534
|
}
|
|
541
|
-
if (
|
|
542
|
-
|
|
535
|
+
if (lowerKey === "content-length") {
|
|
536
|
+
const parsed = Number.parseInt(value, 10);
|
|
537
|
+
if (Number.isFinite(parsed) && parsed >= 0) {
|
|
538
|
+
contentLength = parsed;
|
|
539
|
+
}
|
|
540
|
+
if (gzip)
|
|
541
|
+
continue;
|
|
543
542
|
}
|
|
544
543
|
headers.append(key, value);
|
|
545
544
|
}
|
|
@@ -548,9 +547,34 @@ function parseResponseHead(head) {
|
|
|
548
547
|
statusText: match[2] ?? "",
|
|
549
548
|
headers,
|
|
550
549
|
chunked,
|
|
551
|
-
gzip
|
|
550
|
+
gzip,
|
|
551
|
+
contentLength
|
|
552
552
|
};
|
|
553
553
|
}
|
|
554
|
+
var ContentLengthStream = class extends Transform {
|
|
555
|
+
remaining;
|
|
556
|
+
constructor(contentLength) {
|
|
557
|
+
super();
|
|
558
|
+
this.remaining = contentLength;
|
|
559
|
+
}
|
|
560
|
+
_transform(chunk, _encoding, callback) {
|
|
561
|
+
if (this.remaining <= 0) {
|
|
562
|
+
callback();
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
if (chunk.length <= this.remaining) {
|
|
566
|
+
this.remaining -= chunk.length;
|
|
567
|
+
this.push(chunk);
|
|
568
|
+
} else {
|
|
569
|
+
this.push(chunk.subarray(0, this.remaining));
|
|
570
|
+
this.remaining = 0;
|
|
571
|
+
}
|
|
572
|
+
if (this.remaining <= 0) {
|
|
573
|
+
this.push(null);
|
|
574
|
+
}
|
|
575
|
+
callback();
|
|
576
|
+
}
|
|
577
|
+
};
|
|
554
578
|
var ChunkedDecodeStream = class extends Transform {
|
|
555
579
|
buffer = Buffer2.alloc(0);
|
|
556
580
|
_transform(chunk, _encoding, callback) {
|
|
@@ -596,7 +620,7 @@ var ChunkedDecodeStream = class extends Transform {
|
|
|
596
620
|
}
|
|
597
621
|
}
|
|
598
622
|
};
|
|
599
|
-
function buildResponseStream(socket, leftover, head, signal) {
|
|
623
|
+
function buildResponseStream(socket, leftover, head, signal, idleTimeoutMs, onDebug) {
|
|
600
624
|
const source = new PassThrough();
|
|
601
625
|
if (leftover.length > 0) {
|
|
602
626
|
source.write(leftover);
|
|
@@ -605,12 +629,36 @@ function buildResponseStream(socket, leftover, head, signal) {
|
|
|
605
629
|
let responseBody = source;
|
|
606
630
|
if (head.chunked) {
|
|
607
631
|
responseBody = responseBody.pipe(new ChunkedDecodeStream());
|
|
632
|
+
} else if (typeof head.contentLength === "number") {
|
|
633
|
+
responseBody = responseBody.pipe(new ContentLengthStream(head.contentLength));
|
|
608
634
|
}
|
|
609
635
|
if (head.gzip) {
|
|
610
636
|
responseBody = responseBody.pipe(createGunzip());
|
|
611
637
|
}
|
|
638
|
+
let idleTimer;
|
|
639
|
+
const clearIdle = () => {
|
|
640
|
+
if (idleTimer) {
|
|
641
|
+
clearTimeout(idleTimer);
|
|
642
|
+
idleTimer = void 0;
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
const armIdle = () => {
|
|
646
|
+
if (!idleTimeoutMs || idleTimeoutMs <= 0)
|
|
647
|
+
return;
|
|
648
|
+
clearIdle();
|
|
649
|
+
idleTimer = setTimeout(() => {
|
|
650
|
+
onDebug?.(`agy transport idle timeout after ${idleTimeoutMs}ms with no body data`);
|
|
651
|
+
socket.destroy(new Error(`Antigravity response stalled: no data for ${idleTimeoutMs}ms`));
|
|
652
|
+
}, idleTimeoutMs);
|
|
653
|
+
};
|
|
654
|
+
socket.on("data", armIdle);
|
|
655
|
+
armIdle();
|
|
612
656
|
const abort = () => socket.destroy(new DOMException("The operation was aborted", "AbortError"));
|
|
613
|
-
const cleanup = () =>
|
|
657
|
+
const cleanup = () => {
|
|
658
|
+
clearIdle();
|
|
659
|
+
socket.off("data", armIdle);
|
|
660
|
+
signal?.removeEventListener("abort", abort);
|
|
661
|
+
};
|
|
614
662
|
if (signal?.aborted) {
|
|
615
663
|
abort();
|
|
616
664
|
} else {
|
|
@@ -632,11 +680,15 @@ async function fetchWithAgyCliTransport(url, init = {}, options = {}) {
|
|
|
632
680
|
if (parsedUrl.protocol !== "https:") {
|
|
633
681
|
throw new Error(`agy transport only supports https URLs: ${url}`);
|
|
634
682
|
}
|
|
683
|
+
if (options.signal?.aborted) {
|
|
684
|
+
throw new DOMException("The operation was aborted", "AbortError");
|
|
685
|
+
}
|
|
635
686
|
const body = bodyToBuffer(init.body);
|
|
636
687
|
const requestBytes = serializeRequest(parsedUrl, init, body);
|
|
637
688
|
const timeoutMs = options.timeoutMs ?? DEFAULT_AGY_RESPONSE_HEADER_TIMEOUT_MS;
|
|
689
|
+
const idleTimeoutMs = options.idleTimeoutMs ?? DEFAULT_AGY_IDLE_TIMEOUT_MS;
|
|
638
690
|
options.onDebug?.(`agy transport connecting to ${parsedUrl.hostname} with header timeout ${timeoutMs}ms`);
|
|
639
|
-
const socket = await
|
|
691
|
+
const socket = await connectTlsWithAbort(parsedUrl, timeoutMs, options.signal, options.onDebug);
|
|
640
692
|
const abort = () => {
|
|
641
693
|
socket.destroy(new DOMException("The operation was aborted", "AbortError"));
|
|
642
694
|
};
|
|
@@ -650,7 +702,7 @@ async function fetchWithAgyCliTransport(url, init = {}, options = {}) {
|
|
|
650
702
|
});
|
|
651
703
|
const parsedHead = parseResponseHead(head);
|
|
652
704
|
options.onDebug?.(`agy transport response headers received: ${parsedHead.status} ${parsedHead.statusText}`);
|
|
653
|
-
const bodyStream = buildResponseStream(socket, leftover, parsedHead, options.signal);
|
|
705
|
+
const bodyStream = buildResponseStream(socket, leftover, parsedHead, options.signal, idleTimeoutMs, options.onDebug);
|
|
654
706
|
return new Response(bodyStream, {
|
|
655
707
|
status: parsedHead.status,
|
|
656
708
|
statusText: parsedHead.statusText,
|
|
@@ -663,6 +715,199 @@ async function fetchWithAgyCliTransport(url, init = {}, options = {}) {
|
|
|
663
715
|
options.signal?.removeEventListener("abort", abort);
|
|
664
716
|
}
|
|
665
717
|
}
|
|
718
|
+
async function connectTlsWithAbort(targetUrl, timeoutMs, signal, onDebug) {
|
|
719
|
+
if (!signal) {
|
|
720
|
+
return connectTls(targetUrl, timeoutMs, onDebug);
|
|
721
|
+
}
|
|
722
|
+
const connectPromise = connectTls(targetUrl, timeoutMs, onDebug);
|
|
723
|
+
let onAbort;
|
|
724
|
+
const abortPromise = new Promise((_, reject) => {
|
|
725
|
+
onAbort = () => reject(new DOMException("The operation was aborted", "AbortError"));
|
|
726
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
727
|
+
});
|
|
728
|
+
try {
|
|
729
|
+
return await Promise.race([connectPromise, abortPromise]);
|
|
730
|
+
} catch (error) {
|
|
731
|
+
void connectPromise.then((socket) => socket.destroy()).catch(() => {
|
|
732
|
+
});
|
|
733
|
+
throw error;
|
|
734
|
+
} finally {
|
|
735
|
+
if (onAbort)
|
|
736
|
+
signal.removeEventListener("abort", onAbort);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// ../core/dist/agy-request-metadata.js
|
|
741
|
+
import { Buffer as Buffer3 } from "node:buffer";
|
|
742
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
743
|
+
var FNV1A_64_OFFSET_BASIS = 0xcbf29ce484222325n;
|
|
744
|
+
var FNV1A_64_PRIME = 0x100000001b3n;
|
|
745
|
+
var DEFAULT_SESSION_STATE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
746
|
+
var DEFAULT_MAX_SESSION_STATES = 256;
|
|
747
|
+
var AGY_REQUEST_FIELD_ORDER = [
|
|
748
|
+
"contents",
|
|
749
|
+
"systemInstruction",
|
|
750
|
+
"tools",
|
|
751
|
+
"toolConfig",
|
|
752
|
+
"labels",
|
|
753
|
+
"generationConfig",
|
|
754
|
+
"sessionId"
|
|
755
|
+
];
|
|
756
|
+
var AGY_MODEL_ENUM_BY_WIRE_MODEL = {
|
|
757
|
+
"gemini-3.5-flash-extra-low": "MODEL_PLACEHOLDER_M187",
|
|
758
|
+
"gemini-3.5-flash-low": "MODEL_PLACEHOLDER_M20",
|
|
759
|
+
"gemini-3-flash-agent": "MODEL_PLACEHOLDER_M84",
|
|
760
|
+
"gemini-3.6-flash-low": "MODEL_PLACEHOLDER_M266",
|
|
761
|
+
"gemini-3.6-flash-medium": "MODEL_PLACEHOLDER_M265",
|
|
762
|
+
"gemini-3.6-flash-high": "MODEL_PLACEHOLDER_M264",
|
|
763
|
+
"gemini-3.1-pro-low": "MODEL_PLACEHOLDER_M36",
|
|
764
|
+
"gemini-pro-agent": "MODEL_PLACEHOLDER_M16",
|
|
765
|
+
"claude-sonnet-4-6": "MODEL_PLACEHOLDER_M35",
|
|
766
|
+
"claude-opus-4-6-thinking": "MODEL_PLACEHOLDER_M26",
|
|
767
|
+
"gemini-3.1-flash-image": "MODEL_PLACEHOLDER_M21",
|
|
768
|
+
"gpt-oss-120b-medium": "MODEL_OPENAI_GPT_OSS_120B_MEDIUM"
|
|
769
|
+
};
|
|
770
|
+
function fnv1a64Signed(input2) {
|
|
771
|
+
let hash = FNV1A_64_OFFSET_BASIS;
|
|
772
|
+
for (const byte of Buffer3.from(input2, "utf8")) {
|
|
773
|
+
hash ^= BigInt(byte);
|
|
774
|
+
hash = BigInt.asUintN(64, hash * FNV1A_64_PRIME);
|
|
775
|
+
}
|
|
776
|
+
return BigInt.asIntN(64, hash).toString();
|
|
777
|
+
}
|
|
778
|
+
function createAgyRequestSessionContext(workspaceUri, ids = {}) {
|
|
779
|
+
return {
|
|
780
|
+
conversationId: ids.conversationId ?? randomUUID2(),
|
|
781
|
+
trajectoryId: ids.trajectoryId ?? randomUUID2(),
|
|
782
|
+
numericSessionId: fnv1a64Signed(workspaceUri)
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
var AgyRequestSessionStore = class {
|
|
786
|
+
entries = /* @__PURE__ */ new Map();
|
|
787
|
+
workspaceUri;
|
|
788
|
+
ttlMs;
|
|
789
|
+
maxEntries;
|
|
790
|
+
now;
|
|
791
|
+
constructor(workspaceUri, options = {}) {
|
|
792
|
+
this.workspaceUri = workspaceUri;
|
|
793
|
+
this.ttlMs = options.ttlMs ?? DEFAULT_SESSION_STATE_TTL_MS;
|
|
794
|
+
this.maxEntries = options.maxEntries ?? DEFAULT_MAX_SESSION_STATES;
|
|
795
|
+
this.now = options.now ?? Date.now;
|
|
796
|
+
}
|
|
797
|
+
getOrCreate(key) {
|
|
798
|
+
const timestamp = this.now();
|
|
799
|
+
this.prune(timestamp, key);
|
|
800
|
+
const existing = this.entries.get(key);
|
|
801
|
+
if (existing) {
|
|
802
|
+
existing.lastAccessedAt = timestamp;
|
|
803
|
+
return existing.context;
|
|
804
|
+
}
|
|
805
|
+
const context = createAgyRequestSessionContext(this.workspaceUri);
|
|
806
|
+
this.entries.set(key, {
|
|
807
|
+
context,
|
|
808
|
+
lastAccessedAt: timestamp,
|
|
809
|
+
lastRequestTimestamp: 0
|
|
810
|
+
});
|
|
811
|
+
return context;
|
|
812
|
+
}
|
|
813
|
+
beginRequest(key) {
|
|
814
|
+
const session = this.getOrCreate(key);
|
|
815
|
+
const stored = this.entries.get(key);
|
|
816
|
+
const timestamp = Math.max(stored.lastAccessedAt, stored.lastRequestTimestamp + 1);
|
|
817
|
+
stored.lastRequestTimestamp = timestamp;
|
|
818
|
+
return { session, timestamp };
|
|
819
|
+
}
|
|
820
|
+
has(key) {
|
|
821
|
+
return this.entries.has(key);
|
|
822
|
+
}
|
|
823
|
+
delete(key) {
|
|
824
|
+
this.entries.delete(key);
|
|
825
|
+
}
|
|
826
|
+
get size() {
|
|
827
|
+
return this.entries.size;
|
|
828
|
+
}
|
|
829
|
+
prune(timestamp, preservedKey) {
|
|
830
|
+
const expiry = timestamp - this.ttlMs;
|
|
831
|
+
for (const [key, value] of this.entries) {
|
|
832
|
+
if (key !== preservedKey && value.lastAccessedAt < expiry) {
|
|
833
|
+
this.entries.delete(key);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
while (this.entries.size >= this.maxEntries && !this.entries.has(preservedKey)) {
|
|
837
|
+
let oldestKey = null;
|
|
838
|
+
let oldestAccess = Number.POSITIVE_INFINITY;
|
|
839
|
+
for (const [key, value] of this.entries) {
|
|
840
|
+
if (key !== preservedKey && value.lastAccessedAt < oldestAccess) {
|
|
841
|
+
oldestKey = key;
|
|
842
|
+
oldestAccess = value.lastAccessedAt;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
if (!oldestKey) {
|
|
846
|
+
break;
|
|
847
|
+
}
|
|
848
|
+
this.entries.delete(oldestKey);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
function getAgyModelEnum(model) {
|
|
853
|
+
return AGY_MODEL_ENUM_BY_WIRE_MODEL[model.toLowerCase()];
|
|
854
|
+
}
|
|
855
|
+
function orderAgyRequestPayloadInPlace(payload) {
|
|
856
|
+
const ordered = {};
|
|
857
|
+
const remaining = new Set(Object.keys(payload));
|
|
858
|
+
for (const key of AGY_REQUEST_FIELD_ORDER) {
|
|
859
|
+
if (key in payload) {
|
|
860
|
+
ordered[key] = payload[key];
|
|
861
|
+
remaining.delete(key);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
for (const key of remaining) {
|
|
865
|
+
ordered[key] = payload[key];
|
|
866
|
+
}
|
|
867
|
+
for (const key of Object.keys(payload)) {
|
|
868
|
+
delete payload[key];
|
|
869
|
+
}
|
|
870
|
+
Object.assign(payload, ordered);
|
|
871
|
+
}
|
|
872
|
+
function countAgyRequestSteps(payload) {
|
|
873
|
+
const contents = payload.contents;
|
|
874
|
+
if (!Array.isArray(contents)) {
|
|
875
|
+
return 1;
|
|
876
|
+
}
|
|
877
|
+
let partCount = 0;
|
|
878
|
+
for (const content of contents) {
|
|
879
|
+
if (!content || typeof content !== "object" || Array.isArray(content)) {
|
|
880
|
+
continue;
|
|
881
|
+
}
|
|
882
|
+
const parts = content.parts;
|
|
883
|
+
if (Array.isArray(parts)) {
|
|
884
|
+
partCount += parts.length;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
return Math.max(1, partCount);
|
|
888
|
+
}
|
|
889
|
+
function buildAgyAgentRequestMetadata(session, payload, model, timestamp = Date.now()) {
|
|
890
|
+
const lastStepIndex = countAgyRequestSteps(payload);
|
|
891
|
+
const isClaude = model.toLowerCase().startsWith("claude-");
|
|
892
|
+
const isNonGemini = isClaude || model.toLowerCase().startsWith("gpt-");
|
|
893
|
+
session.usedClaude = session.usedClaude === true || isClaude;
|
|
894
|
+
session.usedNonGeminiModel = session.usedNonGeminiModel === true || isNonGemini;
|
|
895
|
+
const modelEnum = getAgyModelEnum(model);
|
|
896
|
+
const labels = {
|
|
897
|
+
last_step_index: String(lastStepIndex),
|
|
898
|
+
...modelEnum ? { model_enum: modelEnum } : {},
|
|
899
|
+
trajectory_id: session.trajectoryId,
|
|
900
|
+
used_claude: session.usedClaude ? "true" : "false",
|
|
901
|
+
used_claude_conservative: session.usedClaude ? "true" : "false",
|
|
902
|
+
used_non_gemini_model: session.usedNonGeminiModel ? "true" : "false"
|
|
903
|
+
};
|
|
904
|
+
return {
|
|
905
|
+
requestId: `agent/${session.conversationId}/${timestamp}/${session.trajectoryId}/${lastStepIndex + 1}`,
|
|
906
|
+
sessionId: session.numericSessionId,
|
|
907
|
+
labels,
|
|
908
|
+
lastStepIndex
|
|
909
|
+
};
|
|
910
|
+
}
|
|
666
911
|
|
|
667
912
|
// ../core/dist/version.js
|
|
668
913
|
var VERSION_URL = "https://antigravity-auto-updater-974169037036.us-central1.run.app";
|
|
@@ -749,8 +994,8 @@ function getDefaultTierId(allowedTiers) {
|
|
|
749
994
|
return allowedTiers[0]?.id;
|
|
750
995
|
}
|
|
751
996
|
function wait(ms) {
|
|
752
|
-
return new Promise(function(
|
|
753
|
-
setTimeout(
|
|
997
|
+
return new Promise(function(resolve2) {
|
|
998
|
+
setTimeout(resolve2, ms);
|
|
754
999
|
});
|
|
755
1000
|
}
|
|
756
1001
|
function extractManagedProjectId(payload) {
|
|
@@ -954,6 +1199,16 @@ var ALL_MODEL_DEFINITIONS = {
|
|
|
954
1199
|
high: { thinkingLevel: "high" }
|
|
955
1200
|
}
|
|
956
1201
|
}),
|
|
1202
|
+
"antigravity-gemini-3.6-flash": defineModel("antigravity-gemini-3.6-flash", {
|
|
1203
|
+
name: "Gemini 3.6 Flash (Antigravity)",
|
|
1204
|
+
reasoning: true,
|
|
1205
|
+
limit: { context: 1048576, output: 65536 },
|
|
1206
|
+
modalities: DEFAULT_MODALITIES,
|
|
1207
|
+
variants: {
|
|
1208
|
+
low: { thinkingLevel: "low" },
|
|
1209
|
+
high: { thinkingLevel: "high" }
|
|
1210
|
+
}
|
|
1211
|
+
}),
|
|
957
1212
|
"antigravity-gemini-3.5-flash": defineModel("antigravity-gemini-3.5-flash", {
|
|
958
1213
|
name: "Gemini 3.5 Flash (Antigravity)",
|
|
959
1214
|
reasoning: true,
|
|
@@ -993,14 +1248,11 @@ var ALL_MODEL_DEFINITIONS = {
|
|
|
993
1248
|
output: ["text", "image"]
|
|
994
1249
|
}
|
|
995
1250
|
}),
|
|
996
|
-
"antigravity-gpt-oss-120b": defineModel("antigravity-gpt-oss-120b", {
|
|
997
|
-
name: "GPT-OSS 120B (Antigravity)",
|
|
998
|
-
reasoning:
|
|
999
|
-
limit: { context:
|
|
1000
|
-
modalities: DEFAULT_MODALITIES
|
|
1001
|
-
variants: {
|
|
1002
|
-
medium: {}
|
|
1003
|
-
}
|
|
1251
|
+
"antigravity-gpt-oss-120b-medium": defineModel("antigravity-gpt-oss-120b-medium", {
|
|
1252
|
+
name: "GPT-OSS 120B Medium (Antigravity)",
|
|
1253
|
+
reasoning: true,
|
|
1254
|
+
limit: { context: 131072, output: 32768 },
|
|
1255
|
+
modalities: DEFAULT_MODALITIES
|
|
1004
1256
|
}),
|
|
1005
1257
|
"gemini-2.5-flash": defineModel("gemini-2.5-flash", {
|
|
1006
1258
|
name: "Gemini 2.5 Flash (Gemini CLI)",
|
|
@@ -1066,6 +1318,9 @@ var RESOLVER_ALIASES = {
|
|
|
1066
1318
|
"gemini-3.5-flash-low": "gemini-3.5-flash",
|
|
1067
1319
|
"gemini-3.5-flash-medium": "gemini-3.5-flash",
|
|
1068
1320
|
"gemini-3.5-flash-high": "gemini-3.5-flash",
|
|
1321
|
+
"gemini-3.6-flash-low": "gemini-3.6-flash",
|
|
1322
|
+
"gemini-3.6-flash-medium": "gemini-3.6-flash",
|
|
1323
|
+
"gemini-3.6-flash-high": "gemini-3.6-flash",
|
|
1069
1324
|
"gemini-claude-opus-4-6-thinking-low": "claude-opus-4-6-thinking",
|
|
1070
1325
|
"gemini-claude-opus-4-6-thinking-medium": "claude-opus-4-6-thinking",
|
|
1071
1326
|
"gemini-claude-opus-4-6-thinking-high": "claude-opus-4-6-thinking",
|
|
@@ -1076,7 +1331,8 @@ var RESOLVER_ALIASES = {
|
|
|
1076
1331
|
"claude-sonnet-4-6-thinking": "claude-sonnet-4-6",
|
|
1077
1332
|
"claude-sonnet-4-6-thinking-low": "claude-sonnet-4-6",
|
|
1078
1333
|
"claude-sonnet-4-6-thinking-medium": "claude-sonnet-4-6",
|
|
1079
|
-
"claude-sonnet-4-6-thinking-high": "claude-sonnet-4-6"
|
|
1334
|
+
"claude-sonnet-4-6-thinking-high": "claude-sonnet-4-6",
|
|
1335
|
+
"gpt-oss-120b": "gpt-oss-120b-medium"
|
|
1080
1336
|
};
|
|
1081
1337
|
var GEMINI_35_FLASH_ROUTES = {
|
|
1082
1338
|
antigravity: {
|
|
@@ -1089,6 +1345,14 @@ var GEMINI_35_FLASH_ROUTES = {
|
|
|
1089
1345
|
},
|
|
1090
1346
|
geminiCliFallbackModel: "gemini-3-flash-preview"
|
|
1091
1347
|
};
|
|
1348
|
+
var GEMINI_36_FLASH_ROUTES = {
|
|
1349
|
+
defaultModel: "gemini-3.6-flash-medium",
|
|
1350
|
+
byTier: {
|
|
1351
|
+
low: "gemini-3.6-flash-low",
|
|
1352
|
+
medium: "gemini-3.6-flash-medium",
|
|
1353
|
+
high: "gemini-3.6-flash-high"
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1092
1356
|
var QUOTA_GROUP_BY_MODEL_ID = {
|
|
1093
1357
|
"claude-opus-4-6-thinking": "claude",
|
|
1094
1358
|
"claude-opus-4-6": "claude",
|
|
@@ -1102,15 +1366,22 @@ var QUOTA_GROUP_BY_MODEL_ID = {
|
|
|
1102
1366
|
"gemini-3-flash-agent": "gemini-flash",
|
|
1103
1367
|
"gemini-3.5-flash-low": "gemini-flash",
|
|
1104
1368
|
"gemini-3.5-flash-extra-low": "gemini-flash",
|
|
1369
|
+
"gemini-3.6-flash-low": "gemini-flash",
|
|
1370
|
+
"gemini-3.6-flash-medium": "gemini-flash",
|
|
1371
|
+
"gemini-3.6-flash-high": "gemini-flash",
|
|
1372
|
+
"gemini-3.6-flash-tiered": "gemini-flash",
|
|
1105
1373
|
"gemini-3.1-flash-image": "gemini-flash",
|
|
1106
1374
|
"gpt-oss-120b": "gpt-oss",
|
|
1107
1375
|
"gpt-oss-120b-medium": "gpt-oss"
|
|
1108
1376
|
};
|
|
1109
1377
|
var ANTIGRAVITY_OPENCODE_MODEL_IDS = [
|
|
1378
|
+
"antigravity-gemini-3.6-flash",
|
|
1110
1379
|
"antigravity-gemini-3.5-flash",
|
|
1111
1380
|
"antigravity-gemini-3.1-pro",
|
|
1112
1381
|
"antigravity-claude-sonnet-4-6-thinking",
|
|
1113
|
-
"antigravity-claude-opus-4-6-thinking"
|
|
1382
|
+
"antigravity-claude-opus-4-6-thinking",
|
|
1383
|
+
"antigravity-gemini-3.1-flash-image",
|
|
1384
|
+
"antigravity-gpt-oss-120b-medium"
|
|
1114
1385
|
];
|
|
1115
1386
|
function pickModelDefinitions(ids) {
|
|
1116
1387
|
return Object.fromEntries(ids.map((id) => [id, ALL_MODEL_DEFINITIONS[id]]));
|
|
@@ -1131,6 +1402,12 @@ function getGemini35FlashAntigravityModel(tier) {
|
|
|
1131
1402
|
function getGemini35FlashGeminiCliFallbackModel() {
|
|
1132
1403
|
return GEMINI_35_FLASH_ROUTES.geminiCliFallbackModel;
|
|
1133
1404
|
}
|
|
1405
|
+
function getGemini36FlashAntigravityModel(tier) {
|
|
1406
|
+
if (!tier) {
|
|
1407
|
+
return GEMINI_36_FLASH_ROUTES.defaultModel;
|
|
1408
|
+
}
|
|
1409
|
+
return GEMINI_36_FLASH_ROUTES.byTier[tier] ?? GEMINI_36_FLASH_ROUTES.defaultModel;
|
|
1410
|
+
}
|
|
1134
1411
|
function getQuotaGroupForModel(modelId) {
|
|
1135
1412
|
return QUOTA_GROUP_BY_MODEL_ID[modelId.toLowerCase()];
|
|
1136
1413
|
}
|
|
@@ -1187,7 +1464,7 @@ function isGemini35FlashModel(model) {
|
|
|
1187
1464
|
function resolveGemini35FlashAntigravityModel(tier) {
|
|
1188
1465
|
return getGemini35FlashAntigravityModel(tier);
|
|
1189
1466
|
}
|
|
1190
|
-
function
|
|
1467
|
+
function getAgyGeminiFlashThinkingBudget(tier) {
|
|
1191
1468
|
switch (tier) {
|
|
1192
1469
|
case "low":
|
|
1193
1470
|
return 1e3;
|
|
@@ -1220,6 +1497,8 @@ function resolveModelWithTier(requestedModel, options = {}) {
|
|
|
1220
1497
|
const isGemini3Flash = isGemini3FlashModel(modelWithoutQuota);
|
|
1221
1498
|
const isGemini31Pro = /^gemini-3\.1-pro/i.test(baseName);
|
|
1222
1499
|
const isGemini35Flash = /^gemini-3\.5-flash/i.test(baseName);
|
|
1500
|
+
const isGemini36Flash = /^gemini-3\.6-flash/i.test(baseName);
|
|
1501
|
+
const isGptOss120b = /^gpt-oss-120b(?:-medium)?$/i.test(baseName);
|
|
1223
1502
|
if (isGemini31Pro && quotaPreference === "antigravity") {
|
|
1224
1503
|
return {
|
|
1225
1504
|
actualModel: getAgyGemini31ProModel(tier),
|
|
@@ -1233,13 +1512,32 @@ function resolveModelWithTier(requestedModel, options = {}) {
|
|
|
1233
1512
|
if (isGemini35Flash && quotaPreference === "antigravity") {
|
|
1234
1513
|
return {
|
|
1235
1514
|
actualModel: resolveGemini35FlashAntigravityModel(tier ?? "medium"),
|
|
1236
|
-
thinkingBudget:
|
|
1515
|
+
thinkingBudget: getAgyGeminiFlashThinkingBudget(tier),
|
|
1516
|
+
tier: tier ?? "medium",
|
|
1517
|
+
isThinkingModel: true,
|
|
1518
|
+
quotaPreference,
|
|
1519
|
+
explicitQuota
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
if (isGemini36Flash && quotaPreference === "antigravity") {
|
|
1523
|
+
return {
|
|
1524
|
+
actualModel: getGemini36FlashAntigravityModel(tier ?? "medium"),
|
|
1525
|
+
thinkingBudget: getAgyGeminiFlashThinkingBudget(tier),
|
|
1237
1526
|
tier: tier ?? "medium",
|
|
1238
1527
|
isThinkingModel: true,
|
|
1239
1528
|
quotaPreference,
|
|
1240
1529
|
explicitQuota
|
|
1241
1530
|
};
|
|
1242
1531
|
}
|
|
1532
|
+
if (isGptOss120b && quotaPreference === "antigravity") {
|
|
1533
|
+
return {
|
|
1534
|
+
actualModel: "gpt-oss-120b-medium",
|
|
1535
|
+
thinkingBudget: 8192,
|
|
1536
|
+
isThinkingModel: true,
|
|
1537
|
+
quotaPreference,
|
|
1538
|
+
explicitQuota
|
|
1539
|
+
};
|
|
1540
|
+
}
|
|
1243
1541
|
let antigravityModel = modelWithoutQuota;
|
|
1244
1542
|
if (skipAlias) {
|
|
1245
1543
|
if ((isGemini3Pro || isGemini3Flash) && !tier && !isImageModel) {
|
|
@@ -1436,12 +1734,26 @@ var UNSUPPORTED_SCHEMA_FIELDS = /* @__PURE__ */ new Set([
|
|
|
1436
1734
|
"minContains",
|
|
1437
1735
|
"maxContains"
|
|
1438
1736
|
]);
|
|
1439
|
-
|
|
1737
|
+
var NUMERIC_SCHEMA_CONSTRAINTS = /* @__PURE__ */ new Set([
|
|
1738
|
+
"minLength",
|
|
1739
|
+
"maxLength",
|
|
1740
|
+
"minItems",
|
|
1741
|
+
"maxItems",
|
|
1742
|
+
"minProperties",
|
|
1743
|
+
"maxProperties",
|
|
1744
|
+
"minimum",
|
|
1745
|
+
"maximum",
|
|
1746
|
+
"exclusiveMinimum",
|
|
1747
|
+
"exclusiveMaximum",
|
|
1748
|
+
"multipleOf"
|
|
1749
|
+
]);
|
|
1750
|
+
function toGeminiSchema(schema, options = {}) {
|
|
1440
1751
|
if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
|
|
1441
1752
|
return schema;
|
|
1442
1753
|
}
|
|
1443
1754
|
const inputSchema = schema;
|
|
1444
1755
|
const result = {};
|
|
1756
|
+
const numericConstraintHints = [];
|
|
1445
1757
|
const propertyNames = /* @__PURE__ */ new Set();
|
|
1446
1758
|
if (inputSchema.properties && typeof inputSchema.properties === "object") {
|
|
1447
1759
|
for (const propName of Object.keys(inputSchema.properties)) {
|
|
@@ -1457,15 +1769,19 @@ function toGeminiSchema(schema) {
|
|
|
1457
1769
|
} else if (key === "properties" && typeof value === "object" && value !== null) {
|
|
1458
1770
|
const props = {};
|
|
1459
1771
|
for (const [propName, propSchema] of Object.entries(value)) {
|
|
1460
|
-
props[propName] = toGeminiSchema(propSchema);
|
|
1772
|
+
props[propName] = toGeminiSchema(propSchema, options);
|
|
1461
1773
|
}
|
|
1462
1774
|
result[key] = props;
|
|
1463
1775
|
} else if (key === "items" && typeof value === "object") {
|
|
1464
|
-
result[key] = toGeminiSchema(value);
|
|
1776
|
+
result[key] = toGeminiSchema(value, options);
|
|
1465
1777
|
} else if ((key === "anyOf" || key === "oneOf" || key === "allOf") && Array.isArray(value)) {
|
|
1466
|
-
result[key] = value.map((item) => toGeminiSchema(item));
|
|
1778
|
+
result[key] = value.map((item) => toGeminiSchema(item, options));
|
|
1467
1779
|
} else if (key === "enum" && Array.isArray(value)) {
|
|
1468
1780
|
result[key] = value;
|
|
1781
|
+
} else if (options.moveNumericConstraintsToDescription && NUMERIC_SCHEMA_CONSTRAINTS.has(key)) {
|
|
1782
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
1783
|
+
numericConstraintHints.push(`${key}: ${value}`);
|
|
1784
|
+
}
|
|
1469
1785
|
} else if (key === "default" || key === "examples") {
|
|
1470
1786
|
result[key] = value;
|
|
1471
1787
|
} else if (key === "required" && Array.isArray(value)) {
|
|
@@ -1481,6 +1797,10 @@ function toGeminiSchema(schema) {
|
|
|
1481
1797
|
result[key] = value;
|
|
1482
1798
|
}
|
|
1483
1799
|
}
|
|
1800
|
+
if (numericConstraintHints.length > 0) {
|
|
1801
|
+
const hint = numericConstraintHints.join(", ");
|
|
1802
|
+
result.description = typeof result.description === "string" && result.description ? `${result.description} (${hint})` : hint;
|
|
1803
|
+
}
|
|
1484
1804
|
if (result.type === "ARRAY" && !result.items) {
|
|
1485
1805
|
result.items = { type: "STRING" };
|
|
1486
1806
|
}
|
|
@@ -1518,7 +1838,7 @@ function buildImageGenerationConfig() {
|
|
|
1518
1838
|
console.warn(`[gemini] Invalid aspect ratio "${aspectRatio}". Using default "1:1". Valid values: ${VALID_ASPECT_RATIOS.join(", ")}`);
|
|
1519
1839
|
return { aspectRatio: "1:1" };
|
|
1520
1840
|
}
|
|
1521
|
-
function normalizeGeminiTools(payload) {
|
|
1841
|
+
function normalizeGeminiTools(payload, schemaOptions = {}) {
|
|
1522
1842
|
let toolDebugMissing = 0;
|
|
1523
1843
|
const toolDebugSummaries = [];
|
|
1524
1844
|
if (!Array.isArray(payload.tools)) {
|
|
@@ -1529,6 +1849,21 @@ function normalizeGeminiTools(payload) {
|
|
|
1529
1849
|
if (t.googleSearch || t.googleSearchRetrieval) {
|
|
1530
1850
|
return t;
|
|
1531
1851
|
}
|
|
1852
|
+
if (Array.isArray(t.functionDeclarations)) {
|
|
1853
|
+
return {
|
|
1854
|
+
...t,
|
|
1855
|
+
functionDeclarations: t.functionDeclarations.map((declaration) => {
|
|
1856
|
+
const normalized = { ...declaration };
|
|
1857
|
+
const rawSchema = normalized.parameters ?? normalized.parametersJsonSchema ?? {
|
|
1858
|
+
type: "OBJECT",
|
|
1859
|
+
properties: {}
|
|
1860
|
+
};
|
|
1861
|
+
normalized.parameters = toGeminiSchema(rawSchema, schemaOptions);
|
|
1862
|
+
delete normalized.parametersJsonSchema;
|
|
1863
|
+
return normalized;
|
|
1864
|
+
})
|
|
1865
|
+
};
|
|
1866
|
+
}
|
|
1532
1867
|
const newTool = { ...t };
|
|
1533
1868
|
const schemaCandidates = [
|
|
1534
1869
|
newTool.function?.input_schema,
|
|
@@ -1556,7 +1891,7 @@ function normalizeGeminiTools(payload) {
|
|
|
1556
1891
|
schema = placeholderSchema;
|
|
1557
1892
|
toolDebugMissing += 1;
|
|
1558
1893
|
} else {
|
|
1559
|
-
schema = toGeminiSchema(schema);
|
|
1894
|
+
schema = toGeminiSchema(schema, schemaOptions);
|
|
1560
1895
|
}
|
|
1561
1896
|
const nameCandidate = newTool.name || newTool.function?.name || newTool.custom?.name || `tool-${toolIndex}`;
|
|
1562
1897
|
if (newTool.function && schema) {
|
|
@@ -1621,7 +1956,9 @@ function applyGeminiTransforms(payload, options) {
|
|
|
1621
1956
|
googleSearch: {}
|
|
1622
1957
|
});
|
|
1623
1958
|
}
|
|
1624
|
-
const result = normalizeGeminiTools(payload
|
|
1959
|
+
const result = normalizeGeminiTools(payload, {
|
|
1960
|
+
moveNumericConstraintsToDescription: model.toLowerCase().startsWith("gpt-oss-")
|
|
1961
|
+
});
|
|
1625
1962
|
const wrapResult = wrapToolsAsFunctionDeclarations(payload);
|
|
1626
1963
|
return {
|
|
1627
1964
|
...result,
|
|
@@ -2122,7 +2459,7 @@ async function select(items, options) {
|
|
|
2122
2459
|
}
|
|
2123
2460
|
renderedLines = linesWritten;
|
|
2124
2461
|
};
|
|
2125
|
-
return new Promise((
|
|
2462
|
+
return new Promise((resolve2) => {
|
|
2126
2463
|
const wasRaw = stdin.isRaw ?? false;
|
|
2127
2464
|
const cleanup = () => {
|
|
2128
2465
|
if (isCleanedUp) return;
|
|
@@ -2143,11 +2480,11 @@ async function select(items, options) {
|
|
|
2143
2480
|
};
|
|
2144
2481
|
const onSignal = () => {
|
|
2145
2482
|
cleanup();
|
|
2146
|
-
|
|
2483
|
+
resolve2(null);
|
|
2147
2484
|
};
|
|
2148
2485
|
const finishWithValue = (value) => {
|
|
2149
2486
|
cleanup();
|
|
2150
|
-
|
|
2487
|
+
resolve2(value);
|
|
2151
2488
|
};
|
|
2152
2489
|
const findNextSelectable = (from, direction) => {
|
|
2153
2490
|
if (items.length === 0) return from;
|
|
@@ -2193,7 +2530,7 @@ async function select(items, options) {
|
|
|
2193
2530
|
stdin.setRawMode(true);
|
|
2194
2531
|
} catch {
|
|
2195
2532
|
cleanup();
|
|
2196
|
-
|
|
2533
|
+
resolve2(null);
|
|
2197
2534
|
return;
|
|
2198
2535
|
}
|
|
2199
2536
|
stdin.resume();
|
|
@@ -2320,7 +2657,7 @@ function classifyOverallQuotaHealth(cachedQuota) {
|
|
|
2320
2657
|
if (!cachedQuota) {
|
|
2321
2658
|
return { health: "unknown" };
|
|
2322
2659
|
}
|
|
2323
|
-
const QUOTA_KEYS2 = ["claude", "gemini-pro", "gemini-flash"];
|
|
2660
|
+
const QUOTA_KEYS2 = ["claude", "gemini-pro", "gemini-flash", "gpt-oss"];
|
|
2324
2661
|
let groupsWithData = 0;
|
|
2325
2662
|
let exhaustedCount = 0;
|
|
2326
2663
|
let maxResetMs;
|
|
@@ -2354,7 +2691,8 @@ function formatCachedQuotaWithStatus(cachedQuota) {
|
|
|
2354
2691
|
const entries = [
|
|
2355
2692
|
{ key: "claude", label: "Claude" },
|
|
2356
2693
|
{ key: "gemini-pro", label: "Gemini Pro" },
|
|
2357
|
-
{ key: "gemini-flash", label: "Gemini Flash" }
|
|
2694
|
+
{ key: "gemini-flash", label: "Gemini Flash" },
|
|
2695
|
+
{ key: "gpt-oss", label: "GPT-OSS" }
|
|
2358
2696
|
].flatMap(({ key, label }) => {
|
|
2359
2697
|
const value = cachedQuota[key]?.remainingFraction;
|
|
2360
2698
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
@@ -2414,6 +2752,8 @@ function getStatusBadge(status, account) {
|
|
|
2414
2752
|
return ` ${ANSI.red}[expired]${ANSI.reset}`;
|
|
2415
2753
|
case "verification-required":
|
|
2416
2754
|
return ` ${ANSI.red}[needs verification]${ANSI.reset}`;
|
|
2755
|
+
case "ineligible":
|
|
2756
|
+
return ` ${ANSI.red}[ineligible]${ANSI.reset}`;
|
|
2417
2757
|
default:
|
|
2418
2758
|
return "";
|
|
2419
2759
|
}
|
|
@@ -2445,7 +2785,8 @@ function getHealthLabel(acc) {
|
|
|
2445
2785
|
var QUOTA_KEYS = [
|
|
2446
2786
|
{ key: "claude", label: "Claude" },
|
|
2447
2787
|
{ key: "gemini-pro", label: "Gemini Pro" },
|
|
2448
|
-
{ key: "gemini-flash", label: "Gemini Flash" }
|
|
2788
|
+
{ key: "gemini-flash", label: "Gemini Flash" },
|
|
2789
|
+
{ key: "gpt-oss", label: "GPT-OSS" }
|
|
2449
2790
|
];
|
|
2450
2791
|
function parseResetTimeToMs2(resetTime) {
|
|
2451
2792
|
if (!resetTime) return null;
|
|
@@ -3083,11 +3424,13 @@ async function getLockFunction() {
|
|
|
3083
3424
|
if (_cachedLock) return _cachedLock;
|
|
3084
3425
|
const mod = await import("proper-lockfile");
|
|
3085
3426
|
const fn = (typeof mod.lock === "function" ? mod.lock : void 0) || (mod.default && typeof mod.default.lock === "function" ? mod.default.lock : void 0);
|
|
3086
|
-
|
|
3087
|
-
|
|
3427
|
+
if (typeof fn !== "function") {
|
|
3428
|
+
throw new Error("proper-lockfile did not expose a lock() function; cannot acquire account file lock");
|
|
3429
|
+
}
|
|
3430
|
+
_cachedLock = fn;
|
|
3088
3431
|
return _cachedLock;
|
|
3089
3432
|
}
|
|
3090
|
-
var lockfile = { lock: (
|
|
3433
|
+
var lockfile = { lock: (path4, options) => getLockFunction().then((fn) => fn(path4, options)) };
|
|
3091
3434
|
var log3 = createLogger2("storage");
|
|
3092
3435
|
var GITIGNORE_ENTRIES = [
|
|
3093
3436
|
".gitignore",
|
|
@@ -3255,29 +3598,29 @@ var LOCK_OPTIONS = {
|
|
|
3255
3598
|
factor: 2
|
|
3256
3599
|
}
|
|
3257
3600
|
};
|
|
3258
|
-
async function ensureSecurePermissions(
|
|
3601
|
+
async function ensureSecurePermissions(path4) {
|
|
3259
3602
|
try {
|
|
3260
|
-
await fs.chmod(
|
|
3603
|
+
await fs.chmod(path4, 384);
|
|
3261
3604
|
} catch {
|
|
3262
3605
|
}
|
|
3263
3606
|
}
|
|
3264
|
-
async function ensureFileExists(
|
|
3607
|
+
async function ensureFileExists(path4) {
|
|
3265
3608
|
try {
|
|
3266
|
-
await fs.access(
|
|
3609
|
+
await fs.access(path4);
|
|
3267
3610
|
} catch {
|
|
3268
|
-
await fs.mkdir(dirname2(
|
|
3611
|
+
await fs.mkdir(dirname2(path4), { recursive: true });
|
|
3269
3612
|
await fs.writeFile(
|
|
3270
|
-
|
|
3613
|
+
path4,
|
|
3271
3614
|
JSON.stringify({ version: 4, accounts: [], activeIndex: 0 }, null, 2),
|
|
3272
3615
|
{ encoding: "utf-8", mode: 384 }
|
|
3273
3616
|
);
|
|
3274
3617
|
}
|
|
3275
3618
|
}
|
|
3276
|
-
async function withFileLock(
|
|
3277
|
-
await ensureFileExists(
|
|
3619
|
+
async function withFileLock(path4, fn) {
|
|
3620
|
+
await ensureFileExists(path4);
|
|
3278
3621
|
let release = null;
|
|
3279
3622
|
try {
|
|
3280
|
-
release = await lockfile.lock(
|
|
3623
|
+
release = await lockfile.lock(path4, LOCK_OPTIONS);
|
|
3281
3624
|
return await fn();
|
|
3282
3625
|
} finally {
|
|
3283
3626
|
if (release) {
|
|
@@ -3300,7 +3643,8 @@ function mergeAccountStorage(existing, incoming) {
|
|
|
3300
3643
|
if (acc.refreshToken) {
|
|
3301
3644
|
const existingAcc = accountMap.get(acc.refreshToken);
|
|
3302
3645
|
if (existingAcc) {
|
|
3303
|
-
|
|
3646
|
+
const eligibilitySource = (acc.eligibilityStateUpdatedAt ?? 0) >= (existingAcc.eligibilityStateUpdatedAt ?? 0) ? acc : existingAcc;
|
|
3647
|
+
const merged = {
|
|
3304
3648
|
...existingAcc,
|
|
3305
3649
|
...acc,
|
|
3306
3650
|
// Preserve manually configured projectId/managedProjectId if not in incoming
|
|
@@ -3310,8 +3654,16 @@ function mergeAccountStorage(existing, incoming) {
|
|
|
3310
3654
|
...existingAcc.rateLimitResetTimes,
|
|
3311
3655
|
...acc.rateLimitResetTimes
|
|
3312
3656
|
},
|
|
3313
|
-
lastUsed: Math.max(existingAcc.lastUsed || 0, acc.lastUsed || 0)
|
|
3314
|
-
|
|
3657
|
+
lastUsed: Math.max(existingAcc.lastUsed || 0, acc.lastUsed || 0),
|
|
3658
|
+
accountIneligible: eligibilitySource.accountIneligible,
|
|
3659
|
+
accountIneligibleAt: eligibilitySource.accountIneligibleAt,
|
|
3660
|
+
accountIneligibleReason: eligibilitySource.accountIneligibleReason,
|
|
3661
|
+
eligibilityStateUpdatedAt: eligibilitySource.eligibilityStateUpdatedAt
|
|
3662
|
+
};
|
|
3663
|
+
if (merged.accountIneligible) {
|
|
3664
|
+
merged.enabled = false;
|
|
3665
|
+
}
|
|
3666
|
+
accountMap.set(acc.refreshToken, merged);
|
|
3315
3667
|
} else {
|
|
3316
3668
|
accountMap.set(acc.refreshToken, acc);
|
|
3317
3669
|
}
|
|
@@ -3429,9 +3781,9 @@ function migrateV3ToV4(v3) {
|
|
|
3429
3781
|
}
|
|
3430
3782
|
async function loadAccounts() {
|
|
3431
3783
|
try {
|
|
3432
|
-
const
|
|
3433
|
-
await ensureSecurePermissions(
|
|
3434
|
-
const content = await fs.readFile(
|
|
3784
|
+
const path4 = getStoragePath();
|
|
3785
|
+
await ensureSecurePermissions(path4);
|
|
3786
|
+
const content = await fs.readFile(path4, "utf-8");
|
|
3435
3787
|
const data = JSON.parse(content);
|
|
3436
3788
|
if (!Array.isArray(data.accounts)) {
|
|
3437
3789
|
log3.warn("Invalid storage format, ignoring");
|
|
@@ -3545,32 +3897,32 @@ async function atomicWriteFile(targetPath, content) {
|
|
|
3545
3897
|
}
|
|
3546
3898
|
}
|
|
3547
3899
|
async function saveAccounts(storage) {
|
|
3548
|
-
const
|
|
3549
|
-
const configDir = dirname2(
|
|
3900
|
+
const path4 = getStoragePath();
|
|
3901
|
+
const configDir = dirname2(path4);
|
|
3550
3902
|
await fs.mkdir(configDir, { recursive: true });
|
|
3551
3903
|
await ensureGitignore(configDir);
|
|
3552
|
-
await withFileLock(
|
|
3904
|
+
await withFileLock(path4, async () => {
|
|
3553
3905
|
const existing = await loadAccountsUnsafe();
|
|
3554
3906
|
const merged = existing ? mergeAccountStorage(existing, storage) : storage;
|
|
3555
3907
|
const content = JSON.stringify(merged, null, 2);
|
|
3556
|
-
await atomicWriteFile(
|
|
3908
|
+
await atomicWriteFile(path4, content);
|
|
3557
3909
|
});
|
|
3558
3910
|
}
|
|
3559
3911
|
async function saveAccountsReplace(storage) {
|
|
3560
|
-
const
|
|
3561
|
-
const configDir = dirname2(
|
|
3912
|
+
const path4 = getStoragePath();
|
|
3913
|
+
const configDir = dirname2(path4);
|
|
3562
3914
|
await fs.mkdir(configDir, { recursive: true });
|
|
3563
3915
|
await ensureGitignore(configDir);
|
|
3564
|
-
await withFileLock(
|
|
3916
|
+
await withFileLock(path4, async () => {
|
|
3565
3917
|
const content = JSON.stringify(storage, null, 2);
|
|
3566
|
-
await atomicWriteFile(
|
|
3918
|
+
await atomicWriteFile(path4, content);
|
|
3567
3919
|
});
|
|
3568
3920
|
}
|
|
3569
3921
|
async function loadAccountsUnsafe() {
|
|
3570
3922
|
try {
|
|
3571
|
-
const
|
|
3572
|
-
await ensureSecurePermissions(
|
|
3573
|
-
const content = await fs.readFile(
|
|
3923
|
+
const path4 = getStoragePath();
|
|
3924
|
+
await ensureSecurePermissions(path4);
|
|
3925
|
+
const content = await fs.readFile(path4, "utf-8");
|
|
3574
3926
|
const parsed = JSON.parse(content);
|
|
3575
3927
|
if (parsed.version === 1) {
|
|
3576
3928
|
return migrateV3ToV4(migrateV2ToV3(migrateV1ToV2(parsed)));
|
|
@@ -3598,9 +3950,11 @@ async function loadAccountsUnsafe() {
|
|
|
3598
3950
|
}
|
|
3599
3951
|
}
|
|
3600
3952
|
async function clearAccounts() {
|
|
3953
|
+
const path4 = getStoragePath();
|
|
3601
3954
|
try {
|
|
3602
|
-
|
|
3603
|
-
|
|
3955
|
+
await withFileLock(path4, async () => {
|
|
3956
|
+
await fs.unlink(path4);
|
|
3957
|
+
});
|
|
3604
3958
|
} catch (error) {
|
|
3605
3959
|
const code = error.code;
|
|
3606
3960
|
if (code !== "ENOENT") {
|
|
@@ -3625,7 +3979,7 @@ function getConfigDir2() {
|
|
|
3625
3979
|
function getLogsDir(customLogDir) {
|
|
3626
3980
|
const logsDir = customLogDir || join3(getConfigDir2(), "antigravity-logs");
|
|
3627
3981
|
try {
|
|
3628
|
-
mkdirSync3(logsDir, { recursive: true });
|
|
3982
|
+
mkdirSync3(logsDir, { recursive: true, mode: 448 });
|
|
3629
3983
|
} catch {
|
|
3630
3984
|
}
|
|
3631
3985
|
return logsDir;
|
|
@@ -3661,7 +4015,7 @@ function createLogWriter(filePath) {
|
|
|
3661
4015
|
};
|
|
3662
4016
|
}
|
|
3663
4017
|
try {
|
|
3664
|
-
const stream = createWriteStream(filePath, { flags: "a" });
|
|
4018
|
+
const stream = createWriteStream(filePath, { flags: "a", mode: 384 });
|
|
3665
4019
|
stream.on("error", () => {
|
|
3666
4020
|
});
|
|
3667
4021
|
return (line) => {
|
|
@@ -4844,17 +5198,17 @@ function getUserConfigPath() {
|
|
|
4844
5198
|
function getProjectConfigPath(directory) {
|
|
4845
5199
|
return join5(directory, ".opencode", "antigravity.json");
|
|
4846
5200
|
}
|
|
4847
|
-
function loadConfigFile(
|
|
5201
|
+
function loadConfigFile(path4) {
|
|
4848
5202
|
try {
|
|
4849
|
-
if (!existsSync4(
|
|
5203
|
+
if (!existsSync4(path4)) {
|
|
4850
5204
|
return null;
|
|
4851
5205
|
}
|
|
4852
|
-
const content = readFileSync4(
|
|
5206
|
+
const content = readFileSync4(path4, "utf-8");
|
|
4853
5207
|
const rawConfig = JSON.parse(content);
|
|
4854
5208
|
const result = AntigravityConfigSchema.partial().safeParse(rawConfig);
|
|
4855
5209
|
if (!result.success) {
|
|
4856
5210
|
log4.warn("Config validation error", {
|
|
4857
|
-
path:
|
|
5211
|
+
path: path4,
|
|
4858
5212
|
issues: result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join(", ")
|
|
4859
5213
|
});
|
|
4860
5214
|
return null;
|
|
@@ -4862,9 +5216,9 @@ function loadConfigFile(path5) {
|
|
|
4862
5216
|
return result.data;
|
|
4863
5217
|
} catch (error) {
|
|
4864
5218
|
if (error instanceof SyntaxError) {
|
|
4865
|
-
log4.warn("Invalid JSON in config file", { path:
|
|
5219
|
+
log4.warn("Invalid JSON in config file", { path: path4, error: error.message });
|
|
4866
5220
|
} else {
|
|
4867
|
-
log4.warn("Failed to load config file", { path:
|
|
5221
|
+
log4.warn("Failed to load config file", { path: path4, error: String(error) });
|
|
4868
5222
|
}
|
|
4869
5223
|
return null;
|
|
4870
5224
|
}
|
|
@@ -4903,50 +5257,54 @@ function getKeepThinking() {
|
|
|
4903
5257
|
}
|
|
4904
5258
|
|
|
4905
5259
|
// src/plugin/image-saver.ts
|
|
4906
|
-
import
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
5260
|
+
import {
|
|
5261
|
+
chmodSync,
|
|
5262
|
+
existsSync as existsSync5,
|
|
5263
|
+
mkdirSync as mkdirSync5,
|
|
5264
|
+
writeFileSync as writeFileSync4
|
|
5265
|
+
} from "node:fs";
|
|
5266
|
+
import { homedir as homedir6 } from "node:os";
|
|
5267
|
+
import { join as join6 } from "node:path";
|
|
5268
|
+
function getImageOutputDir(outputDir) {
|
|
5269
|
+
const resolved = outputDir ?? join6(homedir6(), ".opencode", "generated-images");
|
|
5270
|
+
if (!existsSync5(resolved)) {
|
|
5271
|
+
mkdirSync5(resolved, { recursive: true, mode: 448 });
|
|
4914
5272
|
}
|
|
4915
|
-
|
|
5273
|
+
chmodSync(resolved, 448);
|
|
5274
|
+
return resolved;
|
|
4916
5275
|
}
|
|
4917
5276
|
function generateImageFilename(mimeType) {
|
|
4918
5277
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
4919
5278
|
const random = Math.random().toString(36).substring(2, 8);
|
|
4920
|
-
let
|
|
5279
|
+
let extension = "png";
|
|
4921
5280
|
if (mimeType.includes("jpeg") || mimeType.includes("jpg")) {
|
|
4922
|
-
|
|
5281
|
+
extension = "jpg";
|
|
4923
5282
|
} else if (mimeType.includes("gif")) {
|
|
4924
|
-
|
|
5283
|
+
extension = "gif";
|
|
4925
5284
|
} else if (mimeType.includes("webp")) {
|
|
4926
|
-
|
|
5285
|
+
extension = "webp";
|
|
4927
5286
|
}
|
|
4928
|
-
return `image-${timestamp}-${random}.${
|
|
5287
|
+
return `image-${timestamp}-${random}.${extension}`;
|
|
4929
5288
|
}
|
|
4930
|
-
function saveImageToDisk(base64Data, mimeType) {
|
|
5289
|
+
function saveImageToDisk(base64Data, mimeType, outputDir) {
|
|
4931
5290
|
try {
|
|
4932
|
-
const
|
|
4933
|
-
const
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
fs2.writeFileSync(filePath, buffer);
|
|
5291
|
+
const resolvedOutputDir = getImageOutputDir(outputDir);
|
|
5292
|
+
const filePath = join6(resolvedOutputDir, generateImageFilename(mimeType));
|
|
5293
|
+
writeFileSync4(filePath, Buffer.from(base64Data, "base64"), { mode: 384 });
|
|
5294
|
+
chmodSync(filePath, 384);
|
|
4937
5295
|
return filePath;
|
|
4938
5296
|
} catch (error) {
|
|
4939
5297
|
console.error("[image-saver] Failed to save image:", error);
|
|
4940
5298
|
return "";
|
|
4941
5299
|
}
|
|
4942
5300
|
}
|
|
4943
|
-
function processImageData(inlineData) {
|
|
5301
|
+
function processImageData(inlineData, outputDir) {
|
|
4944
5302
|
const mimeType = inlineData.mimeType || "image/png";
|
|
4945
5303
|
const data = inlineData.data;
|
|
4946
5304
|
if (!data) {
|
|
4947
5305
|
return null;
|
|
4948
5306
|
}
|
|
4949
|
-
const filePath = saveImageToDisk(data, mimeType);
|
|
5307
|
+
const filePath = saveImageToDisk(data, mimeType, outputDir);
|
|
4950
5308
|
if (filePath) {
|
|
4951
5309
|
return `
|
|
4952
5310
|
|
|
@@ -6995,14 +7353,14 @@ function applyToolPairingFixes(payload, isClaude) {
|
|
|
6995
7353
|
}
|
|
6996
7354
|
return { contentsFixed, messagesFixed };
|
|
6997
7355
|
}
|
|
6998
|
-
function
|
|
6999
|
-
const outputTokens = Math.max(1, Math.ceil(
|
|
7356
|
+
function createSyntheticTextResponse(text, extraHeaders = {}) {
|
|
7357
|
+
const outputTokens = Math.max(1, Math.ceil(text.length / 4));
|
|
7000
7358
|
const event = {
|
|
7001
7359
|
candidates: [
|
|
7002
7360
|
{
|
|
7003
7361
|
content: {
|
|
7004
7362
|
role: "model",
|
|
7005
|
-
parts: [{ text
|
|
7363
|
+
parts: [{ text }]
|
|
7006
7364
|
},
|
|
7007
7365
|
finishReason: "STOP"
|
|
7008
7366
|
}
|
|
@@ -7022,10 +7380,15 @@ function createSyntheticErrorResponse(errorMessage, _requestedModel = "unknown")
|
|
|
7022
7380
|
"Cache-Control": "no-cache",
|
|
7023
7381
|
"Connection": "keep-alive",
|
|
7024
7382
|
"X-Antigravity-Synthetic": "true",
|
|
7025
|
-
|
|
7383
|
+
...extraHeaders
|
|
7026
7384
|
}
|
|
7027
7385
|
});
|
|
7028
7386
|
}
|
|
7387
|
+
function createSyntheticErrorResponse(errorMessage, _requestedModel = "unknown") {
|
|
7388
|
+
return createSyntheticTextResponse(errorMessage, {
|
|
7389
|
+
"X-Antigravity-Error-Type": "synthetic_error"
|
|
7390
|
+
});
|
|
7391
|
+
}
|
|
7029
7392
|
|
|
7030
7393
|
// src/plugin/thinking-recovery.ts
|
|
7031
7394
|
function isThinkingPart2(part) {
|
|
@@ -7644,6 +8007,8 @@ var DUMP_USAGE_TITLE = "## Gemini Dump Usage";
|
|
|
7644
8007
|
var DUMP_USAGE = "Usage: `/gemini-dump`, `/gemini-dump on`, or `/gemini-dump off`.";
|
|
7645
8008
|
var DUMP_DIR_ENV = "OPENCODE_ANTIGRAVITY_GEMINI_DUMP_DIR";
|
|
7646
8009
|
var DEFAULT_DUMP_DIR = join9(tmpdir2(), "opencode-antigravity-gemini-dumps");
|
|
8010
|
+
var DUMP_DIR_MODE = 448;
|
|
8011
|
+
var DUMP_FILE_MODE = 384;
|
|
7647
8012
|
var dumpEnabled = process.env.OPENCODE_ANTIGRAVITY_GEMINI_DUMP === "1";
|
|
7648
8013
|
var nextDumpId = 0;
|
|
7649
8014
|
function setGeminiDumpEnabled(enabled) {
|
|
@@ -7762,9 +8127,9 @@ function bodyStructureSummary(bodyText) {
|
|
|
7762
8127
|
bodyBytes: bodyText.length
|
|
7763
8128
|
};
|
|
7764
8129
|
}
|
|
7765
|
-
function writeJson(
|
|
7766
|
-
writeFileSync6(
|
|
7767
|
-
`, "utf8");
|
|
8130
|
+
function writeJson(path4, value) {
|
|
8131
|
+
writeFileSync6(path4, `${JSON.stringify(value, null, 2)}
|
|
8132
|
+
`, { encoding: "utf8", mode: DUMP_FILE_MODE });
|
|
7768
8133
|
}
|
|
7769
8134
|
function updateMetadata(context, patch) {
|
|
7770
8135
|
context.metadata = {
|
|
@@ -7781,7 +8146,7 @@ function dumpGeminiRequest(input2) {
|
|
|
7781
8146
|
const id = `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}-${String(nextDumpId).padStart(5, "0")}-${input2.streaming ? "stream" : "json"}`;
|
|
7782
8147
|
const dumpDir = getGeminiDumpDirectory();
|
|
7783
8148
|
const prefix = join9(dumpDir, id);
|
|
7784
|
-
mkdirSync7(dumpDir, { recursive: true });
|
|
8149
|
+
mkdirSync7(dumpDir, { recursive: true, mode: DUMP_DIR_MODE });
|
|
7785
8150
|
const context = {
|
|
7786
8151
|
id,
|
|
7787
8152
|
files: {
|
|
@@ -7809,8 +8174,8 @@ function dumpGeminiRequest(input2) {
|
|
|
7809
8174
|
}
|
|
7810
8175
|
}
|
|
7811
8176
|
};
|
|
7812
|
-
writeFileSync6(context.files.request, input2.body, "utf8");
|
|
7813
|
-
writeFileSync6(context.files.response, "", "utf8");
|
|
8177
|
+
writeFileSync6(context.files.request, input2.body, { encoding: "utf8", mode: DUMP_FILE_MODE });
|
|
8178
|
+
writeFileSync6(context.files.response, "", { encoding: "utf8", mode: DUMP_FILE_MODE });
|
|
7814
8179
|
writeJson(context.files.metadata, context.metadata);
|
|
7815
8180
|
return context;
|
|
7816
8181
|
}
|
|
@@ -7843,26 +8208,69 @@ function createGeminiDumpResponseTransform(context) {
|
|
|
7843
8208
|
// src/plugin/request.ts
|
|
7844
8209
|
var log6 = createLogger2("request");
|
|
7845
8210
|
var PLUGIN_SESSION_ID = `-${crypto2.randomUUID()}`;
|
|
8211
|
+
var DEFAULT_AGY_REQUEST_SESSION = createAgyRequestSessionContext("");
|
|
7846
8212
|
var sessionDisplayedThinkingHashes = /* @__PURE__ */ new Set();
|
|
7847
8213
|
var MIN_SIGNATURE_LENGTH = 50;
|
|
8214
|
+
var AGY_CLAUDE_THINKING_BUDGET = 1024;
|
|
7848
8215
|
var ANTIGRAVITY_ENVELOPE_FIELD_ORDER = [
|
|
7849
8216
|
"project",
|
|
7850
8217
|
"requestId",
|
|
7851
8218
|
"request",
|
|
7852
8219
|
"model",
|
|
7853
8220
|
"userAgent",
|
|
7854
|
-
"requestType"
|
|
7855
|
-
"enabledCreditTypes"
|
|
8221
|
+
"requestType"
|
|
7856
8222
|
];
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
8223
|
+
var OPENCODE_TITLE_PROMPT_PREFIX = "Generate a title for this conversation:";
|
|
8224
|
+
function getOpenCodeTitleSourceText(payload) {
|
|
8225
|
+
if (!Array.isArray(payload.contents)) {
|
|
8226
|
+
return void 0;
|
|
8227
|
+
}
|
|
8228
|
+
const texts = payload.contents.flatMap((content) => {
|
|
8229
|
+
if (!content || typeof content !== "object") {
|
|
8230
|
+
return [];
|
|
8231
|
+
}
|
|
8232
|
+
const parts = content.parts;
|
|
8233
|
+
if (!Array.isArray(parts)) {
|
|
8234
|
+
return [];
|
|
8235
|
+
}
|
|
8236
|
+
return parts.flatMap(
|
|
8237
|
+
(part) => !!part && typeof part === "object" && typeof part.text === "string" ? [part.text] : []
|
|
8238
|
+
);
|
|
8239
|
+
});
|
|
8240
|
+
const promptIndex = texts.findIndex((text) => text.startsWith(OPENCODE_TITLE_PROMPT_PREFIX));
|
|
8241
|
+
return promptIndex >= 0 ? texts.slice(promptIndex + 1).find((text) => text.trim().length > 0) : void 0;
|
|
8242
|
+
}
|
|
8243
|
+
function isOpenCodeTitleGenerationRequest(payload) {
|
|
8244
|
+
return getOpenCodeTitleSourceText(payload) !== void 0;
|
|
8245
|
+
}
|
|
8246
|
+
function formatLocalImageTitle(sourceText) {
|
|
8247
|
+
const normalized = sourceText.trim().replace(/^(["“])(.*)(["”])$/s, "$2").replace(/\s+/g, " ");
|
|
8248
|
+
const characters = Array.from(normalized);
|
|
8249
|
+
if (characters.length <= 50) {
|
|
8250
|
+
return normalized || "Image generation";
|
|
8251
|
+
}
|
|
8252
|
+
return `${characters.slice(0, 47).join("").trimEnd()}...`;
|
|
8253
|
+
}
|
|
8254
|
+
function getImageModelLocalTitle(input2, init) {
|
|
8255
|
+
const url = fetchInputToUrl(input2);
|
|
8256
|
+
if (!/\/models\/[^/:]*(?:image|imagen)[^/:]*:streamGenerateContent/i.test(url)) {
|
|
8257
|
+
return void 0;
|
|
8258
|
+
}
|
|
8259
|
+
const body = init?.body;
|
|
8260
|
+
const bodyText = typeof body === "string" ? body : body instanceof Uint8Array ? new TextDecoder().decode(body) : "";
|
|
8261
|
+
if (!bodyText) {
|
|
8262
|
+
return void 0;
|
|
8263
|
+
}
|
|
8264
|
+
try {
|
|
8265
|
+
const sourceText = getOpenCodeTitleSourceText(JSON.parse(bodyText));
|
|
8266
|
+
return sourceText === void 0 ? void 0 : formatLocalImageTitle(sourceText);
|
|
8267
|
+
} catch {
|
|
8268
|
+
return void 0;
|
|
7860
8269
|
}
|
|
7861
|
-
return `agent/${crypto2.randomUUID()}/${Date.now()}/${crypto2.randomUUID()}/2`;
|
|
7862
8270
|
}
|
|
7863
8271
|
function getAgyMaxOutputTokens(model) {
|
|
7864
8272
|
const lower = model.toLowerCase();
|
|
7865
|
-
if (lower === "gemini-3.5-flash-low" || lower === "gemini-3.5-flash-extra-low" || lower === "gemini-3-flash-agent") {
|
|
8273
|
+
if (lower === "gemini-3.5-flash-low" || lower === "gemini-3.5-flash-extra-low" || lower === "gemini-3-flash-agent" || lower === "gemini-3.6-flash-low" || lower === "gemini-3.6-flash-medium" || lower === "gemini-3.6-flash-high") {
|
|
7866
8274
|
return 65536;
|
|
7867
8275
|
}
|
|
7868
8276
|
if (lower === "gemini-3.1-pro-low" || lower === "gemini-pro-agent") {
|
|
@@ -7871,6 +8279,9 @@ function getAgyMaxOutputTokens(model) {
|
|
|
7871
8279
|
if (lower === "claude-sonnet-4-6" || lower === "claude-opus-4-6-thinking") {
|
|
7872
8280
|
return 64e3;
|
|
7873
8281
|
}
|
|
8282
|
+
if (lower === "gpt-oss-120b-medium") {
|
|
8283
|
+
return 32768;
|
|
8284
|
+
}
|
|
7874
8285
|
return void 0;
|
|
7875
8286
|
}
|
|
7876
8287
|
function applyAgyGenerationDefaults(model, generationConfig, headerStyle) {
|
|
@@ -7907,7 +8318,7 @@ var JSON_SCHEMA_TYPES = /* @__PURE__ */ new Set(["boolean", "string", "number",
|
|
|
7907
8318
|
function thinkingSafeReplacer(key, value) {
|
|
7908
8319
|
if (key === "thinking" && typeof value === "object" && value !== null) {
|
|
7909
8320
|
const rec = value;
|
|
7910
|
-
if (typeof rec.type === "string" && JSON_SCHEMA_TYPES.has(rec.type)) {
|
|
8321
|
+
if (typeof rec.type === "string" && JSON_SCHEMA_TYPES.has(rec.type.toLowerCase())) {
|
|
7911
8322
|
return value;
|
|
7912
8323
|
}
|
|
7913
8324
|
return "";
|
|
@@ -8110,16 +8521,79 @@ function stripInjectedDebugFromRequestPayload(payload) {
|
|
|
8110
8521
|
if (Array.isArray(message.content)) {
|
|
8111
8522
|
return { ...message, content: stripInjectedDebugFromParts(message.content) };
|
|
8112
8523
|
}
|
|
8113
|
-
return message;
|
|
8114
|
-
});
|
|
8524
|
+
return message;
|
|
8525
|
+
});
|
|
8526
|
+
}
|
|
8527
|
+
}
|
|
8528
|
+
function isValidRequestPart(part) {
|
|
8529
|
+
if (!part || typeof part !== "object") {
|
|
8530
|
+
return false;
|
|
8531
|
+
}
|
|
8532
|
+
const record = part;
|
|
8533
|
+
return Object.prototype.hasOwnProperty.call(record, "text") || Object.prototype.hasOwnProperty.call(record, "functionCall") || Object.prototype.hasOwnProperty.call(record, "functionResponse") || Object.prototype.hasOwnProperty.call(record, "inlineData") || Object.prototype.hasOwnProperty.call(record, "fileData") || Object.prototype.hasOwnProperty.call(record, "executableCode") || Object.prototype.hasOwnProperty.call(record, "codeExecutionResult") || Object.prototype.hasOwnProperty.call(record, "thought");
|
|
8534
|
+
}
|
|
8535
|
+
function stripCacheControlFromParts(parts) {
|
|
8536
|
+
if (!Array.isArray(parts)) {
|
|
8537
|
+
return;
|
|
8538
|
+
}
|
|
8539
|
+
for (const part of parts) {
|
|
8540
|
+
if (!part || typeof part !== "object" || Array.isArray(part)) {
|
|
8541
|
+
continue;
|
|
8542
|
+
}
|
|
8543
|
+
const record = part;
|
|
8544
|
+
delete record.cache_control;
|
|
8545
|
+
delete record.cacheControl;
|
|
8546
|
+
}
|
|
8547
|
+
}
|
|
8548
|
+
function stripUnsupportedAntigravityFields(payload) {
|
|
8549
|
+
delete payload.providerOptions;
|
|
8550
|
+
delete payload.cached_content;
|
|
8551
|
+
delete payload.cachedContent;
|
|
8552
|
+
delete payload.cache_control;
|
|
8553
|
+
delete payload.cacheControl;
|
|
8554
|
+
const extraBody = payload.extra_body;
|
|
8555
|
+
if (extraBody && typeof extraBody === "object" && !Array.isArray(extraBody)) {
|
|
8556
|
+
const extraBodyRecord = extraBody;
|
|
8557
|
+
delete extraBodyRecord.cached_content;
|
|
8558
|
+
delete extraBodyRecord.cachedContent;
|
|
8559
|
+
delete extraBodyRecord.cache_control;
|
|
8560
|
+
delete extraBodyRecord.cacheControl;
|
|
8561
|
+
if (Object.keys(extraBodyRecord).length === 0) {
|
|
8562
|
+
delete payload.extra_body;
|
|
8563
|
+
}
|
|
8564
|
+
}
|
|
8565
|
+
const stripContentParts = (items) => {
|
|
8566
|
+
if (!Array.isArray(items)) {
|
|
8567
|
+
return;
|
|
8568
|
+
}
|
|
8569
|
+
for (const item of items) {
|
|
8570
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) {
|
|
8571
|
+
continue;
|
|
8572
|
+
}
|
|
8573
|
+
const record = item;
|
|
8574
|
+
stripCacheControlFromParts(record.parts);
|
|
8575
|
+
stripCacheControlFromParts(record.content);
|
|
8576
|
+
}
|
|
8577
|
+
};
|
|
8578
|
+
stripContentParts(payload.contents);
|
|
8579
|
+
stripContentParts(payload.messages);
|
|
8580
|
+
for (const instructionKey of ["systemInstruction", "system_instruction"]) {
|
|
8581
|
+
const instruction = payload[instructionKey];
|
|
8582
|
+
if (instruction && typeof instruction === "object" && !Array.isArray(instruction)) {
|
|
8583
|
+
stripCacheControlFromParts(instruction.parts);
|
|
8584
|
+
}
|
|
8115
8585
|
}
|
|
8116
8586
|
}
|
|
8117
|
-
function
|
|
8118
|
-
if (!
|
|
8119
|
-
|
|
8587
|
+
function configureAntigravityToolCalling(payload) {
|
|
8588
|
+
if (!Array.isArray(payload.tools) || payload.tools.length === 0) {
|
|
8589
|
+
delete payload.toolConfig;
|
|
8590
|
+
return;
|
|
8120
8591
|
}
|
|
8121
|
-
const
|
|
8122
|
-
|
|
8592
|
+
const toolConfig = payload.toolConfig && typeof payload.toolConfig === "object" && !Array.isArray(payload.toolConfig) ? payload.toolConfig : {};
|
|
8593
|
+
const functionCallingConfig = toolConfig.functionCallingConfig && typeof toolConfig.functionCallingConfig === "object" && !Array.isArray(toolConfig.functionCallingConfig) ? toolConfig.functionCallingConfig : {};
|
|
8594
|
+
functionCallingConfig.mode = "VALIDATED";
|
|
8595
|
+
toolConfig.functionCallingConfig = functionCallingConfig;
|
|
8596
|
+
payload.toolConfig = toolConfig;
|
|
8123
8597
|
}
|
|
8124
8598
|
function sanitizeRequestPayloadForAntigravity(payload) {
|
|
8125
8599
|
const anyPayload = payload;
|
|
@@ -8421,17 +8895,15 @@ var _lastCacheStats = null;
|
|
|
8421
8895
|
function getLastCacheStats() {
|
|
8422
8896
|
return _lastCacheStats;
|
|
8423
8897
|
}
|
|
8424
|
-
function generateSyntheticProjectId() {
|
|
8425
|
-
const adjectives = ["useful", "bright", "swift", "calm", "bold"];
|
|
8426
|
-
const nouns = ["fuze", "wave", "spark", "flow", "core"];
|
|
8427
|
-
const adj = adjectives[Math.floor(Math.random() * adjectives.length)];
|
|
8428
|
-
const noun = nouns[Math.floor(Math.random() * nouns.length)];
|
|
8429
|
-
const randomPart = crypto2.randomUUID().slice(0, 5).toLowerCase();
|
|
8430
|
-
return `${adj}-${noun}-${randomPart}`;
|
|
8431
|
-
}
|
|
8432
8898
|
var STREAM_ACTION = "streamGenerateContent";
|
|
8899
|
+
function fetchInputToUrl(input2) {
|
|
8900
|
+
if (typeof input2 === "string") return input2;
|
|
8901
|
+
if (input2 instanceof URL) return input2.href;
|
|
8902
|
+
const url = input2.url;
|
|
8903
|
+
return typeof url === "string" ? url : String(input2);
|
|
8904
|
+
}
|
|
8433
8905
|
function isGenerativeLanguageRequest(input2) {
|
|
8434
|
-
return
|
|
8906
|
+
return fetchInputToUrl(input2).includes("generativelanguage.googleapis.com");
|
|
8435
8907
|
}
|
|
8436
8908
|
function prepareAntigravityRequest(input2, init, accessToken, projectId, endpointOverride, headerStyle = "antigravity", forceThinkingRecovery = false, options) {
|
|
8437
8909
|
const baseInit = { ...init };
|
|
@@ -8455,8 +8927,11 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
|
|
|
8455
8927
|
headers.delete("x-api-key");
|
|
8456
8928
|
headers.delete("x-goog-api-key");
|
|
8457
8929
|
headers.delete("x-session-affinity");
|
|
8930
|
+
headers.delete("x-session-id");
|
|
8931
|
+
headers.delete("x-parent-session-id");
|
|
8458
8932
|
headers.delete("x-goog-user-project");
|
|
8459
|
-
const
|
|
8933
|
+
const urlString = fetchInputToUrl(input2);
|
|
8934
|
+
const match = urlString.match(/\/models\/([^:]+):(\w+)/);
|
|
8460
8935
|
if (!match) {
|
|
8461
8936
|
return {
|
|
8462
8937
|
request: input2,
|
|
@@ -8495,9 +8970,6 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
|
|
|
8495
8970
|
model: effectiveModel
|
|
8496
8971
|
};
|
|
8497
8972
|
if (headerStyle === "antigravity") {
|
|
8498
|
-
if (typeof wrappedBody.requestId !== "string" || !wrappedBody.requestId) {
|
|
8499
|
-
wrappedBody.requestId = buildAntigravityRequestId("agent");
|
|
8500
|
-
}
|
|
8501
8973
|
if (typeof wrappedBody.userAgent !== "string" || !wrappedBody.userAgent) {
|
|
8502
8974
|
wrappedBody.userAgent = "antigravity";
|
|
8503
8975
|
}
|
|
@@ -8521,7 +8993,6 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
|
|
|
8521
8993
|
sessionId = signatureSessionKey;
|
|
8522
8994
|
}
|
|
8523
8995
|
for (const req of requestObjects) {
|
|
8524
|
-
req.sessionId = signatureSessionKey;
|
|
8525
8996
|
stripInjectedDebugFromRequestPayload(req);
|
|
8526
8997
|
if (isClaude) {
|
|
8527
8998
|
sanitizeCrossModelPayloadInPlace(req, { targetModel: effectiveModel });
|
|
@@ -8534,6 +9005,11 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
|
|
|
8534
9005
|
}
|
|
8535
9006
|
applyToolPairingFixes(req, true);
|
|
8536
9007
|
}
|
|
9008
|
+
if (headerStyle === "antigravity") {
|
|
9009
|
+
sanitizeRequestPayloadForAntigravity(req);
|
|
9010
|
+
stripUnsupportedAntigravityFields(req);
|
|
9011
|
+
configureAntigravityToolCalling(req);
|
|
9012
|
+
}
|
|
8537
9013
|
}
|
|
8538
9014
|
if (isClaude) {
|
|
8539
9015
|
for (const req of requestObjects) {
|
|
@@ -8563,9 +9039,31 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
|
|
|
8563
9039
|
const hasCachedThinking = defaultSignatureStore.has(signatureSessionKey);
|
|
8564
9040
|
needsSignedThinkingWarmup = hasToolUse && !hasSignedThinking && !hasCachedThinking;
|
|
8565
9041
|
}
|
|
9042
|
+
const wireRequest = requestObjects.at(-1);
|
|
9043
|
+
if (wireRequest) {
|
|
9044
|
+
if (headerStyle === "antigravity") {
|
|
9045
|
+
const metadata = buildAgyAgentRequestMetadata(
|
|
9046
|
+
options?.agySession ?? DEFAULT_AGY_REQUEST_SESSION,
|
|
9047
|
+
wireRequest,
|
|
9048
|
+
effectiveModel,
|
|
9049
|
+
options?.agyRequestTimestamp
|
|
9050
|
+
);
|
|
9051
|
+
wrappedBody.requestId = metadata.requestId;
|
|
9052
|
+
wireRequest.sessionId = metadata.sessionId;
|
|
9053
|
+
wireRequest.labels = metadata.labels;
|
|
9054
|
+
orderAgyRequestPayloadInPlace(wireRequest);
|
|
9055
|
+
} else {
|
|
9056
|
+
wireRequest.sessionId = signatureSessionKey;
|
|
9057
|
+
}
|
|
9058
|
+
}
|
|
8566
9059
|
body = safeStringify(headerStyle === "antigravity" ? orderAntigravityEnvelope(wrappedBody) : wrappedBody);
|
|
8567
9060
|
} else {
|
|
8568
9061
|
const requestPayload = { ...parsedBody };
|
|
9062
|
+
if (headerStyle === "antigravity" && isImageGenerationModel(effectiveModel) && isOpenCodeTitleGenerationRequest(requestPayload)) {
|
|
9063
|
+
effectiveModel = "gemini-3.5-flash-low";
|
|
9064
|
+
tierThinkingBudget = 4e3;
|
|
9065
|
+
tierThinkingLevel = void 0;
|
|
9066
|
+
}
|
|
8569
9067
|
const rawGenerationConfig = requestPayload.generationConfig;
|
|
8570
9068
|
const extraBody = requestPayload.extra_body;
|
|
8571
9069
|
const variantConfig = extractVariantThinkingConfig(
|
|
@@ -8574,6 +9072,7 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
|
|
|
8574
9072
|
);
|
|
8575
9073
|
const isGemini3 = effectiveModel.toLowerCase().includes("gemini-3");
|
|
8576
9074
|
log6.debug(`[ThinkingResolution] rawModel=${rawModel} resolvedModel=${effectiveModel} resolvedTier=${tierThinkingLevel ?? "none"} variantLevel=${variantConfig?.thinkingLevel ?? "none"} variantBudget=${variantConfig?.thinkingBudget ?? "none"} providerOptions.google=${JSON.stringify(requestPayload.providerOptions?.google ?? null)} generationConfig.thinkingConfig=${JSON.stringify(rawGenerationConfig?.thinkingConfig ?? null)}`);
|
|
9075
|
+
delete requestPayload.providerOptions;
|
|
8577
9076
|
if (variantConfig?.thinkingLevel && isGemini3) {
|
|
8578
9077
|
const variantModelBase = rawModel.replace(/-preview-customtools$/i, "").replace(/-preview$/i, "").replace(/-(minimal|low|medium|high)$/i, "");
|
|
8579
9078
|
const variantResolved = resolveModelForHeaderStyle(
|
|
@@ -8593,20 +9092,6 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
|
|
|
8593
9092
|
tierThinkingLevel = void 0;
|
|
8594
9093
|
}
|
|
8595
9094
|
}
|
|
8596
|
-
if (isClaude) {
|
|
8597
|
-
if (!requestPayload.toolConfig) {
|
|
8598
|
-
requestPayload.toolConfig = {};
|
|
8599
|
-
}
|
|
8600
|
-
if (typeof requestPayload.toolConfig === "object" && requestPayload.toolConfig !== null) {
|
|
8601
|
-
const toolConfig = requestPayload.toolConfig;
|
|
8602
|
-
if (!toolConfig.functionCallingConfig) {
|
|
8603
|
-
toolConfig.functionCallingConfig = {};
|
|
8604
|
-
}
|
|
8605
|
-
if (typeof toolConfig.functionCallingConfig === "object" && toolConfig.functionCallingConfig !== null) {
|
|
8606
|
-
toolConfig.functionCallingConfig.mode = "VALIDATED";
|
|
8607
|
-
}
|
|
8608
|
-
}
|
|
8609
|
-
}
|
|
8610
9095
|
const isImageModel = isImageGenerationModel(effectiveModel);
|
|
8611
9096
|
const userThinkingConfig = isImageModel ? void 0 : extractThinkingConfig(requestPayload, rawGenerationConfig, extraBody);
|
|
8612
9097
|
const hasAssistantHistory = Array.isArray(requestPayload.contents) && requestPayload.contents.some((c) => c?.role === "model" || c?.role === "assistant");
|
|
@@ -8703,17 +9188,19 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
|
|
|
8703
9188
|
requestPayload.systemInstruction = requestPayload.system_instruction;
|
|
8704
9189
|
delete requestPayload.system_instruction;
|
|
8705
9190
|
}
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
9191
|
+
if (headerStyle !== "antigravity") {
|
|
9192
|
+
const cachedContentFromExtra = typeof requestPayload.extra_body === "object" && requestPayload.extra_body ? requestPayload.extra_body.cached_content ?? requestPayload.extra_body.cachedContent : void 0;
|
|
9193
|
+
const cachedContent = requestPayload.cached_content ?? requestPayload.cachedContent ?? cachedContentFromExtra;
|
|
9194
|
+
if (cachedContent) {
|
|
9195
|
+
requestPayload.cachedContent = cachedContent;
|
|
9196
|
+
}
|
|
9197
|
+
delete requestPayload.cached_content;
|
|
9198
|
+
if (requestPayload.extra_body && typeof requestPayload.extra_body === "object") {
|
|
9199
|
+
delete requestPayload.extra_body.cached_content;
|
|
9200
|
+
delete requestPayload.extra_body.cachedContent;
|
|
9201
|
+
if (Object.keys(requestPayload.extra_body).length === 0) {
|
|
9202
|
+
delete requestPayload.extra_body;
|
|
9203
|
+
}
|
|
8717
9204
|
}
|
|
8718
9205
|
}
|
|
8719
9206
|
const hasTools = Array.isArray(requestPayload.tools) && requestPayload.tools.length > 0;
|
|
@@ -8909,11 +9396,27 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
|
|
|
8909
9396
|
}
|
|
8910
9397
|
stripInjectedDebugFromRequestPayload(requestPayload);
|
|
8911
9398
|
sanitizeRequestPayloadForAntigravity(requestPayload);
|
|
8912
|
-
|
|
9399
|
+
if (headerStyle === "antigravity") {
|
|
9400
|
+
stripUnsupportedAntigravityFields(requestPayload);
|
|
9401
|
+
configureAntigravityToolCalling(requestPayload);
|
|
9402
|
+
}
|
|
9403
|
+
const effectiveProjectId = projectId?.trim() || (headerStyle === "antigravity" ? ANTIGRAVITY_DEFAULT_PROJECT_ID : "");
|
|
8913
9404
|
resolvedProjectId = effectiveProjectId;
|
|
9405
|
+
sessionId = signatureSessionKey;
|
|
9406
|
+
const agyMetadata = headerStyle === "antigravity" ? buildAgyAgentRequestMetadata(
|
|
9407
|
+
options?.agySession ?? DEFAULT_AGY_REQUEST_SESSION,
|
|
9408
|
+
requestPayload,
|
|
9409
|
+
effectiveModel,
|
|
9410
|
+
options?.agyRequestTimestamp
|
|
9411
|
+
) : null;
|
|
9412
|
+
requestPayload.sessionId = agyMetadata?.sessionId ?? signatureSessionKey;
|
|
9413
|
+
if (agyMetadata) {
|
|
9414
|
+
requestPayload.labels = agyMetadata.labels;
|
|
9415
|
+
orderAgyRequestPayloadInPlace(requestPayload);
|
|
9416
|
+
}
|
|
8914
9417
|
const wrappedBody = headerStyle === "antigravity" ? {
|
|
8915
9418
|
project: effectiveProjectId,
|
|
8916
|
-
requestId:
|
|
9419
|
+
requestId: agyMetadata.requestId,
|
|
8917
9420
|
request: requestPayload,
|
|
8918
9421
|
model: effectiveModel,
|
|
8919
9422
|
userAgent: "antigravity",
|
|
@@ -8923,10 +9426,6 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
|
|
|
8923
9426
|
model: effectiveModel,
|
|
8924
9427
|
request: requestPayload
|
|
8925
9428
|
};
|
|
8926
|
-
if (wrappedBody.request && typeof wrappedBody.request === "object") {
|
|
8927
|
-
sessionId = signatureSessionKey;
|
|
8928
|
-
wrappedBody.request.sessionId = signatureSessionKey;
|
|
8929
|
-
}
|
|
8930
9429
|
body = safeStringify(headerStyle === "antigravity" ? orderAntigravityEnvelope(wrappedBody) : wrappedBody);
|
|
8931
9430
|
}
|
|
8932
9431
|
} catch {
|
|
@@ -8988,17 +9487,20 @@ function buildThinkingWarmupBody(bodyText, isClaudeThinking) {
|
|
|
8988
9487
|
return null;
|
|
8989
9488
|
}
|
|
8990
9489
|
const warmupPrompt = "Warmup request for thinking signature.";
|
|
9490
|
+
const wireModel = typeof parsed.model === "string" ? parsed.model : "claude-sonnet-4-6";
|
|
9491
|
+
const requestObjects = [];
|
|
8991
9492
|
const updateRequest = (req) => {
|
|
8992
9493
|
req.contents = [{ role: "user", parts: [{ text: warmupPrompt }] }];
|
|
8993
9494
|
delete req.tools;
|
|
8994
9495
|
delete req.toolConfig;
|
|
8995
9496
|
const generationConfig = req.generationConfig ?? {};
|
|
8996
9497
|
generationConfig.thinkingConfig = {
|
|
8997
|
-
|
|
8998
|
-
|
|
9498
|
+
includeThoughts: true,
|
|
9499
|
+
thinkingBudget: AGY_CLAUDE_THINKING_BUDGET
|
|
8999
9500
|
};
|
|
9000
|
-
generationConfig.maxOutputTokens = computeClaudeMaxOutputTokens(
|
|
9501
|
+
generationConfig.maxOutputTokens = getAgyMaxOutputTokens(wireModel) ?? computeClaudeMaxOutputTokens(AGY_CLAUDE_THINKING_BUDGET);
|
|
9001
9502
|
req.generationConfig = generationConfig;
|
|
9503
|
+
requestObjects.push(req);
|
|
9002
9504
|
};
|
|
9003
9505
|
if (parsed.request && typeof parsed.request === "object") {
|
|
9004
9506
|
updateRequest(parsed.request);
|
|
@@ -9009,6 +9511,20 @@ function buildThinkingWarmupBody(bodyText, isClaudeThinking) {
|
|
|
9009
9511
|
} else {
|
|
9010
9512
|
updateRequest(parsed);
|
|
9011
9513
|
}
|
|
9514
|
+
const wireRequest = requestObjects.at(-1);
|
|
9515
|
+
if (wireRequest) {
|
|
9516
|
+
const numericSessionId = typeof wireRequest.sessionId === "string" ? wireRequest.sessionId : DEFAULT_AGY_REQUEST_SESSION.numericSessionId;
|
|
9517
|
+
const warmupSession = {
|
|
9518
|
+
conversationId: crypto2.randomUUID(),
|
|
9519
|
+
trajectoryId: crypto2.randomUUID(),
|
|
9520
|
+
numericSessionId
|
|
9521
|
+
};
|
|
9522
|
+
const metadata = buildAgyAgentRequestMetadata(warmupSession, wireRequest, wireModel);
|
|
9523
|
+
parsed.requestId = metadata.requestId;
|
|
9524
|
+
wireRequest.sessionId = metadata.sessionId;
|
|
9525
|
+
wireRequest.labels = metadata.labels;
|
|
9526
|
+
orderAgyRequestPayloadInPlace(wireRequest);
|
|
9527
|
+
}
|
|
9012
9528
|
return safeStringify(parsed);
|
|
9013
9529
|
}
|
|
9014
9530
|
async function transformAntigravityResponse(response, streaming, debugContext, requestedModel, projectId, endpoint, effectiveModel, sessionId, toolDebugMissing, toolDebugSummary, toolDebugPayload, debugLines, dumpContext) {
|
|
@@ -9381,12 +9897,12 @@ async function startOAuthListener({ timeoutMs = 5 * 60 * 1e3 } = {}) {
|
|
|
9381
9897
|
let resolveCallback;
|
|
9382
9898
|
let rejectCallback;
|
|
9383
9899
|
let timeoutHandle;
|
|
9384
|
-
const callbackPromise = new Promise((
|
|
9900
|
+
const callbackPromise = new Promise((resolve2, reject) => {
|
|
9385
9901
|
resolveCallback = (url) => {
|
|
9386
9902
|
if (settled) return;
|
|
9387
9903
|
settled = true;
|
|
9388
9904
|
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
9389
|
-
|
|
9905
|
+
resolve2(url);
|
|
9390
9906
|
};
|
|
9391
9907
|
rejectCallback = (error) => {
|
|
9392
9908
|
if (settled) return;
|
|
@@ -9544,7 +10060,7 @@ async function startOAuthListener({ timeoutMs = 5 * 60 * 1e3 } = {}) {
|
|
|
9544
10060
|
});
|
|
9545
10061
|
});
|
|
9546
10062
|
const bindAddress = getBindAddress();
|
|
9547
|
-
await new Promise((
|
|
10063
|
+
await new Promise((resolve2, reject) => {
|
|
9548
10064
|
const handleError = (error) => {
|
|
9549
10065
|
server.off("error", handleError);
|
|
9550
10066
|
if (error.code === "EADDRINUSE") {
|
|
@@ -9558,7 +10074,7 @@ async function startOAuthListener({ timeoutMs = 5 * 60 * 1e3 } = {}) {
|
|
|
9558
10074
|
server.once("error", handleError);
|
|
9559
10075
|
server.listen(port, bindAddress, () => {
|
|
9560
10076
|
server.off("error", handleError);
|
|
9561
|
-
|
|
10077
|
+
resolve2();
|
|
9562
10078
|
});
|
|
9563
10079
|
});
|
|
9564
10080
|
server.on("error", (error) => {
|
|
@@ -9566,7 +10082,7 @@ async function startOAuthListener({ timeoutMs = 5 * 60 * 1e3 } = {}) {
|
|
|
9566
10082
|
});
|
|
9567
10083
|
return {
|
|
9568
10084
|
waitForCallback: () => callbackPromise,
|
|
9569
|
-
close: () => new Promise((
|
|
10085
|
+
close: () => new Promise((resolve2, reject) => {
|
|
9570
10086
|
server.close((error) => {
|
|
9571
10087
|
if (error && error.code !== "ERR_SERVER_NOT_RUNNING") {
|
|
9572
10088
|
reject(error);
|
|
@@ -9575,7 +10091,7 @@ async function startOAuthListener({ timeoutMs = 5 * 60 * 1e3 } = {}) {
|
|
|
9575
10091
|
if (!settled) {
|
|
9576
10092
|
rejectCallback(new Error("OAuth listener closed before callback"));
|
|
9577
10093
|
}
|
|
9578
|
-
|
|
10094
|
+
resolve2();
|
|
9579
10095
|
});
|
|
9580
10096
|
})
|
|
9581
10097
|
};
|
|
@@ -9969,6 +10485,8 @@ function computeSoftQuotaCacheTtlMs(ttlConfig, refreshIntervalMinutes) {
|
|
|
9969
10485
|
}
|
|
9970
10486
|
return ttlConfig * 60 * 1e3;
|
|
9971
10487
|
}
|
|
10488
|
+
var ACCOUNT_SESSION_STATE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
10489
|
+
var MAX_ACCOUNT_SESSION_STATES = 256;
|
|
9972
10490
|
var AccountManager = class _AccountManager {
|
|
9973
10491
|
accounts = [];
|
|
9974
10492
|
cursorByFamily = { claude: 0, gemini: 0 };
|
|
@@ -9988,6 +10506,7 @@ var AccountManager = class _AccountManager {
|
|
|
9988
10506
|
sessionStartTime = Date.now();
|
|
9989
10507
|
sessionRequestCounts = /* @__PURE__ */ new Map();
|
|
9990
10508
|
sessionUsedAccounts = /* @__PURE__ */ new Set();
|
|
10509
|
+
requestSessionStates = /* @__PURE__ */ new Map();
|
|
9991
10510
|
static async loadFromDisk(authFallback) {
|
|
9992
10511
|
const stored = await loadAccounts();
|
|
9993
10512
|
return new _AccountManager(authFallback, stored);
|
|
@@ -10032,7 +10551,11 @@ var AccountManager = class _AccountManager {
|
|
|
10032
10551
|
verificationRequired: acc.verificationRequired,
|
|
10033
10552
|
verificationRequiredAt: acc.verificationRequiredAt,
|
|
10034
10553
|
verificationRequiredReason: acc.verificationRequiredReason,
|
|
10035
|
-
verificationUrl: acc.verificationUrl
|
|
10554
|
+
verificationUrl: acc.verificationUrl,
|
|
10555
|
+
accountIneligible: acc.accountIneligible,
|
|
10556
|
+
accountIneligibleAt: acc.accountIneligibleAt,
|
|
10557
|
+
accountIneligibleReason: acc.accountIneligibleReason,
|
|
10558
|
+
eligibilityStateUpdatedAt: acc.eligibilityStateUpdatedAt
|
|
10036
10559
|
};
|
|
10037
10560
|
}).filter((a) => a !== null);
|
|
10038
10561
|
let fingerprintVersionChanged = false;
|
|
@@ -10114,11 +10637,104 @@ var AccountManager = class _AccountManager {
|
|
|
10114
10637
|
getEnabledAccounts() {
|
|
10115
10638
|
return this.accounts.filter((account) => account.enabled !== false);
|
|
10116
10639
|
}
|
|
10640
|
+
getEffectiveSoftQuotaThreshold(thresholdPercent) {
|
|
10641
|
+
return this.getEnabledAccounts().length > 1 ? thresholdPercent : 100;
|
|
10642
|
+
}
|
|
10117
10643
|
getAccountsSnapshot() {
|
|
10118
10644
|
return this.accounts.map((a) => ({ ...a, parts: { ...a.parts }, rateLimitResetTimes: { ...a.rateLimitResetTimes } }));
|
|
10119
10645
|
}
|
|
10120
|
-
|
|
10121
|
-
const
|
|
10646
|
+
getRequestSessionState(identity) {
|
|
10647
|
+
const now = nowMs();
|
|
10648
|
+
this.pruneRequestSessionStates(now, identity.id);
|
|
10649
|
+
const existing = this.requestSessionStates.get(identity.id);
|
|
10650
|
+
if (existing) {
|
|
10651
|
+
existing.lastAccessedAt = now;
|
|
10652
|
+
if (identity.parentId) {
|
|
10653
|
+
existing.parentId = identity.parentId;
|
|
10654
|
+
}
|
|
10655
|
+
return existing;
|
|
10656
|
+
}
|
|
10657
|
+
const state = {
|
|
10658
|
+
parentId: identity.parentId ?? null,
|
|
10659
|
+
currentAccountIndexByFamily: { claude: -1, gemini: -1 },
|
|
10660
|
+
cursorByFamily: { ...this.cursorByFamily },
|
|
10661
|
+
offsetAppliedByFamily: { claude: false, gemini: false },
|
|
10662
|
+
usedAccounts: /* @__PURE__ */ new Set(),
|
|
10663
|
+
lastAccessedAt: now
|
|
10664
|
+
};
|
|
10665
|
+
this.requestSessionStates.set(identity.id, state);
|
|
10666
|
+
return state;
|
|
10667
|
+
}
|
|
10668
|
+
pruneRequestSessionStates(now, preservedId) {
|
|
10669
|
+
const expiry = now - ACCOUNT_SESSION_STATE_TTL_MS;
|
|
10670
|
+
for (const [id, state] of this.requestSessionStates) {
|
|
10671
|
+
if (id !== preservedId && state.lastAccessedAt < expiry) {
|
|
10672
|
+
this.requestSessionStates.delete(id);
|
|
10673
|
+
}
|
|
10674
|
+
}
|
|
10675
|
+
if (this.requestSessionStates.size < MAX_ACCOUNT_SESSION_STATES || this.requestSessionStates.has(preservedId)) {
|
|
10676
|
+
return;
|
|
10677
|
+
}
|
|
10678
|
+
let oldestId = null;
|
|
10679
|
+
let oldestAccess = Number.POSITIVE_INFINITY;
|
|
10680
|
+
for (const [id, state] of this.requestSessionStates) {
|
|
10681
|
+
if (id !== preservedId && state.lastAccessedAt < oldestAccess) {
|
|
10682
|
+
oldestId = id;
|
|
10683
|
+
oldestAccess = state.lastAccessedAt;
|
|
10684
|
+
}
|
|
10685
|
+
}
|
|
10686
|
+
if (oldestId) {
|
|
10687
|
+
this.requestSessionStates.delete(oldestId);
|
|
10688
|
+
}
|
|
10689
|
+
}
|
|
10690
|
+
getActiveIndex(family, identity) {
|
|
10691
|
+
return identity ? this.getRequestSessionState(identity).currentAccountIndexByFamily[family] : this.currentAccountIndexByFamily[family];
|
|
10692
|
+
}
|
|
10693
|
+
setActiveIndex(family, index, identity) {
|
|
10694
|
+
if (!identity) {
|
|
10695
|
+
this.currentAccountIndexByFamily[family] = index;
|
|
10696
|
+
return;
|
|
10697
|
+
}
|
|
10698
|
+
const state = this.getRequestSessionState(identity);
|
|
10699
|
+
state.currentAccountIndexByFamily[family] = index;
|
|
10700
|
+
if (!state.parentId) {
|
|
10701
|
+
this.currentAccountIndexByFamily[family] = index;
|
|
10702
|
+
}
|
|
10703
|
+
}
|
|
10704
|
+
getCursor(family, identity) {
|
|
10705
|
+
return identity ? this.getRequestSessionState(identity).cursorByFamily[family] : this.cursorByFamily[family];
|
|
10706
|
+
}
|
|
10707
|
+
advanceCursor(family, identity) {
|
|
10708
|
+
const nextGlobalCursor = this.cursorByFamily[family] + 1;
|
|
10709
|
+
this.cursorByFamily[family] = nextGlobalCursor;
|
|
10710
|
+
if (identity) {
|
|
10711
|
+
this.getRequestSessionState(identity).cursorByFamily[family] += 1;
|
|
10712
|
+
}
|
|
10713
|
+
}
|
|
10714
|
+
getUsedAccounts(identity) {
|
|
10715
|
+
return identity ? this.getRequestSessionState(identity).usedAccounts : this.sessionUsedAccounts;
|
|
10716
|
+
}
|
|
10717
|
+
preferAccountOutsideParent(accounts, family, identity) {
|
|
10718
|
+
if (!identity) {
|
|
10719
|
+
return accounts;
|
|
10720
|
+
}
|
|
10721
|
+
const parentId = this.getRequestSessionState(identity).parentId;
|
|
10722
|
+
if (!parentId) {
|
|
10723
|
+
return accounts;
|
|
10724
|
+
}
|
|
10725
|
+
const parentState = this.requestSessionStates.get(parentId);
|
|
10726
|
+
const parentIndex = parentState?.currentAccountIndexByFamily[family] ?? -1;
|
|
10727
|
+
if (parentIndex < 0) {
|
|
10728
|
+
return accounts;
|
|
10729
|
+
}
|
|
10730
|
+
const isolated = accounts.filter((account) => account.index !== parentIndex);
|
|
10731
|
+
return isolated.length > 0 ? isolated : accounts;
|
|
10732
|
+
}
|
|
10733
|
+
deleteSessionState(sessionId) {
|
|
10734
|
+
this.requestSessionStates.delete(sessionId);
|
|
10735
|
+
}
|
|
10736
|
+
getCurrentAccountForFamily(family, identity) {
|
|
10737
|
+
const currentIndex = this.getActiveIndex(family, identity);
|
|
10122
10738
|
if (currentIndex >= 0 && currentIndex < this.accounts.length) {
|
|
10123
10739
|
const account = this.accounts[currentIndex] ?? null;
|
|
10124
10740
|
if (account && account.enabled !== false) {
|
|
@@ -10127,9 +10743,9 @@ var AccountManager = class _AccountManager {
|
|
|
10127
10743
|
}
|
|
10128
10744
|
return null;
|
|
10129
10745
|
}
|
|
10130
|
-
markSwitched(account, reason, family) {
|
|
10746
|
+
markSwitched(account, reason, family, identity) {
|
|
10131
10747
|
account.lastSwitchReason = reason;
|
|
10132
|
-
this.
|
|
10748
|
+
this.setActiveIndex(family, account.index, identity);
|
|
10133
10749
|
}
|
|
10134
10750
|
/**
|
|
10135
10751
|
* Check if we should show an account switch toast.
|
|
@@ -10146,82 +10762,111 @@ var AccountManager = class _AccountManager {
|
|
|
10146
10762
|
this.lastToastAccountIndex = accountIndex;
|
|
10147
10763
|
this.lastToastTime = nowMs();
|
|
10148
10764
|
}
|
|
10149
|
-
getCurrentOrNextForFamily(family, model, strategy = "sticky", headerStyle = "antigravity", pidOffsetEnabled = false, softQuotaThresholdPercent = 100, softQuotaCacheTtlMs = 10 * 60 * 1e3) {
|
|
10765
|
+
getCurrentOrNextForFamily(family, model, strategy = "sticky", headerStyle = "antigravity", pidOffsetEnabled = false, softQuotaThresholdPercent = 100, softQuotaCacheTtlMs = 10 * 60 * 1e3, identity) {
|
|
10150
10766
|
const quotaKey = getQuotaKey(family, headerStyle, model);
|
|
10767
|
+
const effectiveSoftQuotaThreshold = this.getEffectiveSoftQuotaThreshold(softQuotaThresholdPercent);
|
|
10768
|
+
if (identity) {
|
|
10769
|
+
const pinned = this.getCurrentAccountForFamily(family, identity);
|
|
10770
|
+
if (pinned) {
|
|
10771
|
+
clearExpiredRateLimits(pinned);
|
|
10772
|
+
const unavailable = isRateLimitedForHeaderStyle(pinned, family, headerStyle, model) || isOverSoftQuotaThreshold(pinned, family, effectiveSoftQuotaThreshold, softQuotaCacheTtlMs, model) || this.isAccountCoolingDown(pinned);
|
|
10773
|
+
if (!unavailable) {
|
|
10774
|
+
this.markTouchedForQuota(pinned, quotaKey);
|
|
10775
|
+
return pinned;
|
|
10776
|
+
}
|
|
10777
|
+
}
|
|
10778
|
+
}
|
|
10151
10779
|
if (strategy === "round-robin") {
|
|
10152
|
-
const next2 = this.getNextForFamily(family, model, headerStyle,
|
|
10780
|
+
const next2 = this.getNextForFamily(family, model, headerStyle, effectiveSoftQuotaThreshold, softQuotaCacheTtlMs, identity);
|
|
10153
10781
|
if (next2) {
|
|
10154
10782
|
this.markTouchedForQuota(next2, quotaKey);
|
|
10155
|
-
this.
|
|
10783
|
+
this.setActiveIndex(family, next2.index, identity);
|
|
10156
10784
|
}
|
|
10157
10785
|
return next2;
|
|
10158
10786
|
}
|
|
10159
10787
|
if (strategy === "hybrid") {
|
|
10160
10788
|
const healthTracker = getHealthTracker();
|
|
10161
10789
|
const tokenTracker = getTokenTracker();
|
|
10162
|
-
const
|
|
10790
|
+
const eligibleAccounts = this.preferAccountOutsideParent(
|
|
10791
|
+
this.accounts.filter((acc) => acc.enabled !== false),
|
|
10792
|
+
family,
|
|
10793
|
+
identity
|
|
10794
|
+
);
|
|
10795
|
+
const accountsWithMetrics = eligibleAccounts.map((acc) => {
|
|
10163
10796
|
clearExpiredRateLimits(acc);
|
|
10164
10797
|
return {
|
|
10165
10798
|
index: acc.index,
|
|
10166
10799
|
lastUsed: acc.lastUsed,
|
|
10167
10800
|
healthScore: healthTracker.getScore(acc.index),
|
|
10168
|
-
isRateLimited: isRateLimitedForFamily(acc, family, model) || isOverSoftQuotaThreshold(acc, family,
|
|
10801
|
+
isRateLimited: isRateLimitedForFamily(acc, family, model) || isOverSoftQuotaThreshold(acc, family, effectiveSoftQuotaThreshold, softQuotaCacheTtlMs, model),
|
|
10169
10802
|
isCoolingDown: this.isAccountCoolingDown(acc)
|
|
10170
10803
|
};
|
|
10171
10804
|
});
|
|
10172
|
-
const currentIndex = this.
|
|
10805
|
+
const currentIndex = this.getActiveIndex(family, identity);
|
|
10173
10806
|
const selectedIndex = selectHybridAccount(accountsWithMetrics, tokenTracker, currentIndex);
|
|
10174
10807
|
if (selectedIndex !== null) {
|
|
10175
10808
|
const selected = this.accounts[selectedIndex];
|
|
10176
10809
|
if (selected) {
|
|
10177
10810
|
selected.lastUsed = nowMs();
|
|
10178
10811
|
this.markTouchedForQuota(selected, quotaKey);
|
|
10179
|
-
this.
|
|
10812
|
+
this.setActiveIndex(family, selected.index, identity);
|
|
10180
10813
|
return selected;
|
|
10181
10814
|
}
|
|
10182
10815
|
}
|
|
10183
10816
|
}
|
|
10184
|
-
|
|
10817
|
+
const offsetApplied = identity ? this.getRequestSessionState(identity).offsetAppliedByFamily : this.sessionOffsetApplied;
|
|
10818
|
+
if (pidOffsetEnabled && !offsetApplied[family] && this.accounts.length > 1) {
|
|
10185
10819
|
const pidOffset = process.pid % this.accounts.length;
|
|
10186
|
-
const
|
|
10820
|
+
const activeIndex = this.getActiveIndex(family, identity);
|
|
10821
|
+
const baseIndex = activeIndex >= 0 ? activeIndex : this.getCursor(family, identity);
|
|
10187
10822
|
const newIndex = (baseIndex + pidOffset) % this.accounts.length;
|
|
10188
10823
|
debugLogToFile(`[Account] Applying PID offset: pid=${process.pid} offset=${pidOffset} family=${family} index=${baseIndex}->${newIndex}`);
|
|
10189
|
-
this.
|
|
10190
|
-
|
|
10824
|
+
this.setActiveIndex(family, newIndex, identity);
|
|
10825
|
+
offsetApplied[family] = true;
|
|
10191
10826
|
}
|
|
10192
|
-
const current = this.getCurrentAccountForFamily(family);
|
|
10827
|
+
const current = this.getCurrentAccountForFamily(family, identity);
|
|
10193
10828
|
if (current) {
|
|
10194
10829
|
clearExpiredRateLimits(current);
|
|
10195
10830
|
const isLimitedForRequestedStyle = isRateLimitedForHeaderStyle(current, family, headerStyle, model);
|
|
10196
|
-
const isOverThreshold = isOverSoftQuotaThreshold(current, family,
|
|
10831
|
+
const isOverThreshold = isOverSoftQuotaThreshold(current, family, effectiveSoftQuotaThreshold, softQuotaCacheTtlMs, model);
|
|
10197
10832
|
if (!isLimitedForRequestedStyle && !isOverThreshold && !this.isAccountCoolingDown(current)) {
|
|
10198
10833
|
this.markTouchedForQuota(current, quotaKey);
|
|
10199
10834
|
return current;
|
|
10200
10835
|
}
|
|
10201
10836
|
}
|
|
10202
|
-
const next = this.getNextForFamily(
|
|
10837
|
+
const next = this.getNextForFamily(
|
|
10838
|
+
family,
|
|
10839
|
+
model,
|
|
10840
|
+
headerStyle,
|
|
10841
|
+
effectiveSoftQuotaThreshold,
|
|
10842
|
+
softQuotaCacheTtlMs,
|
|
10843
|
+
identity
|
|
10844
|
+
);
|
|
10203
10845
|
if (next) {
|
|
10204
10846
|
this.markTouchedForQuota(next, quotaKey);
|
|
10205
|
-
this.
|
|
10847
|
+
this.setActiveIndex(family, next.index, identity);
|
|
10206
10848
|
}
|
|
10207
10849
|
return next;
|
|
10208
10850
|
}
|
|
10209
|
-
getNextForFamily(family, model, headerStyle = "antigravity", softQuotaThresholdPercent = 100, softQuotaCacheTtlMs = 10 * 60 * 1e3) {
|
|
10210
|
-
const
|
|
10211
|
-
|
|
10212
|
-
|
|
10851
|
+
getNextForFamily(family, model, headerStyle = "antigravity", softQuotaThresholdPercent = 100, softQuotaCacheTtlMs = 10 * 60 * 1e3, identity) {
|
|
10852
|
+
const effectiveSoftQuotaThreshold = this.getEffectiveSoftQuotaThreshold(softQuotaThresholdPercent);
|
|
10853
|
+
const allAvailable = this.accounts.filter((account2) => {
|
|
10854
|
+
clearExpiredRateLimits(account2);
|
|
10855
|
+
return account2.enabled !== false && !isRateLimitedForHeaderStyle(account2, family, headerStyle, model) && !isOverSoftQuotaThreshold(account2, family, effectiveSoftQuotaThreshold, softQuotaCacheTtlMs, model) && !this.isAccountCoolingDown(account2);
|
|
10213
10856
|
});
|
|
10857
|
+
const available = this.preferAccountOutsideParent(allAvailable, family, identity);
|
|
10214
10858
|
if (available.length === 0) {
|
|
10215
10859
|
return null;
|
|
10216
10860
|
}
|
|
10217
|
-
const
|
|
10861
|
+
const usedAccounts = this.getUsedAccounts(identity);
|
|
10862
|
+
const sessionUsed = available.filter((account2) => usedAccounts.has(account2.index));
|
|
10218
10863
|
const candidates = sessionUsed.length > 0 ? sessionUsed : available;
|
|
10219
|
-
const cursor = this.
|
|
10864
|
+
const cursor = this.getCursor(family, identity);
|
|
10220
10865
|
const account = candidates[cursor % candidates.length];
|
|
10221
10866
|
if (!account) {
|
|
10222
10867
|
return null;
|
|
10223
10868
|
}
|
|
10224
|
-
this.
|
|
10869
|
+
this.advanceCursor(family, identity);
|
|
10225
10870
|
return account;
|
|
10226
10871
|
}
|
|
10227
10872
|
markRateLimited(account, retryAfterMs, family, headerStyle = "antigravity", model) {
|
|
@@ -10239,15 +10884,15 @@ var AccountManager = class _AccountManager {
|
|
|
10239
10884
|
account.lastUsed = nowMs();
|
|
10240
10885
|
}
|
|
10241
10886
|
}
|
|
10242
|
-
recordSessionUsage(accountIndex) {
|
|
10243
|
-
this.
|
|
10887
|
+
recordSessionUsage(accountIndex, identity) {
|
|
10888
|
+
this.getUsedAccounts(identity).add(accountIndex);
|
|
10244
10889
|
}
|
|
10245
|
-
wasUsedInSession(accountIndex) {
|
|
10246
|
-
return this.
|
|
10890
|
+
wasUsedInSession(accountIndex, identity) {
|
|
10891
|
+
return this.getUsedAccounts(identity).has(accountIndex);
|
|
10247
10892
|
}
|
|
10248
|
-
shouldProactivelyRotate(family, model, thresholdPercent, cacheTtlMs) {
|
|
10893
|
+
shouldProactivelyRotate(family, model, thresholdPercent, cacheTtlMs, identity) {
|
|
10249
10894
|
if (thresholdPercent <= 0) return false;
|
|
10250
|
-
const current = this.getCurrentAccountForFamily(family);
|
|
10895
|
+
const current = this.getCurrentAccountForFamily(family, identity);
|
|
10251
10896
|
if (!current || !current.cachedQuota || current.cachedQuotaUpdatedAt == null) return false;
|
|
10252
10897
|
const age = nowMs() - current.cachedQuotaUpdatedAt;
|
|
10253
10898
|
if (age > cacheTtlMs) return false;
|
|
@@ -10257,9 +10902,9 @@ var AccountManager = class _AccountManager {
|
|
|
10257
10902
|
const remainingPercent = Math.max(0, Math.min(100, groupData.remainingFraction * 100));
|
|
10258
10903
|
return remainingPercent < thresholdPercent;
|
|
10259
10904
|
}
|
|
10260
|
-
proactivelyRotateForFamily(family, model, headerStyle, softQuotaThresholdPercent, softQuotaCacheTtlMs) {
|
|
10261
|
-
const currentIndex = this.
|
|
10262
|
-
const candidates = this.accounts.filter((acc) => {
|
|
10905
|
+
proactivelyRotateForFamily(family, model, headerStyle, softQuotaThresholdPercent, softQuotaCacheTtlMs, identity) {
|
|
10906
|
+
const currentIndex = this.getActiveIndex(family, identity);
|
|
10907
|
+
const candidates = this.preferAccountOutsideParent(this.accounts.filter((acc) => {
|
|
10263
10908
|
if (acc.enabled === false) return false;
|
|
10264
10909
|
if (acc.index === currentIndex) return false;
|
|
10265
10910
|
clearExpiredRateLimits(acc);
|
|
@@ -10267,9 +10912,10 @@ var AccountManager = class _AccountManager {
|
|
|
10267
10912
|
if (isOverSoftQuotaThreshold(acc, family, softQuotaThresholdPercent, softQuotaCacheTtlMs, model)) return false;
|
|
10268
10913
|
if (this.isAccountCoolingDown(acc)) return false;
|
|
10269
10914
|
return true;
|
|
10270
|
-
});
|
|
10915
|
+
}), family, identity);
|
|
10271
10916
|
if (candidates.length === 0) return null;
|
|
10272
|
-
const
|
|
10917
|
+
const usedAccounts = this.getUsedAccounts(identity);
|
|
10918
|
+
const warmCandidates = candidates.filter((account) => usedAccounts.has(account.index));
|
|
10273
10919
|
const pool = warmCandidates.length > 0 ? warmCandidates : candidates;
|
|
10274
10920
|
const quotaGroup = resolveQuotaGroup(family, model);
|
|
10275
10921
|
pool.sort((a, b) => {
|
|
@@ -10281,7 +10927,7 @@ var AccountManager = class _AccountManager {
|
|
|
10281
10927
|
if (!selected) return null;
|
|
10282
10928
|
const quotaKey = getQuotaKey(family, headerStyle, model);
|
|
10283
10929
|
this.markTouchedForQuota(selected, quotaKey);
|
|
10284
|
-
this.
|
|
10930
|
+
this.setActiveIndex(family, selected.index, identity);
|
|
10285
10931
|
return selected;
|
|
10286
10932
|
}
|
|
10287
10933
|
markRateLimitedWithReason(account, family, headerStyle, model, reason, retryAfterMs, failureTtlMs = 36e5) {
|
|
@@ -10407,6 +11053,9 @@ var AccountManager = class _AccountManager {
|
|
|
10407
11053
|
if (!account) {
|
|
10408
11054
|
return false;
|
|
10409
11055
|
}
|
|
11056
|
+
if (enabled && account.accountIneligible) {
|
|
11057
|
+
return false;
|
|
11058
|
+
}
|
|
10410
11059
|
account.enabled = enabled;
|
|
10411
11060
|
if (!enabled) {
|
|
10412
11061
|
for (const family of Object.keys(this.currentAccountIndexByFamily)) {
|
|
@@ -10424,9 +11073,16 @@ var AccountManager = class _AccountManager {
|
|
|
10424
11073
|
if (!account) {
|
|
10425
11074
|
return false;
|
|
10426
11075
|
}
|
|
11076
|
+
const timestamp = nowMs();
|
|
10427
11077
|
account.verificationRequired = true;
|
|
10428
|
-
account.verificationRequiredAt =
|
|
11078
|
+
account.verificationRequiredAt = timestamp;
|
|
10429
11079
|
account.verificationRequiredReason = reason?.trim() || void 0;
|
|
11080
|
+
if (account.accountIneligible === true || account.accountIneligibleAt !== void 0 || account.accountIneligibleReason !== void 0) {
|
|
11081
|
+
account.accountIneligible = false;
|
|
11082
|
+
account.accountIneligibleAt = void 0;
|
|
11083
|
+
account.accountIneligibleReason = void 0;
|
|
11084
|
+
account.eligibilityStateUpdatedAt = timestamp;
|
|
11085
|
+
}
|
|
10430
11086
|
const normalizedVerifyUrl = verifyUrl?.trim();
|
|
10431
11087
|
if (normalizedVerifyUrl) {
|
|
10432
11088
|
account.verificationUrl = normalizedVerifyUrl;
|
|
@@ -10438,20 +11094,48 @@ var AccountManager = class _AccountManager {
|
|
|
10438
11094
|
}
|
|
10439
11095
|
return true;
|
|
10440
11096
|
}
|
|
10441
|
-
|
|
11097
|
+
markAccountIneligible(accountIndex, reason) {
|
|
11098
|
+
const account = this.accounts[accountIndex];
|
|
11099
|
+
if (!account) {
|
|
11100
|
+
return false;
|
|
11101
|
+
}
|
|
11102
|
+
const timestamp = nowMs();
|
|
11103
|
+
account.accountIneligible = true;
|
|
11104
|
+
account.accountIneligibleAt = timestamp;
|
|
11105
|
+
account.accountIneligibleReason = reason?.trim() || "Google marked this account as ineligible.";
|
|
11106
|
+
account.eligibilityStateUpdatedAt = timestamp;
|
|
11107
|
+
account.verificationRequired = false;
|
|
11108
|
+
account.verificationRequiredAt = void 0;
|
|
11109
|
+
account.verificationRequiredReason = void 0;
|
|
11110
|
+
account.verificationUrl = void 0;
|
|
11111
|
+
if (account.enabled !== false) {
|
|
11112
|
+
this.setAccountEnabled(accountIndex, false);
|
|
11113
|
+
} else {
|
|
11114
|
+
this.requestSaveToDisk();
|
|
11115
|
+
}
|
|
11116
|
+
return true;
|
|
11117
|
+
}
|
|
11118
|
+
clearAccountAccessBlocks(accountIndex, enableAccount = false) {
|
|
10442
11119
|
const account = this.accounts[accountIndex];
|
|
10443
11120
|
if (!account) {
|
|
10444
11121
|
return false;
|
|
10445
11122
|
}
|
|
10446
11123
|
const wasVerificationRequired = account.verificationRequired === true;
|
|
10447
|
-
const
|
|
11124
|
+
const wasIneligible = account.accountIneligible === true;
|
|
11125
|
+
const hadMetadata = wasVerificationRequired || wasIneligible || account.verificationRequiredAt !== void 0 || account.verificationRequiredReason !== void 0 || account.verificationUrl !== void 0 || account.accountIneligibleAt !== void 0 || account.accountIneligibleReason !== void 0 || account.eligibilityStateUpdatedAt !== void 0;
|
|
10448
11126
|
account.verificationRequired = false;
|
|
10449
11127
|
account.verificationRequiredAt = void 0;
|
|
10450
11128
|
account.verificationRequiredReason = void 0;
|
|
10451
11129
|
account.verificationUrl = void 0;
|
|
10452
|
-
|
|
11130
|
+
account.accountIneligible = false;
|
|
11131
|
+
account.accountIneligibleAt = void 0;
|
|
11132
|
+
account.accountIneligibleReason = void 0;
|
|
11133
|
+
if (wasIneligible || account.eligibilityStateUpdatedAt !== void 0) {
|
|
11134
|
+
account.eligibilityStateUpdatedAt = nowMs();
|
|
11135
|
+
}
|
|
11136
|
+
if (enableAccount && (wasVerificationRequired || wasIneligible) && account.enabled === false) {
|
|
10453
11137
|
this.setAccountEnabled(accountIndex, true);
|
|
10454
|
-
} else if (
|
|
11138
|
+
} else if (hadMetadata) {
|
|
10455
11139
|
this.requestSaveToDisk();
|
|
10456
11140
|
}
|
|
10457
11141
|
return true;
|
|
@@ -10479,6 +11163,7 @@ var AccountManager = class _AccountManager {
|
|
|
10479
11163
|
this.cursorByFamily = { claude: 0, gemini: 0 };
|
|
10480
11164
|
this.currentAccountIndexByFamily.claude = -1;
|
|
10481
11165
|
this.currentAccountIndexByFamily.gemini = -1;
|
|
11166
|
+
this.requestSessionStates.clear();
|
|
10482
11167
|
return true;
|
|
10483
11168
|
}
|
|
10484
11169
|
for (const family of ["claude", "gemini"]) {
|
|
@@ -10492,6 +11177,23 @@ var AccountManager = class _AccountManager {
|
|
|
10492
11177
|
if (this.currentAccountIndexByFamily[family] >= this.accounts.length) {
|
|
10493
11178
|
this.currentAccountIndexByFamily[family] = -1;
|
|
10494
11179
|
}
|
|
11180
|
+
for (const state of this.requestSessionStates.values()) {
|
|
11181
|
+
const currentIndex = state.currentAccountIndexByFamily[family];
|
|
11182
|
+
if (currentIndex === idx) {
|
|
11183
|
+
state.currentAccountIndexByFamily[family] = -1;
|
|
11184
|
+
} else if (currentIndex > idx) {
|
|
11185
|
+
state.currentAccountIndexByFamily[family] -= 1;
|
|
11186
|
+
}
|
|
11187
|
+
if (state.cursorByFamily[family] > idx) {
|
|
11188
|
+
state.cursorByFamily[family] -= 1;
|
|
11189
|
+
}
|
|
11190
|
+
state.cursorByFamily[family] %= this.accounts.length;
|
|
11191
|
+
}
|
|
11192
|
+
}
|
|
11193
|
+
for (const state of this.requestSessionStates.values()) {
|
|
11194
|
+
state.usedAccounts = new Set(
|
|
11195
|
+
[...state.usedAccounts].filter((accountIndex) => accountIndex !== idx).map((accountIndex) => accountIndex > idx ? accountIndex - 1 : accountIndex)
|
|
11196
|
+
);
|
|
10495
11197
|
}
|
|
10496
11198
|
return true;
|
|
10497
11199
|
}
|
|
@@ -10547,10 +11249,10 @@ var AccountManager = class _AccountManager {
|
|
|
10547
11249
|
getAccounts() {
|
|
10548
11250
|
return [...this.accounts];
|
|
10549
11251
|
}
|
|
10550
|
-
|
|
11252
|
+
buildStorageSnapshot() {
|
|
10551
11253
|
const claudeIndex = Math.max(0, this.currentAccountIndexByFamily.claude);
|
|
10552
11254
|
const geminiIndex = Math.max(0, this.currentAccountIndexByFamily.gemini);
|
|
10553
|
-
|
|
11255
|
+
return {
|
|
10554
11256
|
version: 4,
|
|
10555
11257
|
accounts: this.accounts.map((a) => ({
|
|
10556
11258
|
email: a.email,
|
|
@@ -10569,7 +11271,11 @@ var AccountManager = class _AccountManager {
|
|
|
10569
11271
|
verificationRequired: a.verificationRequired,
|
|
10570
11272
|
verificationRequiredAt: a.verificationRequiredAt,
|
|
10571
11273
|
verificationRequiredReason: a.verificationRequiredReason,
|
|
10572
|
-
verificationUrl: a.verificationUrl
|
|
11274
|
+
verificationUrl: a.verificationUrl,
|
|
11275
|
+
accountIneligible: a.accountIneligible,
|
|
11276
|
+
accountIneligibleAt: a.accountIneligibleAt,
|
|
11277
|
+
accountIneligibleReason: a.accountIneligibleReason,
|
|
11278
|
+
eligibilityStateUpdatedAt: a.eligibilityStateUpdatedAt
|
|
10573
11279
|
})),
|
|
10574
11280
|
activeIndex: claudeIndex,
|
|
10575
11281
|
activeIndexByFamily: {
|
|
@@ -10577,7 +11283,17 @@ var AccountManager = class _AccountManager {
|
|
|
10577
11283
|
gemini: geminiIndex
|
|
10578
11284
|
}
|
|
10579
11285
|
};
|
|
10580
|
-
|
|
11286
|
+
}
|
|
11287
|
+
async saveToDisk() {
|
|
11288
|
+
await saveAccounts(this.buildStorageSnapshot());
|
|
11289
|
+
}
|
|
11290
|
+
/**
|
|
11291
|
+
* Persist via full-file replace (no merge). Required after destructive
|
|
11292
|
+
* operations (account removal) so a deleted account is not resurrected by
|
|
11293
|
+
* mergeAccountStorage re-reading it from disk.
|
|
11294
|
+
*/
|
|
11295
|
+
async saveToDiskReplace() {
|
|
11296
|
+
await saveAccountsReplace(this.buildStorageSnapshot());
|
|
10581
11297
|
}
|
|
10582
11298
|
requestSaveToDisk() {
|
|
10583
11299
|
if (this.savePending) {
|
|
@@ -10592,8 +11308,8 @@ var AccountManager = class _AccountManager {
|
|
|
10592
11308
|
if (!this.savePending) {
|
|
10593
11309
|
return;
|
|
10594
11310
|
}
|
|
10595
|
-
return new Promise((
|
|
10596
|
-
this.savePromiseResolvers.push({ resolve, reject });
|
|
11311
|
+
return new Promise((resolve2, reject) => {
|
|
11312
|
+
this.savePromiseResolvers.push({ resolve: resolve2, reject });
|
|
10597
11313
|
});
|
|
10598
11314
|
}
|
|
10599
11315
|
async executeSave() {
|
|
@@ -10603,14 +11319,14 @@ var AccountManager = class _AccountManager {
|
|
|
10603
11319
|
this.savePromiseResolvers = [];
|
|
10604
11320
|
try {
|
|
10605
11321
|
await this.saveToDisk();
|
|
10606
|
-
for (const { resolve } of resolvers) {
|
|
10607
|
-
|
|
11322
|
+
for (const { resolve: resolve2 } of resolvers) {
|
|
11323
|
+
resolve2();
|
|
10608
11324
|
}
|
|
10609
11325
|
} catch (error) {
|
|
10610
11326
|
if (isStorageLockContention(error)) {
|
|
10611
11327
|
debugLogToFile(`[Account] Skipped account-state persist because another plugin instance holds the storage lock: ${String(error)}`);
|
|
10612
|
-
for (const { resolve } of resolvers) {
|
|
10613
|
-
|
|
11328
|
+
for (const { resolve: resolve2 } of resolvers) {
|
|
11329
|
+
resolve2();
|
|
10614
11330
|
}
|
|
10615
11331
|
return;
|
|
10616
11332
|
}
|
|
@@ -10788,7 +11504,13 @@ var AccountManager = class _AccountManager {
|
|
|
10788
11504
|
};
|
|
10789
11505
|
}
|
|
10790
11506
|
isAccountOverSoftQuota(account, family, thresholdPercent, cacheTtlMs, model) {
|
|
10791
|
-
return isOverSoftQuotaThreshold(
|
|
11507
|
+
return isOverSoftQuotaThreshold(
|
|
11508
|
+
account,
|
|
11509
|
+
family,
|
|
11510
|
+
this.getEffectiveSoftQuotaThreshold(thresholdPercent),
|
|
11511
|
+
cacheTtlMs,
|
|
11512
|
+
model
|
|
11513
|
+
);
|
|
10792
11514
|
}
|
|
10793
11515
|
getAccountsForQuotaCheck() {
|
|
10794
11516
|
return this.accounts.map((a) => ({
|
|
@@ -10814,7 +11536,7 @@ var AccountManager = class _AccountManager {
|
|
|
10814
11536
|
areAllAccountsOverSoftQuota(family, thresholdPercent, cacheTtlMs, model) {
|
|
10815
11537
|
if (thresholdPercent >= 100) return false;
|
|
10816
11538
|
const enabled = this.accounts.filter((a) => a.enabled !== false);
|
|
10817
|
-
if (enabled.length
|
|
11539
|
+
if (enabled.length <= 1) return false;
|
|
10818
11540
|
return enabled.every((a) => isOverSoftQuotaThreshold(a, family, thresholdPercent, cacheTtlMs, model));
|
|
10819
11541
|
}
|
|
10820
11542
|
/**
|
|
@@ -10827,6 +11549,7 @@ var AccountManager = class _AccountManager {
|
|
|
10827
11549
|
if (thresholdPercent >= 100) return 0;
|
|
10828
11550
|
const enabled = this.accounts.filter((a) => a.enabled !== false);
|
|
10829
11551
|
if (enabled.length === 0) return null;
|
|
11552
|
+
if (enabled.length === 1) return 0;
|
|
10830
11553
|
const available = enabled.filter((a) => !isOverSoftQuotaThreshold(a, family, thresholdPercent, cacheTtlMs, model));
|
|
10831
11554
|
if (available.length > 0) return 0;
|
|
10832
11555
|
if (!model && family !== "claude") return null;
|
|
@@ -10849,24 +11572,24 @@ var AccountManager = class _AccountManager {
|
|
|
10849
11572
|
};
|
|
10850
11573
|
|
|
10851
11574
|
// src/hooks/auto-update-checker/checker.ts
|
|
10852
|
-
import * as
|
|
10853
|
-
import * as
|
|
11575
|
+
import * as fs2 from "node:fs";
|
|
11576
|
+
import * as path2 from "node:path";
|
|
10854
11577
|
import { fileURLToPath } from "node:url";
|
|
10855
11578
|
|
|
10856
11579
|
// src/hooks/auto-update-checker/constants.ts
|
|
10857
|
-
import * as
|
|
10858
|
-
import * as
|
|
11580
|
+
import * as path from "node:path";
|
|
11581
|
+
import * as os from "node:os";
|
|
10859
11582
|
var PACKAGE_NAME = "@cortexkit/opencode-antigravity-auth";
|
|
10860
11583
|
var NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME}/dist-tags`;
|
|
10861
11584
|
var NPM_FETCH_TIMEOUT = 5e3;
|
|
10862
11585
|
function getCacheDir() {
|
|
10863
11586
|
if (process.platform === "win32") {
|
|
10864
|
-
return
|
|
11587
|
+
return path.join(process.env.LOCALAPPDATA ?? os.homedir(), "opencode");
|
|
10865
11588
|
}
|
|
10866
|
-
return
|
|
11589
|
+
return path.join(os.homedir(), ".cache", "opencode");
|
|
10867
11590
|
}
|
|
10868
11591
|
var CACHE_DIR = getCacheDir();
|
|
10869
|
-
var INSTALLED_PACKAGE_JSON =
|
|
11592
|
+
var INSTALLED_PACKAGE_JSON = path.join(
|
|
10870
11593
|
CACHE_DIR,
|
|
10871
11594
|
"node_modules",
|
|
10872
11595
|
PACKAGE_NAME,
|
|
@@ -10874,13 +11597,13 @@ var INSTALLED_PACKAGE_JSON = path2.join(
|
|
|
10874
11597
|
);
|
|
10875
11598
|
function getUserConfigDir() {
|
|
10876
11599
|
if (process.platform === "win32") {
|
|
10877
|
-
return process.env.APPDATA ??
|
|
11600
|
+
return process.env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming");
|
|
10878
11601
|
}
|
|
10879
|
-
return process.env.XDG_CONFIG_HOME ??
|
|
11602
|
+
return process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), ".config");
|
|
10880
11603
|
}
|
|
10881
11604
|
var USER_CONFIG_DIR = getUserConfigDir();
|
|
10882
|
-
var USER_OPENCODE_CONFIG =
|
|
10883
|
-
var USER_OPENCODE_CONFIG_JSONC =
|
|
11605
|
+
var USER_OPENCODE_CONFIG = path.join(USER_CONFIG_DIR, "opencode", "opencode.json");
|
|
11606
|
+
var USER_OPENCODE_CONFIG_JSONC = path.join(USER_CONFIG_DIR, "opencode", "opencode.jsonc");
|
|
10884
11607
|
|
|
10885
11608
|
// src/hooks/auto-update-checker/logging.ts
|
|
10886
11609
|
var AUTO_UPDATE_LOG_PREFIX = "[auto-update-checker]";
|
|
@@ -10897,9 +11620,9 @@ function stripJsonComments(json) {
|
|
|
10897
11620
|
}
|
|
10898
11621
|
function getConfigPaths(directory) {
|
|
10899
11622
|
return [
|
|
10900
|
-
|
|
10901
|
-
|
|
10902
|
-
|
|
11623
|
+
path2.join(directory, ".opencode", "opencode.json"),
|
|
11624
|
+
path2.join(directory, ".opencode", "opencode.jsonc"),
|
|
11625
|
+
path2.join(directory, ".opencode.json"),
|
|
10903
11626
|
USER_OPENCODE_CONFIG,
|
|
10904
11627
|
USER_OPENCODE_CONFIG_JSONC
|
|
10905
11628
|
];
|
|
@@ -10907,8 +11630,8 @@ function getConfigPaths(directory) {
|
|
|
10907
11630
|
function getLocalDevPath(directory) {
|
|
10908
11631
|
for (const configPath of getConfigPaths(directory)) {
|
|
10909
11632
|
try {
|
|
10910
|
-
if (!
|
|
10911
|
-
const content =
|
|
11633
|
+
if (!fs2.existsSync(configPath)) continue;
|
|
11634
|
+
const content = fs2.readFileSync(configPath, "utf-8");
|
|
10912
11635
|
const config = JSON.parse(stripJsonComments(content));
|
|
10913
11636
|
const plugins = config.plugin ?? [];
|
|
10914
11637
|
for (const entry of plugins) {
|
|
@@ -10928,20 +11651,20 @@ function getLocalDevPath(directory) {
|
|
|
10928
11651
|
}
|
|
10929
11652
|
function findPackageJsonUp(startPath) {
|
|
10930
11653
|
try {
|
|
10931
|
-
const stat =
|
|
10932
|
-
let dir = stat.isDirectory() ? startPath :
|
|
11654
|
+
const stat = fs2.statSync(startPath);
|
|
11655
|
+
let dir = stat.isDirectory() ? startPath : path2.dirname(startPath);
|
|
10933
11656
|
for (let i = 0; i < 10; i++) {
|
|
10934
|
-
const pkgPath =
|
|
10935
|
-
if (
|
|
11657
|
+
const pkgPath = path2.join(dir, "package.json");
|
|
11658
|
+
if (fs2.existsSync(pkgPath)) {
|
|
10936
11659
|
try {
|
|
10937
|
-
const content =
|
|
11660
|
+
const content = fs2.readFileSync(pkgPath, "utf-8");
|
|
10938
11661
|
const pkg = JSON.parse(content);
|
|
10939
11662
|
if (pkg.name === PACKAGE_NAME) return pkgPath;
|
|
10940
11663
|
} catch {
|
|
10941
11664
|
continue;
|
|
10942
11665
|
}
|
|
10943
11666
|
}
|
|
10944
|
-
const parent =
|
|
11667
|
+
const parent = path2.dirname(dir);
|
|
10945
11668
|
if (parent === dir) break;
|
|
10946
11669
|
dir = parent;
|
|
10947
11670
|
}
|
|
@@ -10956,7 +11679,7 @@ function getLocalDevVersion(directory) {
|
|
|
10956
11679
|
try {
|
|
10957
11680
|
const pkgPath = findPackageJsonUp(localPath);
|
|
10958
11681
|
if (!pkgPath) return null;
|
|
10959
|
-
const content =
|
|
11682
|
+
const content = fs2.readFileSync(pkgPath, "utf-8");
|
|
10960
11683
|
const pkg = JSON.parse(content);
|
|
10961
11684
|
return pkg.version ?? null;
|
|
10962
11685
|
} catch {
|
|
@@ -10966,8 +11689,8 @@ function getLocalDevVersion(directory) {
|
|
|
10966
11689
|
function findPluginEntry(directory) {
|
|
10967
11690
|
for (const configPath of getConfigPaths(directory)) {
|
|
10968
11691
|
try {
|
|
10969
|
-
if (!
|
|
10970
|
-
const content =
|
|
11692
|
+
if (!fs2.existsSync(configPath)) continue;
|
|
11693
|
+
const content = fs2.readFileSync(configPath, "utf-8");
|
|
10971
11694
|
const config = JSON.parse(stripJsonComments(content));
|
|
10972
11695
|
const plugins = config.plugin ?? [];
|
|
10973
11696
|
for (const entry of plugins) {
|
|
@@ -10991,8 +11714,8 @@ function findPluginEntry(directory) {
|
|
|
10991
11714
|
}
|
|
10992
11715
|
function getCachedVersion() {
|
|
10993
11716
|
try {
|
|
10994
|
-
if (
|
|
10995
|
-
const content =
|
|
11717
|
+
if (fs2.existsSync(INSTALLED_PACKAGE_JSON)) {
|
|
11718
|
+
const content = fs2.readFileSync(INSTALLED_PACKAGE_JSON, "utf-8");
|
|
10996
11719
|
const pkg = JSON.parse(content);
|
|
10997
11720
|
if (pkg.version) return pkg.version;
|
|
10998
11721
|
}
|
|
@@ -11000,10 +11723,10 @@ function getCachedVersion() {
|
|
|
11000
11723
|
return null;
|
|
11001
11724
|
}
|
|
11002
11725
|
try {
|
|
11003
|
-
const currentDir =
|
|
11726
|
+
const currentDir = path2.dirname(fileURLToPath(import.meta.url));
|
|
11004
11727
|
const pkgPath = findPackageJsonUp(currentDir);
|
|
11005
11728
|
if (pkgPath) {
|
|
11006
|
-
const content =
|
|
11729
|
+
const content = fs2.readFileSync(pkgPath, "utf-8");
|
|
11007
11730
|
const pkg = JSON.parse(content);
|
|
11008
11731
|
if (pkg.version) return pkg.version;
|
|
11009
11732
|
}
|
|
@@ -11014,7 +11737,7 @@ function getCachedVersion() {
|
|
|
11014
11737
|
}
|
|
11015
11738
|
function updatePinnedVersion(configPath, oldEntry, newVersion) {
|
|
11016
11739
|
try {
|
|
11017
|
-
const content =
|
|
11740
|
+
const content = fs2.readFileSync(configPath, "utf-8");
|
|
11018
11741
|
const newEntry = `${PACKAGE_NAME}@${newVersion}`;
|
|
11019
11742
|
const pluginMatch = content.match(/"plugin"\s*:\s*\[/);
|
|
11020
11743
|
if (!pluginMatch || pluginMatch.index === void 0) {
|
|
@@ -11044,7 +11767,7 @@ function updatePinnedVersion(configPath, oldEntry, newVersion) {
|
|
|
11044
11767
|
logAutoUpdate(`No changes made to ${configPath}`);
|
|
11045
11768
|
return false;
|
|
11046
11769
|
}
|
|
11047
|
-
|
|
11770
|
+
fs2.writeFileSync(configPath, updatedContent, "utf-8");
|
|
11048
11771
|
logAutoUpdate(`Updated ${configPath}: ${oldEntry} \u2192 ${newEntry}`);
|
|
11049
11772
|
return true;
|
|
11050
11773
|
} catch (err) {
|
|
@@ -11071,16 +11794,16 @@ async function getLatestVersion() {
|
|
|
11071
11794
|
}
|
|
11072
11795
|
|
|
11073
11796
|
// src/hooks/auto-update-checker/cache.ts
|
|
11074
|
-
import * as
|
|
11075
|
-
import * as
|
|
11797
|
+
import * as fs3 from "node:fs";
|
|
11798
|
+
import * as path3 from "node:path";
|
|
11076
11799
|
function stripTrailingCommas(json) {
|
|
11077
11800
|
return json.replace(/,(\s*[}\]])/g, "$1");
|
|
11078
11801
|
}
|
|
11079
11802
|
function removeFromBunLock(packageName) {
|
|
11080
|
-
const lockPath =
|
|
11081
|
-
if (!
|
|
11803
|
+
const lockPath = path3.join(CACHE_DIR, "bun.lock");
|
|
11804
|
+
if (!fs3.existsSync(lockPath)) return false;
|
|
11082
11805
|
try {
|
|
11083
|
-
const content =
|
|
11806
|
+
const content = fs3.readFileSync(lockPath, "utf-8");
|
|
11084
11807
|
const lock = JSON.parse(stripTrailingCommas(content));
|
|
11085
11808
|
let modified = false;
|
|
11086
11809
|
if (lock.workspaces?.[""]?.dependencies?.[packageName]) {
|
|
@@ -11092,7 +11815,7 @@ function removeFromBunLock(packageName) {
|
|
|
11092
11815
|
modified = true;
|
|
11093
11816
|
}
|
|
11094
11817
|
if (modified) {
|
|
11095
|
-
|
|
11818
|
+
fs3.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
|
|
11096
11819
|
console.log(`[auto-update-checker] Removed from bun.lock: ${packageName}`);
|
|
11097
11820
|
}
|
|
11098
11821
|
return modified;
|
|
@@ -11102,22 +11825,22 @@ function removeFromBunLock(packageName) {
|
|
|
11102
11825
|
}
|
|
11103
11826
|
function invalidatePackage(packageName = PACKAGE_NAME) {
|
|
11104
11827
|
try {
|
|
11105
|
-
const pkgDir =
|
|
11106
|
-
const pkgJsonPath =
|
|
11828
|
+
const pkgDir = path3.join(CACHE_DIR, "node_modules", packageName);
|
|
11829
|
+
const pkgJsonPath = path3.join(CACHE_DIR, "package.json");
|
|
11107
11830
|
let packageRemoved = false;
|
|
11108
11831
|
let dependencyRemoved = false;
|
|
11109
11832
|
let lockRemoved = false;
|
|
11110
|
-
if (
|
|
11111
|
-
|
|
11833
|
+
if (fs3.existsSync(pkgDir)) {
|
|
11834
|
+
fs3.rmSync(pkgDir, { recursive: true, force: true });
|
|
11112
11835
|
console.log(`[auto-update-checker] Package removed: ${pkgDir}`);
|
|
11113
11836
|
packageRemoved = true;
|
|
11114
11837
|
}
|
|
11115
|
-
if (
|
|
11116
|
-
const content =
|
|
11838
|
+
if (fs3.existsSync(pkgJsonPath)) {
|
|
11839
|
+
const content = fs3.readFileSync(pkgJsonPath, "utf-8");
|
|
11117
11840
|
const pkgJson = JSON.parse(content);
|
|
11118
11841
|
if (pkgJson.dependencies?.[packageName]) {
|
|
11119
11842
|
delete pkgJson.dependencies[packageName];
|
|
11120
|
-
|
|
11843
|
+
fs3.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
|
|
11121
11844
|
console.log(`[auto-update-checker] Dependency removed from package.json: ${packageName}`);
|
|
11122
11845
|
dependencyRemoved = true;
|
|
11123
11846
|
}
|
|
@@ -11419,6 +12142,15 @@ function createAuthDoctorReport(input2) {
|
|
|
11419
12142
|
}
|
|
11420
12143
|
}
|
|
11421
12144
|
for (const account of storage.accounts) {
|
|
12145
|
+
if (account.accountIneligible) {
|
|
12146
|
+
findings.push({
|
|
12147
|
+
code: "account-ineligible",
|
|
12148
|
+
severity: "warning",
|
|
12149
|
+
message: account.accountIneligibleReason ?? "Google marked this account as ineligible for Antigravity.",
|
|
12150
|
+
repair: "verify-account",
|
|
12151
|
+
accountEmail: account.email
|
|
12152
|
+
});
|
|
12153
|
+
}
|
|
11422
12154
|
if (account.verificationRequired) {
|
|
11423
12155
|
findings.push({
|
|
11424
12156
|
code: "verification-required",
|
|
@@ -12199,6 +12931,69 @@ async function resolvePromptContext(client, sessionId) {
|
|
|
12199
12931
|
return result;
|
|
12200
12932
|
}
|
|
12201
12933
|
|
|
12934
|
+
// src/plugin/session-context.ts
|
|
12935
|
+
import { resolve } from "node:path";
|
|
12936
|
+
import { pathToFileURL } from "node:url";
|
|
12937
|
+
var FALLBACK_SESSION_KEY = "__default__";
|
|
12938
|
+
function extractOpenCodeSessionIdentity(headers) {
|
|
12939
|
+
const normalized = new Headers(headers);
|
|
12940
|
+
return {
|
|
12941
|
+
sessionId: normalized.get("x-session-affinity") ?? normalized.get("x-session-id"),
|
|
12942
|
+
parentSessionId: normalized.get("x-parent-session-id")
|
|
12943
|
+
};
|
|
12944
|
+
}
|
|
12945
|
+
var AgySessionRegistry = class {
|
|
12946
|
+
requestSessions;
|
|
12947
|
+
parentSessionIds = /* @__PURE__ */ new Map();
|
|
12948
|
+
constructor(directory, options = {}) {
|
|
12949
|
+
const workspaceUri = directory ? pathToFileURL(resolve(directory)).href : "";
|
|
12950
|
+
this.requestSessions = new AgyRequestSessionStore(workspaceUri, options);
|
|
12951
|
+
}
|
|
12952
|
+
getOrCreate(identity) {
|
|
12953
|
+
const key = identity.sessionId ?? FALLBACK_SESSION_KEY;
|
|
12954
|
+
const request = this.requestSessions.getOrCreate(key);
|
|
12955
|
+
this.recordParent(key, identity.parentSessionId);
|
|
12956
|
+
this.pruneParentRelationships();
|
|
12957
|
+
return request;
|
|
12958
|
+
}
|
|
12959
|
+
beginRequest(identity) {
|
|
12960
|
+
const key = identity.sessionId ?? FALLBACK_SESSION_KEY;
|
|
12961
|
+
const scope = this.requestSessions.beginRequest(key);
|
|
12962
|
+
this.recordParent(key, identity.parentSessionId);
|
|
12963
|
+
this.pruneParentRelationships();
|
|
12964
|
+
return scope;
|
|
12965
|
+
}
|
|
12966
|
+
register(sessionId, parentSessionId = null) {
|
|
12967
|
+
this.getOrCreate({ sessionId, parentSessionId });
|
|
12968
|
+
}
|
|
12969
|
+
getParentSessionId(sessionId) {
|
|
12970
|
+
if (!this.requestSessions.has(sessionId)) {
|
|
12971
|
+
this.parentSessionIds.delete(sessionId);
|
|
12972
|
+
return null;
|
|
12973
|
+
}
|
|
12974
|
+
return this.parentSessionIds.get(sessionId) ?? null;
|
|
12975
|
+
}
|
|
12976
|
+
delete(sessionId) {
|
|
12977
|
+
this.requestSessions.delete(sessionId);
|
|
12978
|
+
this.parentSessionIds.delete(sessionId);
|
|
12979
|
+
}
|
|
12980
|
+
get size() {
|
|
12981
|
+
return this.requestSessions.size;
|
|
12982
|
+
}
|
|
12983
|
+
recordParent(key, parentSessionId) {
|
|
12984
|
+
if (parentSessionId || !this.parentSessionIds.has(key)) {
|
|
12985
|
+
this.parentSessionIds.set(key, parentSessionId);
|
|
12986
|
+
}
|
|
12987
|
+
}
|
|
12988
|
+
pruneParentRelationships() {
|
|
12989
|
+
for (const sessionId of this.parentSessionIds.keys()) {
|
|
12990
|
+
if (!this.requestSessions.has(sessionId)) {
|
|
12991
|
+
this.parentSessionIds.delete(sessionId);
|
|
12992
|
+
}
|
|
12993
|
+
}
|
|
12994
|
+
}
|
|
12995
|
+
};
|
|
12996
|
+
|
|
12202
12997
|
// src/plugin.ts
|
|
12203
12998
|
var MAX_OAUTH_ACCOUNTS = 10;
|
|
12204
12999
|
var MAX_WARMUP_SESSIONS = 1e3;
|
|
@@ -12209,8 +13004,6 @@ function isCapacityRetryBudgetExhausted(totalCapacityRetries) {
|
|
|
12209
13004
|
}
|
|
12210
13005
|
var warmupAttemptedSessionIds = /* @__PURE__ */ new Set();
|
|
12211
13006
|
var warmupSucceededSessionIds = /* @__PURE__ */ new Set();
|
|
12212
|
-
var isChildSession = false;
|
|
12213
|
-
var childSessionParentID = void 0;
|
|
12214
13007
|
var log10 = createLogger2("plugin");
|
|
12215
13008
|
var rateLimitToastCooldowns = /* @__PURE__ */ new Map();
|
|
12216
13009
|
var RATE_LIMIT_TOAST_COOLDOWN_MS = 5e3;
|
|
@@ -12401,10 +13194,12 @@ function selectBestVerificationUrl(urls) {
|
|
|
12401
13194
|
});
|
|
12402
13195
|
return unique[0];
|
|
12403
13196
|
}
|
|
12404
|
-
function
|
|
13197
|
+
function extractAccountAccessErrorDetails(bodyText) {
|
|
12405
13198
|
const decodedBody = decodeEscapedText(bodyText);
|
|
12406
13199
|
const lowerBody = decodedBody.toLowerCase();
|
|
12407
13200
|
let validationRequired = lowerBody.includes("validation_required");
|
|
13201
|
+
const ineligiblePattern = /(^|[^a-z0-9_])account_ineligible([^a-z0-9_]|$)/i;
|
|
13202
|
+
let accountIneligible = ineligiblePattern.test(decodedBody);
|
|
12408
13203
|
let message;
|
|
12409
13204
|
const verificationUrls = /* @__PURE__ */ new Set();
|
|
12410
13205
|
const collectUrlsFromText = (text) => {
|
|
@@ -12447,6 +13242,9 @@ function extractVerificationErrorDetails(bodyText) {
|
|
|
12447
13242
|
if (lowerValue.includes("validation_required")) {
|
|
12448
13243
|
validationRequired = true;
|
|
12449
13244
|
}
|
|
13245
|
+
if (ineligiblePattern.test(normalizedValue)) {
|
|
13246
|
+
accountIneligible = true;
|
|
13247
|
+
}
|
|
12450
13248
|
if (!message && (lowerKey.includes("message") || lowerKey.includes("detail") || lowerKey.includes("description"))) {
|
|
12451
13249
|
message = normalizedValue;
|
|
12452
13250
|
}
|
|
@@ -12477,17 +13275,72 @@ function extractVerificationErrorDetails(bodyText) {
|
|
|
12477
13275
|
validationRequired = lowerBody.includes("verification required") || lowerBody.includes("verify your account") || lowerBody.includes("account verification");
|
|
12478
13276
|
}
|
|
12479
13277
|
if (!message) {
|
|
12480
|
-
const fallback = decodedBody.split("\n").map((line) => line.trim()).find((line) => line && !line.startsWith("data:") && /(verify|validation|required)/i.test(line));
|
|
13278
|
+
const fallback = decodedBody.split("\n").map((line) => line.trim()).find((line) => line && !line.startsWith("data:") && /(verify|validation|required|ineligible)/i.test(line));
|
|
12481
13279
|
if (fallback) {
|
|
12482
13280
|
message = fallback;
|
|
12483
13281
|
}
|
|
12484
13282
|
}
|
|
12485
13283
|
return {
|
|
12486
13284
|
validationRequired,
|
|
13285
|
+
accountIneligible,
|
|
12487
13286
|
message,
|
|
12488
13287
|
verifyUrl: selectBestVerificationUrl([...verificationUrls])
|
|
12489
13288
|
};
|
|
12490
13289
|
}
|
|
13290
|
+
function buildAccountAccessProbeRequest(projectId) {
|
|
13291
|
+
const wireModel = "gemini-3.5-flash-low";
|
|
13292
|
+
const request = {
|
|
13293
|
+
contents: [{ role: "user", parts: [{ text: "ping" }] }],
|
|
13294
|
+
generationConfig: { maxOutputTokens: 1, temperature: 0 }
|
|
13295
|
+
};
|
|
13296
|
+
const requestMetadata = buildAgyAgentRequestMetadata(
|
|
13297
|
+
createAgyRequestSessionContext(""),
|
|
13298
|
+
request,
|
|
13299
|
+
wireModel
|
|
13300
|
+
);
|
|
13301
|
+
request.labels = requestMetadata.labels;
|
|
13302
|
+
request.sessionId = requestMetadata.sessionId;
|
|
13303
|
+
orderAgyRequestPayloadInPlace(request);
|
|
13304
|
+
return {
|
|
13305
|
+
project: projectId,
|
|
13306
|
+
requestId: requestMetadata.requestId,
|
|
13307
|
+
request,
|
|
13308
|
+
model: wireModel,
|
|
13309
|
+
userAgent: "antigravity",
|
|
13310
|
+
requestType: "agent"
|
|
13311
|
+
};
|
|
13312
|
+
}
|
|
13313
|
+
async function interpretAccountAccessProbeResponse(response) {
|
|
13314
|
+
if (response.ok) {
|
|
13315
|
+
await response.body?.cancel().catch(() => {
|
|
13316
|
+
});
|
|
13317
|
+
return { status: "ok", message: "Account verification check passed." };
|
|
13318
|
+
}
|
|
13319
|
+
let responseBody = "";
|
|
13320
|
+
try {
|
|
13321
|
+
responseBody = await response.text();
|
|
13322
|
+
} catch {
|
|
13323
|
+
responseBody = "";
|
|
13324
|
+
}
|
|
13325
|
+
const extracted = extractAccountAccessErrorDetails(responseBody);
|
|
13326
|
+
if (response.status === 403 && extracted.accountIneligible) {
|
|
13327
|
+
return {
|
|
13328
|
+
status: "ineligible",
|
|
13329
|
+
message: extracted.message ?? "Google marked this account as ineligible for Antigravity."
|
|
13330
|
+
};
|
|
13331
|
+
}
|
|
13332
|
+
if (response.status === 403 && extracted.validationRequired) {
|
|
13333
|
+
return {
|
|
13334
|
+
status: "verification-required",
|
|
13335
|
+
message: extracted.message ?? "Google requires additional account verification.",
|
|
13336
|
+
verifyUrl: extracted.verifyUrl
|
|
13337
|
+
};
|
|
13338
|
+
}
|
|
13339
|
+
return {
|
|
13340
|
+
status: "error",
|
|
13341
|
+
message: extracted.message ?? `Request failed (${response.status} ${response.statusText}).`
|
|
13342
|
+
};
|
|
13343
|
+
}
|
|
12491
13344
|
async function verifyAccountAccess(account, client, providerId) {
|
|
12492
13345
|
const parsed = parseRefreshParts(account.refreshToken);
|
|
12493
13346
|
if (!parsed.refreshToken) {
|
|
@@ -12523,18 +13376,7 @@ async function verifyAccountAccess(account, client, providerId) {
|
|
|
12523
13376
|
"Content-Type": "application/json",
|
|
12524
13377
|
"Accept-Encoding": "gzip"
|
|
12525
13378
|
};
|
|
12526
|
-
const requestBody =
|
|
12527
|
-
project: projectId,
|
|
12528
|
-
requestId: `agent/${crypto4.randomUUID()}/${Date.now()}/${crypto4.randomUUID()}/2`,
|
|
12529
|
-
request: {
|
|
12530
|
-
model: "gemini-3-flash",
|
|
12531
|
-
contents: [{ role: "user", parts: [{ text: "ping" }] }],
|
|
12532
|
-
generationConfig: { maxOutputTokens: 1, temperature: 0 }
|
|
12533
|
-
},
|
|
12534
|
-
model: "gemini-3-flash",
|
|
12535
|
-
userAgent: "antigravity",
|
|
12536
|
-
requestType: "agent"
|
|
12537
|
-
};
|
|
13379
|
+
const requestBody = buildAccountAccessProbeRequest(projectId);
|
|
12538
13380
|
const controller = new AbortController();
|
|
12539
13381
|
const timeoutId = setTimeout(() => controller.abort(), 2e4);
|
|
12540
13382
|
let response;
|
|
@@ -12552,28 +13394,7 @@ async function verifyAccountAccess(account, client, providerId) {
|
|
|
12552
13394
|
} finally {
|
|
12553
13395
|
clearTimeout(timeoutId);
|
|
12554
13396
|
}
|
|
12555
|
-
|
|
12556
|
-
try {
|
|
12557
|
-
responseBody = await response.text();
|
|
12558
|
-
} catch {
|
|
12559
|
-
responseBody = "";
|
|
12560
|
-
}
|
|
12561
|
-
if (response.ok) {
|
|
12562
|
-
return { status: "ok", message: "Account verification check passed." };
|
|
12563
|
-
}
|
|
12564
|
-
const extracted = extractVerificationErrorDetails(responseBody);
|
|
12565
|
-
if (response.status === 403 && extracted.validationRequired) {
|
|
12566
|
-
return {
|
|
12567
|
-
status: "blocked",
|
|
12568
|
-
message: extracted.message ?? "Google requires additional account verification.",
|
|
12569
|
-
verifyUrl: extracted.verifyUrl
|
|
12570
|
-
};
|
|
12571
|
-
}
|
|
12572
|
-
const fallbackMessage = extracted.message ?? `Request failed (${response.status} ${response.statusText}).`;
|
|
12573
|
-
return {
|
|
12574
|
-
status: "error",
|
|
12575
|
-
message: fallbackMessage
|
|
12576
|
-
};
|
|
13397
|
+
return interpretAccountAccessProbeResponse(response);
|
|
12577
13398
|
}
|
|
12578
13399
|
async function promptAccountIndexForVerification(accounts) {
|
|
12579
13400
|
const { createInterface: createInterface2 } = await import("node:readline/promises");
|
|
@@ -12615,12 +13436,20 @@ async function promptOpenVerificationUrl() {
|
|
|
12615
13436
|
function markStoredAccountVerificationRequired(account, reason, verifyUrl) {
|
|
12616
13437
|
let changed = false;
|
|
12617
13438
|
const wasVerificationRequired = account.verificationRequired === true;
|
|
13439
|
+
const timestamp = Date.now();
|
|
12618
13440
|
if (!wasVerificationRequired) {
|
|
12619
13441
|
account.verificationRequired = true;
|
|
12620
13442
|
changed = true;
|
|
12621
13443
|
}
|
|
12622
13444
|
if (!wasVerificationRequired || account.verificationRequiredAt === void 0) {
|
|
12623
|
-
account.verificationRequiredAt =
|
|
13445
|
+
account.verificationRequiredAt = timestamp;
|
|
13446
|
+
changed = true;
|
|
13447
|
+
}
|
|
13448
|
+
if (account.accountIneligible === true || account.accountIneligibleAt !== void 0 || account.accountIneligibleReason !== void 0) {
|
|
13449
|
+
account.accountIneligible = false;
|
|
13450
|
+
account.accountIneligibleAt = void 0;
|
|
13451
|
+
account.accountIneligibleReason = void 0;
|
|
13452
|
+
account.eligibilityStateUpdatedAt = timestamp;
|
|
12624
13453
|
changed = true;
|
|
12625
13454
|
}
|
|
12626
13455
|
const normalizedReason = reason.trim();
|
|
@@ -12639,8 +13468,25 @@ function markStoredAccountVerificationRequired(account, reason, verifyUrl) {
|
|
|
12639
13468
|
}
|
|
12640
13469
|
return changed;
|
|
12641
13470
|
}
|
|
12642
|
-
function
|
|
13471
|
+
function markStoredAccountIneligible(account, reason) {
|
|
13472
|
+
const timestamp = Date.now();
|
|
13473
|
+
const normalizedReason = reason.trim() || "Google marked this account as ineligible.";
|
|
13474
|
+
const changed = account.accountIneligible !== true || account.accountIneligibleReason !== normalizedReason || account.verificationRequired === true || account.verificationRequiredAt !== void 0 || account.verificationRequiredReason !== void 0 || account.verificationUrl !== void 0 || account.enabled !== false;
|
|
13475
|
+
account.accountIneligible = true;
|
|
13476
|
+
account.accountIneligibleAt = timestamp;
|
|
13477
|
+
account.accountIneligibleReason = normalizedReason;
|
|
13478
|
+
account.eligibilityStateUpdatedAt = timestamp;
|
|
13479
|
+
account.verificationRequired = false;
|
|
13480
|
+
account.verificationRequiredAt = void 0;
|
|
13481
|
+
account.verificationRequiredReason = void 0;
|
|
13482
|
+
account.verificationUrl = void 0;
|
|
13483
|
+
account.enabled = false;
|
|
13484
|
+
return changed;
|
|
13485
|
+
}
|
|
13486
|
+
function clearStoredAccountAccessBlocks(account, enableIfBlocked = false) {
|
|
12643
13487
|
const wasVerificationRequired = account.verificationRequired === true;
|
|
13488
|
+
const wasIneligible = account.accountIneligible === true;
|
|
13489
|
+
const wasAccessBlocked = wasVerificationRequired || wasIneligible;
|
|
12644
13490
|
let changed = false;
|
|
12645
13491
|
if (account.verificationRequired !== false) {
|
|
12646
13492
|
account.verificationRequired = false;
|
|
@@ -12658,11 +13504,27 @@ function clearStoredAccountVerificationRequired(account, enableIfRequired = fals
|
|
|
12658
13504
|
account.verificationUrl = void 0;
|
|
12659
13505
|
changed = true;
|
|
12660
13506
|
}
|
|
12661
|
-
if (
|
|
13507
|
+
if (account.accountIneligible !== false) {
|
|
13508
|
+
account.accountIneligible = false;
|
|
13509
|
+
changed = true;
|
|
13510
|
+
}
|
|
13511
|
+
if (account.accountIneligibleAt !== void 0) {
|
|
13512
|
+
account.accountIneligibleAt = void 0;
|
|
13513
|
+
changed = true;
|
|
13514
|
+
}
|
|
13515
|
+
if (account.accountIneligibleReason !== void 0) {
|
|
13516
|
+
account.accountIneligibleReason = void 0;
|
|
13517
|
+
changed = true;
|
|
13518
|
+
}
|
|
13519
|
+
if (wasIneligible || account.eligibilityStateUpdatedAt !== void 0) {
|
|
13520
|
+
account.eligibilityStateUpdatedAt = Date.now();
|
|
13521
|
+
changed = true;
|
|
13522
|
+
}
|
|
13523
|
+
if (enableIfBlocked && wasAccessBlocked && account.enabled === false) {
|
|
12662
13524
|
account.enabled = true;
|
|
12663
13525
|
changed = true;
|
|
12664
13526
|
}
|
|
12665
|
-
return { changed,
|
|
13527
|
+
return { changed, wasAccessBlocked };
|
|
12666
13528
|
}
|
|
12667
13529
|
async function promptOAuthCallbackValue(message) {
|
|
12668
13530
|
const { createInterface: createInterface2 } = await import("node:readline/promises");
|
|
@@ -13054,14 +13916,14 @@ function throwHandledCommandSentinel() {
|
|
|
13054
13916
|
throw new Error(HANDLED_COMMAND_SENTINEL);
|
|
13055
13917
|
}
|
|
13056
13918
|
function sleep(ms, signal) {
|
|
13057
|
-
return new Promise((
|
|
13919
|
+
return new Promise((resolve2, reject) => {
|
|
13058
13920
|
if (signal?.aborted) {
|
|
13059
13921
|
reject(signal.reason instanceof Error ? signal.reason : new Error("Aborted"));
|
|
13060
13922
|
return;
|
|
13061
13923
|
}
|
|
13062
13924
|
const timeout = setTimeout(() => {
|
|
13063
13925
|
cleanup();
|
|
13064
|
-
|
|
13926
|
+
resolve2();
|
|
13065
13927
|
}, ms);
|
|
13066
13928
|
const onAbort = () => {
|
|
13067
13929
|
cleanup();
|
|
@@ -13077,6 +13939,7 @@ function sleep(ms, signal) {
|
|
|
13077
13939
|
var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
|
|
13078
13940
|
const config = loadConfig(directory);
|
|
13079
13941
|
initRuntimeConfig(config);
|
|
13942
|
+
const agySessionRegistry = new AgySessionRegistry(directory);
|
|
13080
13943
|
let cachedGetAuth = null;
|
|
13081
13944
|
initializeDebug(config);
|
|
13082
13945
|
initLogger(client);
|
|
@@ -13110,25 +13973,34 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
|
|
|
13110
13973
|
const eventHandler = async (input2) => {
|
|
13111
13974
|
await updateChecker.event(input2);
|
|
13112
13975
|
if (input2.event.type === "session.created") {
|
|
13113
|
-
const prevSummary = activeAccountManager?.getSessionSummary();
|
|
13114
|
-
if (prevSummary && (prevSummary.totalClaude > 0 || prevSummary.totalGemini > 0)) {
|
|
13115
|
-
log10.debug("prev-session-quota-summary", {
|
|
13116
|
-
durationMinutes: prevSummary.durationMinutes,
|
|
13117
|
-
totalClaude: prevSummary.totalClaude,
|
|
13118
|
-
totalGemini: prevSummary.totalGemini,
|
|
13119
|
-
requestsPerHour: prevSummary.requestsPerHour,
|
|
13120
|
-
accountsUsed: prevSummary.accountsUsed
|
|
13121
|
-
});
|
|
13122
|
-
}
|
|
13123
13976
|
const props = input2.event.properties;
|
|
13124
|
-
|
|
13125
|
-
|
|
13126
|
-
|
|
13127
|
-
|
|
13977
|
+
const sessionId = props?.info?.id;
|
|
13978
|
+
const parentSessionId = props?.info?.parentID ?? null;
|
|
13979
|
+
if (sessionId) {
|
|
13980
|
+
agySessionRegistry.register(sessionId, parentSessionId);
|
|
13981
|
+
}
|
|
13982
|
+
if (parentSessionId) {
|
|
13983
|
+
log10.debug("child-session-detected", { sessionId, parentID: parentSessionId });
|
|
13128
13984
|
} else {
|
|
13129
|
-
|
|
13130
|
-
|
|
13131
|
-
|
|
13985
|
+
const prevSummary = activeAccountManager?.getSessionSummary();
|
|
13986
|
+
if (prevSummary && (prevSummary.totalClaude > 0 || prevSummary.totalGemini > 0)) {
|
|
13987
|
+
log10.debug("prev-session-quota-summary", {
|
|
13988
|
+
durationMinutes: prevSummary.durationMinutes,
|
|
13989
|
+
totalClaude: prevSummary.totalClaude,
|
|
13990
|
+
totalGemini: prevSummary.totalGemini,
|
|
13991
|
+
requestsPerHour: prevSummary.requestsPerHour,
|
|
13992
|
+
accountsUsed: prevSummary.accountsUsed
|
|
13993
|
+
});
|
|
13994
|
+
}
|
|
13995
|
+
log10.debug("root-session-detected", { sessionId });
|
|
13996
|
+
}
|
|
13997
|
+
}
|
|
13998
|
+
if (input2.event.type === "session.deleted") {
|
|
13999
|
+
const props = input2.event.properties;
|
|
14000
|
+
const sessionId = props?.sessionID ?? props?.info?.id;
|
|
14001
|
+
if (sessionId) {
|
|
14002
|
+
agySessionRegistry.delete(sessionId);
|
|
14003
|
+
activeAccountManager?.deleteSessionState(sessionId);
|
|
13132
14004
|
}
|
|
13133
14005
|
}
|
|
13134
14006
|
if (sessionRecovery && input2.event.type === "session.error") {
|
|
@@ -13152,8 +14024,13 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
|
|
|
13152
14024
|
}).catch(() => {
|
|
13153
14025
|
});
|
|
13154
14026
|
const successToast = getRecoverySuccessToast();
|
|
13155
|
-
|
|
13156
|
-
|
|
14027
|
+
const isChildRecovery = agySessionRegistry.getParentSessionId(sessionID) !== null;
|
|
14028
|
+
log10.debug("recovery-toast", {
|
|
14029
|
+
...successToast,
|
|
14030
|
+
isChildSession: isChildRecovery,
|
|
14031
|
+
toastScope: config.toast_scope
|
|
14032
|
+
});
|
|
14033
|
+
if (!(config.toast_scope === "root_only" && isChildRecovery)) {
|
|
13157
14034
|
await client.tui.showToast({
|
|
13158
14035
|
body: {
|
|
13159
14036
|
title: successToast.title,
|
|
@@ -13318,6 +14195,39 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
|
|
|
13318
14195
|
if (!isOAuthAuth(latestAuth)) {
|
|
13319
14196
|
return fetch(input2, init);
|
|
13320
14197
|
}
|
|
14198
|
+
if (typeof input2 !== "string") {
|
|
14199
|
+
if (input2 instanceof Request) {
|
|
14200
|
+
const req = input2;
|
|
14201
|
+
const headers = new Headers(req.headers);
|
|
14202
|
+
if (init?.headers) {
|
|
14203
|
+
new Headers(init.headers).forEach((v, k) => headers.set(k, v));
|
|
14204
|
+
}
|
|
14205
|
+
const bodyBuffer = req.body ? await req.clone().arrayBuffer() : void 0;
|
|
14206
|
+
init = {
|
|
14207
|
+
method: init?.method ?? req.method,
|
|
14208
|
+
headers,
|
|
14209
|
+
body: init?.body ?? (bodyBuffer ? Buffer.from(bodyBuffer) : void 0),
|
|
14210
|
+
signal: init?.signal ?? req.signal
|
|
14211
|
+
};
|
|
14212
|
+
input2 = req.url;
|
|
14213
|
+
} else {
|
|
14214
|
+
input2 = String(input2.href ?? input2);
|
|
14215
|
+
}
|
|
14216
|
+
}
|
|
14217
|
+
const localImageTitle = getImageModelLocalTitle(input2, init);
|
|
14218
|
+
if (localImageTitle !== void 0) {
|
|
14219
|
+
return createSyntheticTextResponse(localImageTitle, {
|
|
14220
|
+
"X-Antigravity-Response-Type": "local_title"
|
|
14221
|
+
});
|
|
14222
|
+
}
|
|
14223
|
+
const requestSessionIdentity = extractOpenCodeSessionIdentity(init?.headers);
|
|
14224
|
+
const agyRequestScope = agySessionRegistry.beginRequest(requestSessionIdentity);
|
|
14225
|
+
const agyRequestSession = agyRequestScope.session;
|
|
14226
|
+
const accountSessionIdentity = requestSessionIdentity.sessionId ? {
|
|
14227
|
+
id: requestSessionIdentity.sessionId,
|
|
14228
|
+
parentId: requestSessionIdentity.parentSessionId
|
|
14229
|
+
} : void 0;
|
|
14230
|
+
const isChildRequest = requestSessionIdentity.parentSessionId !== null;
|
|
13321
14231
|
if (accountManager.getAccountCount() === 0) {
|
|
13322
14232
|
return createSyntheticErrorResponse(
|
|
13323
14233
|
"No Antigravity accounts configured. Run `opencode auth login`.",
|
|
@@ -13333,6 +14243,11 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
|
|
|
13333
14243
|
debugLines.push(line);
|
|
13334
14244
|
};
|
|
13335
14245
|
pushDebug(`request=${urlString}`);
|
|
14246
|
+
if (requestSessionIdentity.sessionId) {
|
|
14247
|
+
pushDebug(
|
|
14248
|
+
`[Session] id=${requestSessionIdentity.sessionId} parent=${requestSessionIdentity.parentSessionId ?? "none"} child=${isChildRequest}`
|
|
14249
|
+
);
|
|
14250
|
+
}
|
|
13336
14251
|
const cachedStats = getLastCacheStats();
|
|
13337
14252
|
if (cachedStats) {
|
|
13338
14253
|
const label = cachedStats.hitRate > 0 ? "HIT" : "MISS";
|
|
@@ -13349,11 +14264,15 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
|
|
|
13349
14264
|
const quietMode = config.quiet_mode;
|
|
13350
14265
|
const toastScope = config.toast_scope;
|
|
13351
14266
|
const showToast = async (message, variant) => {
|
|
13352
|
-
log10.debug("toast", { message, variant, isChildSession, toastScope });
|
|
14267
|
+
log10.debug("toast", { message, variant, isChildSession: isChildRequest, toastScope });
|
|
13353
14268
|
if (quietMode) return;
|
|
13354
14269
|
if (abortSignal?.aborted) return;
|
|
13355
|
-
if (toastScope === "root_only" &&
|
|
13356
|
-
log10.debug("toast-suppressed-child-session", {
|
|
14270
|
+
if (toastScope === "root_only" && isChildRequest) {
|
|
14271
|
+
log10.debug("toast-suppressed-child-session", {
|
|
14272
|
+
message,
|
|
14273
|
+
variant,
|
|
14274
|
+
parentID: requestSessionIdentity.parentSessionId
|
|
14275
|
+
});
|
|
13357
14276
|
return;
|
|
13358
14277
|
}
|
|
13359
14278
|
if (variant === "warning" && message.toLowerCase().includes("rate")) {
|
|
@@ -13403,7 +14322,8 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
|
|
|
13403
14322
|
preferredHeaderStyle,
|
|
13404
14323
|
config.pid_offset_enabled,
|
|
13405
14324
|
config.soft_quota_threshold_percent,
|
|
13406
|
-
softQuotaCacheTtlMs
|
|
14325
|
+
softQuotaCacheTtlMs,
|
|
14326
|
+
accountSessionIdentity
|
|
13407
14327
|
);
|
|
13408
14328
|
if (!account && allowQuotaFallback) {
|
|
13409
14329
|
const alternateHeaderStyle = preferredHeaderStyle === "antigravity" ? "gemini-cli" : "antigravity";
|
|
@@ -13414,7 +14334,8 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
|
|
|
13414
14334
|
alternateHeaderStyle,
|
|
13415
14335
|
config.pid_offset_enabled,
|
|
13416
14336
|
config.soft_quota_threshold_percent,
|
|
13417
|
-
softQuotaCacheTtlMs
|
|
14337
|
+
softQuotaCacheTtlMs,
|
|
14338
|
+
accountSessionIdentity
|
|
13418
14339
|
);
|
|
13419
14340
|
if (account) {
|
|
13420
14341
|
pushDebug(
|
|
@@ -13492,7 +14413,7 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
|
|
|
13492
14413
|
pushDebug(`account-switch: ${previousAccountIndex} \u2192 ${account.index}, warmup=${needsCacheWarmup}`);
|
|
13493
14414
|
}
|
|
13494
14415
|
previousAccountIndex = account.index;
|
|
13495
|
-
accountManager.recordSessionUsage(account.index);
|
|
14416
|
+
accountManager.recordSessionUsage(account.index, accountSessionIdentity);
|
|
13496
14417
|
if (isDebugEnabled()) {
|
|
13497
14418
|
logAccountContext("Selected", {
|
|
13498
14419
|
index: account.index,
|
|
@@ -13542,7 +14463,7 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
|
|
|
13542
14463
|
if (removed) {
|
|
13543
14464
|
log10.warn("Removed revoked account from pool - reauthenticate via `opencode auth login`");
|
|
13544
14465
|
try {
|
|
13545
|
-
await accountManager.
|
|
14466
|
+
await accountManager.saveToDiskReplace();
|
|
13546
14467
|
} catch (persistError) {
|
|
13547
14468
|
log10.error("Failed to persist revoked account removal", { error: String(persistError) });
|
|
13548
14469
|
}
|
|
@@ -13785,7 +14706,9 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
|
|
|
13785
14706
|
{
|
|
13786
14707
|
claudeToolHardening: config.claude_tool_hardening,
|
|
13787
14708
|
claudePromptAutoCaching: config.claude_prompt_auto_caching,
|
|
13788
|
-
fingerprint: account.fingerprint
|
|
14709
|
+
fingerprint: account.fingerprint,
|
|
14710
|
+
agySession: agyRequestSession,
|
|
14711
|
+
agyRequestTimestamp: agyRequestScope.timestamp
|
|
13789
14712
|
}
|
|
13790
14713
|
);
|
|
13791
14714
|
const originalUrl = toUrlString(input2);
|
|
@@ -14013,7 +14936,24 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
|
|
|
14013
14936
|
resetAccountFailureState(account.index);
|
|
14014
14937
|
if (response.status === 403) {
|
|
14015
14938
|
const errorBodyText = await response.clone().text().catch(() => "");
|
|
14016
|
-
const extracted =
|
|
14939
|
+
const extracted = extractAccountAccessErrorDetails(errorBodyText);
|
|
14940
|
+
if (extracted.accountIneligible) {
|
|
14941
|
+
const ineligibleReason = extracted.message ?? "Google marked this account as ineligible for Antigravity.";
|
|
14942
|
+
accountManager.markAccountIneligible(account.index, ineligibleReason);
|
|
14943
|
+
const label = account.email || `Account ${account.index + 1}`;
|
|
14944
|
+
if (accountManager.shouldShowAccountToast(account.index, 6e4)) {
|
|
14945
|
+
await showToast(
|
|
14946
|
+
`${label} is not eligible for Antigravity and has been disabled. Recheck it from opencode auth login > Verify accounts.`,
|
|
14947
|
+
"warning"
|
|
14948
|
+
);
|
|
14949
|
+
accountManager.markToastShown(account.index);
|
|
14950
|
+
}
|
|
14951
|
+
pushDebug(`account-ineligible: disabled account ${account.index}`);
|
|
14952
|
+
getHealthTracker().recordFailure(account.index);
|
|
14953
|
+
lastFailure = createFailureContext(response);
|
|
14954
|
+
shouldSwitchAccount = true;
|
|
14955
|
+
break;
|
|
14956
|
+
}
|
|
14017
14957
|
if (extracted.validationRequired) {
|
|
14018
14958
|
const verificationReason = extracted.message ?? "Google requires account verification.";
|
|
14019
14959
|
const cooldownMs = 10 * 60 * 1e3;
|
|
@@ -14057,20 +14997,24 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
|
|
|
14057
14997
|
family,
|
|
14058
14998
|
model,
|
|
14059
14999
|
proactiveThreshold,
|
|
14060
|
-
softQuotaCacheTtlMs
|
|
15000
|
+
softQuotaCacheTtlMs,
|
|
15001
|
+
accountSessionIdentity
|
|
14061
15002
|
)) {
|
|
14062
15003
|
const rotated = accountManager.proactivelyRotateForFamily(
|
|
14063
15004
|
family,
|
|
14064
15005
|
model,
|
|
14065
15006
|
headerStyle,
|
|
14066
15007
|
config.soft_quota_threshold_percent,
|
|
14067
|
-
softQuotaCacheTtlMs
|
|
15008
|
+
softQuotaCacheTtlMs,
|
|
15009
|
+
accountSessionIdentity
|
|
14068
15010
|
);
|
|
14069
15011
|
if (rotated) {
|
|
14070
15012
|
const remaining = account.cachedQuota?.[resolveQuotaGroup(family, model)]?.remainingFraction;
|
|
14071
15013
|
const remainingPct = remaining != null ? `${(remaining * 100).toFixed(1)}%` : "?";
|
|
14072
15014
|
pushDebug(`[ProactiveRotation] account ${account.index} quota ${remainingPct} < ${proactiveThreshold}%, pre-switched to account ${rotated.index} for next request`);
|
|
14073
|
-
pushDebug(
|
|
15015
|
+
pushDebug(
|
|
15016
|
+
`[ProactiveRotation] ${account.index} \u2192 ${rotated.index} (warm=${accountManager.wasUsedInSession(rotated.index, accountSessionIdentity)})`
|
|
15017
|
+
);
|
|
14074
15018
|
}
|
|
14075
15019
|
}
|
|
14076
15020
|
}
|
|
@@ -14169,7 +15113,7 @@ Alternatively, you can:
|
|
|
14169
15113
|
pushDebug(`[Quota] Total ${family} requests today (all accounts): ${totalToday}`);
|
|
14170
15114
|
const cachedQuota = account.cachedQuota;
|
|
14171
15115
|
if (cachedQuota) {
|
|
14172
|
-
const quotaFamily = family
|
|
15116
|
+
const quotaFamily = resolveQuotaGroup(family, model);
|
|
14173
15117
|
const groupQuota = cachedQuota[quotaFamily];
|
|
14174
15118
|
if (groupQuota?.remainingFraction != null) {
|
|
14175
15119
|
const pct = Math.round(groupQuota.remainingFraction * 100);
|
|
@@ -14324,7 +15268,9 @@ Alternatively, you can:
|
|
|
14324
15268
|
const now = Date.now();
|
|
14325
15269
|
const existingAccounts = existingStorage2.accounts.map((acc, idx) => {
|
|
14326
15270
|
let status = "unknown";
|
|
14327
|
-
if (acc.
|
|
15271
|
+
if (acc.accountIneligible) {
|
|
15272
|
+
status = "ineligible";
|
|
15273
|
+
} else if (acc.verificationRequired) {
|
|
14328
15274
|
status = "verification-required";
|
|
14329
15275
|
} else {
|
|
14330
15276
|
const rateLimits = acc.rateLimitResetTimes;
|
|
@@ -14460,7 +15406,8 @@ Alternatively, you can:
|
|
|
14460
15406
|
const groupEntries = [
|
|
14461
15407
|
{ name: "Claude", data: groups.claude },
|
|
14462
15408
|
{ name: "Gemini 3 Pro", data: groups["gemini-pro"] },
|
|
14463
|
-
{ name: "Gemini 3 Flash", data: groups["gemini-flash"] }
|
|
15409
|
+
{ name: "Gemini 3 Flash", data: groups["gemini-flash"] },
|
|
15410
|
+
{ name: "GPT-OSS", data: groups["gpt-oss"] }
|
|
14464
15411
|
].filter((g) => g.data);
|
|
14465
15412
|
groupEntries.forEach((g, idx) => {
|
|
14466
15413
|
const isLast = idx === groupEntries.length - 1;
|
|
@@ -14519,7 +15466,16 @@ ${formatAuthDoctorReport(report)}
|
|
|
14519
15466
|
if (menuResult.toggleAccountIndex !== void 0) {
|
|
14520
15467
|
const acc = existingStorage2.accounts[menuResult.toggleAccountIndex];
|
|
14521
15468
|
if (acc) {
|
|
14522
|
-
|
|
15469
|
+
const shouldEnable = acc.enabled === false;
|
|
15470
|
+
if (shouldEnable && acc.accountIneligible) {
|
|
15471
|
+
console.log(
|
|
15472
|
+
`
|
|
15473
|
+
${acc.email || `Account ${menuResult.toggleAccountIndex + 1}`} remains disabled. Use Verify accounts to recheck eligibility.
|
|
15474
|
+
`
|
|
15475
|
+
);
|
|
15476
|
+
continue;
|
|
15477
|
+
}
|
|
15478
|
+
acc.enabled = shouldEnable;
|
|
14523
15479
|
await saveAccounts(existingStorage2);
|
|
14524
15480
|
activeAccountManager?.setAccountEnabled(menuResult.toggleAccountIndex, acc.enabled);
|
|
14525
15481
|
console.log(`
|
|
@@ -14541,6 +15497,7 @@ Checking verification status for ${existingStorage2.accounts.length} account(s).
|
|
|
14541
15497
|
`);
|
|
14542
15498
|
let okCount = 0;
|
|
14543
15499
|
let blockedCount = 0;
|
|
15500
|
+
let ineligibleCount = 0;
|
|
14544
15501
|
let errorCount = 0;
|
|
14545
15502
|
let storageUpdated = false;
|
|
14546
15503
|
const blockedResults = [];
|
|
@@ -14551,16 +15508,16 @@ Checking verification status for ${existingStorage2.accounts.length} account(s).
|
|
|
14551
15508
|
process.stdout.write(`- [${i + 1}/${existingStorage2.accounts.length}] ${label2} ... `);
|
|
14552
15509
|
const verification2 = await verifyAccountAccess(account2, client, providerId);
|
|
14553
15510
|
if (verification2.status === "ok") {
|
|
14554
|
-
const { changed,
|
|
15511
|
+
const { changed, wasAccessBlocked } = clearStoredAccountAccessBlocks(account2, true);
|
|
14555
15512
|
if (changed) {
|
|
14556
15513
|
storageUpdated = true;
|
|
14557
15514
|
}
|
|
14558
|
-
activeAccountManager?.
|
|
15515
|
+
activeAccountManager?.clearAccountAccessBlocks(i, wasAccessBlocked);
|
|
14559
15516
|
okCount += 1;
|
|
14560
15517
|
console.log("ok");
|
|
14561
15518
|
continue;
|
|
14562
15519
|
}
|
|
14563
|
-
if (verification2.status === "
|
|
15520
|
+
if (verification2.status === "verification-required") {
|
|
14564
15521
|
const changed = markStoredAccountVerificationRequired(
|
|
14565
15522
|
account2,
|
|
14566
15523
|
verification2.message,
|
|
@@ -14580,14 +15537,26 @@ Checking verification status for ${existingStorage2.accounts.length} account(s).
|
|
|
14580
15537
|
});
|
|
14581
15538
|
continue;
|
|
14582
15539
|
}
|
|
15540
|
+
if (verification2.status === "ineligible") {
|
|
15541
|
+
const changed = markStoredAccountIneligible(account2, verification2.message);
|
|
15542
|
+
if (changed) {
|
|
15543
|
+
storageUpdated = true;
|
|
15544
|
+
}
|
|
15545
|
+
activeAccountManager?.markAccountIneligible(i, verification2.message);
|
|
15546
|
+
ineligibleCount += 1;
|
|
15547
|
+
console.log("ineligible");
|
|
15548
|
+
continue;
|
|
15549
|
+
}
|
|
14583
15550
|
errorCount += 1;
|
|
14584
15551
|
console.log(`error (${verification2.message})`);
|
|
14585
15552
|
}
|
|
14586
15553
|
if (storageUpdated) {
|
|
14587
15554
|
await saveAccounts(existingStorage2);
|
|
14588
15555
|
}
|
|
14589
|
-
console.log(
|
|
14590
|
-
|
|
15556
|
+
console.log(
|
|
15557
|
+
`
|
|
15558
|
+
Verification summary: ${okCount} ready, ${blockedCount} need verification, ${ineligibleCount} ineligible, ${errorCount} errors.`
|
|
15559
|
+
);
|
|
14591
15560
|
if (blockedResults.length > 0) {
|
|
14592
15561
|
console.log("\nAccounts needing verification:");
|
|
14593
15562
|
for (const result of blockedResults) {
|
|
@@ -14627,12 +15596,12 @@ Checking verification status for ${label}...
|
|
|
14627
15596
|
`);
|
|
14628
15597
|
const verification = await verifyAccountAccess(account, client, providerId);
|
|
14629
15598
|
if (verification.status === "ok") {
|
|
14630
|
-
const { changed,
|
|
15599
|
+
const { changed, wasAccessBlocked } = clearStoredAccountAccessBlocks(account, true);
|
|
14631
15600
|
if (changed) {
|
|
14632
15601
|
await saveAccounts(existingStorage2);
|
|
14633
15602
|
}
|
|
14634
|
-
activeAccountManager?.
|
|
14635
|
-
if (
|
|
15603
|
+
activeAccountManager?.clearAccountAccessBlocks(verifyAccountIndex, wasAccessBlocked);
|
|
15604
|
+
if (wasAccessBlocked) {
|
|
14636
15605
|
console.log(`\u2713 ${label} is ready for requests and has been re-enabled.
|
|
14637
15606
|
`);
|
|
14638
15607
|
} else {
|
|
@@ -14641,7 +15610,7 @@ Checking verification status for ${label}...
|
|
|
14641
15610
|
}
|
|
14642
15611
|
continue;
|
|
14643
15612
|
}
|
|
14644
|
-
if (verification.status === "
|
|
15613
|
+
if (verification.status === "verification-required") {
|
|
14645
15614
|
const changed = markStoredAccountVerificationRequired(
|
|
14646
15615
|
account,
|
|
14647
15616
|
verification.message,
|
|
@@ -14679,6 +15648,20 @@ ${verifyUrl}
|
|
|
14679
15648
|
}
|
|
14680
15649
|
continue;
|
|
14681
15650
|
}
|
|
15651
|
+
if (verification.status === "ineligible") {
|
|
15652
|
+
const changed = markStoredAccountIneligible(account, verification.message);
|
|
15653
|
+
if (changed) {
|
|
15654
|
+
await saveAccounts(existingStorage2);
|
|
15655
|
+
}
|
|
15656
|
+
activeAccountManager?.markAccountIneligible(
|
|
15657
|
+
verifyAccountIndex,
|
|
15658
|
+
verification.message
|
|
15659
|
+
);
|
|
15660
|
+
console.log(`\u26A0 ${label} is not eligible for Antigravity and has been disabled.`);
|
|
15661
|
+
console.log(`${verification.message}
|
|
15662
|
+
`);
|
|
15663
|
+
continue;
|
|
15664
|
+
}
|
|
14682
15665
|
console.log(`\u2717 ${label}: ${verification.message}
|
|
14683
15666
|
`);
|
|
14684
15667
|
continue;
|