@eddyskywalker/dsh-chatgpt-subscription 0.1.37 → 0.1.39

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 (56) hide show
  1. package/bin/antigravity-login.mjs +36 -0
  2. package/lib/client.js +1306 -53
  3. package/lib/client.js.map +1 -1
  4. package/lib/index.js +1921 -23
  5. package/lib/types/client/CodexSubscriptionSection.d.ts.map +1 -1
  6. package/lib/types/client/antigravity/AntigravityComposerQuota.d.ts +11 -0
  7. package/lib/types/client/antigravity/AntigravityComposerQuota.d.ts.map +1 -0
  8. package/lib/types/client/antigravity/AntigravitySection.d.ts +10 -0
  9. package/lib/types/client/antigravity/AntigravitySection.d.ts.map +1 -0
  10. package/lib/types/client/antigravity/locales.d.ts +298 -0
  11. package/lib/types/client/antigravity/locales.d.ts.map +1 -0
  12. package/lib/types/client/antigravity/styles.d.ts +3 -0
  13. package/lib/types/client/antigravity/styles.d.ts.map +1 -0
  14. package/lib/types/client/index.d.ts +1 -0
  15. package/lib/types/client/index.d.ts.map +1 -1
  16. package/lib/types/client/locales.d.ts +19 -7
  17. package/lib/types/client/locales.d.ts.map +1 -1
  18. package/lib/types/client/mermaid/renderer.d.ts +3 -0
  19. package/lib/types/client/mermaid/renderer.d.ts.map +1 -0
  20. package/lib/types/client/mermaid/sanitize.d.ts +2 -0
  21. package/lib/types/client/mermaid/sanitize.d.ts.map +1 -0
  22. package/lib/types/client/mermaid/styles.d.ts +3 -0
  23. package/lib/types/client/mermaid/styles.d.ts.map +1 -0
  24. package/lib/types/host/antigravity/adapter.d.ts +15 -0
  25. package/lib/types/host/antigravity/adapter.d.ts.map +1 -0
  26. package/lib/types/host/antigravity/client.d.ts +21 -0
  27. package/lib/types/host/antigravity/client.d.ts.map +1 -0
  28. package/lib/types/host/antigravity/mapper.d.ts +28 -0
  29. package/lib/types/host/antigravity/mapper.d.ts.map +1 -0
  30. package/lib/types/host/antigravity/oauth.d.ts +38 -0
  31. package/lib/types/host/antigravity/oauth.d.ts.map +1 -0
  32. package/lib/types/host/antigravity/routes.d.ts +6 -0
  33. package/lib/types/host/antigravity/routes.d.ts.map +1 -0
  34. package/lib/types/host/antigravity/token-store.d.ts +60 -0
  35. package/lib/types/host/antigravity/token-store.d.ts.map +1 -0
  36. package/lib/types/host/antigravity/types.d.ts +46 -0
  37. package/lib/types/host/antigravity/types.d.ts.map +1 -0
  38. package/lib/types/host/common/idle-watchdog.d.ts +8 -0
  39. package/lib/types/host/common/idle-watchdog.d.ts.map +1 -0
  40. package/lib/types/host/preferences.d.ts.map +1 -1
  41. package/lib/types/host/responses-client.d.ts +3 -1
  42. package/lib/types/host/responses-client.d.ts.map +1 -1
  43. package/lib/types/host/responses-mapper.d.ts +2 -2
  44. package/lib/types/host/responses-mapper.d.ts.map +1 -1
  45. package/lib/types/host/routes.d.ts.map +1 -1
  46. package/lib/types/index.d.ts +4 -0
  47. package/lib/types/index.d.ts.map +1 -1
  48. package/lib/types/shared/antigravity-contracts.d.ts +72 -0
  49. package/lib/types/shared/antigravity-contracts.d.ts.map +1 -0
  50. package/lib/types/shared/contracts.d.ts +3 -0
  51. package/lib/types/shared/contracts.d.ts.map +1 -1
  52. package/lib/types/shared/model-catalog.d.ts +7 -0
  53. package/lib/types/shared/model-catalog.d.ts.map +1 -1
  54. package/lib/types/shared/preferences.d.ts +2 -1
  55. package/lib/types/shared/preferences.d.ts.map +1 -1
  56. package/package.json +34 -29
package/lib/index.js CHANGED
@@ -1,18 +1,20 @@
1
+ import { createRequire } from "node:module";
1
2
  import * as LlmModule from "@deepseek-ai/dsh-llm";
