@cortexkit/opencode-antigravity-auth 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -299,6 +299,7 @@ import { createGunzip } from "node:zlib";
299
299
  var DEFAULT_HTTPS_PORT = 443;
300
300
  var DEFAULT_PROXY_PORT = 8080;
301
301
  var DEFAULT_AGY_RESPONSE_HEADER_TIMEOUT_MS = 18e4;
302
+ var DEFAULT_AGY_IDLE_TIMEOUT_MS = 18e4;
302
303
  function headersToRecord(headers) {
303
304
  const result = {};
304
305
  if (!headers)
@@ -522,6 +523,7 @@ function parseResponseHead(head) {
522
523
  const headers = new Headers();
523
524
  let chunked = false;
524
525
  let gzip = false;
526
+ let contentLength;
525
527
  for (const line of lines) {
526
528
  const index = line.indexOf(":");
527
529
  if (index <= 0)
@@ -538,8 +540,13 @@ function parseResponseHead(head) {
538
540
  gzip = true;
539
541
  continue;
540
542
  }
541
- if (gzip && lowerKey === "content-length") {
542
- continue;
543
+ if (lowerKey === "content-length") {
544
+ const parsed = Number.parseInt(value, 10);
545
+ if (Number.isFinite(parsed) && parsed >= 0) {
546
+ contentLength = parsed;
547
+ }
548
+ if (gzip)
549
+ continue;
543
550
  }
544
551
  headers.append(key, value);
545
552
  }
@@ -548,9 +555,34 @@ function parseResponseHead(head) {
548
555
  statusText: match[2] ?? "",
549
556
  headers,
550
557
  chunked,
551
- gzip
558
+ gzip,
559
+ contentLength
552
560
  };
553
561
  }
562
+ var ContentLengthStream = class extends Transform {
563
+ remaining;
564
+ constructor(contentLength) {
565
+ super();
566
+ this.remaining = contentLength;
567
+ }
568
+ _transform(chunk, _encoding, callback) {
569
+ if (this.remaining <= 0) {
570
+ callback();
571
+ return;
572
+ }
573
+ if (chunk.length <= this.remaining) {
574
+ this.remaining -= chunk.length;
575
+ this.push(chunk);
576
+ } else {
577
+ this.push(chunk.subarray(0, this.remaining));
578
+ this.remaining = 0;
579
+ }
580
+ if (this.remaining <= 0) {
581
+ this.push(null);
582
+ }
583
+ callback();
584
+ }
585
+ };
554
586
  var ChunkedDecodeStream = class extends Transform {
555
587
  buffer = Buffer2.alloc(0);
556
588
  _transform(chunk, _encoding, callback) {
@@ -596,7 +628,7 @@ var ChunkedDecodeStream = class extends Transform {
596
628
  }
597
629
  }
598
630
  };
599
- function buildResponseStream(socket, leftover, head, signal) {
631
+ function buildResponseStream(socket, leftover, head, signal, idleTimeoutMs, onDebug) {
600
632
  const source = new PassThrough();
601
633
  if (leftover.length > 0) {
602
634
  source.write(leftover);
@@ -605,12 +637,36 @@ function buildResponseStream(socket, leftover, head, signal) {
605
637
  let responseBody = source;
606
638
  if (head.chunked) {
607
639
  responseBody = responseBody.pipe(new ChunkedDecodeStream());
640
+ } else if (typeof head.contentLength === "number") {
641
+ responseBody = responseBody.pipe(new ContentLengthStream(head.contentLength));
608
642
  }
609
643
  if (head.gzip) {
610
644
  responseBody = responseBody.pipe(createGunzip());
611
645
  }
646
+ let idleTimer;
647
+ const clearIdle = () => {
648
+ if (idleTimer) {
649
+ clearTimeout(idleTimer);
650
+ idleTimer = void 0;
651
+ }
652
+ };
653
+ const armIdle = () => {
654
+ if (!idleTimeoutMs || idleTimeoutMs <= 0)
655
+ return;
656
+ clearIdle();
657
+ idleTimer = setTimeout(() => {
658
+ onDebug?.(`agy transport idle timeout after ${idleTimeoutMs}ms with no body data`);
659
+ socket.destroy(new Error(`Antigravity response stalled: no data for ${idleTimeoutMs}ms`));
660
+ }, idleTimeoutMs);
661
+ };
662
+ socket.on("data", armIdle);
663
+ armIdle();
612
664
  const abort = () => socket.destroy(new DOMException("The operation was aborted", "AbortError"));
613
- const cleanup = () => signal?.removeEventListener("abort", abort);
665
+ const cleanup = () => {
666
+ clearIdle();
667
+ socket.off("data", armIdle);
668
+ signal?.removeEventListener("abort", abort);
669
+ };
614
670
  if (signal?.aborted) {
615
671
  abort();
616
672
  } else {
@@ -632,11 +688,15 @@ async function fetchWithAgyCliTransport(url, init = {}, options = {}) {
632
688
  if (parsedUrl.protocol !== "https:") {
633
689
  throw new Error(`agy transport only supports https URLs: ${url}`);
634
690
  }
691
+ if (options.signal?.aborted) {
692
+ throw new DOMException("The operation was aborted", "AbortError");
693
+ }
635
694
  const body = bodyToBuffer(init.body);
636
695
  const requestBytes = serializeRequest(parsedUrl, init, body);
637
696
  const timeoutMs = options.timeoutMs ?? DEFAULT_AGY_RESPONSE_HEADER_TIMEOUT_MS;
697
+ const idleTimeoutMs = options.idleTimeoutMs ?? DEFAULT_AGY_IDLE_TIMEOUT_MS;
638
698
  options.onDebug?.(`agy transport connecting to ${parsedUrl.hostname} with header timeout ${timeoutMs}ms`);
639
- const socket = await connectTls(parsedUrl, timeoutMs, options.onDebug);
699
+ const socket = await connectTlsWithAbort(parsedUrl, timeoutMs, options.signal, options.onDebug);
640
700
  const abort = () => {
641
701
  socket.destroy(new DOMException("The operation was aborted", "AbortError"));
642
702
  };
@@ -650,7 +710,7 @@ async function fetchWithAgyCliTransport(url, init = {}, options = {}) {
650
710
  });
651
711
  const parsedHead = parseResponseHead(head);
652
712
  options.onDebug?.(`agy transport response headers received: ${parsedHead.status} ${parsedHead.statusText}`);
653
- const bodyStream = buildResponseStream(socket, leftover, parsedHead, options.signal);
713
+ const bodyStream = buildResponseStream(socket, leftover, parsedHead, options.signal, idleTimeoutMs, options.onDebug);
654
714
  return new Response(bodyStream, {
655
715
  status: parsedHead.status,
656
716
  statusText: parsedHead.statusText,
@@ -663,6 +723,27 @@ async function fetchWithAgyCliTransport(url, init = {}, options = {}) {
663
723
  options.signal?.removeEventListener("abort", abort);
664
724
  }
665
725
  }
726
+ async function connectTlsWithAbort(targetUrl, timeoutMs, signal, onDebug) {
727
+ if (!signal) {
728
+ return connectTls(targetUrl, timeoutMs, onDebug);
729
+ }
730
+ const connectPromise = connectTls(targetUrl, timeoutMs, onDebug);
731
+ let onAbort;
732
+ const abortPromise = new Promise((_, reject) => {
733
+ onAbort = () => reject(new DOMException("The operation was aborted", "AbortError"));
734
+ signal.addEventListener("abort", onAbort, { once: true });
735
+ });
736
+ try {
737
+ return await Promise.race([connectPromise, abortPromise]);
738
+ } catch (error) {
739
+ void connectPromise.then((socket) => socket.destroy()).catch(() => {
740
+ });
741
+ throw error;
742
+ } finally {
743
+ if (onAbort)
744
+ signal.removeEventListener("abort", onAbort);
745
+ }
746
+ }
666
747
 
667
748
  // ../core/dist/version.js
668
749
  var VERSION_URL = "https://antigravity-auto-updater-974169037036.us-central1.run.app";
@@ -3083,8 +3164,10 @@ async function getLockFunction() {
3083
3164
  if (_cachedLock) return _cachedLock;
3084
3165
  const mod = await import("proper-lockfile");
3085
3166
  const fn = (typeof mod.lock === "function" ? mod.lock : void 0) || (mod.default && typeof mod.default.lock === "function" ? mod.default.lock : void 0);
3086
- _cachedLock = fn || (async () => async () => {
3087
- });
3167
+ if (typeof fn !== "function") {
3168
+ throw new Error("proper-lockfile did not expose a lock() function; cannot acquire account file lock");
3169
+ }
3170
+ _cachedLock = fn;
3088
3171
  return _cachedLock;
3089
3172
  }
3090
3173
  var lockfile = { lock: (path5, options) => getLockFunction().then((fn) => fn(path5, options)) };
@@ -3598,9 +3681,11 @@ async function loadAccountsUnsafe() {
3598
3681
  }
3599
3682
  }
3600
3683
  async function clearAccounts() {
3684
+ const path5 = getStoragePath();
3601
3685
  try {
3602
- const path5 = getStoragePath();
3603
- await fs.unlink(path5);
3686
+ await withFileLock(path5, async () => {
3687
+ await fs.unlink(path5);
3688
+ });
3604
3689
  } catch (error) {
3605
3690
  const code = error.code;
3606
3691
  if (code !== "ENOENT") {
@@ -3625,7 +3710,7 @@ function getConfigDir2() {
3625
3710
  function getLogsDir(customLogDir) {
3626
3711
  const logsDir = customLogDir || join3(getConfigDir2(), "antigravity-logs");
3627
3712
  try {
3628
- mkdirSync3(logsDir, { recursive: true });
3713
+ mkdirSync3(logsDir, { recursive: true, mode: 448 });
3629
3714
  } catch {
3630
3715
  }
3631
3716
  return logsDir;
@@ -3661,7 +3746,7 @@ function createLogWriter(filePath) {
3661
3746
  };
3662
3747
  }
3663
3748
  try {
3664
- const stream = createWriteStream(filePath, { flags: "a" });
3749
+ const stream = createWriteStream(filePath, { flags: "a", mode: 384 });
3665
3750
  stream.on("error", () => {
3666
3751
  });
3667
3752
  return (line) => {
@@ -7644,6 +7729,8 @@ var DUMP_USAGE_TITLE = "## Gemini Dump Usage";
7644
7729
  var DUMP_USAGE = "Usage: `/gemini-dump`, `/gemini-dump on`, or `/gemini-dump off`.";
7645
7730
  var DUMP_DIR_ENV = "OPENCODE_ANTIGRAVITY_GEMINI_DUMP_DIR";
7646
7731
  var DEFAULT_DUMP_DIR = join9(tmpdir2(), "opencode-antigravity-gemini-dumps");
7732
+ var DUMP_DIR_MODE = 448;
7733
+ var DUMP_FILE_MODE = 384;
7647
7734
  var dumpEnabled = process.env.OPENCODE_ANTIGRAVITY_GEMINI_DUMP === "1";
7648
7735
  var nextDumpId = 0;
7649
7736
  function setGeminiDumpEnabled(enabled) {
@@ -7764,7 +7851,7 @@ function bodyStructureSummary(bodyText) {
7764
7851
  }
7765
7852
  function writeJson(path5, value) {
7766
7853
  writeFileSync6(path5, `${JSON.stringify(value, null, 2)}
7767
- `, "utf8");
7854
+ `, { encoding: "utf8", mode: DUMP_FILE_MODE });
7768
7855
  }
7769
7856
  function updateMetadata(context, patch) {
7770
7857
  context.metadata = {
@@ -7781,7 +7868,7 @@ function dumpGeminiRequest(input2) {
7781
7868
  const id = `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}-${String(nextDumpId).padStart(5, "0")}-${input2.streaming ? "stream" : "json"}`;
7782
7869
  const dumpDir = getGeminiDumpDirectory();
7783
7870
  const prefix = join9(dumpDir, id);
7784
- mkdirSync7(dumpDir, { recursive: true });
7871
+ mkdirSync7(dumpDir, { recursive: true, mode: DUMP_DIR_MODE });
7785
7872
  const context = {
7786
7873
  id,
7787
7874
  files: {
@@ -7809,8 +7896,8 @@ function dumpGeminiRequest(input2) {
7809
7896
  }
7810
7897
  }
7811
7898
  };
7812
- writeFileSync6(context.files.request, input2.body, "utf8");
7813
- writeFileSync6(context.files.response, "", "utf8");
7899
+ writeFileSync6(context.files.request, input2.body, { encoding: "utf8", mode: DUMP_FILE_MODE });
7900
+ writeFileSync6(context.files.response, "", { encoding: "utf8", mode: DUMP_FILE_MODE });
7814
7901
  writeJson(context.files.metadata, context.metadata);
7815
7902
  return context;
7816
7903
  }
@@ -8421,17 +8508,15 @@ var _lastCacheStats = null;
8421
8508
  function getLastCacheStats() {
8422
8509
  return _lastCacheStats;
8423
8510
  }
8424
- function generateSyntheticProjectId() {
8425
- const adjectives = ["useful", "bright", "swift", "calm", "bold"];
8426
- const nouns = ["fuze", "wave", "spark", "flow", "core"];
8427
- const adj = adjectives[Math.floor(Math.random() * adjectives.length)];
8428
- const noun = nouns[Math.floor(Math.random() * nouns.length)];
8429
- const randomPart = crypto2.randomUUID().slice(0, 5).toLowerCase();
8430
- return `${adj}-${noun}-${randomPart}`;
8431
- }
8432
8511
  var STREAM_ACTION = "streamGenerateContent";
8512
+ function fetchInputToUrl(input2) {
8513
+ if (typeof input2 === "string") return input2;
8514
+ if (input2 instanceof URL) return input2.href;
8515
+ const url = input2.url;
8516
+ return typeof url === "string" ? url : String(input2);
8517
+ }
8433
8518
  function isGenerativeLanguageRequest(input2) {
8434
- return typeof input2 === "string" && input2.includes("generativelanguage.googleapis.com");
8519
+ return fetchInputToUrl(input2).includes("generativelanguage.googleapis.com");
8435
8520
  }
8436
8521
  function prepareAntigravityRequest(input2, init, accessToken, projectId, endpointOverride, headerStyle = "antigravity", forceThinkingRecovery = false, options) {
8437
8522
  const baseInit = { ...init };
@@ -8456,7 +8541,8 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
8456
8541
  headers.delete("x-goog-api-key");
8457
8542
  headers.delete("x-session-affinity");
8458
8543
  headers.delete("x-goog-user-project");
8459
- const match = input2.match(/\/models\/([^:]+):(\w+)/);
8544
+ const urlString = fetchInputToUrl(input2);
8545
+ const match = urlString.match(/\/models\/([^:]+):(\w+)/);
8460
8546
  if (!match) {
8461
8547
  return {
8462
8548
  request: input2,
@@ -8909,7 +8995,7 @@ function prepareAntigravityRequest(input2, init, accessToken, projectId, endpoin
8909
8995
  }
8910
8996
  stripInjectedDebugFromRequestPayload(requestPayload);
8911
8997
  sanitizeRequestPayloadForAntigravity(requestPayload);
8912
- const effectiveProjectId = projectId?.trim() || (headerStyle === "antigravity" ? generateSyntheticProjectId() : "");
8998
+ const effectiveProjectId = projectId?.trim() || (headerStyle === "antigravity" ? ANTIGRAVITY_DEFAULT_PROJECT_ID : "");
8913
8999
  resolvedProjectId = effectiveProjectId;
8914
9000
  const wrappedBody = headerStyle === "antigravity" ? {
8915
9001
  project: effectiveProjectId,
@@ -10547,10 +10633,10 @@ var AccountManager = class _AccountManager {
10547
10633
  getAccounts() {
10548
10634
  return [...this.accounts];
10549
10635
  }
10550
- async saveToDisk() {
10636
+ buildStorageSnapshot() {
10551
10637
  const claudeIndex = Math.max(0, this.currentAccountIndexByFamily.claude);
10552
10638
  const geminiIndex = Math.max(0, this.currentAccountIndexByFamily.gemini);
10553
- const storage = {
10639
+ return {
10554
10640
  version: 4,
10555
10641
  accounts: this.accounts.map((a) => ({
10556
10642
  email: a.email,
@@ -10577,7 +10663,17 @@ var AccountManager = class _AccountManager {
10577
10663
  gemini: geminiIndex
10578
10664
  }
10579
10665
  };
10580
- await saveAccounts(storage);
10666
+ }
10667
+ async saveToDisk() {
10668
+ await saveAccounts(this.buildStorageSnapshot());
10669
+ }
10670
+ /**
10671
+ * Persist via full-file replace (no merge). Required after destructive
10672
+ * operations (account removal) so a deleted account is not resurrected by
10673
+ * mergeAccountStorage re-reading it from disk.
10674
+ */
10675
+ async saveToDiskReplace() {
10676
+ await saveAccountsReplace(this.buildStorageSnapshot());
10581
10677
  }
10582
10678
  requestSaveToDisk() {
10583
10679
  if (this.savePending) {
@@ -13318,6 +13414,25 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
13318
13414
  if (!isOAuthAuth(latestAuth)) {
13319
13415
  return fetch(input2, init);
13320
13416
  }
13417
+ if (typeof input2 !== "string") {
13418
+ if (input2 instanceof Request) {
13419
+ const req = input2;
13420
+ const headers = new Headers(req.headers);
13421
+ if (init?.headers) {
13422
+ new Headers(init.headers).forEach((v, k) => headers.set(k, v));
13423
+ }
13424
+ const bodyBuffer = req.body ? await req.clone().arrayBuffer() : void 0;
13425
+ init = {
13426
+ method: init?.method ?? req.method,
13427
+ headers,
13428
+ body: init?.body ?? (bodyBuffer ? Buffer.from(bodyBuffer) : void 0),
13429
+ signal: init?.signal ?? req.signal
13430
+ };
13431
+ input2 = req.url;
13432
+ } else {
13433
+ input2 = String(input2.href ?? input2);
13434
+ }
13435
+ }
13321
13436
  if (accountManager.getAccountCount() === 0) {
13322
13437
  return createSyntheticErrorResponse(
13323
13438
  "No Antigravity accounts configured. Run `opencode auth login`.",
@@ -13542,7 +13657,7 @@ var createAntigravityPlugin = (providerId) => async ({ client, directory }) => {
13542
13657
  if (removed) {
13543
13658
  log10.warn("Removed revoked account from pool - reauthenticate via `opencode auth login`");
13544
13659
  try {
13545
- await accountManager.saveToDisk();
13660
+ await accountManager.saveToDiskReplace();
13546
13661
  } catch (persistError) {
13547
13662
  log10.error("Failed to persist revoked account removal", { error: String(persistError) });
13548
13663
  }