@cortexkit/opencode-antigravity-auth 1.0.1 → 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.
Files changed (47) hide show
  1. package/README.md +24 -8
  2. package/dist/index.js +1299 -431
  3. package/dist/index.js.map +4 -4
  4. package/dist/src/plugin/accounts.d.ts +29 -9
  5. package/dist/src/plugin/accounts.d.ts.map +1 -1
  6. package/dist/src/plugin/accounts.js +253 -52
  7. package/dist/src/plugin/accounts.js.map +1 -1
  8. package/dist/src/plugin/agy-request-metadata.d.ts +2 -0
  9. package/dist/src/plugin/agy-request-metadata.d.ts.map +1 -0
  10. package/dist/src/plugin/agy-request-metadata.js +2 -0
  11. package/dist/src/plugin/agy-request-metadata.js.map +1 -0
  12. package/dist/src/plugin/auth-doctor.d.ts +1 -1
  13. package/dist/src/plugin/auth-doctor.d.ts.map +1 -1
  14. package/dist/src/plugin/auth-doctor.js +9 -0
  15. package/dist/src/plugin/auth-doctor.js.map +1 -1
  16. package/dist/src/plugin/image-saver.d.ts +2 -21
  17. package/dist/src/plugin/image-saver.d.ts.map +1 -1
  18. package/dist/src/plugin/image-saver.js +29 -63
  19. package/dist/src/plugin/image-saver.js.map +1 -1
  20. package/dist/src/plugin/request-helpers.d.ts +1 -0
  21. package/dist/src/plugin/request-helpers.d.ts.map +1 -1
  22. package/dist/src/plugin/request-helpers.js +9 -4
  23. package/dist/src/plugin/request-helpers.js.map +1 -1
  24. package/dist/src/plugin/request.d.ts +6 -0
  25. package/dist/src/plugin/request.d.ts.map +1 -1
  26. package/dist/src/plugin/request.js +230 -57
  27. package/dist/src/plugin/request.js.map +1 -1
  28. package/dist/src/plugin/session-context.d.ts +21 -0
  29. package/dist/src/plugin/session-context.d.ts.map +1 -0
  30. package/dist/src/plugin/session-context.js +63 -0
  31. package/dist/src/plugin/session-context.js.map +1 -0
  32. package/dist/src/plugin/storage.d.ts +6 -0
  33. package/dist/src/plugin/storage.d.ts.map +1 -1
  34. package/dist/src/plugin/storage.js +14 -3
  35. package/dist/src/plugin/storage.js.map +1 -1
  36. package/dist/src/plugin/ui/auth-menu.d.ts +1 -1
  37. package/dist/src/plugin/ui/auth-menu.d.ts.map +1 -1
  38. package/dist/src/plugin/ui/auth-menu.js +3 -1
  39. package/dist/src/plugin/ui/auth-menu.js.map +1 -1
  40. package/dist/src/plugin/ui/quota-status.d.ts.map +1 -1
  41. package/dist/src/plugin/ui/quota-status.js +2 -1
  42. package/dist/src/plugin/ui/quota-status.js.map +1 -1
  43. package/dist/src/plugin.d.ts +16 -0
  44. package/dist/src/plugin.d.ts.map +1 -1
  45. package/dist/src/plugin.js +261 -101
  46. package/dist/src/plugin.js.map +1 -1
  47. package/package.json +2 -2
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": `antigravity/cli/1.0.4 ${platform}`
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";
@@ -332,7 +324,7 @@ function buildAgyCliHeaderPairs(url, init = {}) {
332
324
  const headers = headersToRecord(init.headers);
333
325
  const body = bodyToBuffer(init.body);
334
326
  const host = parsedUrl.port ? `${parsedUrl.hostname}:${parsedUrl.port}` : parsedUrl.hostname;
335
- const userAgent = getHeader(headers, "User-Agent") ?? "antigravity/cli/1.0.4 darwin/arm64";
327
+ const userAgent = getHeader(headers, "User-Agent") ?? buildAntigravityHarnessUserAgent();
336
328
  const authorization = getHeader(headers, "Authorization");
337
329
  const contentType = getHeader(headers, "Content-Type") ?? "application/json";
338
330
  const acceptEncoding = getHeader(headers, "Accept-Encoding") ?? "gzip";
@@ -381,7 +373,7 @@ function getHttpsProxy(url) {
381
373
  }
382
374
  }