2
3
  import { HarnessError, LlmAdapter, LlmError, ProviderRequestId, ReasoningEffortId, attributionHeaders, resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
3
4
  import { WebError } from "@deepseek-ai/dsh-web";
4
5
  import { createUserMessage } from "@deepseek-ai/dsh-llm/message";
5
6
  import { defineTool } from "@deepseek-ai/dsh-tools";
6
7
  import { createHash, randomBytes, randomUUID } from "node:crypto";
7
- import http from "node:http";
8
+ import http, { createServer } from "node:http";
8
9
  import { execSync, spawn } from "node:child_process";
9
10
  import { ProxyAgent, fetch as fetch$1 } from "undici";
10
11
  import * as SettingsModule from "@deepseek-ai/dsh-settings";
11
12
  import z from "@deepseek-ai/schemastery";
12
- import { constants } from "node:fs";
13
- import { chmod, lstat, mkdir, open, rename, stat, unlink } from "node:fs/promises";
14
- import { homedir } from "node:os";
15
- import { dirname, join } from "node:path";
13
+ import fs, { constants } from "node:fs";
14
+ import fsPromises, { chmod, lstat, mkdir, open, rename, stat, unlink } from "node:fs/promises";
15
+ import os, { homedir } from "node:os";
16
+ import path, { dirname, join } from "node:path";
17
+ import { URL as URL$1, URLSearchParams as URLSearchParams$1 } from "node:url";
16
18
  //#region src/compat.ts
17
19
  /**
18
20
  * Compatibility constants for the ChatGPT-backed Codex flow. The backend and
@@ -55,7 +57,8 @@ const CODEX_MODEL_CATALOG = [
55
57
  inputModalities: ["text", "image"],
56
58
  defaultReasoningEffort: "medium",
57
59
  reasoningProfile: "gpt-5.6",
58
- supportsReasoningSummary: true
60
+ supportsReasoningSummary: true,
61
+ fallbackModelId: "gpt-5.6-terra"
59
62
  },
60
63
  {
61
64
  id: "gpt-5.6-terra",
@@ -64,7 +67,8 @@ const CODEX_MODEL_CATALOG = [
64
67
  inputModalities: ["text", "image"],
65
68
  defaultReasoningEffort: "medium",
66
69
  reasoningProfile: "gpt-5.6",
67
- supportsReasoningSummary: true
70
+ supportsReasoningSummary: true,
71
+ fallbackModelId: "gpt-5.5"
68
72
  },
69
73
  {
70
74
  id: "gpt-5.6-luna",
@@ -73,7 +77,8 @@ const CODEX_MODEL_CATALOG = [
73
77
  inputModalities: ["text", "image"],
74
78
  defaultReasoningEffort: "medium",
75
79
  reasoningProfile: "gpt-5.6",
76
- supportsReasoningSummary: true
80
+ supportsReasoningSummary: true,
81
+ fallbackModelId: "gpt-5.5"
77
82
  },
78
83
  {
79
84
  id: "gpt-5.5",
@@ -91,7 +96,8 @@ const CODEX_MODEL_CATALOG = [
91
96
  inputModalities: ["text", "image"],
92
97
  defaultReasoningEffort: "none",
93
98
  reasoningProfile: "standard",
94
- supportsReasoningSummary: true
99
+ supportsReasoningSummary: true,
100
+ fallbackModelId: "gpt-5.4-mini"
95
101
  },
96
102
  {
97
103
  id: "gpt-5.4-mini",
@@ -149,14 +155,19 @@ function codexModelSupportsImageInput(model) {
149
155
  function codexModelSupportsReasoningSummary(model) {
150
156
  return resolveCodexCatalogEntry(model).supportsReasoningSummary;
151
157
  }
158
+ function resolveCodexFallbackModel(model) {
159
+ const entry = resolveCodexCatalogEntry(model);
160
+ if (!entry.fallbackModelId) return void 0;
161
+ return CODEX_MODEL_CATALOG.find((cand) => cand.id === entry.fallbackModelId);
162
+ }
152
163
  //#endregion
153
164
  //#region src/host/model-catalog.ts
154
- const PROVIDER_ID = CODEX_CHATGPT_PROVIDER_ID;
155
- const PROVIDER_NAME = "Codex(ChatGPT 订阅)";
165
+ const PROVIDER_ID$1 = CODEX_CHATGPT_PROVIDER_ID;
166
+ const PROVIDER_NAME$1 = "Codex(ChatGPT 订阅)";
156
167
  function listCodexModels(preferences) {
157
168
  const visible = new Set(preferences?.status().visibleModelIds ?? CODEX_MODEL_CATALOG.map((entry) => entry.id));
158
169
  return CODEX_MODEL_CATALOG.filter((entry) => visible.has(entry.id)).map((entry) => ({
159
- provider: PROVIDER_ID,
170
+ provider: PROVIDER_ID$1,
160
171
  id: entry.id,
161
172
  name: entry.name,
162
173
  inputModalities: [...entry.inputModalities]
@@ -168,7 +179,7 @@ function resolveCodexModel(model, preferences) {
168
179
  const configuredContextWindow = isConfigurableContextModelId(model) ? status?.contextWindowOverrides[model] : void 0;
169
180
  const efforts = reasoningEffortsForModel(model);
170
181
  return {
171
- provider: PROVIDER_ID,
182
+ provider: PROVIDER_ID$1,
172
183
  id: model,
173
184
  name: entry.id === model ? entry.name : model,
174
185
  inputModalities: [...entry.inputModalities],
@@ -213,7 +224,7 @@ var CodexChatGptAdapter = class extends LlmAdapter {
213
224
  providerInfo(provider) {
214
225
  return {
215
226
  id: provider,
216
- name: PROVIDER_NAME
227
+ name: PROVIDER_NAME$1
217
228
  };
218
229
  }
219
230
  providerRetryPolicy() {
@@ -1306,6 +1317,7 @@ const DEFAULT_PREFERENCES = {
1306
1317
  quickQuotaVisible: false,
1307
1318
  fastMode: false,
1308
1319
  outputVerbosity: null,
1320
+ reasoningSummary: null,
1309
1321
  visibleModelIds: [...DEFAULT_VISIBLE_CODEX_MODEL_IDS],
1310
1322
  searchProvider: "dsh",
1311
1323
  contextWindowOverrides: {
@@ -1325,6 +1337,9 @@ function isSearchProviderPreference(value) {
1325
1337
  function isCodexOutputVerbosity(value) {
1326
1338
  return value === "low" || value === "medium" || value === "high";
1327
1339
  }
1340
+ function isCodexReasoningSummary(value) {
1341
+ return value === "auto" || value === "concise" || value === "detailed" || value === "none";
1342
+ }
1328
1343
  function isProxyMode(value) {
1329
1344
  return value === "auto" || value === "custom" || value === "direct";
1330
1345
  }
@@ -1341,6 +1356,13 @@ function registerPreferenceStore(settings) {
1341
1356
  z.const("high"),
1342
1357
  z.const(null)
1343
1358
  ]).default(DEFAULT_PREFERENCES.outputVerbosity),
1359
+ reasoningSummary: z.union([
1360
+ z.const("auto"),
1361
+ z.const("concise"),
1362
+ z.const("detailed"),
1363
+ z.const("none"),
1364
+ z.const(null)
1365
+ ]).default(DEFAULT_PREFERENCES.reasoningSummary),
1344
1366
  visibleModelIds: z.array(z.string()).default(DEFAULT_PREFERENCES.visibleModelIds),
1345
1367
  searchProvider: z.union([z.const("dsh"), z.const(SEARCH_PROVIDER_CODEX)]).default(DEFAULT_PREFERENCES.searchProvider),
1346
1368
  contextWindowOverrides: z.object({
@@ -1374,6 +1396,10 @@ var SettingsPreferenceStore = class {
1374
1396
  if (patch.outputVerbosity !== null && !isCodexOutputVerbosity(patch.outputVerbosity)) throw new PreferenceError("Unsupported output verbosity preference.");
1375
1397
  normalized.outputVerbosity = patch.outputVerbosity;
1376
1398
  }
1399
+ if (patch.reasoningSummary !== void 0) {
1400
+ if (patch.reasoningSummary !== null && !isCodexReasoningSummary(patch.reasoningSummary)) throw new PreferenceError("Unsupported reasoning summary preference.");
1401
+ normalized.reasoningSummary = patch.reasoningSummary;
1402
+ }
1377
1403
  if (patch.visibleModelIds !== void 0) {
1378
1404
  if (patch.visibleModelIds.length === 0 || !patch.visibleModelIds.every(isCodexModelId)) throw new PreferenceError("At least one supported Codex model must be visible.");
1379
1405
  normalized.visibleModelIds = [...new Set(patch.visibleModelIds)];
@@ -1416,6 +1442,137 @@ function withWritable(value) {
1416
1442
  };
1417
1443
  }
1418
1444
  //#endregion
1445
+ //#region node_modules/@deepseek-ai/dsh-timeout/lib/index.js
1446
+ /**
1447
+ * Shared timeout arithmetic, signal fusion, and classification. The library
1448
+ * only notifies through abort signals; each capability still owns the mechanism
1449
+ * that stops its work and translates timeout reasons into public outcomes.
1450
+ * @module @deepseek-ai/dsh-timeout
1451
+ */
1452
+ /**
1453
+ * Internal abort reason carrying a capability-owned code and elapsed deadline.
1454
+ * Providers translate it through {@link timeoutOf} before returning to callers.
1455
+ */
1456
+ var TimeoutReason = class extends Error {
1457
+ code;
1458
+ timeoutMs;
1459
+ name = "TimeoutReason";
1460
+ /**
1461
+ * @param code Capability-owned timeout code (e.g. `BASH_TIMEOUT`).
1462
+ * @param timeoutMs The deadline that elapsed, in milliseconds.
1463
+ */
1464
+ constructor(code, timeoutMs) {
1465
+ super(`${code} after ${timeoutMs}ms`);
1466
+ this.code = code;
1467
+ this.timeoutMs = timeoutMs;
1468
+ }
1469
+ };
1470
+ /** Largest delay Node schedules without clamping it to one millisecond. */
1471
+ const MAX_TIMER_DELAY_MS = 2147483647;
1472
+ function assertTimerDelay(timeoutMs, name) {
1473
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 2147483647) throw new Error(`${name} must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);
1474
+ }
1475
+ /**
1476
+ * Create a rearmable idle watchdog for an async iterator. The timer exists only
1477
+ * while {@link IdleWatchdog.next} is outstanding, so consumer think time does
1478
+ * not count as provider idle time. The returned signal is stable for the whole
1479
+ * call and only notifies; the iterator must observe it to terminate its work.
1480
+ *
1481
+ * @param upstream - caller cancellation fused into the stable signal.
1482
+ * @param timeoutMs - positive finite idle interval in milliseconds.
1483
+ * @param code - capability-owned code carried by the timeout reason.
1484
+ * @returns a stable signal, guarded next operation, and timer disposer.
1485
+ */
1486
+ function idleWatchdog(upstream, timeoutMs, code) {
1487
+ assertTimerDelay(timeoutMs, "idleWatchdog timeoutMs");
1488
+ const timeout = new AbortController();
1489
+ const signal = upstream === void 0 ? timeout.signal : AbortSignal.any([upstream, timeout.signal]);
1490
+ let timer;
1491
+ let outstanding = false;
1492
+ let disposed = false;
1493
+ const arm = () => {
1494
+ if (timer !== void 0) clearTimeout(timer);
1495
+ timer = setTimeout(() => {
1496
+ timeout.abort(new TimeoutReason(code, timeoutMs));
1497
+ }, timeoutMs);
1498
+ };
1499
+ return {
1500
+ signal,
1501
+ async next(iterator) {
1502
+ if (disposed) throw new Error("idleWatchdog is disposed");
1503
+ if (outstanding) throw new Error("idleWatchdog next is already outstanding");
1504
+ outstanding = true;
1505
+ arm();
1506
+ try {
1507
+ return await iterator.next();
1508
+ } finally {
1509
+ clearTimeout(timer);
1510
+ timer = void 0;
1511
+ outstanding = false;
1512
+ }
1513
+ },
1514
+ pulse() {
1515
+ if (disposed || !outstanding) return;
1516
+ arm();
1517
+ },
1518
+ [Symbol.dispose]() {
1519
+ if (disposed) return;
1520
+ disposed = true;
1521
+ if (timer !== void 0) clearTimeout(timer);
1522
+ timer = void 0;
1523
+ }
1524
+ };
1525
+ }
1526
+ /**
1527
+ * Recover a timeout reason from a reason-bearing object. Supplying `code`
1528
+ * distinguishes this deadline from a nested upstream deadline; a foreign code
1529
+ * follows the ordinary cancellation path.
1530
+ *
1531
+ * @param x An {@link AbortSignal} or any `{ reason }` carrier (e.g. a caught abort error).
1532
+ * @param code When provided, only a {@link TimeoutReason} with this exact `code` matches.
1533
+ * @returns The matching {@link TimeoutReason}, else `undefined`.
1534
+ */
1535
+ function timeoutOf(x, code) {
1536
+ const reason = x.reason;
1537
+ if (!(reason instanceof TimeoutReason)) return void 0;
1538
+ return code === void 0 || reason.code === code ? reason : void 0;
1539
+ }
1540
+ //#endregion
1541
+ //#region src/host/common/idle-watchdog.ts
1542
+ const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 3e5;
1543
+ const STREAM_IDLE_TIMEOUT_CODE$1 = "LLM_STREAM_IDLE_TIMEOUT";
1544
+ /**
1545
+ * 为异步流包裹可复位的空闲超时看门狗。
1546
+ * 当流式 chunk 产出之间的间隔超过指定阈值时,主动终止并抛出带有 TIMEOUT 的 LlmError。
1547
+ */
1548
+ async function* wrapStreamWithWatchdog(source, upstreamSignal, timeoutMs = DEFAULT_STREAM_IDLE_TIMEOUT_MS, timeoutCode = STREAM_IDLE_TIMEOUT_CODE$1, providerTag = "llm") {
1549
+ const consumer = new AbortController();
1550
+ const watchdog = idleWatchdog(upstreamSignal === void 0 ? consumer.signal : AbortSignal.any([upstreamSignal, consumer.signal]), timeoutMs, timeoutCode);
1551
+ const iterator = source(watchdog.signal)[Symbol.asyncIterator]();
1552
+ let exhausted = false;
1553
+ try {
1554
+ while (true) {
1555
+ const result = await watchdog.next(iterator);
1556
+ if (timeoutOf(watchdog.signal, timeoutCode) !== void 0) throw new LlmError(`${providerTag} stream idle timeout after ${timeoutMs}ms`, "TIMEOUT");
1557
+ if (result.done) {
1558
+ exhausted = true;
1559
+ return;
1560
+ }
1561
+ yield result.value;
1562
+ }
1563
+ } catch (error) {
1564
+ if (timeoutOf(watchdog.signal, timeoutCode) !== void 0) throw new LlmError(`${providerTag} stream idle timeout after ${timeoutMs}ms`, "TIMEOUT", { cause: error });
1565
+ if (upstreamSignal?.aborted) throw new LlmError(`${providerTag} request aborted by caller`, "ABORTED", { cause: error });
1566
+ throw error;
1567
+ } finally {
1568
+ consumer.abort(`${providerTag} stream consumer stopped`);
1569
+ if (!exhausted) try {
1570
+ await iterator.return?.(void 0);
1571
+ } catch {}
1572
+ watchdog[Symbol.dispose]();
1573
+ }
1574
+ }
1575
+ //#endregion
1419
1576
  //#region src/host/responses-mapper.ts
1420
1577
  function hiddenSandboxControlToolNames(options) {
1421
1578
  const retryTools = recentSandboxRetryToolNames(options.messages);
@@ -1450,7 +1607,7 @@ function normalizeReplayCallIds(items, normalizeCallId) {
1450
1607
  call_id: normalizeCallId(item.call_id)
1451
1608
  } : item);
1452
1609
  }
1453
- async function buildResponsesPayload(options, attachments, localRawImages = {}, outputVerbosity = null, fastMode = false) {
1610
+ async function buildResponsesPayload(options, attachments, localRawImages = {}, outputVerbosity = null, fastMode = false, reasoningSummary = null) {
1454
1611
  const sandboxRetryTools = recentSandboxRetryToolNames(options.messages);
1455
1612
  const resolveLocalRawImages = supportsImageInput(options);
1456
1613
  const normalizeCallId = createCallIdNormalizer();
@@ -1536,7 +1693,7 @@ async function buildResponsesPayload(options, attachments, localRawImages = {},
1536
1693
  if (fastMode) payload.service_tier = "priority";
1537
1694
  if (options.reasoningEffort !== void 0) payload.reasoning = codexModelSupportsReasoningSummary(options.model) ? {
1538
1695
  effort: options.reasoningEffort,
1539
- summary: "auto"
1696
+ summary: reasoningSummary ?? "auto"
1540
1697
  } : { effort: options.reasoningEffort };
1541
1698
  return payload;
1542
1699
  }
@@ -1843,6 +2000,7 @@ var ResponsesClient = class {
1843
2000
  onGenerationFinished;
1844
2001
  outputVerbosity;
1845
2002
  fastMode;
2003
+ reasoningSummary;
1846
2004
  constructor(oauth, attachments, options = {}) {
1847
2005
  this.oauth = oauth;
1848
2006
  this.attachments = attachments;
@@ -1851,14 +2009,37 @@ var ResponsesClient = class {
1851
2009
  this.onGenerationFinished = options.onGenerationFinished ?? (() => void 0);
1852
2010
  this.outputVerbosity = options.outputVerbosity ?? (() => null);
1853
2011
  this.fastMode = options.fastMode ?? (() => false);
2012
+ this.reasoningSummary = options.reasoningSummary ?? (() => null);
1854
2013
  }
1855
2014
  localRawImages;
1856
2015
  async *stream(options) {
1857
- const payload = await buildResponsesPayload(options, this.attachments, this.localRawImages, this.outputVerbosity(), this.fastMode());
1858
2016
  const hiddenSandboxControls = hiddenSandboxControlToolNames(options);
1859
2017
  const sessionId = stableSessionId(options.sessionId);
2018
+ let currentModel = options.model;
2019
+ let attemptOptions = options;
2020
+ let response;
2021
+ while (true) {
2022
+ const payload = await buildResponsesPayload(attemptOptions, this.attachments, this.localRawImages, this.outputVerbosity(), this.fastMode(), this.reasoningSummary());
2023
+ try {
2024
+ response = await this.send(payload, sessionId, options.signal);
2025
+ break;
2026
+ } catch (error) {
2027
+ if (error instanceof LlmError && (error.code === "NOT_FOUND" || error.status === 404)) {
2028
+ const fallback = resolveCodexFallbackModel(currentModel);
2029
+ if (fallback && fallback.id !== currentModel) {
2030
+ currentModel = fallback.id;
2031
+ attemptOptions = {
2032
+ ...attemptOptions,
2033
+ model: fallback.id
2034
+ };
2035
+ continue;
2036
+ }
2037
+ }
2038
+ throw error;
2039
+ }
2040
+ }
1860
2041
  try {
1861
- yield* parseResponsesStream(await this.send(payload, sessionId, options.signal), options.signal, hiddenSandboxControls);
2042
+ yield* wrapStreamWithWatchdog((watchdogSignal) => parseResponsesStream(response, watchdogSignal, hiddenSandboxControls), options.signal, 3e5, "LLM_STREAM_IDLE_TIMEOUT", "Codex");
1862
2043
  } finally {
1863
2044
  this.onGenerationFinished();
1864
2045
  }
@@ -2203,6 +2384,7 @@ async function responseError(response) {
2203
2384
  ...response.status === 429 ? { providerRetryAfterMs: retryAfterMs(response.headers) } : {}
2204
2385
  };
2205
2386
  if (response.status === 401) return new LlmError("ChatGPT sign-in has expired. Sign in again.", "AUTH", options);
2387
+ if (response.status === 404) return new LlmError(`Codex model or resource not found (${response.status})${detail ? `: ${detail}` : "."}`, "NOT_FOUND", options);
2206
2388
  if (response.status === 429) return new LlmError("Codex rate limit reached.", "RATE_LIMIT", options);
2207
2389
  if (response.status >= 500) return new LlmError(`Codex service error (${response.status}).`, "SERVER_ERROR", options);
2208
2390
  return new LlmError(`Codex request failed (${response.status})${detail ? `: ${detail}` : "."}`, "PROVIDER_ERROR", options);
@@ -2651,6 +2833,20 @@ function registerRoutes(ctx, oauth, usage, preferences, proxyManager) {
2651
2833
  });
2652
2834
  return;
2653
2835
  }
2836
+ if (request.method === "GET" && url.pathname === `/api/dsh-chatgpt-subscription/mermaid.min.js`) {
2837
+ try {
2838
+ const mermaidPath = createRequire(import.meta.url).resolve("mermaid/dist/mermaid.min.js");
2839
+ response.writeHead(200, {
2840
+ "Content-Type": "application/javascript; charset=utf-8",
2841
+ "Cache-Control": "public, max-age=86400"
2842
+ });
2843
+ fs.createReadStream(mermaidPath).pipe(response);
2844
+ } catch {
2845
+ response.writeHead(404, { "Content-Type": "text/plain" });
2846
+ response.end("Not found");
2847
+ }
2848
+ return;
2849
+ }
2654
2850
  if (request.method !== "POST") {
2655
2851
  jsonError(response, 405, {
2656
2852
  code: "bad-request",
@@ -2854,7 +3050,7 @@ function field(value, name) {
2854
3050
  const candidate = value[name];
2855
3051
  return typeof candidate === "string" && candidate !== "" ? candidate : null;
2856
3052
  }
2857
- function isRecord(value) {
3053
+ function isRecord$1(value) {
2858
3054
  return typeof value === "object" && value !== null && !Array.isArray(value);
2859
3055
  }
2860
3056
  function readPreferencesUpdate(value, current) {
@@ -2875,12 +3071,16 @@ function readPreferencesUpdate(value, current) {
2875
3071
  if (value.outputVerbosity !== null && value.outputVerbosity !== "low" && value.outputVerbosity !== "medium" && value.outputVerbosity !== "high") throw new PreferenceError("outputVerbosity must be null, low, medium, or high.");
2876
3072
  patch.outputVerbosity = value.outputVerbosity;
2877
3073
  }
3074
+ if ("reasoningSummary" in value) {
3075
+ if (value.reasoningSummary !== null && !isCodexReasoningSummary(value.reasoningSummary)) throw new PreferenceError("reasoningSummary must be null, auto, concise, detailed, or none.");
3076
+ patch.reasoningSummary = value.reasoningSummary;
3077
+ }
2878
3078
  if ("searchProvider" in value) {
2879
3079
  if (value.searchProvider !== "dsh" && value.searchProvider !== "codex") throw new PreferenceError("searchProvider must be dsh or codex.");
2880
3080
  patch.searchProvider = value.searchProvider;
2881
3081
  }
2882
3082
  if ("contextWindowOverrides" in value) {
2883
- if (!isRecord(value.contextWindowOverrides)) throw new PreferenceError("contextWindowOverrides must be an object.");
3083
+ if (!isRecord$1(value.contextWindowOverrides)) throw new PreferenceError("contextWindowOverrides must be an object.");
2884
3084
  const overrides = {};
2885
3085
  for (const [model, contextWindow] of Object.entries(value.contextWindowOverrides)) {
2886
3086
  if (!isConfigurableContextModelId(model)) throw new PreferenceError("Only GPT-5.6 context windows can be changed.");
@@ -3307,6 +3507,1691 @@ function currentConfig(entry) {
3307
3507
  return typeof config === "object" && config !== null && !Array.isArray(config) ? config : {};
3308
3508
  }
3309
3509
  //#endregion
3510
+ //#region src/host/antigravity/types.ts
3511
+ const PROVIDER_NAME = "Antigravity";
3512
+ const PROVIDER_ID = "antigravity";
3513
+ const STREAM_IDLE_TIMEOUT_MS = 3e5;
3514
+ const STREAM_IDLE_TIMEOUT_CODE = "LLM_STREAM_IDLE_TIMEOUT";
3515
+ const DISCOVERY_TIMEOUT_MS = 8e3;
3516
+ const PROJECT_CACHE_TTL_MS = 1800 * 1e3;
3517
+ const OAUTH_CALLBACK_TIMEOUT_MS = 300 * 1e3;
3518
+ const ENDPOINT_FALLBACKS = ["https://cloudcode-pa.googleapis.com", "https://daily-cloudcode-pa.sandbox.googleapis.com"];
3519
+ const REDIRECT_PATH = "/oauth-callback";
3520
+ const AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
3521
+ const TOKEN_URL = "https://oauth2.googleapis.com/token";
3522
+ const SCOPES = [
3523
+ "https://www.googleapis.com/auth/aicode",
3524
+ "https://www.googleapis.com/auth/cloud-platform",
3525
+ "https://www.googleapis.com/auth/userinfo.email",
3526
+ "https://www.googleapis.com/auth/userinfo.profile",
3527
+ "https://www.googleapis.com/auth/cclog",
3528
+ "https://www.googleapis.com/auth/experimentsandconfigs"
3529
+ ];
3530
+ const DEFAULT_CLIENT_ID = Buffer.from("MTA3MTAwNjA2MDU5MS10bWhzc2luMmgyMWxjcmUyMzV2dG9sb2poNGc0MDNlcC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbQ==", "base64").toString("utf8");
3531
+ const DEFAULT_CLIENT_SECRET = Buffer.from("R09DU1BYLUs1OEZXUjQ4NkxkTEoxbUxCOHNYQzR6NnFEQWY=", "base64").toString("utf8");
3532
+ const ANTIGRAVITY_SYSTEM_INSTRUCTION = "You are Antigravity, a powerful agentic AI coding assistant designed by Google DeepMind. You are pair programming with a user to solve coding tasks. Be concise, practical, and tool-aware.";
3533
+ const ANTIGRAVITY_NO_PREAMBLE_INSTRUCTION = "CRITICAL: NEVER output rule checks, formatting guidelines, constraint checklists, or thinking/personality preambles in the final response. Output only the final response.";
3534
+ const GEMINI_ROLE = {
3535
+ user: "user",
3536
+ model: "model"
3537
+ };
3538
+ const TOOL_CALLING_MODE = {
3539
+ none: "NONE",
3540
+ any: "ANY",
3541
+ auto: "AUTO",
3542
+ validated: "VALIDATED"
3543
+ };
3544
+ const ROUTING = {
3545
+ "gemini-3.8-flash": {
3546
+ off: "gemini-3.8-flash-tiered",
3547
+ routing: {
3548
+ minimal: "gemini-3.8-flash-tiered",
3549
+ low: "gemini-3.8-flash-tiered",
3550
+ medium: "gemini-3.8-flash-tiered",
3551
+ high: "gemini-3.8-flash-tiered",
3552
+ xhigh: "gemini-3.8-flash-tiered"
3553
+ },
3554
+ defaultRequestId: "gemini-3.8-flash-tiered",
3555
+ fallbackCandidates: ["gemini-3.7-flash-tiered", "gemini-3.6-flash-low"]
3556
+ },
3557
+ "claude-opus-4-6": {
3558
+ off: "claude-opus-4-6-thinking",
3559
+ routing: {
3560
+ minimal: "claude-opus-4-6-thinking",
3561
+ low: "claude-opus-4-6-thinking",
3562
+ medium: "claude-opus-4-6-thinking",
3563
+ high: "claude-opus-4-6-thinking",
3564
+ xhigh: "claude-opus-4-6-thinking"
3565
+ },
3566
+ defaultRequestId: "claude-opus-4-6-thinking",
3567
+ fallbackCandidates: ["claude-sonnet-4-6"]
3568
+ },
3569
+ "claude-sonnet-4-6": {
3570
+ off: "claude-sonnet-4-6",
3571
+ routing: {
3572
+ minimal: "claude-sonnet-4-6",
3573
+ low: "claude-sonnet-4-6",
3574
+ medium: "claude-sonnet-4-6",
3575
+ high: "claude-sonnet-4-6",
3576
+ xhigh: "claude-sonnet-4-6"
3577
+ },
3578
+ defaultRequestId: "claude-sonnet-4-6"
3579
+ },
3580
+ "gemini-3.7-flash": {
3581
+ off: "gemini-3.7-flash-tiered",
3582
+ routing: {
3583
+ minimal: "gemini-3.7-flash-tiered",
3584
+ low: "gemini-3.7-flash-tiered",
3585
+ medium: "gemini-3.7-flash-tiered",
3586
+ high: "gemini-3.7-flash-tiered",
3587
+ xhigh: "gemini-3.7-flash-tiered"
3588
+ },
3589
+ defaultRequestId: "gemini-3.7-flash-tiered",
3590
+ fallbackCandidates: ["gemini-3.6-flash-low"]
3591
+ },
3592
+ "gemini-3.6-flash": {
3593
+ off: "gemini-3.6-flash-low",
3594
+ routing: {
3595
+ minimal: "gemini-3.6-flash-low",
3596
+ low: "gemini-3.6-flash-low",
3597
+ medium: "gemini-3.6-flash-medium",
3598
+ high: "gemini-3.6-flash-high",
3599
+ xhigh: "gemini-3.6-flash-high"
3600
+ },
3601
+ defaultRequestId: "gemini-3.6-flash-high"
3602
+ },
3603
+ "gemini-3.5-flash": {
3604
+ off: "gemini-3.5-flash-extra-low",
3605
+ routing: {
3606
+ minimal: "gemini-3.5-flash-extra-low",
3607
+ low: "gemini-3.5-flash-low",
3608
+ medium: "gemini-3.5-flash-low",
3609
+ high: "gemini-3-flash-agent",
3610
+ xhigh: "gemini-3-flash-agent"
3611
+ },
3612
+ defaultRequestId: "gemini-3-flash-agent"
3613
+ },
3614
+ "gemini-3.1-pro": {
3615
+ off: "gemini-3.1-pro-low",
3616
+ routing: {
3617
+ minimal: "gemini-3.1-pro-low",
3618
+ low: "gemini-3.1-pro-low",
3619
+ medium: "gemini-pro-agent",
3620
+ high: "gemini-pro-agent",
3621
+ xhigh: "gemini-pro-agent"
3622
+ },
3623
+ defaultRequestId: "gemini-pro-agent"
3624
+ },
3625
+ "gemini-3.1-flash-image": {
3626
+ off: "gemini-3.1-flash-image",
3627
+ routing: {
3628
+ minimal: "gemini-3.1-flash-image",
3629
+ low: "gemini-3.1-flash-image",
3630
+ medium: "gemini-3.1-flash-image",
3631
+ high: "gemini-3.1-flash-image",
3632
+ xhigh: "gemini-3.1-flash-image"
3633
+ },
3634
+ defaultRequestId: "gemini-3.1-flash-image"
3635
+ },
3636
+ "gemini-3-flash": {
3637
+ off: "gemini-3-flash",
3638
+ routing: {
3639
+ minimal: "gemini-3-flash",
3640
+ low: "gemini-3-flash",
3641
+ medium: "gemini-3-flash",
3642
+ high: "gemini-3-flash",
3643
+ xhigh: "gemini-3-flash"
3644
+ },
3645
+ defaultRequestId: "gemini-3-flash"
3646
+ },
3647
+ "gemini-2.5-pro": {
3648
+ off: "gemini-2.5-pro",
3649
+ routing: {
3650
+ minimal: "gemini-2.5-pro",
3651
+ low: "gemini-2.5-pro",
3652
+ medium: "gemini-2.5-pro",
3653
+ high: "gemini-2.5-pro",
3654
+ xhigh: "gemini-2.5-pro"
3655
+ },
3656
+ defaultRequestId: "gemini-2.5-pro"
3657
+ },
3658
+ "gemini-2.5-flash": {
3659
+ off: "gemini-2.5-flash",
3660
+ routing: {
3661
+ minimal: "gemini-2.5-flash",
3662
+ low: "gemini-2.5-flash",
3663
+ medium: "gemini-2.5-flash",
3664
+ high: "gemini-2.5-flash",
3665
+ xhigh: "gemini-2.5-flash"
3666
+ },
3667
+ defaultRequestId: "gemini-2.5-flash"
3668
+ },
3669
+ "gpt-oss-120b": {
3670
+ off: "gpt-oss-120b-medium",
3671
+ routing: {
3672
+ minimal: "gpt-oss-120b-medium",
3673
+ low: "gpt-oss-120b-medium",
3674
+ medium: "gpt-oss-120b-medium",
3675
+ high: "gpt-oss-120b-medium",
3676
+ xhigh: "gpt-oss-120b-medium"
3677
+ },
3678
+ defaultRequestId: "gpt-oss-120b-medium"
3679
+ }
3680
+ };
3681
+ const RUNTIME_MAX_OUTPUT_TOKENS = {
3682
+ "gemini-3.8-flash": 65536,
3683
+ "gemini-3.8-flash-tiered": 65536,
3684
+ "gemini-3.7-flash": 65536,
3685
+ "gemini-3.7-flash-tiered": 65536,
3686
+ "gemini-3.7-flash-low": 65536,
3687
+ "gemini-3.7-flash-medium": 65536,
3688
+ "gemini-3.7-flash-high": 65536,
3689
+ "gemini-3.6-flash": 65536,
3690
+ "gemini-3.6-flash-low": 65536,
3691
+ "gemini-3.6-flash-medium": 65536,
3692
+ "gemini-3.6-flash-high": 65536,
3693
+ "gemini-3.5-flash": 65536,
3694
+ "gemini-3.5-flash-extra-low": 65536,
3695
+ "gemini-3.5-flash-low": 65536,
3696
+ "gemini-3-flash-agent": 65536,
3697
+ "gemini-3.1-pro": 65535,
3698
+ "gemini-3.1-pro-low": 65535,
3699
+ "gemini-3.1-pro-high": 65535,
3700
+ "gemini-pro-agent": 65535,
3701
+ "claude-opus-4-6": 64e3,
3702
+ "claude-opus-4-6-thinking": 64e3,
3703
+ "claude-sonnet-4-6": 64e3,
3704
+ "gpt-oss-120b": 32768,
3705
+ "gpt-oss-120b-medium": 32768
3706
+ };
3707
+ const MODELS = [
3708
+ {
3709
+ id: "gemini-3.8-flash",
3710
+ name: "Gemini 3.8 Flash",
3711
+ inputModalities: ["text", "image"],
3712
+ contextWindow: 1048576,
3713
+ maxTokens: 65536,
3714
+ reasoningEfforts: [
3715
+ "low",
3716
+ "medium",
3717
+ "high"
3718
+ ]
3719
+ },
3720
+ {
3721
+ id: "gemini-3.7-flash",
3722
+ name: "Gemini 3.7 Flash",
3723
+ inputModalities: ["text", "image"],
3724
+ contextWindow: 1048576,
3725
+ maxTokens: 65536,
3726
+ reasoningEfforts: [
3727
+ "low",
3728
+ "medium",
3729
+ "high"
3730
+ ]
3731
+ },
3732
+ {
3733
+ id: "gemini-3.6-flash",
3734
+ name: "Gemini 3.6 Flash",
3735
+ inputModalities: ["text", "image"],
3736
+ contextWindow: 1048576,
3737
+ maxTokens: 65536,
3738
+ reasoningEfforts: [
3739
+ "low",
3740
+ "medium",
3741
+ "high"
3742
+ ]
3743
+ },
3744
+ {
3745
+ id: "gemini-3.5-flash",
3746
+ name: "Gemini 3.5 Flash",
3747
+ inputModalities: ["text", "image"],
3748
+ contextWindow: 1048576,
3749
+ maxTokens: 65536,
3750
+ reasoningEfforts: [
3751
+ "low",
3752
+ "medium",
3753
+ "high"
3754
+ ]
3755
+ },
3756
+ {
3757
+ id: "gemini-3.1-pro",
3758
+ name: "Gemini 3.1 Pro",
3759
+ inputModalities: ["text", "image"],
3760
+ contextWindow: 1048576,
3761
+ maxTokens: 65535,
3762
+ reasoningEfforts: ["low", "high"]
3763
+ },
3764
+ {
3765
+ id: "gemini-3.1-flash-image",
3766
+ name: "Gemini 3.1 Flash Image",
3767
+ inputModalities: ["text", "image"],
3768
+ contextWindow: 1048576,
3769
+ maxTokens: 8192
3770
+ },
3771
+ {
3772
+ id: "gemini-3-flash",
3773
+ name: "Gemini 3 Flash",
3774
+ inputModalities: ["text", "image"],
3775
+ contextWindow: 1048576,
3776
+ maxTokens: 65536
3777
+ },
3778
+ {
3779
+ id: "gemini-2.5-pro",
3780
+ name: "Gemini 2.5 Pro",
3781
+ inputModalities: ["text", "image"],
3782
+ contextWindow: 1048576,
3783
+ maxTokens: 65535
3784
+ },
3785
+ {
3786
+ id: "gemini-2.5-flash",
3787
+ name: "Gemini 2.5 Flash",
3788
+ inputModalities: ["text", "image"],
3789
+ contextWindow: 1048576,
3790
+ maxTokens: 65536
3791
+ },
3792
+ {
3793
+ id: "claude-opus-4-6",
3794
+ name: "Claude Opus 4.6",
3795
+ inputModalities: ["text", "image"],
3796
+ contextWindow: 1048576,
3797
+ maxTokens: 64e3,
3798
+ reasoningEfforts: [
3799
+ "low",
3800
+ "medium",
3801
+ "high"
3802
+ ]
3803
+ },
3804
+ {
3805
+ id: "claude-sonnet-4-6",
3806
+ name: "Claude Sonnet 4.6",
3807
+ inputModalities: ["text", "image"],
3808
+ contextWindow: 1048576,
3809
+ maxTokens: 64e3,
3810
+ reasoningEfforts: [
3811
+ "low",
3812
+ "medium",
3813
+ "high"
3814
+ ]
3815
+ },
3816
+ {
3817
+ id: "gpt-oss-120b",
3818
+ name: "GPT-OSS 120B",
3819
+ inputModalities: ["text"],
3820
+ contextWindow: 262144,
3821
+ maxTokens: 32768,
3822
+ reasoningEfforts: [
3823
+ "low",
3824
+ "medium",
3825
+ "high"
3826
+ ]
3827
+ }
3828
+ ];
3829
+ //#endregion
3830
+ //#region src/host/antigravity/token-store.ts
3831
+ const ANTIGRAVITY_PREFERENCES_NAMESPACE = "dsh-antigravity";
3832
+ function registerAntigravityPreferenceStore(settings, fallbackStore = new FileModelSettingsStore()) {
3833
+ if (!settings) return {
3834
+ status: () => ({
3835
+ enabledModelIds: MODELS.map((m) => m.id),
3836
+ catalogModels: [],
3837
+ contextWindowOverrides: {},
3838
+ defaultReasoningEffort: null
3839
+ }),
3840
+ update: async (patch) => fallbackStore.updateSettings(patch)
3841
+ };
3842
+ const ns = SettingsModule.settingsNamespace ? SettingsModule.settingsNamespace(ANTIGRAVITY_PREFERENCES_NAMESPACE) : ANTIGRAVITY_PREFERENCES_NAMESPACE;
3843
+ const scope = settings.register.call(settings, ns, z.object({
3844
+ enabledModelIds: z.array(z.string()).default(MODELS.map((m) => m.id)),
3845
+ contextWindowOverrides: z.dict(z.number()).default({}),
3846
+ defaultReasoningEffort: z.union([
3847
+ z.const("low"),
3848
+ z.const("medium"),
3849
+ z.const("high"),
3850
+ z.const(null)
3851
+ ]).default(null)
3852
+ }));
3853
+ return {
3854
+ status: () => {
3855
+ const val = scope.get();
3856
+ return {
3857
+ enabledModelIds: val.enabledModelIds,
3858
+ catalogModels: [],
3859
+ contextWindowOverrides: val.contextWindowOverrides,
3860
+ defaultReasoningEffort: val.defaultReasoningEffort
3861
+ };
3862
+ },
3863
+ update: async (patch) => {
3864
+ const current = scope.get();
3865
+ const normalized = {
3866
+ enabledModelIds: patch.enabledModelIds ?? current.enabledModelIds,
3867
+ contextWindowOverrides: patch.contextWindowOverrides ? {
3868
+ ...current.contextWindowOverrides,
3869
+ ...patch.contextWindowOverrides
3870
+ } : current.contextWindowOverrides,
3871
+ defaultReasoningEffort: patch.defaultReasoningEffort !== void 0 ? patch.defaultReasoningEffort : current.defaultReasoningEffort
3872
+ };
3873
+ await scope.update(normalized);
3874
+ fallbackStore.updateSettings(patch).catch(() => void 0);
3875
+ return {
3876
+ ...normalized,
3877
+ catalogModels: []
3878
+ };
3879
+ }
3880
+ };
3881
+ }
3882
+ function dshHomeDir() {
3883
+ return process.env.DSH_HOME?.trim() || path.join(os.homedir(), ".dsh");
3884
+ }
3885
+ function credentialPath() {
3886
+ return path.join(dshHomeDir(), "storages", "antigravity-oauth.json");
3887
+ }
3888
+ function modelSettingsPath() {
3889
+ return path.join(dshHomeDir(), "storages", "antigravity-models.json");
3890
+ }
3891
+ var FileCredentialStore = class {
3892
+ filePath;
3893
+ constructor(filePath = credentialPath()) {
3894
+ this.filePath = filePath;
3895
+ }
3896
+ path() {
3897
+ return this.filePath;
3898
+ }
3899
+ async read() {
3900
+ try {
3901
+ const content = await fsPromises.readFile(this.filePath, "utf8");
3902
+ const parsed = JSON.parse(content);
3903
+ if (typeof parsed === "object" && parsed !== null && ("access_token" in parsed || "access" in parsed)) return parsed;
3904
+ return null;
3905
+ } catch {
3906
+ return null;
3907
+ }
3908
+ }
3909
+ async write(credentials) {
3910
+ await fsPromises.mkdir(path.dirname(this.filePath), { recursive: true });
3911
+ const tmp = `${this.filePath}.tmp.${Date.now()}`;
3912
+ await fsPromises.writeFile(tmp, JSON.stringify(credentials, null, 2), "utf8");
3913
+ await fsPromises.rename(tmp, this.filePath);
3914
+ }
3915
+ async delete() {
3916
+ try {
3917
+ await fsPromises.unlink(this.filePath);
3918
+ } catch (err) {
3919
+ if (err.code !== "ENOENT") throw err;
3920
+ }
3921
+ }
3922
+ };
3923
+ var FileModelSettingsStore = class {
3924
+ filePath;
3925
+ constructor(filePath = modelSettingsPath()) {
3926
+ this.filePath = filePath;
3927
+ }
3928
+ path() {
3929
+ return this.filePath;
3930
+ }
3931
+ async read() {
3932
+ try {
3933
+ const content = await fsPromises.readFile(this.filePath, "utf8");
3934
+ const parsed = JSON.parse(content);
3935
+ if (typeof parsed === "object" && parsed !== null) {
3936
+ const record = parsed;
3937
+ return {
3938
+ enabledModelIds: Array.isArray(record.enabledModelIds) ? record.enabledModelIds.filter((id) => typeof id === "string") : MODELS.map((m) => m.id),
3939
+ catalogModels: Array.isArray(record.catalogModels) ? record.catalogModels : [],
3940
+ contextWindowOverrides: typeof record.contextWindowOverrides === "object" && record.contextWindowOverrides !== null ? record.contextWindowOverrides : {},
3941
+ defaultReasoningEffort: record.defaultReasoningEffort === "low" || record.defaultReasoningEffort === "medium" || record.defaultReasoningEffort === "high" ? record.defaultReasoningEffort : null
3942
+ };
3943
+ }
3944
+ } catch {}
3945
+ return {
3946
+ enabledModelIds: MODELS.map((m) => m.id),
3947
+ catalogModels: [],
3948
+ contextWindowOverrides: {},
3949
+ defaultReasoningEffort: null
3950
+ };
3951
+ }
3952
+ async write(settings) {
3953
+ await fsPromises.mkdir(path.dirname(this.filePath), { recursive: true });
3954
+ const tmp = `${this.filePath}.tmp.${Date.now()}`;
3955
+ await fsPromises.writeFile(tmp, JSON.stringify(settings, null, 2), "utf8");
3956
+ await fsPromises.rename(tmp, this.filePath);
3957
+ }
3958
+ async updateSettings(patch) {
3959
+ const current = await this.read();
3960
+ const next = {
3961
+ ...current,
3962
+ ...patch.enabledModelIds !== void 0 ? { enabledModelIds: patch.enabledModelIds } : {},
3963
+ ...patch.contextWindowOverrides !== void 0 ? { contextWindowOverrides: {
3964
+ ...current.contextWindowOverrides || {},
3965
+ ...patch.contextWindowOverrides
3966
+ } } : {},
3967
+ ...patch.defaultReasoningEffort !== void 0 ? { defaultReasoningEffort: patch.defaultReasoningEffort } : {}
3968
+ };
3969
+ await this.write(next);
3970
+ return next;
3971
+ }
3972
+ async setEnabledModelIds(enabledModelIds) {
3973
+ return this.updateSettings({ enabledModelIds });
3974
+ }
3975
+ async setCatalogModels(catalogModels, options) {
3976
+ const current = await this.read();
3977
+ const next = {
3978
+ ...current,
3979
+ enabledModelIds: options?.enabledModelIds ?? current.enabledModelIds,
3980
+ catalogModels
3981
+ };
3982
+ await this.write(next);
3983
+ return next;
3984
+ }
3985
+ };
3986
+ //#endregion
3987
+ //#region src/host/antigravity/client.ts
3988
+ const projectCache = /* @__PURE__ */ new Map();
3989
+ let cachedQuota;
3990
+ const PLATFORM = process.platform === "darwin" ? "MACOS" : process.platform === "win32" ? "WINDOWS" : "LINUX";
3991
+ function defaultUserAgent() {
3992
+ return `antigravity/1.15.8 ${process.platform === "darwin" ? "darwin" : process.platform === "win32" ? "windows" : "linux"}/${process.arch === "x64" ? "amd64" : process.arch}`;
3993
+ }
3994
+ function antigravityHeaders(token) {
3995
+ return {
3996
+ Authorization: `Bearer ${token}`,
3997
+ "Content-Type": "application/json",
3998
+ Accept: "text/event-stream",
3999
+ "User-Agent": process.env.DSH_ANTIGRAVITY_USER_AGENT || defaultUserAgent(),
4000
+ "X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
4001
+ "Client-Metadata": JSON.stringify({
4002
+ ideType: "ANTIGRAVITY",
4003
+ platform: PLATFORM,
4004
+ pluginType: "GEMINI"
4005
+ })
4006
+ };
4007
+ }
4008
+ function jsonHeaders(token) {
4009
+ return {
4010
+ ...antigravityHeaders(token),
4011
+ Accept: "application/json"
4012
+ };
4013
+ }
4014
+ function endpointCandidates() {
4015
+ const custom = process.env.DSH_ANTIGRAVITY_ENDPOINT?.trim();
4016
+ if (custom) return [custom];
4017
+ return ENDPOINT_FALLBACKS;
4018
+ }
4019
+ function extractProjectId(data) {
4020
+ if (typeof data !== "object" || data === null) return void 0;
4021
+ const record = data;
4022
+ const direct = record.antigravityProjectId ?? record.projectId ?? record.backendProjectId ?? record.userDefinedCloudaicompanionProject ?? record.cloudaicompanionProject ?? record.project;
4023
+ if (typeof direct === "string" && direct.length > 0) return direct;
4024
+ if (typeof direct === "object" && direct !== null && "id" in direct && typeof direct.id === "string") return direct.id;
4025
+ for (const key of [
4026
+ "projects",
4027
+ "projectIds",
4028
+ "cloudaicompanionProjects"
4029
+ ]) {
4030
+ const list = record[key];
4031
+ if (Array.isArray(list)) for (const item of list) {
4032
+ const nested = extractProjectId(item);
4033
+ if (nested) return nested;
4034
+ if (typeof item === "string" && item.length > 0) return item;
4035
+ }
4036
+ }
4037
+ }
4038
+ async function listCloudAICompanionProjects(token) {
4039
+ for (const endpoint of endpointCandidates()) try {
4040
+ const response = await fetch(`${endpoint}/v1internal:listCloudAICompanionProjects`, {
4041
+ method: "POST",
4042
+ headers: antigravityHeaders(token),
4043
+ body: JSON.stringify({}),
4044
+ signal: AbortSignal.timeout(DISCOVERY_TIMEOUT_MS)
4045
+ });
4046
+ if (!response.ok) continue;
4047
+ return extractProjectId(await response.json());
4048
+ } catch {}
4049
+ }
4050
+ async function loadCodeAssist(token) {
4051
+ const cached = projectCache.get(token);
4052
+ if (cached && cached.expiresAt > Date.now()) return cached.projectId;
4053
+ const body = JSON.stringify({ metadata: {
4054
+ ideType: "ANTIGRAVITY",
4055
+ platform: "PLATFORM_UNSPECIFIED",
4056
+ pluginType: "GEMINI"
4057
+ } });
4058
+ for (const endpoint of endpointCandidates()) try {
4059
+ const response = await fetch(`${endpoint}/v1internal:loadCodeAssist`, {
4060
+ method: "POST",
4061
+ headers: antigravityHeaders(token),
4062
+ body,
4063
+ signal: AbortSignal.timeout(DISCOVERY_TIMEOUT_MS)
4064
+ });
4065
+ if (!response.ok) continue;
4066
+ const project = extractProjectId(await response.json());
4067
+ if (project) {
4068
+ projectCache.set(token, {
4069
+ projectId: project,
4070
+ expiresAt: Date.now() + PROJECT_CACHE_TTL_MS
4071
+ });
4072
+ return project;
4073
+ }
4074
+ const listProj = await listCloudAICompanionProjects(token);
4075
+ if (listProj) {
4076
+ projectCache.set(token, {
4077
+ projectId: listProj,
4078
+ expiresAt: Date.now() + PROJECT_CACHE_TTL_MS
4079
+ });
4080
+ return listProj;
4081
+ }
4082
+ } catch {}
4083
+ }
4084
+ async function postJson(path, token, body) {
4085
+ for (const endpoint of endpointCandidates()) try {
4086
+ const response = await fetch(`${endpoint}${path}`, {
4087
+ method: "POST",
4088
+ headers: jsonHeaders(token),
4089
+ body: JSON.stringify(body)
4090
+ });
4091
+ if (response.ok) return {
4092
+ endpoint,
4093
+ status: response.status,
4094
+ data: await response.json()
4095
+ };
4096
+ } catch {}
4097
+ throw new Error(`Failed to call Antigravity API ${path}`);
4098
+ }
4099
+ function parseQuotaSummary(data) {
4100
+ const summary = typeof data === "object" && data !== null ? data : {};
4101
+ const rawGroups = Array.isArray(summary.groups) ? summary.groups : [];
4102
+ const groups = [];
4103
+ for (const group of rawGroups) {
4104
+ if (typeof group !== "object" || group === null) continue;
4105
+ const groupRec = group;
4106
+ const buckets = [];
4107
+ const rawBuckets = Array.isArray(groupRec.buckets) ? groupRec.buckets : [];
4108
+ for (const bucket of rawBuckets) {
4109
+ if (typeof bucket !== "object" || bucket === null) continue;
4110
+ const bRec = bucket;
4111
+ const remaining = typeof bRec.remainingFraction === "number" ? Math.max(0, Math.min(1, bRec.remainingFraction)) : 0;
4112
+ buckets.push({
4113
+ bucketId: String(bRec.bucketId || bRec.displayName || "limit"),
4114
+ displayName: String(bRec.displayName || bRec.bucketId || "Limit"),
4115
+ window: typeof bRec.window === "string" ? bRec.window : void 0,
4116
+ resetTime: typeof bRec.resetTime === "string" ? bRec.resetTime : void 0,
4117
+ description: typeof bRec.description === "string" ? bRec.description : void 0,
4118
+ remainingFraction: remaining
4119
+ });
4120
+ }
4121
+ if (buckets.length > 0 || groupRec.displayName) groups.push({
4122
+ displayName: String(groupRec.displayName || "Quota group"),
4123
+ description: typeof groupRec.description === "string" ? groupRec.description : void 0,
4124
+ buckets
4125
+ });
4126
+ }
4127
+ return {
4128
+ groups,
4129
+ description: typeof summary.description === "string" ? summary.description : void 0
4130
+ };
4131
+ }
4132
+ function parseCatalogModels(data) {
4133
+ if (typeof data !== "object" || data === null) return [];
4134
+ const record = data;
4135
+ const rawModels = typeof record.models === "object" && record.models !== null ? record.models : {};
4136
+ const list = [];
4137
+ for (const [modelId, info] of Object.entries(rawModels)) {
4138
+ if (typeof info !== "object" || info === null) continue;
4139
+ const rec = info;
4140
+ if (rec.isInternal || modelId.startsWith("chat_")) continue;
4141
+ list.push({
4142
+ id: modelId,
4143
+ name: typeof rec.displayName === "string" ? rec.displayName : modelId,
4144
+ description: typeof rec.description === "string" ? rec.description : void 0
4145
+ });
4146
+ }
4147
+ return list;
4148
+ }
4149
+ async function fetchAccountQuota(store = new FileCredentialStore(), modelSettings) {
4150
+ const { token, projectId: credentialProjectId } = await ensureApiKey(store);
4151
+ const [assistResult, summaryResult] = await Promise.all([postJson("/v1internal:loadCodeAssist", token, { metadata: {
4152
+ ideType: "ANTIGRAVITY",
4153
+ platform: "PLATFORM_UNSPECIFIED",
4154
+ pluginType: "GEMINI"
4155
+ } }).catch(() => null), postJson("/v1internal:retrieveUserQuotaSummary", token, {}).catch(() => null)]);
4156
+ const discoveredProject = assistResult ? extractProjectId(assistResult.data) : void 0;
4157
+ const projectId = credentialProjectId || discoveredProject || "antigravity-default";
4158
+ const modelsData = (await postJson("/v1internal:fetchAvailableModels", token, { project: projectId }).catch(() => null))?.data;
4159
+ const { groups, description } = summaryResult ? parseQuotaSummary(summaryResult.data) : { groups: [] };
4160
+ const catalogModels = modelsData ? parseCatalogModels(modelsData) : [];
4161
+ const assistData = assistResult?.data || {};
4162
+ const currentTier = assistData.currentTier;
4163
+ const paidTier = assistData.paidTier;
4164
+ const planLabel = paidTier?.name || currentTier?.name || void 0;
4165
+ cachedQuota = {
4166
+ projectId,
4167
+ endpoint: summaryResult?.endpoint || "https://cloudcode-pa.googleapis.com",
4168
+ planLabel,
4169
+ productTier: currentTier,
4170
+ paidTier,
4171
+ groups,
4172
+ groupDescription: description,
4173
+ models: catalogModels.map((m) => ({
4174
+ modelId: m.id,
4175
+ displayName: m.name,
4176
+ description: m.description
4177
+ })),
4178
+ catalogModels,
4179
+ fetchedAt: Date.now()
4180
+ };
4181
+ if (modelSettings && catalogModels.length > 0) {
4182
+ const current = await modelSettings.read();
4183
+ const isFirstTime = current.catalogModels.length === 0 && current.enabledModelIds.length === 0;
4184
+ const catalogIds = new Set(catalogModels.map((m) => m.id));
4185
+ const mergedEnabled = isFirstTime ? catalogModels.map((m) => m.id) : current.enabledModelIds.filter((id) => catalogIds.has(id));
4186
+ await modelSettings.setCatalogModels(catalogModels, { enabledModelIds: mergedEnabled });
4187
+ }
4188
+ return cachedQuota;
4189
+ }
4190
+ function getCachedQuota() {
4191
+ return cachedQuota;
4192
+ }
4193
+ //#endregion
4194
+ //#region src/host/antigravity/oauth.ts
4195
+ let webLoginFlow = { status: "idle" };
4196
+ function antigravityEnv(namePart) {
4197
+ const full = `DSH_ANTIGRAVITY_${namePart}`;
4198
+ return process.env[full];
4199
+ }
4200
+ function callbackPort() {
4201
+ const configured = Number(antigravityEnv("CALLBACK_PORT"));
4202
+ if (Number.isInteger(configured) && configured > 0 && configured <= 65535) return configured;
4203
+ return 51121;
4204
+ }
4205
+ function resolveCallbackHost(raw = antigravityEnv("CALLBACK_HOST")) {
4206
+ const host = (raw || "localhost").trim().toLowerCase();
4207
+ if (host === "localhost" || host === "127.0.0.1" || host === "::1") return host;
4208
+ return "localhost";
4209
+ }
4210
+ function redirectUri() {
4211
+ return `http://${resolveCallbackHost()}:${callbackPort()}${"/oauth-callback".startsWith("/"), REDIRECT_PATH}`;
4212
+ }
4213
+ function clientId() {
4214
+ return antigravityEnv("CLIENT_ID")?.trim() || DEFAULT_CLIENT_ID;
4215
+ }
4216
+ function clientSecret() {
4217
+ return antigravityEnv("CLIENT_SECRET")?.trim() || DEFAULT_CLIENT_SECRET;
4218
+ }
4219
+ function base64Url(buffer) {
4220
+ return buffer.toString("base64url");
4221
+ }
4222
+ function generatePKCE() {
4223
+ const verifier = base64Url(randomBytes(32));
4224
+ return {
4225
+ verifier,
4226
+ challenge: base64Url(createHash("sha256").update(verifier).digest())
4227
+ };
4228
+ }
4229
+ function escapeHtml(text) {
4230
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
4231
+ }
4232
+ function sanitizeOAuthProviderError(text) {
4233
+ return escapeHtml(text.slice(0, 300).replace(/[\r\n\t]+/g, " "));
4234
+ }
4235
+ function openBrowser(url) {
4236
+ try {
4237
+ if (process.platform === "darwin") spawn("open", [url], {
4238
+ stdio: "ignore",
4239
+ detached: true
4240
+ });
4241
+ else if (process.platform === "win32") spawn("cmd", [
4242
+ "/c",
4243
+ "start",
4244
+ "",
4245
+ url
4246
+ ], {
4247
+ stdio: "ignore",
4248
+ detached: true
4249
+ });
4250
+ else spawn("xdg-open", [url], {
4251
+ stdio: "ignore",
4252
+ detached: true
4253
+ });
4254
+ } catch {}
4255
+ }
4256
+ async function getUserEmail(token) {
4257
+ try {
4258
+ const response = await fetch("https://www.googleapis.com/oauth2/v1/userinfo?alt=json", { headers: { Authorization: `Bearer ${token}` } });
4259
+ if (!response.ok) return void 0;
4260
+ const data = await response.json();
4261
+ return typeof data.email === "string" ? data.email : void 0;
4262
+ } catch {
4263
+ return;
4264
+ }
4265
+ }
4266
+ function startCallbackServer(expectedState) {
4267
+ return new Promise((resolve, reject) => {
4268
+ let settled = false;
4269
+ let timeout;
4270
+ let resolveCode;
4271
+ let rejectCode;
4272
+ const codePromise = new Promise((res, rej) => {
4273
+ resolveCode = res;
4274
+ rejectCode = rej;
4275
+ });
4276
+ const finish = (fn) => {
4277
+ if (settled) return;
4278
+ settled = true;
4279
+ if (timeout) clearTimeout(timeout);
4280
+ fn();
4281
+ };
4282
+ const callbackUrl = redirectUri();
4283
+ const server = createServer((request, response) => {
4284
+ if (request.method !== "GET" && request.method !== "HEAD") {
4285
+ response.writeHead(405, { "Content-Type": "text/plain; charset=utf-8" });
4286
+ response.end("Method Not Allowed");
4287
+ return;
4288
+ }
4289
+ const url = new URL$1(request.url || "", callbackUrl);
4290
+ if (url.pathname !== "/oauth-callback") {
4291
+ response.writeHead(404, { "Content-Type": "text/html; charset=utf-8" });
4292
+ response.end("Antigravity OAuth callback route not found.");
4293
+ return;
4294
+ }
4295
+ const providerError = url.searchParams.get("error");
4296
+ const code = url.searchParams.get("code");
4297
+ const state = url.searchParams.get("state");
4298
+ if (providerError) {
4299
+ const safe = escapeHtml(providerError.slice(0, 200));
4300
+ response.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
4301
+ response.end(`Antigravity authentication failed: ${safe}`);
4302
+ finish(() => rejectCode(/* @__PURE__ */ new Error(`OAuth error: ${providerError.slice(0, 200)}`)));
4303
+ return;
4304
+ }
4305
+ if (!code || !state) {
4306
+ response.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
4307
+ response.end("Antigravity authentication failed: missing code or state.");
4308
+ finish(() => rejectCode(/* @__PURE__ */ new Error("Missing code or state in OAuth callback")));
4309
+ return;
4310
+ }
4311
+ if (state !== expectedState) {
4312
+ response.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
4313
+ response.end("Antigravity authentication failed: invalid state.");
4314
+ finish(() => rejectCode(/* @__PURE__ */ new Error("OAuth state mismatch")));
4315
+ return;
4316
+ }
4317
+ response.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
4318
+ response.end("Antigravity authentication complete. You can close this window and return to DSH.");
4319
+ finish(() => resolveCode({
4320
+ code,
4321
+ state
4322
+ }));
4323
+ });
4324
+ server.on("error", reject);
4325
+ server.listen(callbackPort(), resolveCallbackHost(), () => {
4326
+ timeout = setTimeout(() => {
4327
+ finish(() => rejectCode(/* @__PURE__ */ new Error("OAuth callback timed out waiting for browser login")));
4328
+ server.close();
4329
+ }, OAUTH_CALLBACK_TIMEOUT_MS);
4330
+ resolve({
4331
+ server,
4332
+ waitForCode: () => codePromise
4333
+ });
4334
+ });
4335
+ });
4336
+ }
4337
+ async function exchangeOAuthCode(code, verifier, callbackUrl) {
4338
+ const tokenResponse = await fetch(TOKEN_URL, {
4339
+ method: "POST",
4340
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
4341
+ body: new URLSearchParams$1({
4342
+ client_id: clientId(),
4343
+ client_secret: clientSecret(),
4344
+ code,
4345
+ grant_type: "authorization_code",
4346
+ redirect_uri: callbackUrl,
4347
+ code_verifier: verifier
4348
+ }).toString()
4349
+ });
4350
+ if (!tokenResponse.ok) throw new Error(`Token exchange failed: ${sanitizeOAuthProviderError(await tokenResponse.text())}`);
4351
+ const tokenData = await tokenResponse.json();
4352
+ const refreshToken = typeof tokenData.refresh_token === "string" ? tokenData.refresh_token : void 0;
4353
+ const accessToken = typeof tokenData.access_token === "string" ? tokenData.access_token : "";
4354
+ const expiresIn = typeof tokenData.expires_in === "number" ? tokenData.expires_in : 3600;
4355
+ if (!refreshToken) throw new Error("No refresh token received. Re-run login and allow offline access.");
4356
+ const [email, discoveredProject] = await Promise.all([getUserEmail(accessToken), loadCodeAssist(accessToken).catch(() => void 0)]);
4357
+ return {
4358
+ refresh: refreshToken,
4359
+ refresh_token: refreshToken,
4360
+ access: accessToken,
4361
+ access_token: accessToken,
4362
+ expires: Date.now() + expiresIn * 1e3 - 300 * 1e3,
4363
+ expires_at: Date.now() + expiresIn * 1e3 - 300 * 1e3,
4364
+ projectId: discoveredProject || void 0,
4365
+ email
4366
+ };
4367
+ }
4368
+ async function beginWebLogin(store) {
4369
+ if (webLoginFlow.status === "pending") return { ...webLoginFlow };
4370
+ const { verifier, challenge } = generatePKCE();
4371
+ const state = base64Url(randomBytes(32));
4372
+ const { server, waitForCode } = await startCallbackServer(state);
4373
+ const callbackUrl = redirectUri();
4374
+ webLoginFlow = {
4375
+ status: "pending",
4376
+ authUrl: `${AUTH_URL}?${new URLSearchParams$1({
4377
+ client_id: clientId(),
4378
+ response_type: "code",
4379
+ redirect_uri: callbackUrl,
4380
+ scope: SCOPES.join(" "),
4381
+ code_challenge: challenge,
4382
+ code_challenge_method: "S256",
4383
+ state,
4384
+ access_type: "offline",
4385
+ prompt: "consent"
4386
+ }).toString()}`,
4387
+ startedAt: Date.now(),
4388
+ error: void 0
4389
+ };
4390
+ (async () => {
4391
+ try {
4392
+ const { code, state: returnedState } = await waitForCode();
4393
+ if (returnedState !== state) throw new Error("OAuth state mismatch");
4394
+ const credentials = await exchangeOAuthCode(code, verifier, callbackUrl);
4395
+ await store.write(credentials);
4396
+ webLoginFlow.status = "complete";
4397
+ webLoginFlow.email = credentials.email;
4398
+ webLoginFlow.completedAt = Date.now();
4399
+ } catch (error) {
4400
+ webLoginFlow.status = "error";
4401
+ webLoginFlow.error = error instanceof Error ? error.message : String(error);
4402
+ webLoginFlow.completedAt = Date.now();
4403
+ } finally {
4404
+ server.close();
4405
+ }
4406
+ })();
4407
+ return { ...webLoginFlow };
4408
+ }
4409
+ function getWebLoginStatus() {
4410
+ return { ...webLoginFlow };
4411
+ }
4412
+ async function refreshAntigravityToken(credentials) {
4413
+ const refreshToken = credentials.refresh || credentials.refresh_token;
4414
+ if (!refreshToken) throw new Error("Missing Antigravity refresh token.");
4415
+ const response = await fetch(TOKEN_URL, {
4416
+ method: "POST",
4417
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
4418
+ body: new URLSearchParams$1({
4419
+ client_id: clientId(),
4420
+ client_secret: clientSecret(),
4421
+ refresh_token: refreshToken,
4422
+ grant_type: "refresh_token"
4423
+ }).toString()
4424
+ });
4425
+ if (!response.ok) throw new Error(`Token refresh failed: ${sanitizeOAuthProviderError(await response.text())}`);
4426
+ const data = await response.json();
4427
+ const accessToken = typeof data.access_token === "string" ? data.access_token : "";
4428
+ const expiresIn = typeof data.expires_in === "number" ? data.expires_in : 3600;
4429
+ const nextRefreshToken = typeof data.refresh_token === "string" ? data.refresh_token : refreshToken;
4430
+ return {
4431
+ ...credentials,
4432
+ refresh: nextRefreshToken,
4433
+ refresh_token: nextRefreshToken,
4434
+ access: accessToken,
4435
+ access_token: accessToken,
4436
+ expires: Date.now() + expiresIn * 1e3 - 300 * 1e3,
4437
+ expires_at: Date.now() + expiresIn * 1e3 - 300 * 1e3
4438
+ };
4439
+ }
4440
+ async function ensureApiKey(store) {
4441
+ let credentials = await store.read();
4442
+ if (!credentials) throw new Error("Not logged into Antigravity. Please log in from Settings > Antigravity.");
4443
+ const expires = credentials.expires || credentials.expires_at || 0;
4444
+ if (!(credentials.access || credentials.access_token) || expires <= Date.now() + 6e4) {
4445
+ credentials = await refreshAntigravityToken(credentials);
4446
+ await store.write(credentials);
4447
+ }
4448
+ return {
4449
+ token: credentials.access || credentials.access_token,
4450
+ projectId: credentials.projectId
4451
+ };
4452
+ }
4453
+ async function loginAndSave(store, signal, onUrl) {
4454
+ const { verifier, challenge } = generatePKCE();
4455
+ const state = base64Url(randomBytes(32));
4456
+ const { server, waitForCode } = await startCallbackServer(state);
4457
+ const callbackUrl = redirectUri();
4458
+ const authUrl = `${AUTH_URL}?${new URLSearchParams$1({
4459
+ client_id: clientId(),
4460
+ response_type: "code",
4461
+ redirect_uri: callbackUrl,
4462
+ scope: SCOPES.join(" "),
4463
+ code_challenge: challenge,
4464
+ code_challenge_method: "S256",
4465
+ state,
4466
+ access_type: "offline",
4467
+ prompt: "consent"
4468
+ }).toString()}`;
4469
+ try {
4470
+ if (onUrl) onUrl(authUrl);
4471
+ openBrowser(authUrl);
4472
+ if (signal?.aborted) throw new Error("OAuth login aborted");
4473
+ const { code, state: returnedState } = await waitForCode();
4474
+ if (returnedState !== state) throw new Error("OAuth state mismatch");
4475
+ const credentials = await exchangeOAuthCode(code, verifier, callbackUrl);
4476
+ await store.write(credentials);
4477
+ return credentials;
4478
+ } finally {
4479
+ server.close();
4480
+ }
4481
+ }
4482
+ //#endregion
4483
+ //#region src/host/antigravity/mapper.ts
4484
+ let toolCallCounter = 0;
4485
+ function sanitizeText(text) {
4486
+ return text.replace(/\0/g, "");
4487
+ }
4488
+ function isRecord(value) {
4489
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4490
+ }
4491
+ function asString(value) {
4492
+ return typeof value === "string" ? value : void 0;
4493
+ }
4494
+ function safeJsonParse(text) {
4495
+ try {
4496
+ return JSON.parse(text);
4497
+ } catch {
4498
+ return;
4499
+ }
4500
+ }
4501
+ function sanitizeToolCallId(id, fallbackName) {
4502
+ return String(id || "").replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64) || `${fallbackName || "tool"}_${Date.now()}_${++toolCallCounter}`;
4503
+ }
4504
+ function toolCallIdNeeded(modelId, runtimeModel) {
4505
+ return modelId.startsWith("claude-") || modelId.startsWith("gpt-oss-") || runtimeModel.startsWith("claude-") || runtimeModel.startsWith("gpt-oss-");
4506
+ }
4507
+ function parseArguments(raw) {
4508
+ if (isRecord(raw)) return raw;
4509
+ if (raw === void 0 || raw === null || raw === "") return {};
4510
+ const parsed = typeof raw === "string" ? safeJsonParse(raw) : raw;
4511
+ return isRecord(parsed) ? parsed : {};
4512
+ }
4513
+ function imageBlockToPart(block) {
4514
+ let data = asString(block.data) || asString(block.base64);
4515
+ const source = isRecord(block.source) ? block.source : void 0;
4516
+ if (!data && source) data = asString(source.data) || asString(source.base64);
4517
+ let mimeType = asString(block.mimeType) || asString(block.mediaType) || (source ? asString(source.mimeType) || asString(source.mediaType) : void 0) || "image/png";
4518
+ if (data?.startsWith("data:")) {
4519
+ const match = data.match(/^data:([^;,]+);base64,(.*)$/s);
4520
+ if (match) {
4521
+ mimeType = match[1] || mimeType;
4522
+ data = match[2] || "";
4523
+ }
4524
+ }
4525
+ return data ? { inlineData: {
4526
+ mimeType,
4527
+ data
4528
+ } } : void 0;
4529
+ }
4530
+ function contentToUserParts(content) {
4531
+ if (typeof content === "string") return [{ text: sanitizeText(content) }];
4532
+ if (!Array.isArray(content)) return [];
4533
+ const parts = [];
4534
+ for (const block of content) if (isRecord(block) && block.type === "text" && typeof block.text === "string") parts.push({ text: sanitizeText(block.text) });
4535
+ else if (isRecord(block) && block.type === "image") {
4536
+ const img = imageBlockToPart(block);
4537
+ if (img) parts.push(img);
4538
+ }
4539
+ return parts;
4540
+ }
4541
+ function toolResultText(blocks) {
4542
+ if (!Array.isArray(blocks)) return "";
4543
+ return blocks.map((block) => {
4544
+ if (!isRecord(block)) return "";
4545
+ if (block.type === "text" && typeof block.text === "string") return sanitizeText(block.text);
4546
+ if (block.type === "tool-result") return toolResultText(block.content);
4547
+ return "";
4548
+ }).join("");
4549
+ }
4550
+ function replayBlockFor(message, index) {
4551
+ const source = message.source;
4552
+ if (!source || source.kind !== "model") return void 0;
4553
+ const state = source.replayState;
4554
+ if (!isRecord(state)) return void 0;
4555
+ const resp = isRecord(state.response) ? state.response : void 0;
4556
+ if (resp) {
4557
+ if (Array.isArray(resp.outputItems)) return resp.outputItems[index];
4558
+ if (Array.isArray(resp.blocks)) return resp.blocks[index];
4559
+ }
4560
+ if (Array.isArray(state.blocks)) return state.blocks[index];
4561
+ }
4562
+ function assistantParts(message, model, runtimeModel, toolNames) {
4563
+ const parts = [];
4564
+ if (!Array.isArray(message.content)) return parts;
4565
+ for (let index = 0; index < message.content.length; index++) {
4566
+ const block = message.content[index];
4567
+ if (!isRecord(block)) continue;
4568
+ const replay = replayBlockFor(message, index);
4569
+ if (block.type === "text" && String(block.text || "").trim()) parts.push({ text: sanitizeText(String(block.text)) });
4570
+ else if (block.type === "reasoning" && String(block.text || "").trim()) {
4571
+ const sig = asString(replay?.thinkingSignature) || asString(replay?.thought_signature) || asString(block.thought_signature);
4572
+ if (sig) parts.push({
4573
+ thought: true,
4574
+ text: sanitizeText(String(block.text)),
4575
+ thought_signature: sig,
4576
+ thoughtSignature: sig
4577
+ });
4578
+ else parts.push({ text: sanitizeText(String(block.text)) });
4579
+ } else if (block.type === "tool-call") {
4580
+ const toolId = String(block.id || "");
4581
+ const toolName = String(block.name || "");
4582
+ toolNames.set(toolId, toolName);
4583
+ const sig = asString(replay?.thought_signature) || asString(replay?.thoughtSignature) || asString(block.thought_signature) || asString(block.thoughtSignature) || "skip_thought_signature_validator";
4584
+ parts.push({
4585
+ functionCall: {
4586
+ name: toolName,
4587
+ args: parseArguments(block.arguments),
4588
+ ...toolCallIdNeeded(model.id, runtimeModel) ? { id: sanitizeToolCallId(toolId, toolName) } : {}
4589
+ },
4590
+ thought_signature: sig,
4591
+ thoughtSignature: sig
4592
+ });
4593
+ }
4594
+ }
4595
+ return parts;
4596
+ }
4597
+ function pushToolResult(contents, result, toolNames, model, runtimeModel) {
4598
+ const toolCallId = String(result.toolCallId || "");
4599
+ const toolName = toolNames.get(toolCallId) || "unknown";
4600
+ const responseText = toolResultText(result.content) || (result.isError ? "Tool failed" : "");
4601
+ const part = { functionResponse: {
4602
+ name: toolName,
4603
+ response: result.isError ? { error: responseText } : { output: responseText },
4604
+ ...toolCallIdNeeded(model.id, runtimeModel) ? { id: sanitizeToolCallId(toolCallId, toolName) } : {}
4605
+ } };
4606
+ const last = contents[contents.length - 1];
4607
+ if (last?.role === GEMINI_ROLE.user && last.parts.some((entry) => "functionResponse" in entry)) last.parts.push(part);
4608
+ else contents.push({
4609
+ role: GEMINI_ROLE.user,
4610
+ parts: [part]
4611
+ });
4612
+ }
4613
+ function convertMessages(options, model, runtimeModel) {
4614
+ const contents = [];
4615
+ const toolNames = /* @__PURE__ */ new Map();
4616
+ for (const message of options.messages) {
4617
+ const role = message.role || (message.source?.kind === "model" ? "assistant" : "user");
4618
+ if (role === "assistant" || message.source?.kind === "model") {
4619
+ const parts = assistantParts(message, model, runtimeModel, toolNames);
4620
+ if (parts.length) contents.push({
4621
+ role: GEMINI_ROLE.model,
4622
+ parts
4623
+ });
4624
+ continue;
4625
+ }
4626
+ const content = Array.isArray(message.content) ? message.content : [];
4627
+ const userParts = contentToUserParts(content.filter((b) => !isRecord(b) || b.type !== "tool-result"));
4628
+ if (role === "system") {
4629
+ if (userParts.length) contents.push({
4630
+ role: GEMINI_ROLE.user,
4631
+ parts: userParts
4632
+ });
4633
+ continue;
4634
+ }
4635
+ if (userParts.length) contents.push({
4636
+ role: GEMINI_ROLE.user,
4637
+ parts: userParts
4638
+ });
4639
+ for (const b of content) if (isRecord(b) && b.type === "tool-result") pushToolResult(contents, b, toolNames, model, runtimeModel);
4640
+ }
4641
+ return contents;
4642
+ }
4643
+ function stripMetaSchema(schema) {
4644
+ if (!schema || typeof schema !== "object" || Array.isArray(schema)) return schema;
4645
+ const omit = /* @__PURE__ */ new Set([
4646
+ "$schema",
4647
+ "$id",
4648
+ "$anchor",
4649
+ "$dynamicAnchor",
4650
+ "$vocabulary",
4651
+ "$comment",
4652
+ "$defs",
4653
+ "definitions"
4654
+ ]);
4655
+ const out = {};
4656
+ for (const [k, v] of Object.entries(schema)) if (!omit.has(k)) out[k] = stripMetaSchema(v);
4657
+ return out;
4658
+ }
4659
+ function convertTools(tools) {
4660
+ if (!tools || tools.length === 0) return void 0;
4661
+ return [{ functionDeclarations: tools.map((tool) => ({
4662
+ name: tool.name,
4663
+ description: tool.description || "",
4664
+ parameters: stripMetaSchema(tool.parameters) || {
4665
+ type: "object",
4666
+ properties: {}
4667
+ }
4668
+ })) }];
4669
+ }
4670
+ function mapToolChoiceMode(toolChoice) {
4671
+ if (toolChoice === "none") return TOOL_CALLING_MODE.none;
4672
+ if (toolChoice === "any" || toolChoice === "required") return TOOL_CALLING_MODE.any;
4673
+ return TOOL_CALLING_MODE.auto;
4674
+ }
4675
+ function getMaxOutputTokens(modelId, runtimeModel) {
4676
+ return RUNTIME_MAX_OUTPUT_TOKENS[runtimeModel] || RUNTIME_MAX_OUTPUT_TOKENS[modelId] || 65536;
4677
+ }
4678
+ function buildRequest(options, model, projectId, runtimeModel, effort) {
4679
+ const request = {
4680
+ contents: convertMessages(options, model, runtimeModel),
4681
+ systemInstruction: {
4682
+ role: GEMINI_ROLE.user,
4683
+ parts: [
4684
+ { text: ANTIGRAVITY_SYSTEM_INSTRUCTION },
4685
+ { text: `Please ignore following [ignore]${ANTIGRAVITY_SYSTEM_INSTRUCTION}[/ignore]` },
4686
+ { text: ANTIGRAVITY_NO_PREAMBLE_INSTRUCTION },
4687
+ ...options.system ? [{ text: sanitizeText(options.system) }] : []
4688
+ ]
4689
+ }
4690
+ };
4691
+ const generationConfig = {};
4692
+ if (options.temperature !== void 0) generationConfig.temperature = options.temperature;
4693
+ if (runtimeModel === "gemini-3.8-flash-tiered" || runtimeModel === "gemini-3.7-flash-tiered") {
4694
+ const selected = effort || "off";
4695
+ generationConfig.thinkingConfig = { thinkingLevel: selected === "high" || selected === "xhigh" ? "HIGH" : selected === "medium" ? "MEDIUM" : "LOW" };
4696
+ }
4697
+ const maxAllowed = getMaxOutputTokens(model.id, runtimeModel);
4698
+ generationConfig.maxOutputTokens = options.maxTokens !== void 0 ? Math.min(options.maxTokens, maxAllowed) : maxAllowed;
4699
+ request.generationConfig = generationConfig;
4700
+ const toolChoice = options.toolChoice;
4701
+ const tools = convertTools(options.tools);
4702
+ if (tools) {
4703
+ request.tools = tools;
4704
+ if (toolChoice) request.toolConfig = { functionCallingConfig: { mode: mapToolChoiceMode(toolChoice) } };
4705
+ }
4706
+ if (options.sessionId) request.sessionId = String(options.sessionId);
4707
+ return {
4708
+ project: projectId,
4709
+ model: runtimeModel,
4710
+ request,
4711
+ requestType: "agent",
4712
+ userAgent: "antigravity",
4713
+ requestId: `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
4714
+ };
4715
+ }
4716
+ function createStreamState() {
4717
+ return {
4718
+ blocks: [],
4719
+ replayBlocks: [],
4720
+ currentBlock: null,
4721
+ hasContent: false,
4722
+ hasToolCall: false
4723
+ };
4724
+ }
4725
+ function processStreamLine(line, state) {
4726
+ if (!line.startsWith("data:")) return [];
4727
+ const json = line.slice(5).trim();
4728
+ if (!json || json === "[DONE]") return [];
4729
+ const chunk = safeJsonParse(json);
4730
+ if (!isRecord(chunk)) return [];
4731
+ const responseData = isRecord(chunk.response) ? chunk.response : chunk;
4732
+ const candidate = (Array.isArray(responseData.candidates) ? responseData.candidates : [])[0];
4733
+ const content = isRecord(candidate?.content) ? candidate.content : void 0;
4734
+ const parts = Array.isArray(content?.parts) ? content.parts : [];
4735
+ const out = [];
4736
+ const closeCurrentBlock = () => {
4737
+ if (!state.currentBlock) return;
4738
+ const index = state.blocks.length - 1;
4739
+ if (state.currentBlock.type === "text") out.push({
4740
+ type: "block-end",
4741
+ index,
4742
+ block: {
4743
+ type: "text",
4744
+ text: state.currentBlock.text
4745
+ }
4746
+ });
4747
+ else out.push({
4748
+ type: "block-end",
4749
+ index,
4750
+ block: {
4751
+ type: "reasoning",
4752
+ text: state.currentBlock.text
4753
+ }
4754
+ });
4755
+ state.currentBlock = null;
4756
+ };
4757
+ for (const part of parts) {
4758
+ if (!isRecord(part)) continue;
4759
+ if (part.text !== void 0 && typeof part.text === "string") {
4760
+ const isThinking = part.thought === true;
4761
+ const blockType = isThinking ? "reasoning" : "text";
4762
+ if (!state.currentBlock || state.currentBlock.type !== blockType) {
4763
+ closeCurrentBlock();
4764
+ state.currentBlock = {
4765
+ type: blockType,
4766
+ text: ""
4767
+ };
4768
+ const index = state.blocks.length;
4769
+ state.blocks.push({
4770
+ type: blockType,
4771
+ text: ""
4772
+ });
4773
+ state.replayBlocks.push({ type: blockType });
4774
+ out.push({
4775
+ type: "block-start",
4776
+ index,
4777
+ blockType
4778
+ });
4779
+ }
4780
+ const delta = sanitizeText(part.text);
4781
+ state.currentBlock.text += delta;
4782
+ state.hasContent = true;
4783
+ if (isThinking && part.thoughtSignature) {
4784
+ state.currentBlock.thinkingSignature = part.thoughtSignature;
4785
+ state.replayBlocks[state.blocks.length - 1].thinkingSignature = part.thoughtSignature;
4786
+ } else if (!isThinking && part.thoughtSignature) {
4787
+ state.currentBlock.textSignature = part.thoughtSignature;
4788
+ state.replayBlocks[state.blocks.length - 1].textSignature = part.thoughtSignature;
4789
+ }
4790
+ out.push({
4791
+ type: isThinking ? "reasoning-delta" : "text-delta",
4792
+ index: state.blocks.length - 1,
4793
+ text: delta
4794
+ });
4795
+ }
4796
+ if (isRecord(part.functionCall)) {
4797
+ closeCurrentBlock();
4798
+ const fc = part.functionCall;
4799
+ const toolName = asString(fc.name) || "";
4800
+ const toolId = sanitizeToolCallId(asString(fc.id) || "", toolName);
4801
+ const argsText = JSON.stringify(isRecord(fc.args) ? fc.args : {});
4802
+ const index = state.blocks.length;
4803
+ const sig = asString(part.thought_signature) || asString(part.thoughtSignature) || asString(part.thinkingSignature) || asString(fc.thought_signature) || asString(fc.thoughtSignature) || state.currentBlock?.thinkingSignature;
4804
+ const block = {
4805
+ type: "tool-call",
4806
+ id: toolId,
4807
+ name: toolName,
4808
+ arguments: argsText,
4809
+ ...sig ? {
4810
+ thought_signature: sig,
4811
+ thoughtSignature: sig
4812
+ } : {}
4813
+ };
4814
+ state.blocks.push(block);
4815
+ state.replayBlocks.push({
4816
+ type: "tool-call",
4817
+ ...sig ? {
4818
+ thought_signature: sig,
4819
+ thoughtSignature: sig
4820
+ } : {}
4821
+ });
4822
+ state.hasContent = true;
4823
+ state.hasToolCall = true;
4824
+ out.push({
4825
+ type: "block-start",
4826
+ index,
4827
+ blockType: "tool-call"
4828
+ });
4829
+ out.push({
4830
+ type: "tool-call-delta",
4831
+ index,
4832
+ id: toolId,
4833
+ name: toolName,
4834
+ argumentsDelta: argsText
4835
+ });
4836
+ out.push({
4837
+ type: "block-end",
4838
+ index,
4839
+ block
4840
+ });
4841
+ }
4842
+ }
4843
+ if (responseData.usageMetadata && isRecord(responseData.usageMetadata)) {
4844
+ const u = responseData.usageMetadata;
4845
+ const usage = {
4846
+ inputTokens: Math.max(0, (u.promptTokenCount || 0) - (u.cachedContentTokenCount || 0)),
4847
+ outputTokens: (u.candidatesTokenCount || 0) + (u.thoughtsTokenCount || 0),
4848
+ ...u.cachedContentTokenCount ? { cacheReadTokens: u.cachedContentTokenCount } : {}
4849
+ };
4850
+ out.push({
4851
+ type: "usage",
4852
+ usage
4853
+ });
4854
+ }
4855
+ const finishReason = candidate?.finishReason;
4856
+ if (finishReason) {
4857
+ closeCurrentBlock();
4858
+ const reason = state.hasToolCall ? { kind: "tool-calls" } : finishReason === "MAX_TOKENS" ? { kind: "max-tokens" } : { kind: "stop" };
4859
+ out.push({
4860
+ type: "finish",
4861
+ reason,
4862
+ replayState: { response: {
4863
+ outputItems: state.replayBlocks,
4864
+ blocks: state.replayBlocks
4865
+ } }
4866
+ });
4867
+ }
4868
+ return out;
4869
+ }
4870
+ function closeStream(state) {
4871
+ const out = [];
4872
+ if (state.currentBlock) {
4873
+ const index = state.blocks.length - 1;
4874
+ if (state.currentBlock.type === "text") out.push({
4875
+ type: "block-end",
4876
+ index,
4877
+ block: {
4878
+ type: "text",
4879
+ text: state.currentBlock.text
4880
+ }
4881
+ });
4882
+ else out.push({
4883
+ type: "block-end",
4884
+ index,
4885
+ block: {
4886
+ type: "reasoning",
4887
+ text: state.currentBlock.text
4888
+ }
4889
+ });
4890
+ state.currentBlock = null;
4891
+ }
4892
+ return out;
4893
+ }
4894
+ //#endregion
4895
+ //#region src/host/antigravity/adapter.ts
4896
+ var AntigravityAdapter = class extends LlmAdapter {
4897
+ store;
4898
+ modelSettings;
4899
+ preferences;
4900
+ constructor(store = new FileCredentialStore(), modelSettings = new FileModelSettingsStore(), preferences) {
4901
+ super();
4902
+ this.store = store;
4903
+ this.modelSettings = modelSettings;
4904
+ this.preferences = preferences;
4905
+ }
4906
+ providerInfo(provider) {
4907
+ return {
4908
+ id: provider,
4909
+ name: PROVIDER_NAME
4910
+ };
4911
+ }
4912
+ async listModels(provider) {
4913
+ const prov = provider || "antigravity";
4914
+ const settings = this.preferences ? this.preferences.status() : await this.modelSettings.read();
4915
+ const enabledSet = new Set(settings.enabledModelIds);
4916
+ const available = MODELS.filter((m) => enabledSet.has(m.id));
4917
+ const overrides = settings.contextWindowOverrides || {};
4918
+ return available.map((model) => ({
4919
+ provider: prov,
4920
+ id: model.id,
4921
+ name: model.name,
4922
+ inputModalities: model.inputModalities,
4923
+ context: { contextWindow: overrides[model.id] || model.contextWindow },
4924
+ defaultMaxTokens: model.maxTokens,
4925
+ ...model.reasoningEfforts ? { reasoningEfforts: model.reasoningEfforts } : {}
4926
+ }));
4927
+ }
4928
+ async resolveModel(provider, modelId, signal) {
4929
+ if (signal?.aborted) throw new LlmError("antigravity model resolution aborted", "ABORTED");
4930
+ const model = MODELS.find((m) => m.id === modelId) || {
4931
+ id: modelId,
4932
+ name: modelId,
4933
+ inputModalities: ["text", "image"],
4934
+ contextWindow: 128e3,
4935
+ maxTokens: 65536
4936
+ };
4937
+ const settings = this.preferences ? this.preferences.status() : await this.modelSettings.read();
4938
+ const overrides = settings.contextWindowOverrides || {};
4939
+ const efforts = model.reasoningEfforts || [
4940
+ "low",
4941
+ "medium",
4942
+ "high"
4943
+ ];
4944
+ const defaultEffort = settings.defaultReasoningEffort || "medium";
4945
+ return {
4946
+ provider,
4947
+ id: model.id,
4948
+ name: model.name,
4949
+ inputModalities: model.inputModalities,
4950
+ context: { contextWindow: overrides[model.id] || model.contextWindow },
4951
+ defaultMaxTokens: model.maxTokens,
4952
+ ...model.reasoningEfforts ? { reasoning: {
4953
+ efforts: efforts.map((effort) => ({
4954
+ id: ReasoningEffortId(effort),
4955
+ name: effort
4956
+ })),
4957
+ defaultEffort: ReasoningEffortId(defaultEffort)
4958
+ } } : {}
4959
+ };
4960
+ }
4961
+ async prepareCall(provider, model, signal) {
4962
+ return {
4963
+ model: await this.resolveModel(provider, model, signal),
4964
+ stream: (options) => this.stream(options)
4965
+ };
4966
+ }
4967
+ async *stream(options) {
4968
+ const model = MODELS.find((m) => m.id === options.model) || {
4969
+ id: options.model,
4970
+ name: options.model,
4971
+ inputModalities: ["text", "image"],
4972
+ contextWindow: 128e3,
4973
+ maxTokens: 65536
4974
+ };
4975
+ const settings = await this.modelSettings.read();
4976
+ const effectiveEffort = options.reasoningEffort || settings.defaultReasoningEffort || void 0;
4977
+ const effectiveOptions = effectiveEffort ? {
4978
+ ...options,
4979
+ reasoningEffort: effectiveEffort
4980
+ } : options;
4981
+ yield* wrapStreamWithWatchdog((watchdogSignal) => this.requestStream(effectiveOptions, model, watchdogSignal), options.signal, STREAM_IDLE_TIMEOUT_MS, STREAM_IDLE_TIMEOUT_CODE, "Antigravity");
4982
+ }
4983
+ async *requestStream(options, model, signal) {
4984
+ const { token, projectId: defaultProj } = await ensureApiKey(this.store);
4985
+ const projectId = defaultProj || "antigravity-default";
4986
+ const effort = String(options.reasoningEffort || "medium").toLowerCase();
4987
+ const routing = ROUTING[model.id];
4988
+ const initialRuntime = routing?.routing[effort] || routing?.defaultRequestId || model.id;
4989
+ const fallbackRuntime = routing?.off && routing.off !== initialRuntime ? routing.off : void 0;
4990
+ const candidates = [initialRuntime];
4991
+ if (fallbackRuntime && !candidates.includes(fallbackRuntime)) candidates.push(fallbackRuntime);
4992
+ if (routing?.fallbackCandidates) {
4993
+ for (const fc of routing.fallbackCandidates) if (!candidates.includes(fc)) candidates.push(fc);
4994
+ }
4995
+ let response;
4996
+ candidates[0];
4997
+ for (const runtimeModel of candidates) {
4998
+ const body = JSON.stringify(buildRequest(options, model, projectId, runtimeModel, effort));
4999
+ const headers = {
5000
+ ...antigravityHeaders(token),
5001
+ ...model.id.startsWith("claude-") ? { "anthropic-beta": "interleaved-thinking-2025-05-14" } : {}
5002
+ };
5003
+ for (const endpoint of endpointCandidates()) try {
5004
+ response = await fetch(`${endpoint}/v1internal:streamGenerateContent?alt=sse`, {
5005
+ method: "POST",
5006
+ headers,
5007
+ body,
5008
+ signal
5009
+ });
5010
+ if (response.ok) break;
5011
+ if (response.status === 404) break;
5012
+ } catch (err) {
5013
+ if (signal.aborted) throw new LlmError("Antigravity request aborted", "ABORTED", { cause: err });
5014
+ }
5015
+ if (response && response.ok) break;
5016
+ }
5017
+ if (!response || !response.ok) {
5018
+ const status = response?.status ?? 500;
5019
+ const errText = await response?.text().catch(() => "");
5020
+ if (status === 429) throw new LlmError(`Antigravity 账号配额已耗尽或请求受限 (429 RESOURCE_EXHAUSTED)。请在插件设置页查看配额剩余百分比及重置倒计时。原始响应: ${errText || "No response"}`, "RATE_LIMIT", { status: 429 });
5021
+ throw new LlmError(`Antigravity API error (${status}): ${errText || "No response"}`, "PROVIDER_ERROR", { status });
5022
+ }
5023
+ if (!response.body) throw new LlmError("Antigravity returned empty response body", "PROVIDER_ERROR");
5024
+ const reader = response.body.getReader();
5025
+ const decoder = new TextDecoder();
5026
+ const state = createStreamState();
5027
+ let buffer = "";
5028
+ try {
5029
+ while (true) {
5030
+ const { done, value } = await reader.read();
5031
+ if (done) break;
5032
+ buffer += decoder.decode(value, { stream: true });
5033
+ const lines = buffer.split("\n");
5034
+ buffer = lines.pop() || "";
5035
+ for (const line of lines) {
5036
+ const trimmed = line.trim();
5037
+ if (!trimmed) continue;
5038
+ const chunks = processStreamLine(trimmed, state);
5039
+ for (const chunk of chunks) yield chunk;
5040
+ }
5041
+ }
5042
+ if (buffer.trim()) {
5043
+ const chunks = processStreamLine(buffer.trim(), state);
5044
+ for (const chunk of chunks) yield chunk;
5045
+ }
5046
+ for (const chunk of closeStream(state)) yield chunk;
5047
+ } finally {
5048
+ reader.cancel().catch(() => void 0);
5049
+ }
5050
+ }
5051
+ };
5052
+ //#endregion
5053
+ //#region src/host/antigravity/routes.ts
5054
+ function sendJson(response, status, body) {
5055
+ response.writeHead(status, { "Content-Type": "application/json" });
5056
+ response.end(JSON.stringify(body));
5057
+ }
5058
+ function sendMethodNotAllowed(response) {
5059
+ sendJson(response, 405, {
5060
+ ok: false,
5061
+ error: "Method Not Allowed"
5062
+ });
5063
+ }
5064
+ async function readRequestJson(request) {
5065
+ return new Promise((resolve, reject) => {
5066
+ let raw = "";
5067
+ request.on("data", (chunk) => {
5068
+ raw += String(chunk);
5069
+ if (raw.length > 64 * 1024) reject(/* @__PURE__ */ new Error("Request body too large"));
5070
+ });
5071
+ request.on("end", () => {
5072
+ try {
5073
+ resolve(raw ? JSON.parse(raw) : {});
5074
+ } catch (err) {
5075
+ reject(err);
5076
+ }
5077
+ });
5078
+ request.on("error", reject);
5079
+ });
5080
+ }
5081
+ async function getAntigravityWebStatus(store, modelSettings, preferences) {
5082
+ const credentials = await store.read();
5083
+ const settings = preferences ? preferences.status() : await modelSettings.read();
5084
+ const quota = getCachedQuota();
5085
+ const enabledSet = new Set(settings.enabledModelIds);
5086
+ const overrides = settings.contextWindowOverrides || {};
5087
+ const models = MODELS.map((m) => ({
5088
+ id: m.id,
5089
+ name: m.name,
5090
+ enabled: enabledSet.has(m.id),
5091
+ defaultContextWindow: m.contextWindow,
5092
+ contextWindow: overrides[m.id] || m.contextWindow,
5093
+ reasoningEfforts: m.reasoningEfforts
5094
+ }));
5095
+ return {
5096
+ authenticated: !!(credentials?.access || credentials?.access_token),
5097
+ email: credentials?.email,
5098
+ projectId: credentials?.projectId,
5099
+ hasCredentials: !!credentials,
5100
+ storagePath: store.path(),
5101
+ lastFetchedAt: quota?.fetchedAt,
5102
+ quota,
5103
+ models,
5104
+ contextWindowOverrides: overrides,
5105
+ defaultReasoningEffort: settings.defaultReasoningEffort || null
5106
+ };
5107
+ }
5108
+ function registerAntigravityRoutes(ctx, store, modelSettings, preferences) {
5109
+ return ctx.webServer.register({
5110
+ kind: "prefix",
5111
+ path: "/antigravity/api",
5112
+ handler: async (request, response) => {
5113
+ const path = new URL(request.url || "/", "http://dsh.local").pathname.replace(/^\/antigravity\/api\/?/, "");
5114
+ try {
5115
+ if (path === "status" || path === "") {
5116
+ if (request.method !== "GET") return sendMethodNotAllowed(response);
5117
+ return sendJson(response, 200, {
5118
+ ok: true,
5119
+ value: await getAntigravityWebStatus(store, modelSettings, preferences)
5120
+ });
5121
+ }
5122
+ if (path === "login") {
5123
+ if (request.method !== "POST") return sendMethodNotAllowed(response);
5124
+ return sendJson(response, 200, {
5125
+ ok: true,
5126
+ value: await beginWebLogin(store)
5127
+ });
5128
+ }
5129
+ if (path === "login/status") {
5130
+ if (request.method !== "GET") return sendMethodNotAllowed(response);
5131
+ return sendJson(response, 200, {
5132
+ ok: true,
5133
+ value: getWebLoginStatus()
5134
+ });
5135
+ }
5136
+ if (path === "quota") {
5137
+ if (request.method !== "GET" && request.method !== "POST") return sendMethodNotAllowed(response);
5138
+ const quota = await fetchAccountQuota(store, modelSettings);
5139
+ return sendJson(response, 200, {
5140
+ ok: true,
5141
+ value: {
5142
+ ...await getAntigravityWebStatus(store, modelSettings, preferences),
5143
+ quota
5144
+ }
5145
+ });
5146
+ }
5147
+ if (path === "settings") {
5148
+ if (request.method !== "POST") return sendMethodNotAllowed(response);
5149
+ const body = await readRequestJson(request);
5150
+ if (preferences) await preferences.update(body);
5151
+ else await modelSettings.updateSettings(body);
5152
+ return sendJson(response, 200, {
5153
+ ok: true,
5154
+ value: await getAntigravityWebStatus(store, modelSettings, preferences)
5155
+ });
5156
+ }
5157
+ if (path === "models") {
5158
+ if (request.method === "GET") return sendJson(response, 200, {
5159
+ ok: true,
5160
+ value: (await getAntigravityWebStatus(store, modelSettings, preferences)).models
5161
+ });
5162
+ if (request.method === "POST") {
5163
+ const body = await readRequestJson(request);
5164
+ if (Array.isArray(body.enabledModelIds) || body.contextWindowOverrides || body.defaultReasoningEffort !== void 0) if (preferences) await preferences.update(body);
5165
+ else await modelSettings.updateSettings(body);
5166
+ return sendJson(response, 200, {
5167
+ ok: true,
5168
+ value: await getAntigravityWebStatus(store, modelSettings, preferences)
5169
+ });
5170
+ }
5171
+ return sendMethodNotAllowed(response);
5172
+ }
5173
+ if (path === "logout") {
5174
+ if (request.method !== "POST") return sendMethodNotAllowed(response);
5175
+ await store.delete();
5176
+ return sendJson(response, 200, {
5177
+ ok: true,
5178
+ value: await getAntigravityWebStatus(store, modelSettings)
5179
+ });
5180
+ }
5181
+ return sendJson(response, 404, {
5182
+ ok: false,
5183
+ error: "not-found"
5184
+ });
5185
+ } catch (err) {
5186
+ return sendJson(response, 500, {
5187
+ ok: false,
5188
+ error: err instanceof Error ? err.message : String(err)
5189
+ });
5190
+ }
5191
+ }
5192
+ });
5193
+ }
5194
+ //#endregion
3310
5195
  //#region src/index.ts
3311
5196
  const inject = [
3312
5197
  "webServer",
@@ -3320,6 +5205,18 @@ const inject = [
3320
5205
  function apply(ctx) {
3321
5206
  const store = createPlatformTokenStore();
3322
5207
  const preferences = registerPreferenceStore(ctx.settings);
5208
+ const antigravityStore = new FileCredentialStore();
5209
+ const antigravityModelSettings = new FileModelSettingsStore();
5210
+ const antigravityPreferences = registerAntigravityPreferenceStore(ctx.settings, antigravityModelSettings);
5211
+ const antigravityAdapter = new AntigravityAdapter(antigravityStore, antigravityModelSettings, antigravityPreferences);
5212
+ ctx.effect(() => {
5213
+ const disposeAntigravityAdapter = ctx.llm.registerAdapter([PROVIDER_ID], antigravityAdapter);
5214
+ const disposeAntigravityRoutes = registerAntigravityRoutes(ctx, antigravityStore, antigravityModelSettings, antigravityPreferences);
5215
+ return () => {
5216
+ disposeAntigravityRoutes();
5217
+ disposeAntigravityAdapter();
5218
+ };
5219
+ }, "dsh-antigravity: adapter, routes, and lifecycle");
3323
5220
  ctx.effect(() => {
3324
5221
  const proxyManager = new ProxyManager({
3325
5222
  getPreferences: () => preferences.status(),
@@ -3336,7 +5233,8 @@ function apply(ctx) {
3336
5233
  localRawImages: { baseUrl: localWebServerBaseUrl(ctx.webServer.host, ctx.webServer.port) },
3337
5234
  onGenerationFinished: () => usage.invalidate(),
3338
5235
  outputVerbosity: () => preferences.status().outputVerbosity,
3339
- fastMode: () => preferences.status().fastMode
5236
+ fastMode: () => preferences.status().fastMode,
5237
+ reasoningSummary: () => preferences.status().reasoningSummary
3340
5238
  }), preferences);
3341
5239
  const searchSwitcher = new SearchProviderSwitcher(ctx.loader);
3342
5240
  const applySearchPreference = (searchProvider = preferences.status().searchProvider) => {
@@ -3345,7 +5243,7 @@ function apply(ctx) {
3345
5243
  });
3346
5244
  };
3347
5245
  const disposeRoutes = registerRoutes(ctx, oauth, usage, preferences, proxyManager);
3348
- const disposeAdapter = ctx.llm.registerAdapter([PROVIDER_ID], adapter);
5246
+ const disposeAdapter = ctx.llm.registerAdapter([PROVIDER_ID$1], adapter);
3349
5247
  const disposeImageTool = ctx.tools.register(createCodexImageTool(oauth, ctx.attachments, { fetchFn: proxyFetch }));
3350
5248
  let disposeWebProviders = () => {};
3351
5249
  const registerWebProviders = () => {
@@ -3377,4 +5275,4 @@ function localWebServerBaseUrl(host, port) {
3377
5275
  return `http://${host === "0.0.0.0" ? "127.0.0.1" : host}:${port}`;
3378
5276
  }
3379
5277
  //#endregion
3380
- export { CodexChatGptAdapter, LinuxFileTokenStore, MacKeychainTokenStore, OAuthService, ProxyManager, ResponsesClient, UsageService, WindowsDpapiTokenStore, apply, createCodexFetchProvider, createCodexImageTool, createCodexSearchProvider, createPlatformTokenStore, detectSystemProxy, inject, mapCodexUsage, parseCodexUsage, parseResponsesStream };
5278
+ export { AntigravityAdapter, CodexChatGptAdapter, FileCredentialStore, FileModelSettingsStore, LinuxFileTokenStore, MacKeychainTokenStore, OAuthService, ProxyManager, ResponsesClient, UsageService, WindowsDpapiTokenStore, apply, beginWebLogin, createCodexFetchProvider, createCodexImageTool, createCodexSearchProvider, createPlatformTokenStore, credentialPath, detectSystemProxy, fetchAccountQuota, getCachedQuota, inject, loginAndSave, mapCodexUsage, modelSettingsPath, parseCodexUsage, parseResponsesStream, refreshAntigravityToken };