383
375
  function waitForHead(socket, timeoutMs, onTimeout) {
384
- return new Promise((resolve, reject) => {
376
+ return new Promise((resolve2, reject) => {
385
377
  let buffer = Buffer2.alloc(0);
386
378
  const timeout = setTimeout(() => {
387
379
  onTimeout();
@@ -401,7 +393,7 @@ function waitForHead(socket, timeoutMs, onTimeout) {
401
393
  return;
402
394
  const head = buffer.subarray(0, marker).toString("latin1");
403
395
  const leftover = buffer.subarray(marker + 4);
404
- cleanup(() => resolve({ head, leftover }));
396
+ cleanup(() => resolve2({ head, leftover }));
405
397
  };
406
398
  socket.on("data", onData);
407
399
  socket.once("error", onError);
@@ -412,7 +404,7 @@ async function connectViaProxy(proxyUrl, targetUrl, timeoutMs, onDebug) {
412
404
  host: proxyUrl.hostname,
413
405
  port: Number(proxyUrl.port || DEFAULT_PROXY_PORT)
414
406
  });
415
- await new Promise((resolve, reject) => {
407
+ await new Promise((resolve2, reject) => {
416
408
  const timeout = setTimeout(() => {
417
409
  onDebug?.(`agy transport proxy connect timeout after ${timeoutMs}ms`);
418
410
  proxySocket.destroy();
@@ -421,7 +413,7 @@ async function connectViaProxy(proxyUrl, targetUrl, timeoutMs, onDebug) {
421
413
  const cleanup = () => clearTimeout(timeout);
422
414
  proxySocket.once("connect", () => {
423
415
  cleanup();
424
- resolve();
416
+ resolve2();
425
417
  });
426
418
  proxySocket.once("error", (error) => {
427
419
  cleanup();
@@ -446,7 +438,7 @@ Host: ${targetHost}:${targetPort}\r
446
438
  if (leftover.length > 0) {
447
439
  proxySocket.unshift(leftover);
448
440
  }
449
- return await new Promise((resolve, reject) => {
441
+ return await new Promise((resolve2, reject) => {
450
442
  const tlsSocket = tls.connect({ socket: proxySocket, servername: targetHost });
451
443
  const timeout = setTimeout(() => {
452
444
  onDebug?.(`agy transport proxy TLS handshake timeout after ${timeoutMs}ms`);
@@ -456,7 +448,7 @@ Host: ${targetHost}:${targetPort}\r
456
448
  const cleanup = () => clearTimeout(timeout);
457
449
  tlsSocket.once("secureConnect", () => {
458
450
  cleanup();
459
- resolve(tlsSocket);
451
+ resolve2(tlsSocket);
460
452
  });
461
453
  tlsSocket.once("error", (error) => {
462
454
  cleanup();
@@ -465,7 +457,7 @@ Host: ${targetHost}:${targetPort}\r
465
457
  });
466
458
  }
467
459
  async function connectDirect(targetUrl, timeoutMs, onDebug) {
468
- return await new Promise((resolve, reject) => {
460
+ return await new Promise((resolve2, reject) => {
469
461
  const socket = tls.connect({
470
462
  host: targetUrl.hostname,
471
463
  port: Number(targetUrl.port || DEFAULT_HTTPS_PORT),
@@ -479,7 +471,7 @@ async function connectDirect(targetUrl, timeoutMs, onDebug) {
479
471
  const cleanup = () => clearTimeout(timeout);
480
472
  socket.once("secureConnect", () => {
481
473
  cleanup();
482
- resolve(socket);
474
+ resolve2(socket);
483
475
  });
484
476
  socket.once("error", (error) => {
485
477
  cleanup();
@@ -493,9 +485,9 @@ async function connectTls(targetUrl, timeoutMs, onDebug) {
493
485
  }
494
486
  function serializeRequest(url, init, body) {
495
487
  const method = init.method ?? "POST";
496
- const path5 = `${url.pathname}${url.search}`;
488
+ const path4 = `${url.pathname}${url.search}`;
497
489
  const headerLines = buildAgyCliHeaderPairs(url.toString(), init).map(([key, value]) => `${key}: ${value}`).join("\r\n");
498
- const head = Buffer2.from(`${method} ${path5} HTTP/1.1\r
490
+ const head = Buffer2.from(`${method} ${path4} HTTP/1.1\r
499
491
  ${headerLines}\r
500
492
  \r
501
493
  `);
@@ -745,6 +737,178 @@ async function connectTlsWithAbort(targetUrl, timeoutMs, signal, onDebug) {
745
737
  }
746
738
  }
747
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
+ }
911
+
748
912
  // ../core/dist/version.js
749
913
  var VERSION_URL = "https://antigravity-auto-updater-974169037036.us-central1.run.app";
750
914
  var CHANGELOG_URL = "https://antigravity.google/changelog";
@@ -830,8 +994,8 @@ function getDefaultTierId(allowedTiers) {
830
994
  return allowedTiers[0]?.id;
831
995
  }
832
996
  function wait(ms) {
833
- return new Promise(function(resolve) {
834
- setTimeout(resolve, ms);
997
+ return new Promise(function(resolve2) {
998
+ setTimeout(resolve2, ms);
835
999
  });
836
1000
  }
837
1001
  function extractManagedProjectId(payload) {
@@ -1035,6 +1199,16 @@ var ALL_MODEL_DEFINITIONS = {
1035
1199
  high: { thinkingLevel: "high" }
1036
1200
  }
1037
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
+ }),
1038
1212
  "antigravity-gemini-3.5-flash": defineModel("antigravity-gemini-3.5-flash", {
1039
1213
  name: "Gemini 3.5 Flash (Antigravity)",
1040
1214
  reasoning: true,
@@ -1074,14 +1248,11 @@ var ALL_MODEL_DEFINITIONS = {
1074
1248
  output: ["text", "image"]
1075
1249
  }
1076
1250
  }),
1077
- "antigravity-gpt-oss-120b": defineModel("antigravity-gpt-oss-120b", {
1078
- name: "GPT-OSS 120B (Antigravity)",
1079
- reasoning: false,
1080
- limit: { context: 128e3, output: 16384 },
1081
- modalities: DEFAULT_MODALITIES,
1082
- variants: {
1083
- medium: {}
1084
- }
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
1085
1256
  }),
1086
1257
  "gemini-2.5-flash": defineModel("gemini-2.5-flash", {
1087
1258
  name: "Gemini 2.5 Flash (Gemini CLI)",
@@ -1147,6 +1318,9 @@ var RESOLVER_ALIASES = {
1147
1318
  "gemini-3.5-flash-low": "gemini-3.5-flash",
1148
1319
  "gemini-3.5-flash-medium": "gemini-3.5-flash",
1149
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",
1150
1324
  "gemini-claude-opus-4-6-thinking-low": "claude-opus-4-6-thinking",
1151
1325
  "gemini-claude-opus-4-6-thinking-medium": "claude-opus-4-6-thinking",
1152
1326
  "gemini-claude-opus-4-6-thinking-high": "claude-opus-4-6-thinking",
@@ -1157,7 +1331,8 @@ var RESOLVER_ALIASES = {
1157
1331
  "claude-sonnet-4-6-thinking": "claude-sonnet-4-6",
1158
1332
  "claude-sonnet-4-6-thinking-low": "claude-sonnet-4-6",
1159
1333
  "claude-sonnet-4-6-thinking-medium": "claude-sonnet-4-6",
1160
- "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"
1161
1336
  };
1162
1337
  var GEMINI_35_FLASH_ROUTES = {
1163
1338
  antigravity: {
@@ -1170,6 +1345,14 @@ var GEMINI_35_FLASH_ROUTES = {
1170
1345
  },
1171
1346
  geminiCliFallbackModel: "gemini-3-flash-preview"
1172
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
+ };
1173
1356
  var QUOTA_GROUP_BY_MODEL_ID = {
1174
1357
  "claude-opus-4-6-thinking": "claude",
1175
1358
  "claude-opus-4-6": "claude",
@@ -1183,15 +1366,22 @@ var QUOTA_GROUP_BY_MODEL_ID = {
1183
1366
  "gemini-3-flash-agent": "gemini-flash",
1184
1367
  "gemini-3.5-flash-low": "gemini-flash",
1185
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",
1186
1373
  "gemini-3.1-flash-image": "gemini-flash",
1187
1374
  "gpt-oss-120b": "gpt-oss",
1188
1375
  "gpt-oss-120b-medium": "gpt-oss"
1189
1376
  };
1190
1377
  var ANTIGRAVITY_OPENCODE_MODEL_IDS = [
1378
+ "antigravity-gemini-3.6-flash",
1191
1379
  "antigravity-gemini-3.5-flash",
1192
1380
  "antigravity-gemini-3.1-pro",
1193
1381
  "antigravity-claude-sonnet-4-6-thinking",
1194
- "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"
1195
1385
  ];
1196
1386
  function pickModelDefinitions(ids) {
1197
1387
  return Object.fromEntries(ids.map((id) => [id, ALL_MODEL_DEFINITIONS[id]]));
@@ -1212,6 +1402,12 @@ function getGemini35FlashAntigravityModel(tier) {
1212
1402
  function getGemini35FlashGeminiCliFallbackModel() {
1213
1403
  return GEMINI_35_FLASH_ROUTES.geminiCliFallbackModel;
1214
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
+ }
1215
1411
  function getQuotaGroupForModel(modelId) {
1216
1412
  return QUOTA_GROUP_BY_MODEL_ID[modelId.toLowerCase()];
1217
1413
  }
@@ -1268,7 +1464,7 @@ function isGemini35FlashModel(model) {
1268
1464
  function resolveGemini35FlashAntigravityModel(tier) {
1269
1465
  return getGemini35FlashAntigravityModel(tier);
1270
1466
  }
1271
- function getAgyGemini35FlashThinkingBudget(tier) {
1467
+ function getAgyGeminiFlashThinkingBudget(tier) {
1272
1468
  switch (tier) {
1273
1469
  case "low":
1274
1470
  return 1e3;
@@ -1301,6 +1497,8 @@ function resolveModelWithTier(requestedModel, options = {}) {
1301
1497
  const isGemini3Flash = isGemini3FlashModel(modelWithoutQuota);
1302
1498
  const isGemini31Pro = /^gemini-3\.1-pro/i.test(baseName);
1303
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);
1304
1502
  if (isGemini31Pro && quotaPreference === "antigravity") {
1305
1503
  return {
1306
1504
  actualModel: getAgyGemini31ProModel(tier),
@@ -1314,13 +1512,32 @@ function resolveModelWithTier(requestedModel, options = {}) {
1314
1512
  if (isGemini35Flash && quotaPreference === "antigravity") {
1315
1513
  return {
1316
1514
  actualModel: resolveGemini35FlashAntigravityModel(tier ?? "medium"),
1317
- thinkingBudget: getAgyGemini35FlashThinkingBudget(tier),
1515
+ thinkingBudget: getAgyGeminiFlashThinkingBudget(tier),
1318
1516
  tier: tier ?? "medium",
1319
1517
  isThinkingModel: true,
1320
1518
  quotaPreference,
1321
1519
  explicitQuota
1322
1520
  };
1323
1521
  }
1522
+ if (isGemini36Flash && quotaPreference === "antigravity") {
1523
+ return {
1524
+ actualModel: getGemini36FlashAntigravityModel(tier ?? "medium"),
1525
+ thinkingBudget: getAgyGeminiFlashThinkingBudget(tier),
1526
+ tier: tier ?? "medium",
1527
+ isThinkingModel: true,
1528
+ quotaPreference,
1529
+ explicitQuota
1530
+ };
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
+ }
1324
1541
  let antigravityModel = modelWithoutQuota;
1325
1542
  if (skipAlias) {
1326
1543
  if ((isGemini3Pro || isGemini3Flash) && !tier && !isImageModel) {
@@ -1517,12 +1734,26 @@ var UNSUPPORTED_SCHEMA_FIELDS = /* @__PURE__ */ new Set([
1517
1734
  "minContains",
1518
1735
  "maxContains"
1519
1736
  ]);
1520
- function toGeminiSchema(schema) {
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 = {}) {
1521
1751
  if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
1522
1752
  return schema;
1523
1753
  }
1524
1754
  const inputSchema = schema;
1525
1755
  const result = {};
1756
+ const numericConstraintHints = [];
1526
1757
  const propertyNames = /* @__PURE__ */ new Set();
1527
1758
  if (inputSchema.properties && typeof inputSchema.properties === "object") {
1528
1759
  for (const propName of Object.keys(inputSchema.properties)) {
@@ -1538,15 +1769,19 @@ function toGeminiSchema(schema) {
1538
1769
  } else if (key === "properties" && typeof value === "object" && value !== null) {
1539
1770
  const props = {};
1540
1771
  for (const [propName, propSchema] of Object.entries(value)) {
1541
- props[propName] = toGeminiSchema(propSchema);
1772
+ props[propName] = toGeminiSchema(propSchema, options);
1542
1773
  }
1543
1774
  result[key] = props;
1544
1775
  } else if (key === "items" && typeof value === "object") {
1545
- result[key] = toGeminiSchema(value);
1776
+ result[key] = toGeminiSchema(value, options);
1546
1777
  } else if ((key === "anyOf" || key === "oneOf" || key === "allOf") && Array.isArray(value)) {
1547
- result[key] = value.map((item) => toGeminiSchema(item));
1778
+ result[key] = value.map((item) => toGeminiSchema(item, options));
1548
1779
  } else if (key === "enum" && Array.isArray(value)) {
1549
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
+ }
1550
1785
  } else if (key === "default" || key === "examples") {
1551
1786
  result[key] = value;
1552
1787
  } else if (key === "required" && Array.isArray(value)) {
@@ -1562,6 +1797,10 @@ function toGeminiSchema(schema) {
1562
1797
  result[key] = value;
1563
1798
  }
1564
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
+ }
1565
1804
  if (result.type === "ARRAY" && !result.items) {
1566
1805
  result.items = { type: "STRING" };
1567
1806
  }
@@ -1599,7 +1838,7 @@ function buildImageGenerationConfig() {
1599
1838
  console.warn(`[gemini] Invalid aspect ratio "${aspectRatio}". Using default "1:1". Valid values: ${VALID_ASPECT_RATIOS.join(", ")}`);
1600
1839
  return { aspectRatio: "1:1" };
1601
1840
  }
1602
- function normalizeGeminiTools(payload) {
1841
+ function normalizeGeminiTools(payload, schemaOptions = {}) {
1603
1842
  let toolDebugMissing = 0;
1604
1843
  const toolDebugSummaries = [];
1605
1844
  if (!Array.isArray(payload.tools)) {
@@ -1610,6 +1849,21 @@ function normalizeGeminiTools(payload) {
1610
1849
  if (t.googleSearch || t.googleSearchRetrieval) {
1611
1850
  return t;
1612
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
+ }
1613
1867
  const newTool = { ...t };
1614
1868
  const schemaCandidates = [
1615
1869
  newTool.function?.input_schema,
@@ -1637,7 +1891,7 @@ function normalizeGeminiTools(payload) {
1637
1891
  schema = placeholderSchema;
1638
1892
  toolDebugMissing += 1;
1639
1893
  } else {
1640
- schema = toGeminiSchema(schema);
1894
+ schema = toGeminiSchema(schema, schemaOptions);
1641
1895
  }
1642
1896
  const nameCandidate = newTool.name || newTool.function?.name || newTool.custom?.name || `tool-${toolIndex}`;
1643
1897
  if (newTool.function && schema) {
@@ -1702,7 +1956,9 @@ function applyGeminiTransforms(payload, options) {
1702
1956
  googleSearch: {}
1703
1957
  });
1704
1958
  }
1705
- const result = normalizeGeminiTools(payload);
1959
+ const result = normalizeGeminiTools(payload, {
1960
+ moveNumericConstraintsToDescription: model.toLowerCase().startsWith("gpt-oss-")
1961
+ });
1706
1962
  const wrapResult = wrapToolsAsFunctionDeclarations(payload);
1707
1963
  return {
1708
1964
  ...result,
@@ -2203,7 +2459,7 @@ async function select(items, options) {
2203
2459
  }
2204
2460
  renderedLines = linesWritten;
2205
2461
  };
2206
- return new Promise((resolve) => {
2462
+ return new Promise((resolve2) => {
2207
2463
  const wasRaw = stdin.isRaw ?? false;
2208
2464
  const cleanup = () => {
2209
2465
  if (isCleanedUp) return;
@@ -2224,11 +2480,11 @@ async function select(items, options) {
2224
2480
  };
2225
2481
  const onSignal = () => {
2226
2482
  cleanup();
2227
- resolve(null);
2483
+ resolve2(null);
2228
2484
  };
2229
2485
  const finishWithValue = (value) => {
2230
2486
  cleanup();
2231
- resolve(value);
2487
+ resolve2(value);
2232
2488
  };
2233
2489
  const findNextSelectable = (from, direction) => {
2234
2490
  if (items.length === 0) return from;
@@ -2274,7 +2530,7 @@ async function select(items, options) {
2274
2530
  stdin.setRawMode(true);
2275
2531
  } catch {
2276
2532
  cleanup();
2277
- resolve(null);
2533
+ resolve2(null);
2278
2534
  return;
2279
2535
  }
2280
2536
  stdin.resume();
@@ -2401,7 +2657,7 @@ function classifyOverallQuotaHealth(cachedQuota) {
2401
2657
  if (!cachedQuota) {
2402
2658
  return { health: "unknown" };
2403
2659
  }
2404
- const QUOTA_KEYS2 = ["claude", "gemini-pro", "gemini-flash"];
2660
+ const QUOTA_KEYS2 = ["claude", "gemini-pro", "gemini-flash", "gpt-oss"];
2405
2661
  let groupsWithData = 0;
2406
2662
  let exhaustedCount = 0;
2407
2663
  let maxResetMs;
@@ -2435,7 +2691,8 @@ function formatCachedQuotaWithStatus(cachedQuota) {
2435
2691
  const entries = [
2436
2692
  { key: "claude", label: "Claude" },
2437
2693
  { key: "gemini-pro", label: "Gemini Pro" },
2438
- { key: "gemini-flash", label: "Gemini Flash" }
2694
+ { key: "gemini-flash", label: "Gemini Flash" },
2695
+ { key: "gpt-oss", label: "GPT-OSS" }
2439
2696
  ].flatMap(({ key, label }) => {
2440
2697
  const value = cachedQuota[key]?.remainingFraction;
2441
2698
  if (typeof value !== "number" || !Number.isFinite(value)) {
@@ -2495,6 +2752,8 @@ function getStatusBadge(status, account) {
2495
2752
  return ` ${ANSI.red}[expired]${ANSI.reset}`;
2496
2753
  case "verification-required":
2497
2754
  return ` ${ANSI.red}[needs verification]${ANSI.reset}`;
2755
+ case "ineligible":
2756
+ return ` ${ANSI.red}[ineligible]${ANSI.reset}`;
2498
2757
  default:
2499
2758
  return "";
2500
2759
  }
@@ -2526,7 +2785,8 @@ function getHealthLabel(acc) {
2526
2785
  var QUOTA_KEYS = [
2527
2786
  { key: "claude", label: "Claude" },
2528
2787
  { key: "gemini-pro", label: "Gemini Pro" },
2529
- { key: "gemini-flash", label: "Gemini Flash" }
2788
+ { key: "gemini-flash", label: "Gemini Flash" },
2789
+ { key: "gpt-oss", label: "GPT-OSS" }
2530
2790
  ];
2531
2791
  function parseResetTimeToMs2(resetTime) {
2532
2792
  if (!resetTime) return null;
@@ -3170,7 +3430,7 @@ async function getLockFunction() {
3170
3430
  _cachedLock = fn;
3171
3431
  return _cachedLock;
3172
3432
  }
3173
- var lockfile = { lock: (path5, options) => getLockFunction().then((fn) => fn(path5, options)) };
3433
+ var lockfile = { lock: (path4, options) => getLockFunction().then((fn) => fn(path4, options)) };
3174
3434
  var log3 = createLogger2("storage");
3175
3435
  var GITIGNORE_ENTRIES = [
3176
3436
  ".gitignore",
@@ -3338,29 +3598,29 @@ var LOCK_OPTIONS = {
3338
3598
  factor: 2
3339
3599
  }
3340
3600
  };
3341
- async function ensureSecurePermissions(path5) {
3601
+ async function ensureSecurePermissions(path4) {
3342
3602
  try {
3343
- await fs.chmod(path5, 384);
3603
+ await fs.chmod(path4, 384);
3344
3604
  } catch {
3345
3605
  }
3346
3606
  }
3347
- async function ensureFileExists(path5) {
3607
+ async function ensureFileExists(path4) {
3348
3608
  try {
3349
- await fs.access(path5);
3609
+ await fs.access(path4);
3350
3610
  } catch {
3351
- await fs.mkdir(dirname2(path5), { recursive: true });
3611
+ await fs.mkdir(dirname2(path4), { recursive: true });
3352
3612
  await fs.writeFile(
3353
- path5,
3613
+ path4,
3354
3614
  JSON.stringify({ version: 4, accounts: [], activeIndex: 0 }, null, 2),
3355
3615
  { encoding: "utf-8", mode: 384 }
3356
3616
  );
3357
3617
  }
3358
3618
  }
3359
- async function withFileLock(path5, fn) {
3360
- await ensureFileExists(path5);
3619
+ async function withFileLock(path4, fn) {
3620
+ await ensureFileExists(path4);
3361
3621
  let release = null;
3362
3622
  try {
3363
- release = await lockfile.lock(path5, LOCK_OPTIONS);
3623
+ release = await lockfile.lock(path4, LOCK_OPTIONS);
3364
3624
  return await fn();
3365
3625
  } finally {
3366
3626
  if (release) {
@@ -3383,7 +3643,8 @@ function mergeAccountStorage(existing, incoming) {
3383
3643
  if (acc.refreshToken) {
3384
3644
  const existingAcc = accountMap.get(acc.refreshToken);
3385
3645
  if (existingAcc) {
3386
- accountMap.set(acc.refreshToken, {
3646
+ const eligibilitySource = (acc.eligibilityStateUpdatedAt ?? 0) >= (existingAcc.eligibilityStateUpdatedAt ?? 0) ? acc : existingAcc;
3647
+ const merged = {
3387
3648
  ...existingAcc,
3388
3649
  ...acc,
3389
3650
  // Preserve manually configured projectId/managedProjectId if not in incoming
@@ -3393,8 +3654,16 @@ function mergeAccountStorage(existing, incoming) {
3393
3654
  ...existingAcc.rateLimitResetTimes,
3394
3655
  ...acc.rateLimitResetTimes
3395
3656
  },
3396
- lastUsed: Math.max(existingAcc.lastUsed || 0, acc.lastUsed || 0)
3397
- });
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);
3398
3667
  } else {
3399
3668
  accountMap.set(acc.refreshToken, acc);
3400
3669
  }
@@ -3512,9 +3781,9 @@ function migrateV3ToV4(v3) {
3512
3781
  }
3513
3782
  async function loadAccounts() {
3514
3783
  try {
3515
- const path5 = getStoragePath();
3516
- await ensureSecurePermissions(path5);
3517
- const content = await fs.readFile(path5, "utf-8");
3784
+ const path4 = getStoragePath();
3785
+ await ensureSecurePermissions(path4);
3786
+ const content = await fs.readFile(path4, "utf-8");
3518
3787
  const data = JSON.parse(content);
3519
3788
  if (!Array.isArray(data.accounts)) {
3520
3789
  log3.warn("Invalid storage format, ignoring");
@@ -3628,32 +3897,32 @@ async function atomicWriteFile(targetPath, content) {
3628
3897
  }
3629
3898
  }
3630
3899
  async function saveAccounts(storage) {
3631
- const path5 = getStoragePath();
3632
- const configDir = dirname2(path5);
3900
+ const path4 = getStoragePath();
3901
+ const configDir = dirname2(path4);
3633
3902
  await fs.mkdir(configDir, { recursive: true });
3634
3903
  await ensureGitignore(configDir);
3635
- await withFileLock(path5, async () => {
3904
+ await withFileLock(path4, async () => {
3636
3905
  const existing = await loadAccountsUnsafe();
3637
3906
  const merged = existing ? mergeAccountStorage(existing, storage) : storage;
3638
3907
  const content = JSON.stringify(merged, null, 2);
3639
- await atomicWriteFile(path5, content);
3908
+ await atomicWriteFile(path4, content);
3640
3909
  });
3641
3910
  }
3642
3911
  async function saveAccountsReplace(storage) {
3643
- const path5 = getStoragePath();
3644
- const configDir = dirname2(path5);
3912
+ const path4 = getStoragePath();
3913
+ const configDir = dirname2(path4);
3645
3914
  await fs.mkdir(configDir, { recursive: true });
3646
3915
  await ensureGitignore(configDir);
3647
- await withFileLock(path5, async () => {
3916
+ await withFileLock(path4, async () => {
3648
3917
  const content = JSON.stringify(storage, null, 2);
3649
- await atomicWriteFile(path5, content);
3918
+ await atomicWriteFile(path4, content);
3650
3919
  });
3651
3920
  }
3652
3921
  async function loadAccountsUnsafe() {
3653
3922
  try {
3654
- const path5 = getStoragePath();
3655
- await ensureSecurePermissions(path5);
3656
- const content = await fs.readFile(path5, "utf-8");
3923
+ const path4 = getStoragePath();
3924
+ await ensureSecurePermissions(path4);
3925
+ const content = await fs.readFile(path4, "utf-8");
3657
3926
  const parsed = JSON.parse(content);
3658
3927
  if (parsed.version === 1) {
3659
3928
  return migrateV3ToV4(migrateV2ToV3(migrateV1ToV2(parsed)));
@@ -3681,10 +3950,10 @@ async function loadAccountsUnsafe() {
3681
3950
  }
3682
3951
  }
3683
3952
  async function clearAccounts() {
3684
- const path5 = getStoragePath();
3953
+ const path4 = getStoragePath();
3685
3954
  try {
3686
- await withFileLock(path5, async () => {
3687
- await fs.unlink(path5);
3955
+ await withFileLock(path4, async () => {
3956
+ await fs.unlink(path4);
3688
3957
  });
3689
3958
  } catch (error) {
3690
3959
  const code = error.code;
@@ -4929,17 +5198,17 @@ function getUserConfigPath() {
4929
5198
  function getProjectConfigPath(directory) {
4930
5199
  return join5(directory, ".opencode", "antigravity.json");
4931
5200
  }
4932
- function loadConfigFile(path5) {
5201
+ function loadConfigFile(path4) {
4933
5202
  try {
4934
- if (!existsSync4(path5)) {
5203
+ if (!existsSync4(path4)) {
4935
5204
  return null;
4936
5205
  }
4937
- const content = readFileSync4(path5, "utf-8");
5206
+ const content = readFileSync4(path4, "utf-8");
4938
5207
  const rawConfig = JSON.parse(content);
4939
5208
  const result = AntigravityConfigSchema.partial().safeParse(rawConfig);
4940
5209
  if (!result.success) {
4941
5210
  log4.warn("Config validation error", {
4942
- path: path5,
5211
+ path: path4,
4943
5212
  issues: result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join(", ")
4944
5213
  });
4945
5214
  return null;
@@ -4947,9 +5216,9 @@ function loadConfigFile(path5) {
4947
5216
  return result.data;
4948
5217
  } catch (error) {
4949
5218
  if (error instanceof SyntaxError) {
4950
- log4.warn("Invalid JSON in config file", { path: path5, error: error.message });
5219
+ log4.warn("Invalid JSON in config file", { path: path4, error: error.message });
4951
5220
  } else {
4952
- log4.warn("Failed to load config file", { path: path5, error: String(error) });
5221
+ log4.warn("Failed to load config file", { path: path4, error: String(error) });
4953
5222
  }
4954
5223
  return null;
4955
5224
  }
@@ -4988,50 +5257,54 @@ function getKeepThinking() {
4988
5257
  }
4989
5258
 
4990
5259
  // src/plugin/image-saver.ts
4991
- import * as fs2 from "fs";
4992
- import * as path from "path";
4993
- import * as os from "os";
4994
- function getImageOutputDir() {
4995
- const homeDir = os.homedir();
4996
- const outputDir = path.join(homeDir, ".opencode", "generated-images");
4997
- if (!fs2.existsSync(outputDir)) {
4998
- fs2.mkdirSync(outputDir, { recursive: true });
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 });
4999
5272
  }
5000
- return outputDir;
5273
+ chmodSync(resolved, 448);
5274
+ return resolved;
5001
5275
  }
5002
5276
  function generateImageFilename(mimeType) {
5003
5277
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
5004
5278
  const random = Math.random().toString(36).substring(2, 8);
5005
- let ext = "png";
5279
+ let extension = "png";
5006
5280
  if (mimeType.includes("jpeg") || mimeType.includes("jpg")) {
5007
- ext = "jpg";
5281
+ extension = "jpg";
5008
5282
  } else if (mimeType.includes("gif")) {
5009
- ext = "gif";
5283
+ extension = "gif";
5010
5284
  } else if (mimeType.includes("webp")) {
5011
- ext = "webp";
5285
+ extension = "webp";
5012
5286
  }
5013
- return `image-${timestamp}-${random}.${ext}`;
5287
+ return `image-${timestamp}-${random}.${extension}`;
5014
5288
  }
5015
- function saveImageToDisk(base64Data, mimeType) {
5289
+ function saveImageToDisk(base64Data, mimeType, outputDir) {
5016
5290
  try {
5017
- const outputDir = getImageOutputDir();
5018
- const filename = generateImageFilename(mimeType);
5019
- const filePath = path.join(outputDir, filename);
5020
- const buffer = Buffer.from(base64Data, "base64");
5021
- 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);
5022
5295
  return filePath;
5023
5296
  } catch (error) {
5024
5297
  console.error("[image-saver] Failed to save image:", error);
5025
5298
  return "";
5026
5299
  }
5027
5300
  }
5028
- function processImageData(inlineData) {
5301
+ function processImageData(inlineData, outputDir) {
5029
5302
  const mimeType = inlineData.mimeType || "image/png";
5030
5303
  const data = inlineData.data;
5031
5304
  if (!data) {
5032
5305
  return null;
5033
5306
  }
5034
- const filePath = saveImageToDisk(data, mimeType);
5307
+ const filePath = saveImageToDisk(data, mimeType, outputDir);
5035
5308
  if (filePath) {
5036
5309
  return `![Generated Image](${filePath})
5037
5310
 
@@ -7080,14 +7353,14 @@ function applyToolPairingFixes(payload, isClaude) {
7080
7353
  }
7081
7354
  return { contentsFixed, messagesFixed };
7082
7355
  }
7083
- function createSyntheticErrorResponse(errorMessage, _requestedModel = "unknown") {
7084
- const outputTokens = Math.max(1, Math.ceil(errorMessage.length / 4));
7356
+ function createSyntheticTextResponse(text, extraHeaders = {}) {
7357
+ const outputTokens = Math.max(1, Math.ceil(text.length / 4));
7085
7358
  const event = {
7086
7359
  candidates: [
7087
7360
  {
7088
7361
  content: {
7089
7362
  role: "model",
7090
- parts: [{ text: errorMessage }]
7363
+ parts: [{ text }]
7091
7364
  },
7092
7365
  finishReason: "STOP"
7093
7366
  }
@@ -7107,10 +7380,15 @@ function createSyntheticErrorResponse(errorMessage, _requestedModel = "unknown")
7107
7380
  "Cache-Control": "no-cache",
7108
7381
  "Connection": "keep-alive",
7109
7382
  "X-Antigravity-Synthetic": "true",
7110
- "X-Antigravity-Error-Type": "synthetic_error"
7383
+ ...extraHeaders
7111
7384
  }
7112
7385
  });
7113
7386
  }
7387
+ function createSyntheticErrorResponse(errorMessage, _requestedModel = "unknown") {
7388
+ return createSyntheticTextResponse(errorMessage, {
7389
+ "X-Antigravity-Error-Type": "synthetic_error"
7390
+ });
7391
+ }
7114
7392
 
7115
7393
  // src/plugin/thinking-recovery.ts
7116
7394
  function isThinkingPart2(part) {
@@ -7849,8 +8127,8 @@ function bodyStructureSummary(bodyText) {
7849
8127
  bodyBytes: bodyText.length
7850
8128
  };
7851
8129
  }
7852
- function writeJson(path5, value) {
7853
- writeFileSync6(path5, `${JSON.stringify(value, null, 2)}
8130
+ function writeJson(path4, value) {
8131
+ writeFileSync6(path4, `${JSON.stringify(value, null, 2)}
7854
8132
  `, { encoding: "utf8", mode: DUMP_FILE_MODE });
7855
8133
  }
7856
8134
  function updateMetadata(context, patch) {
@@ -7930,26 +8208,69 @@ function createGeminiDumpResponseTransform(context) {
7930
8208
  // src/plugin/request.ts
7931
8209
  var log6 = createLogger2("request");
7932
8210
  var PLUGIN_SESSION_ID = `-${crypto2.randomUUID()}`;
8211
+ var DEFAULT_AGY_REQUEST_SESSION = createAgyRequestSessionContext("");
7933
8212
  var sessionDisplayedThinkingHashes = /* @__PURE__ */ new Set();
7934
8213
  var MIN_SIGNATURE_LENGTH = 50;
8214
+ var AGY_CLAUDE_THINKING_BUDGET = 1024;
7935
8215
  var ANTIGRAVITY_ENVELOPE_FIELD_ORDER = [
7936
8216
  "project",
7937
8217
  "requestId",
7938
8218
  "request",
7939
8219
  "model",
7940
8220
  "userAgent",
7941
- "requestType",
7942
- "enabledCreditTypes"
8221
+ "requestType"
7943
8222
  ];
7944
- function buildAntigravityRequestId(type = "agent") {
7945
- if (type === "checkpoint") {
7946
- return `checkpoint/${crypto2.randomUUID()}`;
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;
7947
8269
  }
7948
- return `agent/${crypto2.randomUUID()}/${Date.now()}/${crypto2.randomUUID()}/2`;
7949
8270
  }
7950
8271
  function getAgyMaxOutputTokens(model) {
7951
8272
  const lower = model.toLowerCase();
7952
- 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") {
7953
8274
  return 65536;
7954
8275
  }
7955
8276
  if (lower === "gemini-3.1-pro-low" || lower === "gemini-pro-agent") {
@@ -7958,6 +8279,9 @@ function getAgyMaxOutputTokens(model) {
7958
8279
  if (lower === "claude-sonnet-4-6" || lower === "claude-opus-4-6-thinking") {
7959
8280
  return 64e3;
7960
8281
  }
8282
+ if (lower === "gpt-oss-120b-medium") {
8283
+ return 32768;
8284
+ }
7961
8285
  return void 0;
7962
8286
  }
7963
8287
  function applyAgyGenerationDefaults(model, generationConfig, headerStyle) {
@@ -7994,7 +8318,7 @@ var JSON_SCHEMA_TYPES = /* @__PURE__ */ new Set(["boolean", "string", "number",
7994
8318
  function thinkingSafeReplacer(key, value) {
7995
8319
  if (key === "thinking" && typeof value === "object" && value !== null) {
7996
8320
  const rec = value;
7997
- if (typeof rec.type === "string" && JSON_SCHEMA_TYPES.has(rec.type)) {
8321
+ if (typeof rec.type === "string" && JSON_SCHEMA_TYPES.has(rec.type.toLowerCase())) {
7998
8322
  return value;
7999
8323
  }
8000
8324
  return "";
@@ -8208,6 +8532,69 @@ function isValidRequestPart(part) {
8208
8532
  const record = part;
8209
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");
8210
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
+ }
8585
+ }
8586
+ }
8587
+ function configureAntigravityToolCalling(payload) {
8588
+ if (!Array.isArray(payload.tools) || payload.tools.length === 0) {
8589
+ delete payload.toolConfig;
8590
+ return;
8591
+ }
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;
8597
+ }
8211
8598
  function sanitizeRequestPayloadForAntigravity(payload) {
8212
8599
  const anyPayload = payload;
8213
8600
  if (Array.isArray(anyPayload.contents)) {
@@ -8540,6 +8927,8 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
8540
8927
  headers.delete("x-api-key");
8541
8928
  headers.delete("x-goog-api-key");
8542
8929
  headers.delete("x-session-affinity");
8930
+ headers.delete("x-session-id");
8931
+ headers.delete("x-parent-session-id");
8543
8932
  headers.delete("x-goog-user-project");
8544
8933
  const urlString = fetchInputToUrl(input2);
8545
8934
  const match = urlString.match(/\/models\/([^:]+):(\w+)/);
@@ -8581,9 +8970,6 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
8581
8970
  model: effectiveModel
8582
8971
  };
8583
8972
  if (headerStyle === "antigravity") {
8584
- if (typeof wrappedBody.requestId !== "string" || !wrappedBody.requestId) {
8585
- wrappedBody.requestId = buildAntigravityRequestId("agent");
8586
- }
8587
8973
  if (typeof wrappedBody.userAgent !== "string" || !wrappedBody.userAgent) {
8588
8974
  wrappedBody.userAgent = "antigravity";
8589
8975
  }
@@ -8607,7 +8993,6 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
8607
8993
  sessionId = signatureSessionKey;
8608
8994
  }
8609
8995
  for (const req of requestObjects) {
8610
- req.sessionId = signatureSessionKey;
8611
8996
  stripInjectedDebugFromRequestPayload(req);
8612
8997
  if (isClaude) {
8613
8998
  sanitizeCrossModelPayloadInPlace(req, { targetModel: effectiveModel });
@@ -8620,6 +9005,11 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
8620
9005
  }
8621
9006
  applyToolPairingFixes(req, true);
8622
9007
  }
9008
+ if (headerStyle === "antigravity") {
9009
+ sanitizeRequestPayloadForAntigravity(req);
9010
+ stripUnsupportedAntigravityFields(req);
9011
+ configureAntigravityToolCalling(req);
9012
+ }
8623
9013
  }
8624
9014
  if (isClaude) {
8625
9015
  for (const req of requestObjects) {
@@ -8649,9 +9039,31 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
8649
9039
  const hasCachedThinking = defaultSignatureStore.has(signatureSessionKey);
8650
9040
  needsSignedThinkingWarmup = hasToolUse && !hasSignedThinking && !hasCachedThinking;
8651
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
+ }
8652
9059
  body = safeStringify(headerStyle === "antigravity" ? orderAntigravityEnvelope(wrappedBody) : wrappedBody);
8653
9060
  } else {
8654
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
+ }
8655
9067
  const rawGenerationConfig = requestPayload.generationConfig;
8656
9068
  const extraBody = requestPayload.extra_body;
8657
9069
  const variantConfig = extractVariantThinkingConfig(
@@ -8660,6 +9072,7 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
8660
9072
  );
8661
9073
  const isGemini3 = effectiveModel.toLowerCase().includes("gemini-3");
8662
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;
8663
9076
  if (variantConfig?.thinkingLevel && isGemini3) {
8664
9077
  const variantModelBase = rawModel.replace(/-preview-customtools$/i, "").replace(/-preview$/i, "").replace(/-(minimal|low|medium|high)$/i, "");
8665
9078
  const variantResolved = resolveModelForHeaderStyle(
@@ -8679,20 +9092,6 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
8679
9092
  tierThinkingLevel = void 0;
8680
9093
  }
8681
9094
  }
8682
- if (isClaude) {
8683
- if (!requestPayload.toolConfig) {
8684
- requestPayload.toolConfig = {};
8685
- }
8686
- if (typeof requestPayload.toolConfig === "object" && requestPayload.toolConfig !== null) {
8687
- const toolConfig = requestPayload.toolConfig;
8688
- if (!toolConfig.functionCallingConfig) {
8689
- toolConfig.functionCallingConfig = {};
8690
- }
8691
- if (typeof toolConfig.functionCallingConfig === "object" && toolConfig.functionCallingConfig !== null) {
8692
- toolConfig.functionCallingConfig.mode = "VALIDATED";
8693
- }
8694
- }
8695
- }
8696
9095
  const isImageModel = isImageGenerationModel(effectiveModel);
8697
9096
  const userThinkingConfig = isImageModel ? void 0 : extractThinkingConfig(requestPayload, rawGenerationConfig, extraBody);
8698
9097
  const hasAssistantHistory = Array.isArray(requestPayload.contents) && requestPayload.contents.some((c) => c?.role === "model" || c?.role === "assistant");
@@ -8789,17 +9188,19 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
8789
9188
  requestPayload.systemInstruction = requestPayload.system_instruction;
8790
9189
  delete requestPayload.system_instruction;
8791
9190
  }
8792
- const cachedContentFromExtra = typeof requestPayload.extra_body === "object" && requestPayload.extra_body ? requestPayload.extra_body.cached_content ?? requestPayload.extra_body.cachedContent : void 0;
8793
- const cachedContent = requestPayload.cached_content ?? requestPayload.cachedContent ?? cachedContentFromExtra;
8794
- if (cachedContent) {
8795
- requestPayload.cachedContent = cachedContent;
8796
- }
8797
- delete requestPayload.cached_content;
8798
- if (requestPayload.extra_body && typeof requestPayload.extra_body === "object") {
8799
- delete requestPayload.extra_body.cached_content;
8800
- delete requestPayload.extra_body.cachedContent;
8801
- if (Object.keys(requestPayload.extra_body).length === 0) {
8802
- delete requestPayload.extra_body;
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
+ }
8803
9204
  }
8804
9205
  }
8805
9206
  const hasTools = Array.isArray(requestPayload.tools) && requestPayload.tools.length > 0;
@@ -8995,11 +9396,27 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
8995
9396
  }
8996
9397
  stripInjectedDebugFromRequestPayload(requestPayload);
8997
9398
  sanitizeRequestPayloadForAntigravity(requestPayload);
9399
+ if (headerStyle === "antigravity") {
9400
+ stripUnsupportedAntigravityFields(requestPayload);
9401
+ configureAntigravityToolCalling(requestPayload);
9402
+ }
8998
9403
  const effectiveProjectId = projectId?.trim() || (headerStyle === "antigravity" ? ANTIGRAVITY_DEFAULT_PROJECT_ID : "");
8999
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
+ }
9000
9417
  const wrappedBody = headerStyle === "antigravity" ? {
9001
9418
  project: effectiveProjectId,
9002
- requestId: buildAntigravityRequestId("agent"),
9419
+ requestId: agyMetadata.requestId,
9003
9420
  request: requestPayload,
9004
9421
  model: effectiveModel,
9005
9422
  userAgent: "antigravity",
@@ -9009,10 +9426,6 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
9009
9426
  model: effectiveModel,
9010
9427
  request: requestPayload
9011
9428
  };
9012
- if (wrappedBody.request && typeof wrappedBody.request === "object") {
9013
- sessionId = signatureSessionKey;
9014
- wrappedBody.request.sessionId = signatureSessionKey;
9015
- }
9016
9429
  body = safeStringify(headerStyle === "antigravity" ? orderAntigravityEnvelope(wrappedBody) : wrappedBody);
9017
9430
  }
9018
9431
  } catch {
@@ -9074,17 +9487,20 @@ function buildThinkingWarmupBody(bodyText, isClaudeThinking) {
9074
9487
  return null;
9075
9488
  }
9076
9489
  const warmupPrompt = "Warmup request for thinking signature.";
9490
+ const wireModel = typeof parsed.model === "string" ? parsed.model : "claude-sonnet-4-6";
9491
+ const requestObjects = [];
9077
9492
  const updateRequest = (req) => {
9078
9493
  req.contents = [{ role: "user", parts: [{ text: warmupPrompt }] }];
9079
9494
  delete req.tools;
9080
9495
  delete req.toolConfig;
9081
9496
  const generationConfig = req.generationConfig ?? {};
9082
9497
  generationConfig.thinkingConfig = {
9083
- include_thoughts: true,
9084
- thinking_budget: DEFAULT_THINKING_BUDGET
9498
+ includeThoughts: true,
9499
+ thinkingBudget: AGY_CLAUDE_THINKING_BUDGET
9085
9500
  };
9086
- generationConfig.maxOutputTokens = computeClaudeMaxOutputTokens(DEFAULT_THINKING_BUDGET);
9501
+ generationConfig.maxOutputTokens = getAgyMaxOutputTokens(wireModel) ?? computeClaudeMaxOutputTokens(AGY_CLAUDE_THINKING_BUDGET);
9087
9502
  req.generationConfig = generationConfig;
9503
+ requestObjects.push(req);
9088
9504
  };
9089
9505
  if (parsed.request && typeof parsed.request === "object") {
9090
9506
  updateRequest(parsed.request);
@@ -9095,6 +9511,20 @@ function buildThinkingWarmupBody(bodyText, isClaudeThinking) {
9095
9511
  } else {
9096
9512
  updateRequest(parsed);
9097
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
+ }
9098
9528
  return safeStringify(parsed);
9099
9529
  }
9100
9530
  async function transformAntigravityResponse(response, streaming, debugContext, requestedModel, projectId, endpoint, effectiveModel, sessionId, toolDebugMissing, toolDebugSummary, toolDebugPayload, debugLines, dumpContext) {
@@ -9467,12 +9897,12 @@ async function startOAuthListener({ timeoutMs = 5 * 60 * 1e3 } = {}) {
9467
9897
  let resolveCallback;
9468
9898
  let rejectCallback;
9469
9899
  let timeoutHandle;
9470
- const callbackPromise = new Promise((resolve, reject) => {
9900
+ const callbackPromise = new Promise((resolve2, reject) => {
9471
9901
  resolveCallback = (url) => {
9472
9902
  if (settled) return;
9473
9903
  settled = true;
9474
9904
  if (timeoutHandle) clearTimeout(timeoutHandle);
9475
- resolve(url);
9905
+ resolve2(url);
9476
9906
  };
9477
9907
  rejectCallback = (error) => {
9478
9908
  if (settled) return;
@@ -9630,7 +10060,7 @@ async function startOAuthListener({ timeoutMs = 5 * 60 * 1e3 } = {}) {
9630
10060
  });
9631
10061
  });
9632
10062
  const bindAddress = getBindAddress();
9633
- await new Promise((resolve, reject) => {
10063
+ await new Promise((resolve2, reject) => {
9634
10064
  const handleError = (error) => {
9635
10065
  server.off("error", handleError);
9636
10066
  if (error.code === "EADDRINUSE") {
@@ -9644,7 +10074,7 @@ async function startOAuthListener({ timeoutMs = 5 * 60 * 1e3 } = {}) {
9644
10074
  server.once("error", handleError);
9645
10075
  server.listen(port, bindAddress, () => {
9646
10076
  server.off("error", handleError);
9647
- resolve();
10077
+ resolve2();
9648
10078
  });
9649
10079
  });
9650
10080
  server.on("error", (error) => {
@@ -9652,7 +10082,7 @@ async function startOAuthListener({ timeoutMs = 5 * 60 * 1e3 } = {}) {
9652
10082
  });
9653
10083
  return {
9654
10084
  waitForCallback: () => callbackPromise,
9655
- close: () => new Promise((resolve, reject) => {
10085
+ close: () => new Promise((resolve2, reject) => {
9656
10086
  server.close((error) => {
9657
10087
  if (error && error.code !== "ERR_SERVER_NOT_RUNNING") {
9658
10088
  reject(error);
@@ -9661,7 +10091,7 @@ async function startOAuthListener({ timeoutMs = 5 * 60 * 1e3 } = {}) {
9661
10091
  if (!settled) {
9662
10092
  rejectCallback(new Error("OAuth listener closed before callback"));
9663
10093
  }
9664
- resolve();
10094
+ resolve2();
9665
10095
  });
9666
10096
  })
9667
10097
  };
@@ -10055,6 +10485,8 @@ function computeSoftQuotaCacheTtlMs(ttlConfig, refreshIntervalMinutes) {
10055
10485
  }
10056
10486
  return ttlConfig * 60 * 1e3;
10057
10487
  }
10488
+ var ACCOUNT_SESSION_STATE_TTL_MS = 24 * 60 * 60 * 1e3;
10489
+ var MAX_ACCOUNT_SESSION_STATES = 256;
10058
10490
  var AccountManager = class _AccountManager {
10059
10491
  accounts = [];
10060
10492
  cursorByFamily = { claude: 0, gemini: 0 };
@@ -10074,6 +10506,7 @@ var AccountManager = class _AccountManager {
10074
10506
  sessionStartTime = Date.now();
10075
10507
  sessionRequestCounts = /* @__PURE__ */ new Map();
10076
10508
  sessionUsedAccounts = /* @__PURE__ */ new Set();
10509
+ requestSessionStates = /* @__PURE__ */ new Map();
10077
10510
  static async loadFromDisk(authFallback) {
10078
10511
  const stored = await loadAccounts();
10079
10512
  return new _AccountManager(authFallback, stored);
@@ -10118,7 +10551,11 @@ var AccountManager = class _AccountManager {
10118
10551
  verificationRequired: acc.verificationRequired,
10119
10552
  verificationRequiredAt: acc.verificationRequiredAt,
10120
10553
  verificationRequiredReason: acc.verificationRequiredReason,
10121
- verificationUrl: acc.verificationUrl
10554
+ verificationUrl: acc.verificationUrl,
10555
+ accountIneligible: acc.accountIneligible,
10556
+ accountIneligibleAt: acc.accountIneligibleAt,
10557
+ accountIneligibleReason: acc.accountIneligibleReason,
10558
+ eligibilityStateUpdatedAt: acc.eligibilityStateUpdatedAt
10122
10559
  };
10123
10560
  }).filter((a) => a !== null);
10124
10561
  let fingerprintVersionChanged = false;
@@ -10200,11 +10637,104 @@ var AccountManager = class _AccountManager {
10200
10637
  getEnabledAccounts() {
10201
10638
  return this.accounts.filter((account) => account.enabled !== false);
10202
10639
  }
10640
+ getEffectiveSoftQuotaThreshold(thresholdPercent) {
10641
+ return this.getEnabledAccounts().length > 1 ? thresholdPercent : 100;
10642
+ }
10203
10643
  getAccountsSnapshot() {
10204
10644
  return this.accounts.map((a) => ({ ...a, parts: { ...a.parts }, rateLimitResetTimes: { ...a.rateLimitResetTimes } }));
10205
10645
  }
10206
- getCurrentAccountForFamily(family) {
10207
- const currentIndex = this.currentAccountIndexByFamily[family];
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);
10208
10738
  if (currentIndex >= 0 && currentIndex < this.accounts.length) {
10209
10739
  const account = this.accounts[currentIndex] ?? null;
10210
10740
  if (account && account.enabled !== false) {
@@ -10213,9 +10743,9 @@ var AccountManager = class _AccountManager {
10213
10743
  }
10214
10744
  return null;
10215
10745
  }
10216
- markSwitched(account, reason, family) {
10746
+ markSwitched(account, reason, family, identity) {
10217
10747
  account.lastSwitchReason = reason;
10218
- this.currentAccountIndexByFamily[family] = account.index;
10748
+ this.setActiveIndex(family, account.index, identity);
10219
10749
  }
10220
10750
  /**
10221
10751
  * Check if we should show an account switch toast.
@@ -10232,82 +10762,111 @@ var AccountManager = class _AccountManager {
10232
10762
  this.lastToastAccountIndex = accountIndex;
10233
10763
  this.lastToastTime = nowMs();
10234
10764
  }
10235
- 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) {
10236
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
+ }
10237
10779
  if (strategy === "round-robin") {
10238
- const next2 = this.getNextForFamily(family, model, headerStyle, softQuotaThresholdPercent, softQuotaCacheTtlMs);
10780
+ const next2 = this.getNextForFamily(family, model, headerStyle, effectiveSoftQuotaThreshold, softQuotaCacheTtlMs, identity);
10239
10781
  if (next2) {
10240
10782
  this.markTouchedForQuota(next2, quotaKey);
10241
- this.currentAccountIndexByFamily[family] = next2.index;
10783
+ this.setActiveIndex(family, next2.index, identity);
10242
10784
  }
10243
10785
  return next2;
10244
10786
  }
10245
10787
  if (strategy === "hybrid") {
10246
10788
  const healthTracker = getHealthTracker();
10247
10789
  const tokenTracker = getTokenTracker();
10248
- const accountsWithMetrics = this.accounts.filter((acc) => acc.enabled !== false).map((acc) => {
10790
+ const eligibleAccounts = this.preferAccountOutsideParent(
10791
+ this.accounts.filter((acc) => acc.enabled !== false),
10792
+ family,
10793
+ identity
10794
+ );
10795
+ const accountsWithMetrics = eligibleAccounts.map((acc) => {
10249
10796
  clearExpiredRateLimits(acc);
10250
10797
  return {
10251
10798
  index: acc.index,
10252
10799
  lastUsed: acc.lastUsed,
10253
10800
  healthScore: healthTracker.getScore(acc.index),
10254
- isRateLimited: isRateLimitedForFamily(acc, family, model) || isOverSoftQuotaThreshold(acc, family, softQuotaThresholdPercent, softQuotaCacheTtlMs, model),
10801
+ isRateLimited: isRateLimitedForFamily(acc, family, model) || isOverSoftQuotaThreshold(acc, family, effectiveSoftQuotaThreshold, softQuotaCacheTtlMs, model),
10255
10802
  isCoolingDown: this.isAccountCoolingDown(acc)
10256
10803
  };
10257
10804
  });
10258
- const currentIndex = this.currentAccountIndexByFamily[family] ?? null;
10805
+ const currentIndex = this.getActiveIndex(family, identity);
10259
10806
  const selectedIndex = selectHybridAccount(accountsWithMetrics, tokenTracker, currentIndex);
10260
10807
  if (selectedIndex !== null) {
10261
10808
  const selected = this.accounts[selectedIndex];
10262
10809
  if (selected) {
10263
10810
  selected.lastUsed = nowMs();
10264
10811
  this.markTouchedForQuota(selected, quotaKey);
10265
- this.currentAccountIndexByFamily[family] = selected.index;
10812
+ this.setActiveIndex(family, selected.index, identity);
10266
10813
  return selected;
10267
10814
  }
10268
10815
  }
10269
10816
  }
10270
- if (pidOffsetEnabled && !this.sessionOffsetApplied[family] && this.accounts.length > 1) {
10817
+ const offsetApplied = identity ? this.getRequestSessionState(identity).offsetAppliedByFamily : this.sessionOffsetApplied;
10818
+ if (pidOffsetEnabled && !offsetApplied[family] && this.accounts.length > 1) {
10271
10819
  const pidOffset = process.pid % this.accounts.length;
10272
- const baseIndex = this.currentAccountIndexByFamily[family] ?? 0;
10820
+ const activeIndex = this.getActiveIndex(family, identity);
10821
+ const baseIndex = activeIndex >= 0 ? activeIndex : this.getCursor(family, identity);
10273
10822
  const newIndex = (baseIndex + pidOffset) % this.accounts.length;
10274
10823
  debugLogToFile(`[Account] Applying PID offset: pid=${process.pid} offset=${pidOffset} family=${family} index=${baseIndex}->${newIndex}`);
10275
- this.currentAccountIndexByFamily[family] = newIndex;
10276
- this.sessionOffsetApplied[family] = true;
10824
+ this.setActiveIndex(family, newIndex, identity);
10825
+ offsetApplied[family] = true;
10277
10826
  }
10278
- const current = this.getCurrentAccountForFamily(family);
10827
+ const current = this.getCurrentAccountForFamily(family, identity);
10279
10828
  if (current) {
10280
10829
  clearExpiredRateLimits(current);
10281
10830
  const isLimitedForRequestedStyle = isRateLimitedForHeaderStyle(current, family, headerStyle, model);
10282
- const isOverThreshold = isOverSoftQuotaThreshold(current, family, softQuotaThresholdPercent, softQuotaCacheTtlMs, model);
10831
+ const isOverThreshold = isOverSoftQuotaThreshold(current, family, effectiveSoftQuotaThreshold, softQuotaCacheTtlMs, model);
10283
10832
  if (!isLimitedForRequestedStyle && !isOverThreshold && !this.isAccountCoolingDown(current)) {
10284
10833
  this.markTouchedForQuota(current, quotaKey);
10285
10834
  return current;
10286
10835
  }
10287
10836
  }
10288
- const next = this.getNextForFamily(family, model, headerStyle, softQuotaThresholdPercent, softQuotaCacheTtlMs);
10837
+ const next = this.getNextForFamily(
10838
+ family,
10839
+ model,
10840
+ headerStyle,
10841
+ effectiveSoftQuotaThreshold,
10842
+ softQuotaCacheTtlMs,
10843
+ identity
10844
+ );
10289
10845
  if (next) {
10290
10846
  this.markTouchedForQuota(next, quotaKey);
10291
- this.currentAccountIndexByFamily[family] = next.index;
10847
+ this.setActiveIndex(family, next.index, identity);
10292
10848
  }
10293
10849
  return next;
10294
10850
  }
10295
- getNextForFamily(family, model, headerStyle = "antigravity", softQuotaThresholdPercent = 100, softQuotaCacheTtlMs = 10 * 60 * 1e3) {
10296
- const available = this.accounts.filter((a) => {
10297
- clearExpiredRateLimits(a);
10298
- return a.enabled !== false && !isRateLimitedForHeaderStyle(a, family, headerStyle, model) && !isOverSoftQuotaThreshold(a, family, softQuotaThresholdPercent, softQuotaCacheTtlMs, model) && !this.isAccountCoolingDown(a);
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);
10299
10856
  });
10857
+ const available = this.preferAccountOutsideParent(allAvailable, family, identity);
10300
10858
  if (available.length === 0) {
10301
10859
  return null;
10302
10860
  }
10303
- const sessionUsed = available.filter((a) => this.sessionUsedAccounts.has(a.index));
10861
+ const usedAccounts = this.getUsedAccounts(identity);
10862
+ const sessionUsed = available.filter((account2) => usedAccounts.has(account2.index));
10304
10863
  const candidates = sessionUsed.length > 0 ? sessionUsed : available;
10305
- const cursor = this.cursorByFamily[family];
10864
+ const cursor = this.getCursor(family, identity);
10306
10865
  const account = candidates[cursor % candidates.length];
10307
10866
  if (!account) {
10308
10867
  return null;
10309
10868
  }
10310
- this.cursorByFamily[family] = cursor + 1;
10869
+ this.advanceCursor(family, identity);
10311
10870
  return account;
10312
10871
  }
10313
10872
  markRateLimited(account, retryAfterMs, family, headerStyle = "antigravity", model) {
@@ -10325,15 +10884,15 @@ var AccountManager = class _AccountManager {
10325
10884
  account.lastUsed = nowMs();
10326
10885
  }
10327
10886
  }
10328
- recordSessionUsage(accountIndex) {
10329
- this.sessionUsedAccounts.add(accountIndex);
10887
+ recordSessionUsage(accountIndex, identity) {
10888
+ this.getUsedAccounts(identity).add(accountIndex);
10330
10889
  }
10331
- wasUsedInSession(accountIndex) {
10332
- return this.sessionUsedAccounts.has(accountIndex);
10890
+ wasUsedInSession(accountIndex, identity) {
10891
+ return this.getUsedAccounts(identity).has(accountIndex);
10333
10892
  }
10334
- shouldProactivelyRotate(family, model, thresholdPercent, cacheTtlMs) {
10893
+ shouldProactivelyRotate(family, model, thresholdPercent, cacheTtlMs, identity) {
10335
10894
  if (thresholdPercent <= 0) return false;
10336
- const current = this.getCurrentAccountForFamily(family);
10895
+ const current = this.getCurrentAccountForFamily(family, identity);
10337
10896
  if (!current || !current.cachedQuota || current.cachedQuotaUpdatedAt == null) return false;
10338
10897
  const age = nowMs() - current.cachedQuotaUpdatedAt;
10339
10898
  if (age > cacheTtlMs) return false;
@@ -10343,9 +10902,9 @@ var AccountManager = class _AccountManager {
10343
10902
  const remainingPercent = Math.max(0, Math.min(100, groupData.remainingFraction * 100));
10344
10903
  return remainingPercent < thresholdPercent;
10345
10904
  }
10346
- proactivelyRotateForFamily(family, model, headerStyle, softQuotaThresholdPercent, softQuotaCacheTtlMs) {
10347
- const currentIndex = this.currentAccountIndexByFamily[family];
10348
- 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) => {
10349
10908
  if (acc.enabled === false) return false;
10350
10909
  if (acc.index === currentIndex) return false;
10351
10910
  clearExpiredRateLimits(acc);
@@ -10353,9 +10912,10 @@ var AccountManager = class _AccountManager {
10353
10912
  if (isOverSoftQuotaThreshold(acc, family, softQuotaThresholdPercent, softQuotaCacheTtlMs, model)) return false;
10354
10913
  if (this.isAccountCoolingDown(acc)) return false;
10355
10914
  return true;
10356
- });
10915
+ }), family, identity);
10357
10916
  if (candidates.length === 0) return null;
10358
- const warmCandidates = candidates.filter((a) => this.sessionUsedAccounts.has(a.index));
10917
+ const usedAccounts = this.getUsedAccounts(identity);
10918
+ const warmCandidates = candidates.filter((account) => usedAccounts.has(account.index));
10359
10919
  const pool = warmCandidates.length > 0 ? warmCandidates : candidates;
10360
10920
  const quotaGroup = resolveQuotaGroup(family, model);
10361
10921
  pool.sort((a, b) => {
@@ -10367,7 +10927,7 @@ var AccountManager = class _AccountManager {
10367
10927
  if (!selected) return null;
10368
10928
  const quotaKey = getQuotaKey(family, headerStyle, model);
10369
10929
  this.markTouchedForQuota(selected, quotaKey);
10370
- this.currentAccountIndexByFamily[family] = selected.index;
10930
+ this.setActiveIndex(family, selected.index, identity);
10371
10931
  return selected;
10372
10932
  }
10373
10933
  markRateLimitedWithReason(account, family, headerStyle, model, reason, retryAfterMs, failureTtlMs = 36e5) {
@@ -10493,6 +11053,9 @@ var AccountManager = class _AccountManager {
10493
11053
  if (!account) {
10494
11054
  return false;
10495
11055
  }
11056
+ if (enabled && account.accountIneligible) {
11057
+ return false;
11058
+ }
10496
11059
  account.enabled = enabled;
10497
11060
  if (!enabled) {
10498
11061
  for (const family of Object.keys(this.currentAccountIndexByFamily)) {
@@ -10510,9 +11073,16 @@ var AccountManager = class _AccountManager {
10510
11073
  if (!account) {
10511
11074
  return false;
10512
11075
  }
11076
+ const timestamp = nowMs();
10513
11077
  account.verificationRequired = true;
10514
- account.verificationRequiredAt = nowMs();
11078
+ account.verificationRequiredAt = timestamp;
10515
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
+ }
10516
11086
  const normalizedVerifyUrl = verifyUrl?.trim();
10517
11087
  if (normalizedVerifyUrl) {
10518
11088
  account.verificationUrl = normalizedVerifyUrl;
@@ -10524,20 +11094,48 @@ var AccountManager = class _AccountManager {
10524
11094
  }
10525
11095
  return true;
10526
11096
  }
10527
- clearAccountVerificationRequired(accountIndex, enableAccount = false) {
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) {
10528
11119
  const account = this.accounts[accountIndex];
10529
11120
  if (!account) {
10530
11121
  return false;
10531
11122
  }
10532
11123
  const wasVerificationRequired = account.verificationRequired === true;
10533
- const hadMetadata = account.verificationRequiredAt !== void 0 || account.verificationRequiredReason !== void 0 || account.verificationUrl !== void 0;
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;
10534
11126
  account.verificationRequired = false;
10535
11127
  account.verificationRequiredAt = void 0;
10536
11128
  account.verificationRequiredReason = void 0;
10537
11129
  account.verificationUrl = void 0;
10538
- if (enableAccount && wasVerificationRequired && account.enabled === false) {
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) {
10539
11137
  this.setAccountEnabled(accountIndex, true);
10540
- } else if (wasVerificationRequired || hadMetadata) {
11138
+ } else if (hadMetadata) {
10541
11139
  this.requestSaveToDisk();
10542
11140
  }
10543
11141
  return true;
@@ -10565,6 +11163,7 @@ var AccountManager = class _AccountManager {
10565
11163
  this.cursorByFamily = { claude: 0, gemini: 0 };
10566
11164
  this.currentAccountIndexByFamily.claude = -1;
10567
11165
  this.currentAccountIndexByFamily.gemini = -1;
11166
+ this.requestSessionStates.clear();
10568
11167
  return true;
10569
11168
  }
10570
11169
  for (const family of ["claude", "gemini"]) {
@@ -10578,6 +11177,23 @@ var AccountManager = class _AccountManager {
10578
11177
  if (this.currentAccountIndexByFamily[family] >= this.accounts.length) {
10579
11178
  this.currentAccountIndexByFamily[family] = -1;
10580
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
+ );
10581
11197
  }
10582
11198
  return true;
10583
11199
  }
@@ -10655,7 +11271,11 @@ var AccountManager = class _AccountManager {
10655
11271
  verificationRequired: a.verificationRequired,
10656
11272
  verificationRequiredAt: a.verificationRequiredAt,
10657
11273
  verificationRequiredReason: a.verificationRequiredReason,
10658
- verificationUrl: a.verificationUrl
11274
+ verificationUrl: a.verificationUrl,
11275
+ accountIneligible: a.accountIneligible,
11276
+ accountIneligibleAt: a.accountIneligibleAt,
11277
+ accountIneligibleReason: a.accountIneligibleReason,
11278
+ eligibilityStateUpdatedAt: a.eligibilityStateUpdatedAt
10659
11279
  })),
10660
11280
  activeIndex: claudeIndex,
10661
11281
  activeIndexByFamily: {
@@ -10688,8 +11308,8 @@ var AccountManager = class _AccountManager {
10688
11308
  if (!this.savePending) {
10689
11309
  return;
10690
11310
  }
10691
- return new Promise((resolve, reject) => {
10692
- this.savePromiseResolvers.push({ resolve, reject });
11311
+ return new Promise((resolve2, reject) => {
11312
+ this.savePromiseResolvers.push({ resolve: resolve2, reject });
10693
11313
  });
10694
11314
  }
10695
11315
  async executeSave() {
@@ -10699,14 +11319,14 @@ var AccountManager = class _AccountManager {
10699
11319
  this.savePromiseResolvers = [];
10700
11320
  try {
10701
11321
  await this.saveToDisk();
10702
- for (const { resolve } of resolvers) {
10703
- resolve();
11322
+ for (const { resolve: resolve2 } of resolvers) {
11323
+ resolve2();
10704
11324
  }
10705
11325
  } catch (error) {
10706
11326
  if (isStorageLockContention(error)) {
10707
11327
  debugLogToFile(`[Account] Skipped account-state persist because another plugin instance holds the storage lock: ${String(error)}`);
10708
- for (const { resolve } of resolvers) {
10709
- resolve();
11328
+ for (const { resolve: resolve2 } of resolvers) {
11329
+ resolve2();
10710
11330
  }
10711
11331
  return;
10712
11332
  }
@@ -10884,7 +11504,13 @@ var AccountManager = class _AccountManager {
10884
11504
  };
10885
11505
  }
10886
11506
  isAccountOverSoftQuota(account, family, thresholdPercent, cacheTtlMs, model) {
10887
- return isOverSoftQuotaThreshold(account, family, thresholdPercent, cacheTtlMs, model);
11507
+ return isOverSoftQuotaThreshold(
11508
+ account,
11509
+ family,
11510
+ this.getEffectiveSoftQuotaThreshold(thresholdPercent),
11511
+ cacheTtlMs,
11512
+ model
11513
+ );
10888
11514
  }
10889
11515
  getAccountsForQuotaCheck() {
10890
11516
  return this.accounts.map((a) => ({
@@ -10910,7 +11536,7 @@ var AccountManager = class _AccountManager {
10910
11536
  areAllAccountsOverSoftQuota(family, thresholdPercent, cacheTtlMs, model) {
10911
11537
  if (thresholdPercent >= 100) return false;
10912
11538
  const enabled = this.accounts.filter((a) => a.enabled !== false);
10913
- if (enabled.length === 0) return false;
11539
+ if (enabled.length <= 1) return false;
10914
11540
  return enabled.every((a) => isOverSoftQuotaThreshold(a, family, thresholdPercent, cacheTtlMs, model));
10915
11541
  }
10916
11542
  /**
@@ -10923,6 +11549,7 @@ var AccountManager = class _AccountManager {
10923
11549
  if (thresholdPercent >= 100) return 0;
10924
11550
  const enabled = this.accounts.filter((a) => a.enabled !== false);
10925
11551
  if (enabled.length === 0) return null;
11552
+ if (enabled.length === 1) return 0;
10926
11553
  const available = enabled.filter((a) => !isOverSoftQuotaThreshold(a, family, thresholdPercent, cacheTtlMs, model));
10927
11554
  if (available.length > 0) return 0;
10928
11555
  if (!model && family !== "claude") return null;
@@ -10945,24 +11572,24 @@ var AccountManager = class _AccountManager {
10945
11572
  };
10946
11573
 
10947
11574
  // src/hooks/auto-update-checker/checker.ts
10948
- import * as fs3 from "node:fs";
10949
- import * as path3 from "node:path";
11575
+ import * as fs2 from "node:fs";
11576
+ import * as path2 from "node:path";
10950
11577
  import { fileURLToPath } from "node:url";
10951
11578
 
10952
11579
  // src/hooks/auto-update-checker/constants.ts
10953
- import * as path2 from "node:path";
10954
- import * as os2 from "node:os";
11580
+ import * as path from "node:path";
11581
+ import * as os from "node:os";
10955
11582
  var PACKAGE_NAME = "@cortexkit/opencode-antigravity-auth";
10956
11583
  var NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME}/dist-tags`;
10957
11584
  var NPM_FETCH_TIMEOUT = 5e3;
10958
11585
  function getCacheDir() {
10959
11586
  if (process.platform === "win32") {
10960
- return path2.join(process.env.LOCALAPPDATA ?? os2.homedir(), "opencode");
11587
+ return path.join(process.env.LOCALAPPDATA ?? os.homedir(), "opencode");
10961
11588
  }
10962
- return path2.join(os2.homedir(), ".cache", "opencode");
11589
+ return path.join(os.homedir(), ".cache", "opencode");
10963
11590
  }
10964
11591
  var CACHE_DIR = getCacheDir();
10965
- var INSTALLED_PACKAGE_JSON = path2.join(
11592
+ var INSTALLED_PACKAGE_JSON = path.join(
10966
11593
  CACHE_DIR,
10967
11594
  "node_modules",
10968
11595
  PACKAGE_NAME,
@@ -10970,13 +11597,13 @@ var INSTALLED_PACKAGE_JSON = path2.join(
10970
11597
  );
10971
11598
  function getUserConfigDir() {
10972
11599
  if (process.platform === "win32") {
10973
- return process.env.APPDATA ?? path2.join(os2.homedir(), "AppData", "Roaming");
11600
+ return process.env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming");
10974
11601
  }
10975
- return process.env.XDG_CONFIG_HOME ?? path2.join(os2.homedir(), ".config");
11602
+ return process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), ".config");
10976
11603
  }
10977
11604
  var USER_CONFIG_DIR = getUserConfigDir();
10978
- var USER_OPENCODE_CONFIG = path2.join(USER_CONFIG_DIR, "opencode", "opencode.json");
10979
- var USER_OPENCODE_CONFIG_JSONC = path2.join(USER_CONFIG_DIR, "opencode", "opencode.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");
10980
11607
 
10981
11608
  // src/hooks/auto-update-checker/logging.ts
10982
11609
  var AUTO_UPDATE_LOG_PREFIX = "[auto-update-checker]";
@@ -10993,9 +11620,9 @@ function stripJsonComments(json) {
10993
11620
  }
10994
11621
  function getConfigPaths(directory) {
10995
11622
  return [
10996
- path3.join(directory, ".opencode", "opencode.json"),
10997
- path3.join(directory, ".opencode", "opencode.jsonc"),
10998
- path3.join(directory, ".opencode.json"),
11623
+ path2.join(directory, ".opencode", "opencode.json"),
11624
+ path2.join(directory, ".opencode", "opencode.jsonc"),
11625
+ path2.join(directory, ".opencode.json"),
10999
11626
  USER_OPENCODE_CONFIG,
11000
11627
  USER_OPENCODE_CONFIG_JSONC
11001
11628
  ];
@@ -11003,8 +11630,8 @@ function getConfigPaths(directory) {
11003
11630
  function getLocalDevPath(directory) {
11004
11631
  for (const configPath of getConfigPaths(directory)) {
11005
11632
  try {
11006
- if (!fs3.existsSync(configPath)) continue;
11007
- const content = fs3.readFileSync(configPath, "utf-8");
11633
+ if (!fs2.existsSync(configPath)) continue;
11634
+ const content = fs2.readFileSync(configPath, "utf-8");
11008
11635
  const config = JSON.parse(stripJsonComments(content));
11009
11636
  const plugins = config.plugin ?? [];
11010
11637
  for (const entry of plugins) {
@@ -11024,20 +11651,20 @@ function getLocalDevPath(directory) {
11024
11651
  }
11025
11652
  function findPackageJsonUp(startPath) {
11026
11653
  try {
11027
- const stat = fs3.statSync(startPath);
11028
- let dir = stat.isDirectory() ? startPath : path3.dirname(startPath);
11654
+ const stat = fs2.statSync(startPath);
11655
+ let dir = stat.isDirectory() ? startPath : path2.dirname(startPath);
11029
11656
  for (let i = 0; i < 10; i++) {
11030
- const pkgPath = path3.join(dir, "package.json");
11031
- if (fs3.existsSync(pkgPath)) {
11657
+ const pkgPath = path2.join(dir, "package.json");
11658
+ if (fs2.existsSync(pkgPath)) {
11032
11659
  try {
11033
- const content = fs3.readFileSync(pkgPath, "utf-8");
11660
+ const content = fs2.readFileSync(pkgPath, "utf-8");
11034
11661
  const pkg = JSON.parse(content);
11035
11662
  if (pkg.name === PACKAGE_NAME) return pkgPath;
11036
11663
  } catch {
11037
11664
  continue;
11038
11665
  }
11039
11666
  }
11040
- const parent = path3.dirname(dir);
11667
+ const parent = path2.dirname(dir);
11041
11668
  if (parent === dir) break;
11042
11669
  dir = parent;
11043
11670
  }
@@ -11052,7 +11679,7 @@ function getLocalDevVersion(directory) {
11052
11679
  try {
11053
11680
  const pkgPath = findPackageJsonUp(localPath);
11054
11681
  if (!pkgPath) return null;
11055
- const content = fs3.readFileSync(pkgPath, "utf-8");
11682
+ const content = fs2.readFileSync(pkgPath, "utf-8");
11056
11683
  const pkg = JSON.parse(content);
11057
11684
  return pkg.version ?? null;
11058
11685
  } catch {
@@ -11062,8 +11689,8 @@ function getLocalDevVersion(directory) {
11062
11689
  function findPluginEntry(directory) {
11063
11690
  for (const configPath of getConfigPaths(directory)) {
11064
11691
  try {
11065
- if (!fs3.existsSync(configPath)) continue;
11066
- const content = fs3.readFileSync(configPath, "utf-8");
11692
+ if (!fs2.existsSync(configPath)) continue;
11693
+ const content = fs2.readFileSync(configPath, "utf-8");
11067
11694
  const config = JSON.parse(stripJsonComments(content));
11068
11695
  const plugins = config.plugin ?? [];
11069
11696
  for (const entry of plugins) {
@@ -11087,8 +11714,8 @@ function findPluginEntry(directory) {
11087
11714
  }
11088
11715
  function getCachedVersion() {
11089
11716
  try {
11090
- if (fs3.existsSync(INSTALLED_PACKAGE_JSON)) {
11091
- const content = fs3.readFileSync(INSTALLED_PACKAGE_JSON, "utf-8");
11717
+ if (fs2.existsSync(INSTALLED_PACKAGE_JSON)) {
11718
+ const content = fs2.readFileSync(INSTALLED_PACKAGE_JSON, "utf-8");
11092
11719
  const pkg = JSON.parse(content);
11093
11720
  if (pkg.version) return pkg.version;
11094
11721
  }
@@ -11096,10 +11723,10 @@ function getCachedVersion() {
11096
11723
  return null;
11097
11724
  }
11098
11725
  try {
11099
- const currentDir = path3.dirname(fileURLToPath(import.meta.url));
11726
+ const currentDir = path2.dirname(fileURLToPath(import.meta.url));
11100
11727
  const pkgPath = findPackageJsonUp(currentDir);
11101
11728
  if (pkgPath) {
11102
- const content = fs3.readFileSync(pkgPath, "utf-8");
11729
+ const content = fs2.readFileSync(pkgPath, "utf-8");
11103
11730
  const pkg = JSON.parse(content);
11104
11731
  if (pkg.version) return pkg.version;
11105
11732
  }
@@ -11110,7 +11737,7 @@ function getCachedVersion() {
11110
11737
  }
11111
11738
  function updatePinnedVersion(configPath, oldEntry, newVersion) {
11112
11739
  try {
11113
- const content = fs3.readFileSync(configPath, "utf-8");
11740
+ const content = fs2.readFileSync(configPath, "utf-8");
11114
11741
  const newEntry = `${PACKAGE_NAME}@${newVersion}`;
11115
11742
  const pluginMatch = content.match(/"plugin"\s*:\s*\[/);
11116
11743
  if (!pluginMatch || pluginMatch.index === void 0) {
@@ -11140,7 +11767,7 @@ function updatePinnedVersion(configPath, oldEntry, newVersion) {
11140
11767
  logAutoUpdate(`No changes made to ${configPath}`);
11141
11768
  return false;
11142
11769
  }
11143
- fs3.writeFileSync(configPath, updatedContent, "utf-8");
11770
+ fs2.writeFileSync(configPath, updatedContent, "utf-8");
11144
11771
  logAutoUpdate(`Updated ${configPath}: ${oldEntry} \u2192 ${newEntry}`);
11145
11772
  return true;
11146
11773
  } catch (err) {
@@ -11167,16 +11794,16 @@ async function getLatestVersion() {
11167
11794
  }
11168
11795
 
11169
11796
  // src/hooks/auto-update-checker/cache.ts
11170
- import * as fs4 from "node:fs";
11171
- import * as path4 from "node:path";
11797
+ import * as fs3 from "node:fs";
11798
+ import * as path3 from "node:path";
11172
11799
  function stripTrailingCommas(json) {
11173
11800
  return json.replace(/,(\s*[}\]])/g, "$1");
11174
11801
  }
11175
11802
  function removeFromBunLock(packageName) {
11176
- const lockPath = path4.join(CACHE_DIR, "bun.lock");
11177
- if (!fs4.existsSync(lockPath)) return false;
11803
+ const lockPath = path3.join(CACHE_DIR, "bun.lock");
11804
+ if (!fs3.existsSync(lockPath)) return false;
11178
11805
  try {
11179
- const content = fs4.readFileSync(lockPath, "utf-8");
11806
+ const content = fs3.readFileSync(lockPath, "utf-8");
11180
11807
  const lock = JSON.parse(stripTrailingCommas(content));
11181
11808
  let modified = false;
11182
11809
  if (lock.workspaces?.[""]?.dependencies?.[packageName]) {
@@ -11188,7 +11815,7 @@ function removeFromBunLock(packageName) {
11188
11815
  modified = true;
11189
11816
  }
11190
11817
  if (modified) {
11191
- fs4.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
11818
+ fs3.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
11192
11819
  console.log(`[auto-update-checker] Removed from bun.lock: ${packageName}`);
11193
11820
  }
11194
11821
  return modified;
@@ -11198,22 +11825,22 @@ function removeFromBunLock(packageName) {
11198
11825
  }
11199
11826
  function invalidatePackage(packageName = PACKAGE_NAME) {
11200
11827
  try {
11201
- const pkgDir = path4.join(CACHE_DIR, "node_modules", packageName);
11202
- const pkgJsonPath = path4.join(CACHE_DIR, "package.json");
11828
+ const pkgDir = path3.join(CACHE_DIR, "node_modules", packageName);
11829
+ const pkgJsonPath = path3.join(CACHE_DIR, "package.json");
11203
11830
  let packageRemoved = false;
11204
11831
  let dependencyRemoved = false;
11205
11832
  let lockRemoved = false;
11206
- if (fs4.existsSync(pkgDir)) {
11207
- fs4.rmSync(pkgDir, { recursive: true, force: true });
11833
+ if (fs3.existsSync(pkgDir)) {
11834
+ fs3.rmSync(pkgDir, { recursive: true, force: true });
11208
11835
  console.log(`[auto-update-checker] Package removed: ${pkgDir}`);
11209
11836
  packageRemoved = true;
11210
11837
  }
11211
- if (fs4.existsSync(pkgJsonPath)) {
11212
- const content = fs4.readFileSync(pkgJsonPath, "utf-8");
11838
+ if (fs3.existsSync(pkgJsonPath)) {
11839
+ const content = fs3.readFileSync(pkgJsonPath, "utf-8");
11213
11840
  const pkgJson = JSON.parse(content);
11214
11841
  if (pkgJson.dependencies?.[packageName]) {
11215
11842
  delete pkgJson.dependencies[packageName];
11216
- fs4.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
11843
+ fs3.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
11217
11844
  console.log(`[auto-update-checker] Dependency removed from package.json: ${packageName}`);
11218
11845
  dependencyRemoved = true;
11219
11846
  }
@@ -11515,6 +12142,15 @@ function createAuthDoctorReport(input2) {
11515
12142
  }
11516
12143
  }
11517
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
+ }
11518
12154
  if (account.verificationRequired) {
11519
12155
  findings.push({
11520
12156
  code: "verification-required",
@@ -12295,6 +12931,69 @@ async function resolvePromptContext(client, sessionId) {
12295
12931
  return result;
12296
12932
  }
12297
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
+
12298
12997
  // src/plugin.ts
12299
12998
  var MAX_OAUTH_ACCOUNTS = 10;
12300
12999
  var MAX_WARMUP_SESSIONS = 1e3;
@@ -12305,8 +13004,6 @@ function isCapacityRetryBudgetExhausted(totalCapacityRetries) {
12305
13004
  }
12306
13005
  var warmupAttemptedSessionIds = /* @__PURE__ */ new Set();
12307
13006
  var warmupSucceededSessionIds = /* @__PURE__ */ new Set();
12308
- var isChildSession = false;
12309
- var childSessionParentID = void 0;
12310
13007
  var log10 = createLogger2("plugin");
12311
13008
  var rateLimitToastCooldowns = /* @__PURE__ */ new Map();
12312
13009
  var RATE_LIMIT_TOAST_COOLDOWN_MS = 5e3;
@@ -12497,10 +13194,12 @@ function selectBestVerificationUrl(urls) {
12497
13194
  });
12498
13195
  return unique[0];
12499
13196
  }
12500
- function extractVerificationErrorDetails(bodyText) {
13197
+ function extractAccountAccessErrorDetails(bodyText) {
12501
13198
  const decodedBody = decodeEscapedText(bodyText);
12502
13199
  const lowerBody = decodedBody.toLowerCase();
12503
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);
12504
13203
  let message;
12505
13204
  const verificationUrls = /* @__PURE__ */ new Set();
12506
13205
  const collectUrlsFromText = (text) => {
@@ -12543,6 +13242,9 @@ function extractVerificationErrorDetails(bodyText) {
12543
13242
  if (lowerValue.includes("validation_required")) {
12544
13243
  validationRequired = true;
12545
13244
  }
13245
+ if (ineligiblePattern.test(normalizedValue)) {
13246
+ accountIneligible = true;
13247
+ }
12546
13248
  if (!message && (lowerKey.includes("message") || lowerKey.includes("detail") || lowerKey.includes("description"))) {
12547
13249
  message = normalizedValue;
12548
13250
  }
@@ -12573,17 +13275,72 @@ function extractVerificationErrorDetails(bodyText) {
12573
13275
  validationRequired = lowerBody.includes("verification required") || lowerBody.includes("verify your account") || lowerBody.includes("account verification");
12574
13276
  }
12575
13277
  if (!message) {
12576
- 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));
12577
13279
  if (fallback) {
12578
13280
  message = fallback;
12579
13281
  }
12580
13282
  }
12581
13283
  return {
12582
13284
  validationRequired,
13285
+ accountIneligible,
12583
13286
  message,
12584
13287
  verifyUrl: selectBestVerificationUrl([...verificationUrls])
12585
13288
  };
12586
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
+ }
12587
13344
  async function verifyAccountAccess(account, client, providerId) {
12588
13345
  const parsed = parseRefreshParts(account.refreshToken);
12589
13346
  if (!parsed.refreshToken) {
@@ -12619,18 +13376,7 @@ async function verifyAccountAccess(account, client, providerId) {
12619
13376
  "Content-Type": "application/json",
12620
13377
  "Accept-Encoding": "gzip"
12621
13378
  };
12622
- const requestBody = {
12623
- project: projectId,
12624
- requestId: `agent/${crypto4.randomUUID()}/${Date.now()}/${crypto4.randomUUID()}/2`,
12625
- request: {
12626
- model: "gemini-3-flash",
12627
- contents: [{ role: "user", parts: [{ text: "ping" }] }],
12628
- generationConfig: { maxOutputTokens: 1, temperature: 0 }
12629
- },
12630
- model: "gemini-3-flash",
12631
- userAgent: "antigravity",
12632
- requestType: "agent"
12633
- };
13379
+ const requestBody = buildAccountAccessProbeRequest(projectId);
12634
13380
  const controller = new AbortController();
12635
13381
  const timeoutId = setTimeout(() => controller.abort(), 2e4);
12636
13382
  let response;
@@ -12648,28 +13394,7 @@ async function verifyAccountAccess(account, client, providerId) {
12648
13394
  } finally {
12649
13395
  clearTimeout(timeoutId);
12650
13396
  }
12651
- let responseBody = "";
12652
- try {
12653
- responseBody = await response.text();
12654
- } catch {
12655
- responseBody = "";
12656
- }
12657
- if (response.ok) {
12658
- return { status: "ok", message: "Account verification check passed." };
12659
- }
12660
- const extracted = extractVerificationErrorDetails(responseBody);
12661
- if (response.status === 403 && extracted.validationRequired) {
12662
- return {
12663
- status: "blocked",
12664
- message: extracted.message ?? "Google requires additional account verification.",
12665
- verifyUrl: extracted.verifyUrl
12666
- };
12667
- }
12668
- const fallbackMessage = extracted.message ?? `Request failed (${response.status} ${response.statusText}).`;
12669
- return {
12670
- status: "error",
12671
- message: fallbackMessage
12672
- };
13397
+ return interpretAccountAccessProbeResponse(response);
12673
13398
  }
12674
13399
  async function promptAccountIndexForVerification(accounts) {
12675
13400
  const { createInterface: createInterface2 } = await import("node:readline/promises");
@@ -12711,12 +13436,20 @@ async function promptOpenVerificationUrl() {
12711
13436
  function markStoredAccountVerificationRequired(account, reason, verifyUrl) {
12712
13437
  let changed = false;
12713
13438
  const wasVerificationRequired = account.verificationRequired === true;
13439
+ const timestamp = Date.now();
12714
13440
  if (!wasVerificationRequired) {
12715
13441
  account.verificationRequired = true;
12716
13442
  changed = true;
12717
13443
  }
12718
13444
  if (!wasVerificationRequired || account.verificationRequiredAt === void 0) {
12719
- account.verificationRequiredAt = Date.now();
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;
12720
13453
  changed = true;
12721
13454
  }
12722
13455
  const normalizedReason = reason.trim();
@@ -12735,8 +13468,25 @@ function markStoredAccountVerificationRequired(account, reason, verifyUrl) {
12735
13468
  }
12736
13469
  return changed;
12737
13470
  }
12738
- function clearStoredAccountVerificationRequired(account, enableIfRequired = false) {
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) {
12739
13487
  const wasVerificationRequired = account.verificationRequired === true;
13488
+ const wasIneligible = account.accountIneligible === true;
13489
+ const wasAccessBlocked = wasVerificationRequired || wasIneligible;
12740
13490
  let changed = false;
12741
13491
  if (account.verificationRequired !== false) {
12742
13492
  account.verificationRequired = false;
@@ -12754,11 +13504,27 @@ function clearStoredAccountVerificationRequired(account, enableIfRequired = fals
12754
13504
  account.verificationUrl = void 0;
12755
13505
  changed = true;
12756
13506
  }
12757
- if (enableIfRequired && wasVerificationRequired && account.enabled === false) {
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) {
12758
13524
  account.enabled = true;
12759
13525
  changed = true;
12760
13526
  }
12761
- return { changed, wasVerificationRequired };
13527
+ return { changed, wasAccessBlocked };
12762
13528
  }
12763
13529
  async function promptOAuthCallbackValue(message) {
12764
13530
  const { createInterface: createInterface2 } = await import("node:readline/promises");
@@ -13150,14 +13916,14 @@ function throwHandledCommandSentinel() {
13150
13916
  throw new Error(HANDLED_COMMAND_SENTINEL);
13151
13917
  }
13152
13918
  function sleep(ms, signal) {
13153
- return new Promise((resolve, reject) => {
13919
+ return new Promise((resolve2, reject) => {
13154
13920
  if (signal?.aborted) {
13155
13921
  reject(signal.reason instanceof Error ? signal.reason : new Error("Aborted"));
13156
13922
  return;
13157
13923
  }
13158
13924
  const timeout = setTimeout(() => {
13159
13925
  cleanup();
13160
- resolve();
13926
+ resolve2();
13161
13927
  }, ms);
13162
13928
  const onAbort = () => {
13163
13929
  cleanup();
@@ -13173,6 +13939,7 @@ function sleep(ms, signal) {
13173
13939
  var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
13174
13940
  const config = loadConfig(directory);
13175
13941
  initRuntimeConfig(config);
13942
+ const agySessionRegistry = new AgySessionRegistry(directory);
13176
13943
  let cachedGetAuth = null;
13177
13944
  initializeDebug(config);
13178
13945
  initLogger(client);
@@ -13206,25 +13973,34 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
13206
13973
  const eventHandler = async (input2) => {
13207
13974
  await updateChecker.event(input2);
13208
13975
  if (input2.event.type === "session.created") {
13209
- const prevSummary = activeAccountManager?.getSessionSummary();
13210
- if (prevSummary && (prevSummary.totalClaude > 0 || prevSummary.totalGemini > 0)) {
13211
- log10.debug("prev-session-quota-summary", {
13212
- durationMinutes: prevSummary.durationMinutes,
13213
- totalClaude: prevSummary.totalClaude,
13214
- totalGemini: prevSummary.totalGemini,
13215
- requestsPerHour: prevSummary.requestsPerHour,
13216
- accountsUsed: prevSummary.accountsUsed
13217
- });
13218
- }
13219
13976
  const props = input2.event.properties;
13220
- if (props?.info?.parentID) {
13221
- isChildSession = true;
13222
- childSessionParentID = props.info.parentID;
13223
- log10.debug("child-session-detected", { parentID: props.info.parentID });
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 });
13224
13984
  } else {
13225
- isChildSession = false;
13226
- childSessionParentID = void 0;
13227
- log10.debug("root-session-detected", {});
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);
13228
14004
  }
13229
14005
  }
13230
14006
  if (sessionRecovery && input2.event.type === "session.error") {
@@ -13248,8 +14024,13 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
13248
14024
  }).catch(() => {
13249
14025
  });
13250
14026
  const successToast = getRecoverySuccessToast();
13251
- log10.debug("recovery-toast", { ...successToast, isChildSession, toastScope: config.toast_scope });
13252
- if (!(config.toast_scope === "root_only" && isChildSession)) {
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)) {
13253
14034
  await client.tui.showToast({
13254
14035
  body: {
13255
14036
  title: successToast.title,
@@ -13433,6 +14214,20 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
13433
14214
  input2 = String(input2.href ?? input2);
13434
14215
  }
13435
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;
13436
14231
  if (accountManager.getAccountCount() === 0) {
13437
14232
  return createSyntheticErrorResponse(
13438
14233
  "No Antigravity accounts configured. Run `opencode auth login`.",
@@ -13448,6 +14243,11 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
13448
14243
  debugLines.push(line);
13449
14244
  };
13450
14245
  pushDebug(`request=${urlString}`);
14246
+ if (requestSessionIdentity.sessionId) {
14247
+ pushDebug(
14248
+ `[Session] id=${requestSessionIdentity.sessionId} parent=${requestSessionIdentity.parentSessionId ?? "none"} child=${isChildRequest}`
14249
+ );
14250
+ }
13451
14251
  const cachedStats = getLastCacheStats();
13452
14252
  if (cachedStats) {
13453
14253
  const label = cachedStats.hitRate > 0 ? "HIT" : "MISS";
@@ -13464,11 +14264,15 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
13464
14264
  const quietMode = config.quiet_mode;
13465
14265
  const toastScope = config.toast_scope;
13466
14266
  const showToast = async (message, variant) => {
13467
- log10.debug("toast", { message, variant, isChildSession, toastScope });
14267
+ log10.debug("toast", { message, variant, isChildSession: isChildRequest, toastScope });
13468
14268
  if (quietMode) return;
13469
14269
  if (abortSignal?.aborted) return;
13470
- if (toastScope === "root_only" && isChildSession) {
13471
- log10.debug("toast-suppressed-child-session", { message, variant, parentID: childSessionParentID });
14270
+ if (toastScope === "root_only" && isChildRequest) {
14271
+ log10.debug("toast-suppressed-child-session", {
14272
+ message,
14273
+ variant,
14274
+ parentID: requestSessionIdentity.parentSessionId
14275
+ });
13472
14276
  return;
13473
14277
  }
13474
14278
  if (variant === "warning" && message.toLowerCase().includes("rate")) {
@@ -13518,7 +14322,8 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
13518
14322
  preferredHeaderStyle,
13519
14323
  config.pid_offset_enabled,
13520
14324
  config.soft_quota_threshold_percent,
13521
- softQuotaCacheTtlMs
14325
+ softQuotaCacheTtlMs,
14326
+ accountSessionIdentity
13522
14327
  );
13523
14328
  if (!account && allowQuotaFallback) {
13524
14329
  const alternateHeaderStyle = preferredHeaderStyle === "antigravity" ? "gemini-cli" : "antigravity";
@@ -13529,7 +14334,8 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
13529
14334
  alternateHeaderStyle,
13530
14335
  config.pid_offset_enabled,
13531
14336
  config.soft_quota_threshold_percent,
13532
- softQuotaCacheTtlMs
14337
+ softQuotaCacheTtlMs,
14338
+ accountSessionIdentity
13533
14339
  );
13534
14340
  if (account) {
13535
14341
  pushDebug(
@@ -13607,7 +14413,7 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
13607
14413
  pushDebug(`account-switch: ${previousAccountIndex} \u2192 ${account.index}, warmup=${needsCacheWarmup}`);
13608
14414
  }
13609
14415
  previousAccountIndex = account.index;
13610
- accountManager.recordSessionUsage(account.index);
14416
+ accountManager.recordSessionUsage(account.index, accountSessionIdentity);
13611
14417
  if (isDebugEnabled()) {
13612
14418
  logAccountContext("Selected", {
13613
14419
  index: account.index,
@@ -13900,7 +14706,9 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
13900
14706
  {
13901
14707
  claudeToolHardening: config.claude_tool_hardening,
13902
14708
  claudePromptAutoCaching: config.claude_prompt_auto_caching,
13903
- fingerprint: account.fingerprint
14709
+ fingerprint: account.fingerprint,
14710
+ agySession: agyRequestSession,
14711
+ agyRequestTimestamp: agyRequestScope.timestamp
13904
14712
  }
13905
14713
  );
13906
14714
  const originalUrl = toUrlString(input2);
@@ -14128,7 +14936,24 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
14128
14936
  resetAccountFailureState(account.index);
14129
14937
  if (response.status === 403) {
14130
14938
  const errorBodyText = await response.clone().text().catch(() => "");
14131
- const extracted = extractVerificationErrorDetails(errorBodyText);
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
+ }
14132
14957
  if (extracted.validationRequired) {
14133
14958
  const verificationReason = extracted.message ?? "Google requires account verification.";
14134
14959
  const cooldownMs = 10 * 60 * 1e3;
@@ -14172,20 +14997,24 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
14172
14997
  family,
14173
14998
  model,
14174
14999
  proactiveThreshold,
14175
- softQuotaCacheTtlMs
15000
+ softQuotaCacheTtlMs,
15001
+ accountSessionIdentity
14176
15002
  )) {
14177
15003
  const rotated = accountManager.proactivelyRotateForFamily(
14178
15004
  family,
14179
15005
  model,
14180
15006
  headerStyle,
14181
15007
  config.soft_quota_threshold_percent,
14182
- softQuotaCacheTtlMs
15008
+ softQuotaCacheTtlMs,
15009
+ accountSessionIdentity
14183
15010
  );
14184
15011
  if (rotated) {
14185
15012
  const remaining = account.cachedQuota?.[resolveQuotaGroup(family, model)]?.remainingFraction;
14186
15013
  const remainingPct = remaining != null ? `${(remaining * 100).toFixed(1)}%` : "?";
14187
15014
  pushDebug(`[ProactiveRotation] account ${account.index} quota ${remainingPct} < ${proactiveThreshold}%, pre-switched to account ${rotated.index} for next request`);
14188
- pushDebug(`[ProactiveRotation] ${account.index} \u2192 ${rotated.index} (warm=${accountManager.wasUsedInSession(rotated.index)})`);
15015
+ pushDebug(
15016
+ `[ProactiveRotation] ${account.index} \u2192 ${rotated.index} (warm=${accountManager.wasUsedInSession(rotated.index, accountSessionIdentity)})`
15017
+ );
14189
15018
  }
14190
15019
  }
14191
15020
  }
@@ -14284,7 +15113,7 @@ Alternatively, you can:
14284
15113
  pushDebug(`[Quota] Total ${family} requests today (all accounts): ${totalToday}`);
14285
15114
  const cachedQuota = account.cachedQuota;
14286
15115
  if (cachedQuota) {
14287
- const quotaFamily = family === "claude" ? "claude" : "gemini-flash";
15116
+ const quotaFamily = resolveQuotaGroup(family, model);
14288
15117
  const groupQuota = cachedQuota[quotaFamily];
14289
15118
  if (groupQuota?.remainingFraction != null) {
14290
15119
  const pct = Math.round(groupQuota.remainingFraction * 100);
@@ -14439,7 +15268,9 @@ Alternatively, you can:
14439
15268
  const now = Date.now();
14440
15269
  const existingAccounts = existingStorage2.accounts.map((acc, idx) => {
14441
15270
  let status = "unknown";
14442
- if (acc.verificationRequired) {
15271
+ if (acc.accountIneligible) {
15272
+ status = "ineligible";
15273
+ } else if (acc.verificationRequired) {
14443
15274
  status = "verification-required";
14444
15275
  } else {
14445
15276
  const rateLimits = acc.rateLimitResetTimes;
@@ -14575,7 +15406,8 @@ Alternatively, you can:
14575
15406
  const groupEntries = [
14576
15407
  { name: "Claude", data: groups.claude },
14577
15408
  { name: "Gemini 3 Pro", data: groups["gemini-pro"] },
14578
- { 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"] }
14579
15411
  ].filter((g) => g.data);
14580
15412
  groupEntries.forEach((g, idx) => {
14581
15413
  const isLast = idx === groupEntries.length - 1;
@@ -14634,7 +15466,16 @@ ${formatAuthDoctorReport(report)}
14634
15466
  if (menuResult.toggleAccountIndex !== void 0) {
14635
15467
  const acc = existingStorage2.accounts[menuResult.toggleAccountIndex];
14636
15468
  if (acc) {
14637
- acc.enabled = acc.enabled === false;
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;
14638
15479
  await saveAccounts(existingStorage2);
14639
15480
  activeAccountManager?.setAccountEnabled(menuResult.toggleAccountIndex, acc.enabled);
14640
15481
  console.log(`
@@ -14656,6 +15497,7 @@ Checking verification status for ${existingStorage2.accounts.length} account(s).
14656
15497
  `);
14657
15498
  let okCount = 0;
14658
15499
  let blockedCount = 0;
15500
+ let ineligibleCount = 0;
14659
15501
  let errorCount = 0;
14660
15502
  let storageUpdated = false;
14661
15503
  const blockedResults = [];
@@ -14666,16 +15508,16 @@ Checking verification status for ${existingStorage2.accounts.length} account(s).
14666
15508
  process.stdout.write(`- [${i + 1}/${existingStorage2.accounts.length}] ${label2} ... `);
14667
15509
  const verification2 = await verifyAccountAccess(account2, client, providerId);
14668
15510
  if (verification2.status === "ok") {
14669
- const { changed, wasVerificationRequired } = clearStoredAccountVerificationRequired(account2, true);
15511
+ const { changed, wasAccessBlocked } = clearStoredAccountAccessBlocks(account2, true);
14670
15512
  if (changed) {
14671
15513
  storageUpdated = true;
14672
15514
  }
14673
- activeAccountManager?.clearAccountVerificationRequired(i, wasVerificationRequired);
15515
+ activeAccountManager?.clearAccountAccessBlocks(i, wasAccessBlocked);
14674
15516
  okCount += 1;
14675
15517
  console.log("ok");
14676
15518
  continue;
14677
15519
  }
14678
- if (verification2.status === "blocked") {
15520
+ if (verification2.status === "verification-required") {
14679
15521
  const changed = markStoredAccountVerificationRequired(
14680
15522
  account2,
14681
15523
  verification2.message,
@@ -14695,14 +15537,26 @@ Checking verification status for ${existingStorage2.accounts.length} account(s).
14695
15537
  });
14696
15538
  continue;
14697
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
+ }
14698
15550
  errorCount += 1;
14699
15551
  console.log(`error (${verification2.message})`);
14700
15552
  }
14701
15553
  if (storageUpdated) {
14702
15554
  await saveAccounts(existingStorage2);
14703
15555
  }
14704
- console.log(`
14705
- Verification summary: ${okCount} ready, ${blockedCount} need verification, ${errorCount} errors.`);
15556
+ console.log(
15557
+ `
15558
+ Verification summary: ${okCount} ready, ${blockedCount} need verification, ${ineligibleCount} ineligible, ${errorCount} errors.`
15559
+ );
14706
15560
  if (blockedResults.length > 0) {
14707
15561
  console.log("\nAccounts needing verification:");
14708
15562
  for (const result of blockedResults) {
@@ -14742,12 +15596,12 @@ Checking verification status for ${label}...
14742
15596
  `);
14743
15597
  const verification = await verifyAccountAccess(account, client, providerId);
14744
15598
  if (verification.status === "ok") {
14745
- const { changed, wasVerificationRequired } = clearStoredAccountVerificationRequired(account, true);
15599
+ const { changed, wasAccessBlocked } = clearStoredAccountAccessBlocks(account, true);
14746
15600
  if (changed) {
14747
15601
  await saveAccounts(existingStorage2);
14748
15602
  }
14749
- activeAccountManager?.clearAccountVerificationRequired(verifyAccountIndex, wasVerificationRequired);
14750
- if (wasVerificationRequired) {
15603
+ activeAccountManager?.clearAccountAccessBlocks(verifyAccountIndex, wasAccessBlocked);
15604
+ if (wasAccessBlocked) {
14751
15605
  console.log(`\u2713 ${label} is ready for requests and has been re-enabled.
14752
15606
  `);
14753
15607
  } else {
@@ -14756,7 +15610,7 @@ Checking verification status for ${label}...
14756
15610
  }
14757
15611
  continue;
14758
15612
  }
14759
- if (verification.status === "blocked") {
15613
+ if (verification.status === "verification-required") {
14760
15614
  const changed = markStoredAccountVerificationRequired(
14761
15615
  account,
14762
15616
  verification.message,
@@ -14794,6 +15648,20 @@ ${verifyUrl}
14794
15648
  }
14795
15649
  continue;
14796
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
+ }
14797
15665
  console.log(`\u2717 ${label}: ${verification.message}
14798
15666
  `);
14799
15667
  continue;